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,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ # A mixin for tags that returns the file as their content.
4
+ module ComfortableMediaSurfer::Content::Tags::Mixins
5
+ module FileContent
6
+ # @param [ActiveStorage::Blob] file
7
+ # @param ["link", "image", "url"] as
8
+ # @param [{String => String}] variant_attrs ImageMagick variant attributes
9
+ # @param [String] label alt text for `as: "image"`, link text for `as: "link"`
10
+ # @return [String]
11
+ def content(file: self.file, as: self.as, variant_attrs: self.variant_attrs, label: self.label)
12
+ return '' unless file
13
+
14
+ url_helpers = Rails.application.routes.url_helpers
15
+
16
+ attachment_url =
17
+ if variant_attrs.present? && file.image?
18
+ variant = file.variant(combine_options: variant_attrs)
19
+ url_helpers.rails_representation_path(variant, only_path: true)
20
+ else
21
+ url_helpers.rails_blob_path(file, only_path: true)
22
+ end
23
+
24
+ case as
25
+ when 'link'
26
+ "<a href='#{attachment_url}'#{html_class_attribute} target='_blank'>#{label}</a>"
27
+ when 'image'
28
+ "<img src='#{attachment_url}'#{html_class_attribute} alt='#{label}' title='#{label}'/>"
29
+ else
30
+ attachment_url
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ def html_class_attribute
37
+ return if @class.blank?
38
+
39
+ " class='#{@class}'"
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Tag for text content that is going to be rendered using number input
4
+ # {{ cms:number identifier }}
5
+ #
6
+ class ComfortableMediaSurfer::Content::Tags::Number < ComfortableMediaSurfer::Content::Tags::Fragment
7
+ def form_field(object_name, view, index)
8
+ name = "#{object_name}[fragments_attributes][#{index}][content]"
9
+ options = { id: form_field_id, class: 'form-control' }
10
+ input = view.send(:number_field_tag, name, content, options)
11
+
12
+ yield input
13
+ end
14
+ end
15
+
16
+ ComfortableMediaSurfer::Content::Renderer.register_tag(
17
+ :number, ComfortableMediaSurfer::Content::Tags::Number
18
+ )
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'mixins/file_content'
4
+
5
+ # This tag allows you to link page-level files from within the page content.
6
+ #
7
+ # E.g. if your layout has:
8
+ #
9
+ # {{ cms:file graphic, render: false }}
10
+ # {{ cms:files attachments, redner: false }}
11
+ #
12
+ # You can link to the files from an individual page (or snippet rendered in
13
+ # the context of the page) like so:
14
+ #
15
+ # {{ cms:page_file_link graphic }}
16
+ # {{ cms:page_file_link attachments, filename: "cat.jpg" }}
17
+ #
18
+ # `as` - url (default) | link | image - how file gets rendered out
19
+ # `class` - any html classes that you want on the result link or image tag. For example "class1 class2"
20
+ #
21
+ # - the following params are deprecated / not functional, perhaps due to some change in ImageMagick
22
+ # - Simply use a class in your CSS / SASS to style your image display
23
+ # `label` - attach label attribute to link or image tag
24
+ # `resize` - imagemagick option. For example: "100x50>"
25
+ # `gravity` - imagemagick option. For example: "center"
26
+ # `crop` - imagemagick option. For example: "100x50+0+0"
27
+ #
28
+ class ComfortableMediaSurfer::Content::Tags::PageFileLink < ComfortableMediaSurfer::Content::Tag
29
+ include ComfortableMediaSurfer::Content::Tags::Mixins::FileContent
30
+
31
+ # @return [String] A `cms:file(s)` identifier.
32
+ attr_reader :identifier
33
+
34
+ # @type ["url", "link", "image"]
35
+ attr_reader :as
36
+
37
+ # @type [{String => String}]
38
+ attr_reader :variant_attrs
39
+
40
+ # @return [String] Used to refer to a file in a {{ cms:files }} tag.
41
+ attr_reader :filename
42
+
43
+ # @param (see ComfortableMediaSurfer::Content::Tag#initialize)
44
+ def initialize(context:, params: [], source: nil)
45
+ super
46
+
47
+ options = params.extract_options!
48
+ @identifier = params[0]
49
+ @as = options['as'] || 'url'
50
+ @class = options['class']
51
+ @variant_attrs = options.slice('resize', 'gravity', 'crop')
52
+ @filename = options['filename']
53
+
54
+ return if @identifier.present?
55
+
56
+ raise Error, 'Missing identifier for page file link tag'
57
+ end
58
+
59
+ # @return [Comfy::Cms::Fragment]
60
+ def fragment
61
+ @fragment ||= context.fragments.detect { |f| f.identifier == identifier }
62
+ end
63
+
64
+ # @return [ActiveStorage::Blob]
65
+ def file
66
+ @file ||=
67
+ if fragment.nil?
68
+ nil
69
+ elsif filename.nil?
70
+ fragment.attachments.first
71
+ else
72
+ fragment.attachments.detect { |a| a.filename.to_s == filename }
73
+ end
74
+ end
75
+
76
+ # @return [String]
77
+ def label
78
+ return if file.nil?
79
+
80
+ file.filename.to_s
81
+ end
82
+ end
83
+
84
+ ComfortableMediaSurfer::Content::Renderer.register_tag(
85
+ :page_file_link, ComfortableMediaSurfer::Content::Tags::PageFileLink
86
+ )
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Tag for injecting partials. Example tag:
4
+ # {{cms:partial path/to/partial, foo: bar, zip: zoop}}
5
+ # This expands into a familiar:
6
+ # <%= render partial: "path/to/partial", locals: {foo: bar, zip: zoop} %>
7
+ # Whitelist is can be used to control what partials are renderable.
8
+ #
9
+ class ComfortableMediaSurfer::Content::Tags::Partial < ComfortableMediaSurfer::Content::Tag
10
+ attr_reader :path, :locals
11
+
12
+ def initialize(context:, params: [], source: nil)
13
+ super
14
+ @locals = params.extract_options!
15
+ @path = params[0]
16
+
17
+ return if @path.present?
18
+
19
+ raise Error, 'Missing path for partial tag'
20
+ end
21
+
22
+ # we output erb into rest of the content
23
+ def allow_erb?
24
+ true
25
+ end
26
+
27
+ def content
28
+ format(
29
+ '<%%= render partial: %<path>p, locals: %<locals>s %%>',
30
+ path: @path,
31
+ locals: @locals
32
+ )
33
+ end
34
+
35
+ def render
36
+ whitelist = ComfortableMediaSurfer.config.allowed_partials
37
+ if whitelist.is_a?(Array)
38
+ whitelist.member?(@path) ? content : ''
39
+ else
40
+ content
41
+ end
42
+ end
43
+ end
44
+
45
+ ComfortableMediaSurfer::Content::Renderer.register_tag(
46
+ :partial, ComfortableMediaSurfer::Content::Tags::Partial
47
+ )
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Nav Tag for rendering previous and next sibling links relative to current page
4
+ # {{ cms:siblings }}
5
+ # {{ cms:siblings style: "font-style: italic", exclude: "404-page, search-page" }}
6
+ # To customize your siblings style, add a 'siblings' id to your CSS, e.g
7
+ # #siblings {
8
+ # color: #006633;
9
+ # font-size: 95%;
10
+ # margin-top: 12px;
11
+ # font-style: italic;
12
+ # }
13
+ # and/or pass in style overrides with the 'style' parameter (see above)
14
+ #
15
+ # To exclude siblings, list their slugs with the 'exclude' parameter
16
+ # as comma-delimited string, e.g. as above - exclude: "404-page, search-page"
17
+ #
18
+ # style and exclude parameters are optional
19
+
20
+ class ComfortableMediaSurfer::Content::Tags::Siblings < ComfortableMediaSurfer::Content::Tag
21
+ attr_reader :locals, :style, :sibs
22
+ attr_accessor :links
23
+
24
+ def initialize(context:, params: [], source: nil)
25
+ super
26
+ @locals = params.extract_options!
27
+ @style = ''
28
+ @style = "<style>#siblings {#{@locals['style']}}</style>" if @locals['style']
29
+ @exclude = []
30
+ @exclude = @locals['exclude'].split(',') if @locals['exclude']
31
+ @links = ''
32
+ # ActiveRecord_Associations_CollectionProxy
33
+ @sibs = context.self_and_siblings.order(:position).to_ary
34
+ unless Rails.env == 'development'
35
+ @sibs.delete_if { |sib| !sib.is_published }
36
+ end
37
+ @sibs.delete_if { |sib| @exclude.include? sib.slug }
38
+ end
39
+
40
+ def content
41
+ if @sibs.count > 1
42
+ @links = '<div id="siblings">'
43
+ prevp = false
44
+ @sibs.each do |sib|
45
+ sib_idx = @sibs.index(sib)
46
+ next if sib.slug == context.slug
47
+ next if Rails.env == 'production' && !sib.is_published
48
+ next unless @sibs.index(context) # current page is excluded
49
+
50
+ if sib_idx == @sibs.index(context) - 1
51
+ @links += "<a href=#{sib.url(relative: true)}>#{sib.label}</a> &laquo;&nbsp;<em>Previous</em> &bull; "
52
+ prevp = true
53
+ elsif sib_idx == @sibs.index(context) + 1
54
+ @links += '&bull;' unless prevp
55
+ @links += "<em>Next</em>&nbsp;&raquo; <a href=#{sib.url(relative: true)}>#{sib.label}</a>"
56
+ end
57
+ end
58
+ @links += '</div>'
59
+ end
60
+ "#{@style}#{@links}"
61
+ end
62
+ end
63
+
64
+ ComfortableMediaSurfer::Content::Renderer.register_tag(
65
+ :siblings, ComfortableMediaSurfer::Content::Tags::Siblings
66
+ )
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Tag for reusable snippets within context's site scope. Looks like this:
4
+ # {{cms:snippet identifier}}
5
+ # Snippets may have more tags in them like fragments, so they may be expanded too.
6
+ #
7
+ class ComfortableMediaSurfer::Content::Tags::Snippet < ComfortableMediaSurfer::Content::Tag
8
+ attr_reader :identifier
9
+
10
+ def initialize(context:, params: [], source: nil)
11
+ super
12
+ @identifier = params[0]
13
+
14
+ return if @identifier.present?
15
+
16
+ raise Error, 'Missing identifier for snippet tag'
17
+ end
18
+
19
+ def content
20
+ if snippet.markdown
21
+ Kramdown::Document.new(snippet.content.to_s).to_html
22
+ else
23
+ snippet.content
24
+ end
25
+ end
26
+
27
+ # Grabbing or initializing Comfy::Cms::Snippet object
28
+ def snippet
29
+ context.site.snippets.detect { |s| s.identifier == identifier } ||
30
+ context.site.snippets.build(identifier: identifier)
31
+ end
32
+ end
33
+
34
+ ComfortableMediaSurfer::Content::Renderer.register_tag(
35
+ :snippet, ComfortableMediaSurfer::Content::Tags::Snippet
36
+ )
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Tag for injecting template rendering. Example tag:
4
+ # {{cms:template template/path}}
5
+ # This expands into something like this:
6
+ # <%= render template: "template/path" %>
7
+ # Whitelist is can be used to control what templates are available.
8
+ #
9
+ class ComfortableMediaSurfer::Content::Tags::Template < ComfortableMediaSurfer::Content::Tag
10
+ attr_reader :path
11
+
12
+ def initialize(context:, params: [], source: nil)
13
+ super
14
+ @path = params[0]
15
+
16
+ return if @path.present?
17
+
18
+ raise Error, 'Missing template path for template tag'
19
+ end
20
+
21
+ # we output erb into rest of the content
22
+ def allow_erb?
23
+ true
24
+ end
25
+
26
+ def content
27
+ format('<%%= render template: %<path>p %%>', path: path)
28
+ end
29
+
30
+ def render
31
+ whitelist = ComfortableMediaSurfer.config.allowed_templates
32
+ if whitelist.is_a?(Array)
33
+ whitelist.member?(@path) ? content : ''
34
+ else
35
+ content
36
+ end
37
+ end
38
+ end
39
+
40
+ ComfortableMediaSurfer::Content::Renderer.register_tag(
41
+ :template, ComfortableMediaSurfer::Content::Tags::Template
42
+ )
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Tag for text content that is going to be rendered using text input
4
+ # {{ cms:text identifier }}
5
+ #
6
+ class ComfortableMediaSurfer::Content::Tags::Text < ComfortableMediaSurfer::Content::Tags::Fragment
7
+ def form_field(object_name, view, index)
8
+ name = "#{object_name}[fragments_attributes][#{index}][content]"
9
+ options = { id: form_field_id, class: 'form-control' }
10
+ input = view.send(:text_field_tag, name, content, options)
11
+
12
+ yield input
13
+ end
14
+ end
15
+
16
+ ComfortableMediaSurfer::Content::Renderer.register_tag(
17
+ :text, ComfortableMediaSurfer::Content::Tags::Text
18
+ )
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Tag for text content that is going to be rendered using textarea
4
+ # {{ cms:textarea identifier }}
5
+ #
6
+
7
+ class ComfortableMediaSurfer::Content::Tags::Textarea < ComfortableMediaSurfer::Content::Tags::Fragment
8
+ def form_field(object_name, view, index)
9
+ name = "#{object_name}[fragments_attributes][#{index}][content]"
10
+ options = { id: form_field_id, data: { 'cms-cm-mode' => 'text/html' } }
11
+ input = view.send(:text_area_tag, name, content, options)
12
+
13
+ yield input
14
+ end
15
+ end
16
+
17
+ ComfortableMediaSurfer::Content::Renderer.register_tag(
18
+ :textarea, ComfortableMediaSurfer::Content::Tags::Textarea
19
+ )
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Tag for text content that is going to be rendered using Redactor (default) in
4
+ # the admin area
5
+ # {{ cms:wysiwyg identifier }}
6
+ #
7
+ #
8
+ class ComfortableMediaSurfer::Content::Tags::Wysiwyg < ComfortableMediaSurfer::Content::Tags::Fragment
9
+ def form_field(object_name, view, index)
10
+ name = "#{object_name}[fragments_attributes][#{index}][content]"
11
+ options = { id: form_field_id, data: { 'cms-rich-text' => true } }
12
+ input = view.send(:text_area_tag, name, content, options)
13
+ yield input
14
+ end
15
+ end
16
+
17
+ ComfortableMediaSurfer::Content::Renderer.register_tag(
18
+ :wysiwyg, ComfortableMediaSurfer::Content::Tags::Wysiwyg
19
+ )
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ComfortableMediaSurfer::Content::Tags
4
+ # ...
5
+ end
6
+
7
+ require_relative 'tags/fragment'
8
+ require_relative 'tags/wysiwyg'
9
+ require_relative 'tags/text'
10
+ require_relative 'tags/textarea'
11
+ require_relative 'tags/markdown'
12
+ require_relative 'tags/datetime'
13
+ require_relative 'tags/date'
14
+ require_relative 'tags/number'
15
+ require_relative 'tags/checkbox'
16
+ require_relative 'tags/file'
17
+ require_relative 'tags/files'
18
+ require_relative 'tags/snippet'
19
+ require_relative 'tags/asset'
20
+ require_relative 'tags/file_link'
21
+ require_relative 'tags/image'
22
+ require_relative 'tags/page_file_link'
23
+ require_relative 'tags/helper'
24
+ require_relative 'tags/partial'
25
+ require_relative 'tags/template'
26
+ require_relative 'tags/audio'
27
+ require_relative 'tags/breadcrumbs'
28
+ require_relative 'tags/children'
29
+ require_relative 'tags/siblings'
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ComfortableMediaSurfer::Content
4
+ # ...
5
+ end
6
+
7
+ require_relative 'content/renderer'
8
+ require_relative 'content/params_parser'
9
+ require_relative 'content/tag'
10
+ require_relative 'content/tags'
11
+ require_relative 'content/block'
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'comfortable_media_surfer'
4
+ require 'rails'
5
+ require 'rails-i18n'
6
+ require 'comfy_bootstrap_form'
7
+ require 'active_link_to'
8
+ require 'kramdown'
9
+ require 'haml-rails'
10
+
11
+ module ComfortableMediaSurfer
12
+ class Engine < ::Rails::Engine
13
+ initializer 'comfortable_media_surfer.setup_assets' do |app|
14
+ app.config.assets.paths << root.join('app/assets/builds')
15
+ app.config.assets.precompile += %w[comfy/admin/cms/application.js comfy/admin/cms/application.css]
16
+ end
17
+
18
+ config.to_prepare do
19
+ Dir.glob("#{Rails.root}app/decorators/comfortable_media_surfer/*_decorator*.rb").each do |c|
20
+ require_dependency(c)
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ComfortableMediaSurfer
4
+ class Error < StandardError
5
+ end
6
+
7
+ class MissingSite < ComfortableMediaSurfer::Error
8
+ def initialize(identifier)
9
+ super("Cannot find CMS Site with identifier: #{identifier}")
10
+ end
11
+ end
12
+
13
+ class MissingLayout < ComfortableMediaSurfer::Error
14
+ def initialize(identifier)
15
+ super("Cannot find CMS Layout with identifier: #{identifier}")
16
+ end
17
+ end
18
+
19
+ class MissingPage < ComfortableMediaSurfer::Error
20
+ def initialize(path)
21
+ super("Cannot find CMS Page at #{path}")
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,114 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ComfortableMediaSurfer::Extensions::ActsAsTree
4
+ def self.included(base)
5
+ base.extend(ClassMethods)
6
+ end
7
+
8
+ module ClassMethods
9
+ def cms_acts_as_tree(options = {})
10
+ configuration = {
11
+ foreign_key: 'parent_id',
12
+ order: nil,
13
+ counter_cache: nil,
14
+ dependent: :destroy,
15
+ touch: false
16
+ }
17
+ configuration.update(options) if options.is_a?(Hash)
18
+
19
+ belongs_to :parent,
20
+ optional: true,
21
+ class_name: name,
22
+ foreign_key: configuration[:foreign_key],
23
+ counter_cache: configuration[:counter_cache],
24
+ touch: configuration[:touch]
25
+
26
+ has_many :children,
27
+ -> { order(configuration[:order]) },
28
+ class_name: name,
29
+ foreign_key: configuration[:foreign_key],
30
+ dependent: configuration[:dependent]
31
+
32
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
33
+ include ComfortableMediaSurfer::Extensions::ActsAsTree::InstanceMethods
34
+
35
+ scope :roots, -> {
36
+ where("#{configuration[:foreign_key]} IS NULL").
37
+ order(#{configuration[:order].nil? ? 'nil' : %("#{configuration[:order]}")})
38
+ }
39
+
40
+ def self.root
41
+ roots.first
42
+ end
43
+
44
+ validates_each "#{configuration[:foreign_key]}" do |record, attr, value|
45
+ if value
46
+ if record.id == value
47
+ record.errors.add attr, "cannot be it's own id"
48
+ elsif record.descendants.map {|c| c.id}.include?(value)
49
+ record.errors.add attr, "cannot be a descendant's id"
50
+ end
51
+ end
52
+ end
53
+ RUBY
54
+ end
55
+ end
56
+
57
+ module InstanceMethods
58
+ # Returns list of ancestors, starting from parent until root.
59
+ #
60
+ # subchild1.ancestors # => [child1, root]
61
+ def ancestors
62
+ node = self
63
+ nodes = []
64
+ nodes << node = node.parent while node.parent
65
+ nodes
66
+ end
67
+
68
+ # Returns all children and children of children
69
+ def descendants
70
+ nodes = []
71
+ children.each do |c|
72
+ nodes << c
73
+ nodes << c.descendants
74
+ end
75
+ nodes.flatten
76
+ end
77
+
78
+ # Returns the root node of the tree.
79
+ def root
80
+ node = self
81
+ node = node.parent while node.parent
82
+ node
83
+ end
84
+
85
+ # Checks if this node is a root
86
+ def root?
87
+ !parent_id
88
+ end
89
+
90
+ # Returns all siblings of the current node.
91
+ #
92
+ # subchild1.siblings # => [subchild2]
93
+ def siblings
94
+ self_and_siblings - [self]
95
+ end
96
+
97
+ # Returns all siblings and a reference to the current node.
98
+ #
99
+ # subchild1.self_and_siblings # => [subchild1, subchild2]
100
+ def self_and_siblings
101
+ parent ? parent.children : self.class.roots
102
+ end
103
+
104
+ # BUG: https://github.com/rails/rails/issues/14369
105
+ # It's still a bug. Remove it to see failing test
106
+ def parent_id=(id)
107
+ self.parent = self.class.find_by(id: id)
108
+ end
109
+ end
110
+ end
111
+
112
+ ActiveSupport.on_load :active_record do
113
+ include ComfortableMediaSurfer::Extensions::ActsAsTree
114
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ComfortableMediaSurfer::Extensions::HasRevisions
4
+ def self.included(base)
5
+ base.send :extend, ClassMethods
6
+ end
7
+
8
+ module ClassMethods
9
+ def cms_has_revisions_for(*fields)
10
+ include ComfortableMediaSurfer::Extensions::HasRevisions::InstanceMethods
11
+
12
+ attr_accessor :revision_data
13
+
14
+ has_many :revisions,
15
+ as: :record,
16
+ dependent: :destroy,
17
+ class_name: 'Comfy::Cms::Revision'
18
+
19
+ before_save :prepare_revision
20
+ after_save :create_revision
21
+
22
+ define_method(:revision_fields) do
23
+ fields.collect(&:to_s)
24
+ end
25
+ end
26
+ end
27
+
28
+ module InstanceMethods
29
+ # Preparing revision data. A bit of a special thing to grab page blocks
30
+ def prepare_revision
31
+ return if new_record?
32
+
33
+ if (respond_to?(:fragments_attributes_changed) && fragments_attributes_changed) ||
34
+ !!changed.intersect?(revision_fields)
35
+ self.revision_data = revision_fields.to_h do |field|
36
+ [field, send("#{field}_was")]
37
+ end
38
+ end
39
+ end
40
+
41
+ # Revision is created only if relevant data changed
42
+ def create_revision
43
+ return unless revision_data
44
+
45
+ limit = ComfortableMediaSurfer.config.revisions_limit.to_i
46
+
47
+ # creating revision
48
+ if limit != 0
49
+ revisions.create!(data: revision_data)
50
+ end
51
+
52
+ # blowing away old revisions
53
+ ids = [0] + revisions.order(created_at: :desc).limit(limit).pluck(:id)
54
+ revisions.where('id NOT IN (?)', ids).destroy_all
55
+ end
56
+
57
+ # Assigning whatever is found in revision data and attempting to save the object
58
+ def restore_from_revision(revision)
59
+ return unless revision.record == self
60
+
61
+ update!(revision.data)
62
+ end
63
+ end
64
+ end
65
+
66
+ ActiveSupport.on_load :active_record do
67
+ include ComfortableMediaSurfer::Extensions::HasRevisions
68
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ComfortableMediaSurfer::Extensions
4
+ # ...
5
+ end
6
+
7
+ require_relative 'extensions/acts_as_tree'
8
+ require_relative 'extensions/has_revisions'