kcy1 1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.codeclimate.yml +4 -0
- data/.gitattributes +2 -0
- data/.github/issue_template.md +22 -0
- data/.github/pull_request_template.md +6 -0
- data/.gitignore +21 -0
- data/.rubocop.yml +100 -0
- data/.travis.yml +43 -0
- data/CONTRIBUTING.md +35 -0
- data/Gemfile +29 -0
- data/LICENSE +20 -0
- data/README.md +116 -0
- data/Rakefile +5 -0
- data/app/assets/fonts/comfy/admin/cms/lib/redactor-font.eot +0 -0
- data/app/assets/javascripts/comfy/admin/cms/application.js +39 -0
- data/app/assets/javascripts/comfy/admin/cms/base.js +46 -0
- data/app/assets/javascripts/comfy/admin/cms/categories.js +17 -0
- data/app/assets/javascripts/comfy/admin/cms/codemirror.js +31 -0
- data/app/assets/javascripts/comfy/admin/cms/custom.js +1 -0
- data/app/assets/javascripts/comfy/admin/cms/diff.js +10 -0
- data/app/assets/javascripts/comfy/admin/cms/file_link.js +67 -0
- data/app/assets/javascripts/comfy/admin/cms/file_upload.js +194 -0
- data/app/assets/javascripts/comfy/admin/cms/files_modal.js +40 -0
- data/app/assets/javascripts/comfy/admin/cms/page_fragments.js +22 -0
- data/app/assets/javascripts/comfy/admin/cms/slugify.js +34 -0
- data/app/assets/javascripts/comfy/admin/cms/sortable_list.js +40 -0
- data/app/assets/javascripts/comfy/admin/cms/timepicker.js +30 -0
- data/app/assets/javascripts/comfy/admin/cms/wysiwyg.js +65 -0
- data/app/assets/javascripts/comfy/vendor/Moxie.swf +0 -0
- data/app/assets/javascripts/comfy/vendor/Moxie.xap +0 -0
- data/app/assets/javascripts/comfy/vendor/bootstrap.bundle.min.js +7 -0
- data/app/assets/javascripts/comfy/vendor/bootstrap.bundle.min.js.map +1 -0
- data/app/assets/javascripts/comfy/vendor/codemirror.js +9653 -0
- data/app/assets/javascripts/comfy/vendor/codemirror/addon/edit/closetag.js +169 -0
- data/app/assets/javascripts/comfy/vendor/codemirror/mode/css/css.js +832 -0
- data/app/assets/javascripts/comfy/vendor/codemirror/mode/htmlmixed/htmlmixed.js +152 -0
- data/app/assets/javascripts/comfy/vendor/codemirror/mode/javascript/javascript.js +875 -0
- data/app/assets/javascripts/comfy/vendor/codemirror/mode/markdown/markdown.js +861 -0
- data/app/assets/javascripts/comfy/vendor/codemirror/mode/xml/xml.js +394 -0
- data/app/assets/javascripts/comfy/vendor/diff/diff_match_patch.min.js +49 -0
- data/app/assets/javascripts/comfy/vendor/diff/pretty_text_diff.js +76 -0
- data/app/assets/javascripts/comfy/vendor/flatpickr.min.js +2 -0
- data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/ar.js +52 -0
- data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/bg.js +65 -0
- data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/bn.js +65 -0
- data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/ca.js +83 -0
- data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/cs.js +70 -0
- data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/cy.js +92 -0
- data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/da.js +71 -0
- data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/de.js +70 -0
- data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/default.js +80 -0
- data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/eo.js +73 -0
- data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/es.js +69 -0
- data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/et.js +73 -0
- data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/fa.js +68 -0
- data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/fi.js +69 -0
- data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/fr.js +75 -0
- data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/gr.js +74 -0
- data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/he.js +57 -0
- data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/hi.js +65 -0
- data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/hr.js +66 -0
- data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/hu.js +72 -0
- data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/id.js +61 -0
- data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/it.js +70 -0
- data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/ja.js +57 -0
- data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/ko.js +60 -0
- data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/lt.js +72 -0
- data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/lv.js +67 -0
- data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/mk.js +69 -0
- data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/mn.js +67 -0
- data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/ms.js +68 -0
- data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/my.js +69 -0
- data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/nl.js +75 -0
- data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/no.js +73 -0
- data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/pa.js +65 -0
- data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/pl.js +68 -0
- data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/pt-BR.js +66 -0
- data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/pt.js +66 -0
- data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/ro.js +69 -0
- data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/ru.js +66 -0
- data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/si.js +65 -0
- data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/sk.js +70 -0
- data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/sl.js +70 -0
- data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/sq.js +65 -0
- data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/sr.js +69 -0
- data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/sv.js +70 -0
- data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/th.js +72 -0
- data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/tr.js +66 -0
- data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/uk.js +66 -0
- data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/vn.js +66 -0
- data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/zh-CN.js +61 -0
- data/app/assets/javascripts/comfy/vendor/flatpickr/i18n/zh-TW.js +61 -0
- data/app/assets/javascripts/comfy/vendor/fontawesome.js +5 -0
- data/app/assets/javascripts/comfy/vendor/moxie.min.js +16 -0
- data/app/assets/javascripts/comfy/vendor/plupload.dev.js +2497 -0
- data/app/assets/javascripts/comfy/vendor/redactor.js +9561 -0
- data/app/assets/javascripts/comfy/vendor/redactor/definedlinks.js +53 -0
- data/app/assets/javascripts/comfy/vendor/redactor/filemanager.js +64 -0
- data/app/assets/javascripts/comfy/vendor/redactor/i18n/ar.js +76 -0
- data/app/assets/javascripts/comfy/vendor/redactor/i18n/az.js +75 -0
- data/app/assets/javascripts/comfy/vendor/redactor/i18n/ba.js +79 -0
- data/app/assets/javascripts/comfy/vendor/redactor/i18n/bg.js +77 -0
- data/app/assets/javascripts/comfy/vendor/redactor/i18n/by.js +77 -0
- data/app/assets/javascripts/comfy/vendor/redactor/i18n/ca.js +75 -0
- data/app/assets/javascripts/comfy/vendor/redactor/i18n/cs.js +87 -0
- data/app/assets/javascripts/comfy/vendor/redactor/i18n/da.js +75 -0
- data/app/assets/javascripts/comfy/vendor/redactor/i18n/de.js +80 -0
- data/app/assets/javascripts/comfy/vendor/redactor/i18n/el.js +76 -0
- data/app/assets/javascripts/comfy/vendor/redactor/i18n/en.js +75 -0
- data/app/assets/javascripts/comfy/vendor/redactor/i18n/eo.js +76 -0
- data/app/assets/javascripts/comfy/vendor/redactor/i18n/es.js +75 -0
- data/app/assets/javascripts/comfy/vendor/redactor/i18n/es_AR.js +76 -0
- data/app/assets/javascripts/comfy/vendor/redactor/i18n/fa.js +76 -0
- data/app/assets/javascripts/comfy/vendor/redactor/i18n/fi.js +75 -0
- data/app/assets/javascripts/comfy/vendor/redactor/i18n/fr.js +75 -0
- data/app/assets/javascripts/comfy/vendor/redactor/i18n/ge.js +75 -0
- data/app/assets/javascripts/comfy/vendor/redactor/i18n/gr.js +75 -0
- data/app/assets/javascripts/comfy/vendor/redactor/i18n/he.js +75 -0
- data/app/assets/javascripts/comfy/vendor/redactor/i18n/hr.js +76 -0
- data/app/assets/javascripts/comfy/vendor/redactor/i18n/hu.js +77 -0
- data/app/assets/javascripts/comfy/vendor/redactor/i18n/id.js +76 -0
- data/app/assets/javascripts/comfy/vendor/redactor/i18n/it.js +78 -0
- data/app/assets/javascripts/comfy/vendor/redactor/i18n/ja.js +76 -0
- data/app/assets/javascripts/comfy/vendor/redactor/i18n/kn.js +75 -0
- data/app/assets/javascripts/comfy/vendor/redactor/i18n/ko.js +76 -0
- data/app/assets/javascripts/comfy/vendor/redactor/i18n/lt.js +75 -0
- data/app/assets/javascripts/comfy/vendor/redactor/i18n/lv.js +75 -0
- data/app/assets/javascripts/comfy/vendor/redactor/i18n/mk.js +75 -0
- data/app/assets/javascripts/comfy/vendor/redactor/i18n/nb.js +75 -0
- data/app/assets/javascripts/comfy/vendor/redactor/i18n/nl.js +80 -0
- data/app/assets/javascripts/comfy/vendor/redactor/i18n/pl.js +76 -0
- data/app/assets/javascripts/comfy/vendor/redactor/i18n/pt-BR.js +75 -0
- data/app/assets/javascripts/comfy/vendor/redactor/i18n/pt.js +75 -0
- data/app/assets/javascripts/comfy/vendor/redactor/i18n/ro.js +76 -0
- data/app/assets/javascripts/comfy/vendor/redactor/i18n/ru.js +76 -0
- data/app/assets/javascripts/comfy/vendor/redactor/i18n/sk.js +76 -0
- data/app/assets/javascripts/comfy/vendor/redactor/i18n/sl.js +79 -0
- data/app/assets/javascripts/comfy/vendor/redactor/i18n/sq.js +79 -0
- data/app/assets/javascripts/comfy/vendor/redactor/i18n/sr-CIR.js +79 -0
- data/app/assets/javascripts/comfy/vendor/redactor/i18n/sr-LAT.js +79 -0
- data/app/assets/javascripts/comfy/vendor/redactor/i18n/sv.js +74 -0
- data/app/assets/javascripts/comfy/vendor/redactor/i18n/th.js +74 -0
- data/app/assets/javascripts/comfy/vendor/redactor/i18n/tr.js +75 -0
- data/app/assets/javascripts/comfy/vendor/redactor/i18n/ua.js +77 -0
- data/app/assets/javascripts/comfy/vendor/redactor/i18n/uk.js +77 -0
- data/app/assets/javascripts/comfy/vendor/redactor/i18n/vi.js +74 -0
- data/app/assets/javascripts/comfy/vendor/redactor/i18n/zh-CN.js +75 -0
- data/app/assets/javascripts/comfy/vendor/redactor/i18n/zh-TW.js +75 -0
- data/app/assets/javascripts/comfy/vendor/redactor/imagemanager.js +57 -0
- data/app/assets/javascripts/comfy/vendor/redactor/table.js +337 -0
- data/app/assets/javascripts/comfy/vendor/redactor/video.js +77 -0
- data/app/assets/javascripts/comfy/vendor/sortable.min.js +5 -0
- data/app/assets/stylesheets/comfy/admin/cms/application.sass +11 -0
- data/app/assets/stylesheets/comfy/admin/cms/base.sass +256 -0
- data/app/assets/stylesheets/comfy/admin/cms/codemirror_overrides.sass +19 -0
- data/app/assets/stylesheets/comfy/admin/cms/custom.sass +1 -0
- data/app/assets/stylesheets/comfy/admin/cms/redactor_overrides.sass +22 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/_alert.scss +51 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/_badge.scss +54 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/_breadcrumb.scss +41 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/_button-group.scss +163 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/_buttons.scss +137 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/_card.scss +289 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/_carousel.scss +197 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/_close.scss +41 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/_code.scss +48 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/_custom-forms.scss +507 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/_dropdown.scss +191 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/_forms.scss +330 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/_functions.scss +86 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/_grid.scss +52 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/_images.scss +42 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/_input-group.scss +193 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/_jumbotron.scss +17 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/_list-group.scss +149 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/_media.scss +8 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/_mixins.scss +47 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/_modal.scss +229 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/_nav.scss +120 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/_navbar.scss +294 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/_pagination.scss +73 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/_popover.scss +171 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/_print.scss +141 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/_progress.scss +43 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/_reboot.scss +483 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/_root.scss +19 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/_spinners.scss +55 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/_tables.scss +185 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/_toasts.scss +44 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/_tooltip.scss +115 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/_transitions.scss +20 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/_type.scss +125 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/_utilities.scss +17 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/_variables.scss +1123 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/bootstrap-grid.scss +29 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/bootstrap-reboot.scss +12 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/bootstrap.scss +44 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_alert.scss +13 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_background-variant.scss +21 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_badge.scss +17 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_border-radius.scss +63 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_box-shadow.scss +20 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_breakpoints.scss +123 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_buttons.scss +107 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_caret.scss +62 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_clearfix.scss +7 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_deprecate.scss +10 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_float.scss +14 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_forms.scss +192 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_gradients.scss +45 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_grid-framework.scss +66 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_grid.scss +51 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_hover.scss +37 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_image.scss +36 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_list-group.scss +21 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_lists.scss +7 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_nav-divider.scss +10 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_pagination.scss +22 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_reset-text.scss +17 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_resize.scss +6 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_screen-reader.scss +33 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_size.scss +7 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_table-row.scss +39 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_text-emphasis.scss +16 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_text-hide.scss +11 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_text-truncate.scss +8 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_transition.scss +16 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/mixins/_visibility.scss +8 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/utilities/_align.scss +8 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/utilities/_background.scss +19 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/utilities/_borders.scss +75 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/utilities/_clearfix.scss +3 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/utilities/_display.scss +26 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/utilities/_embed.scss +39 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/utilities/_flex.scss +51 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/utilities/_float.scss +11 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/utilities/_overflow.scss +5 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/utilities/_position.scss +32 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/utilities/_screenreaders.scss +11 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/utilities/_shadows.scss +6 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/utilities/_sizing.scss +20 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/utilities/_spacing.scss +73 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/utilities/_stretched-link.scss +19 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/utilities/_text.scss +72 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/utilities/_visibility.scss +13 -0
- data/app/assets/stylesheets/comfy/vendor/bootstrap/vendor/_rfs.scss +204 -0
- data/app/assets/stylesheets/comfy/vendor/codemirror.css +346 -0
- data/app/assets/stylesheets/comfy/vendor/flatpickr.min.css +13 -0
- data/app/assets/stylesheets/comfy/vendor/fontawesome.css +343 -0
- data/app/assets/stylesheets/comfy/vendor/redactor.css +948 -0
- data/app/controllers/application_controller.rb +7 -0
- data/app/controllers/comfy/admin/base_controller.rb +22 -0
- data/app/controllers/comfy/admin/cms/base_controller.rb +55 -0
- data/app/controllers/comfy/admin/cms/categories_controller.rb +40 -0
- data/app/controllers/comfy/admin/cms/files_controller.rb +142 -0
- data/app/controllers/comfy/admin/cms/layouts_controller.rb +69 -0
- data/app/controllers/comfy/admin/cms/pages_controller.rb +156 -0
- data/app/controllers/comfy/admin/cms/revisions/base_controller.rb +50 -0
- data/app/controllers/comfy/admin/cms/revisions/layout_controller.rb +18 -0
- data/app/controllers/comfy/admin/cms/revisions/page_controller.rb +30 -0
- data/app/controllers/comfy/admin/cms/revisions/snippet_controller.rb +18 -0
- data/app/controllers/comfy/admin/cms/revisions/translation_controller.rb +31 -0
- data/app/controllers/comfy/admin/cms/sites_controller.rb +69 -0
- data/app/controllers/comfy/admin/cms/snippets_controller.rb +66 -0
- data/app/controllers/comfy/admin/cms/translations_controller.rb +107 -0
- data/app/controllers/comfy/cms/assets_controller.rb +40 -0
- data/app/controllers/comfy/cms/base_controller.rb +33 -0
- data/app/controllers/comfy/cms/content_controller.rb +87 -0
- data/app/controllers/concerns/comfy/paginate.rb +16 -0
- data/app/controllers/concerns/comfy/reorder_action.rb +19 -0
- data/app/helpers/comfy/admin/cms_helper.rb +49 -0
- data/app/helpers/comfy/cms_helper.rb +73 -0
- data/app/models/comfy/cms/categorization.rb +16 -0
- data/app/models/comfy/cms/category.rb +24 -0
- data/app/models/comfy/cms/file.rb +57 -0
- data/app/models/comfy/cms/fragment.rb +59 -0
- data/app/models/comfy/cms/layout.rb +113 -0
- data/app/models/comfy/cms/page.rb +169 -0
- data/app/models/comfy/cms/revision.rb +12 -0
- data/app/models/comfy/cms/site.rb +94 -0
- data/app/models/comfy/cms/snippet.rb +45 -0
- data/app/models/comfy/cms/translation.rb +43 -0
- data/app/models/concerns/comfy/cms/with_categories.rb +53 -0
- data/app/models/concerns/comfy/cms/with_fragments.rb +125 -0
- data/app/views/comfy/admin/cms/categories/_categories.html.haml +4 -0
- data/app/views/comfy/admin/cms/categories/_edit.html.haml +7 -0
- data/app/views/comfy/admin/cms/categories/_form.html.haml +5 -0
- data/app/views/comfy/admin/cms/categories/_index.html.haml +28 -0
- data/app/views/comfy/admin/cms/categories/_show.html.haml +15 -0
- data/app/views/comfy/admin/cms/categories/create.js.erb +7 -0
- data/app/views/comfy/admin/cms/categories/destroy.js.erb +8 -0
- data/app/views/comfy/admin/cms/categories/edit.js.erb +3 -0
- data/app/views/comfy/admin/cms/categories/update.js.erb +6 -0
- data/app/views/comfy/admin/cms/files/_file.html.haml +31 -0
- data/app/views/comfy/admin/cms/files/_form.html.haml +26 -0
- data/app/views/comfy/admin/cms/files/_modal.html.haml +3 -0
- data/app/views/comfy/admin/cms/files/destroy.js.erb +4 -0
- data/app/views/comfy/admin/cms/files/edit.html.haml +5 -0
- data/app/views/comfy/admin/cms/files/index.html.haml +29 -0
- data/app/views/comfy/admin/cms/files/new.html.haml +5 -0
- data/app/views/comfy/admin/cms/fragments/_form_fragment_attachments.html.haml +23 -0
- data/app/views/comfy/admin/cms/fragments/_form_fragments.html.haml +38 -0
- data/app/views/comfy/admin/cms/layouts/_form.html.haml +20 -0
- data/app/views/comfy/admin/cms/layouts/_index_branch.html.haml +26 -0
- data/app/views/comfy/admin/cms/layouts/edit.html.haml +9 -0
- data/app/views/comfy/admin/cms/layouts/index.html.haml +10 -0
- data/app/views/comfy/admin/cms/layouts/new.html.haml +5 -0
- data/app/views/comfy/admin/cms/pages/_form.html.haml +31 -0
- data/app/views/comfy/admin/cms/pages/_index_branch.html.haml +44 -0
- data/app/views/comfy/admin/cms/pages/edit.html.haml +10 -0
- data/app/views/comfy/admin/cms/pages/index.html.haml +13 -0
- data/app/views/comfy/admin/cms/pages/new.html.haml +5 -0
- data/app/views/comfy/admin/cms/pages/toggle_branch.js.erb +13 -0
- data/app/views/comfy/admin/cms/revisions/_sidebar.html.haml +2 -0
- data/app/views/comfy/admin/cms/revisions/show.html.haml +36 -0
- data/app/views/comfy/admin/cms/sites/_form.html.haml +15 -0
- data/app/views/comfy/admin/cms/sites/edit.html.haml +5 -0
- data/app/views/comfy/admin/cms/sites/index.html.haml +28 -0
- data/app/views/comfy/admin/cms/sites/new.html.haml +5 -0
- data/app/views/comfy/admin/cms/snippets/_form.html.haml +13 -0
- data/app/views/comfy/admin/cms/snippets/edit.html.haml +9 -0
- data/app/views/comfy/admin/cms/snippets/index.html.haml +33 -0
- data/app/views/comfy/admin/cms/snippets/new.html.haml +5 -0
- data/app/views/comfy/admin/cms/translations/_form.html.haml +20 -0
- data/app/views/comfy/admin/cms/translations/_sidebar.html.haml +19 -0
- data/app/views/comfy/admin/cms/translations/edit.html.haml +10 -0
- data/app/views/comfy/admin/cms/translations/new.html.haml +5 -0
- data/app/views/kaminari/comfy/_first_page.html.haml +3 -0
- data/app/views/kaminari/comfy/_gap.html.haml +2 -0
- data/app/views/kaminari/comfy/_last_page.html.haml +3 -0
- data/app/views/kaminari/comfy/_next_page.html.haml +2 -0
- data/app/views/kaminari/comfy/_page.html.haml +2 -0
- data/app/views/kaminari/comfy/_paginator.html.haml +11 -0
- data/app/views/kaminari/comfy/_prev_page.html.haml +2 -0
- data/app/views/layouts/comfy/admin/cms.html.haml +4 -0
- data/app/views/layouts/comfy/admin/cms/_body.html.haml +14 -0
- data/app/views/layouts/comfy/admin/cms/_flash.html.haml +4 -0
- data/app/views/layouts/comfy/admin/cms/_footer_js.html.haml +6 -0
- data/app/views/layouts/comfy/admin/cms/_head.html.haml +19 -0
- data/app/views/layouts/comfy/admin/cms/_left.html.haml +39 -0
- data/app/views/layouts/comfy/admin/cms/_right.html.haml +5 -0
- data/bin/bundle +3 -0
- data/bin/rails +4 -0
- data/bin/rake +4 -0
- data/bin/setup +36 -0
- data/bin/update +31 -0
- data/bin/yarn +11 -0
- data/comfortable_mexican_sofa.gemspec +33 -0
- data/config.ru +6 -0
- data/config/application.rb +39 -0
- data/config/boot.rb +7 -0
- data/config/cms_routes.rb +8 -0
- data/config/database.yml +11 -0
- data/config/environment.rb +7 -0
- data/config/environments/development.rb +64 -0
- data/config/environments/test.rb +55 -0
- data/config/initializers/comfortable_mexican_sofa.rb +122 -0
- data/config/locales/ca.yml +263 -0
- data/config/locales/cs.yml +263 -0
- data/config/locales/da.yml +263 -0
- data/config/locales/de.yml +263 -0
- data/config/locales/en.yml +263 -0
- data/config/locales/es.yml +263 -0
- data/config/locales/fi.yml +263 -0
- data/config/locales/fr.yml +263 -0
- data/config/locales/gr.yml +263 -0
- data/config/locales/hr.yml +263 -0
- data/config/locales/it.yml +263 -0
- data/config/locales/ja.yml +263 -0
- data/config/locales/nb.yml +263 -0
- data/config/locales/nl.yml +263 -0
- data/config/locales/pl.yml +263 -0
- data/config/locales/pt-BR.yml +263 -0
- data/config/locales/ru.yml +263 -0
- data/config/locales/sk.yml +263 -0
- data/config/locales/sv.yml +263 -0
- data/config/locales/tr.yml +263 -0
- data/config/locales/uk.yml +263 -0
- data/config/locales/zh-CN.yml +263 -0
- data/config/locales/zh-TW.yml +263 -0
- data/config/storage.yml +35 -0
- data/db/cms_seeds/sample-site/files/_default.jpg.yml +5 -0
- data/db/cms_seeds/sample-site/files/default.jpg +0 -0
- data/db/cms_seeds/sample-site/layouts/default/content.html +16 -0
- data/db/cms_seeds/sample-site/layouts/default/nested/content.html +14 -0
- data/db/cms_seeds/sample-site/pages/index/child_a/content.html +7 -0
- data/db/cms_seeds/sample-site/pages/index/child_b/content.html +6 -0
- data/db/cms_seeds/sample-site/pages/index/cms logo.png +0 -0
- data/db/cms_seeds/sample-site/pages/index/content.es.html +6 -0
- data/db/cms_seeds/sample-site/pages/index/content.fr.html +6 -0
- data/db/cms_seeds/sample-site/pages/index/content.html +25 -0
- data/db/cms_seeds/sample-site/pages/index/footer.png +0 -0
- data/db/cms_seeds/sample-site/pages/index/header.png +0 -0
- data/db/cms_seeds/sample-site/snippets/default.html +8 -0
- data/db/migrate/00_create_active_storage_tables.active_storage.rb +26 -0
- data/db/migrate/01_create_cms.rb +142 -0
- data/lib/comfortable_mexican_sofa.rb +60 -0
- data/lib/comfortable_mexican_sofa/access_control/admin_authentication.rb +24 -0
- data/lib/comfortable_mexican_sofa/access_control/admin_authorization.rb +12 -0
- data/lib/comfortable_mexican_sofa/access_control/public_authentication.rb +12 -0
- data/lib/comfortable_mexican_sofa/access_control/public_authorization.rb +12 -0
- data/lib/comfortable_mexican_sofa/configuration.rb +139 -0
- data/lib/comfortable_mexican_sofa/content.rb +31 -0
- data/lib/comfortable_mexican_sofa/content/block.rb +14 -0
- data/lib/comfortable_mexican_sofa/content/params_parser.rb +149 -0
- data/lib/comfortable_mexican_sofa/content/renderer.rb +149 -0
- data/lib/comfortable_mexican_sofa/content/tag.rb +50 -0
- data/lib/comfortable_mexican_sofa/content/tags/asset.rb +59 -0
- data/lib/comfortable_mexican_sofa/content/tags/checkbox.rb +29 -0
- data/lib/comfortable_mexican_sofa/content/tags/date.rb +21 -0
- data/lib/comfortable_mexican_sofa/content/tags/datetime.rb +44 -0
- data/lib/comfortable_mexican_sofa/content/tags/file.rb +72 -0
- data/lib/comfortable_mexican_sofa/content/tags/file_link.rb +63 -0
- data/lib/comfortable_mexican_sofa/content/tags/files.rb +43 -0
- data/lib/comfortable_mexican_sofa/content/tags/fragment.rb +66 -0
- data/lib/comfortable_mexican_sofa/content/tags/helper.rb +55 -0
- data/lib/comfortable_mexican_sofa/content/tags/markdown.rb +24 -0
- data/lib/comfortable_mexican_sofa/content/tags/mixins/file_content.rb +43 -0
- data/lib/comfortable_mexican_sofa/content/tags/number.rb +20 -0
- data/lib/comfortable_mexican_sofa/content/tags/page_file_link.rb +84 -0
- data/lib/comfortable_mexican_sofa/content/tags/partial.rb +49 -0
- data/lib/comfortable_mexican_sofa/content/tags/snippet.rb +34 -0
- data/lib/comfortable_mexican_sofa/content/tags/template.rb +44 -0
- data/lib/comfortable_mexican_sofa/content/tags/text.rb +20 -0
- data/lib/comfortable_mexican_sofa/content/tags/textarea.rb +20 -0
- data/lib/comfortable_mexican_sofa/content/tags/wysiwyg.rb +21 -0
- data/lib/comfortable_mexican_sofa/engine.rb +31 -0
- data/lib/comfortable_mexican_sofa/error.rb +32 -0
- data/lib/comfortable_mexican_sofa/extensions/acts_as_tree.rb +120 -0
- data/lib/comfortable_mexican_sofa/extensions/has_revisions.rb +72 -0
- data/lib/comfortable_mexican_sofa/form_builder.rb +47 -0
- data/lib/comfortable_mexican_sofa/render_methods.rb +112 -0
- data/lib/comfortable_mexican_sofa/routes/cms.rb +18 -0
- data/lib/comfortable_mexican_sofa/routes/cms_admin.rb +58 -0
- data/lib/comfortable_mexican_sofa/routing.rb +12 -0
- data/lib/comfortable_mexican_sofa/seeds.rb +114 -0
- data/lib/comfortable_mexican_sofa/seeds/file/exporter.rb +43 -0
- data/lib/comfortable_mexican_sofa/seeds/file/importer.rb +63 -0
- data/lib/comfortable_mexican_sofa/seeds/layout/exporter.rb +40 -0
- data/lib/comfortable_mexican_sofa/seeds/layout/importer.rb +62 -0
- data/lib/comfortable_mexican_sofa/seeds/page/exporter.rb +92 -0
- data/lib/comfortable_mexican_sofa/seeds/page/importer.rb +219 -0
- data/lib/comfortable_mexican_sofa/seeds/snippet/exporter.rb +34 -0
- data/lib/comfortable_mexican_sofa/seeds/snippet/importer.rb +51 -0
- data/lib/comfortable_mexican_sofa/version.rb +7 -0
- data/lib/comfortable_mexican_sofa/view_hooks.rb +35 -0
- data/lib/generators/comfy/cms/README +17 -0
- data/lib/generators/comfy/cms/assets_generator.rb +18 -0
- data/lib/generators/comfy/cms/cms_generator.rb +69 -0
- data/lib/generators/comfy/cms/controllers_generator.rb +17 -0
- data/lib/generators/comfy/cms/models_generator.rb +17 -0
- data/lib/generators/comfy/cms/views_generator.rb +17 -0
- data/lib/generators/comfy/scaffold/scaffold_generator.rb +80 -0
- data/lib/generators/comfy/scaffold/templates/controller.rb.tt +62 -0
- data/lib/generators/comfy/scaffold/templates/migration.rb.tt +11 -0
- data/lib/generators/comfy/scaffold/templates/model.rb.tt +21 -0
- data/lib/generators/comfy/scaffold/templates/tests/controller.rb.tt +115 -0
- data/lib/generators/comfy/scaffold/templates/tests/fixture.yml.tt +4 -0
- data/lib/generators/comfy/scaffold/templates/tests/model.rb.tt +26 -0
- data/lib/generators/comfy/scaffold/templates/views/_form.haml.tt +7 -0
- data/lib/generators/comfy/scaffold/templates/views/edit.haml.tt +5 -0
- data/lib/generators/comfy/scaffold/templates/views/index.haml.tt +21 -0
- data/lib/generators/comfy/scaffold/templates/views/new.haml.tt +5 -0
- data/lib/generators/comfy/scaffold/templates/views/show.haml.tt +4 -0
- data/lib/tasks/cms_seeds.rake +40 -0
- data/public/favicon.ico +0 -0
- metadata +648 -0
@@ -0,0 +1,139 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ComfortableMexicanSofa::Configuration
|
4
|
+
|
5
|
+
# Don't like ComfortableMexicanSofa? 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 Comfy::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 = "ComfortableMexicanSofa CMS Engine"
|
91
|
+
@admin_base_controller = "ApplicationController"
|
92
|
+
@public_base_controller = "ApplicationController"
|
93
|
+
@admin_auth = "ComfortableMexicanSofa::AccessControl::AdminAuthentication"
|
94
|
+
@admin_authorization = "ComfortableMexicanSofa::AccessControl::AdminAuthorization"
|
95
|
+
@public_auth = "ComfortableMexicanSofa::AccessControl::PublicAuthentication"
|
96
|
+
@public_authorization = "ComfortableMexicanSofa::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
|
+
"ca" => "Català",
|
105
|
+
"cs" => "Česky",
|
106
|
+
"da" => "Dansk",
|
107
|
+
"de" => "Deutsch",
|
108
|
+
"en" => "English",
|
109
|
+
"es" => "Español",
|
110
|
+
"fi" => "Suomi",
|
111
|
+
"fr" => "Français",
|
112
|
+
"gr" => "Ελληνικά",
|
113
|
+
"hr" => "Hrvatski",
|
114
|
+
"it" => "Italiano",
|
115
|
+
"ja" => "日本語",
|
116
|
+
"nb" => "Norsk",
|
117
|
+
"nl" => "Nederlands",
|
118
|
+
"pl" => "Polski",
|
119
|
+
"pt-BR" => "Português Brasileiro",
|
120
|
+
"ru" => "Русский",
|
121
|
+
"sk" => "Slovensky",
|
122
|
+
"sv" => "Svenska",
|
123
|
+
"tr" => "Türkçe",
|
124
|
+
"uk" => "Українська",
|
125
|
+
"zh-CN" => "简体中文",
|
126
|
+
"zh-TW" => "正體中文"
|
127
|
+
}
|
128
|
+
@admin_locale = nil
|
129
|
+
@admin_cache_sweeper = nil
|
130
|
+
@allow_erb = false
|
131
|
+
@allowed_helpers = nil
|
132
|
+
@allowed_partials = nil
|
133
|
+
@hostname_aliases = nil
|
134
|
+
@reveal_cms_partials = false
|
135
|
+
@public_cms_path = nil
|
136
|
+
@page_to_json_options = { methods: [:content], except: [:content_cache] }
|
137
|
+
end
|
138
|
+
|
139
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ComfortableMexicanSofa::Content
|
4
|
+
# ...
|
5
|
+
end
|
6
|
+
|
7
|
+
require_relative "content/renderer"
|
8
|
+
require_relative "content/params_parser"
|
9
|
+
require_relative "content/tag"
|
10
|
+
require_relative "content/block"
|
11
|
+
|
12
|
+
require_relative "content/tags/fragment"
|
13
|
+
|
14
|
+
require_relative "content/tags/wysiwyg"
|
15
|
+
require_relative "content/tags/text"
|
16
|
+
require_relative "content/tags/textarea"
|
17
|
+
require_relative "content/tags/markdown"
|
18
|
+
require_relative "content/tags/datetime"
|
19
|
+
require_relative "content/tags/date"
|
20
|
+
require_relative "content/tags/number"
|
21
|
+
require_relative "content/tags/checkbox"
|
22
|
+
require_relative "content/tags/file"
|
23
|
+
require_relative "content/tags/files"
|
24
|
+
|
25
|
+
require_relative "content/tags/snippet"
|
26
|
+
require_relative "content/tags/asset"
|
27
|
+
require_relative "content/tags/file_link"
|
28
|
+
require_relative "content/tags/page_file_link"
|
29
|
+
require_relative "content/tags/helper"
|
30
|
+
require_relative "content/tags/partial"
|
31
|
+
require_relative "content/tags/template"
|
@@ -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 ComfortableMexicanSofa::Content::Block < ComfortableMexicanSofa::Content::Tag
|
7
|
+
|
8
|
+
attr_writer :nodes
|
9
|
+
|
10
|
+
def nodes
|
11
|
+
@nodes ||= []
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "strscan"
|
4
|
+
|
5
|
+
class ComfortableMexicanSofa::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
|
+
|
18
|
+
# @param <String> string
|
19
|
+
def initialize(string = "")
|
20
|
+
@string = string
|
21
|
+
end
|
22
|
+
|
23
|
+
# Takes CMS content tag parameters and converts them into array of strings,
|
24
|
+
# hashes and arrays.
|
25
|
+
#
|
26
|
+
# @return [Array<String, {String => String}>]
|
27
|
+
# @raise [Error] if the given `text` is malformed.
|
28
|
+
#
|
29
|
+
# @example
|
30
|
+
# new("a, b, c").parse
|
31
|
+
# #=> ["a", "b", "c"]
|
32
|
+
#
|
33
|
+
# new("a, b: c, d: e").parse
|
34
|
+
# #=> ["a", {"b" => "c", "d" => "e"}]
|
35
|
+
#
|
36
|
+
# new("a, b: {c: [d, e]}").parse
|
37
|
+
# #=> ["a", {"b" => {"c" => ["d", "e"]}}]
|
38
|
+
#
|
39
|
+
def params
|
40
|
+
@tokens = tokenize(@string)
|
41
|
+
parse_params
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
# Contructs root-level list of arguments sent via content tag
|
47
|
+
def parse_params
|
48
|
+
params = []
|
49
|
+
while (token = @tokens.shift)
|
50
|
+
params << parse_value(token)
|
51
|
+
end
|
52
|
+
params
|
53
|
+
end
|
54
|
+
|
55
|
+
# Gets token value. Will trigger parsing of hash and array structures
|
56
|
+
def parse_value(token)
|
57
|
+
case token&.first
|
58
|
+
when :string
|
59
|
+
token[1]
|
60
|
+
when :hash_key
|
61
|
+
@tokens.unshift(token)
|
62
|
+
parse_hash
|
63
|
+
when :hash_open
|
64
|
+
parse_hash
|
65
|
+
when :array_open
|
66
|
+
parse_array
|
67
|
+
else
|
68
|
+
raise Error, "Invalid params: #{@string}"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# Hash constructor method. Will handle nested hashes as well
|
73
|
+
def parse_hash
|
74
|
+
opens = 1
|
75
|
+
hash = {}
|
76
|
+
|
77
|
+
while (token = @tokens.shift)
|
78
|
+
case token&.first
|
79
|
+
when :hash_key
|
80
|
+
hash[token[1]] = parse_value(@tokens.shift)
|
81
|
+
when :hash_close
|
82
|
+
opens -= 1
|
83
|
+
when :hash_open
|
84
|
+
opens += 1
|
85
|
+
else
|
86
|
+
raise Error, "Invalid params: #{@string}"
|
87
|
+
end
|
88
|
+
|
89
|
+
return hash if opens.zero?
|
90
|
+
end
|
91
|
+
|
92
|
+
# We're can't really detect unclosed hashes as we can construct them without
|
93
|
+
# opening brakets. For example, `a: b, c: d` is same as `{a: b, c: d}` and
|
94
|
+
# `{a: b, c: d` is also ends up to be a valid hash. It will error out if
|
95
|
+
# unclosed hash is followed by some other unexpected token. Like: `{a: b, c`
|
96
|
+
hash
|
97
|
+
end
|
98
|
+
|
99
|
+
# Array construction method. Will handle nested arrays
|
100
|
+
def parse_array
|
101
|
+
opens = 1
|
102
|
+
array = []
|
103
|
+
while (token = @tokens.shift)
|
104
|
+
case token&.first
|
105
|
+
when :array_close
|
106
|
+
opens -= 1
|
107
|
+
else
|
108
|
+
array << parse_value(token)
|
109
|
+
end
|
110
|
+
|
111
|
+
return array if opens.zero?
|
112
|
+
end
|
113
|
+
|
114
|
+
raise Error, "Unclosed array param: #{@string}"
|
115
|
+
end
|
116
|
+
|
117
|
+
# Tokenizing input string into a list of touples
|
118
|
+
# Also args_string is stripped of "smart" quotes coming from wysiwyg
|
119
|
+
#
|
120
|
+
# @param [String] args_string
|
121
|
+
# @return [Array<String>] tokens
|
122
|
+
def tokenize(args_string)
|
123
|
+
args_string = args_string.tr("“”‘’", %q(""''))
|
124
|
+
ss = StringScanner.new(args_string)
|
125
|
+
tokens = []
|
126
|
+
loop do
|
127
|
+
ss.skip(%r{\s*})
|
128
|
+
break if ss.eos?
|
129
|
+
|
130
|
+
# commas are just separators like spaces
|
131
|
+
next if ss.scan(COMMA)
|
132
|
+
|
133
|
+
tokens <<
|
134
|
+
if (t = ss.scan(STRING_LITERAL)) then [:string, t[1...-1]]
|
135
|
+
elsif (t = ss.scan(HASH_KEY)) then [:hash_key, t[0...-1]]
|
136
|
+
elsif (t = ss.scan(IDENTIFIER)) then [:string, t]
|
137
|
+
elsif (t = ss.scan(HASH_OPEN)) then [:hash_open, t]
|
138
|
+
elsif (t = ss.scan(HASH_CLOSE)) then [:hash_close, t]
|
139
|
+
elsif (t = ss.scan(ARRAY_OPEN)) then [:array_open, t]
|
140
|
+
elsif (t = ss.scan(ARRAY_CLOSE)) then [:array_close, t]
|
141
|
+
else
|
142
|
+
raise Error, "Unexpected char: #{ss.getch}"
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
tokens
|
147
|
+
end
|
148
|
+
|
149
|
+
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 ComfortableMexicanSofa::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<ComfortableMexicanSofa::Content::Tag>>]
|
30
|
+
def tags
|
31
|
+
@tags ||= {}
|
32
|
+
end
|
33
|
+
|
34
|
+
# @param [String] name
|
35
|
+
# @param [Class<ComfortableMexicanSofa::Content::Tag>] klass
|
36
|
+
def register_tag(name, klass)
|
37
|
+
tags[name.to_s] = klass
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
# @param [Comfy::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, ComfortableMexicanSofa::Content::Tag>]
|
51
|
+
# @param [Boolean] allow_erb
|
52
|
+
def render(nodes, allow_erb = ComfortableMexicanSofa.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("<%", "<%").gsub("%>", "%>")
|
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, ComfortableMexicanSofa::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<ComfortableMexicanSofa::Content::Tag>]
|
119
|
+
klass = self.class.tags[tag_class] ||
|
120
|
+
raise(SyntaxError, "Unrecognized tag: #{token[:source]}")
|
121
|
+
|
122
|
+
# @type [ComfortableMexicanSofa::Content::Tag]
|
123
|
+
tag = klass.new(
|
124
|
+
context: @context,
|
125
|
+
params: ComfortableMexicanSofa::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?(ComfortableMexicanSofa::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
|