PixelForce_ETS 0.0.1

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 (467) 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 +100 -0
  8. data/.travis.yml +43 -0
  9. data/CONTRIBUTING.md +35 -0
  10. data/Gemfile +29 -0
  11. data/LICENSE +20 -0
  12. data/README.md +116 -0
  13. data/Rakefile +5 -0
  14. data/app/assets/fonts/comfy/admin/cms/lib/redactor-font.eot +0 -0
  15. data/app/assets/javascripts/comfy/admin/cms/application.js +39 -0
  16. data/app/assets/javascripts/comfy/admin/cms/base.js +46 -0
  17. data/app/assets/javascripts/comfy/admin/cms/categories.js +17 -0
  18. data/app/assets/javascripts/comfy/admin/cms/codemirror.js +31 -0
  19. data/app/assets/javascripts/comfy/admin/cms/custom.js +1 -0
  20. data/app/assets/javascripts/comfy/admin/cms/diff.js +10 -0
  21. data/app/assets/javascripts/comfy/admin/cms/file_link.js +67 -0
  22. data/app/assets/javascripts/comfy/admin/cms/file_upload.js +194 -0
  23. data/app/assets/javascripts/comfy/admin/cms/files_modal.js +40 -0
  24. data/app/assets/javascripts/comfy/admin/cms/page_fragments.js +22 -0
  25. data/app/assets/javascripts/comfy/admin/cms/slugify.js +34 -0
  26. data/app/assets/javascripts/comfy/admin/cms/sortable_list.js +40 -0
  27. data/app/assets/javascripts/comfy/admin/cms/timepicker.js +30 -0
  28. data/app/assets/javascripts/comfy/admin/cms/wysiwyg.js +65 -0
  29. data/app/assets/javascripts/comfy/vendor/Moxie.swf +0 -0
  30. data/app/assets/javascripts/comfy/vendor/Moxie.xap +0 -0
  31. data/app/assets/javascripts/comfy/vendor/bootstrap.bundle.min.js +7 -0
  32. data/app/assets/javascripts/comfy/vendor/bootstrap.bundle.min.js.map +1 -0
  33. data/app/assets/javascripts/comfy/vendor/codemirror.js +9653 -0
  34. data/app/assets/javascripts/comfy/vendor/codemirror/addon/edit/closetag.js +169 -0
  35. data/app/assets/javascripts/comfy/vendor/codemirror/mode/css/css.js +832 -0
  36. data/app/assets/javascripts/comfy/vendor/codemirror/mode/htmlmixed/htmlmixed.js +152 -0
  37. data/app/assets/javascripts/comfy/vendor/codemirror/mode/javascript/javascript.js +875 -0
  38. data/app/assets/javascripts/comfy/vendor/codemirror/mode/markdown/markdown.js +861 -0
  39. data/app/assets/javascripts/comfy/vendor/codemirror/mode/xml/xml.js +394 -0
  40. data/app/assets/javascripts/comfy/vendor/diff/diff_match_patch.min.js +49 -0
  41. data/app/assets/javascripts/comfy/vendor/diff/pretty_text_diff.js +76 -0
  42. data/app/assets/javascripts/comfy/vendor/flatpickr.min.js +2 -0
  43. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/ar.js +52 -0
  44. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/bg.js +65 -0
  45. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/bn.js +65 -0
  46. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/ca.js +83 -0
  47. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/cs.js +70 -0
  48. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/cy.js +92 -0
  49. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/da.js +71 -0
  50. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/de.js +70 -0
  51. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/default.js +80 -0
  52. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/eo.js +73 -0
  53. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/es.js +69 -0
  54. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/et.js +73 -0
  55. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/fa.js +68 -0
  56. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/fi.js +69 -0
  57. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/fr.js +75 -0
  58. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/gr.js +74 -0
  59. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/he.js +57 -0
  60. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/hi.js +65 -0
  61. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/hr.js +66 -0
  62. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/hu.js +72 -0
  63. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/id.js +61 -0
  64. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/it.js +70 -0
  65. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/ja.js +57 -0
  66. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/ko.js +60 -0
  67. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/lt.js +72 -0
  68. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/lv.js +67 -0
  69. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/mk.js +69 -0
  70. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/mn.js +67 -0
  71. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/ms.js +68 -0
  72. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/my.js +69 -0
  73. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/nl.js +75 -0
  74. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/no.js +73 -0
  75. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/pa.js +65 -0
  76. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/pl.js +68 -0
  77. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/pt-BR.js +66 -0
  78. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/pt.js +66 -0
  79. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/ro.js +69 -0
  80. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/ru.js +66 -0
  81. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/si.js +65 -0
  82. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/sk.js +70 -0
  83. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/sl.js +70 -0
  84. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/sq.js +65 -0
  85. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/sr.js +69 -0
  86. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/sv.js +70 -0
  87. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/th.js +72 -0
  88. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/tr.js +66 -0
  89. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/uk.js +66 -0
  90. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/vn.js +66 -0
  91. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/zh-CN.js +61 -0
  92. data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/zh-TW.js +61 -0
  93. data/app/assets/javascripts/comfy/vendor/fontawesome.js +5 -0
  94. data/app/assets/javascripts/comfy/vendor/moxie.min.js +16 -0
  95. data/app/assets/javascripts/comfy/vendor/plupload.dev.js +2497 -0
  96. data/app/assets/javascripts/comfy/vendor/redactor.js +9561 -0
  97. data/app/assets/javascripts/comfy/vendor/redactor/definedlinks.js +53 -0
  98. data/app/assets/javascripts/comfy/vendor/redactor/filemanager.js +64 -0
  99. data/app/assets/javascripts/comfy/vendor/redactor/i18n/ar.js +76 -0
  100. data/app/assets/javascripts/comfy/vendor/redactor/i18n/az.js +75 -0
  101. data/app/assets/javascripts/comfy/vendor/redactor/i18n/ba.js +79 -0
  102. data/app/assets/javascripts/comfy/vendor/redactor/i18n/bg.js +77 -0
  103. data/app/assets/javascripts/comfy/vendor/redactor/i18n/by.js +77 -0
  104. data/app/assets/javascripts/comfy/vendor/redactor/i18n/ca.js +75 -0
  105. data/app/assets/javascripts/comfy/vendor/redactor/i18n/cs.js +87 -0
  106. data/app/assets/javascripts/comfy/vendor/redactor/i18n/da.js +75 -0
  107. data/app/assets/javascripts/comfy/vendor/redactor/i18n/de.js +80 -0
  108. data/app/assets/javascripts/comfy/vendor/redactor/i18n/el.js +76 -0
  109. data/app/assets/javascripts/comfy/vendor/redactor/i18n/en.js +75 -0
  110. data/app/assets/javascripts/comfy/vendor/redactor/i18n/eo.js +76 -0
  111. data/app/assets/javascripts/comfy/vendor/redactor/i18n/es.js +75 -0
  112. data/app/assets/javascripts/comfy/vendor/redactor/i18n/es_AR.js +76 -0
  113. data/app/assets/javascripts/comfy/vendor/redactor/i18n/fa.js +76 -0
  114. data/app/assets/javascripts/comfy/vendor/redactor/i18n/fi.js +75 -0
  115. data/app/assets/javascripts/comfy/vendor/redactor/i18n/fr.js +75 -0
  116. data/app/assets/javascripts/comfy/vendor/redactor/i18n/ge.js +75 -0
  117. data/app/assets/javascripts/comfy/vendor/redactor/i18n/gr.js +75 -0
  118. data/app/assets/javascripts/comfy/vendor/redactor/i18n/he.js +75 -0
  119. data/app/assets/javascripts/comfy/vendor/redactor/i18n/hr.js +76 -0
  120. data/app/assets/javascripts/comfy/vendor/redactor/i18n/hu.js +77 -0
  121. data/app/assets/javascripts/comfy/vendor/redactor/i18n/id.js +76 -0
  122. data/app/assets/javascripts/comfy/vendor/redactor/i18n/it.js +78 -0
  123. data/app/assets/javascripts/comfy/vendor/redactor/i18n/ja.js +76 -0
  124. data/app/assets/javascripts/comfy/vendor/redactor/i18n/kn.js +75 -0
  125. data/app/assets/javascripts/comfy/vendor/redactor/i18n/ko.js +76 -0
  126. data/app/assets/javascripts/comfy/vendor/redactor/i18n/lt.js +75 -0
  127. data/app/assets/javascripts/comfy/vendor/redactor/i18n/lv.js +75 -0
  128. data/app/assets/javascripts/comfy/vendor/redactor/i18n/mk.js +75 -0
  129. data/app/assets/javascripts/comfy/vendor/redactor/i18n/nb.js +75 -0
  130. data/app/assets/javascripts/comfy/vendor/redactor/i18n/nl.js +80 -0
  131. data/app/assets/javascripts/comfy/vendor/redactor/i18n/pl.js +76 -0
  132. data/app/assets/javascripts/comfy/vendor/redactor/i18n/pt-BR.js +75 -0
  133. data/app/assets/javascripts/comfy/vendor/redactor/i18n/pt.js +75 -0
  134. data/app/assets/javascripts/comfy/vendor/redactor/i18n/ro.js +76 -0
  135. data/app/assets/javascripts/comfy/vendor/redactor/i18n/ru.js +76 -0
  136. data/app/assets/javascripts/comfy/vendor/redactor/i18n/sk.js +76 -0
  137. data/app/assets/javascripts/comfy/vendor/redactor/i18n/sl.js +79 -0
  138. data/app/assets/javascripts/comfy/vendor/redactor/i18n/sq.js +79 -0
  139. data/app/assets/javascripts/comfy/vendor/redactor/i18n/sr-CIR.js +79 -0
  140. data/app/assets/javascripts/comfy/vendor/redactor/i18n/sr-LAT.js +79 -0
  141. data/app/assets/javascripts/comfy/vendor/redactor/i18n/sv.js +74 -0
  142. data/app/assets/javascripts/comfy/vendor/redactor/i18n/th.js +74 -0
  143. data/app/assets/javascripts/comfy/vendor/redactor/i18n/tr.js +75 -0
  144. data/app/assets/javascripts/comfy/vendor/redactor/i18n/ua.js +77 -0
  145. data/app/assets/javascripts/comfy/vendor/redactor/i18n/uk.js +77 -0
  146. data/app/assets/javascripts/comfy/vendor/redactor/i18n/vi.js +74 -0
  147. data/app/assets/javascripts/comfy/vendor/redactor/i18n/zh-CN.js +75 -0
  148. data/app/assets/javascripts/comfy/vendor/redactor/i18n/zh-TW.js +75 -0
  149. data/app/assets/javascripts/comfy/vendor/redactor/imagemanager.js +57 -0
  150. data/app/assets/javascripts/comfy/vendor/redactor/table.js +337 -0
  151. data/app/assets/javascripts/comfy/vendor/redactor/video.js +77 -0
  152. data/app/assets/javascripts/comfy/vendor/sortable.min.js +5 -0
  153. data/app/assets/stylesheets/comfy/admin/cms/application.sass +11 -0
  154. data/app/assets/stylesheets/comfy/admin/cms/base.sass +256 -0
  155. data/app/assets/stylesheets/comfy/admin/cms/codemirror_overrides.sass +19 -0
  156. data/app/assets/stylesheets/comfy/admin/cms/custom.sass +1 -0
  157. data/app/assets/stylesheets/comfy/admin/cms/redactor_overrides.sass +22 -0
  158. data/app/assets/stylesheets/comfy/vendor/bootstrap/_alert.scss +51 -0
  159. data/app/assets/stylesheets/comfy/vendor/bootstrap/_badge.scss +54 -0
  160. data/app/assets/stylesheets/comfy/vendor/bootstrap/_breadcrumb.scss +41 -0
  161. data/app/assets/stylesheets/comfy/vendor/bootstrap/_button-group.scss +163 -0
  162. data/app/assets/stylesheets/comfy/vendor/bootstrap/_buttons.scss +137 -0
  163. data/app/assets/stylesheets/comfy/vendor/bootstrap/_card.scss +289 -0
  164. data/app/assets/stylesheets/comfy/vendor/bootstrap/_carousel.scss +197 -0
  165. data/app/assets/stylesheets/comfy/vendor/bootstrap/_close.scss +41 -0
  166. data/app/assets/stylesheets/comfy/vendor/bootstrap/_code.scss +48 -0
  167. data/app/assets/stylesheets/comfy/vendor/bootstrap/_custom-forms.scss +507 -0
  168. data/app/assets/stylesheets/comfy/vendor/bootstrap/_dropdown.scss +191 -0
  169. data/app/assets/stylesheets/comfy/vendor/bootstrap/_forms.scss +330 -0
  170. data/app/assets/stylesheets/comfy/vendor/bootstrap/_functions.scss +86 -0
  171. data/app/assets/stylesheets/comfy/vendor/bootstrap/_grid.scss +52 -0
  172. data/app/assets/stylesheets/comfy/vendor/bootstrap/_images.scss +42 -0
  173. data/app/assets/stylesheets/comfy/vendor/bootstrap/_input-group.scss +193 -0
  174. data/app/assets/stylesheets/comfy/vendor/bootstrap/_jumbotron.scss +17 -0
  175. data/app/assets/stylesheets/comfy/vendor/bootstrap/_list-group.scss +149 -0
  176. data/app/assets/stylesheets/comfy/vendor/bootstrap/_media.scss +8 -0
  177. data/app/assets/stylesheets/comfy/vendor/bootstrap/_mixins.scss +47 -0
  178. data/app/assets/stylesheets/comfy/vendor/bootstrap/_modal.scss +229 -0
  179. data/app/assets/stylesheets/comfy/vendor/bootstrap/_nav.scss +120 -0
  180. data/app/assets/stylesheets/comfy/vendor/bootstrap/_navbar.scss +294 -0
  181. data/app/assets/stylesheets/comfy/vendor/bootstrap/_pagination.scss +73 -0
  182. data/app/assets/stylesheets/comfy/vendor/bootstrap/_popover.scss +171 -0
  183. data/app/assets/stylesheets/comfy/vendor/bootstrap/_print.scss +141 -0
  184. data/app/assets/stylesheets/comfy/vendor/bootstrap/_progress.scss +43 -0
  185. data/app/assets/stylesheets/comfy/vendor/bootstrap/_reboot.scss +483 -0
  186. data/app/assets/stylesheets/comfy/vendor/bootstrap/_root.scss +19 -0
  187. data/app/assets/stylesheets/comfy/vendor/bootstrap/_spinners.scss +55 -0
  188. data/app/assets/stylesheets/comfy/vendor/bootstrap/_tables.scss +185 -0
  189. data/app/assets/stylesheets/comfy/vendor/bootstrap/_toasts.scss +44 -0
  190. data/app/assets/stylesheets/comfy/vendor/bootstrap/_tooltip.scss +115 -0
  191. data/app/assets/stylesheets/comfy/vendor/bootstrap/_transitions.scss +20 -0
  192. data/app/assets/stylesheets/comfy/vendor/bootstrap/_type.scss +125 -0
  193. data/app/assets/stylesheets/comfy/vendor/bootstrap/_utilities.scss +17 -0
  194. data/app/assets/stylesheets/comfy/vendor/bootstrap/_variables.scss +1123 -0
  195. data/app/assets/stylesheets/comfy/vendor/bootstrap/bootstrap-grid.scss +29 -0
  196. data/app/assets/stylesheets/comfy/vendor/bootstrap/bootstrap-reboot.scss +12 -0
  197. data/app/assets/stylesheets/comfy/vendor/bootstrap/bootstrap.scss +44 -0
  198. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_alert.scss +13 -0
  199. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_background-variant.scss +21 -0
  200. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_badge.scss +17 -0
  201. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_border-radius.scss +63 -0
  202. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_box-shadow.scss +20 -0
  203. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_breakpoints.scss +123 -0
  204. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_buttons.scss +107 -0
  205. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_caret.scss +62 -0
  206. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_clearfix.scss +7 -0
  207. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_deprecate.scss +10 -0
  208. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_float.scss +14 -0
  209. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_forms.scss +192 -0
  210. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_gradients.scss +45 -0
  211. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_grid-framework.scss +66 -0
  212. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_grid.scss +51 -0
  213. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_hover.scss +37 -0
  214. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_image.scss +36 -0
  215. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_list-group.scss +21 -0
  216. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_lists.scss +7 -0
  217. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_nav-divider.scss +10 -0
  218. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_pagination.scss +22 -0
  219. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_reset-text.scss +17 -0
  220. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_resize.scss +6 -0
  221. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_screen-reader.scss +33 -0
  222. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_size.scss +7 -0
  223. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_table-row.scss +39 -0
  224. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_text-emphasis.scss +16 -0
  225. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_text-hide.scss +11 -0
  226. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_text-truncate.scss +8 -0
  227. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_transition.scss +16 -0
  228. data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_visibility.scss +8 -0
  229. data/app/assets/stylesheets/comfy/vendor/bootstrap/utilities/_align.scss +8 -0
  230. data/app/assets/stylesheets/comfy/vendor/bootstrap/utilities/_background.scss +19 -0
  231. data/app/assets/stylesheets/comfy/vendor/bootstrap/utilities/_borders.scss +75 -0
  232. data/app/assets/stylesheets/comfy/vendor/bootstrap/utilities/_clearfix.scss +3 -0
  233. data/app/assets/stylesheets/comfy/vendor/bootstrap/utilities/_display.scss +26 -0
  234. data/app/assets/stylesheets/comfy/vendor/bootstrap/utilities/_embed.scss +39 -0
  235. data/app/assets/stylesheets/comfy/vendor/bootstrap/utilities/_flex.scss +51 -0
  236. data/app/assets/stylesheets/comfy/vendor/bootstrap/utilities/_float.scss +11 -0
  237. data/app/assets/stylesheets/comfy/vendor/bootstrap/utilities/_overflow.scss +5 -0
  238. data/app/assets/stylesheets/comfy/vendor/bootstrap/utilities/_position.scss +32 -0
  239. data/app/assets/stylesheets/comfy/vendor/bootstrap/utilities/_screenreaders.scss +11 -0
  240. data/app/assets/stylesheets/comfy/vendor/bootstrap/utilities/_shadows.scss +6 -0
  241. data/app/assets/stylesheets/comfy/vendor/bootstrap/utilities/_sizing.scss +20 -0
  242. data/app/assets/stylesheets/comfy/vendor/bootstrap/utilities/_spacing.scss +73 -0
  243. data/app/assets/stylesheets/comfy/vendor/bootstrap/utilities/_stretched-link.scss +19 -0
  244. data/app/assets/stylesheets/comfy/vendor/bootstrap/utilities/_text.scss +72 -0
  245. data/app/assets/stylesheets/comfy/vendor/bootstrap/utilities/_visibility.scss +13 -0
  246. data/app/assets/stylesheets/comfy/vendor/bootstrap/vendor/_rfs.scss +204 -0
  247. data/app/assets/stylesheets/comfy/vendor/codemirror.css +346 -0
  248. data/app/assets/stylesheets/comfy/vendor/flatpickr.min.css +13 -0
  249. data/app/assets/stylesheets/comfy/vendor/fontawesome.css +343 -0
  250. data/app/assets/stylesheets/comfy/vendor/redactor.css +948 -0
  251. data/app/controllers/application_controller.rb +7 -0
  252. data/app/controllers/comfy/admin/base_controller.rb +22 -0
  253. data/app/controllers/comfy/admin/cms/base_controller.rb +55 -0
  254. data/app/controllers/comfy/admin/cms/categories_controller.rb +40 -0
  255. data/app/controllers/comfy/admin/cms/files_controller.rb +142 -0
  256. data/app/controllers/comfy/admin/cms/layouts_controller.rb +69 -0
  257. data/app/controllers/comfy/admin/cms/pages_controller.rb +156 -0
  258. data/app/controllers/comfy/admin/cms/revisions/base_controller.rb +50 -0
  259. data/app/controllers/comfy/admin/cms/revisions/layout_controller.rb +18 -0
  260. data/app/controllers/comfy/admin/cms/revisions/page_controller.rb +30 -0
  261. data/app/controllers/comfy/admin/cms/revisions/snippet_controller.rb +18 -0
  262. data/app/controllers/comfy/admin/cms/revisions/translation_controller.rb +31 -0
  263. data/app/controllers/comfy/admin/cms/sites_controller.rb +69 -0
  264. data/app/controllers/comfy/admin/cms/snippets_controller.rb +66 -0
  265. data/app/controllers/comfy/admin/cms/translations_controller.rb +107 -0
  266. data/app/controllers/comfy/cms/assets_controller.rb +40 -0
  267. data/app/controllers/comfy/cms/base_controller.rb +33 -0
  268. data/app/controllers/comfy/cms/content_controller.rb +87 -0
  269. data/app/controllers/concerns/comfy/paginate.rb +16 -0
  270. data/app/controllers/concerns/comfy/reorder_action.rb +19 -0
  271. data/app/helpers/comfy/admin/cms_helper.rb +49 -0
  272. data/app/helpers/comfy/cms_helper.rb +73 -0
  273. data/app/models/comfy/cms/categorization.rb +16 -0
  274. data/app/models/comfy/cms/category.rb +24 -0
  275. data/app/models/comfy/cms/file.rb +57 -0
  276. data/app/models/comfy/cms/fragment.rb +59 -0
  277. data/app/models/comfy/cms/layout.rb +113 -0
  278. data/app/models/comfy/cms/page.rb +169 -0
  279. data/app/models/comfy/cms/revision.rb +12 -0
  280. data/app/models/comfy/cms/site.rb +94 -0
  281. data/app/models/comfy/cms/snippet.rb +45 -0
  282. data/app/models/comfy/cms/translation.rb +43 -0
  283. data/app/models/concerns/comfy/cms/with_categories.rb +53 -0
  284. data/app/models/concerns/comfy/cms/with_fragments.rb +125 -0
  285. data/app/views/comfy/admin/cms/categories/_categories.html.haml +4 -0
  286. data/app/views/comfy/admin/cms/categories/_edit.html.haml +7 -0
  287. data/app/views/comfy/admin/cms/categories/_form.html.haml +5 -0
  288. data/app/views/comfy/admin/cms/categories/_index.html.haml +28 -0
  289. data/app/views/comfy/admin/cms/categories/_show.html.haml +15 -0
  290. data/app/views/comfy/admin/cms/categories/create.js.erb +7 -0
  291. data/app/views/comfy/admin/cms/categories/destroy.js.erb +8 -0
  292. data/app/views/comfy/admin/cms/categories/edit.js.erb +3 -0
  293. data/app/views/comfy/admin/cms/categories/update.js.erb +6 -0
  294. data/app/views/comfy/admin/cms/files/_file.html.haml +31 -0
  295. data/app/views/comfy/admin/cms/files/_form.html.haml +26 -0
  296. data/app/views/comfy/admin/cms/files/_modal.html.haml +3 -0
  297. data/app/views/comfy/admin/cms/files/destroy.js.erb +4 -0
  298. data/app/views/comfy/admin/cms/files/edit.html.haml +5 -0
  299. data/app/views/comfy/admin/cms/files/index.html.haml +29 -0
  300. data/app/views/comfy/admin/cms/files/new.html.haml +5 -0
  301. data/app/views/comfy/admin/cms/fragments/_form_fragment_attachments.html.haml +23 -0
  302. data/app/views/comfy/admin/cms/fragments/_form_fragments.html.haml +38 -0
  303. data/app/views/comfy/admin/cms/layouts/_form.html.haml +20 -0
  304. data/app/views/comfy/admin/cms/layouts/_index_branch.html.haml +26 -0
  305. data/app/views/comfy/admin/cms/layouts/edit.html.haml +9 -0
  306. data/app/views/comfy/admin/cms/layouts/index.html.haml +10 -0
  307. data/app/views/comfy/admin/cms/layouts/new.html.haml +5 -0
  308. data/app/views/comfy/admin/cms/pages/_form.html.haml +31 -0
  309. data/app/views/comfy/admin/cms/pages/_index_branch.html.haml +44 -0
  310. data/app/views/comfy/admin/cms/pages/edit.html.haml +10 -0
  311. data/app/views/comfy/admin/cms/pages/index.html.haml +13 -0
  312. data/app/views/comfy/admin/cms/pages/new.html.haml +5 -0
  313. data/app/views/comfy/admin/cms/pages/toggle_branch.js.erb +13 -0
  314. data/app/views/comfy/admin/cms/revisions/_sidebar.html.haml +2 -0
  315. data/app/views/comfy/admin/cms/revisions/show.html.haml +36 -0
  316. data/app/views/comfy/admin/cms/sites/_form.html.haml +15 -0
  317. data/app/views/comfy/admin/cms/sites/edit.html.haml +5 -0
  318. data/app/views/comfy/admin/cms/sites/index.html.haml +28 -0
  319. data/app/views/comfy/admin/cms/sites/new.html.haml +5 -0
  320. data/app/views/comfy/admin/cms/snippets/_form.html.haml +13 -0
  321. data/app/views/comfy/admin/cms/snippets/edit.html.haml +9 -0
  322. data/app/views/comfy/admin/cms/snippets/index.html.haml +33 -0
  323. data/app/views/comfy/admin/cms/snippets/new.html.haml +5 -0
  324. data/app/views/comfy/admin/cms/translations/_form.html.haml +20 -0
  325. data/app/views/comfy/admin/cms/translations/_sidebar.html.haml +19 -0
  326. data/app/views/comfy/admin/cms/translations/edit.html.haml +10 -0
  327. data/app/views/comfy/admin/cms/translations/new.html.haml +5 -0
  328. data/app/views/kaminari/comfy/_first_page.html.haml +3 -0
  329. data/app/views/kaminari/comfy/_gap.html.haml +2 -0
  330. data/app/views/kaminari/comfy/_last_page.html.haml +3 -0
  331. data/app/views/kaminari/comfy/_next_page.html.haml +2 -0
  332. data/app/views/kaminari/comfy/_page.html.haml +2 -0
  333. data/app/views/kaminari/comfy/_paginator.html.haml +11 -0
  334. data/app/views/kaminari/comfy/_prev_page.html.haml +2 -0
  335. data/app/views/layouts/comfy/admin/cms.html.haml +4 -0
  336. data/app/views/layouts/comfy/admin/cms/_body.html.haml +14 -0
  337. data/app/views/layouts/comfy/admin/cms/_flash.html.haml +4 -0
  338. data/app/views/layouts/comfy/admin/cms/_footer_js.html.haml +6 -0
  339. data/app/views/layouts/comfy/admin/cms/_head.html.haml +19 -0
  340. data/app/views/layouts/comfy/admin/cms/_left.html.haml +39 -0
  341. data/app/views/layouts/comfy/admin/cms/_right.html.haml +5 -0
  342. data/bin/bundle +3 -0
  343. data/bin/rails +4 -0
  344. data/bin/rake +4 -0
  345. data/bin/setup +36 -0
  346. data/bin/update +31 -0
  347. data/bin/yarn +11 -0
  348. data/comfortable_mexican_sofa.gemspec +34 -0
  349. data/config.ru +6 -0
  350. data/config/application.rb +39 -0
  351. data/config/boot.rb +7 -0
  352. data/config/cms_routes.rb +8 -0
  353. data/config/database.yml +11 -0
  354. data/config/environment.rb +7 -0
  355. data/config/environments/development.rb +64 -0
  356. data/config/environments/test.rb +55 -0
  357. data/config/initializers/comfortable_mexican_sofa.rb +122 -0
  358. data/config/locales/ca.yml +263 -0
  359. data/config/locales/cs.yml +263 -0
  360. data/config/locales/da.yml +263 -0
  361. data/config/locales/de.yml +263 -0
  362. data/config/locales/en.yml +263 -0
  363. data/config/locales/es.yml +263 -0
  364. data/config/locales/fi.yml +263 -0
  365. data/config/locales/fr.yml +263 -0
  366. data/config/locales/gr.yml +263 -0
  367. data/config/locales/hr.yml +263 -0
  368. data/config/locales/it.yml +263 -0
  369. data/config/locales/ja.yml +263 -0
  370. data/config/locales/nb.yml +263 -0
  371. data/config/locales/nl.yml +263 -0
  372. data/config/locales/pl.yml +263 -0
  373. data/config/locales/pt-BR.yml +263 -0
  374. data/config/locales/ru.yml +263 -0
  375. data/config/locales/sk.yml +263 -0
  376. data/config/locales/sv.yml +263 -0
  377. data/config/locales/tr.yml +263 -0
  378. data/config/locales/uk.yml +263 -0
  379. data/config/locales/zh-CN.yml +263 -0
  380. data/config/locales/zh-TW.yml +263 -0
  381. data/config/storage.yml +35 -0
  382. data/db/cms_seeds/sample-site/files/_default.jpg.yml +5 -0
  383. data/db/cms_seeds/sample-site/files/default.jpg +0 -0
  384. data/db/cms_seeds/sample-site/layouts/default/content.html +16 -0
  385. data/db/cms_seeds/sample-site/layouts/default/nested/content.html +14 -0
  386. data/db/cms_seeds/sample-site/pages/index/child_a/content.html +7 -0
  387. data/db/cms_seeds/sample-site/pages/index/child_b/content.html +6 -0
  388. data/db/cms_seeds/sample-site/pages/index/cms logo.png +0 -0
  389. data/db/cms_seeds/sample-site/pages/index/content.es.html +6 -0
  390. data/db/cms_seeds/sample-site/pages/index/content.fr.html +6 -0
  391. data/db/cms_seeds/sample-site/pages/index/content.html +25 -0
  392. data/db/cms_seeds/sample-site/pages/index/footer.png +0 -0
  393. data/db/cms_seeds/sample-site/pages/index/header.png +0 -0
  394. data/db/cms_seeds/sample-site/snippets/default.html +8 -0
  395. data/db/migrate/00_create_active_storage_tables.active_storage.rb +26 -0
  396. data/db/migrate/01_create_cms.rb +142 -0
  397. data/lib/comfortable_mexican_sofa.rb +60 -0
  398. data/lib/comfortable_mexican_sofa/access_control/admin_authentication.rb +24 -0
  399. data/lib/comfortable_mexican_sofa/access_control/admin_authorization.rb +12 -0
  400. data/lib/comfortable_mexican_sofa/access_control/public_authentication.rb +12 -0
  401. data/lib/comfortable_mexican_sofa/access_control/public_authorization.rb +12 -0
  402. data/lib/comfortable_mexican_sofa/configuration.rb +139 -0
  403. data/lib/comfortable_mexican_sofa/content.rb +31 -0
  404. data/lib/comfortable_mexican_sofa/content/block.rb +14 -0
  405. data/lib/comfortable_mexican_sofa/content/params_parser.rb +149 -0
  406. data/lib/comfortable_mexican_sofa/content/renderer.rb +149 -0
  407. data/lib/comfortable_mexican_sofa/content/tag.rb +50 -0
  408. data/lib/comfortable_mexican_sofa/content/tags/asset.rb +59 -0
  409. data/lib/comfortable_mexican_sofa/content/tags/checkbox.rb +29 -0
  410. data/lib/comfortable_mexican_sofa/content/tags/date.rb +21 -0
  411. data/lib/comfortable_mexican_sofa/content/tags/datetime.rb +44 -0
  412. data/lib/comfortable_mexican_sofa/content/tags/file.rb +72 -0
  413. data/lib/comfortable_mexican_sofa/content/tags/file_link.rb +63 -0
  414. data/lib/comfortable_mexican_sofa/content/tags/files.rb +43 -0
  415. data/lib/comfortable_mexican_sofa/content/tags/fragment.rb +66 -0
  416. data/lib/comfortable_mexican_sofa/content/tags/helper.rb +55 -0
  417. data/lib/comfortable_mexican_sofa/content/tags/markdown.rb +24 -0
  418. data/lib/comfortable_mexican_sofa/content/tags/mixins/file_content.rb +43 -0
  419. data/lib/comfortable_mexican_sofa/content/tags/number.rb +20 -0
  420. data/lib/comfortable_mexican_sofa/content/tags/page_file_link.rb +84 -0
  421. data/lib/comfortable_mexican_sofa/content/tags/partial.rb +49 -0
  422. data/lib/comfortable_mexican_sofa/content/tags/snippet.rb +34 -0
  423. data/lib/comfortable_mexican_sofa/content/tags/template.rb +44 -0
  424. data/lib/comfortable_mexican_sofa/content/tags/text.rb +20 -0
  425. data/lib/comfortable_mexican_sofa/content/tags/textarea.rb +20 -0
  426. data/lib/comfortable_mexican_sofa/content/tags/wysiwyg.rb +21 -0
  427. data/lib/comfortable_mexican_sofa/engine.rb +31 -0
  428. data/lib/comfortable_mexican_sofa/error.rb +32 -0
  429. data/lib/comfortable_mexican_sofa/extensions/acts_as_tree.rb +120 -0
  430. data/lib/comfortable_mexican_sofa/extensions/has_revisions.rb +72 -0
  431. data/lib/comfortable_mexican_sofa/form_builder.rb +47 -0
  432. data/lib/comfortable_mexican_sofa/render_methods.rb +112 -0
  433. data/lib/comfortable_mexican_sofa/routes/cms.rb +18 -0
  434. data/lib/comfortable_mexican_sofa/routes/cms_admin.rb +58 -0
  435. data/lib/comfortable_mexican_sofa/routing.rb +12 -0
  436. data/lib/comfortable_mexican_sofa/seeds.rb +114 -0
  437. data/lib/comfortable_mexican_sofa/seeds/file/exporter.rb +43 -0
  438. data/lib/comfortable_mexican_sofa/seeds/file/importer.rb +63 -0
  439. data/lib/comfortable_mexican_sofa/seeds/layout/exporter.rb +40 -0
  440. data/lib/comfortable_mexican_sofa/seeds/layout/importer.rb +62 -0
  441. data/lib/comfortable_mexican_sofa/seeds/page/exporter.rb +92 -0
  442. data/lib/comfortable_mexican_sofa/seeds/page/importer.rb +219 -0
  443. data/lib/comfortable_mexican_sofa/seeds/snippet/exporter.rb +34 -0
  444. data/lib/comfortable_mexican_sofa/seeds/snippet/importer.rb +51 -0
  445. data/lib/comfortable_mexican_sofa/version.rb +9 -0
  446. data/lib/comfortable_mexican_sofa/view_hooks.rb +35 -0
  447. data/lib/generators/comfy/cms/README +17 -0
  448. data/lib/generators/comfy/cms/assets_generator.rb +18 -0
  449. data/lib/generators/comfy/cms/cms_generator.rb +69 -0
  450. data/lib/generators/comfy/cms/controllers_generator.rb +17 -0
  451. data/lib/generators/comfy/cms/models_generator.rb +17 -0
  452. data/lib/generators/comfy/cms/views_generator.rb +17 -0
  453. data/lib/generators/comfy/scaffold/scaffold_generator.rb +80 -0
  454. data/lib/generators/comfy/scaffold/templates/controller.rb.tt +62 -0
  455. data/lib/generators/comfy/scaffold/templates/migration.rb.tt +11 -0
  456. data/lib/generators/comfy/scaffold/templates/model.rb.tt +21 -0
  457. data/lib/generators/comfy/scaffold/templates/tests/controller.rb.tt +115 -0
  458. data/lib/generators/comfy/scaffold/templates/tests/fixture.yml.tt +4 -0
  459. data/lib/generators/comfy/scaffold/templates/tests/model.rb.tt +26 -0
  460. data/lib/generators/comfy/scaffold/templates/views/_form.haml.tt +7 -0
  461. data/lib/generators/comfy/scaffold/templates/views/edit.haml.tt +5 -0
  462. data/lib/generators/comfy/scaffold/templates/views/index.haml.tt +21 -0
  463. data/lib/generators/comfy/scaffold/templates/views/new.haml.tt +5 -0
  464. data/lib/generators/comfy/scaffold/templates/views/show.haml.tt +4 -0
  465. data/lib/tasks/cms_seeds.rake +40 -0
  466. data/public/favicon.ico +0 -0
  467. metadata +648 -0
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "routes/cms_admin"
4
+ require_relative "routes/cms"
5
+
6
+ class ActionDispatch::Routing::Mapper
7
+
8
+ def comfy_route(identifier, options = {})
9
+ send("comfy_route_#{identifier}", options)
10
+ end
11
+
12
+ end
@@ -0,0 +1,114 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ComfortableMexicanSofa::Seeds
4
+
5
+ SEED_CLASSES = %w[Layout Page Snippet File].freeze
6
+
7
+ class Error < StandardError; end
8
+
9
+ require "mimemagic"
10
+
11
+ class Importer
12
+
13
+ attr_accessor :site,
14
+ :path,
15
+ :from,
16
+ :to,
17
+ :seed_ids
18
+
19
+ # `from` and `to` indicate site identifier and folder name
20
+ def initialize(from, to = from)
21
+ self.from = from
22
+ self.to = to
23
+ self.site = Comfy::Cms::Site.where(identifier: to).first!
24
+ self.seed_ids = []
25
+
26
+ unless ::File.exist?(path = ::File.join(ComfortableMexicanSofa.config.seeds_path, from))
27
+ raise Error, "Folder for import: '#{path}' is not found"
28
+ end
29
+ end
30
+
31
+ # if passed nil will use default seed classes
32
+ def import!(classes = nil)
33
+ classes ||= SEED_CLASSES
34
+ classes.each do |klass|
35
+ klass = "ComfortableMexicanSofa::Seeds::#{klass}::Importer"
36
+ klass.constantize.new(from, to).import!
37
+ end
38
+ end
39
+
40
+ private
41
+
42
+ # Splitting file content in sections delimited by headers that look like this:
43
+ # [header]
44
+ # some content
45
+ # [header 2]
46
+ # some more content
47
+ def parse_file_content(file_path)
48
+ text = ::File.read(file_path)
49
+ tokens = text.split(%r{^\[(.*?)\]\r?\n})
50
+ tokens.shift # first item should be blank
51
+ tokens.in_groups_of(2).each_with_object({}) do |pair, h|
52
+ h[pair[0]] = pair[1]
53
+ end
54
+ end
55
+
56
+ def fresh_seed?(object, file_path)
57
+ object.new_record? || ::File.mtime(file_path) > object.updated_at
58
+ end
59
+
60
+ def category_names_to_ids(record, names)
61
+ [names].flatten.map do |name|
62
+ category = site.categories.find_or_create_by(
63
+ label: name,
64
+ categorized_type: record.class.to_s
65
+ )
66
+ category.id
67
+ end
68
+ end
69
+
70
+ end
71
+
72
+ class Exporter
73
+
74
+ attr_accessor :site,
75
+ :path,
76
+ :from,
77
+ :to
78
+
79
+ def initialize(from, to = from)
80
+ self.from = from
81
+ self.to = to
82
+ self.site = Comfy::Cms::Site.where(identifier: from).first!
83
+ end
84
+
85
+ # if passed nil will use default seed classes
86
+ def export!(classes = nil)
87
+ classes ||= SEED_CLASSES
88
+ classes.each do |klass|
89
+ klass = "ComfortableMexicanSofa::Seeds::#{klass}::Exporter"
90
+ klass.constantize.new(from, to).export!
91
+ end
92
+ end
93
+
94
+ private
95
+
96
+ # Writing to the seed file. Takes in file handler and array of hashes with
97
+ # `header` and `content` keys
98
+ def write_file_content(path, data)
99
+ ::File.open(::File.join(path), "wb") do |f|
100
+ data.each do |item|
101
+ f.write("[#{item[:header]}]\n")
102
+ f.write("#{item[:content]}\n")
103
+ end
104
+ end
105
+ end
106
+
107
+ def prepare_folder!(path)
108
+ FileUtils.rm_rf(path)
109
+ FileUtils.mkdir_p(path)
110
+ end
111
+
112
+ end
113
+
114
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ComfortableMexicanSofa::Seeds::File
4
+ class Exporter < ComfortableMexicanSofa::Seeds::Exporter
5
+
6
+ def initialize(from, to = from)
7
+ super
8
+ self.path = ::File.join(ComfortableMexicanSofa.config.seeds_path, to, "files/")
9
+ end
10
+
11
+ def export!
12
+ prepare_folder!(path)
13
+
14
+ site.files.each do |file|
15
+ file_path = File.join(path, file.attachment.filename.to_s)
16
+
17
+ # writing attributes
18
+ ::File.open(::File.join(path, "_#{file.attachment.filename}.yml"), "w") do |f|
19
+ f.write({
20
+ "label" => file.label,
21
+ "description" => file.description,
22
+ "categories" => file.categories.map(&:label)
23
+ }.to_yaml)
24
+ end
25
+
26
+ # writing content
27
+ begin
28
+ ::File.open(::File.join(path, ::File.basename(file_path)), "wb") do |f|
29
+ f.write(file.attachment.download)
30
+ end
31
+ rescue Errno::ENOENT, OpenURI::HTTPError
32
+ message = "[CMS SEEDS] No physical File \t #{file.attachment.filename}"
33
+ ComfortableMexicanSofa.logger.warn(message)
34
+ next
35
+ end
36
+
37
+ message = "[CMS SEEDS] Exported File \t #{file.attachment.filename}"
38
+ ComfortableMexicanSofa.logger.info(message)
39
+ end
40
+ end
41
+
42
+ end
43
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ComfortableMexicanSofa::Seeds::File
4
+ class Importer < ComfortableMexicanSofa::Seeds::Importer
5
+
6
+ def initialize(from, to = from)
7
+ super
8
+ self.path = ::File.join(ComfortableMexicanSofa.config.seeds_path, from, "files/")
9
+ end
10
+
11
+ def import!
12
+ Dir["#{path}[^_]*"].each do |file_path|
13
+ filename = ::File.basename(file_path)
14
+
15
+ file = site.files.with_attached_attachment
16
+ .where("active_storage_blobs.filename" => filename).references(:blob).first ||
17
+ site.files.new
18
+
19
+ # We need to track actual file and its attributes
20
+ fresh_file = false
21
+
22
+ if File.exist?(attrs_path = File.join(path, "_#{filename}.yml"))
23
+ if fresh_seed?(file, attrs_path)
24
+ fresh_file = true
25
+
26
+ attrs = YAML.safe_load(File.read(attrs_path))
27
+ category_ids = category_names_to_ids(file, attrs.delete("categories"))
28
+ file.attributes = attrs.merge(
29
+ category_ids: category_ids
30
+ )
31
+ end
32
+ end
33
+
34
+ if fresh_seed?(file, file_path)
35
+ fresh_file = true
36
+
37
+ file_handler = File.open(file_path)
38
+ file.file = {
39
+ io: file_handler,
40
+ filename: filename,
41
+ content_type: MimeMagic.by_magic(file_handler)
42
+ }
43
+ end
44
+
45
+ if fresh_file
46
+ if file.save
47
+ message = "[CMS SEEDS] Imported File \t #{file_path}"
48
+ ComfortableMexicanSofa.logger.info(message)
49
+ else
50
+ message = "[CMS SEEDS] Failed to import File \n#{file.errors.inspect}"
51
+ ComfortableMexicanSofa.logger.warn(message)
52
+ end
53
+ end
54
+
55
+ seed_ids << file.id
56
+ end
57
+
58
+ # cleaning up
59
+ site.files.where("id NOT IN (?)", seed_ids).destroy_all
60
+ end
61
+
62
+ end
63
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ComfortableMexicanSofa::Seeds::Layout
4
+ class Exporter < ComfortableMexicanSofa::Seeds::Exporter
5
+
6
+ def initialize(from, to = from)
7
+ super
8
+ self.path = ::File.join(ComfortableMexicanSofa.config.seeds_path, to, "layouts/")
9
+ end
10
+
11
+ def export!
12
+ prepare_folder!(path)
13
+
14
+ site.layouts.each do |layout|
15
+ layout_path = File.join(path, layout.ancestors.reverse.collect(&:identifier), layout.identifier)
16
+ FileUtils.mkdir_p(layout_path)
17
+
18
+ path = ::File.join(layout_path, "content.html")
19
+ data = []
20
+
21
+ attrs = {
22
+ "label" => layout.label,
23
+ "app_layout" => layout.app_layout,
24
+ "position" => layout.position
25
+ }.to_yaml
26
+
27
+ data << { header: "attributes", content: attrs }
28
+ data << { header: "content", content: layout.content }
29
+ data << { header: "js", content: layout.js }
30
+ data << { header: "css", content: layout.css }
31
+
32
+ write_file_content(path, data)
33
+
34
+ message = "[CMS SEEDS] Exported Layout \t #{layout.identifier}"
35
+ ComfortableMexicanSofa.logger.info(message)
36
+ end
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ComfortableMexicanSofa::Seeds::Layout
4
+ class Importer < ComfortableMexicanSofa::Seeds::Importer
5
+
6
+ def initialize(from, to = from)
7
+ super
8
+ self.path = ::File.join(ComfortableMexicanSofa.config.seeds_path, from, "layouts/")
9
+ end
10
+
11
+ def import!(path = self.path, parent = nil)
12
+ Dir["#{path}*/"].each do |layout_path|
13
+ import_layout(layout_path, parent)
14
+ end
15
+
16
+ # cleaning up
17
+ site.layouts.where("id NOT IN (?)", seed_ids).destroy_all
18
+ end
19
+
20
+ private
21
+
22
+ def import_layout(path, parent)
23
+ identifier = path.split("/").last
24
+
25
+ # reading file content in, resulting in a hash
26
+ content_path = File.join(path, "content.html")
27
+ content_hash = parse_file_content(content_path)
28
+
29
+ # parsing attributes section
30
+ attributes_yaml = content_hash.delete("attributes")
31
+ attrs = YAML.safe_load(attributes_yaml)
32
+
33
+ layout = site.layouts.where(identifier: identifier).first_or_initialize
34
+ layout.parent = parent
35
+
36
+ if fresh_seed?(layout, content_path)
37
+ layout.attributes = attrs.merge(
38
+ app_layout: attrs["app_layout"] || parent.try(:app_layout),
39
+ content: content_hash["content"],
40
+ js: content_hash["js"],
41
+ css: content_hash["css"]
42
+ )
43
+
44
+ if layout.save
45
+ message = "[CMS SEEDS] Imported Layout \t #{layout.identifier}"
46
+ ComfortableMexicanSofa.logger.info(message)
47
+ else
48
+ message = "[CMS SEEDS] Failed to import Layout \n#{layout.errors.inspect}"
49
+ ComfortableMexicanSofa.logger.warn(message)
50
+ end
51
+ end
52
+
53
+ seed_ids << layout.id
54
+
55
+ # importing child layouts (if there are any)
56
+ Dir["#{path}*/"].each do |layout_path|
57
+ import_layout(layout_path, layout)
58
+ end
59
+ end
60
+
61
+ end
62
+ end
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ComfortableMexicanSofa::Seeds::Page
4
+ class Exporter < ComfortableMexicanSofa::Seeds::Exporter
5
+
6
+ def initialize(from, to = from)
7
+ super
8
+ self.path = ::File.join(ComfortableMexicanSofa.config.seeds_path, to, "pages/")
9
+ end
10
+
11
+ def export!
12
+ prepare_folder!(path)
13
+
14
+ site.pages.each do |page|
15
+ page.slug = "index" if page.slug.blank?
16
+ page_path = File.join(path, page.ancestors.reverse.map { |p| p.slug.blank? ? "index" : p.slug }, page.slug)
17
+ FileUtils.mkdir_p(page_path)
18
+
19
+ path = ::File.join(page_path, "content.html")
20
+ data = []
21
+
22
+ attrs = {
23
+ "label" => page.label,
24
+ "layout" => page.layout.try(:identifier),
25
+ "target_page" => page.target_page.try(:full_path),
26
+ "categories" => page.categories.map(&:label),
27
+ "is_published" => page.is_published,
28
+ "position" => page.position
29
+ }.to_yaml
30
+
31
+ data << { header: "attributes", content: attrs }
32
+ data += fragments_data(page, page_path)
33
+
34
+ write_file_content(path, data)
35
+
36
+ message = "[CMS SEEDS] Exported Page \t #{page.full_path}"
37
+ ComfortableMexicanSofa.logger.info(message)
38
+
39
+ export_translations(page, page_path)
40
+ end
41
+ end
42
+
43
+ private
44
+
45
+ def export_translations(page, page_path)
46
+ page.translations.each do |translation|
47
+ path = ::File.join(page_path, "content.#{translation.locale}.html")
48
+ data = []
49
+
50
+ attrs = {
51
+ "label" => translation.label,
52
+ "layout" => translation.layout.try(:identifier),
53
+ "is_published" => page.is_published
54
+ }.to_yaml
55
+
56
+ data << { header: "attributes", content: attrs }
57
+ data += fragments_data(translation, page_path)
58
+
59
+ write_file_content(path, data)
60
+
61
+ message = "[CMS SEEDS] Exported Translation \t #{translation.locale}"
62
+ ComfortableMexicanSofa.logger.info(message)
63
+ end
64
+ end
65
+
66
+ # Collecting fragment data and writing attachment files to disk
67
+ def fragments_data(record, page_path)
68
+ record.fragments.collect do |frag|
69
+ header = "#{frag.tag} #{frag.identifier}"
70
+ content =
71
+ case frag.tag
72
+ when "datetime", "date"
73
+ frag.datetime
74
+ when "checkbox"
75
+ frag.boolean
76
+ when "file", "files"
77
+ frag.attachments.map do |attachment|
78
+ ::File.open(::File.join(page_path, attachment.filename.to_s), "wb") do |f|
79
+ f.write(attachment.download)
80
+ end
81
+ attachment.filename
82
+ end.join("\n")
83
+ else
84
+ frag.content
85
+ end
86
+
87
+ { header: header, content: content }
88
+ end
89
+ end
90
+
91
+ end
92
+ end
@@ -0,0 +1,219 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ComfortableMexicanSofa::Seeds::Page
4
+ class Importer < ComfortableMexicanSofa::Seeds::Importer
5
+
6
+ # tracking target page linking. Since we might be linking to something that
7
+ # doesn't exist yet, we'll defer linking to the end of import
8
+ attr_accessor :target_pages
9
+
10
+ def initialize(from, to = from)
11
+ super
12
+ self.path = ::File.join(ComfortableMexicanSofa.config.seeds_path, from, "pages/")
13
+ end
14
+
15
+ def import!
16
+ import_page(File.join(path, "index/"), nil)
17
+
18
+ link_target_pages
19
+
20
+ # Remove pages not found in seeds
21
+ site.pages.where("id NOT IN (?)", seed_ids).destroy_all
22
+ end
23
+
24
+ private
25
+
26
+ # Recursive function that will be called for each child page (subfolder)
27
+ def import_page(path, parent)
28
+ slug = path.split("/").last
29
+
30
+ # setting page record
31
+ page =
32
+ if parent.present?
33
+ child = site.pages.where(slug: slug).first_or_initialize
34
+ child.parent = parent
35
+ child
36
+ else
37
+ site.pages.root || site.pages.new(slug: slug)
38
+ end
39
+
40
+ content_path = File.join(path, "content.html")
41
+
42
+ # If file is newer than page record we'll process it
43
+ if fresh_seed?(page, content_path)
44
+
45
+ # reading file content in, resulting in a hash
46
+ fragments_hash = parse_file_content(content_path)
47
+
48
+ # parsing attributes section
49
+ attributes_yaml = fragments_hash.delete("attributes")
50
+ attrs = YAML.safe_load(attributes_yaml)
51
+
52
+ # applying attributes
53
+ layout = site.layouts.find_by(identifier: attrs.delete("layout")) || parent.try(:layout)
54
+ category_ids = category_names_to_ids(page, attrs.delete("categories"))
55
+ target_page = attrs.delete("target_page")
56
+
57
+ page.attributes = attrs.merge(
58
+ layout: layout,
59
+ category_ids: category_ids
60
+ )
61
+
62
+ # applying fragments
63
+ old_frag_identifiers = page.fragments.pluck(:identifier)
64
+
65
+ new_frag_identifiers, fragments_attributes =
66
+ construct_fragments_attributes(fragments_hash, page, path)
67
+ page.fragments_attributes = fragments_attributes
68
+
69
+ if page.save
70
+ message = "[CMS SEEDS] Imported Page \t #{page.full_path}"
71
+ ComfortableMexicanSofa.logger.info(message)
72
+
73
+ # defering target page linking
74
+ if target_page.present?
75
+ self.target_pages ||= {}
76
+ self.target_pages[page.id] = target_page
77
+ end
78
+
79
+ # cleaning up old fragments
80
+ page.fragments.where(identifier: old_frag_identifiers - new_frag_identifiers).destroy_all
81
+
82
+ else
83
+ message = "[CMS SEEDS] Failed to import Page \n#{page.errors.inspect}"
84
+ ComfortableMexicanSofa.logger.warn(message)
85
+ end
86
+ end
87
+
88
+ import_translations(path, page)
89
+
90
+ # Tracking what page from seeds we're working with. So we can remove pages
91
+ # that are no longer in seeds
92
+ seed_ids << page.id
93
+
94
+ # importing child pages (if there are any)
95
+ Dir["#{path}*/"].each do |page_path|
96
+ import_page(page_path, page)
97
+ end
98
+ end
99
+
100
+ # Importing translations for given page. They look like `content.locale.html`
101
+ def import_translations(path, page)
102
+ old_translations = page.translations.pluck(:locale)
103
+ new_translations = []
104
+
105
+ Dir["#{path}content.*.html"].each do |file_path|
106
+ locale = File.basename(file_path).match(%r{content\.(\w+)\.html})[1]
107
+ new_translations << locale
108
+
109
+ translation = page.translations.where(locale: locale).first_or_initialize
110
+
111
+ next unless fresh_seed?(translation, file_path)
112
+
113
+ # reading file content in, resulting in a hash
114
+ fragments_hash = parse_file_content(file_path)
115
+
116
+ # parsing attributes section
117
+ attributes_yaml = fragments_hash.delete("attributes")
118
+ attrs = YAML.safe_load(attributes_yaml)
119
+
120
+ # applying attributes
121
+ layout = site.layouts.find_by(identifier: attrs.delete("layout")) || page.try(:layout)
122
+ translation.attributes = attrs.merge(
123
+ layout: layout
124
+ )
125
+
126
+ # applying fragments
127
+ old_frag_identifiers = translation.fragments.pluck(:identifier)
128
+
129
+ new_frag_identifiers, fragments_attributes =
130
+ construct_fragments_attributes(fragments_hash, translation, path)
131
+ translation.fragments_attributes = fragments_attributes
132
+
133
+ if translation.save
134
+ message = "[CMS SEEDS] Imported Translation \t #{locale}"
135
+ ComfortableMexicanSofa.logger.info(message)
136
+
137
+ # cleaning up old fragments
138
+ frags_to_remove = old_frag_identifiers - new_frag_identifiers
139
+ translation.fragments.where(identifier: frags_to_remove).destroy_all
140
+
141
+ else
142
+ message = "[CMS SEEDS] Failed to import Translation \n#{locale}"
143
+ ComfortableMexicanSofa.logger.warn(message)
144
+ end
145
+ end
146
+
147
+ # Cleaning up removed translations
148
+ translations_to_remove = old_translations - new_translations
149
+ page.translations.where(locale: translations_to_remove).destroy_all
150
+ end
151
+
152
+ # Constructing frag attributes hash that can be assigned to page or translation
153
+ # also returning list of frag identifiers so we can destroy old ones
154
+ def construct_fragments_attributes(hash, record, path)
155
+ frag_identifiers = []
156
+ frag_attributes = hash.collect do |frag_header, frag_content|
157
+ tag, identifier = frag_header.split
158
+ frag_hash = {
159
+ identifier: identifier,
160
+ tag: tag
161
+ }
162
+
163
+ # tracking fragments that need removing later
164
+ frag_identifiers << identifier
165
+
166
+ # based on tag we need to cram content in proper place and proper format
167
+ case tag
168
+ when "date", "datetime"
169
+ frag_hash[:datetime] = frag_content
170
+ when "checkbox"
171
+ frag_hash[:boolean] = frag_content
172
+ when "file", "files"
173
+ files, file_ids_destroy = files_content(record, identifier, path, frag_content)
174
+ frag_hash[:files] = files
175
+ frag_hash[:file_ids_destroy] = file_ids_destroy
176
+ else
177
+ frag_hash[:content] = frag_content
178
+ end
179
+
180
+ frag_hash
181
+ end
182
+
183
+ [frag_identifiers, frag_attributes]
184
+ end
185
+
186
+ # Preparing fragment attachments. Returns hashes with file data for
187
+ # ActiveStorage and a list of ids of old attachements to destroy
188
+ def files_content(record, identifier, path, frag_content)
189
+ # preparing attachments
190
+ files = frag_content.split("\n").collect do |filename|
191
+ file_handler = File.open(File.join(path, filename))
192
+ {
193
+ io: file_handler,
194
+ filename: filename,
195
+ content_type: MimeMagic.by_magic(file_handler)
196
+ }
197
+ end
198
+
199
+ # ensuring that old attachments get removed
200
+ ids_destroy = []
201
+ if (frag = record.fragments.find_by(identifier: identifier))
202
+ ids_destroy = frag.attachments.pluck(:id)
203
+ end
204
+
205
+ [files, ids_destroy]
206
+ end
207
+
208
+ def link_target_pages
209
+ return unless self.target_pages.present?
210
+
211
+ self.target_pages.each do |page_id, target|
212
+ if (target = site.pages.find_by(full_path: target))
213
+ @site.pages.find(page_id).update_column(:target_page_id, target.id)
214
+ end
215
+ end
216
+ end
217
+
218
+ end
219
+ end