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.
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?, #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.
102 103 104 |
# File 'app/models/alchemy/element.rb', line 102 def autogenerate_nested_elements @autogenerate_nested_elements end |
Class Method Details
.all_from_clipboard(clipboard) ⇒ Object
164 165 166 167 168 |
# File 'app/models/alchemy/element.rb', line 164 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
172 173 174 175 176 |
# File 'app/models/alchemy/element.rb', line 172 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
179 180 181 182 183 |
# File 'app/models/alchemy/element.rb', line 179 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
This methods does a copy of source and all its ingredients.
Options
You can pass a differences Hash as second option to update attributes for the copy.
Example
@copy = Alchemy::Element.copy(@element, {public: false})
@copy.public? # => false
160 161 162 |
# File 'app/models/alchemy/element.rb', line 160 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
137 138 139 140 141 142 143 144 145 146 147 |
# File 'app/models/alchemy/element.rb', line 137 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?
263 264 265 |
# File 'app/models/alchemy/element.rb', line 263 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 is deprecated
Or add a translation to your locale file for a per element notice.
en:
alchemy:
element_deprecation_notices:
old_element: Foo baz is deprecated
Pass a String
- name: old_element
deprecated: This element will be removed soon.
295 296 297 |
# File 'app/models/alchemy/element.rb', line 295 def deprecated? !!definition.deprecated end |
#expanded? ⇒ Boolean
The opposite of folded?
258 259 260 |
# File 'app/models/alchemy/element.rb', line 258 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.
192 193 194 195 196 197 198 199 200 201 202 203 |
# File 'app/models/alchemy/element.rb', line 192 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.
318 319 320 |
# File 'app/models/alchemy/element.rb', line 318 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.
209 210 211 212 |
# File 'app/models/alchemy/element.rb', line 209 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.
218 219 220 221 |
# File 'app/models/alchemy/element.rb', line 218 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.
234 235 236 237 238 239 240 241 242 |
# File 'app/models/alchemy/element.rb', line 234 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.
247 248 249 250 |
# File 'app/models/alchemy/element.rb', line 247 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).
224 225 226 227 228 229 230 |
# File 'app/models/alchemy/element.rb', line 224 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.
253 254 255 |
# File 'app/models/alchemy/element.rb', line 253 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
313 314 315 |
# File 'app/models/alchemy/element.rb', line 313 def to_partial_path "alchemy/elements/#{name}" end |