Skip to content

Commit

Permalink
resolves asciidoctor#110 fix xrefs to non-section content
Browse files Browse the repository at this point in the history
- introduce add_dest_for_block for adding xref targets (i.e, destinations)
- call add_dest_for_block in each block handler
- add support in parser for <a name> to set inline destinations
- handle render_behind callback to add inline destinations
- enable inline ref and bibref targets
  • Loading branch information
mojavelinux committed May 18, 2015
1 parent 74bc08e commit eb984e3
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 12 deletions.
57 changes: 45 additions & 12 deletions lib/asciidoctor-pdf/converter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ def self.unicode_char number
TabSpaces = ' ' * 4
NoBreakSpace = unicode_char 0x00a0
NarrowNoBreakSpace = unicode_char 0x202f
ZeroWidthSpace = unicode_char 0x200b
HairSpace = unicode_char 0x200a
DotLeader = %(#{HairSpace}.)
EmDash = unicode_char 0x2014
Expand Down Expand Up @@ -259,9 +260,7 @@ def convert_section sect, opts = {}
end
# QUESTION should we store page_start & destination in internal map?
sect.set_attr 'page_start', page_number
dest_y = at_page_top? ? page_height : y
sect.set_attr 'destination', (sect_destination = (dest_xyz 0, dest_y))
add_dest sect.id, sect_destination
add_dest_for_block sect
sect.chapter? ? (layout_chapter_title sect, title) : (layout_heading title)
end

Expand All @@ -270,12 +269,14 @@ def convert_section sect, opts = {}
end

def convert_floating_title node
add_dest_for_block node if node.id
theme_font :heading, level: (node.level + 1) do
layout_heading node.title
end
end

def convert_abstract node
add_dest_for_block node if node.id
pad_box @theme.abstract_padding do
theme_font :abstract do
# FIXME control first_line_options using theme
Expand Down Expand Up @@ -313,6 +314,7 @@ def convert_preamble node

# TODO add prose around image logic (use role to add special logic for headshot)
def convert_paragraph node
add_dest_for_block node if node.id
is_lead = false
prose_opts = {}
node.roles.each do |role|
Expand Down Expand Up @@ -345,6 +347,7 @@ def convert_paragraph node

# FIXME alignment of content is off
def convert_admonition node
add_dest_for_block node if node.id
#move_down @theme.block_margin_top unless at_page_top?
theme_margin :block, :top
icons = node.document.attr? 'icons', 'font'
Expand Down Expand Up @@ -391,6 +394,7 @@ def convert_admonition node
end

def convert_example node
add_dest_for_block node if node.id
#move_down @theme.block_margin_top unless at_page_top?
theme_margin :block, :top
keep_together do |box_height = nil|
Expand Down Expand Up @@ -421,14 +425,17 @@ def convert_open node
if node.blocks.size == 1 && node.blocks.first.style == 'abstract'
convert_abstract node.blocks.first
else
add_dest_for_block node if node.id
convert_content_for_block node
end
else
add_dest_for_block node if node.id
convert_content_for_block node
end
end

def convert_quote_or_verse node
add_dest_for_block node if node.id
border_width = @theme.blockquote_border_width
#move_down @theme.block_margin_top unless at_page_top?
theme_margin :block, :top
Expand Down Expand Up @@ -466,6 +473,7 @@ def convert_quote_or_verse node
alias :convert_verse :convert_quote_or_verse

def convert_sidebar node
add_dest_for_block node if node.id
#move_down @theme.block_margin_top unless at_page_top?
theme_margin :block, :top
keep_together do |box_height = nil|
Expand Down Expand Up @@ -495,6 +503,7 @@ def convert_sidebar node
end

def convert_colist node
add_dest_for_block node if node.id
# HACK undo the margin below the listing
move_up ((@theme.block_margin_bottom || @theme.vertical_rhythm) * 0.5)
@list_numbers ||= []
Expand All @@ -508,6 +517,7 @@ def convert_colist node
end

def convert_dlist node
add_dest_for_block node if node.id
node.items.each do |terms, desc|
terms = [*terms]
# NOTE don't orphan the terms, allow for at least one line of content
Expand All @@ -525,6 +535,7 @@ def convert_dlist node
end

def convert_olist node
add_dest_for_block node if node.id
@list_numbers ||= []
list_number = case node.style
when 'arabic'
Expand Down Expand Up @@ -554,6 +565,7 @@ def convert_olist node

# TODO implement checklist
def convert_ulist node
add_dest_for_block node if node.id
bullet_type = if (style = node.style)
case style
when 'bibliography'
Expand Down Expand Up @@ -629,6 +641,7 @@ def convert_content_for_list_item node
end

def convert_image node
add_dest_for_block node if node.id
#move_down @theme.block_margin_top unless at_page_top?
theme_margin :block, :top
target = node.attr 'target'
Expand Down Expand Up @@ -699,6 +712,7 @@ def convert_image node
end

def convert_listing_or_literal node
add_dest_for_block node if node.id
# HACK disable built-in syntax highlighter; must be done before calling node.content!
if (node.style == 'source')
node.subs.delete :highlight
Expand Down Expand Up @@ -771,6 +785,7 @@ def convert_listing_or_literal node
alias :convert_literal :convert_listing_or_literal

def convert_table node
add_dest_for_block node if node.id
num_rows = 0
num_cols = node.columns.size
table_header = false
Expand Down Expand Up @@ -971,15 +986,11 @@ def convert_inline_anchor node
end
end
when :ref
# FIXME add destination to PDF document
#target = node.target
#%(<a id="#{target}"></a>)
''
# NOTE destination is created inside callback registered by FormattedTextTransform#build_fragment
%(<a name="#{node.target}">#{ZeroWidthSpace}</a>)
when :bibref
# FIXME add destination to PDF document
#target = node.target
#%(<a id="#{target}"></a>[#{target}])
%([#{node.target}])
# NOTE destination is created inside callback registered by FormattedTextTransform#build_fragment
%(<a name="#{target = node.target}">#{ZeroWidthSpace}</a>[#{target}])
else
warn %(asciidoctor: WARNING: unknown anchor type: #{node.type.inspect})
end
Expand Down Expand Up @@ -1052,7 +1063,7 @@ def convert_inline_quoted node
quoted_text = %(#{open}#{node.text}#{close})
end

node.id ? %(<a id="#{node.id}"></a>#{quoted_text}) : quoted_text
node.id ? %(<a name="#{node.id}">#{ZeroWidthSpace}</a>#{quoted_text}) : quoted_text
end

def layout_title_page doc
Expand Down Expand Up @@ -1469,6 +1480,28 @@ def sanitize string
.strip
end

# If the node passed as the first argument has an id, add a named destination
# to the document equivalent to the node id at the current y position. If the
# node does not have an id, do nothing.
#
# If the node is a section, and the current y position is the top of the
# page, set the position equal to the page height to improve the navigation
# experience.
def add_dest_for_block node
if !scratch? && (id = node.id)
dest_y = if node.context == :section && at_page_top?
page_height
else
y
end
# QUESTION should this attribute be named pdf-destination instead?
# FIXME destination is not always the left margin; use x value of current bounding box
node.set_attr 'destination', (node_dest = (dest_xyz 0, dest_y))
add_dest id, node_dest
end
nil
end

def resolve_imagesdir doc
@imagesdir ||= begin
imagesdir = (doc.attr 'imagesdir', '.').chomp '/'
Expand Down
22 changes: 22 additions & 0 deletions lib/asciidoctor-pdf/prawn_ext/formatted_text/transform.rb
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,10 @@ def build_fragment(fragment, tag_name = nil, attrs = {})
if !fragment[:local] && (value = attrs[:local])
fragment[:local] = value
end
if !fragment[:name] && (value = attrs[:name])
fragment[:name] = value
fragment[:callback] = InlineDestinationMarker.instance
end
fragment[:color] ||= @link_font_color
when :sub
styles << :subscript
Expand Down Expand Up @@ -174,5 +178,23 @@ def build_fragment(fragment, tag_name = nil, attrs = {})
fragment
end
end

class InlineDestinationMarker
@__instance__ = new

def self.instance
@__instance__
end

def render_behind fragment
unless (doc = fragment.instance_variable_get :@document).scratch?
if (name = (fragment.instance_variable_get :@format_state)[:name])
# get precise position of the reference
dest_rect = fragment.absolute_bounding_box
doc.add_dest name, (doc.dest_xyz dest_rect.first, dest_rect.last)
end
end
end
end
end
end

0 comments on commit eb984e3

Please sign in to comment.