module Docx class Document include OpenXml::Docx::Elements def initialize end def generate yield(self) tmpfile = Tempfile.new("#{Time.current.to_f}.xlsx", Rails.root.join("tmp")) _document.save(tmpfile.path) tmpfile.path end def heading1(text) paragraph = create_paragraph(text) paragraph.paragraph_style = "Heading 1" _document.document << paragraph end def heading2(text) paragraph = create_paragraph(text) paragraph.paragraph_style = "Heading 2" _document.document << paragraph end def heading3(text) paragraph = create_paragraph(text) paragraph.paragraph_style = "Heading 3" _document.document << paragraph end def paragraph(text) html = Nokogiri::HTML5.fragment(text) html.search(".trix-content").each do |node| node.children.each do |child| Rails.logger.debug { "content kids: #{child.class}: #{child.name} (#{child.children.size}): #{child.text}" } case child when Nokogiri::XML::Text paragraph = create_paragraph(child.text) _document.document << paragraph when Nokogiri::XML::Element case child.name when "h1" paragraph = create_paragraph(child.text) paragraph.paragraph_style = "Heading 3" when "div" paragraph = Paragraph.new paragraph.paragraph_style = "Body Text" child.children.each do |node| Rails.logger.debug { "div kids: #{node.class}: #{node.name} (#{node.children.size}): #{node.text}" } case node.name when "strong" paragraph << create_run(node.text, bold: true) when "em" paragraph << create_run(node.text, italic: true) when "del" paragraph << create_run(node.text, strike_through: true) when "br" paragraph << create_run("\n") else paragraph << create_run(node.text) end end when "ul" # paragraph = Paragraph.new # paragraph.paragraph_style = "Body Text" # # Create an abstract numbering that describes a bulleted list: # abstract_numbering = AbstractNumbering.new(0) # # Each numbering can have multiple levels. Define the first level as a bulleted list: # level_0 = Level.new # level_0.level = 0 # level_0.start = 1 # level_0.number_format = :bullet # # This is the default bullet Word uses # level_0.level_text = "\u00B7".encode("UTF-8") # level_0.alignment = :left # level_0.character_style.font.ascii = "Symbol" # level_0.character_style.font.high_ansi = "Symbol" # level_0.character_style.font.hint = :default # level_0.paragraph_style.indentation.left = 720 # level_0.paragraph_style.indentation.hanging = 360 # abstract_numbering << level_0 # _document.numbering << abstract_numbering when "ol" else paragraph = create_paragraph(child.text) paragraph.paragraph_style = "Body Text" end _document.document << paragraph end end end end private def create_run(content, bold: false, italic: false, strike_through: false) text = Text.new(content) text.space = :preserve run = Run.new run.bold = bold run.italics = italic run.strikethrough = strike_through run << text run end def create_paragraph(content) text = case content when String Text.new(content) when ActionText::RichText Text.new(content.to_plain_text) else Text.new(content.to_s) end run = Run.new run << text paragraph = Paragraph.new paragraph << run paragraph end def _document @_document ||= OpenXml::Docx::Package.new end end end