Class: Alchemy::Element
- Inherits:
-
BaseRecord
- Object
- ActiveRecord::Base
- BaseRecord
- Alchemy::Element
- Includes:
- Definitions, ElementIngredients, Presenters, Publishable, Taggable
- Defined in:
- app/models/alchemy/element.rb,
app/models/alchemy/element/presenters.rb,
app/models/alchemy/element/definitions.rb,
app/models/alchemy/element/element_ingredients.rb
Defined Under Namespace
Modules: Definitions, ElementIngredients, Presenters
Constant Summary collapse
- NAME_REGEXP =
/\A[a-z0-9_-]+\z/- FORBIDDEN_DEFINITION_ATTRIBUTES =
[ "amount", "autogenerate", "compact", "deprecated", "hint", "icon", "ingredients", "message", "nestable_elements", "searchable", "taggable", "warning" ].freeze
Constants included from SearchableResource
SearchableResource::SEARCHABLE_COLUMN_TYPES
Instance Attribute Summary collapse
-
#autogenerate_nested_elements ⇒ Object
Returns the value of attribute autogenerate_nested_elements.
-
#skip_ingredient_validations ⇒ Object
Returns the value of attribute skip_ingredient_validations.
Class Method Summary collapse
- .all_from_clipboard(clipboard) ⇒ Object
-
.all_from_clipboard_for_page(clipboard, page) ⇒ Object
All elements in clipboard that could be placed on page.
-
.all_from_clipboard_for_parent_element(clipboard, parent_element) ⇒ Object
All elements in clipboard that could be placed as a child of ‘parent_element`.
-
.copy(source_element, differences = {}) ⇒ Object
This methods does a copy of source and all its ingredients.
-
.new(attributes = {}) ⇒ Object
Builds a new element as described in
/config/alchemy/elements.yml.
Instance Method Summary collapse
-
#compact? ⇒ Boolean
Defined as compact element?.
-
#deprecated? ⇒ Boolean
Defined as deprecated element?.
-
#expanded? ⇒ Boolean
The opposite of folded?.
-
#folded_parent_element_ids ⇒ Array<Integer>
Returns IDs of all folded parent elements from immediate parent up to root.
-
#nestable_elements ⇒ Object
A collection of element names that can be nested inside this element.
-
#next(name = nil) ⇒ Object
Returns next public element from same page.
-
#prev(name = nil) ⇒ Object
Returns previous public element from same page.
-
#public=(value) ⇒ Object
Convenience setter to set public_on attribute when setting public to true or false.
-
#public_on=(value) ⇒ Object
Override setter to track if public_on was already set in order to not override it with default value if someone explicitly set it to nil.
-
#store_page(page) ⇒ Object
Stores the page into
touchable_pages(Pages that have to be touched after updating the element). -
#taggable? ⇒ Boolean
Returns true if the definition of this element has a taggable true value.
-
#to_partial_path ⇒ Object
The element’s view partial is dependent from its name.
Methods included from Presenters
#display_name, #display_name_with_preview_text, #preview_ingredient, #preview_text
Methods included from ElementIngredients
#copy_ingredients_to, #has_validations?, #has_value_for?, #ingredient_by_role, #ingredient_by_type, #ingredient_definition_for, #ingredient_definitions, #ingredients_by_type, #ingredients_with_errors, #richtext_ingredients_ids, #value_for
Methods included from Definitions
Methods included from Publishable
#already_public_for?, #public?, #publishable?, #scheduled?, #still_public_for?
Methods included from Taggable
Methods included from ConfigMissing
Methods included from SearchableResource
#ransackable_associations, #ransackable_attributes, #ransackable_scopes, #ransortable_attributes
Instance Attribute Details
#autogenerate_nested_elements ⇒ Object
Returns the value of attribute autogenerate_nested_elements.
105 106 107 |
# File 'app/models/alchemy/element.rb', line 105 def autogenerate_nested_elements @autogenerate_nested_elements end |
#skip_ingredient_validations ⇒ Object
Returns the value of attribute skip_ingredient_validations.
40 41 42 |
# File 'app/models/alchemy/element.rb', line 40 def skip_ingredient_validations @skip_ingredient_validations end |
Class Method Details
.all_from_clipboard(clipboard) ⇒ Object
167 168 169 170 171 |
# File 'app/models/alchemy/element.rb', line 167 def all_from_clipboard(clipboard) return none if clipboard.nil? where(id: clipboard.collect { |e| e["id"] }) end |
.all_from_clipboard_for_page(clipboard, page) ⇒ Object
All elements in clipboard that could be placed on page
175 176 177 178 179 |
# File 'app/models/alchemy/element.rb', line 175 def all_from_clipboard_for_page(clipboard, page) return none if clipboard.nil? || page.nil? all_from_clipboard(clipboard).where(name: page.available_element_names) end |
.all_from_clipboard_for_parent_element(clipboard, parent_element) ⇒ Object
All elements in clipboard that could be placed as a child of ‘parent_element`
182 183 184 185 186 |
# File 'app/models/alchemy/element.rb', line 182 def all_from_clipboard_for_parent_element(clipboard, parent_element) return none if clipboard.nil? || parent_element.nil? all_from_clipboard(clipboard).where(name: parent_element.definition.nestable_elements) end |
.copy(source_element, differences = {}) ⇒ Object
163 164 165 |
# File 'app/models/alchemy/element.rb', line 163 def copy(source_element, differences = {}) Alchemy::DuplicateElement.new(source_element).call(differences) end |
.new(attributes = {}) ⇒ Object
Builds a new element as described in /config/alchemy/elements.yml
-
Returns a new Alchemy::Element object if no name is given in attributes, because the definition can not be found w/o name
-
Raises Alchemy::ElementDefinitionError if no definition for given attributes could be found
140 141 142 143 144 145 146 147 148 149 150 |
# File 'app/models/alchemy/element.rb', line 140 def new(attributes = {}) return super if attributes[:name].blank? element_attributes = attributes.to_h.merge(name: attributes[:name].split("#").first) element_definition = Element.definition_by_name(element_attributes[:name]) if element_definition.nil? raise(ElementDefinitionError, attributes) end super(element_definition.attributes.merge(element_attributes).except(*FORBIDDEN_DEFINITION_ATTRIBUTES)) end |
Instance Method Details
#compact? ⇒ Boolean
Defined as compact element?
266 267 268 |
# File 'app/models/alchemy/element.rb', line 266 def compact? definition.compact end |
#deprecated? ⇒ Boolean
Defined as deprecated element?
You can either set true or a String on your elements definition.
Passing true
- name: old_element
deprecated: true
The deprecation notice can be translated. Either as global notice for all deprecated elements.
en:
alchemy:
element_deprecation_notice: Foo baz widget is deprecated
Or add a translation to your locale file for a per element notice.
en:
alchemy:
element_deprecation_notices:
old_element: Foo baz widget is deprecated
Pass a String
- name: old_element
deprecated: This element will be removed soon.
298 299 300 |
# File 'app/models/alchemy/element.rb', line 298 def deprecated? !!definition.deprecated end |
#expanded? ⇒ Boolean
The opposite of folded?
261 262 263 |
# File 'app/models/alchemy/element.rb', line 261 def !folded? end |
#folded_parent_element_ids ⇒ Array<Integer>
Returns IDs of all folded parent elements from immediate parent up to root
Walks up the ancestor chain and collects only the ones that are folded, skipping already expanded parents.
195 196 197 198 199 200 201 202 203 204 205 206 |
# File 'app/models/alchemy/element.rb', line 195 def folded_parent_element_ids return [] unless parent_element_id ids = [] current_id = parent_element_id while current_id folded, parent_id = self.class.where(id: current_id).pick(:folded, :parent_element_id) ids << current_id if folded current_id = parent_id end ids end |
#nestable_elements ⇒ Object
A collection of element names that can be nested inside this element.
321 322 323 |
# File 'app/models/alchemy/element.rb', line 321 def nestable_elements definition.nestable_elements end |
#next(name = nil) ⇒ Object
Returns next public element from same page.
Pass an element name to get next of this kind.
212 213 214 215 |
# File 'app/models/alchemy/element.rb', line 212 def next(name = nil) elements = page.elements.published.where("position > ?", position) select_element(elements, name, :asc) end |
#prev(name = nil) ⇒ Object
Returns previous public element from same page.
Pass an element name to get previous of this kind.
221 222 223 224 |
# File 'app/models/alchemy/element.rb', line 221 def prev(name = nil) elements = page.elements.published.where("position < ?", position) select_element(elements, name, :desc) end |
#public=(value) ⇒ Object
Convenience setter to set public_on attribute when setting public to true or false.
237 238 239 240 241 242 243 244 245 |
# File 'app/models/alchemy/element.rb', line 237 def public=(value) @public_on_explicitely_set = true if ActiveModel::Type::Boolean.new.cast(value) self.public_on = Time.current self.public_until = nil else self.public_until = Time.current end end |
#public_on=(value) ⇒ Object
Override setter to track if public_on was already set in order to not override it with default value if someone explicitly set it to nil.
250 251 252 253 |
# File 'app/models/alchemy/element.rb', line 250 def public_on=(value) @public_on_explicitely_set = true super end |
#store_page(page) ⇒ Object
Stores the page into touchable_pages (Pages that have to be touched after updating the element).
227 228 229 230 231 232 233 |
# File 'app/models/alchemy/element.rb', line 227 def store_page(page) return true if page.nil? unless touchable_pages.include? page touchable_pages << page end end |
#taggable? ⇒ Boolean
Returns true if the definition of this element has a taggable true value.
256 257 258 |
# File 'app/models/alchemy/element.rb', line 256 def taggable? definition.taggable == true end |
#to_partial_path ⇒ Object
The element’s view partial is dependent from its name
Define elements
Elements are defined in the config/alchemy/elements.yml file
- name: article
ingredients:
...
Override the view
Element partials live in app/views/alchemy/elements
316 317 318 |
# File 'app/models/alchemy/element.rb', line 316 def to_partial_path "alchemy/elements/#{name}" end |