diff options
| -rw-r--r-- | CHANGELOG.adoc | 1 | ||||
| -rw-r--r-- | lib/asciidoctor/pdf/converter.rb | 71 | ||||
| -rw-r--r-- | spec/section_spec.rb | 40 |
3 files changed, 80 insertions, 32 deletions
diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index bbfa8041..2d42fa74 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -68,6 +68,7 @@ Enhancements:: * use Document#authors to retrieve authors instead of extracting the information from the indexed document attributes * add support for character references that contain both uppercase and lowercase hexadecimal characters (#1990) (*@etiwnad*) * log error and skip table instead of raising error if cell content cannot fit into column width of table (#2009) +* extract `arrange_section` method to compute whether section title should be advanced to next page (#2023) Bug Fixes:: diff --git a/lib/asciidoctor/pdf/converter.rb b/lib/asciidoctor/pdf/converter.rb index d8419b35..5d54debf 100644 --- a/lib/asciidoctor/pdf/converter.rb +++ b/lib/asciidoctor/pdf/converter.rb @@ -647,42 +647,36 @@ module Asciidoctor title, _, subtitle = title.rpartition sep title = %(#{title}\n<em class="subtitle">#{subtitle}</em>) end + hlevel = sect.level + 1 + align = (@theme[%(heading_h#{hlevel}_align)] || @theme.heading_align || @base_align).to_sym chapterlike = !(part = sectname == 'part') && (sectname == 'chapter' || (sect.document.doctype == 'book' && sect.level == 1)) - theme_font :heading, level: (hlevel = sect.level + 1) do - align = (@theme[%(heading_h#{hlevel}_align)] || @theme.heading_align || @base_align).to_sym - if part - unless @theme.heading_part_break_before == 'auto' - start_new = true - start_new_part sect - end - elsif chapterlike - if @theme.heading_chapter_break_before != 'auto' || - (@theme.heading_part_break_after == 'always' && sect == sect.parent.sections[0]) - start_new = true - start_new_chapter sect - end - end - unless start_new || at_page_top? - # FIXME: this height doesn't account for impact of text transform or inline formatting - heading_height = - (height_of_typeset_text title, line_height: (@theme[%(heading_h#{hlevel}_line_height)] || @theme.heading_line_height)) + - (@theme[%(heading_h#{hlevel}_margin_top)] || @theme.heading_margin_top) + - (@theme[%(heading_h#{hlevel}_margin_bottom)] || @theme.heading_margin_bottom) - heading_height += @theme.heading_min_height_after if sect.blocks? && @theme.heading_min_height_after - start_new_page unless cursor > heading_height - end - # QUESTION: should we store pdf-page-start, pdf-anchor & pdf-destination in internal map? - sect.set_attr 'pdf-page-start', (start_pgnum = page_number) - # QUESTION: should we just assign the section this generated id? - # NOTE: section must have pdf-anchor in order to be listed in the TOC - sect.set_attr 'pdf-anchor', (sect_anchor = derive_anchor_from_id sect.id, %(#{start_pgnum}-#{y.ceil})) - add_dest_for_block sect, id: sect_anchor, y: (at_page_top? ? page_height : nil) + hopts = { align: align, level: hlevel, outdent: !(part || chapterlike) } + if part + unless @theme.heading_part_break_before == 'auto' + start_new = true + theme_font(:heading, level: hlevel) { start_new_part sect } + end + elsif chapterlike + if @theme.heading_chapter_break_before != 'auto' || + (@theme.heading_part_break_after == 'always' && sect == sect.parent.sections[0]) + start_new = true + theme_font(:heading, level: hlevel) { start_new_chapter sect } + end + end + arrange_section sect, title, hopts unless start_new || at_page_top? + # QUESTION: should we store pdf-page-start, pdf-anchor & pdf-destination in internal map? + sect.set_attr 'pdf-page-start', (start_pgnum = page_number) + # QUESTION: should we just assign the section this generated id? + # NOTE: section must have pdf-anchor in order to be listed in the TOC + sect.set_attr 'pdf-anchor', (sect_anchor = derive_anchor_from_id sect.id, %(#{start_pgnum}-#{y.ceil})) + add_dest_for_block sect, id: sect_anchor, y: (at_page_top? ? page_height : nil) + theme_font :heading, level: hlevel do if part - layout_part_title sect, title, align: align, level: hlevel + layout_part_title sect, title, hopts elsif chapterlike - layout_chapter_title sect, title, align: align, level: hlevel unless sect.special && (sect.option? 'untitled') + layout_chapter_title sect, title, hopts unless sect.special && (sect.option? 'untitled') else - layout_general_heading sect, title, align: align, level: hlevel, outdent: true + layout_general_heading sect, title, hopts end end @@ -2866,6 +2860,19 @@ module Asciidoctor alias start_new_part start_new_chapter + def arrange_section sect, title, opts + theme_font :heading, level: (hlevel = opts[:level]) do + # FIXME: this height doesn't account for impact of text transform or inline formatting + heading_height = + (height_of_typeset_text title, line_height: (@theme[%(heading_h#{hlevel}_line_height)] || @theme.heading_line_height)) + + (@theme[%(heading_h#{hlevel}_margin_top)] || @theme.heading_margin_top) + + (@theme[%(heading_h#{hlevel}_margin_bottom)] || @theme.heading_margin_bottom) + heading_height += @theme.heading_min_height_after if sect.blocks? && @theme.heading_min_height_after + start_new_page unless cursor > heading_height + nil + end + end + def layout_chapter_title node, title, opts = {} layout_general_heading node, title, (opts.merge outdent: true) end diff --git a/spec/section_spec.rb b/spec/section_spec.rb index 4b1c5da5..9dfe6dd1 100644 --- a/spec/section_spec.rb +++ b/spec/section_spec.rb @@ -867,6 +867,46 @@ describe 'Asciidoctor::PDF::Converter - Section' do (expect content_text[:page_number]).to be 2 end + it 'should allow arrange_section to be reimplemented to keep section with content that follows' do + backend = nil + create_class (Asciidoctor::Converter.for 'pdf') do + register_for (backend = %(pdf#{object_id}).to_sym) + def arrange_section sect, title, opts + orphaned = nil + dry_run single_page: true do + start_page = page + theme_font(:heading, level: opts[:level]) { layout_general_heading sect, title, opts } + next if page != start_page + page.tare_content_stream + orphaned = stop_if_first_page_empty { traverse sect } + end + start_new_page if orphaned + end + end + + pdf = to_pdf <<~EOS, backend: backend, analyze: true + == Section A + + image::tall.svg[pdfwidth=70mm] + + == Section B + + [%unbreakable] + -- + keep + + this + + together + -- + EOS + + section_b_text = pdf.find_unique_text 'Section B' + (expect section_b_text[:page_number]).to be 2 + content_text = pdf.find_unique_text 'keep' + (expect content_text[:page_number]).to be 2 + end + it 'should not add break before chapter if heading-chapter-break-before key in theme is auto' do pdf = to_pdf <<~'EOS', pdf_theme: { heading_chapter_break_before: 'auto' }, analyze: true = Document Title |
