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,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This tag allows for linking of js and css content defined on the layout.
4
+ # Looks something like this:
5
+ # {{cms:asset layout_identifier, type: css, as: tag}}
6
+ #
7
+ # `type` - css | js - what we're outputting here
8
+ # `as` - url (default) | tag - output url or wrap it in the appropriate tag
9
+ #
10
+ class ComfortableMediaSurfer::Content::Tags::Asset < ComfortableMediaSurfer::Content::Tag
11
+ attr_reader :identifier, :type, :as
12
+
13
+ def initialize(context:, params: [], source: nil)
14
+ super
15
+
16
+ options = params.extract_options!
17
+ @identifier = params[0]
18
+ @type = options['type']
19
+ @as = options['as'] || 'url'
20
+
21
+ return if @identifier.present?
22
+
23
+ raise Error, 'Missing layout identifier for asset tag'
24
+ end
25
+
26
+ def layout
27
+ @layout ||= context.site.layouts.find_by(identifier: @identifier)
28
+ end
29
+
30
+ def content
31
+ return '' unless layout
32
+
33
+ base = ComfortableMediaSurfer.config.public_cms_path || ''
34
+ unless base.ends_with?('/')
35
+ base += '/'
36
+ end
37
+
38
+ case @type
39
+ when 'css'
40
+ out = "#{base}cms-css/#{context.site.id}/#{@identifier}/#{layout.cache_buster}.css"
41
+ if @as == 'tag'
42
+ out = "<link href='#{out}' media='screen' rel='stylesheet' type='text/css' />"
43
+ end
44
+ out
45
+ when 'js'
46
+ out = "#{base}cms-js/#{context.site.id}/#{@identifier}/#{layout.cache_buster}.js"
47
+ if @as == 'tag'
48
+ out = "<script src='#{out}' type='text/javascript'></script>"
49
+ end
50
+ out
51
+ end
52
+ end
53
+ end
54
+
55
+ ComfortableMediaSurfer::Content::Renderer.register_tag(
56
+ :asset, ComfortableMediaSurfer::Content::Tags::Asset
57
+ )
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Tag for injecting HTML5 audio player. Example tag:
4
+ # {{ cms:audio "path/to/audio", style: "height: 22px; width: 80%" }}
5
+ # This expands into:
6
+ # <audio controls src="path/to/audio"></audio>
7
+ # To customize your player style, add a 'audioplayer' class to your CSS, e.g
8
+ # .audioplayer {
9
+ # border-radius: 6px;
10
+ # height: 22px;
11
+ # width: 60%;
12
+ # margin: 2px 0 2px 8px;
13
+ # padding: 0;
14
+ # }
15
+ # and/or pass in style overrides with the 'style' parameter, as above
16
+
17
+ class ComfortableMediaSurfer::Content::Tags::Audio < ComfortableMediaSurfer::Content::Tag
18
+ attr_reader :path, :style, :locals
19
+
20
+ def initialize(context:, params: [], source: nil)
21
+ super
22
+ @locals = params.extract_options!
23
+ @path = params[0]
24
+ @style = ''
25
+ @style = "<style>.audioplayer {#{@locals['style']}}</style>" if @locals['style']
26
+
27
+ return if @path.present?
28
+
29
+ raise Error, 'Missing path for audio tag'
30
+ end
31
+
32
+ def content
33
+ "#{@style}<audio controls class=\"audioplayer\" src=#{@path}></audio>"
34
+ end
35
+ end
36
+
37
+ ComfortableMediaSurfer::Content::Renderer.register_tag(
38
+ :audio, ComfortableMediaSurfer::Content::Tags::Audio
39
+ )
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Nav Tag for rendering breadcrumb links to current page
4
+ # {{ cms:breadcrumbs }}
5
+ # {{ cms:breadcrumbs style: "font-weight: bold" }}
6
+ # To customize your breadcrumbs style, add a 'breadcrumbs' id to your CSS, e.g
7
+ # #breadcrumbs {
8
+ # color: #006633;
9
+ # font-family: Verdana, Arial, Helvetica, sans-serif;
10
+ # font-size: 105%;
11
+ # font-weight: bold;
12
+ # margin-top: 12px;
13
+ # margin-bottom: 4px;
14
+ # font-style: italic;
15
+ # }
16
+ # and/or pass in style overrides with the 'style' parameter, as above
17
+
18
+ class ComfortableMediaSurfer::Content::Tags::Breadcrumbs < ComfortableMediaSurfer::Content::Tag
19
+ attr_reader :links, :style, :locals
20
+
21
+ def initialize(context:, params: [], source: nil)
22
+ super
23
+ @locals = params.extract_options!
24
+ @style = ''
25
+ @style = "<style>#breadcrumbs {#{@locals['style']}}</style>" if @locals['style']
26
+
27
+ @links = '<div id="breadcrumbs">'
28
+ context.ancestors.reverse.each do |a|
29
+ next if Rails.env == 'production' && !a.is_published
30
+
31
+ @links += "<a href=#{a.url(relative: true)}>#{a.label}</a> &raquo; "
32
+ end
33
+ @links += "#{context.label}</div>"
34
+ end
35
+
36
+ def content
37
+ "#{@style}#{@links}"
38
+ end
39
+ end
40
+
41
+ ComfortableMediaSurfer::Content::Renderer.register_tag(
42
+ :breadcrumbs, ComfortableMediaSurfer::Content::Tags::Breadcrumbs
43
+ )
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Tag for boolean content that is going to be rendered using checkbox
4
+ # {{ cms:checkbox identifier }}
5
+ #
6
+ class ComfortableMediaSurfer::Content::Tags::Checkbox < ComfortableMediaSurfer::Content::Tags::Fragment
7
+ def content
8
+ fragment.boolean
9
+ end
10
+
11
+ def form_field(object_name, view, index)
12
+ name = "#{object_name}[fragments_attributes][#{index}][boolean]"
13
+
14
+ input = view.content_tag(:div, class: 'form-check mt-2') do
15
+ view.concat view.hidden_field_tag(name, '0', id: nil)
16
+
17
+ options = { id: form_field_id, class: 'form-check-input position-static' }
18
+ view.concat view.check_box_tag(name, '1', content.present?, options)
19
+ end
20
+
21
+ yield input
22
+ end
23
+ end
24
+
25
+ ComfortableMediaSurfer::Content::Renderer.register_tag(
26
+ :checkbox, ComfortableMediaSurfer::Content::Tags::Checkbox
27
+ )
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Nav Tag for unordered list of links to the children of the current page
4
+ # {{ cms:children }}
5
+ # {{ cms:children style: "font-weight: bold", exclude: "404-page, search-page" }}
6
+ # To customize your children style, add a 'children' id to your CSS, e.g
7
+ # #children {
8
+ # color: #006633;
9
+ # font-size: 90%;
10
+ # margin-bottom: 4px;
11
+ # font-style: italic;
12
+ # }
13
+ # and/or pass in style overrides with the 'style' parameter, as above
14
+ #
15
+ # To exclude children, list their slugs with the 'exclude' parameter
16
+ # as comma-delimited string, e.g. as above - exclude: "404-page, search-page"
17
+
18
+ class ComfortableMediaSurfer::Content::Tags::Children < ComfortableMediaSurfer::Content::Tag
19
+ attr_reader :style, :page_children, :locals
20
+ attr_accessor :list
21
+
22
+ def initialize(context:, params: [], source: nil)
23
+ super
24
+ @locals = params.extract_options!
25
+ @style = ''
26
+ @style = "<style>#children {#{@locals['style']}}</style>\n" if @locals['style']
27
+ @exclude = []
28
+ @exclude = @locals['exclude'].split(',').map(&:strip) if @locals['exclude']
29
+ @list = ''
30
+ # ActiveRecord_Associations_CollectionProxy
31
+ @page_children = context.children.order(:position).to_ary
32
+ unless Rails.env == 'development'
33
+ @page_children.delete_if { |child| !child.is_published }
34
+ end
35
+ @page_children.delete_if { |child| @exclude.include? child.slug }
36
+ end
37
+
38
+ def content
39
+ if @page_children.any?
40
+ @list = "<ul id=\"children\">\n"
41
+ @page_children.each do |c|
42
+ @list += " <li><a href=#{c.url(relative: true)}>#{c.label}</a></li>\n"
43
+ end
44
+ @list += '</ul>'
45
+ end
46
+ "#{@style}#{@list}"
47
+ end
48
+ end
49
+
50
+ ComfortableMediaSurfer::Content::Renderer.register_tag(
51
+ :children, ComfortableMediaSurfer::Content::Tags::Children
52
+ )
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Tag for text content that is going to be rendered using text input with date widget
4
+ # {{ cms:date identifier }}
5
+ #
6
+ class ComfortableMediaSurfer::Content::Tags::Date < ComfortableMediaSurfer::Content::Tags::Datetime
7
+ def form_field(object_name, view, index)
8
+ name = "#{object_name}[fragments_attributes][#{index}][datetime]"
9
+ options = { id: form_field_id, class: 'form-control', data: { 'cms-date' => true } }
10
+ value = content.present? ? content.to_fs(:db) : ''
11
+ input = view.send(:text_field_tag, name, value, options)
12
+
13
+ yield input
14
+ end
15
+ end
16
+
17
+ ComfortableMediaSurfer::Content::Renderer.register_tag(
18
+ :date, ComfortableMediaSurfer::Content::Tags::Date
19
+ )
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Tag for text content that is going to be rendered using text input with datetime widget
4
+ # {{ cms:datetime identifier, strftime: "at %I:%M%p" }}
5
+ #
6
+ # `strftime` - Format datetime string during rendering
7
+ #
8
+ class ComfortableMediaSurfer::Content::Tags::Datetime < ComfortableMediaSurfer::Content::Tags::Fragment
9
+ attr_reader :strftime
10
+
11
+ def initialize(context:, params: [], source: nil)
12
+ super
13
+ @strftime = options['strftime']
14
+ end
15
+
16
+ def content
17
+ fragment.datetime
18
+ end
19
+
20
+ def render
21
+ return '' unless renderable
22
+
23
+ if strftime.present?
24
+ content.strftime(strftime)
25
+ else
26
+ content.to_s
27
+ end
28
+ end
29
+
30
+ def form_field(object_name, view, index)
31
+ name = "#{object_name}[fragments_attributes][#{index}][datetime]"
32
+ options = { id: form_field_id, class: 'form-control', data: { 'cms-datetime' => true } }
33
+ value = content.present? ? content.to_fs(:db) : ''
34
+ input = view.send(:text_field_tag, name, value, options)
35
+
36
+ yield input
37
+ end
38
+ end
39
+
40
+ ComfortableMediaSurfer::Content::Renderer.register_tag(
41
+ :datetime, ComfortableMediaSurfer::Content::Tags::Datetime
42
+ )
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'mixins/file_content'
4
+
5
+ # File tag allows attaching of file to the page. This controls how files are
6
+ # uploaded and then displayed on the page. Example tag:
7
+ # {{ cms:file identifier, as: link, label: "My File" }}
8
+ #
9
+ # `as` - url (default) | link | image - render out link or image tag
10
+ # `label` - attach label attribute to link or image tag
11
+ # `resize` - imagemagic option. For example: "100x50>"
12
+ # `gravity` - imagemagic option. For example: "center"
13
+ # `crop` - imagemagic option. For example: "100x50+0+0"
14
+ # `class` - any html classes that you want on the result link or image tag. For example "class1 class2"
15
+ #
16
+ class ComfortableMediaSurfer::Content::Tags::File < ComfortableMediaSurfer::Content::Tags::Fragment
17
+ include ComfortableMediaSurfer::Content::Tags::Mixins::FileContent
18
+
19
+ # @type ["url", "link", "image"]
20
+ attr_reader :as
21
+
22
+ # @type [{String => String}]
23
+ attr_reader :variant_attrs
24
+
25
+ # @param (see ComfortableMediaSurfer::Content::Tag#initialize)
26
+ def initialize(context:, params: [], source: nil)
27
+ super
28
+ @as = options['as'] || 'url'
29
+ @label = options['label']
30
+ @class = options['class']
31
+ @variant_attrs = options.slice('resize', 'gravity', 'crop')
32
+ end
33
+
34
+ def form_field(object_name, view, index)
35
+ name = "#{object_name}[fragments_attributes][#{index}][files]"
36
+ input = view.send(:file_field_tag, name, id: form_field_id, class: 'form-control')
37
+
38
+ attachments_partial =
39
+ if fragment.attachments
40
+ view.render(
41
+ partial: 'comfy/admin/cms/fragments/form_fragment_attachments',
42
+ locals: {
43
+ object_name: object_name,
44
+ index: index,
45
+ attachments: fragment.attachments,
46
+ fragment_id: identifier,
47
+ multiple: false
48
+ }
49
+ )
50
+ end
51
+
52
+ yield view.safe_join([input, attachments_partial], '')
53
+ end
54
+
55
+ protected
56
+
57
+ # @return [ActiveStorage::Blob]
58
+ def file
59
+ fragment.attachments.first
60
+ end
61
+
62
+ # @return [String]
63
+ def label
64
+ @label || file&.filename
65
+ end
66
+ end
67
+
68
+ ComfortableMediaSurfer::Content::Renderer.register_tag(
69
+ :file, ComfortableMediaSurfer::Content::Tags::File
70
+ )
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'mixins/file_content'
4
+
5
+ # This is how you link previously uploaded file to anywhere. Good example may be
6
+ # a header image you want to use on the layout level.
7
+ # {{cms:file_link id, as: image}}
8
+ #
9
+ # `as` - url (default) | link | image - how file gets rendered out
10
+ # `class` - any html classes that you want on the result link or image tag. For example "class1 class2"
11
+ #
12
+ # - variant_attrs are not functional, perhaps due to some change in ImageMagick
13
+ # - Simply use a class in your CSS / SASS to style your image display
14
+ # `label` - attach label attribute to link or image tag
15
+ # `resize` - imagemagick option. For example: "100x50>"
16
+ # `gravity` - imagemagick option. For example: "center"
17
+ # `crop` - imagemagick option. For example: "100x50+0+0"
18
+ #
19
+ class ComfortableMediaSurfer::Content::Tags::FileLink < ComfortableMediaSurfer::Content::Tag
20
+ include ComfortableMediaSurfer::Content::Tags::Mixins::FileContent
21
+
22
+ attr_reader :identifier, :as, :variant_attrs
23
+
24
+ def initialize(context:, params: [], source: nil)
25
+ super
26
+
27
+ options = params.extract_options!
28
+ @identifier = params[0]
29
+ @as = options['as'] || 'url'
30
+ @class = options['class']
31
+ @variant_attrs = options.slice('resize', 'gravity', 'crop') # broken for ImageMagick
32
+
33
+ return if @identifier.present?
34
+
35
+ raise Error, 'Missing identifier for file link tag'
36
+ end
37
+
38
+ # @return [Comfy::Cms::File]
39
+ def file_record
40
+ @file_record ||= context.site.files.detect { |f| f.id == identifier.to_i }
41
+ end
42
+
43
+ # @return [ActiveStorage::Blob]
44
+ def file
45
+ file_record&.attachment
46
+ end
47
+
48
+ # @return [String]
49
+ def label
50
+ return '' if file_record.nil?
51
+
52
+ file_record.label.presence || file.filename.to_s
53
+ end
54
+ end
55
+
56
+ ComfortableMediaSurfer::Content::Renderer.register_tag(
57
+ :file_link, ComfortableMediaSurfer::Content::Tags::FileLink
58
+ )
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Same tag as File, only it handles multiple attachments.
4
+ # Generally not a bad idea to handle rendering of this in a partial/helper.
5
+ # Example tag:
6
+ # {{ cms:files identifier }}
7
+ #
8
+ class ComfortableMediaSurfer::Content::Tags::Files < ComfortableMediaSurfer::Content::Tags::File
9
+ def content
10
+ return '' if fragment.attachments.blank?
11
+
12
+ fragment.attachments.collect do |attachment|
13
+ super(file: attachment, label: attachment.filename)
14
+ end.join(' ')
15
+ end
16
+
17
+ def form_field(object_name, view, index)
18
+ name = "#{object_name}[fragments_attributes][#{index}][files][]"
19
+ input = view.send(:file_field_tag, name, id: form_field_id, multiple: true, class: 'form-control')
20
+
21
+ attachments_partial =
22
+ if fragment.attachments
23
+ view.render(
24
+ partial: 'comfy/admin/cms/fragments/form_fragment_attachments',
25
+ locals: {
26
+ object_name: object_name,
27
+ index: index,
28
+ attachments: fragment.attachments,
29
+ fragment_id: identifier,
30
+ multiple: true
31
+ }
32
+ )
33
+ end
34
+
35
+ yield view.safe_join([input, attachments_partial], '')
36
+ end
37
+ end
38
+
39
+ ComfortableMediaSurfer::Content::Renderer.register_tag(
40
+ :files, ComfortableMediaSurfer::Content::Tags::Files
41
+ )
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Base Tag class that other fragment tags depend on.
4
+ # Tag handles following options:
5
+ # `render`: true (default) | false
6
+ # do we want to render this content on the page, or manually access it via
7
+ # helpers. Good example would be content for meta tags.
8
+ # `namespace`:
9
+ # Just a string that allows grouping of form elements in the admin area
10
+ #
11
+ class ComfortableMediaSurfer::Content::Tags::Fragment < ComfortableMediaSurfer::Content::Tag
12
+ attr_accessor :renderable
13
+ attr_reader :identifier, :namespace
14
+
15
+ # @type [{String => String}]
16
+ attr_reader :options
17
+
18
+ def initialize(context:, params: [], source: nil)
19
+ super
20
+
21
+ @options = params.extract_options!
22
+ @identifier = params[0]
23
+
24
+ unless @identifier.present?
25
+ raise Error, "Missing identifier for fragment tag: #{source}"
26
+ end
27
+
28
+ @namespace = @options['namespace'] || 'default'
29
+ @renderable = @options['render'].to_s.downcase != 'false'
30
+ end
31
+
32
+ # Grabs existing fragment record or spins up a new instance if there's none
33
+ # @return [Comfy::Cms::Fragment]
34
+ def fragment
35
+ context.fragments.detect { |f| f.identifier == identifier } ||
36
+ context.fragments.build(identifier: identifier)
37
+ end
38
+
39
+ def content
40
+ fragment.content
41
+ end
42
+
43
+ # If `render: false` was passed in we won't render anything. Assuming that
44
+ # that fragment content will be rendered manually
45
+ def render
46
+ renderable ? content : ''
47
+ end
48
+
49
+ # Tag renders its own form inputs via `form_field(template, index)`
50
+ # For example:
51
+ # class MyTag < ComfortableMediaSurfer::Content::Tags::Fragment
52
+ # def form_field(view, index, &block)
53
+ # # omit yield if you don't want default wrapper
54
+ # yield view.text_area "input_name", "value"
55
+ # end
56
+ # end
57
+ def form_field
58
+ raise 'Form field rendering not implemented for this Tag'
59
+ end
60
+
61
+ def form_field_id
62
+ "fragment-#{@identifier}"
63
+ end
64
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Tag for injecting view helpers. Example tag:
4
+ # {{cms:helper method_name, param_a, param_b, foo: bar}}
5
+ # This expands into something like this:
6
+ # <%= method_name("param_a", "param_b", "foo" => "bar") %>
7
+ # Whitelist is can be used to control what helpers are available.
8
+ # By default there's a blacklist of methods that should not be called.
9
+ #
10
+ class ComfortableMediaSurfer::Content::Tags::Helper < ComfortableMediaSurfer::Content::Tag
11
+ BLACKLIST = %w[eval class_eval instance_eval render].freeze
12
+
13
+ attr_reader :method_name
14
+
15
+ def initialize(context:, params: [], source: nil)
16
+ super
17
+ @method_name = params.shift
18
+
19
+ return if @method_name.present?
20
+
21
+ raise Error, 'Missing method name for helper tag'
22
+ end
23
+
24
+ # we output erb into rest of the content
25
+ def allow_erb?
26
+ true
27
+ end
28
+
29
+ def content
30
+ helper_params = params.map do |p|
31
+ case p
32
+ when Hash
33
+ format('%<arg>s', arg: p)
34
+ else
35
+ format('%<arg>p', arg: p)
36
+ end
37
+ end.join(',')
38
+ "<%= #{method_name}(#{helper_params}) %>"
39
+ end
40
+
41
+ def render
42
+ whitelist = ComfortableMediaSurfer.config.allowed_helpers
43
+ if whitelist.is_a?(Array)
44
+ content if whitelist.map!(&:to_s).member?(method_name)
45
+ else
46
+ content unless BLACKLIST.member?(method_name)
47
+ end
48
+ end
49
+ end
50
+
51
+ ComfortableMediaSurfer::Content::Renderer.register_tag(
52
+ :helper, ComfortableMediaSurfer::Content::Tags::Helper
53
+ )
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'mixins/file_content'
4
+
5
+ # This is like the the file_link tag, but specifically for images
6
+ # Identify the image by its label {{ cms:image label }}
7
+ #
8
+ # `class` - any html classes that you want on the image tag. For example "class1 class2"
9
+ #
10
+ # - variant_attrs are not functional, perhaps due to some change in ImageMagick
11
+ # - Simply use a class in your CSS / SASS to style your image display
12
+ # `label` - attach label attribute to link or image tag
13
+ # `resize` - imagemagick option. For example: "100x50>"
14
+ # `gravity` - imagemagick option. For example: "center"
15
+ # `crop` - imagemagick option. For example: "100x50+0+0"
16
+
17
+ class ComfortableMediaSurfer::Content::Tags::Image < ComfortableMediaSurfer::Content::Tag
18
+ include ComfortableMediaSurfer::Content::Tags::Mixins::FileContent
19
+
20
+ attr_reader :identifier, :as, :variant_attrs
21
+
22
+ def initialize(context:, params: [], source: nil)
23
+ super
24
+
25
+ options = params.extract_options!
26
+ @identifier = params[0]
27
+ @as = 'image'
28
+ @class = options['class']
29
+ @variant_attrs = options.slice('resize', 'gravity', 'crop') # broken for ImageMagick
30
+
31
+ return if @identifier.present?
32
+
33
+ raise Error, 'Missing identifier label for image tag'
34
+ end
35
+
36
+ # @return [Comfy::Cms::File]
37
+ def file_record
38
+ @file_record ||= context.site.files.detect { |f| f.label == identifier }
39
+ end
40
+
41
+ # @return [ActiveStorage::Blob]
42
+ def file
43
+ file_record&.attachment
44
+ end
45
+
46
+ # @return [String]
47
+ def label
48
+ return '' if file_record.nil?
49
+
50
+ file_record.label.presence || file.filename.to_s
51
+ end
52
+ end
53
+
54
+ ComfortableMediaSurfer::Content::Renderer.register_tag(
55
+ :image, ComfortableMediaSurfer::Content::Tags::Image
56
+ )
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Tag for text content that is going to be rendered using textarea with markdown
4
+ # {{ cms:markdown identifier }}
5
+ #
6
+ class ComfortableMediaSurfer::Content::Tags::Markdown < ComfortableMediaSurfer::Content::Tags::Fragment
7
+ def render
8
+ renderable ? Kramdown::Document.new(content.to_s).to_html : ''
9
+ end
10
+
11
+ def form_field(object_name, view, index)
12
+ name = "#{object_name}[fragments_attributes][#{index}][content]"
13
+ options = { id: form_field_id, data: { 'cms-cm-mode' => 'text/x-markdown' } }
14
+ input = view.send(:text_area_tag, name, content, options)
15
+
16
+ yield input
17
+ end
18
+ end
19
+
20
+ ComfortableMediaSurfer::Content::Renderer.register_tag(
21
+ :markdown, ComfortableMediaSurfer::Content::Tags::Markdown
22
+ )