Вопрос по ruby-on-rails – Использование списков в креветках

11

Я использую креветки для создания PDF-файлов, которые содержат много данных в табличном формате и некоторые списки. Проблема со списками в том, что я просто использую текст в качестве списков, потому что нет семантического эквивалента ul & gt; Ли списки, как я использую их в веб-браузере. Так что списки не оправданы. Точка списка, которая использует более одной строки, выглядит неестественно, потому что я не помещаю значок списка. Как я могу реализовать списки в креветках, которые не похожи на дерьмо?

что ты пробовал? tmaximini
Я только что попробовал списки iplement как тексты, но это выглядит глупо, как только комментарий имеет более одной строки. davidb

Ваш Ответ

7   ответов
9

и я решил ее в 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 (), а не с каждым ()). Он также допускает произвольное содержимое в ограничивающей рамке (что не разрешено в таблицах).

Это решение имеет проблему, когда документ PDF имеет несколько страниц: когда текст переходит на следующую страницу, он отображается внизу.
1

pre-processing HTML-строка с использованием Nokogiri, оставляя только основные теги, которыми Prawn мог бы управлять с помощью & quot; inline_format & quot; вариант, как в этом коде:

def self.render_html_text(instr)
   # Replacing <p> tag
   outstr = instr.gsub('<p>',"\n")
   outstr.gsub!('</p>',"\n")
   # Replacing <ul> & <li> 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 <html><body> tags inserted by Nokogiri
   doc.at_xpath('//body').inner_html
end
0

аналогичного ответу 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")

Не стесняйтесь рефакторинга.

23

но проблема в ее собственной системе просмотра. ЕстьКреветка-формат но больше не поддерживается.

Я предлагаю использоватьWickedPDF, это позволяет вам включить простой код ERB в ваш PDF.

Using Prawn: другойdirty and ugly Решение представляет собой таблицу из двух столбцовwithout borderпервый столбец содержит список-маркер, текст второго столбца:

table([ ["•", "First Element"],
        ["•", "Second Element"],
        ["•", "Third Element"] ])
спасибо, я думаю, что это будет работать для меня, ... davidb
Большой! Вы также можете использоватьcell_style: { borders: [] } как вариант, чтобы избавиться от границ и сделать его похожим на фактический список.
4

которое учитывает положение курсора, а также отображает как настоящий список с небольшим количеством строк кода:

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:

Example Rendered List

4

кто хочет визуализировать предварительно отформатированный HTML, содержащий списки ul / ol:

def render_html_text(text, pdf)
  #render text (indented if inside ul)
  indent = 0 #current indentation (absolute, e.g. 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('<li>').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 += '</ul>'.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 += '<ul>'.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
Спасибо, мужик, это было очень полезно для меня! Возможные улучшения:String#blank? это не чистый рубин. Используемый.strip == '' как быстрое решение. Используемый#{item.strip} при отображении элемента маркера, в противном случае я получаю перевод строки после маркеров (возможно, из-за перевода строки в моей разметке HTML)
4

используйте \ u2022.

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

Prawn поддерживает символы (также известные как глифы) с кодами WinAnsi, и они должны быть закодированы как UTF-8. Смотрите этот пост для более подробной информации:https://groups.google.com/forum/#!topic/prawn-ruby/axynpwaqK1g

Руководство по креветкам имеет полный список глифов, которые поддерживаются.

Почему этот ответ не получил больше признания? @Powers - просто использовал это сам, он работал отлично. Следует сказать, что ваш синтаксис предполагает инкапсуляцию в двойных кавычках.

Похожие вопросы