|
| 1 | +#!/usr/bin/env ruby |
| 2 | + |
| 3 | +# This example shows how to use the "numbering" system to describe how a list |
| 4 | +# should be numbered within a document. |
| 5 | + |
| 6 | +# require "rails" # workaround: openxml-package uses `extract_options!` |
| 7 | +$:.push Dir.pwd + "/lib" |
| 8 | +require "openxml/docx" |
| 9 | + |
| 10 | +package = OpenXml::Docx::Package.new |
| 11 | + |
| 12 | +include OpenXml::Docx::Elements |
| 13 | + |
| 14 | +# Each list item is a paragraph. A helper function to create paragraphs in the |
| 15 | +# final document: |
| 16 | +def create_paragraph(content) |
| 17 | + text = Text.new(content) |
| 18 | + run = Run.new |
| 19 | + run << text |
| 20 | + paragraph = Paragraph.new |
| 21 | + paragraph << run |
| 22 | + paragraph |
| 23 | +end |
| 24 | + |
| 25 | +# First up, create a style for the list paragraph |
| 26 | +list_style = OpenXml::Docx::Style.new :paragraph |
| 27 | +list_style.id = 'ListParagraph' |
| 28 | +list_style.style_name = 'List Paragraph' |
| 29 | +list_style.paragraph.indentation.left = 720 |
| 30 | +list_style.paragraph.contextual_spacing = true |
| 31 | + |
| 32 | +package.styles << list_style |
| 33 | + |
| 34 | +# Each list needs a numbering within the numbering part of the document. |
| 35 | + |
| 36 | +# Create an abstract numbering that describes a bulleted list: |
| 37 | +abstract_numbering = AbstractNumbering.new(0) |
| 38 | + |
| 39 | +# Each numbering can have multiple levels. Define the first level as a bulleted list: |
| 40 | +level_0 = Level.new |
| 41 | +level_0.level = 0 |
| 42 | +level_0.start = 1 |
| 43 | +level_0.number_format = :bullet |
| 44 | +# This is the default bullet Word uses |
| 45 | +level_0.level_text = "\u00B7".encode("UTF-8") |
| 46 | +level_0.alignment = :left |
| 47 | +level_0.character_style.font.ascii = "Symbol" |
| 48 | +level_0.character_style.font.high_ansi = "Symbol" |
| 49 | +level_0.character_style.font.hint = :default |
| 50 | +level_0.paragraph_style.indentation.left = 720 |
| 51 | +level_0.paragraph_style.indentation.hanging = 360 |
| 52 | +abstract_numbering << level_0 |
| 53 | + |
| 54 | +package.numbering << abstract_numbering |
| 55 | + |
| 56 | +package.document << create_paragraph("Example of adding a list to a document") |
| 57 | + |
| 58 | +list_item = create_paragraph("First list item") |
| 59 | +list_item.paragraph_style = 'ListParagraph' |
| 60 | +# Say that this list item belongs to our first abstract numbering: |
| 61 | +list_item.numbering.level = 0 |
| 62 | +list_item.numbering.id = 1 |
| 63 | +# This ID is NOT the numbering ID we created above. Instead, it is a concrete |
| 64 | +# numbering that defines an instance of a list in the document. To link it to |
| 65 | +# our existing abstract numbering, we need to create a concrete numbering |
| 66 | +# instance: |
| 67 | + |
| 68 | +numbering = Numbering.new(1) |
| 69 | +# Setting the abstract numbering ID here links it to a given abstract numbering |
| 70 | +numbering.abstract_numbering_id = 0 |
| 71 | + |
| 72 | +# And add this number to the numbering |
| 73 | +package.numbering << numbering |
| 74 | + |
| 75 | +# All that allows us to finally add the item to the document. |
| 76 | + |
| 77 | +package.document << list_item |
| 78 | + |
| 79 | +list_item = create_paragraph("Second list item") |
| 80 | +list_item.paragraph_style = 'ListParagraph' |
| 81 | + |
| 82 | +# The second list item is simpler: we can reuse the numbering we used above. |
| 83 | +list_item.numbering.level = 0 |
| 84 | +list_item.numbering.id = 1 |
| 85 | + |
| 86 | +package.document << list_item |
| 87 | + |
| 88 | +package.document << create_paragraph("Outline Example") |
| 89 | + |
| 90 | +# Lists with numbers are a bit more complicated. The following creates an |
| 91 | +# "outline" list: |
| 92 | + |
| 93 | +abstract_numbering = AbstractNumbering.new(1) |
| 94 | + |
| 95 | +[:upperRoman, :upperLetter, :decimal, :lowerLetter, :lowerRoman, :decimal, :lowerLetter].each.with_index do |number_format, index| |
| 96 | + level = Level.new |
| 97 | + level.level = index |
| 98 | + level.start = 1 |
| 99 | + level.number_format = number_format |
| 100 | + # Level text replacement tokens are always 1-based, while the levels |
| 101 | + # themselves are 0-based |
| 102 | + level.level_text = index < 4 ? "%#{index+1}." : "(%#{index+1})" |
| 103 | + level.alignment = :left |
| 104 | + level.paragraph_style.indentation.left = (360 * (index+1)) |
| 105 | + level.paragraph_style.indentation.hanging = 360 |
| 106 | + abstract_numbering << level |
| 107 | +end |
| 108 | + |
| 109 | +package.numbering << abstract_numbering |
| 110 | + |
| 111 | +numbering = Numbering.new(2) |
| 112 | +numbering.abstract_numbering_id = 1 |
| 113 | + |
| 114 | +package.numbering << numbering |
| 115 | + |
| 116 | +(0..6).each do |level| |
| 117 | + list_item = create_paragraph("Level #{level+1}") |
| 118 | + list_item.paragraph_style = 'ListParagraph' |
| 119 | + list_item.numbering.level = level |
| 120 | + list_item.numbering.id = 2 |
| 121 | + package.document << list_item |
| 122 | +end |
| 123 | + |
| 124 | +filename = "numbering_example.docx" |
| 125 | +package.save File.expand_path("#{filename}") |
0 commit comments