module Ecoportal module API class V2 class Page class Section < Common::Content::DoubleModel INITIAL_WEIGHT = 9999 class << self def new_doc(split: false) { "id" => new_uuid, "type" => split ? "split" : "content", "weight" => INITIAL_WEIGHT }.tap do |out| component_ids = if split { "left_component_ids" => [], "right_component_ids" => [] } else { "component_ids" => [] } end out.merge!(component_ids) end end end passkey :id passforced :patch_ver, default: 1 passthrough :weight, :type passthrough :heading, :left_heading, :right_heading passarray :component_ids, :left_component_ids, :right_component_ids passboolean :minimized def ooze self._parent.ooze end # @return [Array] the stage(s) this section belongs to. def stages ooze.stages.select {|stg| stg.section?(self)} end # @return [Boolean] whether or not the section appears in an ooze instance def attached? !ooze.stages? || stages.any? {|stg| stg.section?(self)} end # @return [Boolean] whether or not this section is a split section def split? doc && doc["type"] == "split" end # @return [Array] all the `ids` of the components/fields in this section def all_component_ids return component_ids.to_a unless split? left_component_ids.to_a | right_component_ids.to_a end # @raise [ArgumentError] if `com_or_id` is not of any of the allowed types # @param com_or_id [Ecoportal::API::V2::Page::Component, String] Component or `id` thereof # @return [Boolean] whether or not a component/field belongs to this section. def component?(com_or_id) case com_or_id when Ecoportal::API::V2::Page::Component component?(com_or_id.id) when String all_component_ids.include?(com_or_id) else msg = "Missuse: com_or_id should be a Component or a String. Given: #{com_or_id.class}" raise ArgumentError.new(msg) end end # It looks up the components that belong to this section. # @return [Array] def components(side: nil) case side when :right components_right when :left components_left when NilClass components_by_id(*all_component_ids) else raise "Side should be one of [nil, :right, :left]. Given: #{side}" end end # It looks up the components that belong to the `left` side of this section. # @raise [Exception] if this is not a `split` section # @return [Array] def components_left raise "You are trying to retrieve side components in a Split Section" unless split? components_by_id(*left_component_ids) end # It looks up the components that belong to the `right` side of this section. # @raise [Exception] if this is not a `split` section # @return [Array] def components_right raise "You are trying to retrieve side components in a Split Section" unless split? components_by_id(*right_component_ids) end # Adds `field` to the section # @note # - To the specified `side`, when split section (default `:left`) # - To the end if `after` is not specified # - If `after` is specified, it searches field # - On the specific `side`, if specified (and split section) # - And adds the `field` after it, when found, or at the end if `after` is not found # @raise [ArgumentError] if `field` is not a Component # @raise [Exception] if the field does not belong to ooze.components # @raise [Exception] if the field belongs to another section # @param field [Ecoportal::API::V2::Page::Component] the field to be added. def add_component(field, before: nil, after: nil, side: nil) unless field.is_a?(Ecoportal::API::V2::Page::Component) msg = "Expected Ecoportal::API::V2::Page::Component. Given: #{field.class}" raise ArgumentError.new(msg) end unless ooze.components.include?(field) msg = "The field '#{field.label}' (#{field.id}) is not present in ooze.components.\n" msg += "Review your script (i.e. @var where you store previous ooze runs)." raise msg end # IMPORTANT NOTE: The code below creates objects, because field.section does a search on section.component_ids if field.section == self puts "Field with id '#{field.id}' already belongs to this section" elsif sec = field.section # Field belongs to another section raise "Field with id '#{field.id}' belongs to section '#{sec.heading || "Unnamed"}' (id: '#{sec.id}')" end if before before_fld = to_component(before, side: side) elsif after after_fld = to_component(afterm, side: side) end if split? ids_ary = side == :right ? right_component_ids : left_component_ids else ids_ary = component_ids end ids_ary.insert_one(field.id, before: before_fld&.id, after: after_fld&.id) self end private def components_by_id(*ids) root.components.values_at(*ids).select.with_index do |fld, i| puts "Warning: field id #{ids[i]} points to missing field" if !fld fld && (!block_given? || yield(fld)) end end def to_component(value, side: nil) if split? fields = components(side: side || :left) else fields = components end fields.find do |fld| found = nil found ||= !!value if value.is_a?(Ecoportal::API::V2::Page::Component) found ||= fld.id == value found ||= same_string?(fld.label, value) end end end end end end end