# encoding: UTF-8 module Spontaneous::Model::Core module Aliases extend Spontaneous::Concern module ClassMethods def alias_of(*args) options_list, class_list = args.partition { |e| e.is_a?(Hash) } @alias_options = options_list.first || {} @alias_classes = class_list extend ClassAliasMethods include AliasMethods include PieceAliasMethods unless page? include PageAliasMethods if page? # alias_method :target, :__target alias_method :target=, :__target= end alias_method :aliases, :alias_of def targets(owner = nil, box = nil, options = {}) targets = [] classes = [] proc_args = [owner, box].compact @alias_classes.each do |source| case source when Proc targets.concat(source[*proc_args]) else type = source.to_s.constantize classes.push(type) classes.concat(type.subclasses) end end query = content_model.filter(:type_sid => classes.map { |c| c.schema_id }) if (container_procs = @alias_options[:container]) containers = [container_procs].flatten.map { |p| p[*proc_args] }.flatten params = [] containers.each do |container| if container.is_page? params << Sequel::SQL::BooleanExpression.new(:'=', :page_id, container.id) else box_params = [ [:box_sid, container.schema_id], [:owner_id, container.owner.id] ] params << Sequel::SQL::BooleanExpression.from_value_pairs(box_params, :AND) end end container_query = params[1..-1].inject(params.first) { |q, expr| q = q | expr; q } query = query.and(container_query) end targets.concat(query.all) if (filter = @alias_options[:filter]) and filter.is_a?(Proc) filtered = [] targets.each { |target| filtered << target if filter[*([target, owner, box][0...(filter.arity)])] } targets = filtered end if @alias_options[:unique] && box existing = box.map { |entry| entry.target || entry } targets.reject! { |target| existing.include?(target) } end if (query = options[:search]) targets.select! { |target| query === target.alias_title } end targets end def target_class(class_definition) end def alias? false end end # ClassMethods module ClassAliasMethods def for_target(target_id) self.create(:target_id => target_id) end def alias? true end def use_configured_generator(generator_name, *args) return nil unless @alias_options.key?(generator_name) (generator = @alias_options[generator_name]).call(*args) end def lookup_target(target_id) use_configured_generator(:lookup, target_id) end def target_slug(target) use_configured_generator(:slug, target) end end # included only in instances that are aliases module AliasMethods def alias? true end def target (_target = self.class.lookup_target(self.target_id)) and return _target __target end def field?(field_name) super || target.class.field?(field_name) end def respond_to_missing?(name, include_private = false) return true if target && target.respond_to?(name) super end def respond_to?(name, include_private = false) return true if target && target.respond_to?(name) super end def method_missing(method, *args) if target && target.respond_to?(method) if block_given? target.__send__(method, *args, &Proc.new) else target.__send__(method, *args) end else super end end def find_named_style(style_name) super or target.find_named_style(style_name) end def style return self.resolve_style(self.style_sid) unless target.respond_to?(:resolve_style) if self.class.styles.empty? target.resolve_style(style_sid) else self.resolve_style(self.style_sid) or target.resolve_style(self.style_sid) end end def styles @styles ||= Spontaneous::Collections::PrototypeSet.new(target, :styles) end def export(user = nil) super.merge(:target => exported_target(user), :alias_title => target.alias_title, :alias_icon => target.exported_alias_icon) end def exported_target(user = nil) case target when Spontaneous::Content target.shallow_export(user) else target.to_json end end def hidden? super || target.nil? || (target.respond_to?(:hidden?) && target.hidden?) end end module PieceAliasMethods def path target.path end end module PageAliasMethods def slug unless target.respond_to?(:slug) slug = self.class.target_slug(target) and return slug end target.slug end def layout # if this alias class has no layouts defined, then just use the one set on the target if self.class.layouts.empty? target.resolve_layout(self.style_sid) else # but if it does have layouts defined, use them self.resolve_layout(self.style_sid) or target.resolve_layout(self.style_sid) end end def find_named_layout(layout_name) super or target.find_named_layout(layout_name) end end # InstanceMethods def alias_title fields[:title].to_s end def alias_icon_field if field = fields.detect { |f| f.image? } field else nil end end def exported_alias_icon return nil unless alias_icon_field alias_icon_field.export end end end