Module: Asciidoctor::PDF::Rhrev::ChangeBars

Included in:
Converter
Defined in:
lib/asciidoctor/rhrev/change_bars.rb

Overview

Inks a vertical change bar in the page margin next to blocks marked with the current revision (revnumber 1.2 => attribute rhrev1-2). Enabled by the rhrev-change-bars document attribute.

Styling comes from the PDF theme by default (rhrev_change_bars category: color, width, offset, side), overridable per document via the rhrev-change-bars-color/-width/-offset/-side attributes.

Instance Method Summary collapse

Instance Method Details

#arrange_block(node, &block) ⇒ Object

Examples and listings are arranged blocks: the extent yielded here is exact across page breaks. Tables and images never reach this hook with their own node, so they are handled in the converter overrides instead.



108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/asciidoctor/rhrev/change_bars.rb', line 108

def arrange_block node, &block
  if @change_bar_attr && !scratch? &&
      (node.context == :example || node.context == :listing) && (change_bar? node)
    super node do |extent|
      if scratch?
        # measurement pass: upstream instance_execs this wrapper on the scratch
        # document, so re-bind the original block to it the same way
        instance_exec(&block)
      else
        block.call extent
        ink_change_bar_for_extent extent
      end
    end
  else
    super
  end
end

#change_bar?(node) ⇒ Boolean

Returns:

  • (Boolean)


51
52
53
54
# File 'lib/asciidoctor/rhrev/change_bars.rb', line 51

def change_bar? node
  @change_bar_attr && node.respond_to?(:attributes) &&
    node.attributes && (node.attributes.key? @change_bar_attr)
end

#change_bar_settingsObject

Resolved lazily on first ink: the theme (and @media/@folio_placement) are not loaded yet when init_change_bars runs; upstream convert_document sets them up after rhrev's pre-super initialization. Precedence: document attribute > theme key > built-in default.



36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/asciidoctor/rhrev/change_bars.rb', line 36

def change_bar_settings
  @change_bar_settings ||= begin
    overrides = @change_bar_overrides || {}
    theme = @theme
    side = overrides[:side] || theme&.rhrev_change_bars_side ||
      (@media == 'prepress' ? 'outer' : 'right')
    {
      color: (overrides[:color] || theme&.rhrev_change_bars_color || 'FF0000').to_s.delete_prefix('#').upcase,
      width: (overrides[:width] || theme&.rhrev_change_bars_width || 2).to_f,
      offset: (overrides[:offset] || theme&.rhrev_change_bars_offset || 16).to_f,
      side: side.to_s,
    }
  end
end

#change_bar_x(pgnum, settings) ⇒ Object

The offset measures the gap between the text edge and the near edge of the bar. Sides recto/verso are determined by the physical page number (honoring pdf-folio-placement inversion), matching prepress physical folio placement.



68
69
70
71
72
73
74
75
76
77
# File 'lib/asciidoctor/rhrev/change_bars.rb', line 68

def change_bar_x pgnum, settings
  case settings[:side]
  when 'right'
    on_right = true
  when 'outer', 'inner'
    recto = (page_side pgnum, @folio_placement && @folio_placement[:inverted]) == :recto
    on_right = settings[:side] == 'outer' ? recto : !recto
  end
  on_right ? bounds.right + settings[:offset] : bounds.left - settings[:offset] - settings[:width]
end

#init_change_bars(doc) ⇒ Object



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/asciidoctor/rhrev/change_bars.rb', line 14

def init_change_bars doc
  @change_bar_attr = nil
  @change_bar_settings = nil
  return unless doc.attr? 'rhrev-change-bars'
  # Without a revnumber there is no "current" revision to match
  return unless (revnumber = doc.attr 'revnumber')
  @change_bar_attr = %(#{@revision_prefix}#{revnumber.to_s.tr '.', '-'})
  # Capture attribute values only; holding the Document in an ivar here
  # would leak it into the scratch prototype, which must stay marshalable
  @change_bar_overrides = {
    color: (doc.attr 'rhrev-change-bars-color'),
    width: (doc.attr 'rhrev-change-bars-width'),
    offset: (doc.attr 'rhrev-change-bars-offset'),
    side: (doc.attr 'rhrev-change-bars-side'),
  }
  @change_bar_starts = {}
end

#ink_change_bar(from, to) ⇒ Object

Paints the bar page by page; from/to are { page:, cursor: }. Called immediately after the block is rendered, so all spanned pages exist.



81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/asciidoctor/rhrev/change_bars.rb', line 81

def ink_change_bar from, to
  return if scratch? || from.nil? || to.nil?
  return if to[:page] < from[:page]
  return if to[:page] == from[:page] && to[:cursor] >= from[:cursor]
  settings = change_bar_settings
  float do
    (from[:page]..to[:page]).each do |pgnum|
      go_to_page pgnum unless page_number == pgnum
      top = pgnum == from[:page] ? from[:cursor] : bounds.top
      bottom = pgnum == to[:page] ? to[:cursor] : 0
      next if (height = top - bottom) <= 0
      bounding_box [(change_bar_x pgnum, settings), top], width: settings[:width], height: height do
        fill_bounds settings[:color]
      end
    end
  end
end

#ink_change_bar_for_extent(extent) ⇒ Object



99
100
101
102
103
# File 'lib/asciidoctor/rhrev/change_bars.rb', line 99

def ink_change_bar_for_extent extent
  return unless extent
  ink_change_bar({ page: extent.from.page, cursor: extent.from.cursor },
    { page: extent.to.page, cursor: extent.to.cursor })
end

#ink_chapter_title(node, title, opts = {}) ⇒ Object



133
134
135
136
# File 'lib/asciidoctor/rhrev/change_bars.rb', line 133

def ink_chapter_title node, title, opts = {}
  record_change_bar_start node if @change_bar_attr && !scratch? && (change_bar? node)
  super
end

#ink_general_heading(node, title, opts = {}) ⇒ Object

The heading ink methods run after arrange_heading / start_new_chapter have settled the page, so this is the first accurate start position.



128
129
130
131
# File 'lib/asciidoctor/rhrev/change_bars.rb', line 128

def ink_general_heading node, title, opts = {}
  record_change_bar_start node if @change_bar_attr && !scratch? && (change_bar? node)
  super
end

#ink_part_title(node, title, opts = {}) ⇒ Object

Upstream defines ink_part_title as an alias copy of ink_chapter_title, so it must be overridden separately



140
141
142
143
# File 'lib/asciidoctor/rhrev/change_bars.rb', line 140

def ink_part_title node, title, opts = {}
  record_change_bar_start node if @change_bar_attr && !scratch? && (change_bar? node)
  super
end

#record_change_bar_start(node) ⇒ Object



56
57
58
# File 'lib/asciidoctor/rhrev/change_bars.rb', line 56

def record_change_bar_start node
  @change_bar_starts[node] = { page: page_number, cursor: cursor }
end

#take_change_bar_start(node) ⇒ Object



60
61
62
# File 'lib/asciidoctor/rhrev/change_bars.rb', line 60

def take_change_bar_start node
  @change_bar_starts&.delete node
end