occams 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (471) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +4 -0
  3. data/.gitattributes +2 -0
  4. data/.github/issue_template.md +22 -0
  5. data/.github/pull_request_template.md +6 -0
  6. data/.gitignore +21 -0
  7. data/.rubocop.yml +87 -0
  8. data/.travis.yml +44 -0
  9. data/CHANGELOG.md +7 -0
  10. data/CONTRIBUTING.md +35 -0
  11. data/Gemfile +30 -0
  12. data/LICENSE +20 -0
  13. data/LICENSE.comfy +20 -0
  14. data/README.md +121 -0
  15. data/Rakefile +5 -0
  16. data/app/assets/config/manifest.js +0 -0
  17. data/app/assets/fonts/occams/admin/cms/lib/redactor-font.eot +0 -0
  18. data/app/assets/javascripts/occams/admin/cms/application.js +39 -0
  19. data/app/assets/javascripts/occams/admin/cms/base.js +46 -0
  20. data/app/assets/javascripts/occams/admin/cms/categories.js +17 -0
  21. data/app/assets/javascripts/occams/admin/cms/codemirror.js +31 -0
  22. data/app/assets/javascripts/occams/admin/cms/custom.js +1 -0
  23. data/app/assets/javascripts/occams/admin/cms/diff.js +10 -0
  24. data/app/assets/javascripts/occams/admin/cms/file_link.js +67 -0
  25. data/app/assets/javascripts/occams/admin/cms/file_upload.js +194 -0
  26. data/app/assets/javascripts/occams/admin/cms/files_modal.js +40 -0
  27. data/app/assets/javascripts/occams/admin/cms/page_fragments.js +22 -0
  28. data/app/assets/javascripts/occams/admin/cms/slugify.js +34 -0
  29. data/app/assets/javascripts/occams/admin/cms/sortable_list.js +40 -0
  30. data/app/assets/javascripts/occams/admin/cms/timepicker.js +30 -0
  31. data/app/assets/javascripts/occams/admin/cms/wysiwyg.js +72 -0
  32. data/app/assets/javascripts/occams/vendor/Moxie.swf +0 -0
  33. data/app/assets/javascripts/occams/vendor/Moxie.xap +0 -0
  34. data/app/assets/javascripts/occams/vendor/bootstrap.bundle.min.js +7 -0
  35. data/app/assets/javascripts/occams/vendor/bootstrap.bundle.min.js.map +1 -0
  36. data/app/assets/javascripts/occams/vendor/codemirror/addon/edit/closetag.js +169 -0
  37. data/app/assets/javascripts/occams/vendor/codemirror/mode/css/css.js +832 -0
  38. data/app/assets/javascripts/occams/vendor/codemirror/mode/htmlmixed/htmlmixed.js +152 -0
  39. data/app/assets/javascripts/occams/vendor/codemirror/mode/javascript/javascript.js +875 -0
  40. data/app/assets/javascripts/occams/vendor/codemirror/mode/markdown/markdown.js +861 -0
  41. data/app/assets/javascripts/occams/vendor/codemirror/mode/xml/xml.js +394 -0
  42. data/app/assets/javascripts/occams/vendor/codemirror.js +9653 -0
  43. data/app/assets/javascripts/occams/vendor/diff/diff_match_patch.min.js +49 -0
  44. data/app/assets/javascripts/occams/vendor/diff/pretty_text_diff.js +76 -0
  45. data/app/assets/javascripts/occams/vendor/flatpickr/i18n/ar.js +52 -0
  46. data/app/assets/javascripts/occams/vendor/flatpickr/i18n/bg.js +65 -0
  47. data/app/assets/javascripts/occams/vendor/flatpickr/i18n/bn.js +65 -0
  48. data/app/assets/javascripts/occams/vendor/flatpickr/i18n/ca.js +83 -0
  49. data/app/assets/javascripts/occams/vendor/flatpickr/i18n/cs.js +70 -0
  50. data/app/assets/javascripts/occams/vendor/flatpickr/i18n/cy.js +92 -0
  51. data/app/assets/javascripts/occams/vendor/flatpickr/i18n/da.js +71 -0
  52. data/app/assets/javascripts/occams/vendor/flatpickr/i18n/de.js +70 -0
  53. data/app/assets/javascripts/occams/vendor/flatpickr/i18n/default.js +80 -0
  54. data/app/assets/javascripts/occams/vendor/flatpickr/i18n/eo.js +73 -0
  55. data/app/assets/javascripts/occams/vendor/flatpickr/i18n/es.js +69 -0
  56. data/app/assets/javascripts/occams/vendor/flatpickr/i18n/et.js +73 -0
  57. data/app/assets/javascripts/occams/vendor/flatpickr/i18n/fa.js +68 -0
  58. data/app/assets/javascripts/occams/vendor/flatpickr/i18n/fi.js +69 -0
  59. data/app/assets/javascripts/occams/vendor/flatpickr/i18n/fr.js +75 -0
  60. data/app/assets/javascripts/occams/vendor/flatpickr/i18n/gr.js +74 -0
  61. data/app/assets/javascripts/occams/vendor/flatpickr/i18n/he.js +57 -0
  62. data/app/assets/javascripts/occams/vendor/flatpickr/i18n/hi.js +65 -0
  63. data/app/assets/javascripts/occams/vendor/flatpickr/i18n/hr.js +66 -0
  64. data/app/assets/javascripts/occams/vendor/flatpickr/i18n/hu.js +72 -0
  65. data/app/assets/javascripts/occams/vendor/flatpickr/i18n/id.js +61 -0
  66. data/app/assets/javascripts/occams/vendor/flatpickr/i18n/it.js +70 -0
  67. data/app/assets/javascripts/occams/vendor/flatpickr/i18n/ja.js +57 -0
  68. data/app/assets/javascripts/occams/vendor/flatpickr/i18n/ko.js +60 -0
  69. data/app/assets/javascripts/occams/vendor/flatpickr/i18n/lt.js +72 -0
  70. data/app/assets/javascripts/occams/vendor/flatpickr/i18n/lv.js +67 -0
  71. data/app/assets/javascripts/occams/vendor/flatpickr/i18n/mk.js +69 -0
  72. data/app/assets/javascripts/occams/vendor/flatpickr/i18n/mn.js +67 -0
  73. data/app/assets/javascripts/occams/vendor/flatpickr/i18n/ms.js +68 -0
  74. data/app/assets/javascripts/occams/vendor/flatpickr/i18n/my.js +69 -0
  75. data/app/assets/javascripts/occams/vendor/flatpickr/i18n/nl.js +75 -0
  76. data/app/assets/javascripts/occams/vendor/flatpickr/i18n/no.js +73 -0
  77. data/app/assets/javascripts/occams/vendor/flatpickr/i18n/pa.js +65 -0
  78. data/app/assets/javascripts/occams/vendor/flatpickr/i18n/pl.js +68 -0
  79. data/app/assets/javascripts/occams/vendor/flatpickr/i18n/pt-BR.js +66 -0
  80. data/app/assets/javascripts/occams/vendor/flatpickr/i18n/pt.js +66 -0
  81. data/app/assets/javascripts/occams/vendor/flatpickr/i18n/ro.js +69 -0
  82. data/app/assets/javascripts/occams/vendor/flatpickr/i18n/ru.js +66 -0
  83. data/app/assets/javascripts/occams/vendor/flatpickr/i18n/si.js +65 -0
  84. data/app/assets/javascripts/occams/vendor/flatpickr/i18n/sk.js +70 -0
  85. data/app/assets/javascripts/occams/vendor/flatpickr/i18n/sl.js +70 -0
  86. data/app/assets/javascripts/occams/vendor/flatpickr/i18n/sq.js +65 -0
  87. data/app/assets/javascripts/occams/vendor/flatpickr/i18n/sr.js +69 -0
  88. data/app/assets/javascripts/occams/vendor/flatpickr/i18n/sv.js +70 -0
  89. data/app/assets/javascripts/occams/vendor/flatpickr/i18n/th.js +72 -0
  90. data/app/assets/javascripts/occams/vendor/flatpickr/i18n/tr.js +66 -0
  91. data/app/assets/javascripts/occams/vendor/flatpickr/i18n/uk.js +66 -0
  92. data/app/assets/javascripts/occams/vendor/flatpickr/i18n/vn.js +66 -0
  93. data/app/assets/javascripts/occams/vendor/flatpickr/i18n/zh-CN.js +61 -0
  94. data/app/assets/javascripts/occams/vendor/flatpickr/i18n/zh-TW.js +61 -0
  95. data/app/assets/javascripts/occams/vendor/flatpickr.min.js +2 -0
  96. data/app/assets/javascripts/occams/vendor/fontawesome.js +5 -0
  97. data/app/assets/javascripts/occams/vendor/moxie.min.js +16 -0
  98. data/app/assets/javascripts/occams/vendor/plupload.dev.js +2497 -0
  99. data/app/assets/javascripts/occams/vendor/redactor/definedlinks.js +53 -0
  100. data/app/assets/javascripts/occams/vendor/redactor/filemanager.js +64 -0
  101. data/app/assets/javascripts/occams/vendor/redactor/i18n/ar.js +76 -0
  102. data/app/assets/javascripts/occams/vendor/redactor/i18n/az.js +75 -0
  103. data/app/assets/javascripts/occams/vendor/redactor/i18n/ba.js +79 -0
  104. data/app/assets/javascripts/occams/vendor/redactor/i18n/bg.js +77 -0
  105. data/app/assets/javascripts/occams/vendor/redactor/i18n/by.js +77 -0
  106. data/app/assets/javascripts/occams/vendor/redactor/i18n/ca.js +75 -0
  107. data/app/assets/javascripts/occams/vendor/redactor/i18n/cs.js +87 -0
  108. data/app/assets/javascripts/occams/vendor/redactor/i18n/da.js +75 -0
  109. data/app/assets/javascripts/occams/vendor/redactor/i18n/de.js +80 -0
  110. data/app/assets/javascripts/occams/vendor/redactor/i18n/el.js +76 -0
  111. data/app/assets/javascripts/occams/vendor/redactor/i18n/en.js +75 -0
  112. data/app/assets/javascripts/occams/vendor/redactor/i18n/eo.js +76 -0
  113. data/app/assets/javascripts/occams/vendor/redactor/i18n/es.js +75 -0
  114. data/app/assets/javascripts/occams/vendor/redactor/i18n/es_AR.js +76 -0
  115. data/app/assets/javascripts/occams/vendor/redactor/i18n/fa.js +76 -0
  116. data/app/assets/javascripts/occams/vendor/redactor/i18n/fi.js +75 -0
  117. data/app/assets/javascripts/occams/vendor/redactor/i18n/fr.js +75 -0
  118. data/app/assets/javascripts/occams/vendor/redactor/i18n/ge.js +75 -0
  119. data/app/assets/javascripts/occams/vendor/redactor/i18n/gr.js +75 -0
  120. data/app/assets/javascripts/occams/vendor/redactor/i18n/he.js +75 -0
  121. data/app/assets/javascripts/occams/vendor/redactor/i18n/hr.js +76 -0
  122. data/app/assets/javascripts/occams/vendor/redactor/i18n/hu.js +77 -0
  123. data/app/assets/javascripts/occams/vendor/redactor/i18n/id.js +76 -0
  124. data/app/assets/javascripts/occams/vendor/redactor/i18n/it.js +78 -0
  125. data/app/assets/javascripts/occams/vendor/redactor/i18n/ja.js +76 -0
  126. data/app/assets/javascripts/occams/vendor/redactor/i18n/kn.js +75 -0
  127. data/app/assets/javascripts/occams/vendor/redactor/i18n/ko.js +76 -0
  128. data/app/assets/javascripts/occams/vendor/redactor/i18n/lt.js +75 -0
  129. data/app/assets/javascripts/occams/vendor/redactor/i18n/lv.js +75 -0
  130. data/app/assets/javascripts/occams/vendor/redactor/i18n/mk.js +75 -0
  131. data/app/assets/javascripts/occams/vendor/redactor/i18n/nb.js +75 -0
  132. data/app/assets/javascripts/occams/vendor/redactor/i18n/nl.js +80 -0
  133. data/app/assets/javascripts/occams/vendor/redactor/i18n/pl.js +76 -0
  134. data/app/assets/javascripts/occams/vendor/redactor/i18n/pt-BR.js +75 -0
  135. data/app/assets/javascripts/occams/vendor/redactor/i18n/pt.js +75 -0
  136. data/app/assets/javascripts/occams/vendor/redactor/i18n/ro.js +76 -0
  137. data/app/assets/javascripts/occams/vendor/redactor/i18n/ru.js +76 -0
  138. data/app/assets/javascripts/occams/vendor/redactor/i18n/sk.js +76 -0
  139. data/app/assets/javascripts/occams/vendor/redactor/i18n/sl.js +79 -0
  140. data/app/assets/javascripts/occams/vendor/redactor/i18n/sq.js +79 -0
  141. data/app/assets/javascripts/occams/vendor/redactor/i18n/sr-CIR.js +79 -0
  142. data/app/assets/javascripts/occams/vendor/redactor/i18n/sr-LAT.js +79 -0
  143. data/app/assets/javascripts/occams/vendor/redactor/i18n/sv.js +74 -0
  144. data/app/assets/javascripts/occams/vendor/redactor/i18n/th.js +74 -0
  145. data/app/assets/javascripts/occams/vendor/redactor/i18n/tr.js +75 -0
  146. data/app/assets/javascripts/occams/vendor/redactor/i18n/ua.js +77 -0
  147. data/app/assets/javascripts/occams/vendor/redactor/i18n/uk.js +77 -0
  148. data/app/assets/javascripts/occams/vendor/redactor/i18n/vi.js +74 -0
  149. data/app/assets/javascripts/occams/vendor/redactor/i18n/zh-CN.js +75 -0
  150. data/app/assets/javascripts/occams/vendor/redactor/i18n/zh-TW.js +75 -0
  151. data/app/assets/javascripts/occams/vendor/redactor/imagemanager.js +57 -0
  152. data/app/assets/javascripts/occams/vendor/redactor/table.js +337 -0
  153. data/app/assets/javascripts/occams/vendor/redactor/video.js +77 -0
  154. data/app/assets/javascripts/occams/vendor/redactor.js +9561 -0
  155. data/app/assets/javascripts/occams/vendor/sortable.min.js +5 -0
  156. data/app/assets/stylesheets/occams/admin/cms/application.sass +11 -0
  157. data/app/assets/stylesheets/occams/admin/cms/base.sass +256 -0
  158. data/app/assets/stylesheets/occams/admin/cms/codemirror_overrides.sass +19 -0
  159. data/app/assets/stylesheets/occams/admin/cms/custom.sass +1 -0
  160. data/app/assets/stylesheets/occams/admin/cms/redactor_overrides.sass +22 -0
  161. data/app/assets/stylesheets/occams/vendor/bootstrap/_alert.scss +51 -0
  162. data/app/assets/stylesheets/occams/vendor/bootstrap/_badge.scss +54 -0
  163. data/app/assets/stylesheets/occams/vendor/bootstrap/_breadcrumb.scss +41 -0
  164. data/app/assets/stylesheets/occams/vendor/bootstrap/_button-group.scss +163 -0
  165. data/app/assets/stylesheets/occams/vendor/bootstrap/_buttons.scss +137 -0
  166. data/app/assets/stylesheets/occams/vendor/bootstrap/_card.scss +289 -0
  167. data/app/assets/stylesheets/occams/vendor/bootstrap/_carousel.scss +197 -0
  168. data/app/assets/stylesheets/occams/vendor/bootstrap/_close.scss +41 -0
  169. data/app/assets/stylesheets/occams/vendor/bootstrap/_code.scss +48 -0
  170. data/app/assets/stylesheets/occams/vendor/bootstrap/_custom-forms.scss +507 -0
  171. data/app/assets/stylesheets/occams/vendor/bootstrap/_dropdown.scss +191 -0
  172. data/app/assets/stylesheets/occams/vendor/bootstrap/_forms.scss +330 -0
  173. data/app/assets/stylesheets/occams/vendor/bootstrap/_functions.scss +86 -0
  174. data/app/assets/stylesheets/occams/vendor/bootstrap/_grid.scss +52 -0
  175. data/app/assets/stylesheets/occams/vendor/bootstrap/_images.scss +42 -0
  176. data/app/assets/stylesheets/occams/vendor/bootstrap/_input-group.scss +193 -0
  177. data/app/assets/stylesheets/occams/vendor/bootstrap/_jumbotron.scss +17 -0
  178. data/app/assets/stylesheets/occams/vendor/bootstrap/_list-group.scss +149 -0
  179. data/app/assets/stylesheets/occams/vendor/bootstrap/_media.scss +8 -0
  180. data/app/assets/stylesheets/occams/vendor/bootstrap/_mixins.scss +47 -0
  181. data/app/assets/stylesheets/occams/vendor/bootstrap/_modal.scss +229 -0
  182. data/app/assets/stylesheets/occams/vendor/bootstrap/_nav.scss +120 -0
  183. data/app/assets/stylesheets/occams/vendor/bootstrap/_navbar.scss +294 -0
  184. data/app/assets/stylesheets/occams/vendor/bootstrap/_pagination.scss +73 -0
  185. data/app/assets/stylesheets/occams/vendor/bootstrap/_popover.scss +171 -0
  186. data/app/assets/stylesheets/occams/vendor/bootstrap/_print.scss +141 -0
  187. data/app/assets/stylesheets/occams/vendor/bootstrap/_progress.scss +43 -0
  188. data/app/assets/stylesheets/occams/vendor/bootstrap/_reboot.scss +483 -0
  189. data/app/assets/stylesheets/occams/vendor/bootstrap/_root.scss +19 -0
  190. data/app/assets/stylesheets/occams/vendor/bootstrap/_spinners.scss +55 -0
  191. data/app/assets/stylesheets/occams/vendor/bootstrap/_tables.scss +185 -0
  192. data/app/assets/stylesheets/occams/vendor/bootstrap/_toasts.scss +44 -0
  193. data/app/assets/stylesheets/occams/vendor/bootstrap/_tooltip.scss +115 -0
  194. data/app/assets/stylesheets/occams/vendor/bootstrap/_transitions.scss +20 -0
  195. data/app/assets/stylesheets/occams/vendor/bootstrap/_type.scss +125 -0
  196. data/app/assets/stylesheets/occams/vendor/bootstrap/_utilities.scss +17 -0
  197. data/app/assets/stylesheets/occams/vendor/bootstrap/_variables.scss +1123 -0
  198. data/app/assets/stylesheets/occams/vendor/bootstrap/bootstrap-grid.scss +29 -0
  199. data/app/assets/stylesheets/occams/vendor/bootstrap/bootstrap-reboot.scss +12 -0
  200. data/app/assets/stylesheets/occams/vendor/bootstrap/bootstrap.scss +44 -0
  201. data/app/assets/stylesheets/occams/vendor/bootstrap/mixins/_alert.scss +13 -0
  202. data/app/assets/stylesheets/occams/vendor/bootstrap/mixins/_background-variant.scss +21 -0
  203. data/app/assets/stylesheets/occams/vendor/bootstrap/mixins/_badge.scss +17 -0
  204. data/app/assets/stylesheets/occams/vendor/bootstrap/mixins/_border-radius.scss +63 -0
  205. data/app/assets/stylesheets/occams/vendor/bootstrap/mixins/_box-shadow.scss +20 -0
  206. data/app/assets/stylesheets/occams/vendor/bootstrap/mixins/_breakpoints.scss +123 -0
  207. data/app/assets/stylesheets/occams/vendor/bootstrap/mixins/_buttons.scss +107 -0
  208. data/app/assets/stylesheets/occams/vendor/bootstrap/mixins/_caret.scss +62 -0
  209. data/app/assets/stylesheets/occams/vendor/bootstrap/mixins/_clearfix.scss +7 -0
  210. data/app/assets/stylesheets/occams/vendor/bootstrap/mixins/_deprecate.scss +10 -0
  211. data/app/assets/stylesheets/occams/vendor/bootstrap/mixins/_float.scss +14 -0
  212. data/app/assets/stylesheets/occams/vendor/bootstrap/mixins/_forms.scss +192 -0
  213. data/app/assets/stylesheets/occams/vendor/bootstrap/mixins/_gradients.scss +45 -0
  214. data/app/assets/stylesheets/occams/vendor/bootstrap/mixins/_grid-framework.scss +66 -0
  215. data/app/assets/stylesheets/occams/vendor/bootstrap/mixins/_grid.scss +51 -0
  216. data/app/assets/stylesheets/occams/vendor/bootstrap/mixins/_hover.scss +37 -0
  217. data/app/assets/stylesheets/occams/vendor/bootstrap/mixins/_image.scss +36 -0
  218. data/app/assets/stylesheets/occams/vendor/bootstrap/mixins/_list-group.scss +21 -0
  219. data/app/assets/stylesheets/occams/vendor/bootstrap/mixins/_lists.scss +7 -0
  220. data/app/assets/stylesheets/occams/vendor/bootstrap/mixins/_nav-divider.scss +10 -0
  221. data/app/assets/stylesheets/occams/vendor/bootstrap/mixins/_pagination.scss +22 -0
  222. data/app/assets/stylesheets/occams/vendor/bootstrap/mixins/_reset-text.scss +17 -0
  223. data/app/assets/stylesheets/occams/vendor/bootstrap/mixins/_resize.scss +6 -0
  224. data/app/assets/stylesheets/occams/vendor/bootstrap/mixins/_screen-reader.scss +33 -0
  225. data/app/assets/stylesheets/occams/vendor/bootstrap/mixins/_size.scss +7 -0
  226. data/app/assets/stylesheets/occams/vendor/bootstrap/mixins/_table-row.scss +39 -0
  227. data/app/assets/stylesheets/occams/vendor/bootstrap/mixins/_text-emphasis.scss +16 -0
  228. data/app/assets/stylesheets/occams/vendor/bootstrap/mixins/_text-hide.scss +11 -0
  229. data/app/assets/stylesheets/occams/vendor/bootstrap/mixins/_text-truncate.scss +8 -0
  230. data/app/assets/stylesheets/occams/vendor/bootstrap/mixins/_transition.scss +16 -0
  231. data/app/assets/stylesheets/occams/vendor/bootstrap/mixins/_visibility.scss +8 -0
  232. data/app/assets/stylesheets/occams/vendor/bootstrap/utilities/_align.scss +8 -0
  233. data/app/assets/stylesheets/occams/vendor/bootstrap/utilities/_background.scss +19 -0
  234. data/app/assets/stylesheets/occams/vendor/bootstrap/utilities/_borders.scss +75 -0
  235. data/app/assets/stylesheets/occams/vendor/bootstrap/utilities/_clearfix.scss +3 -0
  236. data/app/assets/stylesheets/occams/vendor/bootstrap/utilities/_display.scss +26 -0
  237. data/app/assets/stylesheets/occams/vendor/bootstrap/utilities/_embed.scss +39 -0
  238. data/app/assets/stylesheets/occams/vendor/bootstrap/utilities/_flex.scss +51 -0
  239. data/app/assets/stylesheets/occams/vendor/bootstrap/utilities/_float.scss +11 -0
  240. data/app/assets/stylesheets/occams/vendor/bootstrap/utilities/_overflow.scss +5 -0
  241. data/app/assets/stylesheets/occams/vendor/bootstrap/utilities/_position.scss +32 -0
  242. data/app/assets/stylesheets/occams/vendor/bootstrap/utilities/_screenreaders.scss +11 -0
  243. data/app/assets/stylesheets/occams/vendor/bootstrap/utilities/_shadows.scss +6 -0
  244. data/app/assets/stylesheets/occams/vendor/bootstrap/utilities/_sizing.scss +20 -0
  245. data/app/assets/stylesheets/occams/vendor/bootstrap/utilities/_spacing.scss +73 -0
  246. data/app/assets/stylesheets/occams/vendor/bootstrap/utilities/_stretched-link.scss +19 -0
  247. data/app/assets/stylesheets/occams/vendor/bootstrap/utilities/_text.scss +72 -0
  248. data/app/assets/stylesheets/occams/vendor/bootstrap/utilities/_visibility.scss +13 -0
  249. data/app/assets/stylesheets/occams/vendor/bootstrap/vendor/_rfs.scss +204 -0
  250. data/app/assets/stylesheets/occams/vendor/codemirror.css +346 -0
  251. data/app/assets/stylesheets/occams/vendor/flatpickr.min.css +13 -0
  252. data/app/assets/stylesheets/occams/vendor/fontawesome.css +343 -0
  253. data/app/assets/stylesheets/occams/vendor/redactor.css +948 -0
  254. data/app/controllers/application_controller.rb +7 -0
  255. data/app/controllers/concerns/occams/paginate.rb +16 -0
  256. data/app/controllers/concerns/occams/reorder_action.rb +19 -0
  257. data/app/controllers/occams/admin/base_controller.rb +22 -0
  258. data/app/controllers/occams/admin/cms/base_controller.rb +55 -0
  259. data/app/controllers/occams/admin/cms/categories_controller.rb +40 -0
  260. data/app/controllers/occams/admin/cms/files_controller.rb +142 -0
  261. data/app/controllers/occams/admin/cms/layouts_controller.rb +69 -0
  262. data/app/controllers/occams/admin/cms/pages_controller.rb +156 -0
  263. data/app/controllers/occams/admin/cms/revisions/base_controller.rb +50 -0
  264. data/app/controllers/occams/admin/cms/revisions/layout_controller.rb +18 -0
  265. data/app/controllers/occams/admin/cms/revisions/page_controller.rb +30 -0
  266. data/app/controllers/occams/admin/cms/revisions/snippet_controller.rb +18 -0
  267. data/app/controllers/occams/admin/cms/revisions/translation_controller.rb +31 -0
  268. data/app/controllers/occams/admin/cms/sites_controller.rb +69 -0
  269. data/app/controllers/occams/admin/cms/snippets_controller.rb +66 -0
  270. data/app/controllers/occams/admin/cms/translations_controller.rb +107 -0
  271. data/app/controllers/occams/cms/assets_controller.rb +40 -0
  272. data/app/controllers/occams/cms/base_controller.rb +33 -0
  273. data/app/controllers/occams/cms/content_controller.rb +87 -0
  274. data/app/helpers/occams/admin/cms_helper.rb +49 -0
  275. data/app/helpers/occams/cms_helper.rb +73 -0
  276. data/app/models/concerns/occams/cms/with_categories.rb +53 -0
  277. data/app/models/concerns/occams/cms/with_fragments.rb +125 -0
  278. data/app/models/occams/cms/categorization.rb +16 -0
  279. data/app/models/occams/cms/category.rb +24 -0
  280. data/app/models/occams/cms/file.rb +70 -0
  281. data/app/models/occams/cms/fragment.rb +63 -0
  282. data/app/models/occams/cms/layout.rb +113 -0
  283. data/app/models/occams/cms/page.rb +170 -0
  284. data/app/models/occams/cms/revision.rb +12 -0
  285. data/app/models/occams/cms/site.rb +94 -0
  286. data/app/models/occams/cms/snippet.rb +45 -0
  287. data/app/models/occams/cms/translation.rb +43 -0
  288. data/app/views/kaminari/occams/_first_page.html.haml +3 -0
  289. data/app/views/kaminari/occams/_gap.html.haml +2 -0
  290. data/app/views/kaminari/occams/_last_page.html.haml +3 -0
  291. data/app/views/kaminari/occams/_next_page.html.haml +2 -0
  292. data/app/views/kaminari/occams/_page.html.haml +2 -0
  293. data/app/views/kaminari/occams/_paginator.html.haml +11 -0
  294. data/app/views/kaminari/occams/_prev_page.html.haml +2 -0
  295. data/app/views/layouts/occams/admin/cms/_body.html.haml +14 -0
  296. data/app/views/layouts/occams/admin/cms/_flash.html.haml +4 -0
  297. data/app/views/layouts/occams/admin/cms/_footer_js.html.haml +6 -0
  298. data/app/views/layouts/occams/admin/cms/_head.html.haml +19 -0
  299. data/app/views/layouts/occams/admin/cms/_left.html.haml +39 -0
  300. data/app/views/layouts/occams/admin/cms/_right.html.haml +5 -0
  301. data/app/views/layouts/occams/admin/cms.html.haml +4 -0
  302. data/app/views/occams/admin/cms/categories/_categories.html.haml +4 -0
  303. data/app/views/occams/admin/cms/categories/_edit.html.haml +7 -0
  304. data/app/views/occams/admin/cms/categories/_form.html.haml +5 -0
  305. data/app/views/occams/admin/cms/categories/_index.html.haml +28 -0
  306. data/app/views/occams/admin/cms/categories/_show.html.haml +15 -0
  307. data/app/views/occams/admin/cms/categories/create.js.erb +7 -0
  308. data/app/views/occams/admin/cms/categories/destroy.js.erb +8 -0
  309. data/app/views/occams/admin/cms/categories/edit.js.erb +3 -0
  310. data/app/views/occams/admin/cms/categories/update.js.erb +6 -0
  311. data/app/views/occams/admin/cms/files/_file.html.haml +31 -0
  312. data/app/views/occams/admin/cms/files/_form.html.haml +26 -0
  313. data/app/views/occams/admin/cms/files/_modal.html.haml +3 -0
  314. data/app/views/occams/admin/cms/files/destroy.js.erb +4 -0
  315. data/app/views/occams/admin/cms/files/edit.html.haml +5 -0
  316. data/app/views/occams/admin/cms/files/index.html.haml +31 -0
  317. data/app/views/occams/admin/cms/files/new.html.haml +5 -0
  318. data/app/views/occams/admin/cms/fragments/_form_fragment_attachments.html.haml +23 -0
  319. data/app/views/occams/admin/cms/fragments/_form_fragments.html.haml +38 -0
  320. data/app/views/occams/admin/cms/layouts/_form.html.haml +20 -0
  321. data/app/views/occams/admin/cms/layouts/_index_branch.html.haml +26 -0
  322. data/app/views/occams/admin/cms/layouts/edit.html.haml +9 -0
  323. data/app/views/occams/admin/cms/layouts/index.html.haml +10 -0
  324. data/app/views/occams/admin/cms/layouts/new.html.haml +5 -0
  325. data/app/views/occams/admin/cms/pages/_form.html.haml +31 -0
  326. data/app/views/occams/admin/cms/pages/_index_branch.html.haml +44 -0
  327. data/app/views/occams/admin/cms/pages/edit.html.haml +10 -0
  328. data/app/views/occams/admin/cms/pages/index.html.haml +13 -0
  329. data/app/views/occams/admin/cms/pages/new.html.haml +5 -0
  330. data/app/views/occams/admin/cms/pages/toggle_branch.js.erb +13 -0
  331. data/app/views/occams/admin/cms/revisions/_sidebar.html.haml +2 -0
  332. data/app/views/occams/admin/cms/revisions/show.html.haml +36 -0
  333. data/app/views/occams/admin/cms/sites/_form.html.haml +15 -0
  334. data/app/views/occams/admin/cms/sites/edit.html.haml +5 -0
  335. data/app/views/occams/admin/cms/sites/index.html.haml +28 -0
  336. data/app/views/occams/admin/cms/sites/new.html.haml +5 -0
  337. data/app/views/occams/admin/cms/snippets/_form.html.haml +18 -0
  338. data/app/views/occams/admin/cms/snippets/edit.html.haml +9 -0
  339. data/app/views/occams/admin/cms/snippets/index.html.haml +33 -0
  340. data/app/views/occams/admin/cms/snippets/new.html.haml +5 -0
  341. data/app/views/occams/admin/cms/translations/_form.html.haml +20 -0
  342. data/app/views/occams/admin/cms/translations/_sidebar.html.haml +19 -0
  343. data/app/views/occams/admin/cms/translations/edit.html.haml +10 -0
  344. data/app/views/occams/admin/cms/translations/new.html.haml +5 -0
  345. data/bin/bundle +3 -0
  346. data/bin/rails +4 -0
  347. data/bin/rake +4 -0
  348. data/bin/setup +36 -0
  349. data/bin/update +31 -0
  350. data/bin/yarn +11 -0
  351. data/config/application.rb +39 -0
  352. data/config/boot.rb +7 -0
  353. data/config/cms_routes.rb +8 -0
  354. data/config/database.yml +11 -0
  355. data/config/environment.rb +7 -0
  356. data/config/environments/development.rb +59 -0
  357. data/config/environments/test.rb +50 -0
  358. data/config/initializers/occams.rb +122 -0
  359. data/config/locales/ar.yml +262 -0
  360. data/config/locales/ca.yml +262 -0
  361. data/config/locales/cs.yml +262 -0
  362. data/config/locales/da.yml +262 -0
  363. data/config/locales/de.yml +262 -0
  364. data/config/locales/en.yml +262 -0
  365. data/config/locales/es.yml +262 -0
  366. data/config/locales/fi.yml +262 -0
  367. data/config/locales/fr.yml +262 -0
  368. data/config/locales/gr.yml +262 -0
  369. data/config/locales/hr.yml +262 -0
  370. data/config/locales/it.yml +262 -0
  371. data/config/locales/ja.yml +262 -0
  372. data/config/locales/nb.yml +262 -0
  373. data/config/locales/nl.yml +262 -0
  374. data/config/locales/pl.yml +262 -0
  375. data/config/locales/pt-BR.yml +262 -0
  376. data/config/locales/ru.yml +262 -0
  377. data/config/locales/sk.yml +262 -0
  378. data/config/locales/sv.yml +262 -0
  379. data/config/locales/tr.yml +262 -0
  380. data/config/locales/uk.yml +262 -0
  381. data/config/locales/zh-CN.yml +262 -0
  382. data/config/locales/zh-TW.yml +262 -0
  383. data/config/storage.yml +35 -0
  384. data/config.ru +6 -0
  385. data/db/cms_seeds/sample-site/files/_default.jpg.yml +5 -0
  386. data/db/cms_seeds/sample-site/files/default.jpg +0 -0
  387. data/db/cms_seeds/sample-site/layouts/default/content.html +16 -0
  388. data/db/cms_seeds/sample-site/layouts/default/nested/content.html +14 -0
  389. data/db/cms_seeds/sample-site/pages/index/child_a/content.html +7 -0
  390. data/db/cms_seeds/sample-site/pages/index/child_b/content.html +6 -0
  391. data/db/cms_seeds/sample-site/pages/index/cms logo.png +0 -0
  392. data/db/cms_seeds/sample-site/pages/index/content.es.html +6 -0
  393. data/db/cms_seeds/sample-site/pages/index/content.fr.html +6 -0
  394. data/db/cms_seeds/sample-site/pages/index/content.html +25 -0
  395. data/db/cms_seeds/sample-site/pages/index/footer.png +0 -0
  396. data/db/cms_seeds/sample-site/pages/index/header.png +0 -0
  397. data/db/cms_seeds/sample-site/snippets/default.html +8 -0
  398. data/db/migrate/00_create_active_storage_tables.rb +34 -0
  399. data/db/migrate/01_create_cms.rb +143 -0
  400. data/lib/generators/occams/cms/README +17 -0
  401. data/lib/generators/occams/cms/assets_generator.rb +18 -0
  402. data/lib/generators/occams/cms/cms_generator.rb +69 -0
  403. data/lib/generators/occams/cms/controllers_generator.rb +17 -0
  404. data/lib/generators/occams/cms/models_generator.rb +17 -0
  405. data/lib/generators/occams/cms/views_generator.rb +17 -0
  406. data/lib/generators/occams/scaffold/scaffold_generator.rb +80 -0
  407. data/lib/generators/occams/scaffold/templates/controller.rb.tt +62 -0
  408. data/lib/generators/occams/scaffold/templates/migration.rb.tt +11 -0
  409. data/lib/generators/occams/scaffold/templates/model.rb.tt +21 -0
  410. data/lib/generators/occams/scaffold/templates/tests/controller.rb.tt +115 -0
  411. data/lib/generators/occams/scaffold/templates/tests/fixture.yml.tt +4 -0
  412. data/lib/generators/occams/scaffold/templates/tests/model.rb.tt +26 -0
  413. data/lib/generators/occams/scaffold/templates/views/_form.haml.tt +7 -0
  414. data/lib/generators/occams/scaffold/templates/views/edit.haml.tt +5 -0
  415. data/lib/generators/occams/scaffold/templates/views/index.haml.tt +21 -0
  416. data/lib/generators/occams/scaffold/templates/views/new.haml.tt +5 -0
  417. data/lib/generators/occams/scaffold/templates/views/show.haml.tt +4 -0
  418. data/lib/occams/access_control/admin_authentication.rb +24 -0
  419. data/lib/occams/access_control/admin_authorization.rb +12 -0
  420. data/lib/occams/access_control/public_authentication.rb +12 -0
  421. data/lib/occams/access_control/public_authorization.rb +12 -0
  422. data/lib/occams/configuration.rb +140 -0
  423. data/lib/occams/content/block.rb +14 -0
  424. data/lib/occams/content/params_parser.rb +151 -0
  425. data/lib/occams/content/renderer.rb +149 -0
  426. data/lib/occams/content/tag.rb +50 -0
  427. data/lib/occams/content/tags/asset.rb +59 -0
  428. data/lib/occams/content/tags/checkbox.rb +29 -0
  429. data/lib/occams/content/tags/date.rb +21 -0
  430. data/lib/occams/content/tags/datetime.rb +44 -0
  431. data/lib/occams/content/tags/file.rb +72 -0
  432. data/lib/occams/content/tags/file_link.rb +63 -0
  433. data/lib/occams/content/tags/files.rb +43 -0
  434. data/lib/occams/content/tags/fragment.rb +66 -0
  435. data/lib/occams/content/tags/helper.rb +55 -0
  436. data/lib/occams/content/tags/markdown.rb +24 -0
  437. data/lib/occams/content/tags/mixins/file_content.rb +43 -0
  438. data/lib/occams/content/tags/number.rb +20 -0
  439. data/lib/occams/content/tags/page_file_link.rb +84 -0
  440. data/lib/occams/content/tags/partial.rb +49 -0
  441. data/lib/occams/content/tags/snippet.rb +38 -0
  442. data/lib/occams/content/tags/template.rb +44 -0
  443. data/lib/occams/content/tags/text.rb +20 -0
  444. data/lib/occams/content/tags/textarea.rb +20 -0
  445. data/lib/occams/content/tags/wysiwyg.rb +21 -0
  446. data/lib/occams/content.rb +31 -0
  447. data/lib/occams/engine.rb +31 -0
  448. data/lib/occams/error.rb +32 -0
  449. data/lib/occams/extensions/acts_as_tree.rb +120 -0
  450. data/lib/occams/extensions/has_revisions.rb +72 -0
  451. data/lib/occams/form_builder.rb +47 -0
  452. data/lib/occams/render_methods.rb +112 -0
  453. data/lib/occams/routes/cms.rb +18 -0
  454. data/lib/occams/routes/cms_admin.rb +58 -0
  455. data/lib/occams/routing.rb +12 -0
  456. data/lib/occams/seeds/file/exporter.rb +43 -0
  457. data/lib/occams/seeds/file/importer.rb +63 -0
  458. data/lib/occams/seeds/layout/exporter.rb +40 -0
  459. data/lib/occams/seeds/layout/importer.rb +62 -0
  460. data/lib/occams/seeds/page/exporter.rb +92 -0
  461. data/lib/occams/seeds/page/importer.rb +219 -0
  462. data/lib/occams/seeds/snippet/exporter.rb +34 -0
  463. data/lib/occams/seeds/snippet/importer.rb +51 -0
  464. data/lib/occams/seeds.rb +118 -0
  465. data/lib/occams/version.rb +7 -0
  466. data/lib/occams/view_hooks.rb +35 -0
  467. data/lib/occams.rb +60 -0
  468. data/lib/tasks/cms_seeds.rake +40 -0
  469. data/occams.gemspec +33 -0
  470. data/public/favicon.ico +0 -0
  471. metadata +666 -0
