metanorma/isodoc

View on GitHub
lib/isodoc/function/lists.rb

Summary

Maintainability
A
2 hrs
Test Coverage
module IsoDoc
  module Function
    module Lists
      def list_title_parse(node, out)
        name = node.at(ns("./name")) or return
        out.p class: "ListTitle" do |p|
          name&.children&.each { |n| parse(n, p) }
        end
      end

      def ul_attrs(node)
        { id: node["id"], style: keep_style(node) }
      end

      def ul_parse(node, out)
        out.div **attr_code(class: "ul_wrap") do |div|
          list_title_parse(node, div)
          div.ul **attr_code(ul_attrs(node)) do |ul|
            node.children.each { |n| n.name == "name" or parse(n, ul) }
          end
        end
      end

      OL_STYLE = {
        arabic: "1",
        roman: "i",
        alphabet: "a",
        roman_upper: "I",
        alphabet_upper: "A",
      }.freeze

      def ol_style(type)
        type ||= :alphabet
        OL_STYLE[type.to_sym]
      end

      # We don't really want users to specify type of ordered list;
      # we will use a fixed hierarchy as practiced by ISO (though not
      # fully spelled out): a) 1) i) A) I)

      def ol_depth(node)
        depth = node.ancestors("ul, ol").size + 1
        type = :alphabet
        type = :arabic if [2, 7].include? depth
        type = :roman if [3, 8].include? depth
        type = :alphabet_upper if [4, 9].include? depth
        type = :roman_upper if [5, 10].include? depth
        ol_style(type)
      end

      def ol_attrs(node)
        { type: node["type"] ? ol_style(node["type"].to_sym) : ol_depth(node),
          id: node["id"], style: keep_style(node) }
      end

      def ol_parse(node, out)
        out.div **attr_code(class: "ol_wrap") do |div|
          list_title_parse(node, div)
          div.ol **attr_code(ol_attrs(node)) do |ol|
            node.children.each { |n| n.name == "name" or parse(n, ol) }
          end
        end
      end

      def li_parse(node, out)
        out.li **attr_code(id: node["id"]) do |li|
          if node["uncheckedcheckbox"] == "true"
            li << '<span class="zzMoveToFollowing">' \
                  '<input type="checkbox" checked="checked"/></span>'
          elsif node["checkedcheckbox"] == "true"
            li << '<span class="zzMoveToFollowing">' \
                  '<input type="checkbox"/></span>'
          end
          node.children.each { |n| parse(n, li) }
        end
      end

      def dt_parse(dterm, term)
        if dterm.elements.empty?
          term.p do |p|
            dterm.children.each { |n| parse(n, p) }
          end
        else
          dterm.children.each { |n| parse(n, term) }
        end
      end

      def dt_dd?(node)
        %w{dt dd}.include? node.name
      end

      def dl_attrs(node)
        attr_code(id: node["id"], style: keep_style(node), class: node["class"])
      end

      def dl_parse(node, out)
        out.div **attr_code(class: "figdl") do |div|
          list_title_parse(node, div)
          div.dl **dl_attrs(node) do |v|
            node.elements.select { |n| dt_dd? n }.each_slice(2) do |dt, dd|
              dl_parse1(v, dt, dd)
            end
          end
          dl_parse_notes(node, div)
        end
      end

      def dl_parse_notes(node, out)
        node.elements.reject { |n| dt_dd?(n) || n.name == "name" }
          .each { |n| parse(n, out) }
      end

      def dl_parse1(dlist, dterm, ddef)
        dlist.dt **attr_code(id: dterm["id"]) do |term|
          dt_parse(dterm, term)
        end
        dlist.dd **attr_code(id: ddef["id"]) do |listitem|
          ddef.children.each { |n| parse(n, listitem) }
        end
      end
    end
  end
end