# frozen_string_literal: true module Notare module Xml class StylesXml NAMESPACE = "http://schemas.openxmlformats.org/wordprocessingml/2006/main" ALIGNMENT_MAP = { left: "left", center: "center", right: "right", justify: "both" }.freeze TABLE_ALIGNMENT_MAP = { left: "left", center: "center", right: "right" }.freeze def initialize(styles, table_styles = {}) @styles = styles @table_styles = table_styles end def to_xml builder = Nokogiri::XML::Builder.new(encoding: "UTF-8") do |xml| xml.styles("xmlns:w" => NAMESPACE) do xml.parent.namespace = xml.parent.namespace_definitions.find { |ns| ns.prefix == "w" } @styles.each_value do |style| render_style(xml, style) end @table_styles.each_value do |style| render_table_style(xml, style) end end end builder.to_xml end private def render_style(xml, style) style_type = style.paragraph_properties? ? "paragraph" : "character" xml["w"].style("w:type" => style_type, "w:styleId" => style.style_id) do xml["w"].name("w:val" => style.display_name) render_paragraph_properties(xml, style) if style.paragraph_properties? render_run_properties(xml, style) if style.text_properties? end end def render_paragraph_properties(xml, style) xml["w"].pPr do xml["w"].jc("w:val" => ALIGNMENT_MAP[style.align]) if style.align xml["w"].ind("w:left" => style.indent.to_s) if style.indent xml["w"].spacing("w:before" => style.spacing_before.to_s) if style.spacing_before xml["w"].spacing("w:after" => style.spacing_after.to_s) if style.spacing_after end end def render_run_properties(xml, style) xml["w"].rPr do xml["w"].rFonts("w:ascii" => style.font, "w:hAnsi" => style.font) if style.font xml["w"].sz("w:val" => style.size_half_points.to_s) if style.size xml["w"].color("w:val" => style.color) if style.color xml["w"].b if style.bold xml["w"].i if style.italic xml["w"].u("w:val" => "single") if style.underline xml["w"].strike if style.strike xml["w"].highlight("w:val" => style.highlight) if style.highlight end end def render_table_style(xml, style) xml["w"].style("w:type" => "table", "w:styleId" => style.style_id) do xml["w"].name("w:val" => style.display_name) xml["w"].tblPr do render_table_borders(xml, style.borders) if style.borders render_table_shading(xml, style.shading) if style.shading render_table_cell_margins(xml, style.cell_margins) if style.cell_margins xml["w"].jc("w:val" => TABLE_ALIGNMENT_MAP[style.align]) if style.align end end end def render_table_borders(xml, borders) xml["w"].tblBorders do %i[top left bottom right insideH insideV].each do |pos| border = borders == :none ? :none : (borders[pos] || borders) render_single_border(xml, pos, border) end end end def render_single_border(xml, position, border) if border == :none xml["w"].send(position, "w:val" => "nil") else xml["w"].send(position, "w:val" => border[:style], "w:sz" => border[:size].to_s, "w:space" => "0", "w:color" => border[:color]) end end def render_table_shading(xml, color) xml["w"].shd("w:val" => "clear", "w:color" => "auto", "w:fill" => color) end def render_table_cell_margins(xml, margins) xml["w"].tblCellMar do if margins.is_a?(Hash) xml["w"].top("w:w" => margins[:top].to_s, "w:type" => "dxa") if margins[:top] xml["w"].left("w:w" => margins[:left].to_s, "w:type" => "dxa") if margins[:left] xml["w"].bottom("w:w" => margins[:bottom].to_s, "w:type" => "dxa") if margins[:bottom] xml["w"].right("w:w" => margins[:right].to_s, "w:type" => "dxa") if margins[:right] else %i[top left bottom right].each do |side| xml["w"].send(side, "w:w" => margins.to_s, "w:type" => "dxa") end end end end end end end