@@ -0,0 +1,21 @@
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 Occams::Content::Tag::Date < Occams::Content::Tag::Datetime
7
+
8
+ def form_field(object_name, view, index)
9
+ name = "#{object_name}[fragments_attributes][#{index}][datetime]"
10
+ options = { id: form_field_id, class: "form-control", data: { "cms-date" => true } }
11
+ value = content.present? ? content.to_s(:db) : ""
12
+ input = view.send(:text_field_tag, name, value, options)
13
+
14
+ yield input
15
+ end
16
+
17
+ end
18
+
19
+ Occams::Content::Renderer.register_tag(
20
+ :date, Occams::Content::Tag::Date
21
+ )
@@ -0,0 +1,44 @@
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 Occams::Content::Tag::Datetime < Occams::Content::Tag::Fragment
9
+
10
+ attr_reader :strftime
11
+
12
+ def initialize(context:, params: [], source: nil)
13
+ super
14
+ @strftime = options["strftime"]
15
+ end
16
+
17
+ def content
18
+ fragment.datetime
19
+ end
20
+
21
+ def render
22
+ return "" unless renderable
23
+
24
+ if strftime.present?
25
+ content.strftime(strftime)
26
+ else
27
+ content.to_s
28
+ end
29
+ end
30
+
31
+ def form_field(object_name, view, index)
32
+ name = "#{object_name}[fragments_attributes][#{index}][datetime]"
33
+ options = { id: form_field_id, class: "form-control", data: { "cms-datetime" => true } }
34
+ value = content.present? ? content.to_s(:db) : ""
35
+ input = view.send(:text_field_tag, name, value, options)
36
+
37
+ yield input
38
+ end
39
+
40
+ end
41
+
42
+ Occams::Content::Renderer.register_tag(
43
+ :datetime, Occams::Content::Tag::Datetime
44
+ )
@@ -0,0 +1,72 @@
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 Occams::Content::Tag::File < Occams::Content::Tag::Fragment
17
+
18
+ include Occams::Content::Tag::Mixins::FileContent
19
+
20
+ # @type ["url", "link", "image"]
21
+ attr_reader :as
22
+
23
+ # @type [{String => String}]
24
+ attr_reader :variant_attrs
25
+
26
+ # @param (see Occams::Content::Tag#initialize)
27
+ def initialize(context:, params: [], source: nil)
28
+ super
29
+ @as = options["as"] || "url"
30
+ @label = options["label"]
31
+ @class = options["class"]
32
+ @variant_attrs = options.slice("resize", "gravity", "crop")
33
+ end
34
+
35
+ def form_field(object_name, view, index)
36
+ name = "#{object_name}[fragments_attributes][#{index}][files]"
37
+ input = view.send(:file_field_tag, name, id: form_field_id, class: "form-control")
38
+
39
+ attachments_partial =
40
+ if fragment.attachments
41
+ view.render(
42
+ partial: "occams/admin/cms/fragments/form_fragment_attachments",
43
+ locals: {
44
+ object_name: object_name,
45
+ index: index,
46
+ attachments: fragment.attachments,
47
+ fragment_id: identifier,
48
+ multiple: false
49
+ }
50
+ )
51
+ end
52
+
53
+ yield view.safe_join([input, attachments_partial], "")
54
+ end
55
+
56
+ protected
57
+
58
+ # @return [ActiveStorage::Blob]
59
+ def file
60
+ fragment.attachments.first
61
+ end
62
+
63
+ # @return [String]
64
+ def label
65
+ @label || file&.filename
66
+ end
67
+
68
+ end
69
+
70
+ Occams::Content::Renderer.register_tag(
71
+ :file, Occams::Content::Tag::File
72
+ )
@@ -0,0 +1,63 @@
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
+ # `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 Occams::Content::Tag::FileLink < Occams::Content::Tag
17
+
18
+ include Occams::Content::Tag::Mixins::FileContent
19
+
20
+ # @return [String] A {Occams::Cms::Site#files} ID.
21
+ attr_reader :identifier
22
+
23
+ # @type ["url", "link", "image"]
24
+ attr_reader :as
25
+
26
+ # @type [{String => String}]
27
+ attr_reader :variant_attrs
28
+
29
+ def initialize(context:, params: [], source: nil)
30
+ super
31
+
32
+ options = params.extract_options!
33
+ @identifier = params[0]
34
+ @as = options["as"] || "url"
35
+ @class = options["class"]
36
+ @variant_attrs = options.slice("resize", "gravity", "crop")
37
+
38
+ unless @identifier.present?
39
+ raise Error, "Missing identifier for file link tag"
40
+ end
41
+ end
42
+
43
+ # @return [Occams::Cms::File]
44
+ def file_record
45
+ @file_record ||= context.site.files.detect { |f| f.id == identifier.to_i }
46
+ end
47
+
48
+ # @return [ActiveStorage::Blob]
49
+ def file
50
+ file_record&.attachment
51
+ end
52
+
53
+ # @return [String]
54
+ def label
55
+ return "" if file_record.nil?
56
+ file_record.label.presence || file.filename.to_s
57
+ end
58
+
59
+ end
60
+
61
+ Occams::Content::Renderer.register_tag(
62
+ :file_link, Occams::Content::Tag::FileLink
63
+ )
@@ -0,0 +1,43 @@
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 Occams::Content::Tag::Files < Occams::Content::Tag::File
9
+
10
+ def content
11
+ return "" if fragment.attachments.blank?
12
+
13
+ fragment.attachments.collect do |attachment|
14
+ super(file: attachment, label: attachment.filename)
15
+ end.join(" ")
16
+ end
17
+
18
+ def form_field(object_name, view, index)
19
+ name = "#{object_name}[fragments_attributes][#{index}][files][]"
20
+ input = view.send(:file_field_tag, name, id: form_field_id, multiple: true, class: "form-control")
21
+
22
+ attachments_partial =
23
+ if fragment.attachments
24
+ view.render(
25
+ partial: "occams/admin/cms/fragments/form_fragment_attachments",
26
+ locals: {
27
+ object_name: object_name,
28
+ index: index,
29
+ attachments: fragment.attachments,
30
+ fragment_id: identifier,
31
+ multiple: true
32
+ }
33
+ )
34
+ end
35
+
36
+ yield view.safe_join([input, attachments_partial], "")
37
+ end
38
+
39
+ end
40
+
41
+ Occams::Content::Renderer.register_tag(
42
+ :files, Occams::Content::Tag::Files
43
+ )
@@ -0,0 +1,66 @@
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 Occams::Content::Tag::Fragment < Occams::Content::Tag
12
+
13
+ attr_accessor :renderable
14
+ attr_reader :identifier, :namespace
15
+
16
+ # @type [{String => String}]
17
+ attr_reader :options
18
+
19
+ def initialize(context:, params: [], source: nil)
20
+ super
21
+
22
+ @options = params.extract_options!
23
+ @identifier = params[0]
24
+
25
+ unless @identifier.present?
26
+ raise Error, "Missing identifier for fragment tag: #{source}"
27
+ end
28
+
29
+ @namespace = @options["namespace"] || "default"
30
+ @renderable = @options["render"].to_s.downcase != "false"
31
+ end
32
+
33
+ # Grabs existing fragment record or spins up a new instance if there's none
34
+ # @return [Occams::Cms::Fragment]
35
+ def fragment
36
+ context.fragments.detect { |f| f.identifier == identifier } ||
37
+ context.fragments.build(identifier: identifier)
38
+ end
39
+
40
+ def content
41
+ fragment.content
42
+ end
43
+
44
+ # If `render: false` was passed in we won't render anything. Assuming that
45
+ # that fragment content will be rendered manually
46
+ def render
47
+ renderable ? content : ""
48
+ end
49
+
50
+ # Tag renders its own form inputs via `form_field(template, index)`
51
+ # For example:
52
+ # class MyTag < Occams::Content::Tag::Fragment
53
+ # def form_field(view, index, &block)
54
+ # # omit yield if you don't want default wrapper
55
+ # yield view.text_area "input_name", "value"
56
+ # end
57
+ # end
58
+ def form_field
59
+ raise "Form field rendering not implemented for this Tag"
60
+ end
61
+
62
+ def form_field_id
63
+ "fragment-#{@identifier}"
64
+ end
65
+
66
+ end
@@ -0,0 +1,55 @@
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 Occams::Content::Tag::Helper < Occams::Content::Tag
11
+
12
+ BLACKLIST = %w[eval class_eval instance_eval render].freeze
13
+
14
+ attr_reader :method_name
15
+
16
+ def initialize(context:, params: [], source: nil)
17
+ super
18
+ @method_name = params.shift
19
+
20
+ unless @method_name.present?
21
+ raise Error, "Missing method name for helper tag"
22
+ end
23
+ end
24
+
25
+ # we output erb into rest of the content
26
+ def allow_erb?
27
+ true
28
+ end
29
+
30
+ def content
31
+ helper_params = params.map do |p|
32
+ case p
33
+ when Hash
34
+ format("%<arg>s", arg: p)
35
+ else
36
+ format("%<arg>p", arg: p)
37
+ end
38
+ end.join(",")
39
+ "<%= #{method_name}(#{helper_params}) %>"
40
+ end
41
+
42
+ def render
43
+ whitelist = Occams.config.allowed_helpers
44
+ if whitelist.is_a?(Array)
45
+ content if whitelist.map!(&:to_s).member?(method_name)
46
+ else
47
+ content unless BLACKLIST.member?(method_name)
48
+ end
49
+ end
50
+
51
+ end
52
+
53
+ Occams::Content::Renderer.register_tag(
54
+ :helper, Occams::Content::Tag::Helper
55
+ )
@@ -0,0 +1,24 @@
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 Occams::Content::Tag::Markdown < Occams::Content::Tag::Fragment
7
+
8
+ def render
9
+ renderable ? Kramdown::Document.new(content.to_s).to_html : ""
10
+ end
11
+
12
+ def form_field(object_name, view, index)
13
+ name = "#{object_name}[fragments_attributes][#{index}][content]"
14
+ options = { id: form_field_id, data: { "cms-cm-mode" => "text/x-markdown" } }
15
+ input = view.send(:text_area_tag, name, content, options)
16
+
17
+ yield input
18
+ end
19
+
20
+ end
21
+
22
+ Occams::Content::Renderer.register_tag(
23
+ :markdown, Occams::Content::Tag::Markdown
24
+ )
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ # A mixin for tags that returns the file as their content.
4
+ module Occams::Content::Tag::Mixins
5
+ module FileContent
6
+
7
+ # @param [ActiveStorage::Blob] file
8
+ # @param ["link", "image", "url"] as
9
+ # @param [{String => String}] variant_attrs ImageMagick variant attributes
10
+ # @param [String] label alt text for `as: "image"`, link text for `as: "link"`
11
+ # @return [String]
12
+ def content(file: self.file, as: self.as, variant_attrs: self.variant_attrs, label: self.label)
13
+ return "" unless file
14
+
15
+ url_helpers = Rails.application.routes.url_helpers
16
+
17
+ attachment_url =
18
+ if variant_attrs.present? && file.image?
19
+ variant = file.variant(combine_options: variant_attrs)
20
+ url_helpers.rails_representation_path(variant, only_path: true)
21
+ else
22
+ url_helpers.rails_blob_path(file, only_path: true)
23
+ end
24
+
25
+ case as
26
+ when "link"
27
+ "<a href='#{attachment_url}'#{html_class_attribute} target='_blank'>#{label}</a>"
28
+ when "image"
29
+ "<img src='#{attachment_url}'#{html_class_attribute} alt='#{label}'/>"
30
+ else
31
+ attachment_url
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ def html_class_attribute
38
+ return if @class.blank?
39
+ " class='#{@class}'"
40
+ end
41
+
42
+ end
43
+ end
@@ -0,0 +1,20 @@
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 Occams::Content::Tag::Number < Occams::Content::Tag::Fragment
7
+
8
+ def form_field(object_name, view, index)
9
+ name = "#{object_name}[fragments_attributes][#{index}][content]"
10
+ options = { id: form_field_id, class: "form-control" }
11
+ input = view.send(:number_field_tag, name, content, options)
12
+
13
+ yield input
14
+ end
15
+
16
+ end
17
+
18
+ Occams::Content::Renderer.register_tag(
19
+ :number, Occams::Content::Tag::Number
20
+ )
@@ -0,0 +1,84 @@
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
+ # `label` - attach label attribute to link or image tag
20
+ # `resize` - imagemagick option. For example: "100x50>"
21
+ # `gravity` - imagemagick option. For example: "center"
22
+ # `crop` - imagemagick option. For example: "100x50+0+0"
23
+ # `class` - any html classes that you want on the result link or image tag. For example "class1 class2"
24
+ #
25
+ class Occams::Content::Tag::PageFileLink < Occams::Content::Tag
26
+
27
+ include Occams::Content::Tag::Mixins::FileContent
28
+
29
+ # @return [String] A `cms:file(s)` identifier.
30
+ attr_reader :identifier
31
+
32
+ # @type ["url", "link", "image"]
33
+ attr_reader :as
34
+
35
+ # @type [{String => String}]
36
+ attr_reader :variant_attrs
37
+
38
+ # @return [String] Used to refer to a file in a {{ cms:files }} tag.
39
+ attr_reader :filename
40
+
41
+ # @param (see Occams::Content::Tag#initialize)
42
+ def initialize(context:, params: [], source: nil)
43
+ super
44
+
45
+ options = params.extract_options!
46
+ @identifier = params[0]
47
+ @as = options["as"] || "url"
48
+ @class = options["class"]
49
+ @variant_attrs = options.slice("resize", "gravity", "crop")
50
+ @filename = options["filename"]
51
+
52
+ unless @identifier.present?
53
+ raise Error, "Missing identifier for page file link tag"
54
+ end
55
+ end
56
+
57
+ # @return [Occams::Cms::Fragment]
58
+ def fragment
59
+ @fragment ||= context.fragments.detect { |f| f.identifier == identifier }
60
+ end
61
+
62
+ # @return [ActiveStorage::Blob]
63
+ def file
64
+ @file ||=
65
+ if fragment.nil?
66
+ nil
67
+ elsif filename.nil?
68
+ fragment.attachments.first
69
+ else
70
+ fragment.attachments.detect { |a| a.filename.to_s == filename }
71
+ end
72
+ end
73
+
74
+ # @return [String]
75
+ def label
76
+ return if file.nil?
77
+ file.filename.to_s
78
+ end
79
+
80
+ end
81
+
82
+ Occams::Content::Renderer.register_tag(
83
+ :page_file_link, Occams::Content::Tag::PageFileLink
84
+ )
@@ -0,0 +1,49 @@
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 Occams::Content::Tag::Partial < Occams::Content::Tag
10
+
11
+ attr_reader :path, :locals
12
+
13
+ def initialize(context:, params: [], source: nil)
14
+ super
15
+ @locals = params.extract_options!
16
+ @path = params[0]
17
+
18
+ unless @path.present?
19
+ raise Error, "Missing path for partial tag"
20
+ end
21
+ end
22
+
23
+ # we output erb into rest of the content
24
+ def allow_erb?
25
+ true
26
+ end
27
+
28
+ def content
29
+ format(
30
+ "<%%= render partial: %<path>p, locals: %<locals>s %%>",
31
+ path: @path,
32
+ locals: @locals
33
+ )
34
+ end
35
+
36
+ def render
37
+ whitelist = Occams.config.allowed_partials
38
+ if whitelist.is_a?(Array)
39
+ whitelist.member?(@path) ? content : ""
40
+ else
41
+ content
42
+ end
43
+ end
44
+
45
+ end
46
+
47
+ Occams::Content::Renderer.register_tag(
48
+ :partial, Occams::Content::Tag::Partial
49
+ )
@@ -0,0 +1,38 @@
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 Occams::Content::Tag::Snippet < Occams::Content::Tag
8
+
9
+ attr_reader :identifier
10
+
11
+ def initialize(context:, params: [], source: nil)
12
+ super
13
+ @identifier = params[0]
14
+
15
+ unless @identifier.present?
16
+ raise Error, "Missing identifier for snippet tag"
17
+ end
18
+ end
19
+
20
+ def content
21
+ if snippet.markdown
22
+ Kramdown::Document.new(snippet.content.to_s).to_html
23
+ else
24
+ snippet.content
25
+ end
26
+ end
27
+
28
+ # Grabbing or initializing Occams::Cms::Snippet object
29
+ def snippet
30
+ context.site.snippets.detect { |s| s.identifier == identifier } ||
31
+ context.site.snippets.build(identifier: identifier)
32
+ end
33
+
34
+ end
35
+
36
+ Occams::Content::Renderer.register_tag(
37
+ :snippet, Occams::Content::Tag::Snippet
38
+ )
@@ -0,0 +1,44 @@
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 Occams::Content::Tag::Template < Occams::Content::Tag
10
+
11
+ attr_reader :path
12
+
13
+ def initialize(context:, params: [], source: nil)
14
+ super
15
+ @path = params[0]
16
+
17
+ unless @path.present?
18
+ raise Error, "Missing template path for template tag"
19
+ end
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("<%%= render template: %<path>p %%>", path: path)
29
+ end
30
+
31
+ def render
32
+ whitelist = Occams.config.allowed_templates
33
+ if whitelist.is_a?(Array)
34
+ whitelist.member?(@path) ? content : ""
35
+ else
36
+ content
37
+ end
38
+ end
39
+
40
+ end
41
+
42
+ Occams::Content::Renderer.register_tag(
43
+ :template, Occams::Content::Tag::Template
44
+ )
@@ -0,0 +1,20 @@
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 Occams::Content::Tag::Text < Occams::Content::Tag::Fragment
7
+
8
+ def form_field(object_name, view, index)
9
+ name = "#{object_name}[fragments_attributes][#{index}][content]"
10
+ options = { id: form_field_id, class: "form-control" }
11
+ input = view.send(:text_field_tag, name, content, options)
12
+
13
+ yield input
14
+ end
15
+
16
+ end
17
+
18
+ Occams::Content::Renderer.register_tag(
19
+ :text, Occams::Content::Tag::Text
20
+ )