Files
Notare/lib/notare/xml/numbering.rb
mathias234 75b3a163c7
All checks were successful
CI Pipeline / build (pull_request) Successful in 13s
Implement nested lists
2025-12-02 15:00:39 +01:00

72 lines
2.0 KiB
Ruby

# 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