app/models/alchemy/page/page_elements.rb in alchemy_cms-3.2.1 vs app/models/alchemy/page/page_elements.rb in alchemy_cms-3.3.0.rc1
- old
+ new
@@ -1,52 +1,104 @@
module Alchemy
module Page::PageElements
-
extend ActiveSupport::Concern
included do
attr_accessor :do_not_autogenerate
- has_many :elements, -> { order(:position) }
- has_many :contents, :through => :elements
- has_and_belongs_to_many :to_be_sweeped_elements, -> { uniq },
+ has_many :elements, -> { where(parent_element_id: nil).not_trashed.order(:position) }
+ has_many :trashed_elements,
+ -> { Element.trashed.order(:position) },
+ class_name: 'Alchemy::Element'
+ has_many :descendent_elements,
+ -> { order(:position).not_trashed },
+ class_name: 'Alchemy::Element'
+ has_many :contents, through: :elements
+ has_many :descendent_contents,
+ through: :descendent_elements,
+ class_name: 'Alchemy::Content',
+ source: :contents
+ has_and_belongs_to_many :to_be_swept_elements, -> { uniq },
class_name: 'Alchemy::Element',
join_table: ElementToPage.table_name
- after_create :autogenerate_elements, :unless => proc { systempage? || do_not_autogenerate }
- after_update :trash_not_allowed_elements, :if => :page_layout_changed?
- after_update :autogenerate_elements, :if => :page_layout_changed?
- after_destroy { elements.each { |el| el.destroy unless el.trashed? } }
+ after_create :autogenerate_elements, unless: -> { systempage? || do_not_autogenerate }
+ after_update :trash_not_allowed_elements!, if: :page_layout_changed?
+ after_update :autogenerate_elements, if: :page_layout_changed?
+
+ after_destroy do
+ elements.each do |element|
+ next if element.trashed?
+ element.destroy
+ end
+ end
end
module ClassMethods
-
# Copy page elements
#
# @param source [Alchemy::Page]
# @param target [Alchemy::Page]
# @return [Array]
#
def copy_elements(source, target)
new_elements = []
- source.elements.not_trashed.each do |element|
- # detect cell for element
- if element.cell
- cell = target.cells.detect { |c| c.name == element.cell.name }
- else
- cell = nil
+ source.elements.not_trashed.each do |source_element|
+ cell = nil
+ if source_element.cell
+ cell = target.cells.find_by(name: source_element.cell.name)
end
- # if cell is nil also pass nil to element.cell_id
- new_element = Element.copy(element, :page_id => target.id, :cell_id => (cell.blank? ? nil : cell.id))
- # move element to bottom of the list
+ new_element = Element.copy source_element, {
+ page_id: target.id,
+ cell_id: cell.try(:id)
+ }
new_element.move_to_bottom
new_elements << new_element
end
new_elements
end
+ end
+ # Finds elements of page.
+ #
+ # @param [Hash]
+ # options hash
+ # @param [Boolean] (false)
+ # Pass true, if you want to also have not published elements.
+ #
+ # @option options [Array] only
+ # Returns only elements with given names
+ # @option options [Array] except
+ # Returns all elements except the ones with given names
+ # @option options [Fixnum] count
+ # Limit the count of returned elements
+ # @option options [Fixnum] offset
+ # Starts with an offset while returning elements
+ # @option options [Boolean] random (false)
+ # Return elements randomly shuffled
+ # @option options [Alchemy::Cell || String] from_cell
+ # Return elements from given cell
+ #
+ # @return [ActiveRecord::Relation]
+ #
+ def find_elements(options = {}, show_non_public = false)
+ elements = elements_from_cell_or_self(options[:from_cell])
+ if options[:only].present?
+ elements = elements.named(options[:only])
+ elsif options[:except].present?
+ elements = elements.excluded(options[:except])
+ end
+ if options[:reverse_sort] || options[:reverse]
+ elements = elements.reverse_order
+ end
+ elements = elements.offset(options[:offset]).limit(options[:count])
+ if options[:random]
+ elements = elements.order("RAND()")
+ end
+ show_non_public ? elements : elements.published
end
+ alias_method :find_selected_elements, :find_elements
# All available element definitions that can actually be placed on current page.
#
# It extracts all definitions that are unique or limited and already on page.
#
@@ -64,29 +116,40 @@
# amount: 2
# contents:
# - name: text
# type: EssenceRichtext
#
- def available_element_definitions
- @elements_for_layout ||= element_definitions
- return [] if @elements_for_layout.blank?
- @page_element_names = elements.not_trashed.pluck(:name)
+ def available_element_definitions(only_element_named = nil)
+ @_element_definitions ||= if only_element_named
+ definition = Element.definition_by_name(only_element_named)
+ element_definitions_by_name(definition['nestable_elements'])
+ else
+ element_definitions
+ end
+
+ return [] if @_element_definitions.blank?
+
+ @_existing_element_names = elements.not_trashed.pluck(:name)
delete_unique_element_definitions!
delete_outnumbered_element_definitions!
- @elements_for_layout
+
+ @_element_definitions
end
# All names of elements that can actually be placed on current page.
#
def available_element_names
- available_element_definitions.collect { |e| e['name'] }
+ @_available_element_names ||= available_element_definitions.map { |e| e['name'] }
end
# All element definitions defined for page's page layout
#
+ # Warning: Since elements can be unique or limited in number,
+ # it is more safe to ask for +available_element_definitions+
+ #
def element_definitions
- element_definitions_by_name(element_definition_names)
+ @_element_definitions ||= element_definitions_by_name(element_definition_names)
end
# All names of elements that are defined in the corresponding
# page and cell definition.
#
@@ -103,147 +166,115 @@
#
# - name: right_column
# elements: [teaser]
#
def element_definition_names
- element_names_from_page_definition | element_names_from_cell_definition
+ element_names_from_definition | element_names_from_cell_definitions
end
- def element_names_from_page_definition
- definition['elements'] || []
- end
-
- def element_names_from_cell_definition
- cell_definitions.map { |d| d['elements'] }.flatten
- end
-
- # Returns Element definitions with given name(s)
+ # Element definitions with given name(s)
#
# @param [Array || String]
# one or many Alchemy::Element names. Pass +'all'+ to get all Element definitions
# @return [Array]
# An Array of element definitions
#
def element_definitions_by_name(names)
return [] if names.blank?
+
if names.to_s == "all"
Element.definitions
else
Element.definitions.select { |e| names.include? e['name'] }
end
end
- # Finds elements of page.
- #
- # @param [Hash]
- # options hash
- # @param [Boolean] (false)
- # Pass true, if you want to also have not published elements.
- #
- # @option options [Array] only
- # Returns only elements with given names
- # @option options [Array] except
- # Returns all elements except the ones with given names
- # @option options [Fixnum] count
- # Limit the count of returned elements
- # @option options [Fixnum] offset
- # Starts with an offset while returning elements
- # @option options [Boolean] random (false)
- # Return elements randomly shuffled
- # @option options [Alchemy::Cell || String] from_cell
- # Return elements from given cell
- #
- # @return [ActiveRecord::Relation]
- #
- def find_elements(options = {}, show_non_public = false)
- elements = elements_from_cell_or_self(options[:from_cell])
- if options[:only].present?
- elements = elements.named(options[:only])
- elsif options[:except].present?
- elements = elements.excluded(options[:except])
- end
- if options[:reverse_sort] || options[:reverse]
- elements = elements.reverse_order
- end
- elements = elements.offset(options[:offset]).limit(options[:count])
- if options[:random]
- elements = elements.order("RAND()")
- end
- show_non_public ? elements : elements.published
- end
- alias_method :find_selected_elements, :find_elements
-
# Returns all elements that should be feeded via rss.
#
# Define feedable elements in your +page_layouts.yml+:
#
# - name: news
# feed: true
# feed_elements: [element_name, element_2_name]
#
def feed_elements
- elements.named(definition['feed_elements'])
+ elements.available.named(definition['feed_elements'])
end
- # Returns an array of all EssenceRichtext contents ids
+ # Returns an array of all EssenceRichtext contents ids from not folded elements
#
def richtext_contents_ids
- contents.essence_richtexts.pluck("#{Content.table_name}.id")
+ descendent_contents
+ .where(Element.table_name => {folded: false})
+ .select(&:has_tinymce?)
+ .collect(&:id)
end
+ def element_names_from_definition
+ definition['elements'] || []
+ end
+
private
+ def element_names_from_cell_definitions
+ @_element_names_from_cell_definitions ||= cell_definitions.map do |d|
+ d['elements']
+ end.flatten
+ end
+
# Looks in the page_layout descripion, if there are elements to autogenerate.
#
# And if so, it generates them.
#
# If the page has cells, it looks if there are elements to generate.
#
def autogenerate_elements
- elements_already_on_page = self.elements.available.pluck(:name)
- elements = self.layout_description["autogenerate"]
+ elements_already_on_page = elements.available.pluck(:name)
+ elements = definition["autogenerate"]
if elements.present?
elements.each do |element|
next if elements_already_on_page.include?(element)
Element.create_from_scratch(attributes_for_element_name(element))
end
end
end
# Returns a hash of attributes for given element name
def attributes_for_element_name(element)
- if self.has_cells? && (cell_definition = cell_definitions.detect { |c| c['elements'].include?(element) })
- cell = self.cells.find_by_name(cell_definition['name'])
- if cell
- return {:page_id => self.id, :cell_id => cell.id, :name => element}
- else
- raise "Cell not found for page #{self.inspect}"
- end
+ element_cell_definition = cell_definitions.detect { |c| c['elements'].include?(element) }
+ if has_cells? && element_cell_definition
+ cell = cells.find_by!(name: element_cell_definition['name'])
+ {page_id: id, cell_id: cell.id, name: element}
else
- return {:page_id => self.id, :name => element}
+ {page_id: id, name: element}
end
end
# Trashes all elements that are not allowed for this page_layout.
- def trash_not_allowed_elements
- elements.select { |e| !definition['elements'].include?(e.name) }.map(&:trash!)
+ def trash_not_allowed_elements!
+ not_allowed_elements = elements.where([
+ "#{Element.table_name}.name NOT IN (?)",
+ element_names_from_definition
+ ])
+ not_allowed_elements.to_a.map(&:trash!)
end
- # Deletes unique and already present definitions from @elements_for_layout.
+ # Deletes unique and already present definitions from @_element_definitions.
#
def delete_unique_element_definitions!
- @elements_for_layout.delete_if { |element|
- element['unique'] && @page_element_names.include?(element['name'])
- }
+ @_element_definitions.delete_if do |element|
+ element['unique'] && @_existing_element_names.include?(element['name'])
+ end
end
- # Deletes limited and outnumbered definitions from @elements_for_layout.
+ # Deletes limited and outnumbered definitions from @_element_definitions.
#
def delete_outnumbered_element_definitions!
- @elements_for_layout.delete_if { |element|
- element['amount'] && @page_element_names.select { |i| i == element['name'] }.count >= element['amount'].to_i
- }
+ @_element_definitions.delete_if do |element|
+ outnumbered = @_existing_element_names.select { |name| name == element['name'] }
+ element['amount'] && outnumbered.count >= element['amount'].to_i
+ end
end
# Returns elements either from given cell or self
#
def elements_from_cell_or_self(cell)
@@ -251,11 +282,11 @@
when 'Alchemy::Cell'
cell.elements
when 'String'
cell_elements_by_name(cell)
else
- self.elements.not_in_cell
+ elements.not_in_cell
end
end
# Returns all elements from given cell name
#
@@ -265,8 +296,7 @@
else
Alchemy::Logger.warn("Cell with name `#{name}` could not be found!", caller.first)
Element.none
end
end
-
end
end