# frozen_string_literal: true class Comfy::Cms::Layout < ActiveRecord::Base self.table_name = "comfy_cms_layouts" cms_acts_as_tree cms_has_revisions_for :content, :css, :js # -- Relationships -------------------------------------------------------- belongs_to :site has_many :pages, dependent: :nullify # -- Callbacks --------------------------------------------------------------- before_validation :assign_label before_create :assign_position after_save :clear_page_content_cache after_destroy :clear_page_content_cache # -- Validations ------------------------------------------------------------- validates :site_id, presence: true validates :label, presence: true validates :identifier, presence: true, uniqueness: { scope: :site_id }, format: { with: %r{\A\w[a-z0-9_-]*\z}i } # -- Class Methods ----------------------------------------------------------- # Tree-like structure for layouts def self.options_for_select(site, current_layout = nil) options = [] options_for_layout = ->(layout, depth = 0) do return if layout == current_layout options << ["#{'. . ' * depth}#{layout.label}", layout.id] layout.children.order(:position).each do |child_layout| options_for_layout.call(child_layout, depth + 1) end end site.layouts.roots.order(:position).each do |layout| options_for_layout.call(layout) end options end # List of available application layouts def self.app_layouts_for_select(view_paths) view_paths.map(&:to_s).select { |path| path.start_with?(Rails.root.to_s) }.flat_map do |full_path| Dir.glob("#{full_path}/layouts/**/*.html.*").collect do |filename| filename.gsub!("#{full_path}/layouts/", "") filename.split("/").last[0...1] == "_" ? nil : filename.split(".").first end.compact.sort end.compact.uniq.sort end # -- Instance Methods -------------------------------------------------------- # Tokenized layout content that also pulls in parent layout (if there's one) # and merges on the {{cms:tag_type content}} tag (if parent layout has that). # Returns a list of tokens that can be fed into the renderer. def content_tokens renderer = ComfortableMexicanSofa::Content::Renderer.new(nil) tokens = renderer.tokenize(content) if parent fragment_tags = ComfortableMexicanSofa::Content::Tag::Fragment.subclasses.map do |c| ComfortableMexicanSofa::Content::Renderer.tags.key(c) end parent_tokens = parent.content_tokens replacement_position = parent_tokens.index do |n| n.is_a?(Hash) && fragment_tags.member?(n[:tag_class]) && n[:tag_params].split(%r{\s}).first == "content" end if replacement_position parent_tokens[replacement_position] = tokens tokens = parent_tokens.flatten end end tokens end def cache_buster updated_at.to_i end # Forcing page content reload def clear_page_content_cache Comfy::Cms::Page.where(id: pages.pluck(:id)).update_all(content_cache: nil) children.each(&:clear_page_content_cache) end protected def assign_label self.label = label.blank? ? identifier.try(:titleize) : label end def assign_position return if position.to_i.positive? max = site.layouts.where(parent_id: parent_id).maximum(:position) self.position = max ? max + 1 : 0 end end