# frozen_string_literal: true module Notare module Xml class Numbering NAMESPACE = "http://schemas.openxmlformats.org/wordprocessingml/2006/main" BULLET_CHARS = ["•", "○", "■"].freeze NUMBER_FORMATS = %w[decimal lowerLetter lowerRoman].freeze def initialize(lists) @lists = lists end def to_xml builder = Nokogiri::XML::Builder.new(encoding: "UTF-8") do |xml| xml.numbering("xmlns:w" => NAMESPACE) do xml.parent.namespace = xml.parent.namespace_definitions.find { |ns| ns.prefix == "w" } @lists.each do |list| render_abstract_num(xml, list) render_num(xml, list) end end end builder.to_xml end private def render_abstract_num(xml, list) xml["w"].abstractNum("w:abstractNumId" => list.num_id.to_s) do 9.times do |level| xml["w"].lvl("w:ilvl" => level.to_s) do xml["w"].start("w:val" => "1") xml["w"].numFmt("w:val" => num_format_for_level(list.type, level)) xml["w"].lvlText("w:val" => lvl_text_for_level(list.type, level)) xml["w"].lvlJc("w:val" => "left") xml["w"].pPr do left = 720 * (level + 1) xml["w"].ind("w:left" => left.to_s, "w:hanging" => "360") end end end end end def render_num(xml, list) xml["w"].num("w:numId" => list.num_id.to_s) do xml["w"].abstractNumId("w:val" => list.num_id.to_s) end end def num_format_for_level(type, level) if type == :bullet "bullet" else NUMBER_FORMATS[level % NUMBER_FORMATS.length] end end def lvl_text_for_level(type, level) if type == :bullet BULLET_CHARS[level % BULLET_CHARS.length] else "%#{level + 1}." end end end end end