Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Separate render element calls #1554

Merged
merged 3 commits into from
Mar 29, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 56 additions & 3 deletions app/helpers/alchemy/admin/elements_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,68 @@
module Alchemy
module Admin
module ElementsHelper
include Alchemy::ElementsHelper
include Alchemy::ElementsBlockHelper
include Alchemy::Admin::BaseHelper
include Alchemy::Admin::ContentsHelper
include Alchemy::Admin::EssencesHelper

# Renders the element editor partial
# Renders a {Alchemy::Element} editor partial.
#
# A element editor partial is the form presented to the content author in page edit mode.
#
# The partial is located in <tt>app/views/alchemy/elements</tt>.
#
# == Partial naming
#
# The partials have to be named after the name of the element as defined in the <tt>elements.yml</tt> file and has to be suffixed with <tt>_editor</tt>.
#
# === Example
#
# Given a headline element
#
# # elements.yml
# - name: headline
# contents:
# - name: text
# type: EssenceText
#
# Then your element editor partial has to be named:
#
# app/views/alchemy/elements/_headline_editor.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_editor(Alchemy::Element.published.named(:headline).first) %>
#
# @param [Alchemy::Element] element
# The element you want to render the editor for
#
# @note If the partial is not found
# <tt>alchemy/elements/_editor_not_found.html.erb</tt> gets rendered.
#
def render_editor(element)
render_element(element, :editor)
if element.nil?
warning('Element is nil')
render "alchemy/elements/editor_not_found", {name: 'nil'}
return
end

render "alchemy/elements/#{element.name}_editor", element: element
rescue ActionView::MissingTemplate => e
warning(%(
Element editor partial not found for #{element.name}.\n
#{e}
))
render "alchemy/elements/editor_not_found", {
name: element.name,
error: "Element editor partial not found.<br>Use <code>rails generate alchemy:elements</code> to generate it."
}
end

# Returns an elements array for select helper.
Expand Down
68 changes: 33 additions & 35 deletions app/helpers/alchemy/elements_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -96,37 +96,34 @@ def render_elements(options = {})
}.update(options)

if options[:sort_by]
Alchemy::Deprecation.warn "options[:sort_by] has been removed without replacement. " /
Alchemy::Deprecation.warn "options[:sort_by] has been removed without replacement. " \
"Please implement your own element sorting by passing a custom finder instance to options[:finder]."
end

if options[:from_cell]
Alchemy::Deprecation.warn "options[:from_cell] has been removed without replacement. " /
"Please `render element.nested_elements.published` instead."
Alchemy::Deprecation.warn "options[:from_cell] has been removed without replacement. " \
"Please `render element.nested_elements.available` instead."
end

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

buff = []
elements.each_with_index do |element, i|
buff << render_element(element, :view, options, i + 1)
buff << render_element(element, options, i + 1)
end
buff.join(options[:separator]).html_safe
end

# This helper renders a {Alchemy::Element} partial.
# This helper renders a {Alchemy::Element} view partial.
#
# A element has always two partials:
# A element view partial is the html snippet presented to the website visitor.
#
# 1. A view partial (This is the view presented to the website visitor)
# 2. A editor partial (This is the form presented to the website editor while in page edit mode)
#
# The partials are located in <tt>app/views/alchemy/elements</tt>.
# The partial is located in <tt>app/views/alchemy/elements</tt>.
#
# == View partial naming
#
# The partials have to be named after the name of the element as defined in the <tt>elements.yml</tt> file and has to be suffixed with the partial part.
# The partial has to be named after the name of the element as defined in the <tt>elements.yml</tt> file and has to be suffixed with <tt>_view</tt>.
#
# === Example
#
Expand All @@ -138,10 +135,9 @@ def render_elements(options = {})
# - name: text
# type: EssenceText
#
# Then your element view partials has to be named like:
# Then your element view partial has to be named like:
#
# app/views/alchemy/elements/_headline_editor.html.erb
# app/views/alchemy/elements/_headline_view.html.erb
# app/views/alchemy/elements/_headline_view.html.{erb|haml|slim}
#
# === Element partials generator
#
Expand All @@ -155,43 +151,45 @@ def render_elements(options = {})
#
# @param [Alchemy::Element] element
# The element you want to render the view for
# @param [Symbol] part
# The type of element partial (<tt>:editor</tt> or <tt>:view</tt>) you want to render
# @param [Hash] options
# Additional options
# @param [Number] counter
# a counter
#
# @note If the view partial is not found <tt>alchemy/elements/_view_not_found.html.erb</tt>
# or <tt>alchemy/elements/_editor_not_found.html.erb</tt> gets rendered.
# @note If the view partial is not found
# <tt>alchemy/elements/_view_not_found.html.erb</tt> gets rendered.
#
def render_element(element, part = :view, options = {}, counter = 1)
def render_element(*args)
if args.length == 4
element, _part, options, counter = *args
Alchemy::Deprecation.warn "passing a `part` parameter as second argument to `render_element` has been removed without replacement. " \
"You can safely remove it."
else
element, options, counter = *args
end

options ||= {}
counter ||= 1

if element.nil?
warning('Element is nil')
render "alchemy/elements/#{part}_not_found", {name: 'nil'}
render "alchemy/elements/view_not_found", {name: 'nil'}
return
end

element.store_page(@page) if part.to_sym == :view
element.store_page(@page)

