在虾中使用列表

我正在使用prawn来创建包含表格格式和一些列表的大量数据的pdf。 列表的问题是我只是使用文本作为列表,因为没有语义等同于ul> li列表,就像我在webfrointend中使用它们一样。 因此列表不合理。 使用多行的列表点看起来很狡猾,因为我不适合列表图标。 如何在虾中实现看起来不像垃圾的列表?

Prawn是一个很好的PDF库,但问题是它自己的视图系统。 有Prawn格式但不再维护。

我建议使用WickedPDF ,它允许您在PDF中包含简单的ERB代码。

使用Prawn :另一个肮脏和丑陋的解决方案是没有边框的两列表,第一列包含list-bullet,第二列文本:

table([ ["•", "First Element"], ["•", "Second Element"], ["•", "Third Element"] ]) 

我只是遇到了类似的问题并在Prawn中解决了一个与使用表格略有不同的方法:

 ["Item 1","Item 2","Item 3"].each() do |list-item| #create a bounding box for the list-item label #float it so that the cursor doesn't move down float do bounding_box [15,cursor], :width => 10 do text "•" end end #create a bounding box for the list-item content bounding_box [25,cursor], :width => 600 do text list-item end #provide a space between list-items move_down(5) end 

这显然可以扩展(例如,您可以使用each_with_index()而不是每个()来编号。 它还允许边界框中的任意内容(表中不允许)。

要使用Adobe的内置字体创建项目符号,请使用\ u2022。

 \u2022 This will be the first bullet item \u2022 blah blah blah 

Prawn支持使用WinAnsi代码的符号(也称为字形),这些代码必须编码为UTF-8。 有关详情,请参阅此post: https : //groups.google.com/forum/#!topic / prawn-ruby / axynpwaqK1g

Prawn手册有一个完整的支持字形列表。

刚刚为客户做了这件事。 对于想要渲染包含ul / ol列表的预格式化html的每个人:

 def render_html_text(text, pdf) #render text (indented if inside ul) indent = 0 #current indentation (absolute, eg n*indent_delta for level n) indent_delta = 10 #indentation step per list level states = [] #whether we have an ol or ul at level n indices = [] #remembers at which index the ol list at level n, currently is #while there is another list tag do # => starting position of list tag is at i # render everything that comes before the tag # cut everything we have rendered from the whole text #end while (i = text.index /<\/?[ou]l>/) != nil do part = text[0..i-1] if indent == 0 #we're not in a list, but at the top level pdf.text part, :inline_format => true else pdf.indent indent do #render all the lis part.gsub(/<\/li>/, '').split('
  • ').each do |item| next if item.blank? #split may return some ugly start and end blanks item_text = if states.last == :ul "• #{item}" else # :ol indices[indices.length-1] = indices.last + 1 "#{indices.last}. #{item}" end pdf.text item_text, :inline_format => true end end end is_closing = text[i+1] == '/' #closing tag? if is_closing indent -= indent_delta i += ''.length states.pop indices.pop else pdf.move_down 10 if indent == 0 type_identifier = text[i+1] #<_u_l> or <_o_l> states << if type_identifier == 'u' :ul elsif type_identifier == 'o' :ol else raise "what means type identifier '#{type_identifier}'?" end indices << 0 indent += indent_delta i += '
      '.length end text = text[i..text.length-1] #cut the text we just rendered end #render the last part pdf.text text, :inline_format => true unless text.blank? end
  • 一个优秀的解决方案,尊重光标位置以及渲染像一个具有少量代码行的真实列表是:

     items = ["first","second","third"] def bullet_list(items) start_new_page if cursor < 50 items.each do |item| text_box "•", at: [13, cursor] indent(30) do text item end end end 

    start_new_page子句涵盖子弹行项目可能需要进入下一页的场景。 这样可以保持子弹的子弹内容。

    示例PDF渲染屏幕截图:

    示例呈现列表

    一个复出就是创建一个类似于crm答案的方法。 不同之处在于,当文本转到另一个页面时它不会中断,您也可以有多个级别。

     def bullet_item(level = 1, string) indent (15 * level), 0 do text "• " + string end end 

    只需调用此方法,如下所示:

     bullet_item(1, "Text for bullet point 1") bullet_item(2, "Sub point") 

    随意重构。

    我认为更好的方法是使用Nokogiri 预处理 HTML字符串,只留下Prawn可以使用“inline_format”选项管理的基本标记,如下代码所示:

     def self.render_html_text(instr) # Replacing 

    tag outstr = instr.gsub('

    ',"\n") outstr.gsub!('

    ',"\n") # Replacing
      &
    • tags doc = Nokogiri::HTML(outstr) doc.search('//ul').each do |ul| content = Nokogiri::HTML(ul.inner_html).xpath('//li').map{|n| "• #{n.inner_html}\n"}.join ul.replace(content) end #removing some tags inserted by Nokogiri doc.at_xpath('//body').inner_html end