app/decorators/alchemy/ingredient_editor.rb
# frozen_string_literal: true
module Alchemy
class IngredientEditor < SimpleDelegator
alias_method :ingredient, :__getobj__
def to_partial_path
"alchemy/ingredients/#{partial_name}_editor"
end
# Returns the translated role for displaying in labels
#
# Translate it in your locale yml file:
#
# alchemy:
# ingredient_roles:
# foo: Bar
#
# Optionally you can scope your ingredient role to an element:
#
# alchemy:
# ingredient_roles:
# article:
# foo: Baz
#
def translated_role
Alchemy.t(
role,
scope: "ingredient_roles.#{element.name}",
default: Alchemy.t("ingredient_roles.#{role}", default: role.humanize)
)
end
def css_classes
[
"ingredient-editor",
partial_name,
deprecated? ? "deprecated" : nil,
(respond_to?(:level_options) && level_options.any?) ? "with-level-select" : nil,
(respond_to?(:size_options) && size_options.many?) ? "with-size-select" : nil,
settings[:linkable] ? "linkable" : nil,
settings[:anchor] ? "with-anchor" : nil
].compact
end
def data_attributes
{
ingredient_id: id,
ingredient_role: role
}
end
# Returns a string to be passed to Rails form field tags to ensure it can be used with Rails' nested attributes.
#
# === Example:
#
# <%= text_field_tag text_editor.form_field_name, text_editor.value %>
#
# === Options:
#
# You can pass an Ingredient column_name. Default is 'value'
#
# ==== Example:
#
# <%= text_field_tag text_editor.form_field_name(:link), text_editor.value %>
#
def form_field_name(column = "value")
"element[ingredients_attributes][#{form_field_counter}][#{column}]"
end
# Returns a unique string to be passed to a form field id.
#
# @param column [String] A Ingredient column_name. Default is 'value'
#
def form_field_id(column = "value")
"element_#{element.id}_ingredient_#{id}_#{column}"
end
# Fixes Rails partial renderer calling to_model on the object
# which reveals the delegated ingredient instead of this decorator.
def respond_to?(method_name)
return false if method_name == :to_model
super
end
def has_warnings?
definition.blank? || deprecated?
end
def linked?
link.try(:present?)
end
def warnings
return unless has_warnings?
if definition.blank?
Logger.warn("ingredient #{role} is missing its definition", caller(1..1))
Alchemy.t(:ingredient_definition_missing)
else
deprecation_notice
end
end
# Returns a deprecation notice for ingredients marked deprecated
#
# You can either use localizations or pass a String as notice
# in the ingredient definition.
#
# == Custom deprecation notices
#
# Use general ingredient deprecation notice
#
# - name: element_name
# ingredients:
# - role: old_ingredient
# type: Text
# deprecated: true
#
# Add a translation to your locale file for a per ingredient notice.
#
# en:
# alchemy:
# ingredient_deprecation_notices:
# element_name:
# old_ingredient: Foo baz widget is deprecated
#
# or use the global translation that apply to all deprecated ingredients.
#
# en:
# alchemy:
# ingredient_deprecation_notice: Foo baz widget is deprecated
#
# or pass string as deprecation notice.
#
# - name: element_name
# ingredients:
# - role: old_ingredient
# type: Text
# deprecated: This ingredient will be removed soon.
#
def deprecation_notice
case definition[:deprecated]
when String
definition[:deprecated]
when TrueClass
Alchemy.t(
role,
scope: [:ingredient_deprecation_notices, element.name],
default: Alchemy.t(:ingredient_deprecated)
)
end
end
private
def form_field_counter
element.definition.fetch(:ingredients, []).index { |i| i[:role] == role }
end
end
end