comfy_middle_seat 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.codeclimate.yml +4 -0
- data/.gitattributes +3 -0
- data/.github/dependabot.yml +7 -0
- data/.github/issue_template.md +19 -0
- data/.github/pull_request_template.md +6 -0
- data/.github/workflows/claude-code-review.yml +46 -0
- data/.github/workflows/claude.yml +148 -0
- data/.github/workflows/coveralls.yml +53 -0
- data/.github/workflows/rubyonrails.yml +94 -0
- data/.gitignore +25 -0
- data/.rubocop.yml +82 -0
- data/.travis.yml +44 -0
- data/CHANGELOG.md +147 -0
- data/CONTRIBUTING.md +42 -0
- data/Gemfile +44 -0
- data/LICENSE +20 -0
- data/README.md +158 -0
- data/Rakefile +206 -0
- data/app/assets/builds/.keep +0 -0
- data/app/assets/config/manifest.js +1 -0
- data/app/assets/fonts/comfy/admin/cms/lib/redactor-font.eot +0 -0
- data/app/assets/javascripts/comfy/admin/cms/application.js +27 -0
- data/app/assets/javascripts/comfy/admin/cms/base.js +48 -0
- data/app/assets/javascripts/comfy/admin/cms/categories.js +17 -0
- data/app/assets/javascripts/comfy/admin/cms/codemirror.js +43 -0
- data/app/assets/javascripts/comfy/admin/cms/custom.js +1 -0
- data/app/assets/javascripts/comfy/admin/cms/diff.js +12 -0
- data/app/assets/javascripts/comfy/admin/cms/file_link.js +96 -0
- data/app/assets/javascripts/comfy/admin/cms/file_upload.js +229 -0
- data/app/assets/javascripts/comfy/admin/cms/files_modal.js +97 -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 +49 -0
- data/app/assets/javascripts/comfy/admin/cms/timepicker.js +38 -0
- data/app/assets/javascripts/comfy/admin/cms/wysiwyg.js +91 -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 +88 -0
- data/app/assets/javascripts/comfy/vendor/flatpickr.min.js +2 -0
- data/app/assets/javascripts/comfy/vendor/fontawesome.js +5 -0
- data/app/assets/javascripts/comfy/vendor/redactor/definedlinks.js +50 -0
- data/app/assets/javascripts/comfy/vendor/redactor/filemanager.js +79 -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 +78 -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 +77 -0
- data/app/assets/javascripts/comfy/vendor/redactor/i18n/nl.js +80 -0
- data/app/assets/javascripts/comfy/vendor/redactor/i18n/pl.js +78 -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 +68 -0
- data/app/assets/javascripts/comfy/vendor/redactor/table.js +348 -0
- data/app/assets/javascripts/comfy/vendor/redactor/video.js +82 -0
- data/app/assets/javascripts/comfy/vendor/redactor.js +9563 -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/fontawesome.css +343 -0
- data/app/assets/stylesheets/comfy/vendor/redactor.css +948 -0
- data/app/controllers/application_controller.rb +5 -0
- data/app/controllers/comfy/admin/base_controller.rb +20 -0
- data/app/controllers/comfy/admin/cms/base_controller.rb +54 -0
- data/app/controllers/comfy/admin/cms/categories_controller.rb +38 -0
- data/app/controllers/comfy/admin/cms/files_controller.rb +140 -0
- data/app/controllers/comfy/admin/cms/layouts_controller.rb +69 -0
- data/app/controllers/comfy/admin/cms/pages_controller.rb +193 -0
- data/app/controllers/comfy/admin/cms/revisions/base_controller.rb +48 -0
- data/app/controllers/comfy/admin/cms/revisions/layout_controller.rb +16 -0
- data/app/controllers/comfy/admin/cms/revisions/page_controller.rb +28 -0
- data/app/controllers/comfy/admin/cms/revisions/snippet_controller.rb +16 -0
- data/app/controllers/comfy/admin/cms/revisions/translation_controller.rb +29 -0
- data/app/controllers/comfy/admin/cms/sites_controller.rb +68 -0
- data/app/controllers/comfy/admin/cms/snippets_controller.rb +66 -0
- data/app/controllers/comfy/admin/cms/translations_controller.rb +117 -0
- data/app/controllers/comfy/cms/assets_controller.rb +38 -0
- data/app/controllers/comfy/cms/base_controller.rb +35 -0
- data/app/controllers/comfy/cms/content_controller.rb +90 -0
- data/app/controllers/concerns/comfy/paginate.rb +11 -0
- data/app/controllers/concerns/comfy/reorder_action.rb +19 -0
- data/app/helpers/comfy/admin/cms_helper.rb +50 -0
- data/app/helpers/comfy/cms_helper.rb +71 -0
- data/app/models/comfy/cms/categorization.rb +23 -0
- data/app/models/comfy/cms/category.rb +22 -0
- data/app/models/comfy/cms/file.rb +65 -0
- data/app/models/comfy/cms/fragment.rb +65 -0
- data/app/models/comfy/cms/layout.rb +119 -0
- data/app/models/comfy/cms/page.rb +182 -0
- data/app/models/comfy/cms/revision.rb +10 -0
- data/app/models/comfy/cms/site.rb +93 -0
- data/app/models/comfy/cms/snippet.rb +43 -0
- data/app/models/comfy/cms/translation.rb +47 -0
- data/app/models/concerns/comfy/cms/with_categories.rb +51 -0
- data/app/models/concerns/comfy/cms/with_fragments.rb +123 -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 +31 -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 +14 -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 +19 -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 +19 -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/_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 +46 -0
- data/app/views/layouts/comfy/admin/cms/_right.html.haml +5 -0
- data/app/views/layouts/comfy/admin/cms.html.haml +4 -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/comfy_middle_seat.gemspec +35 -0
- data/config/application.rb +62 -0
- data/config/boot.rb +5 -0
- data/config/cable.yml +10 -0
- data/config/cms_routes.rb +8 -0
- data/config/database.yml +40 -0
- data/config/environment.rb +7 -0
- data/config/environments/development.rb +81 -0
- data/config/environments/production.rb +93 -0
- data/config/environments/test.rb +74 -0
- data/config/initializers/comfortable_media_surfer.rb +122 -0
- data/config/initializers/content_security_policy.rb +27 -0
- data/config/initializers/filter_parameter_logging.rb +10 -0
- data/config/initializers/inflections.rb +18 -0
- data/config/initializers/json.rb +11 -0
- data/config/initializers/new_framework_defaults_7_0.rb +144 -0
- data/config/initializers/new_framework_defaults_7_1.rb +225 -0
- data/config/initializers/permissions_policy.rb +15 -0
- data/config/locales/ar.yml +268 -0
- data/config/locales/ca.yml +268 -0
- data/config/locales/cs.yml +268 -0
- data/config/locales/da.yml +268 -0
- data/config/locales/de.yml +268 -0
- data/config/locales/en.yml +268 -0
- data/config/locales/es.yml +268 -0
- data/config/locales/fi.yml +268 -0
- data/config/locales/fr.yml +268 -0
- data/config/locales/gr.yml +268 -0
- data/config/locales/hr.yml +268 -0
- data/config/locales/it.yml +268 -0
- data/config/locales/ja.yml +268 -0
- data/config/locales/nb.yml +268 -0
- data/config/locales/nl.yml +268 -0
- data/config/locales/pl.yml +268 -0
- data/config/locales/pt-BR.yml +268 -0
- data/config/locales/ru.yml +268 -0
- data/config/locales/sk.yml +268 -0
- data/config/locales/sv.yml +268 -0
- data/config/locales/tr.yml +268 -0
- data/config/locales/uk.yml +268 -0
- data/config/locales/zh-CN.yml +268 -0
- data/config/locales/zh-TW.yml +268 -0
- data/config/puma.rb +43 -0
- data/config/storage.yml +35 -0
- data/config.ru +6 -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/child_a/content.html +6 -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 +50 -0
- data/db/migrate/01_create_cms.rb +142 -0
- data/db/migrate/02_add_markdown_to_snippets.rb +5 -0
- data/gemfiles/7.2.gemfile +36 -0
- data/gemfiles/8.0.gemfile +36 -0
- data/gemfiles/8.1.gemfile +36 -0
- data/lib/comfortable_media_surfer/access_control/admin_authentication.rb +22 -0
- data/lib/comfortable_media_surfer/access_control/admin_authorization.rb +10 -0
- data/lib/comfortable_media_surfer/access_control/public_authentication.rb +10 -0
- data/lib/comfortable_media_surfer/access_control/public_authorization.rb +10 -0
- data/lib/comfortable_media_surfer/configuration.rb +138 -0
- data/lib/comfortable_media_surfer/content/block.rb +12 -0
- data/lib/comfortable_media_surfer/content/params_parser.rb +149 -0
- data/lib/comfortable_media_surfer/content/renderer.rb +146 -0
- data/lib/comfortable_media_surfer/content/tag.rb +48 -0
- data/lib/comfortable_media_surfer/content/tags/asset.rb +57 -0
- data/lib/comfortable_media_surfer/content/tags/audio.rb +39 -0
- data/lib/comfortable_media_surfer/content/tags/breadcrumbs.rb +43 -0
- data/lib/comfortable_media_surfer/content/tags/checkbox.rb +27 -0
- data/lib/comfortable_media_surfer/content/tags/children.rb +52 -0
- data/lib/comfortable_media_surfer/content/tags/date.rb +19 -0
- data/lib/comfortable_media_surfer/content/tags/datetime.rb +42 -0
- data/lib/comfortable_media_surfer/content/tags/file.rb +70 -0
- data/lib/comfortable_media_surfer/content/tags/file_link.rb +58 -0
- data/lib/comfortable_media_surfer/content/tags/files.rb +41 -0
- data/lib/comfortable_media_surfer/content/tags/fragment.rb +64 -0
- data/lib/comfortable_media_surfer/content/tags/helper.rb +53 -0
- data/lib/comfortable_media_surfer/content/tags/image.rb +56 -0
- data/lib/comfortable_media_surfer/content/tags/markdown.rb +22 -0
- data/lib/comfortable_media_surfer/content/tags/mixins/file_content.rb +42 -0
- data/lib/comfortable_media_surfer/content/tags/number.rb +18 -0
- data/lib/comfortable_media_surfer/content/tags/page_file_link.rb +86 -0
- data/lib/comfortable_media_surfer/content/tags/partial.rb +47 -0
- data/lib/comfortable_media_surfer/content/tags/siblings.rb +66 -0
- data/lib/comfortable_media_surfer/content/tags/snippet.rb +36 -0
- data/lib/comfortable_media_surfer/content/tags/template.rb +42 -0
- data/lib/comfortable_media_surfer/content/tags/text.rb +18 -0
- data/lib/comfortable_media_surfer/content/tags/textarea.rb +19 -0
- data/lib/comfortable_media_surfer/content/tags/wysiwyg.rb +19 -0
- data/lib/comfortable_media_surfer/content/tags.rb +29 -0
- data/lib/comfortable_media_surfer/content.rb +11 -0
- data/lib/comfortable_media_surfer/engine.rb +24 -0
- data/lib/comfortable_media_surfer/error.rb +24 -0
- data/lib/comfortable_media_surfer/extensions/acts_as_tree.rb +114 -0
- data/lib/comfortable_media_surfer/extensions/has_revisions.rb +68 -0
- data/lib/comfortable_media_surfer/extensions.rb +8 -0
- data/lib/comfortable_media_surfer/form_builder.rb +43 -0
- data/lib/comfortable_media_surfer/render_methods.rb +106 -0
- data/lib/comfortable_media_surfer/routing.rb +87 -0
- data/lib/comfortable_media_surfer/seeds/file/exporter.rb +37 -0
- data/lib/comfortable_media_surfer/seeds/file/importer.rb +55 -0
- data/lib/comfortable_media_surfer/seeds/layout/exporter.rb +38 -0
- data/lib/comfortable_media_surfer/seeds/layout/importer.rb +60 -0
- data/lib/comfortable_media_surfer/seeds/page/exporter.rb +88 -0
- data/lib/comfortable_media_surfer/seeds/page/importer.rb +245 -0
- data/lib/comfortable_media_surfer/seeds/snippet/exporter.rb +32 -0
- data/lib/comfortable_media_surfer/seeds/snippet/importer.rb +47 -0
- data/lib/comfortable_media_surfer/seeds.rb +110 -0
- data/lib/comfortable_media_surfer/version.rb +3 -0
- data/lib/comfortable_media_surfer/view_hooks.rb +33 -0
- data/lib/comfortable_media_surfer.rb +56 -0
- data/lib/comfy_middle_seat/version.rb +5 -0
- data/lib/comfy_middle_seat.rb +3 -0
- data/lib/generators/comfy/cms/README +21 -0
- data/lib/generators/comfy/cms/assets_generator.rb +16 -0
- data/lib/generators/comfy/cms/cms_generator.rb +69 -0
- data/lib/generators/comfy/cms/controllers_generator.rb +15 -0
- data/lib/generators/comfy/cms/models_generator.rb +15 -0
- data/lib/generators/comfy/cms/views_generator.rb +15 -0
- data/lib/generators/comfy/scaffold/scaffold_generator.rb +79 -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_assets.rake +19 -0
- data/lib/tasks/cms_seeds.rake +40 -0
- data/package-lock.json +989 -0
- data/package.json +23 -0
- data/public/favicon.ico +0 -0
- data/rakelib/create_release.rake +82 -0
- metadata +665 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# This tag allows for linking of js and css content defined on the layout.
|
|
4
|
+
# Looks something like this:
|
|
5
|
+
# {{cms:asset layout_identifier, type: css, as: tag}}
|
|
6
|
+
#
|
|
7
|
+
# `type` - css | js - what we're outputting here
|
|
8
|
+
# `as` - url (default) | tag - output url or wrap it in the appropriate tag
|
|
9
|
+
#
|
|
10
|
+
class ComfortableMediaSurfer::Content::Tags::Asset < ComfortableMediaSurfer::Content::Tag
|
|
11
|
+
attr_reader :identifier, :type, :as
|
|
12
|
+
|
|
13
|
+
def initialize(context:, params: [], source: nil)
|
|
14
|
+
super
|
|
15
|
+
|
|
16
|
+
options = params.extract_options!
|
|
17
|
+
@identifier = params[0]
|
|
18
|
+
@type = options['type']
|
|
19
|
+
@as = options['as'] || 'url'
|
|
20
|
+
|
|
21
|
+
return if @identifier.present?
|
|
22
|
+
|
|
23
|
+
raise Error, 'Missing layout identifier for asset tag'
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def layout
|
|
27
|
+
@layout ||= context.site.layouts.find_by(identifier: @identifier)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def content
|
|
31
|
+
return '' unless layout
|
|
32
|
+
|
|
33
|
+
base = ComfortableMediaSurfer.config.public_cms_path || ''
|
|
34
|
+
unless base.ends_with?('/')
|
|
35
|
+
base += '/'
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
case @type
|
|
39
|
+
when 'css'
|
|
40
|
+
out = "#{base}cms-css/#{context.site.id}/#{@identifier}/#{layout.cache_buster}.css"
|
|
41
|
+
if @as == 'tag'
|
|
42
|
+
out = "<link href='#{out}' media='screen' rel='stylesheet' type='text/css' />"
|
|
43
|
+
end
|
|
44
|
+
out
|
|
45
|
+
when 'js'
|
|
46
|
+
out = "#{base}cms-js/#{context.site.id}/#{@identifier}/#{layout.cache_buster}.js"
|
|
47
|
+
if @as == 'tag'
|
|
48
|
+
out = "<script src='#{out}' type='text/javascript'></script>"
|
|
49
|
+
end
|
|
50
|
+
out
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
ComfortableMediaSurfer::Content::Renderer.register_tag(
|
|
56
|
+
:asset, ComfortableMediaSurfer::Content::Tags::Asset
|
|
57
|
+
)
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Tag for injecting HTML5 audio player. Example tag:
|
|
4
|
+
# {{ cms:audio "path/to/audio", style: "height: 22px; width: 80%" }}
|
|
5
|
+
# This expands into:
|
|
6
|
+
# <audio controls src="path/to/audio"></audio>
|
|
7
|
+
# To customize your player style, add a 'audioplayer' class to your CSS, e.g
|
|
8
|
+
# .audioplayer {
|
|
9
|
+
# border-radius: 6px;
|
|
10
|
+
# height: 22px;
|
|
11
|
+
# width: 60%;
|
|
12
|
+
# margin: 2px 0 2px 8px;
|
|
13
|
+
# padding: 0;
|
|
14
|
+
# }
|
|
15
|
+
# and/or pass in style overrides with the 'style' parameter, as above
|
|
16
|
+
|
|
17
|
+
class ComfortableMediaSurfer::Content::Tags::Audio < ComfortableMediaSurfer::Content::Tag
|
|
18
|
+
attr_reader :path, :style, :locals
|
|
19
|
+
|
|
20
|
+
def initialize(context:, params: [], source: nil)
|
|
21
|
+
super
|
|
22
|
+
@locals = params.extract_options!
|
|
23
|
+
@path = params[0]
|
|
24
|
+
@style = ''
|
|
25
|
+
@style = "<style>.audioplayer {#{@locals['style']}}</style>" if @locals['style']
|
|
26
|
+
|
|
27
|
+
return if @path.present?
|
|
28
|
+
|
|
29
|
+
raise Error, 'Missing path for audio tag'
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def content
|
|
33
|
+
"#{@style}<audio controls class=\"audioplayer\" src=#{@path}></audio>"
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
ComfortableMediaSurfer::Content::Renderer.register_tag(
|
|
38
|
+
:audio, ComfortableMediaSurfer::Content::Tags::Audio
|
|
39
|
+
)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Nav Tag for rendering breadcrumb links to current page
|
|
4
|
+
# {{ cms:breadcrumbs }}
|
|
5
|
+
# {{ cms:breadcrumbs style: "font-weight: bold" }}
|
|
6
|
+
# To customize your breadcrumbs style, add a 'breadcrumbs' id to your CSS, e.g
|
|
7
|
+
# #breadcrumbs {
|
|
8
|
+
# color: #006633;
|
|
9
|
+
# font-family: Verdana, Arial, Helvetica, sans-serif;
|
|
10
|
+
# font-size: 105%;
|
|
11
|
+
# font-weight: bold;
|
|
12
|
+
# margin-top: 12px;
|
|
13
|
+
# margin-bottom: 4px;
|
|
14
|
+
# font-style: italic;
|
|
15
|
+
# }
|
|
16
|
+
# and/or pass in style overrides with the 'style' parameter, as above
|
|
17
|
+
|
|
18
|
+
class ComfortableMediaSurfer::Content::Tags::Breadcrumbs < ComfortableMediaSurfer::Content::Tag
|
|
19
|
+
attr_reader :links, :style, :locals
|
|
20
|
+
|
|
21
|
+
def initialize(context:, params: [], source: nil)
|
|
22
|
+
super
|
|
23
|
+
@locals = params.extract_options!
|
|
24
|
+
@style = ''
|
|
25
|
+
@style = "<style>#breadcrumbs {#{@locals['style']}}</style>" if @locals['style']
|
|
26
|
+
|
|
27
|
+
@links = '<div id="breadcrumbs">'
|
|
28
|
+
context.ancestors.reverse.each do |a|
|
|
29
|
+
next if Rails.env == 'production' && !a.is_published
|
|
30
|
+
|
|
31
|
+
@links += "<a href=#{a.url(relative: true)}>#{a.label}</a> » "
|
|
32
|
+
end
|
|
33
|
+
@links += "#{context.label}</div>"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def content
|
|
37
|
+
"#{@style}#{@links}"
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
ComfortableMediaSurfer::Content::Renderer.register_tag(
|
|
42
|
+
:breadcrumbs, ComfortableMediaSurfer::Content::Tags::Breadcrumbs
|
|
43
|
+
)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Tag for boolean content that is going to be rendered using checkbox
|
|
4
|
+
# {{ cms:checkbox identifier }}
|
|
5
|
+
#
|
|
6
|
+
class ComfortableMediaSurfer::Content::Tags::Checkbox < ComfortableMediaSurfer::Content::Tags::Fragment
|
|
7
|
+
def content
|
|
8
|
+
fragment.boolean
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def form_field(object_name, view, index)
|
|
12
|
+
name = "#{object_name}[fragments_attributes][#{index}][boolean]"
|
|
13
|
+
|
|
14
|
+
input = view.content_tag(:div, class: 'form-check mt-2') do
|
|
15
|
+
view.concat view.hidden_field_tag(name, '0', id: nil)
|
|
16
|
+
|
|
17
|
+
options = { id: form_field_id, class: 'form-check-input position-static' }
|
|
18
|
+
view.concat view.check_box_tag(name, '1', content.present?, options)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
yield input
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
ComfortableMediaSurfer::Content::Renderer.register_tag(
|
|
26
|
+
:checkbox, ComfortableMediaSurfer::Content::Tags::Checkbox
|
|
27
|
+
)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Nav Tag for unordered list of links to the children of the current page
|
|
4
|
+
# {{ cms:children }}
|
|
5
|
+
# {{ cms:children style: "font-weight: bold", exclude: "404-page, search-page" }}
|
|
6
|
+
# To customize your children style, add a 'children' id to your CSS, e.g
|
|
7
|
+
# #children {
|
|
8
|
+
# color: #006633;
|
|
9
|
+
# font-size: 90%;
|
|
10
|
+
# margin-bottom: 4px;
|
|
11
|
+
# font-style: italic;
|
|
12
|
+
# }
|
|
13
|
+
# and/or pass in style overrides with the 'style' parameter, as above
|
|
14
|
+
#
|
|
15
|
+
# To exclude children, list their slugs with the 'exclude' parameter
|
|
16
|
+
# as comma-delimited string, e.g. as above - exclude: "404-page, search-page"
|
|
17
|
+
|
|
18
|
+
class ComfortableMediaSurfer::Content::Tags::Children < ComfortableMediaSurfer::Content::Tag
|
|
19
|
+
attr_reader :style, :page_children, :locals
|
|
20
|
+
attr_accessor :list
|
|
21
|
+
|
|
22
|
+
def initialize(context:, params: [], source: nil)
|
|
23
|
+
super
|
|
24
|
+
@locals = params.extract_options!
|
|
25
|
+
@style = ''
|
|
26
|
+
@style = "<style>#children {#{@locals['style']}}</style>\n" if @locals['style']
|
|
27
|
+
@exclude = []
|
|
28
|
+
@exclude = @locals['exclude'].split(',').map(&:strip) if @locals['exclude']
|
|
29
|
+
@list = ''
|
|
30
|
+
# ActiveRecord_Associations_CollectionProxy
|
|
31
|
+
@page_children = context.children.order(:position).to_ary
|
|
32
|
+
unless Rails.env == 'development'
|
|
33
|
+
@page_children.delete_if { |child| !child.is_published }
|
|
34
|
+
end
|
|
35
|
+
@page_children.delete_if { |child| @exclude.include? child.slug }
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def content
|
|
39
|
+
if @page_children.any?
|
|
40
|
+
@list = "<ul id=\"children\">\n"
|
|
41
|
+
@page_children.each do |c|
|
|
42
|
+
@list += " <li><a href=#{c.url(relative: true)}>#{c.label}</a></li>\n"
|
|
43
|
+
end
|
|
44
|
+
@list += '</ul>'
|
|
45
|
+
end
|
|
46
|
+
"#{@style}#{@list}"
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
ComfortableMediaSurfer::Content::Renderer.register_tag(
|
|
51
|
+
:children, ComfortableMediaSurfer::Content::Tags::Children
|
|
52
|
+
)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Tag for text content that is going to be rendered using text input with date widget
|
|
4
|
+
# {{ cms:date identifier }}
|
|
5
|
+
#
|
|
6
|
+
class ComfortableMediaSurfer::Content::Tags::Date < ComfortableMediaSurfer::Content::Tags::Datetime
|
|
7
|
+
def form_field(object_name, view, index)
|
|
8
|
+
name = "#{object_name}[fragments_attributes][#{index}][datetime]"
|
|
9
|
+
options = { id: form_field_id, class: 'form-control', data: { 'cms-date' => true } }
|
|
10
|
+
value = content.present? ? content.to_fs(:db) : ''
|
|
11
|
+
input = view.send(:text_field_tag, name, value, options)
|
|
12
|
+
|
|
13
|
+
yield input
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
ComfortableMediaSurfer::Content::Renderer.register_tag(
|
|
18
|
+
:date, ComfortableMediaSurfer::Content::Tags::Date
|
|
19
|
+
)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Tag for text content that is going to be rendered using text input with datetime widget
|
|
4
|
+
# {{ cms:datetime identifier, strftime: "at %I:%M%p" }}
|
|
5
|
+
#
|
|
6
|
+
# `strftime` - Format datetime string during rendering
|
|
7
|
+
#
|
|
8
|
+
class ComfortableMediaSurfer::Content::Tags::Datetime < ComfortableMediaSurfer::Content::Tags::Fragment
|
|
9
|
+
attr_reader :strftime
|
|
10
|
+
|
|
11
|
+
def initialize(context:, params: [], source: nil)
|
|
12
|
+
super
|
|
13
|
+
@strftime = options['strftime']
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def content
|
|
17
|
+
fragment.datetime
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def render
|
|
21
|
+
return '' unless renderable
|
|
22
|
+
|
|
23
|
+
if strftime.present?
|
|
24
|
+
content.strftime(strftime)
|
|
25
|
+
else
|
|
26
|
+
content.to_s
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def form_field(object_name, view, index)
|
|
31
|
+
name = "#{object_name}[fragments_attributes][#{index}][datetime]"
|
|
32
|
+
options = { id: form_field_id, class: 'form-control', data: { 'cms-datetime' => true } }
|
|
33
|
+
value = content.present? ? content.to_fs(:db) : ''
|
|
34
|
+
input = view.send(:text_field_tag, name, value, options)
|
|
35
|
+
|
|
36
|
+
yield input
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
ComfortableMediaSurfer::Content::Renderer.register_tag(
|
|
41
|
+
:datetime, ComfortableMediaSurfer::Content::Tags::Datetime
|
|
42
|
+
)
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'mixins/file_content'
|
|
4
|
+
|
|
5
|
+
# File tag allows attaching of file to the page. This controls how files are
|
|
6
|
+
# uploaded and then displayed on the page. Example tag:
|
|
7
|
+
# {{ cms:file identifier, as: link, label: "My File" }}
|
|
8
|
+
#
|
|
9
|
+
# `as` - url (default) | link | image - render out link or image tag
|
|
10
|
+
# `label` - attach label attribute to link or image tag
|
|
11
|
+
# `resize` - imagemagic option. For example: "100x50>"
|
|
12
|
+
# `gravity` - imagemagic option. For example: "center"
|
|
13
|
+
# `crop` - imagemagic option. For example: "100x50+0+0"
|
|
14
|
+
# `class` - any html classes that you want on the result link or image tag. For example "class1 class2"
|
|
15
|
+
#
|
|
16
|
+
class ComfortableMediaSurfer::Content::Tags::File < ComfortableMediaSurfer::Content::Tags::Fragment
|
|
17
|
+
include ComfortableMediaSurfer::Content::Tags::Mixins::FileContent
|
|
18
|
+
|
|
19
|
+
# @type ["url", "link", "image"]
|
|
20
|
+
attr_reader :as
|
|
21
|
+
|
|
22
|
+
# @type [{String => String}]
|
|
23
|
+
attr_reader :variant_attrs
|
|
24
|
+
|
|
25
|
+
# @param (see ComfortableMediaSurfer::Content::Tag#initialize)
|
|
26
|
+
def initialize(context:, params: [], source: nil)
|
|
27
|
+
super
|
|
28
|
+
@as = options['as'] || 'url'
|
|
29
|
+
@label = options['label']
|
|
30
|
+
@class = options['class']
|
|
31
|
+
@variant_attrs = options.slice('resize', 'gravity', 'crop')
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def form_field(object_name, view, index)
|
|
35
|
+
name = "#{object_name}[fragments_attributes][#{index}][files]"
|
|
36
|
+
input = view.send(:file_field_tag, name, id: form_field_id, class: 'form-control')
|
|
37
|
+
|
|
38
|
+
attachments_partial =
|
|
39
|
+
if fragment.attachments
|
|
40
|
+
view.render(
|
|
41
|
+
partial: 'comfy/admin/cms/fragments/form_fragment_attachments',
|
|
42
|
+
locals: {
|
|
43
|
+
object_name: object_name,
|
|
44
|
+
index: index,
|
|
45
|
+
attachments: fragment.attachments,
|
|
46
|
+
fragment_id: identifier,
|
|
47
|
+
multiple: false
|
|
48
|
+
}
|
|
49
|
+
)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
yield view.safe_join([input, attachments_partial], '')
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
protected
|
|
56
|
+
|
|
57
|
+
# @return [ActiveStorage::Blob]
|
|
58
|
+
def file
|
|
59
|
+
fragment.attachments.first
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# @return [String]
|
|
63
|
+
def label
|
|
64
|
+
@label || file&.filename
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
ComfortableMediaSurfer::Content::Renderer.register_tag(
|
|
69
|
+
:file, ComfortableMediaSurfer::Content::Tags::File
|
|
70
|
+
)
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'mixins/file_content'
|
|
4
|
+
|
|
5
|
+
# This is how you link previously uploaded file to anywhere. Good example may be
|
|
6
|
+
# a header image you want to use on the layout level.
|
|
7
|
+
# {{cms:file_link id, as: image}}
|
|
8
|
+
#
|
|
9
|
+
# `as` - url (default) | link | image - how file gets rendered out
|
|
10
|
+
# `class` - any html classes that you want on the result link or image tag. For example "class1 class2"
|
|
11
|
+
#
|
|
12
|
+
# - variant_attrs are not functional, perhaps due to some change in ImageMagick
|
|
13
|
+
# - Simply use a class in your CSS / SASS to style your image display
|
|
14
|
+
# `label` - attach label attribute to link or image tag
|
|
15
|
+
# `resize` - imagemagick option. For example: "100x50>"
|
|
16
|
+
# `gravity` - imagemagick option. For example: "center"
|
|
17
|
+
# `crop` - imagemagick option. For example: "100x50+0+0"
|
|
18
|
+
#
|
|
19
|
+
class ComfortableMediaSurfer::Content::Tags::FileLink < ComfortableMediaSurfer::Content::Tag
|
|
20
|
+
include ComfortableMediaSurfer::Content::Tags::Mixins::FileContent
|
|
21
|
+
|
|
22
|
+
attr_reader :identifier, :as, :variant_attrs
|
|
23
|
+
|
|
24
|
+
def initialize(context:, params: [], source: nil)
|
|
25
|
+
super
|
|
26
|
+
|
|
27
|
+
options = params.extract_options!
|
|
28
|
+
@identifier = params[0]
|
|
29
|
+
@as = options['as'] || 'url'
|
|
30
|
+
@class = options['class']
|
|
31
|
+
@variant_attrs = options.slice('resize', 'gravity', 'crop') # broken for ImageMagick
|
|
32
|
+
|
|
33
|
+
return if @identifier.present?
|
|
34
|
+
|
|
35
|
+
raise Error, 'Missing identifier for file link tag'
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# @return [Comfy::Cms::File]
|
|
39
|
+
def file_record
|
|
40
|
+
@file_record ||= context.site.files.detect { |f| f.id == identifier.to_i }
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# @return [ActiveStorage::Blob]
|
|
44
|
+
def file
|
|
45
|
+
file_record&.attachment
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# @return [String]
|
|
49
|
+
def label
|
|
50
|
+
return '' if file_record.nil?
|
|
51
|
+
|
|
52
|
+
file_record.label.presence || file.filename.to_s
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
ComfortableMediaSurfer::Content::Renderer.register_tag(
|
|
57
|
+
:file_link, ComfortableMediaSurfer::Content::Tags::FileLink
|
|
58
|
+
)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Same tag as File, only it handles multiple attachments.
|
|
4
|
+
# Generally not a bad idea to handle rendering of this in a partial/helper.
|
|
5
|
+
# Example tag:
|
|
6
|
+
# {{ cms:files identifier }}
|
|
7
|
+
#
|
|
8
|
+
class ComfortableMediaSurfer::Content::Tags::Files < ComfortableMediaSurfer::Content::Tags::File
|
|
9
|
+
def content
|
|
10
|
+
return '' if fragment.attachments.blank?
|
|
11
|
+
|
|
12
|
+
fragment.attachments.collect do |attachment|
|
|
13
|
+
super(file: attachment, label: attachment.filename)
|
|
14
|
+
end.join(' ')
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def form_field(object_name, view, index)
|
|
18
|
+
name = "#{object_name}[fragments_attributes][#{index}][files][]"
|
|
19
|
+
input = view.send(:file_field_tag, name, id: form_field_id, multiple: true, class: 'form-control')
|
|
20
|
+
|
|
21
|
+
attachments_partial =
|
|
22
|
+
if fragment.attachments
|
|
23
|
+
view.render(
|
|
24
|
+
partial: 'comfy/admin/cms/fragments/form_fragment_attachments',
|
|
25
|
+
locals: {
|
|
26
|
+
object_name: object_name,
|
|
27
|
+
index: index,
|
|
28
|
+
attachments: fragment.attachments,
|
|
29
|
+
fragment_id: identifier,
|
|
30
|
+
multiple: true
|
|
31
|
+
}
|
|
32
|
+
)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
yield view.safe_join([input, attachments_partial], '')
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
ComfortableMediaSurfer::Content::Renderer.register_tag(
|
|
40
|
+
:files, ComfortableMediaSurfer::Content::Tags::Files
|
|
41
|
+
)
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Base Tag class that other fragment tags depend on.
|
|
4
|
+
# Tag handles following options:
|
|
5
|
+
# `render`: true (default) | false
|
|
6
|
+
# do we want to render this content on the page, or manually access it via
|
|
7
|
+
# helpers. Good example would be content for meta tags.
|
|
8
|
+
# `namespace`:
|
|
9
|
+
# Just a string that allows grouping of form elements in the admin area
|
|
10
|
+
#
|
|
11
|
+
class ComfortableMediaSurfer::Content::Tags::Fragment < ComfortableMediaSurfer::Content::Tag
|
|
12
|
+
attr_accessor :renderable
|
|
13
|
+
attr_reader :identifier, :namespace
|
|
14
|
+
|
|
15
|
+
# @type [{String => String}]
|
|
16
|
+
attr_reader :options
|
|
17
|
+
|
|
18
|
+
def initialize(context:, params: [], source: nil)
|
|
19
|
+
super
|
|
20
|
+
|
|
21
|
+
@options = params.extract_options!
|
|
22
|
+
@identifier = params[0]
|
|
23
|
+
|
|
24
|
+
unless @identifier.present?
|
|
25
|
+
raise Error, "Missing identifier for fragment tag: #{source}"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
@namespace = @options['namespace'] || 'default'
|
|
29
|
+
@renderable = @options['render'].to_s.downcase != 'false'
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Grabs existing fragment record or spins up a new instance if there's none
|
|
33
|
+
# @return [Comfy::Cms::Fragment]
|
|
34
|
+
def fragment
|
|
35
|
+
context.fragments.detect { |f| f.identifier == identifier } ||
|
|
36
|
+
context.fragments.build(identifier: identifier)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def content
|
|
40
|
+
fragment.content
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# If `render: false` was passed in we won't render anything. Assuming that
|
|
44
|
+
# that fragment content will be rendered manually
|
|
45
|
+
def render
|
|
46
|
+
renderable ? content : ''
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Tag renders its own form inputs via `form_field(template, index)`
|
|
50
|
+
# For example:
|
|
51
|
+
# class MyTag < ComfortableMediaSurfer::Content::Tags::Fragment
|
|
52
|
+
# def form_field(view, index, &block)
|
|
53
|
+
# # omit yield if you don't want default wrapper
|
|
54
|
+
# yield view.text_area "input_name", "value"
|
|
55
|
+
# end
|
|
56
|
+
# end
|
|
57
|
+
def form_field
|
|
58
|
+
raise 'Form field rendering not implemented for this Tag'
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def form_field_id
|
|
62
|
+
"fragment-#{@identifier}"
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Tag for injecting view helpers. Example tag:
|
|
4
|
+
# {{cms:helper method_name, param_a, param_b, foo: bar}}
|
|
5
|
+
# This expands into something like this:
|
|
6
|
+
# <%= method_name("param_a", "param_b", "foo" => "bar") %>
|
|
7
|
+
# Whitelist is can be used to control what helpers are available.
|
|
8
|
+
# By default there's a blacklist of methods that should not be called.
|
|
9
|
+
#
|
|
10
|
+
class ComfortableMediaSurfer::Content::Tags::Helper < ComfortableMediaSurfer::Content::Tag
|
|
11
|
+
BLACKLIST = %w[eval class_eval instance_eval render].freeze
|
|
12
|
+
|
|
13
|
+
attr_reader :method_name
|
|
14
|
+
|
|
15
|
+
def initialize(context:, params: [], source: nil)
|
|
16
|
+
super
|
|
17
|
+
@method_name = params.shift
|
|
18
|
+
|
|
19
|
+
return if @method_name.present?
|
|
20
|
+
|
|
21
|
+
raise Error, 'Missing method name for helper tag'
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# we output erb into rest of the content
|
|
25
|
+
def allow_erb?
|
|
26
|
+
true
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def content
|
|
30
|
+
helper_params = params.map do |p|
|
|
31
|
+
case p
|
|
32
|
+
when Hash
|
|
33
|
+
format('%<arg>s', arg: p)
|
|
34
|
+
else
|
|
35
|
+
format('%<arg>p', arg: p)
|
|
36
|
+
end
|
|
37
|
+
end.join(',')
|
|
38
|
+
"<%= #{method_name}(#{helper_params}) %>"
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def render
|
|
42
|
+
whitelist = ComfortableMediaSurfer.config.allowed_helpers
|
|
43
|
+
if whitelist.is_a?(Array)
|
|
44
|
+
content if whitelist.map!(&:to_s).member?(method_name)
|
|
45
|
+
else
|
|
46
|
+
content unless BLACKLIST.member?(method_name)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
ComfortableMediaSurfer::Content::Renderer.register_tag(
|
|
52
|
+
:helper, ComfortableMediaSurfer::Content::Tags::Helper
|
|
53
|
+
)
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'mixins/file_content'
|
|
4
|
+
|
|
5
|
+
# This is like the the file_link tag, but specifically for images
|
|
6
|
+
# Identify the image by its label {{ cms:image label }}
|
|
7
|
+
#
|
|
8
|
+
# `class` - any html classes that you want on the image tag. For example "class1 class2"
|
|
9
|
+
#
|
|
10
|
+
# - variant_attrs are not functional, perhaps due to some change in ImageMagick
|
|
11
|
+
# - Simply use a class in your CSS / SASS to style your image display
|
|
12
|
+
# `label` - attach label attribute to link or image tag
|
|
13
|
+
# `resize` - imagemagick option. For example: "100x50>"
|
|
14
|
+
# `gravity` - imagemagick option. For example: "center"
|
|
15
|
+
# `crop` - imagemagick option. For example: "100x50+0+0"
|
|
16
|
+
|
|
17
|
+
class ComfortableMediaSurfer::Content::Tags::Image < ComfortableMediaSurfer::Content::Tag
|
|
18
|
+
include ComfortableMediaSurfer::Content::Tags::Mixins::FileContent
|
|
19
|
+
|
|
20
|
+
attr_reader :identifier, :as, :variant_attrs
|
|
21
|
+
|
|
22
|
+
def initialize(context:, params: [], source: nil)
|
|
23
|
+
super
|
|
24
|
+
|
|
25
|
+
options = params.extract_options!
|
|
26
|
+
@identifier = params[0]
|
|
27
|
+
@as = 'image'
|
|
28
|
+
@class = options['class']
|
|
29
|
+
@variant_attrs = options.slice('resize', 'gravity', 'crop') # broken for ImageMagick
|
|
30
|
+
|
|
31
|
+
return if @identifier.present?
|
|
32
|
+
|
|
33
|
+
raise Error, 'Missing identifier label for image tag'
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# @return [Comfy::Cms::File]
|
|
37
|
+
def file_record
|
|
38
|
+
@file_record ||= context.site.files.detect { |f| f.label == identifier }
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# @return [ActiveStorage::Blob]
|
|
42
|
+
def file
|
|
43
|
+
file_record&.attachment
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# @return [String]
|
|
47
|
+
def label
|
|
48
|
+
return '' if file_record.nil?
|
|
49
|
+
|
|
50
|
+
file_record.label.presence || file.filename.to_s
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
ComfortableMediaSurfer::Content::Renderer.register_tag(
|
|
55
|
+
:image, ComfortableMediaSurfer::Content::Tags::Image
|
|
56
|
+
)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Tag for text content that is going to be rendered using textarea with markdown
|
|
4
|
+
# {{ cms:markdown identifier }}
|
|
5
|
+
#
|
|
6
|
+
class ComfortableMediaSurfer::Content::Tags::Markdown < ComfortableMediaSurfer::Content::Tags::Fragment
|
|
7
|
+
def render
|
|
8
|
+
renderable ? Kramdown::Document.new(content.to_s).to_html : ''
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def form_field(object_name, view, index)
|
|
12
|
+
name = "#{object_name}[fragments_attributes][#{index}][content]"
|
|
13
|
+
options = { id: form_field_id, data: { 'cms-cm-mode' => 'text/x-markdown' } }
|
|
14
|
+
input = view.send(:text_area_tag, name, content, options)
|
|
15
|
+
|
|
16
|
+
yield input
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
ComfortableMediaSurfer::Content::Renderer.register_tag(
|
|
21
|
+
:markdown, ComfortableMediaSurfer::Content::Tags::Markdown
|
|
22
|
+
)
|