Module: Alchemy::ElementsHelper

Includes:
ElementsBlockHelper, UrlHelper
Included in:
PagesHelper
Defined in:
app/helpers/alchemy/elements_helper.rb

Overview

This helpers are useful to render elements from pages.

The most important helper for frontend developers is the #render_elements helper.

Instance Method Summary collapse

Methods included from ElementsBlockHelper

#element_view_for

Methods included from UrlHelper

#download_alchemy_attachment_path, #download_alchemy_attachment_url, #full_url_for_element, #show_alchemy_page_path, #show_alchemy_page_url, #show_page_path_params

Instance Method Details

#element_dom_id(element) ⇒ Object

Returns a string for the id attribute of a html element for the given element



170
171
172
173
174
# File 'app/helpers/alchemy/elements_helper.rb', line 170

def element_dom_id(element)
  return "" if element.nil?

  "#{element.name}_#{element.id}".html_safe
end

#element_preview_code(element) ⇒ Object

Renders the HTML tag attributes required for preview mode.



177
178
179
# File 'app/helpers/alchemy/elements_helper.rb', line 177

def element_preview_code(element)
  tag_builder.tag_options(element_preview_code_attributes(element))
end

#element_preview_code_attributes(element) ⇒ Object

Returns a hash containing the HTML tag attributes required for preview mode.



182
183
184
185
186
# File 'app/helpers/alchemy/elements_helper.rb', line 182

def element_preview_code_attributes(element)
  return {} unless element.present? && @preview_mode && element.page == @page

  { "data-alchemy-element" => element.id }
end

#element_tags(element, options = {}) ⇒ String

Returns the element’s tags information as a string. Parameters and options are equivalent to #element_tags_attributes.

Returns:

  • (String)

    HTML tag attributes containing the element’s tag information.

See Also:



196
197
198
# File 'app/helpers/alchemy/elements_helper.rb', line 196

def element_tags(element, options = {})
  tag_builder.tag_options(element_tags_attributes(element, options))
end

#element_tags_attributes(element, options = {}) ⇒ Hash

Returns the element’s tags information as an attribute hash.

Parameters:

Options Hash (options):

  • :formatter (Proc) — default: 'lambda { |tags| tags.join(' ') }'

    Lambda converting array of tags to a string.

Returns:

  • (Hash)

    HTML tag attributes containing the element’s tag information.



211
212
213
214
215
216
217
218
219
# File 'app/helpers/alchemy/elements_helper.rb', line 211

def element_tags_attributes(element, options = {})
  options = {
    formatter: lambda { |tags| tags.join(" ") },
  }.merge(options)

  return {} if !element.taggable? || element.tag_list.blank?

  { "data-element-tags" => options[:formatter].call(element.tag_list) }
end

#render_element(element, options = {}, counter = 1) ⇒ Object

Note:

If the view partial is not found alchemy/elements/_view_not_found.html.erb gets rendered.

This helper renders a Alchemy::Element view partial.

A element view partial is the html snippet presented to the website visitor.

The partial is located in app/views/alchemy/elements.

View partial naming

The partial has to be named after the name of the element as defined in the elements.yml file.

Example

Given a headline element

# elements.yml
- name: headline
  contents:
  - name: text
    type: EssenceText

Then your element view partial has to be named like:

app/views/alchemy/elements/_headline.html.{erb|haml|slim}

Element partials generator

You can use this handy generator to let Alchemy generate the partials for you:

$ rails generate alchemy:elements --skip

Usage

<%= render_element(Alchemy::Element.published.named(:headline).first) %>

Parameters:

  • element (Alchemy::Element)

    The element you want to render the view for

  • options (Hash) (defaults to: {})

    Additional options

  • counter (Number) (defaults to: 1)

    a counter



143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'app/helpers/alchemy/elements_helper.rb', line 143

def render_element(element, options = {}, counter = 1)
  if element.nil?
    warning("Element is nil")
    render "alchemy/elements/view_not_found", { name: "nil" }
    return
  end

  element.store_page(@page)

  render(
    partial: options[:partial] || element.to_partial_path,
    object: element,
    locals: {
      element: element,
      counter: counter,
      options: options.except(:locals, :partial),
    }.merge(options[:locals] || {}),
  )
rescue ActionView::MissingTemplate => e
  warning(%(
    Element view partial not found for #{element.name}.\n
    #{e}
  ))
  render "alchemy/elements/view_not_found", name: element.name
end

#render_elements(options = {}, &blk) ⇒ Object

Renders elements from given page

Examples:

Render only certain elements:

<header>
  <%= render_elements only: ['header', 'claim'] %>
</header>
<section id="content">
  <%= render_elements except: ['header', 'claim'] %>
</section>

Render elements from global page:

<footer>
  <%= render_elements from_page: Alchemy::Page.find_by(page_layout: 'footer') %>
</footer>

Custom elements finder:

Having a custom element finder class:

class MyCustomNewsArchive
  def elements(page:)
    news_page.elements.named('news').order(created_at: :desc)
  end

  private

  def news_page
    Alchemy::Page.where(page_layout: 'news-archive')
  end
end

In your view:

<div class="news-archive">
  <%= render_elements finder: MyCustomNewsArchive.new %>
</div>

Parameters:

  • options (Hash) (defaults to: {})

    a customizable set of options

Options Hash (options):

  • :from_page (Alchemy::Page) — default: @page

    The page the elements are rendered from.

  • :only (Array<String>|String)

    A list of element names only to be rendered.

  • :except (Array<String>|String)

    A list of element names not to be rendered.

  • :count (Number)

    The amount of elements to be rendered (begins with first element found)

  • :offset (Number)

    The offset to begin loading elements from

  • :random (Boolean) — default: false

    Randomize the output of elements

  • :reverse (Boolean) — default: false

    Reverse the rendering order

  • :separator (String)

    A string that will be used to join the element partials.

  • :finder (Class) — default: Alchemy::ElementsFinder

    A class instance that will return elements that get rendered. Use this for your custom element loading logic in views.



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'app/helpers/alchemy/elements_helper.rb', line 73

def render_elements(options = {}, &blk)
  options = {
    from_page: @page,
    render_format: "html",
  }.update(options)

  finder = options[:finder] || Alchemy::ElementsFinder.new(options)

  page_version = if @preview_mode
      options[:from_page]&.draft_version
    else
      options[:from_page]&.public_version
    end

  elements = finder.elements(page_version: page_version)

  default_rendering = ->(element, i) { render_element(element, options, i + 1) }
  capture do
    if block_given?
      elements.map.with_index(&blk)
    else
      elements.map.with_index(&default_rendering)
    end.join(options[:separator]).html_safe
  end
end