locomotivecms/engine

View on GitHub
app/models/locomotive/section.rb

Summary

Maintainability
A
2 hrs
Test Coverage
module Locomotive
  class Section

    include Locomotive::Mongoid::Document
    include Concerns::Shared::SiteScope
    include Concerns::Shared::Slug
    include Concerns::Shared::JsonAttribute

    ## fields ##
    field :name
    field :slug
    field :definition, type: Hash, default: {}
    field :template

    ## validations ##
    validates_presence_of   :name, :slug, :template, :definition
    validates_uniqueness_of :slug, scope: :site_id

    ## named scopes ##
    scope :by_id_or_slug, ->(id_or_slug) { where('$or' => [{ _id: id_or_slug }, { slug: id_or_slug }]) }

    ## behaviours ##
    slugify_from    :name
    json_attribute  :definition

    ## indexes ##
    index site_id: 1, slug: 1

    ## methods ##

    def touch_site_attribute
      :template_version
    end

    # Example:
    # {
    #   "name": "Header",
    #   "settings": [
    #     {
    #       "label": "Brand name",
    #       "id": "brand",
    #       "type": "string"
    #     }
    #   ],
    #   "blocks": [
    #     {
    #       "name": "Menu item",
    #       "type": "menu_item",
    #       "settings": [
    #         {
    #           "label": "Item item",
    #           "id": "title",
    #           "type": "text"
    #         },
    #         {
    #           "label": "Item link",
    #           "id": "url",
    #           "type": "text"
    #         },
    #         {
    #           "label": "Open a new tab",
    #           "id": "new_tab",
    #           "type": "boolean",
    #           "default": false
    #         }
    #       ]
    #     }
    #   ]
    # }
    def _definition_schema
      {
        id: 'http://www.locomotive.cms/schemas/sections/definition2.json',
        definitions: {
          settings: {
            type: 'object',
            properties: {
              id:       { type: 'string' },
              label:    { '$ref': '#/definitions/locale_string' },
              type:     { enum: ['text', 'image_picker', 'asset_picker', 'checkbox', 'select', 'url', 'radio', 'content_type', 'content_entry', 'hint', 'integer'] },
              default:  {}
            },
            required: [:id, :type]
          },
          blocks: {
            type: 'object',
            properties: {
              name:       { '$ref': '#/definitions/locale_string' },
              type:       { type: 'string' },
              limit:      { type: 'integer' },
              settings:   { type: 'array', items: { '$ref': '#/definitions/settings' }, default: [] }
            },
            required: [:type, :name]
          },
          preset_blocks: {
            type: 'object',
            properties: {
              type:       { type: 'string' }
            },
            required: [:type]
          },
          preset: {
            type: 'object',
            properties: {
              name:       { '$ref': '#/definitions/locale_string' },
              category:   { '$ref': '#/definitions/locale_string' },
              settings:   { type: 'object' },
              blocks:     { type: 'array', items: { '$ref': '#/definitions/preset_blocks'} }
            },
            required: [:name, :category]
          },
          locale_string: {
             anyOf: [
              { type: 'string' },
              {
                type: 'object',
                patternProperties: {
                  '^[a-z]*(-[A-z]*)*$': { 'type': 'string' }
                },
                additionalProperties: false
              }
            ]
          }
        },
        type: 'object',
        properties: {
          name:             { '$ref': '#/definitions/locale_string' },
          class:            { type: 'string' },
          settings:         { type: 'array', items: { '$ref': '#/definitions/settings' } },
          presets:          { type: 'array', items: { '$ref': '#/definitions/preset' } },
          blocks:           { type: 'array', items: { '$ref': '#/definitions/blocks' } },
          max_blocks:       { type: 'integer' },
          blocks_display:   { enum: ['list', 'tree'] },
          max_blocks_depth: { type: 'integer' },
          default:          {
            type: 'object',
            properties: {
              settings:  { type: 'object' },
              blocks:    { type: 'array' }
            },
            required: [:settings]
          }
        },
        required: [:name, :settings]
      }
    end

  end
end