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
+ .page-header
2
+ = link_to 'New <%= class_name.titleize %>', new_admin_<%= file_name %>_path, class: 'btn btn-secondary float-right'
3
+ %h2= '<%= class_name.pluralize.titleize %>'
4
+
5
+ = paginate @<%= file_name.pluralize %>, theme: 'occams'
6
+
7
+ %ul.list
8
+ - @<%= file_name.pluralize %>.each do |<%= file_name %>|
9
+ %li
10
+ .row
11
+ .col-md-8.item
12
+ .item-content
13
+ .item-title
14
+ = <%= file_name%>.<%= model_attrs.first.name %>
15
+
16
+ .col-md-4.d-flex.align-items-center.justify-content-md-end
17
+ .btn-group.btn-group-sm
18
+ = link_to 'Edit', edit_admin_<%= file_name %>_path(<%= file_name %>), class: 'btn btn-outline-secondary'
19
+ = link_to 'Delete', admin_<%= file_name %>_path(<%= file_name %>), method: :delete, data: {confirm: 'Are you sure?'}, class: 'btn btn-danger'
20
+
21
+ = paginate @<%= file_name.pluralize %>, theme: 'occams'
@@ -0,0 +1,5 @@
1
+ .page-header
2
+ %h2 New <%= class_name.titleize %>
3
+
4
+ = occams_form_with model: @<%= file_name %>, url: [:admin, @<%= file_name %>] do |form|
5
+ = render form
@@ -0,0 +1,4 @@
1
+ .page-header
2
+ %h2 <%= class_name.titleize %>
3
+
4
+ = debug @<%= file_name %>
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Occams::AccessControl
4
+ module AdminAuthentication
5
+
6
+ # Set username and password in config/initializers/occams.rb
7
+ # Like this:
8
+ # Occams::AccessControl::AdminAuthentication.username = 'myname'
9
+ # Occams::AccessControl::AdminAuthentication.password = 'mypassword'
10
+
11
+ mattr_accessor :username,
12
+ :password
13
+
14
+ # Simple http_auth. When implementing some other form of authentication
15
+ # this method should return +true+ if everything is great, or redirect user
16
+ # to some other page, thus denying access to cms admin section.
17
+ def authenticate
18
+ authenticate_or_request_with_http_basic do |username, password|
19
+ self.username == username && self.password == password
20
+ end
21
+ end
22
+
23
+ end
24
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Occams::AccessControl
4
+ module AdminAuthorization
5
+
6
+ # By default there's no authorization of any kind
7
+ def authorize
8
+ true
9
+ end
10
+
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Occams::AccessControl
4
+ module PublicAuthentication
5
+
6
+ # By defaut all published pages are accessible
7
+ def authenticate
8
+ true
9
+ end
10
+
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Occams::AccessControl
4
+ module PublicAuthorization
5
+
6
+ # By default there's no authorization of any kind
7
+ def authorize
8
+ true
9
+ end
10
+
11
+ end
12
+ end
@@ -0,0 +1,140 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Occams::Configuration
4
+
5
+ # Don't like Occams? Set it to whatever you like. :(
6
+ attr_accessor :cms_title
7
+
8
+ # Controller that is inherited from CmsAdmin::BaseController
9
+ # 'ApplicationController' is the default
10
+ attr_accessor :admin_base_controller
11
+
12
+ # Controller that Occams::Cms::BaseController will inherit from
13
+ # 'ApplicationController' is the default
14
+ attr_accessor :public_base_controller
15
+
16
+ # Module that will handle authentication to access cms-admin area
17
+ attr_accessor :admin_auth
18
+
19
+ # Module that will handle authorization against admin cms resources
20
+ attr_accessor :admin_authorization
21
+
22
+ # Module that will handle authentication for public pages
23
+ attr_accessor :public_auth
24
+
25
+ # Module that will handle authorization against public resources
26
+ attr_accessor :public_authorization
27
+
28
+ # When arriving at /cms-admin you may chose to redirect to arbirtary path,
29
+ # for example '/cms-admin/users'
30
+ attr_accessor :admin_route_redirect
31
+
32
+ # With each page load, files will be synched with the database. Database entries are
33
+ # destroyed if there's no corresponding file. Seeds are disabled by default.
34
+ attr_accessor :enable_seeds
35
+
36
+ # Path where seeds can be located.
37
+ attr_accessor :seeds_path
38
+
39
+ # Number of revisions kept. Default is 25. If you wish to disable: set this to 0.
40
+ attr_accessor :revisions_limit
41
+
42
+ # Locale definitions. If you want to define your own locale merge
43
+ # {:locale => 'Locale Title'} with this.
44
+ attr_accessor :locales
45
+
46
+ # Admin interface will respect the locale of the site being managed. However you can
47
+ # force it to English by setting this to `:en`
48
+ attr_accessor :admin_locale
49
+
50
+ # A class that is included as a sweeper to admin base controller if it's set
51
+ attr_accessor :admin_cache_sweeper
52
+
53
+ # Not allowing erb code to be run inside page content. False by default.
54
+ # @return [Boolean]
55
+ attr_accessor :allow_erb
56
+
57
+ # Whitelist of all helper methods that can be used via {{cms:helper}} tag. By default
58
+ # all helpers are allowed except `eval`, `send`, `call` and few others. Empty array
59
+ # will prevent rendering of all helpers.
60
+ attr_accessor :allowed_helpers
61
+
62
+ # Whitelist of partials paths that can be used via {{cms:partial}} tag. All partials
63
+ # are accessible by default. Empty array will prevent rendering of all partials.
64
+ attr_accessor :allowed_partials
65
+
66
+ # Whitelist of template paths that can be used via {{cms:template}} tag. All templates
67
+ # are accessible by default. Empty array will prevent rendering of all templates.
68
+ attr_accessor :allowed_templates
69
+
70
+ # Site aliases, if you want to have aliases for your site. Good for harmonizing
71
+ # production env with dev/testing envs.
72
+ # e.g. config.site_aliases = {'host.com' => 'host.inv', 'host_a.com' => ['host.lvh.me', 'host.dev']}
73
+ # Default is nil (not used)
74
+ attr_accessor :hostname_aliases
75
+
76
+ # Reveal partials that can be overwritten in the admin area.
77
+ # Default is false.
78
+ attr_accessor :reveal_cms_partials
79
+
80
+ # Auto-setting parameter derived from the routes
81
+ attr_accessor :public_cms_path
82
+
83
+ # Customize returned content from `page.to_json`
84
+ # Default is set to `methods: [:content], except: [:content_cache]`
85
+ # For example: include fragments into json data with `config.page_to_json_options = { include: [:fragments] }`
86
+ attr_accessor :page_to_json_options
87
+
88
+ # Configuration defaults
89
+ def initialize
90
+ @cms_title = "Occams CMS Engine"
91
+ @admin_base_controller = "ApplicationController"
92
+ @public_base_controller = "ApplicationController"
93
+ @admin_auth = "Occams::AccessControl::AdminAuthentication"
94
+ @admin_authorization = "Occams::AccessControl::AdminAuthorization"
95
+ @public_auth = "Occams::AccessControl::PublicAuthentication"
96
+ @public_authorization = "Occams::AccessControl::PublicAuthorization"
97
+ @seed_data_path = nil
98
+ @admin_route_redirect = ""
99
+ @enable_sitemap = true
100
+ @enable_seeds = false
101
+ @seeds_path = File.expand_path("db/cms_seeds", Rails.root)
102
+ @revisions_limit = 25
103
+ @locales = {
104
+ "ar" => "عربي",
105
+ "ca" => "Català",
106
+ "cs" => "Česky",
107
+ "da" => "Dansk",
108
+ "de" => "Deutsch",
109
+ "en" => "English",
110
+ "es" => "Español",
111
+ "fi" => "Suomi",
112
+ "fr" => "Français",
113
+ "gr" => "Ελληνικά",
114
+ "hr" => "Hrvatski",
115
+ "it" => "Italiano",
116
+ "ja" => "日本語",
117
+ "nb" => "Norsk",
118
+ "nl" => "Nederlands",
119
+ "pl" => "Polski",
120
+ "pt-BR" => "Português Brasileiro",
121
+ "ru" => "Русский",
122
+ "sk" => "Slovensky",
123
+ "sv" => "Svenska",
124
+ "tr" => "Türkçe",
125
+ "uk" => "Українська",
126
+ "zh-CN" => "简体中文",
127
+ "zh-TW" => "正體中文"
128
+ }
129
+ @admin_locale = nil
130
+ @admin_cache_sweeper = nil
131
+ @allow_erb = false
132
+ @allowed_helpers = nil
133
+ @allowed_partials = nil
134
+ @hostname_aliases = nil
135
+ @reveal_cms_partials = false
136
+ @public_cms_path = nil
137
+ @page_to_json_options = { methods: [:content], except: [:content_cache] }
138
+ end
139
+
140
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ # wtf does this mean
4
+ # it means that all nodes between this must be moved into here
5
+ # {{cms:block}} some content {{cms:end_block}}
6
+ class Occams::Content::Block < Occams::Content::Tag
7
+
8
+ attr_writer :nodes
9
+
10
+ def nodes
11
+ @nodes ||= []
12
+ end
13
+
14
+ end
@@ -0,0 +1,151 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "strscan"
4
+
5
+ class Occams::Content::ParamsParser
6
+
7
+ class Error < StandardError; end
8
+
9
+ STRING_LITERAL = %r{'[^']*'|"[^"]*"}
10
+ IDENTIFIER = %r{[a-z0-9][\w\-/.]*}i
11
+ HASH_KEY = %r{#{IDENTIFIER}:}
12
+ COMMA = %r{,}
13
+ HASH_OPEN = %r{\{}
14
+ HASH_CLOSE = %r{\}}
15
+ ARRAY_OPEN = %r{\[}
16
+ ARRAY_CLOSE = %r{\]}
17
+ INTEGER = %r{\b[0-9]+\b}i
18
+
19
+ # @param <String> string
20
+ def initialize(string = "")
21
+ @string = string
22
+ end
23
+
24
+ # Takes CMS content tag parameters and converts them into array of strings,
25
+ # hashes and arrays.
26
+ #
27
+ # @return [Array<String, {String => String}>]
28
+ # @raise [Error] if the given `text` is malformed.
29
+ #
30
+ # @example
31
+ # new("a, b, c").parse
32
+ # #=> ["a", "b", "c"]
33
+ #
34
+ # new("a, b: c, d: e").parse
35
+ # #=> ["a", {"b" => "c", "d" => "e"}]
36
+ #
37
+ # new("a, b: {c: [d, e]}").parse
38
+ # #=> ["a", {"b" => {"c" => ["d", "e"]}}]
39
+ #
40
+ def params
41
+ @tokens = tokenize(@string)
42
+ parse_params
43
+ end
44
+
45
+ private
46
+
47
+ # Contructs root-level list of arguments sent via content tag
48
+ def parse_params
49
+ params = []
50
+ while (token = @tokens.shift)
51
+ params << parse_value(token)
52
+ end
53
+ params
54
+ end
55
+
56
+ # Gets token value. Will trigger parsing of hash and array structures
57
+ def parse_value(token)
58
+ case token&.first
59
+ when :string
60
+ token[1]
61
+ when :hash_key
62
+ @tokens.unshift(token)
63
+ parse_hash
64
+ when :hash_open
65
+ parse_hash
66
+ when :array_open
67
+ parse_array
68
+ else
69
+ raise Error, "Invalid params: #{@string}"
70
+ end
71
+ end
72
+
73
+ # Hash constructor method. Will handle nested hashes as well
74
+ def parse_hash
75
+ opens = 1
76
+ hash = {}
77
+
78
+ while (token = @tokens.shift)
79
+ case token&.first
80
+ when :hash_key
81
+ hash[token[1]] = parse_value(@tokens.shift)
82
+ when :hash_close
83
+ opens -= 1
84
+ when :hash_open
85
+ opens += 1
86
+ else
87
+ raise Error, "Invalid params: #{@string}"
88
+ end
89
+
90
+ return hash if opens.zero?
91
+ end
92
+
93
+ # We're can't really detect unclosed hashes as we can construct them without
94
+ # opening brakets. For example, `a: b, c: d` is same as `{a: b, c: d}` and
95
+ # `{a: b, c: d` is also ends up to be a valid hash. It will error out if
96
+ # unclosed hash is followed by some other unexpected token. Like: `{a: b, c`
97
+ hash
98
+ end
99
+
100
+ # Array construction method. Will handle nested arrays
101
+ def parse_array
102
+ opens = 1
103
+ array = []
104
+ while (token = @tokens.shift)
105
+ case token&.first
106
+ when :array_close
107
+ opens -= 1
108
+ else
109
+ array << parse_value(token)
110
+ end
111
+
112
+ return array if opens.zero?
113
+ end
114
+
115
+ raise Error, "Unclosed array param: #{@string}"
116
+ end
117
+
118
+ # Tokenizing input string into a list of touples
119
+ # Also args_string is stripped of "smart" quotes coming from wysiwyg
120
+ #
121
+ # @param [String] args_string
122
+ # @return [Array<String>] tokens
123
+ def tokenize(args_string)
124
+ args_string = args_string.tr("“”‘’", %q(""''))
125
+ ss = StringScanner.new(args_string)
126
+ tokens = []
127
+ loop do
128
+ ss.skip(%r{\s*})
129
+ break if ss.eos?
130
+
131
+ # commas are just separators like spaces
132
+ next if ss.scan(COMMA)
133
+
134
+ tokens <<
135
+ if (t = ss.scan(STRING_LITERAL)) then [:string, t[1...-1]]
136
+ elsif (t = ss.scan(HASH_KEY)) then [:hash_key, t[0...-1]]
137
+ elsif (t = ss.scan(INTEGER)) then [:string, t.to_i]
138
+ elsif (t = ss.scan(IDENTIFIER)) then [:string, t]
139
+ elsif (t = ss.scan(HASH_OPEN)) then [:hash_open, t]
140
+ elsif (t = ss.scan(HASH_CLOSE)) then [:hash_close, t]
141
+ elsif (t = ss.scan(ARRAY_OPEN)) then [:array_open, t]
142
+ elsif (t = ss.scan(ARRAY_CLOSE)) then [:array_close, t]
143
+ else
144
+ raise Error, "Unexpected char: #{ss.getch}"
145
+ end
146
+ end
147
+
148
+ tokens
149
+ end
150
+
151
+ end
@@ -0,0 +1,149 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "strscan"
4
+
5
+ # Processing content follows these stages:
6
+ #
7
+ # string - Text with tags. like this: "some {{cms:fragment content}} text"
8
+ # tokenization - Splits string into a list of strings and hashes that define tags
9
+ # Example: ["some ", {tag_class: "fragment", tag_params: ""}, " text"]
10
+ # nodefying - Initializes Tag instances from tag hashes and returns list
11
+ # like this: ["some ", (FragmentTagInstance), " text"]
12
+ # rendering - Recursively iterates through nodes. Tag instances get their
13
+ # `render` method called. Result of that is tokenized, nodefied
14
+ # and rendered once again until there are no tags to expand.
15
+ # Resulting list is flattened and joined into a final rendered string.
16
+ #
17
+ class Occams::Content::Renderer
18
+
19
+ class SyntaxError < StandardError; end
20
+ class Error < StandardError; end
21
+
22
+ MAX_DEPTH = 100
23
+
24
+ # tags are in this format: {{ cms:tag_class params }}
25
+ TAG_REGEX = %r{\{\{\s*?cms:(?<class>\w+)(?<params>.*?)\}\}}
26
+
27
+ class << self
28
+
29
+ # @return [Hash<String, Class<Occams::Content::Tag>>]
30
+ def tags
31
+ @tags ||= {}
32
+ end
33
+
34
+ # @param [String] name
35
+ # @param [Class<Occams::Content::Tag>] klass
36
+ def register_tag(name, klass)
37
+ tags[name.to_s] = klass
38
+ end
39
+
40
+ end
41
+
42
+ # @param [Occams::Cms::WithFragments, nil] context
43
+ def initialize(context)
44
+ @context = context
45
+ @depth = 0
46
+ end
47
+
48
+ # This is how we render content out. Takes context (cms page) and content
49
+ # nodes
50
+ # @param [Array<String, Occams::Content::Tag>]
51
+ # @param [Boolean] allow_erb
52
+ def render(nodes, allow_erb = Occams.config.allow_erb)
53
+ if (@depth += 1) > MAX_DEPTH
54
+ raise Error, "Deep tag nesting or recursive nesting detected"
55
+ end
56
+
57
+ nodes.map do |node|
58
+ case node
59
+ when String
60
+ sanitize_erb(node, allow_erb)
61
+ else
62
+ tokens = tokenize(node.render)
63
+ nodes = nodes(tokens)
64
+ render(nodes, allow_erb || node.allow_erb?)
65
+ end
66
+ end.flatten.join
67
+ end
68
+
69
+ def sanitize_erb(string, allow_erb)
70
+ if allow_erb
71
+ string.to_s
72
+ else
73
+ string.to_s.gsub("<%", "&lt;%").gsub("%>", "%&gt;")
74
+ end
75
+ end
76
+
77
+ # Splitting text with tags into tokens we can process down the line
78
+ # @return [Array<String, {Symbol => String}>]
79
+ def tokenize(string)
80
+ tokens = []
81
+ ss = StringScanner.new(string.to_s)
82
+ while (string = ss.scan_until(TAG_REGEX))
83
+ text = string.sub(ss[0], "")
84
+ tokens << text unless text.empty?
85
+ tokens << {
86
+ tag_class: ss[:class],
87
+ tag_params: ss[:params].strip,
88
+ source: ss[0]
89
+ }
90
+ end
91
+ text = ss.rest
92
+ tokens << text if text.present?
93
+ tokens
94
+ end
95
+
96
+ # Constructing node tree for content. It's a list of strings and tags with
97
+ # their own `nodes` method that has array of strings and tags with their own
98
+ # `nodes` method that... you get the idea.
99
+ # @param [Array<String, {Symbol => String}>] tokens
100
+ # @return [Array<String, Occams::Content::Tag>]
101
+ def nodes(tokens)
102
+ nodes = [[]]
103
+ tokens.each do |token|
104
+ case token
105
+
106
+ # tag signature
107
+ when Hash
108
+ case tag_class = token[:tag_class]
109
+
110
+ # This handles {{cms:end}} tag. Stopping collecting block nodes.
111
+ when "end"
112
+ if nodes.count == 1
113
+ raise SyntaxError, "closing unopened block"
114
+ end
115
+ nodes.pop
116
+
117
+ else
118
+ # @type [Class<Occams::Content::Tag>]
119
+ klass = self.class.tags[tag_class] ||
120
+ raise(SyntaxError, "Unrecognized tag: #{token[:source]}")
121
+
122
+ # @type [Occams::Content::Tag]
123
+ tag = klass.new(
124
+ context: @context,
125
+ params: Occams::Content::ParamsParser.new(token[:tag_params]).params,
126
+ source: token[:source]
127
+ )
128
+ nodes.last << tag
129
+
130
+ # If it's a block tag we start collecting nodes into it
131
+ if tag.is_a?(Occams::Content::Block)
132
+ nodes << tag.nodes
133
+ end
134
+ end
135
+
136
+ # text
137
+ else
138
+ nodes.last << token
139
+ end
140
+ end
141
+
142
+ if nodes.count > 1
143
+ raise SyntaxError, "unclosed block detected"
144
+ end
145
+
146
+ nodes.flatten
147
+ end
148
+
149
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Occams::Content::Tag
4
+
5
+ class Error < StandardError; end
6
+
7
+ # @type [Occams::Cms::WithFragments]
8
+ attr_reader :context
9
+
10
+ # @type [Array<String, {String => String}>] params
11
+ attr_reader :params
12
+
13
+ # @type [String, nil] source
14
+ attr_reader :source
15
+
16
+ # @param [Occams::Cms::WithFragments] context
17
+ # @param [Array<String, {String => String}>] params
18
+ # @param [String, nil] source
19
+ def initialize(context:, params: [], source: nil)
20
+ @context = context
21
+ @params = params
22
+ @source = source
23
+ end
24
+
25
+ # Making sure we don't leak erb from tags by accident.
26
+ # Tag classes can override this, like partials/helpers tags.
27
+ def allow_erb?
28
+ Occams.config.allow_erb
29
+ end
30
+
31
+ # Normally it's a {(String)}. However, if tag content has tags,
32
+ # we need to expand them and that produces potentially more stuff.
33
+ # @return [Array<String, Occams::Content::Tag>]
34
+ def nodes
35
+ template = Occams::Content::Renderer.new(@context)
36
+ tokens = template.tokenize(content)
37
+ template.nodes(tokens)
38
+ end
39
+
40
+ # @return [String]
41
+ def content
42
+ raise Error, "This is a base class. It holds no content"
43
+ end
44
+
45
+ # @return [String]
46
+ def render
47
+ content
48
+ end
49
+
50
+ end
@@ -0,0 +1,59 @@
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 Occams::Content::Tag::Asset < Occams::Content::Tag
11
+
12
+ attr_reader :identifier, :type, :as
13
+
14
+ def initialize(context:, params: [], source: nil)
15
+ super
16
+
17
+ options = params.extract_options!
18
+ @identifier = params[0]
19
+ @type = options["type"]
20
+ @as = options["as"] || "url"
21
+
22
+ unless @identifier.present?
23
+ raise Error, "Missing layout identifier for asset tag"
24
+ end
25
+ end
26
+
27
+ def layout
28
+ @layout ||= context.site.layouts.find_by(identifier: @identifier)
29
+ end
30
+
31
+ def content
32
+ return "" unless layout
33
+
34
+ base = Occams.config.public_cms_path || ""
35
+ unless base.ends_with?("/")
36
+ base += "/"
37
+ end
38
+
39
+ case @type
40
+ when "css"
41
+ out = "#{base}cms-css/#{context.site.id}/#{@identifier}/#{layout.cache_buster}.css"
42
+ if @as == "tag"
43
+ out = "<link href='#{out}' media='screen' rel='stylesheet' type='text/css' />"
44
+ end
45
+ out
46
+ when "js"
47
+ out = "#{base}cms-js/#{context.site.id}/#{@identifier}/#{layout.cache_buster}.js"
48
+ if @as == "tag"
49
+ out = "<script src='#{out}' type='text/javascript'></script>"
50
+ end
51
+ out
52
+ end
53
+ end
54
+
55
+ end
56
+
57
+ Occams::Content::Renderer.register_tag(
58
+ :asset, Occams::Content::Tag::Asset
59
+ )
@@ -0,0 +1,29 @@
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 Occams::Content::Tag::Checkbox < Occams::Content::Tag::Fragment
7
+
8
+ def content
9
+ fragment.boolean
10
+ end
11
+
12
+ def form_field(object_name, view, index)
13
+ name = "#{object_name}[fragments_attributes][#{index}][boolean]"
14
+
15
+ input = view.content_tag(:div, class: "form-check mt-2") do
16
+ view.concat view.hidden_field_tag(name, "0", id: nil)
17
+
18
+ options = { id: form_field_id, class: "form-check-input position-static" }
19
+ view.concat view.check_box_tag(name, "1", content.present?, options)
20
+ end
21
+
22
+ yield input
23
+ end
24
+
25
+ end
26
+
27
+ Occams::Content::Renderer.register_tag(
28
+ :checkbox, Occams::Content::Tag::Checkbox
29
+ )