class Prawn::Outline
The Outline
class organizes the outline tree items for the document. Note that the prev and parent instance variables are adjusted while navigating through the nested blocks. These variables along with the presence or absense of blocks are the primary means by which the relations for the various OutlineItems and the OutlineRoot are set. Unfortunately, the best way to understand how this works is to follow the method calls through a real example.
Some ideas for the organization of this class were gleaned from name_tree. In particular the way in which the OutlineItems are finally rendered into document objects in PdfObject through a hash.
Attributes
@private
@private
@private
@private
Public Class Methods
# File lib/prawn/outline.rb, line 31 def initialize(document) @document = document @parent = root @prev = nil @items = {} end
Public Instance Methods
Inserts an outline section to the outline tree (see outline#define). Although you will probably choose to exclusively use outline#define so that your outline tree is contained and easy to manage, this method gives you the option to insert sections to the outline tree at any point during document generation. This method allows you to add a child subsection to any other item at any level in the outline tree. Currently the only way to locate the place of entry is with the title for the item. If your title names are not unique consider using define_outline. The method takes the following arguments:
title: a string that must match an outline title to add the subsection to position: either :first or :last (the default) where the subsection will be placed relative to other child elements. If you need to position your subsection in between other elements then consider using #insert_section_after block: uses the same DSL syntax as outline#define, for example:
Consider using this method inside of outline.update if you want to have the outline object to be scoped as self (see insert_section_after
example).
go_to_page 2 start_new_page text "Inserted Page" outline.add_subsection_to :title => 'Page 2', :first do outline.page :destination => page_number, :title => "Inserted Page" end
# File lib/prawn/outline.rb, line 108 def add_subsection_to(title, position = :last, &block) @parent = items[title] unless @parent raise Prawn::Errors::UnknownOutlineTitle, "\n No outline item with title: '#{title}' exists in the outline tree" end @prev = position == :first ? nil : @parent.data.last nxt = position == :first ? @parent.data.first : nil insert_section(nxt, &block) end
Defines/Updates an outline for the document. The outline is an optional nested index that appears on the side of a PDF
document usually with direct links to pages. The outline DSL is defined by nested blocks involving two methods: section and page; see the documentation on those methods for their arguments and options. Note that one can also use outline#update to add more sections to the end of the outline tree using the same syntax and scope.
The syntax is best illustrated with an example:
Prawn::Document.generate(outlined_document.pdf)
do
text "Page 1. This is the first Chapter. " start_new_page text "Page 2. More in the first Chapter. " start_new_page outline.define do section 'Chapter 1', :destination => 1, :closed => true do page :destination => 1, :title => 'Page 1' page :destination => 2, :title => 'Page 2' end end start_new_page do outline.update do section 'Chapter 2', :destination => 2, do page :destination => 3, :title => 'Page 3' end end
end
# File lib/prawn/outline.rb, line 74 def define(&block) instance_eval(&block) if block end
Inserts an outline section to the outline tree (see outline#define). Although you will probably choose to exclusively use outline#define so that your outline tree is contained and easy to manage, this method gives you the option to insert sections to the outline tree at any point during document generation. Unlike outline.add_section, this method allows you to enter a section after any other item at any level in the outline tree. Currently the only way to locate the place of entry is with the title for the item. If your title names are not unique consider using define_outline. The method takes the following arguments:
title: the title of other section or page to insert new section after block: uses the same DSL syntax as outline#define, for example: go_to_page 2 start_new_page text "Inserted Page" update_outline do insert_section_after :title => 'Page 2' do page :destination => page_number, :title => "Inserted Page" end end
# File lib/prawn/outline.rb, line 141 def insert_section_after(title, &block) @prev = items[title] unless @prev raise Prawn::Errors::UnknownOutlineTitle, "\n No outline item with title: '#{title}' exists in the outline tree" end @parent = @prev.data.parent nxt = @prev.data.next insert_section(nxt, &block) end
See Outline#define
above for more documentation on how it is used in that context
Adds a page to the outline. Although you will probably choose to exclusively use outline#define so that your outline tree is contained and easy to manage, this method also gives you the option to add pages to the root of outline tree at any point during document generation. Note that the page will be added at the top level after the other root outline elements. For more flexible placement try using outline#insert_section_after and/or outline#add_subsection_to.
Takes the following arguments:
options: title - REQUIRED. The outline text that appears for the page. destination - optional integer defining the page number for a destination link to the top of the page (using a :FIT destination). or an array with a custom destination (see the dest_* methods of the PDF::Destination module) closed - whether the section should show its nested outline elements. - defaults to false.
example usage:
outline.page :title => "Very Last Page"
Note: this method is almost identical to section except that it does not accept a block thereby defining the outline item as a leaf on the outline tree structure.
# File lib/prawn/outline.rb, line 213 def page(options = {}) if options[:title] title = options[:title] else raise Prawn::Errors::RequiredOption, "\nTitle is a required option for page" end add_outline_item(title, options) end
Returns the current page number of the document
# File lib/prawn/outline.rb, line 41 def page_number @document.page_number end
See outline#define above for documentation on how this is used in that context
Adds an outine section to the outline tree. Although you will probably choose to exclusively use outline#define so that your outline tree is contained and easy to manage, this method gives you the option to add sections to the outline tree at any point during document generation. When not being called from within another section
block the section will be added at the top level after the other root elements of the outline. For more flexible placement try using outline#insert_section_after and/or outline#add_subsection_to
Takes the following arguments:
title: the outline text that appears for the section. options: destination - optional integer defining the page number for a destination link to the top of the page (using a :FIT destination). - or an array with a custom destination (see the #dest_* methods of the PDF::Destination module) closed - whether the section should show its nested outline elements. - defaults to false. block: more nested subsections and/or page blocks
example usage:
outline.section 'Added Section', :destination => 3 do outline.page :destionation => 3, :title => 'Page 3' end
# File lib/prawn/outline.rb, line 181 def section(title, options = {}, &block) add_outline_item(title, options, &block) end
Private Instance Methods
# File lib/prawn/outline.rb, line 233 def add_outline_item(title, options, &block) outline_item = create_outline_item(title, options) establish_relations(outline_item) increase_count set_variables_for_block(outline_item, block) yield if block reset_parent(outline_item) end
# File lib/prawn/outline.rb, line 297 def adjust_relations(nxt, last) if nxt nxt.data.prev = @prev @prev.data.next = nxt @parent.data.last = last end end
# File lib/prawn/outline.rb, line 242 def create_outline_item(title, options) outline_item = PDF::Core::OutlineItem.new(title, parent, options) case options[:destination] when Integer page_index = options[:destination] - 1 outline_item.dest = [document.state.pages[page_index].dictionary, :Fit] when Array outline_item.dest = options[:destination] end outline_item.prev = prev if @prev items[title] = document.ref!(outline_item) end
# File lib/prawn/outline.rb, line 257 def establish_relations(outline_item) prev.data.next = outline_item if prev parent.data.first = outline_item unless prev parent.data.last = outline_item end
# File lib/prawn/outline.rb, line 263 def increase_count counting_parent = parent while counting_parent counting_parent.data.count += 1 counting_parent = if counting_parent == root nil else counting_parent.data.parent end end end
# File lib/prawn/outline.rb, line 288 def insert_section(nxt, &block) last = @parent.data.last if block yield end adjust_relations(nxt, last) reset_root_positioning end
# File lib/prawn/outline.rb, line 281 def reset_parent(outline_item) if parent == outline_item self.prev = outline_item self.parent = outline_item.data.parent end end
# File lib/prawn/outline.rb, line 305 def reset_root_positioning @parent = root @prev = root.data.last end
The Outline
dictionary (12.3.3) for this document. It is lazily initialized, so that documents that do not have an outline do not incur the additional overhead.
# File lib/prawn/outline.rb, line 228 def root document.state.store.root.data[:Outlines] ||= document.ref!(PDF::Core::OutlineRoot.new) end
# File lib/prawn/outline.rb, line 276 def set_variables_for_block(outline_item, block) self.prev = block ? nil : outline_item self.parent = outline_item if block end