render(
partial: "alchemy/elements/#{element.name}_#{part}",
object: element,
locals: {
element: element,
counter: counter,
options: options
}.merge(options.delete(:locals) || {})
)
render element, {
element: element,
counter: counter,
options: options
}.merge(options.delete(:locals) || {})
rescue ActionView::MissingTemplate => e
warning(%(
Element #{part} partial not found for #{element.name}.\n
Element view partial not found for #{element.name}.\n
#{e}
))
render "alchemy/elements/#{part}_not_found", {
name: element.name,
error: "Element #{part} partial not found.<br>Use <code>rails generate alchemy:elements</code> to generate it."
}
render "alchemy/elements/view_not_found", name: element.name
end

# Returns a string for the id attribute of a html element for the given element
Expand Down
4 changes: 2 additions & 2 deletions app/models/alchemy/page.rb
Original file line number Diff line number Diff line change
Expand Up @@ -312,8 +312,8 @@ def new_name_for_copy(custom_name, source_name)
# @return [ActiveRecord::Relation]
def find_elements(options = {}, show_non_public = false)
if show_non_public
Alchemy::Deprecation.warn "Passing true as second argument to page#find_elements to include" /
" invisible elements has been removed. Please implement your own ElementsFinder" /
Alchemy::Deprecation.warn "Passing true as second argument to page#find_elements to include" \
" invisible elements has been removed. Please implement your own ElementsFinder" \
" and pass it with options[:finder]."
end

Expand Down
2 changes: 1 addition & 1 deletion app/views/alchemy/elements/_editor_not_found.html.erb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<%= render_message :warning do %>
<h2><%= Alchemy.t(:element_editor_not_found) %>:</h2>
<p><%= error.html_safe %></p>
<p><%== local_assigns[:error] %></p>
<% end %>
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
<%= element_view_for(headline_view, tag: 'h1') do |el| %>
<%= el.render(:headline) %>
<%= local_assigns[:counter] -%>. <%= el.render(:headline) %>
<small><%= local_assigns[:some] -%></small>
<% end %>
30 changes: 26 additions & 4 deletions spec/helpers/alchemy/admin/elements_helper_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,32 @@ module Alchemy
let(:page) { build_stubbed(:alchemy_page, :public) }
let(:element) { build_stubbed(:alchemy_element, page: page) }

context "partial rendering" do
it "should render an element editor partial" do
expect(helper).to receive(:render_element).with(element, :editor)
helper.render_editor(element)
describe "#render_editor" do
subject { render_editor(element) }

context 'with nil element' do
let(:element) { nil }

it { is_expected.to be_nil }
end

context 'with element record given' do
let(:element) do
create(:alchemy_element, :with_contents, name: 'headline')
end

it "renders the element's editor partial" do
is_expected.to have_selector('div.content_editor > label', text: 'Headline')
end

context 'with element editor partial not found' do
let(:element) { build_stubbed(:alchemy_element, name: 'not_present') }

it "renders the editor not found partial" do
is_expected.to have_selector('div.warning')
is_expected.to have_content('Element editor partial not found')
end
end
end
end

Expand Down
71 changes: 57 additions & 14 deletions spec/helpers/alchemy/elements_helper_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,18 @@ module Alchemy
end

describe '#render_element' do
subject { render_element(element, part) }
subject { render_element(element) }

context 'with nil element' do
let(:element) { nil }
let(:part) { :view }

it { is_expected.to be_nil }
end

context 'with view as part given' do
let(:part) { :view }
context 'with element record given' do
let(:element) do
create(:alchemy_element, :with_contents, name: 'headline')
end

it "renders the element's view partial" do
is_expected.to have_selector("##{element.name}_#{element.id}")
Expand All @@ -38,22 +40,41 @@ module Alchemy
end
end

context 'with editor as part given' do
let(:part) { :editor }
context 'with options given' do
subject { render_element(element, locals: { some: 'thing' }) }

it "renders the element's editor partial" do
expect(helper).to receive(:render_essence_editor_by_name)
subject
it 'passes them into the view' do
is_expected.to match(/thing/)
end
end

context 'with element editor partial not found' do
let(:element) { build_stubbed(:alchemy_element, name: 'not_present') }
context 'with counter given' do
subject { render_element(element, {}, 2) }

it 'passes them into the view' do
is_expected.to match(/2\./)
end
end

it "renders the editor not found partial" do
is_expected.to have_selector('div.warning')
is_expected.to have_content('Element editor partial not found')
context 'with 4 arguments given' do
subject { render_element(element, :view, {locals: {some: 'thing'}}, 2) }

it 'passes options into the view' do
Alchemy::Deprecation.silence do
is_expected.to match(/thing/)
end
end

it 'passes counter into the view' do
Alchemy::Deprecation.silence do
is_expected.to match(/2\./)
end
end

it 'warns about removal of second parameter' do
expect(Alchemy::Deprecation).to receive(:warn)
subject
end
end
end

Expand Down Expand Up @@ -107,6 +128,28 @@ module Alchemy
end
end

context 'with sort_by option given' do
let(:options) do
{ sort_by: :name }
end

it 'warns about removal of sort_by option' do
expect(Alchemy::Deprecation).to receive(:warn)
subject
end
end

context 'with from_cell option given' do
let(:options) do
{ from_cell: :header }
end

it 'warns about removal of from_cell option' do
expect(Alchemy::Deprecation).to receive(:warn)
subject
end
end

context 'with option separator given' do
let(:options) { {separator: '<hr>'} }

Expand Down
9 changes: 9 additions & 0 deletions spec/models/alchemy/page_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1124,6 +1124,15 @@ module Alchemy
expect(subject.map(&:name)).to eq(['news'])
end
end

context 'with second argument set to true' do
subject { page.find_elements(options, true) }

it 'warns about removal of second argument' do
expect(Alchemy::Deprecation).to receive(:warn)
subject
end
end
end

describe '#first_public_child' do
Expand Down