asciidoctor-pdf 1.5.0.alpha.17 → 1.5.0.alpha.18
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.adoc +30 -2
- data/README.adoc +31 -4
- data/asciidoctor-pdf.gemspec +2 -1
- data/docs/theming-guide.adoc +126 -1
- data/lib/asciidoctor-pdf/asciidoctor_ext.rb +3 -1
- data/lib/asciidoctor-pdf/asciidoctor_ext/abstract_block.rb +5 -0
- data/lib/asciidoctor-pdf/asciidoctor_ext/document.rb +3 -0
- data/lib/asciidoctor-pdf/asciidoctor_ext/logging_shim.rb +8 -2
- data/lib/asciidoctor-pdf/asciidoctor_ext/section.rb +16 -8
- data/lib/asciidoctor-pdf/converter.rb +300 -167
- data/lib/asciidoctor-pdf/core_ext.rb +1 -0
- data/lib/asciidoctor-pdf/core_ext/regexp.rb +3 -0
- data/lib/asciidoctor-pdf/formatted_text/formatter.rb +8 -1
- data/lib/asciidoctor-pdf/index_catalog.rb +9 -3
- data/lib/asciidoctor-pdf/measurements.rb +1 -1
- data/lib/asciidoctor-pdf/prawn_ext/extensions.rb +28 -10
- data/lib/asciidoctor-pdf/roman_numeral.rb +12 -0
- data/lib/asciidoctor-pdf/theme_loader.rb +17 -5
- data/lib/asciidoctor-pdf/version.rb +1 -1
- metadata +21 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fed971e3655c6b460cdf90ba7205802ad7060710287123a36df56b1e75dd8257
|
4
|
+
data.tar.gz: 888b1ef50e7e690bab7661ee0b10d35671376e85352389ccc8f1bf6b11798cfc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e29597fcbbb5c7cc2b822ad5844f0d656fc5890a1b6fb062511f9fb88a68204d5cde0f98b897b9f448c24897c53a9b221328a53ec8ef2f922f769d9f707153ed
|
7
|
+
data.tar.gz: a0275c1a8cee51ccbcf69102d47508f892784637ed0727a4c507c7d3f538b632aa2e87430e23146c7b93a295a95e4057f794f3b7693a1891517106f16c20b563
|
data/CHANGELOG.adoc
CHANGED
@@ -5,6 +5,33 @@
|
|
5
5
|
This document provides a high-level view of the changes to the {project-name} by release.
|
6
6
|
For a detailed view of what has changed, refer to the {uri-repo}/commits/master[commit history] on GitHub.
|
7
7
|
|
8
|
+
== 1.5.0.alpha.18 (2019-06-01) - @mojavelinux
|
9
|
+
|
10
|
+
* restore compatibility with Asciidoctor back to 1.5.3 and add verification to test matrix (#1038)
|
11
|
+
* allow theme to set text indent for paragraphs using prose_text_indent (#191)
|
12
|
+
* allow theme to set spacing between adjacent paragraphs using prose_margin_inner (#191)
|
13
|
+
* show parts in toc when toclevels=0 (#783)
|
14
|
+
* add support for autonumbered callouts in source blocks (#1076)
|
15
|
+
* fix duplication of footnotes in keep together regions (#1047)
|
16
|
+
* display standalone preamble in book normally (#1051)
|
17
|
+
* allow outline depth to be set using outlinelevels attribute independent of toclevels (#1054)
|
18
|
+
* fix compounding cell padding (#1053)
|
19
|
+
* add support for qanda list (#1013)
|
20
|
+
* fix parsing of bibref and link inside footnote text (#1061)
|
21
|
+
* restore square brackets around ID of bibliography entry with custom ID (#1065)
|
22
|
+
* add page_numbering_start_at key to theme to control start page for page numbering (#1041)
|
23
|
+
* don't allow running_content_start_at key to affect page numbering (#1041)
|
24
|
+
* substitute \{chapter-title} property on front matter pages (replace with doctitle and toc-title, respectively, when running content starts before first page of body) (#1040)
|
25
|
+
* allow side margins to be set on elements on title page (#824)
|
26
|
+
* don't promote preamble to preface if preface-title attribute is empty
|
27
|
+
* expand padding value for running content (header and footer) to array
|
28
|
+
* add support for unnumbered (and no-bullet) style on ordered list (#1073)
|
29
|
+
* add visual regression capability to test suite (@beatchristen)
|
30
|
+
* ensure index section doesn't get numbered when using Asciidoctor < 1.5.7
|
31
|
+
* add part signifier and part number to part title if partnums is set; allow signifier to be customized using part-signifier attribute (#597)
|
32
|
+
* add support for the chapter-signifier attribute as the prefered alternative to chapter-label
|
33
|
+
* warn if the image referenced in the running content cannot be found (#731)
|
34
|
+
|
8
35
|
== 1.5.0.alpha.17 (2019-04-23) - @mojavelinux
|
9
36
|
|
10
37
|
* drop support for Ruby < 2.3 (and installation will fail for Ruby < 2.1)
|
@@ -34,8 +61,8 @@ For a detailed view of what has changed, refer to the {uri-repo}/commits/master[
|
|
34
61
|
* handle case when uri to make breakable is empty (#936)
|
35
62
|
* add support for frame=ends as alternative to frame=topbot on table
|
36
63
|
* allow table frame and grid to be set globally using the table-frame and table-grid attributes (#822)
|
37
|
-
* disable table stripes by default
|
38
|
-
* allow table stripes to be enabled globally using table-stripes attribute
|
64
|
+
* disable table stripes by default (#1049)
|
65
|
+
* allow table stripes to be enabled globally using table-stripes attribute (#1049)
|
39
66
|
* use new logging subsystem, if available; otherwise, use shim (#905)
|
40
67
|
* allow alignment of list text to be controlled using roles (#182)
|
41
68
|
* allow text alignment to be set for abstract (#893)
|
@@ -56,6 +83,7 @@ For a detailed view of what has changed, refer to the {uri-repo}/commits/master[
|
|
56
83
|
* guard against pygments returning nil (#884)
|
57
84
|
* encode quotes in alt text of inline image (#977)
|
58
85
|
* fix crash when menu macro is used in a section or block title (#934)
|
86
|
+
* remove duplicate message when syntax highlighter is unavailable; don't crash processor (#1078)
|
59
87
|
* only look for the start attribute on the code block itself when highlighting with rouge
|
60
88
|
* apply block styling to background for line-oriented tokens in rouge by default
|
61
89
|
* detect pagenum ranges in index when media is print or prepress (#906)
|
data/README.adoc
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
= Asciidoctor PDF: A native PDF converter for AsciiDoc
|
2
2
|
Dan Allen <https://github.com/mojavelinux[@mojavelinux]>; Sarah White <https://github.com/graphitefriction[@graphitefriction]>
|
3
|
-
v1.5.0.alpha.
|
3
|
+
v1.5.0.alpha.18, 2019-06-01
|
4
4
|
// Settings:
|
5
5
|
:experimental:
|
6
6
|
:idprefix:
|
@@ -24,7 +24,7 @@ endif::[]
|
|
24
24
|
:project-name: Asciidoctor PDF
|
25
25
|
:project-handle: asciidoctor-pdf
|
26
26
|
// Variables:
|
27
|
-
:release-version: 1.5.0.alpha.
|
27
|
+
:release-version: 1.5.0.alpha.18
|
28
28
|
// URIs:
|
29
29
|
:uri-asciidoctor: http://asciidoctor.org
|
30
30
|
:uri-gem: http://rubygems.org/gems/asciidoctor-pdf
|
@@ -41,6 +41,7 @@ endif::[]
|
|
41
41
|
|
42
42
|
ifdef::status[]
|
43
43
|
image:https://img.shields.io/travis/asciidoctor/asciidoctor-pdf/master.svg[Build Status (Travis CI),link=https://travis-ci.org/asciidoctor/asciidoctor-pdf]
|
44
|
+
image:https://ci.appveyor.com/api/projects/status/524bhoms3j2dp1o3/branch/master?svg=true[Build Status (AppVeyor),link=https://ci.appveyor.com/project/asciidoctor/asciidoctor-pdf]
|
44
45
|
image:https://img.shields.io/gem/v/asciidoctor-pdf.svg[Latest Release, link={uri-gem}]
|
45
46
|
image:https://img.shields.io/badge/license-MIT-blue.svg[MIT License, link=#copyright]
|
46
47
|
endif::[]
|
@@ -118,7 +119,7 @@ endif::[]
|
|
118
119
|
|
119
120
|
== Prerequisites
|
120
121
|
|
121
|
-
All that's needed is Ruby 2.3 or better and a few Ruby gems, which we explain how to install in the next section.
|
122
|
+
All that's needed is Ruby 2.3 or better and a few Ruby gems (including at least Asciidoctor 1.5.3), which we explain how to install in the next section.
|
122
123
|
|
123
124
|
To check if you have Ruby available, use the `ruby` command to query the version installed:
|
124
125
|
|
@@ -756,7 +757,11 @@ To run the tests, simply invoke rspec via bundler.
|
|
756
757
|
|
757
758
|
$ bundle exec rspec
|
758
759
|
|
759
|
-
|
760
|
+
To disable the visual integration tests, pass the `` option:
|
761
|
+
|
762
|
+
$ bundle exec rspec -t ~integration
|
763
|
+
|
764
|
+
If you want to see the name of each test as it is run, add the `-fd` option:
|
760
765
|
|
761
766
|
$ bundle exec rspec -fd
|
762
767
|
|
@@ -790,6 +795,28 @@ You can use the application to convert a document as follows:
|
|
790
795
|
|
791
796
|
$ bundle exec asciidoctor-pdf /path/to/sample.adoc
|
792
797
|
|
798
|
+
=== Install the Application (optional)
|
799
|
+
|
800
|
+
If you want to install the application globally so you can run it anywhere, use the following `rake` task:
|
801
|
+
|
802
|
+
$ bundle exec rake install
|
803
|
+
|
804
|
+
This task will package the gem and install it into your system gems.
|
805
|
+
|
806
|
+
If you want to install the gem using a separate command, first use the following `rake` task to build it:
|
807
|
+
|
808
|
+
$ rm -rf pkg
|
809
|
+
bundle exec rake build
|
810
|
+
|
811
|
+
This task packages the application as a gem and writes it to the [.path]_pkg_ directory.
|
812
|
+
A message will be printed to the console telling you the exact filename.
|
813
|
+
You can now use the `gem install` command to install it.
|
814
|
+
|
815
|
+
$ gem install pkg/*.gem
|
816
|
+
|
817
|
+
You'll want to pay attention to which Ruby installation you are installing the gem into.
|
818
|
+
If successful, the `asciidoctor-pdf` executable will be available on your PATH.
|
819
|
+
|
793
820
|
endif::[]
|
794
821
|
|
795
822
|
=== Test a Pull Request
|
data/asciidoctor-pdf.gemspec
CHANGED
@@ -35,7 +35,7 @@ Gem::Specification.new do |s|
|
|
35
35
|
s.require_paths = ['lib']
|
36
36
|
#s.test_files = files.grep %r/^(?:test|spec|feature)\/.*$/
|
37
37
|
|
38
|
-
s.add_runtime_dependency 'asciidoctor', '>= 1.5.
|
38
|
+
s.add_runtime_dependency 'asciidoctor', '>= 1.5.3', '< 3.0.0'
|
39
39
|
s.add_runtime_dependency 'prawn', '~> 2.2.0'
|
40
40
|
s.add_runtime_dependency 'prawn-table', '~> 0.2.0'
|
41
41
|
s.add_runtime_dependency 'prawn-templates', '~> 0.1.0'
|
@@ -50,4 +50,5 @@ Gem::Specification.new do |s|
|
|
50
50
|
s.add_development_dependency 'rake', '~> 12.3.0'
|
51
51
|
s.add_development_dependency 'rspec', '~> 3.8.0'
|
52
52
|
s.add_development_dependency 'pdf-inspector', '~> 1.3.0'
|
53
|
+
s.add_development_dependency 'chunky_png', '~> 1.3.0'
|
53
54
|
end
|
data/docs/theming-guide.adoc
CHANGED
@@ -96,12 +96,33 @@ link:
|
|
96
96
|
font_color: #002FA7
|
97
97
|
outline_list:
|
98
98
|
indent: $base_font_size * 1.5
|
99
|
+
footer:
|
100
|
+
height: $base_line_height_length * 2.5
|
101
|
+
line_height: 1
|
102
|
+
recto:
|
103
|
+
right:
|
104
|
+
content: '{page-number}'
|
105
|
+
verso:
|
106
|
+
left:
|
107
|
+
content: $footer_recto_right_content
|
99
108
|
----
|
100
109
|
|
101
110
|
When creating a new theme, you only have to define the keys you want to override from the base theme, which is loaded prior to loading your custom theme.
|
102
111
|
All the available keys are documented in <<Keys>>.
|
103
112
|
The converter uses the information from the theme map to help construct the PDF.
|
104
113
|
|
114
|
+
Instead of writing a theme from scratch, you can extend the default theme using the `extends` key as follows:
|
115
|
+
|
116
|
+
[source,yaml]
|
117
|
+
----
|
118
|
+
extends: default
|
119
|
+
base:
|
120
|
+
color: #ff0000
|
121
|
+
----
|
122
|
+
|
123
|
+
You can also point the extends key at another custom theme to extend from it.
|
124
|
+
Currently, the base theme is always loaded first.
|
125
|
+
|
105
126
|
WARNING: If you start a new theme from scratch, we strongly recommend defining TrueType fonts and specifying them in the `base` and `literal` categories.
|
106
127
|
Otherwise, Asciidoctor PDF will use built-in AFM fonts, which can result in missing functionality and warnings.
|
107
128
|
|
@@ -876,6 +897,34 @@ When creating a theme, all keys are optional.
|
|
876
897
|
Required keys are provided by the base theme.
|
877
898
|
Therefore, you only have to declare keys that you want to override.
|
878
899
|
|
900
|
+
[#keys-extends]
|
901
|
+
=== Extends
|
902
|
+
|
903
|
+
A theme can extend another theme using the `extends` key.
|
904
|
+
The extends key accepts either a single value or an array of values.
|
905
|
+
Each value is interpreted as a filename.
|
906
|
+
If the filename equals `default`, it resolves to the location of the default (built-in) theme.
|
907
|
+
If the filename is absolute, it's used as is.
|
908
|
+
If the filename begins with `./`, it's resolved as a theme file relative to the current theme file.
|
909
|
+
Otherwise, the filename is resolved as a theme file in the normal way (relative to the value of the `pdf-stylesdir` attribute).
|
910
|
+
|
911
|
+
Currently, the base theme is always loaded first.
|
912
|
+
Then, the files referenced by the extends key are loaded in order.
|
913
|
+
Finally, the keys in the current file are loaded.
|
914
|
+
Each time a theme is loaded, the keys are overlaid onto the keys from the previous theme.
|
915
|
+
|
916
|
+
[cols="3,4,5l"]
|
917
|
+
|===
|
918
|
+
|Key |Value Type |Example
|
919
|
+
|
920
|
+
|extends
|
921
|
+
|String or Array
|
922
|
+
(default: [])
|
923
|
+
|extends:
|
924
|
+
- default
|
925
|
+
- ./brand-theme.yml
|
926
|
+
|===
|
927
|
+
|
879
928
|
[#keys-page]
|
880
929
|
=== Page
|
881
930
|
|
@@ -932,6 +981,12 @@ See <<Title Page>> for details.
|
|
932
981
|
(default: A4)
|
933
982
|
|page:
|
934
983
|
size: Letter
|
984
|
+
|
985
|
+
|numbering_start_at
|
986
|
+
|title {vbar} toc {vbar} body +
|
987
|
+
(default: body)
|
988
|
+
|page:
|
989
|
+
numbering_start_at: toc
|
935
990
|
|===
|
936
991
|
|
937
992
|
. Page background images are automatically scaled to fit within the bounds of the page.
|
@@ -1615,8 +1670,23 @@ Typically, all the margin is placed on the bottom.
|
|
1615
1670
|
(default: 12)
|
1616
1671
|
|prose:
|
1617
1672
|
margin_bottom: $vertical_spacing
|
1673
|
+
|
1674
|
+
|margin_inner^[1]^
|
1675
|
+
|<<measurement-units,Measurement>> +
|
1676
|
+
(default: $prose_margin_bottom)
|
1677
|
+
|prose:
|
1678
|
+
margin_inner: 0
|
1679
|
+
|
1680
|
+
|text_indent
|
1681
|
+
|<<measurement-units,Measurement>> +
|
1682
|
+
(default: _not set_)
|
1683
|
+
|prose:
|
1684
|
+
text_indent: 18
|
1618
1685
|
|===
|
1619
1686
|
|
1687
|
+
. Controls the margin between adjacent paragraphs.
|
1688
|
+
Useful when using indented paragraphs.
|
1689
|
+
|
1620
1690
|
[#keys-block]
|
1621
1691
|
=== Block
|
1622
1692
|
|
@@ -2955,6 +3025,56 @@ The keys in this category control the arrangement and style of tables and table
|
|
2955
3025
|
. Applied to even rows by default; controlled using `stripes` attribute (even, odd, all, none) on table.
|
2956
3026
|
//. `<parity>` can be `odd` (odd rows) or `even` (even rows).
|
2957
3027
|
|
3028
|
+
[#keys-footnotes]
|
3029
|
+
=== Footnotes
|
3030
|
+
|
3031
|
+
The keys in this catagory control the style the list of footnotes at the end of the chapter (book) or document (otherwise).
|
3032
|
+
If the `footnotes-title` attribute is specified, it is styled as a block caption.
|
3033
|
+
The styling of the links is controlled by the global link styles.
|
3034
|
+
|
3035
|
+
[cols="3,4,5l"]
|
3036
|
+
|===
|
3037
|
+
|Key |Value Type |Example
|
3038
|
+
|
3039
|
+
3+|[#key-prefix-footnotes]*Key Prefix:* <<key-prefix-footnotes,footnotes>>
|
3040
|
+
|
3041
|
+
|font_color
|
3042
|
+
|<<colors,Color>> +
|
3043
|
+
(default: $base_font_color)
|
3044
|
+
|footnotes:
|
3045
|
+
font_color: #cccccc
|
3046
|
+
|
3047
|
+
|font_size
|
3048
|
+
|<<values,Number>> +
|
3049
|
+
(default: 8)
|
3050
|
+
|footnotes:
|
3051
|
+
font_size: 6
|
3052
|
+
|
3053
|
+
|font_style
|
3054
|
+
|<<font-styles,Font style>> +
|
3055
|
+
(default: $base_font_style)
|
3056
|
+
|footnotes:
|
3057
|
+
font_style: italic
|
3058
|
+
|
3059
|
+
|item_spacing
|
3060
|
+
|<<measurement-units,Measurement>> +
|
3061
|
+
(default: 3)
|
3062
|
+
|footnotes:
|
3063
|
+
item_spacing: 5
|
3064
|
+
|
3065
|
+
|margin_top
|
3066
|
+
|<<measurement-units,Measurement>> +
|
3067
|
+
(default: 0)
|
3068
|
+
|footnotes:
|
3069
|
+
margin_top: 10
|
3070
|
+
|
3071
|
+
|text_transform
|
3072
|
+
|<<text-transforms,Text transform>> +
|
3073
|
+
(default: _inherit_)
|
3074
|
+
|footnotes:
|
3075
|
+
text_transform: lowercase
|
3076
|
+
|===
|
3077
|
+
|
2958
3078
|
[#keys-table-of-contents]
|
2959
3079
|
=== Table of Contents (TOC)
|
2960
3080
|
|
@@ -3144,6 +3264,7 @@ If value is not specified, dot leaders are shown for all levels.
|
|
3144
3264
|
=== Running Content (Header & Footer)
|
3145
3265
|
|
3146
3266
|
The keys in this category control the arrangement and style of running header and footer content.
|
3267
|
+
Please note that the running content will _not_ be used unless a) the periphery (header or footer) is configured and b) the height key for the periphery is assigned a value.
|
3147
3268
|
|
3148
3269
|
[cols="3,4,5l"]
|
3149
3270
|
|===
|
@@ -3347,7 +3468,7 @@ The keys in this category control the arrangement and style of running header an
|
|
3347
3468
|
content: '\{page-number}'
|
3348
3469
|
|===
|
3349
3470
|
. The background color spans the width of the page, as does the border when a background color is specified.
|
3350
|
-
. If the height is not set, the running content at this periphery is disabled
|
3471
|
+
. *If the height is not set, the running content at this periphery is disabled.*
|
3351
3472
|
. If the side padding is negative, the content will bleed into the margin of the page.
|
3352
3473
|
. `<side>` can be `recto` (right-hand, odd-numbered pages) or `verso` (left-hand, even-numbered pages).
|
3353
3474
|
Where the page sides fall in relation to the physical or printed page number is controlled using the `pdf-folio-placement` attribute (except when `media=prepress`, which implies `physical`).
|
@@ -3540,6 +3661,10 @@ These settings override equivalent keys defined in the theme file, where applica
|
|
3540
3661
|
|screen {vbar} print {vbar} prepress
|
3541
3662
|
|:media: prepress
|
3542
3663
|
|
3664
|
+
|outlinelevels
|
3665
|
+
|number (default: same as _toclevels_)
|
3666
|
+
|:outlinelevels: 2
|
3667
|
+
|
3543
3668
|
|page-background-image^[4]^
|
3544
3669
|
|path^[2]^ {vbar} image macro^[3]^
|
3545
3670
|
|:page-background-image: image:bg.jpg[]
|
@@ -1,4 +1,6 @@
|
|
1
|
-
# NOTE these are
|
1
|
+
# NOTE these are either candidates for inclusion in Asciidoctor core or backports
|
2
|
+
require_relative 'asciidoctor_ext/abstract_block'
|
3
|
+
require_relative 'asciidoctor_ext/document'
|
2
4
|
require_relative 'asciidoctor_ext/section'
|
3
5
|
require_relative 'asciidoctor_ext/list'
|
4
6
|
require_relative 'asciidoctor_ext/list_item'
|
@@ -1,11 +1,17 @@
|
|
1
1
|
module Asciidoctor
|
2
2
|
class StubLogger
|
3
3
|
class << self
|
4
|
-
def
|
4
|
+
def info message = nil
|
5
|
+
# ignore since this isn't a real logger
|
6
|
+
end
|
7
|
+
|
8
|
+
def warn message = nil
|
9
|
+
message = block_given? ? yield : message unless message
|
5
10
|
::Kernel.warn %(asciidoctor: WARNING: #{message})
|
6
11
|
end
|
7
12
|
|
8
|
-
def error message
|
13
|
+
def error message = nil
|
14
|
+
message = block_given? ? yield : message unless message
|
9
15
|
::Kernel.warn %(asciidoctor: ERROR: #{message})
|
10
16
|
end
|
11
17
|
end
|
@@ -1,17 +1,25 @@
|
|
1
1
|
class Asciidoctor::Section
|
2
2
|
def numbered_title opts = {}
|
3
3
|
unless (@cached_numbered_title ||= nil)
|
4
|
-
|
5
|
-
|
6
|
-
@cached_numbered_title = @cached_formal_numbered_title = title
|
7
|
-
elsif @numbered && !@caption && slevel <= (@document.attr 'sectnumlevels', 3).to_i
|
4
|
+
slevel = @level == 0 && @special ? 1 : @level
|
5
|
+
if @numbered && !@caption && slevel <= (@document.attr 'sectnumlevels', 3).to_i
|
8
6
|
@is_numbered = true
|
9
|
-
@
|
10
|
-
|
11
|
-
|
7
|
+
@cached_formal_numbered_title = if @document.doctype == 'book'
|
8
|
+
if slevel == 0
|
9
|
+
@cached_numbered_title = %(#{sectnum nil, ':'} #{title})
|
10
|
+
%(#{@document.attr 'part-signifier', 'Part'} #{@cached_numbered_title}).lstrip
|
11
|
+
elsif slevel == 1
|
12
|
+
@cached_numbered_title = %(#{sectnum} #{title})
|
13
|
+
%(#{@document.attr 'chapter-signifier', (@document.attr 'chapter-label', 'Chapter')} #{@cached_numbered_title}).lstrip
|
14
|
+
else
|
15
|
+
@cached_numbered_title = %(#{sectnum} #{title})
|
16
|
+
end
|
12
17
|
else
|
13
|
-
@cached_numbered_title
|
18
|
+
@cached_numbered_title = %(#{sectnum} #{title})
|
14
19
|
end
|
20
|
+
elsif slevel == 0
|
21
|
+
@is_numbered = false
|
22
|
+
@cached_numbered_title = @cached_formal_numbered_title = title
|
15
23
|
else
|
16
24
|
@is_numbered = false
|
17
25
|
@cached_numbered_title = @cached_formal_numbered_title = captioned_title
|
@@ -90,8 +90,7 @@ class Converter < ::Prawn::Document
|
|
90
90
|
MeasurementRxt = '\\d+(?:\\.\\d+)?(?:in|cm|mm|p[txc])?'
|
91
91
|
MeasurementPartsRx = /^(\d+(?:\.\d+)?)(in|mm|cm|p[txc])?$/
|
92
92
|
PageSizeRx = /^(?:\[(#{MeasurementRxt}), ?(#{MeasurementRxt})\]|(#{MeasurementRxt})(?: x |x)(#{MeasurementRxt})|\S+)$/
|
93
|
-
|
94
|
-
CalloutExtractRx = /(?:(?:\/\/|#|--|;;) ?)?(\\)?<!?(--|)(\d+)\2> ?(?=(?:\\?<!?\2\d+\2> ?)*$)/
|
93
|
+
CalloutExtractRx = /(?:(?:\/\/|#|--|;;) ?)?(\\)?<!?(|--)(\d+|\.)\2> ?(?=(?:\\?<!?\2(?:\d+|\.)\2>)*$)/
|
95
94
|
ImageAttributeValueRx = /^image:{1,2}(.*?)\[(.*?)\]$/
|
96
95
|
UriBreakCharsRx = /(?:\/|\?|&|#)(?!$)/
|
97
96
|
UriBreakCharRepl = %(\\&#{ZeroWidthSpace})
|
@@ -113,10 +112,10 @@ class Converter < ::Prawn::Document
|
|
113
112
|
# NOTE enabling data-uri forces Asciidoctor Diagram to produce absolute image paths
|
114
113
|
doc.attributes['data-uri'] = ((doc.instance_variable_get :@attribute_overrides) || {})['data-uri'] = ''
|
115
114
|
end
|
116
|
-
@list_numbers = []
|
117
|
-
@list_bullets = []
|
118
115
|
@capabilities = {
|
119
|
-
expands_tabs: (::Asciidoctor::VERSION.start_with? '1.5.3.') || AsciidoctorVersion >= (::Gem::Version.create '1.5.3')
|
116
|
+
expands_tabs: (::Asciidoctor::VERSION.start_with? '1.5.3.') || AsciidoctorVersion >= (::Gem::Version.create '1.5.3'),
|
117
|
+
special_sectnums: AsciidoctorVersion >= (::Gem::Version.create '1.5.7'),
|
118
|
+
syntax_highlighter: AsciidoctorVersion >= (::Gem::Version.create '2.0.0'),
|
120
119
|
}
|
121
120
|
end
|
122
121
|
|
@@ -155,16 +154,19 @@ class Converter < ::Prawn::Document
|
|
155
154
|
unless (doc.attribute_locked? 'pagenums') || ((doc.instance_variable_get :@attributes_modified).include? 'pagenums')
|
156
155
|
doc.attributes['pagenums'] = ''
|
157
156
|
end
|
157
|
+
if (idx_sect = doc.sections.find {|candidate| candidate.sectname == 'index' }) && idx_sect.numbered
|
158
|
+
idx_sect.numbered = false
|
159
|
+
end unless @capabilities[:special_sectnums]
|
158
160
|
#assign_missing_section_ids doc
|
159
161
|
|
160
162
|
# promote anonymous preface (defined using preamble block) to preface section
|
161
163
|
# FIXME this should be done in core
|
162
|
-
if doc.doctype == 'book' && (blk_0 = doc.blocks[0]) && blk_0.context == :preamble &&
|
163
|
-
blk_0.title? && blk_0.blocks[0].style != 'abstract' && (blk_1 = doc.blocks[1]) && blk_1.context == :section
|
164
|
+
if doc.doctype == 'book' && (blk_0 = doc.blocks[0]) && blk_0.context == :preamble && blk_0.title? &&
|
165
|
+
!blk_0.title.nil_or_empty? && blk_0.blocks[0].style != 'abstract' && (blk_1 = doc.blocks[1]) && blk_1.context == :section
|
164
166
|
preface = Section.new doc, blk_1.level, false, attributes: { 1 => 'preface', 'style' => 'preface' }
|
165
167
|
preface.special = true
|
166
168
|
preface.sectname = 'preface'
|
167
|
-
preface.title =
|
169
|
+
preface.title = blk_0.instance_variable_get :@title
|
168
170
|
# QUESTION should ID be generated from raw or converted title? core is not clear about this
|
169
171
|
preface.id = preface.generate_id
|
170
172
|
preface.blocks.replace blk_0.blocks.map {|b| b.parent = preface; b }
|
@@ -233,20 +235,31 @@ class Converter < ::Prawn::Document
|
|
233
235
|
start_new_page if @media == 'prepress' && verso_page?
|
234
236
|
|
235
237
|
if insert_title_page
|
236
|
-
body_start_page_number = page_number
|
238
|
+
body_offset = (body_start_page_number = page_number) - 1
|
239
|
+
front_matter_sig = [@theme.running_content_start_at || 'body', @theme.page_numbering_start_at || 'body', insert_toc]
|
237
240
|
# NOTE start running content from title or toc, if specified (default: body)
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
241
|
+
num_front_matter_pages = {
|
242
|
+
['title', 'title', true] => [0, 0],
|
243
|
+
['title', 'title', false] => [0, 0],
|
244
|
+
['title', 'toc', true] => [0, 1],
|
245
|
+
['title', 'toc', false] => [0, 1],
|
246
|
+
['title', 'body', true] => [0, body_offset],
|
247
|
+
['title', 'body', false] => [0, 1],
|
248
|
+
['toc', 'title', true] => [1, 0],
|
249
|
+
['toc', 'title', false] => [1, 0],
|
250
|
+
['toc', 'toc', true] => [1, 1],
|
251
|
+
['toc', 'toc', false] => [1, 1],
|
252
|
+
['toc', 'body', true] => [1, body_offset],
|
253
|
+
['body', 'title', true] => [body_offset, 0],
|
254
|
+
['body', 'title', false] => [1, 0],
|
255
|
+
['body', 'toc', true] => [body_offset, 1],
|
256
|
+
}[front_matter_sig] || [body_offset, body_offset]
|
245
257
|
else
|
246
|
-
|
258
|
+
# Q: what if there's only a toc page, but not title?
|
259
|
+
num_front_matter_pages = [body_start_page_number - 1] * 2
|
247
260
|
end
|
248
261
|
|
249
|
-
@index.start_page_number = num_front_matter_pages + 1
|
262
|
+
@index.start_page_number = num_front_matter_pages[1] + 1
|
250
263
|
doc.set_attr 'pdf-anchor', (doc_anchor = derive_anchor_from_id doc.id, 'top')
|
251
264
|
add_dest_for_block doc, doc_anchor
|
252
265
|
|
@@ -261,18 +274,18 @@ class Converter < ::Prawn::Document
|
|
261
274
|
# QUESTION should we delete page if document is empty? (leaving no pages?)
|
262
275
|
delete_page if page_is_empty? && page_count > 1
|
263
276
|
|
264
|
-
toc_page_nums = insert_toc ? (layout_toc doc, num_toc_levels, toc_page_nums.first, num_front_matter_pages, toc_start) : []
|
277
|
+
toc_page_nums = insert_toc ? (layout_toc doc, num_toc_levels, toc_page_nums.first, num_front_matter_pages[1], toc_start) : []
|
265
278
|
|
266
279
|
unless page_count < body_start_page_number
|
267
280
|
unless doc.noheader || @theme.header_height.to_f.zero?
|
268
|
-
layout_running_content :header, doc, skip: num_front_matter_pages
|
281
|
+
layout_running_content :header, doc, skip: num_front_matter_pages, body_start_page_number: body_start_page_number
|
269
282
|
end
|
270
283
|
unless doc.nofooter || @theme.footer_height.to_f.zero?
|
271
|
-
layout_running_content :footer, doc, skip: num_front_matter_pages
|
284
|
+
layout_running_content :footer, doc, skip: num_front_matter_pages, body_start_page_number: body_start_page_number
|
272
285
|
end
|
273
286
|
end
|
274
287
|
|
275
|
-
add_outline doc, num_toc_levels, toc_page_nums, num_front_matter_pages
|
288
|
+
add_outline doc, (doc.attr 'outlinelevels', num_toc_levels).to_i, toc_page_nums, num_front_matter_pages[1]
|
276
289
|
# TODO allow document (or theme) to override initial view magnification
|
277
290
|
# NOTE add 1 to page height to force initial scroll to 0; a nil value also seems to work
|
278
291
|
catalog.data[:OpenAction] = dest_fit_horizontally((page_height + 1), state.pages[0]) if state.pages.size > 0
|
@@ -321,6 +334,8 @@ class Converter < ::Prawn::Document
|
|
321
334
|
@font_color = theme.base_font_color
|
322
335
|
@base_align = (align = doc.attr 'text-alignment') && (TextAlignmentNames.include? align) ? align : theme.base_align
|
323
336
|
@text_transform = nil
|
337
|
+
@list_numerals = []
|
338
|
+
@list_bullets = []
|
324
339
|
@footnotes = []
|
325
340
|
@index = IndexCatalog.new
|
326
341
|
# NOTE we have to init Pdfmark class here while we have reference to the doc
|
@@ -359,19 +374,19 @@ class Converter < ::Prawn::Document
|
|
359
374
|
page_margin = nil
|
360
375
|
end
|
361
376
|
|
362
|
-
|
377
|
+
if (doc.attr? 'pdf-page-size') && PageSizeRx =~ (doc.attr 'pdf-page-size')
|
363
378
|
# e.g, [8.5in, 11in]
|
364
|
-
if
|
365
|
-
[
|
379
|
+
if $1
|
380
|
+
page_size = [$1, $2]
|
366
381
|
# e.g, 8.5in x 11in
|
367
|
-
elsif
|
368
|
-
[
|
382
|
+
elsif $3
|
383
|
+
page_size = [$3, $4]
|
369
384
|
# e.g, A4
|
370
385
|
else
|
371
|
-
|
386
|
+
page_size = $&
|
372
387
|
end
|
373
388
|
else
|
374
|
-
theme.page_size
|
389
|
+
page_size = theme.page_size
|
375
390
|
end
|
376
391
|
|
377
392
|
page_size = case page_size
|
@@ -388,9 +403,9 @@ class Converter < ::Prawn::Document
|
|
388
403
|
if ::Numeric === dim
|
389
404
|
# dimension cannot be less than 0
|
390
405
|
dim > 0 ? dim : break
|
391
|
-
elsif ::String === dim &&
|
406
|
+
elsif ::String === dim && MeasurementPartsRx =~ dim
|
392
407
|
# NOTE truncate to max precision retained by PDF::Core
|
393
|
-
(to_pt
|
408
|
+
(to_pt $1.to_f, $2).truncate 4
|
394
409
|
else
|
395
410
|
break
|
396
411
|
end
|
@@ -519,6 +534,9 @@ class Converter < ::Prawn::Document
|
|
519
534
|
end
|
520
535
|
theme_font :abstract do
|
521
536
|
prose_opts = { line_height: @theme.abstract_line_height, align: (@theme.abstract_align || @base_align).to_sym }
|
537
|
+
if (text_indent = @theme.prose_text_indent)
|
538
|
+
prose_opts[:indent_paragraphs] = text_indent
|
539
|
+
end
|
522
540
|
# FIXME control more first_line_options using theme
|
523
541
|
if (line1_font_style = @theme.abstract_first_line_font_style) && line1_font_style.to_sym != font_style
|
524
542
|
prose_opts[:first_line_options] = { styles: [font_style, line1_font_style.to_sym] }
|
@@ -547,21 +565,25 @@ class Converter < ::Prawn::Document
|
|
547
565
|
|
548
566
|
def convert_preamble node
|
549
567
|
# TODO find_by needs to support a depth argument
|
550
|
-
|
568
|
+
# FIXME core should not be promoting paragraph to preamble if there are no sections
|
569
|
+
if (first_p = (node.find_by context: :paragraph)[0]) && first_p.parent == node && node.document.sections?
|
551
570
|
first_p.add_role 'lead'
|
552
571
|
end
|
553
572
|
convert_content_for_block node
|
554
573
|
end
|
555
574
|
|
556
|
-
# TODO add prose around image logic (use role to add special logic for headshot)
|
557
575
|
def convert_paragraph node
|
558
576
|
add_dest_for_block node if node.id
|
559
|
-
prose_opts = {}
|
577
|
+
prose_opts = { margin_bottom: 0 }
|
560
578
|
lead = (roles = node.roles).include? 'lead'
|
561
579
|
if (align = resolve_alignment_from_role roles)
|
562
580
|
prose_opts[:align] = align
|
563
581
|
end
|
564
582
|
|
583
|
+
if (text_indent = @theme.prose_text_indent)
|
584
|
+
prose_opts[:indent_paragraphs] = text_indent
|
585
|
+
end
|
586
|
+
|
565
587
|
# TODO check if we're within one line of the bottom of the page
|
566
588
|
# and advance to the next page if so (similar to logic for section titles)
|
567
589
|
layout_caption node.title if node.title?
|
@@ -573,6 +595,14 @@ class Converter < ::Prawn::Document
|
|
573
595
|
else
|
574
596
|
layout_prose node.content, prose_opts
|
575
597
|
end
|
598
|
+
|
599
|
+
if (margin_inner_val = @theme.prose_margin_inner) &&
|
600
|
+
(next_block = (siblings = node.parent.blocks)[(siblings.index node) + 1]) && next_block.context == :paragraph
|
601
|
+
margin_bottom_val = margin_inner_val
|
602
|
+
else
|
603
|
+
margin_bottom_val = @theme.prose_margin_bottom
|
604
|
+
end
|
605
|
+
margin_bottom margin_bottom_val
|
576
606
|
end
|
577
607
|
|
578
608
|
def convert_admonition node
|
@@ -627,6 +657,7 @@ class Converter < ::Prawn::Document
|
|
627
657
|
shift_top = shift_base / 3.0
|
628
658
|
shift_bottom = (shift_base * 2) / 3.0
|
629
659
|
keep_together do |box_height = nil|
|
660
|
+
push_scratch doc if scratch?
|
630
661
|
pad_box [0, cpad[1], 0, lpad[3]] do
|
631
662
|
if box_height
|
632
663
|
if (rule_color = @theme.admonition_column_rule_color) &&
|
@@ -634,7 +665,7 @@ class Converter < ::Prawn::Document
|
|
634
665
|
float do
|
635
666
|
bounding_box [0, cursor], width: label_width + lpad[1], height: box_height do
|
636
667
|
stroke_vertical_rule rule_color,
|
637
|
-
at: bounds.
|
668
|
+
at: bounds.right,
|
638
669
|
line_style: (@theme.admonition_column_rule_style || :solid).to_sym,
|
639
670
|
line_width: rule_width
|
640
671
|
end
|
@@ -728,6 +759,7 @@ class Converter < ::Prawn::Document
|
|
728
759
|
move_up shift_bottom unless at_page_top?
|
729
760
|
end
|
730
761
|
end
|
762
|
+
pop_scratch doc if scratch?
|
731
763
|
end
|
732
764
|
theme_margin :block, :bottom
|
733
765
|
end
|
@@ -736,6 +768,7 @@ class Converter < ::Prawn::Document
|
|
736
768
|
add_dest_for_block node if node.id
|
737
769
|
theme_margin :block, :top
|
738
770
|
keep_together do |box_height = nil|
|
771
|
+
push_scratch node.document if scratch?
|
739
772
|
caption_height = node.title? ? (layout_caption node) : 0
|
740
773
|
if box_height
|
741
774
|
float do
|
@@ -749,6 +782,7 @@ class Converter < ::Prawn::Document
|
|
749
782
|
convert_content_for_block node
|
750
783
|
end
|
751
784
|
end
|
785
|
+
pop_scratch node.document if scratch?
|
752
786
|
end
|
753
787
|
theme_margin :block, :bottom
|
754
788
|
end
|
@@ -773,6 +807,7 @@ class Converter < ::Prawn::Document
|
|
773
807
|
b_width = @theme.blockquote_border_width
|
774
808
|
b_color = @theme.blockquote_border_color
|
775
809
|
keep_together do |box_height = nil|
|
810
|
+
push_scratch node.document if scratch?
|
776
811
|
start_page_number = page_number
|
777
812
|
start_cursor = cursor
|
778
813
|
caption_height = node.title? ? (layout_caption node) : 0
|
@@ -823,6 +858,7 @@ class Converter < ::Prawn::Document
|
|
823
858
|
end unless b_height == 0
|
824
859
|
end
|
825
860
|
end
|
861
|
+
pop_scratch node.document if scratch?
|
826
862
|
end
|
827
863
|
theme_margin :block, :bottom
|
828
864
|
end
|
@@ -834,6 +870,7 @@ class Converter < ::Prawn::Document
|
|
834
870
|
add_dest_for_block node if node.id
|
835
871
|
theme_margin :block, :top
|
836
872
|
keep_together do |box_height = nil|
|
873
|
+
push_scratch node.document if scratch?
|
837
874
|
if box_height
|
838
875
|
# FIXME due to the calculation error logged in #789, we must advance page even when content is split across pages
|
839
876
|
advance_page if box_height > cursor && !at_page_top?
|
@@ -890,6 +927,7 @@ class Converter < ::Prawn::Document
|
|
890
927
|
convert_content_for_block node
|
891
928
|
end
|
892
929
|
end
|
930
|
+
pop_scratch node.document if scratch?
|
893
931
|
end
|
894
932
|
theme_margin :block, :bottom
|
895
933
|
end
|
@@ -908,10 +946,10 @@ class Converter < ::Prawn::Document
|
|
908
946
|
end
|
909
947
|
end
|
910
948
|
add_dest_for_block node if node.id
|
911
|
-
@
|
949
|
+
@list_numerals ||= []
|
912
950
|
# FIXME move \u2460 to constant (or theme setting)
|
913
951
|
# \u2460 = circled one, \u24f5 = double circled one, \u278b = negative circled one
|
914
|
-
@
|
952
|
+
@list_numerals << %(\u2460)
|
915
953
|
#stroke_horizontal_rule @theme.caption_border_bottom_color
|
916
954
|
line_metrics = calc_line_metrics @theme.base_line_height
|
917
955
|
node.items.each_with_index do |item, idx|
|
@@ -919,7 +957,7 @@ class Converter < ::Prawn::Document
|
|
919
957
|
advance_page if cursor < (line_metrics.height + line_metrics.leading + line_metrics.padding_top) + 1
|
920
958
|
convert_colist_item item
|
921
959
|
end
|
922
|
-
@
|
960
|
+
@list_numerals.pop
|
923
961
|
# correct bottom margin of last item
|
924
962
|
list_margin_bottom = @theme.prose_margin_bottom
|
925
963
|
margin_bottom list_margin_bottom - @theme.outline_list_item_spacing
|
@@ -931,7 +969,7 @@ class Converter < ::Prawn::Document
|
|
931
969
|
marker_width = rendered_width_of_string %(#{conum_glyph 1}x)
|
932
970
|
float do
|
933
971
|
bounding_box [0, cursor], width: marker_width do
|
934
|
-
@
|
972
|
+
@list_numerals << (index = @list_numerals.pop).next
|
935
973
|
theme_font :conum do
|
936
974
|
layout_prose index, align: :center, line_height: @theme.conum_line_height, inline_format: false, margin: 0
|
937
975
|
end
|
@@ -940,39 +978,46 @@ class Converter < ::Prawn::Document
|
|
940
978
|
end
|
941
979
|
|
942
980
|
indent marker_width do
|
943
|
-
convert_content_for_list_item node, margin_bottom: @theme.outline_list_item_spacing
|
981
|
+
convert_content_for_list_item node, :colist, margin_bottom: @theme.outline_list_item_spacing
|
944
982
|
end
|
945
983
|
end
|
946
984
|
|
947
985
|
def convert_dlist node
|
948
986
|
add_dest_for_block node if node.id
|
949
987
|
|
950
|
-
|
951
|
-
|
952
|
-
|
988
|
+
case node.style
|
989
|
+
when 'qanda'
|
990
|
+
(@list_numerals ||= []) << '1'
|
991
|
+
convert_outline_list node
|
992
|
+
@list_numerals.pop
|
993
|
+
else
|
994
|
+
# TODO check if we're within one line of the bottom of the page
|
995
|
+
# and advance to the next page if so (similar to logic for section titles)
|
996
|
+
layout_caption node.title if node.title?
|
953
997
|
|
954
|
-
|
955
|
-
|
956
|
-
|
957
|
-
|
958
|
-
|
959
|
-
|
960
|
-
|
961
|
-
|
962
|
-
|
963
|
-
|
964
|
-
|
965
|
-
|
966
|
-
|
967
|
-
|
968
|
-
|
969
|
-
|
970
|
-
|
971
|
-
|
972
|
-
|
973
|
-
|
974
|
-
|
975
|
-
|
998
|
+
node.items.each do |terms, desc|
|
999
|
+
terms = [*terms]
|
1000
|
+
# NOTE don't orphan the terms, allow for at least one line of content
|
1001
|
+
# FIXME extract ensure_space (or similar) method
|
1002
|
+
advance_page if cursor < @theme.base_line_height_length * (terms.size + 1)
|
1003
|
+
terms.each do |term|
|
1004
|
+
# FIXME layout_prose should pass style downward when parsing formatted text
|
1005
|
+
#layout_prose term.text, style: @theme.description_list_term_font_style.to_sym, margin_top: 0, margin_bottom: @theme.description_list_term_spacing, align: :left
|
1006
|
+
term_text = term.text
|
1007
|
+
case @theme.description_list_term_font_style.to_sym
|
1008
|
+
when :bold
|
1009
|
+
term_text = %(<strong>#{term_text}</strong>)
|
1010
|
+
when :italic
|
1011
|
+
term_text = %(<em>#{term_text}</em>)
|
1012
|
+
when :bold_italic
|
1013
|
+
term_text = %(<strong><em>#{term_text}</em></strong>)
|
1014
|
+
end
|
1015
|
+
layout_prose term_text, margin_top: 0, margin_bottom: @theme.description_list_term_spacing, align: :left
|
1016
|
+
end
|
1017
|
+
if desc
|
1018
|
+
indent @theme.description_list_description_indent do
|
1019
|
+
convert_content_for_list_item desc, :dlist_desc
|
1020
|
+
end
|
976
1021
|
end
|
977
1022
|
end
|
978
1023
|
end
|
@@ -980,7 +1025,7 @@ class Converter < ::Prawn::Document
|
|
980
1025
|
|
981
1026
|
def convert_olist node
|
982
1027
|
add_dest_for_block node if node.id
|
983
|
-
@
|
1028
|
+
@list_numerals ||= []
|
984
1029
|
# TODO move list_number resolve to a method
|
985
1030
|
list_number = case node.style
|
986
1031
|
when 'arabic'
|
@@ -997,16 +1042,20 @@ class Converter < ::Prawn::Document
|
|
997
1042
|
RomanNumeral.new 'I'
|
998
1043
|
when 'lowergreek'
|
999
1044
|
LowercaseGreekA
|
1045
|
+
when 'unstyled', 'unnumbered', 'no-bullet'
|
1046
|
+
nil
|
1047
|
+
when 'none'
|
1048
|
+
''
|
1000
1049
|
else
|
1001
1050
|
'1'
|
1002
1051
|
end
|
1003
1052
|
# TODO support start values < 1 (issue #498)
|
1004
1053
|
if (start = ((node.attr 'start', nil, false) || ((node.option? 'reversed') ? node.items.size : 1)).to_i) > 1
|
1005
|
-
(start - 1).times { list_number = list_number.next
|
1054
|
+
(start - 1).times { list_number = list_number.next }
|
1006
1055
|
end
|
1007
|
-
@
|
1056
|
+
@list_numerals << list_number
|
1008
1057
|
convert_outline_list node
|
1009
|
-
@
|
1058
|
+
@list_numerals.pop
|
1010
1059
|
end
|
1011
1060
|
|
1012
1061
|
def convert_ulist node
|
@@ -1064,13 +1113,13 @@ class Converter < ::Prawn::Document
|
|
1064
1113
|
complex = false
|
1065
1114
|
# ...or if we want to give all items in the list the same treatment
|
1066
1115
|
#complex = node.items.find(&:complex?) ? true : false
|
1067
|
-
if node.context == :ulist && !@list_bullets[-1]
|
1116
|
+
if (node.context == :ulist && !@list_bullets[-1]) || (node.context == :olist && !@list_numerals[-1])
|
1068
1117
|
if node.style == 'unstyled'
|
1069
1118
|
# unstyled takes away all indentation
|
1070
1119
|
list_indent = 0
|
1071
1120
|
elsif (list_indent = @theme.outline_list_indent) > 0
|
1072
1121
|
# no-bullet aligns text with left-hand side of bullet position (as though there's no bullet)
|
1073
|
-
list_indent = [list_indent - (rendered_width_of_string %(\
|
1122
|
+
list_indent = [list_indent - (rendered_width_of_string %(#{node.context == :ulist ? "\u2022" : '1.'}x)), 0].max
|
1074
1123
|
end
|
1075
1124
|
else
|
1076
1125
|
list_indent = @theme.outline_list_indent
|
@@ -1079,7 +1128,7 @@ class Converter < ::Prawn::Document
|
|
1079
1128
|
node.items.each do |item|
|
1080
1129
|
# FIXME extract to an ensure_space (or similar) method; simplify
|
1081
1130
|
advance_page if cursor < (line_metrics.height + line_metrics.leading + line_metrics.padding_top)
|
1082
|
-
convert_outline_list_item item,
|
1131
|
+
convert_outline_list_item item, node, opts
|
1083
1132
|
end
|
1084
1133
|
end
|
1085
1134
|
# NOTE Children will provide the necessary bottom margin if last item is complex.
|
@@ -1091,33 +1140,48 @@ class Converter < ::Prawn::Document
|
|
1091
1140
|
end
|
1092
1141
|
end
|
1093
1142
|
|
1094
|
-
def convert_outline_list_item node,
|
1143
|
+
def convert_outline_list_item node, list, opts = {}
|
1095
1144
|
# TODO move this to a draw_bullet (or draw_marker) method
|
1096
1145
|
marker_style = {}
|
1097
1146
|
marker_style[:font_color] = @theme.outline_list_marker_font_color || @font_color
|
1098
1147
|
marker_style[:font_family] = font_family
|
1099
1148
|
marker_style[:font_size] = font_size
|
1100
1149
|
marker_style[:line_height] = @theme.base_line_height
|
1101
|
-
case (list_type =
|
1150
|
+
case (list_type = list.context)
|
1102
1151
|
when :ulist
|
1103
|
-
|
1104
|
-
if marker_type
|
1105
|
-
|
1106
|
-
|
1107
|
-
|
1108
|
-
|
1152
|
+
complex = node.complex?
|
1153
|
+
if (marker_type = @list_bullets[-1])
|
1154
|
+
if marker_type == :checkbox
|
1155
|
+
# QUESTION should we remove marker indent if not a checkbox?
|
1156
|
+
if node.attr? 'checkbox', nil, false
|
1157
|
+
marker_type = (node.attr? 'checked', nil, false) ? :checked : :unchecked
|
1158
|
+
marker = @theme[%(ulist_marker_#{marker_type}_content)] || BallotBox[marker_type]
|
1159
|
+
end
|
1160
|
+
else
|
1161
|
+
marker = @theme[%(ulist_marker_#{marker_type}_content)] || Bullets[marker_type]
|
1109
1162
|
end
|
1110
|
-
|
1111
|
-
|
1163
|
+
[:font_color, :font_family, :font_size, :line_height].each do |prop|
|
1164
|
+
marker_style[prop] = @theme[%(ulist_marker_#{marker_type}_#{prop})] || @theme[%(ulist_marker_#{prop})] || marker_style[prop]
|
1165
|
+
end if marker
|
1112
1166
|
end
|
1113
|
-
[:font_color, :font_family, :font_size, :line_height].each do |prop|
|
1114
|
-
marker_style[prop] = @theme[%(ulist_marker_#{marker_type}_#{prop})] || @theme[%(ulist_marker_#{prop})] || marker_style[prop]
|
1115
|
-
end if marker
|
1116
1167
|
when :olist
|
1117
|
-
|
1118
|
-
|
1168
|
+
complex = node.complex?
|
1169
|
+
if (index = @list_numerals.pop)
|
1170
|
+
if index.empty?
|
1171
|
+
marker = ''
|
1172
|
+
else
|
1173
|
+
marker = %(#{index}.)
|
1174
|
+
dir = (node.parent.option? 'reversed') ? :pred : :next
|
1175
|
+
@list_numerals << (index = index.public_send dir)
|
1176
|
+
end
|
1177
|
+
end
|
1178
|
+
when :dlist
|
1179
|
+
# NOTE list.style is 'qanda'
|
1180
|
+
complex = node[1] && node[1].complex?
|
1181
|
+
@list_numerals << (index = @list_numerals.pop).next
|
1119
1182
|
marker = %(#{index}.)
|
1120
1183
|
else
|
1184
|
+
complex = node.complex?
|
1121
1185
|
logger.warn %(unknown list type #{list_type.inspect})
|
1122
1186
|
marker = @theme.ulist_marker_disc_content || Bullets[:disc]
|
1123
1187
|
end
|
@@ -1148,15 +1212,24 @@ class Converter < ::Prawn::Document
|
|
1148
1212
|
end
|
1149
1213
|
|
1150
1214
|
if complex
|
1151
|
-
convert_content_for_list_item node, opts
|
1215
|
+
convert_content_for_list_item node, list_type, opts
|
1152
1216
|
else
|
1153
|
-
convert_content_for_list_item node, (opts.merge margin_bottom: @theme.outline_list_item_spacing)
|
1217
|
+
convert_content_for_list_item node, list_type, (opts.merge margin_bottom: @theme.outline_list_item_spacing)
|
1154
1218
|
end
|
1155
1219
|
end
|
1156
1220
|
|
1157
|
-
def convert_content_for_list_item node, opts = {}
|
1158
|
-
|
1159
|
-
|
1221
|
+
def convert_content_for_list_item node, list_type, opts = {}
|
1222
|
+
if list_type == :dlist # qanda
|
1223
|
+
terms, desc = node
|
1224
|
+
[*terms].each {|term| layout_prose %(<em>#{term.text}</em>), opts }
|
1225
|
+
if desc
|
1226
|
+
layout_prose desc.text, opts if desc.text?
|
1227
|
+
convert_content_for_block desc
|
1228
|
+
end
|
1229
|
+
else
|
1230
|
+
layout_prose node.text, opts if node.text?
|
1231
|
+
convert_content_for_block node
|
1232
|
+
end
|
1160
1233
|
end
|
1161
1234
|
|
1162
1235
|
def convert_image node, opts = {}
|
@@ -1330,10 +1403,8 @@ class Converter < ::Prawn::Document
|
|
1330
1403
|
::OpenURI
|
1331
1404
|
end
|
1332
1405
|
poster = open(%(http://vimeo.com/api/v2/video/#{video_id}.xml), 'r') do |f|
|
1333
|
-
|
1406
|
+
/<thumbnail_large>(.*?)<\/thumbnail_large>/ =~ f.read && $1
|
1334
1407
|
end
|
1335
|
-
else
|
1336
|
-
poster = nil
|
1337
1408
|
end
|
1338
1409
|
type = 'Vimeo video'
|
1339
1410
|
else
|
@@ -1366,13 +1437,27 @@ class Converter < ::Prawn::Document
|
|
1366
1437
|
|
1367
1438
|
# HACK disable built-in syntax highlighter; must be done before calling node.content!
|
1368
1439
|
if node.style == 'source' && node.attributes['language'] &&
|
1369
|
-
(highlighter = node.document.attributes['source-highlighter']) &&
|
1370
|
-
(
|
1440
|
+
(highlighter = node.document.attributes['source-highlighter']) && (SourceHighlighters.include? highlighter) &&
|
1441
|
+
(@capabilities[:syntax_highlighter] ? node.document.syntax_highlighter.highlight? : true)
|
1442
|
+
case highlighter
|
1443
|
+
when 'coderay'
|
1444
|
+
unless defined? ::Asciidoctor::Prawn::CodeRayEncoder
|
1445
|
+
highlighter = nil if (Helpers.require_library CodeRayRequirePath, 'coderay', :warn).nil?
|
1446
|
+
end
|
1447
|
+
when 'pygments'
|
1448
|
+
unless defined? ::Pygments
|
1449
|
+
highlighter = nil if (Helpers.require_library 'pygments', 'pygments.rb', :warn).nil?
|
1450
|
+
end
|
1451
|
+
when 'rouge'
|
1452
|
+
unless defined? ::Rouge::Formatters::Prawn
|
1453
|
+
highlighter = nil if (Helpers.require_library RougeRequirePath, 'rouge', :warn).nil?
|
1454
|
+
end
|
1455
|
+
end
|
1371
1456
|
prev_subs = (subs = node.subs).dup
|
1372
|
-
# NOTE the highlight sub is only set for coderay and pygments atm
|
1457
|
+
# NOTE the highlight sub is only set for coderay, rouge, and pygments atm
|
1373
1458
|
highlight_idx = subs.index :highlight
|
1374
1459
|
# NOTE scratch? here only applies if listing block is nested inside another block
|
1375
|
-
if scratch?
|
1460
|
+
if !highlighter || scratch?
|
1376
1461
|
highlighter = nil
|
1377
1462
|
if highlight_idx
|
1378
1463
|
# switch the :highlight sub back to :specialcharacters
|
@@ -1401,7 +1486,6 @@ class Converter < ::Prawn::Document
|
|
1401
1486
|
|
1402
1487
|
source_chunks = case highlighter
|
1403
1488
|
when 'coderay'
|
1404
|
-
Helpers.require_library CodeRayRequirePath, 'coderay' unless defined? ::Asciidoctor::Prawn::CodeRayEncoder
|
1405
1489
|
source_string, conum_mapping = extract_conums source_string
|
1406
1490
|
srclang = node.attr 'language', 'text', false
|
1407
1491
|
begin
|
@@ -1412,7 +1496,6 @@ class Converter < ::Prawn::Document
|
|
1412
1496
|
fragments = (::CodeRay.scan source_string, srclang).to_prawn
|
1413
1497
|
conum_mapping ? (restore_conums fragments, conum_mapping) : fragments
|
1414
1498
|
when 'pygments'
|
1415
|
-
Helpers.require_library 'pygments', 'pygments.rb' unless defined? ::Pygments
|
1416
1499
|
lexer = ::Pygments::Lexer.find_by_alias(node.attr 'language', 'text', false) || ::Pygments::Lexer.find_by_mimetype('text/plain')
|
1417
1500
|
lexer_opts = {
|
1418
1501
|
nowrap: true,
|
@@ -1451,7 +1534,6 @@ class Converter < ::Prawn::Document
|
|
1451
1534
|
fragments = restore_conums fragments, conum_mapping, num_trailing_spaces, linenums if conum_mapping
|
1452
1535
|
fragments = guard_indentation fragments
|
1453
1536
|
when 'rouge'
|
1454
|
-
Helpers.require_library RougeRequirePath, 'rouge' unless defined? ::Rouge::Formatters::Prawn
|
1455
1537
|
lexer = ::Rouge::Lexer.find(node.attr 'language', 'text', false) || ::Rouge::Lexers::PlainText
|
1456
1538
|
lexer_opts = lexer.tag == 'php' ? { start_inline: !(node.option? 'mixed') } : {}
|
1457
1539
|
formatter = (@rouge_formatter ||= ::Rouge::Formatters::Prawn.new theme: (node.document.attr 'rouge-style'), line_gap: @theme.code_line_gap)
|
@@ -1533,15 +1615,16 @@ class Converter < ::Prawn::Document
|
|
1533
1615
|
# and the mapping of lines to conums as the second.
|
1534
1616
|
def extract_conums string
|
1535
1617
|
conum_mapping = {}
|
1618
|
+
auto_num = 0
|
1536
1619
|
string = string.split(LF).map.with_index {|line, line_num|
|
1537
1620
|
# FIXME we get extra spaces before numbers if more than one on a line
|
1538
1621
|
if line.include? '<'
|
1539
1622
|
line.gsub(CalloutExtractRx) {
|
1540
1623
|
# honor the escape
|
1541
|
-
if $1 ==
|
1542
|
-
$&.sub
|
1624
|
+
if $1 == ?\\
|
1625
|
+
$&.sub $1, ''
|
1543
1626
|
else
|
1544
|
-
(conum_mapping[line_num] ||= []) << $3.to_i
|
1627
|
+
(conum_mapping[line_num] ||= []) << ($3 == '.' ? (auto_num += 1) : $3.to_i)
|
1545
1628
|
''
|
1546
1629
|
end
|
1547
1630
|
}
|
@@ -1748,7 +1831,9 @@ class Converter < ::Prawn::Document
|
|
1748
1831
|
cell_line_metrics = calc_line_metrics theme.base_line_height
|
1749
1832
|
end
|
1750
1833
|
if cell_line_metrics
|
1751
|
-
|
1834
|
+
if ::Array === (cell_padding = cell_data[:padding]) && cell_padding.size == 4
|
1835
|
+
cell_padding = cell_padding.dup
|
1836
|
+
else
|
1752
1837
|
cell_padding = cell_data[:padding] = inflate_padding cell_padding
|
1753
1838
|
end
|
1754
1839
|
cell_padding[0] += cell_line_metrics.padding_top
|
@@ -2026,7 +2111,7 @@ class Converter < ::Prawn::Document
|
|
2026
2111
|
elsif (@media ||= node.document.attr 'media', 'screen') != 'screen' || (node.document.attr? 'show-link-uri')
|
2027
2112
|
# QUESTION should we insert breakable chars into URI when building fragment instead?
|
2028
2113
|
# TODO allow style of printed link to be controlled by theme
|
2029
|
-
%(<a href="#{target = node.target}"#{attrs.join}>#{node.text}</a> [<font size="0.85em">#{breakable_uri target}</font
|
2114
|
+
%(<a href="#{target = node.target}"#{attrs.join}>#{node.text}</a> [<font size="0.85em">#{breakable_uri target}</font>])
|
2030
2115
|
else
|
2031
2116
|
%(<a href="#{node.target}"#{attrs.join}>#{node.text}</a>)
|
2032
2117
|
end
|
@@ -2038,18 +2123,18 @@ class Converter < ::Prawn::Document
|
|
2038
2123
|
%(<a href="#{node.target}">#{node.text || path}</a>)
|
2039
2124
|
elsif (refid = node.attributes['refid'])
|
2040
2125
|
unless (text = node.text)
|
2041
|
-
if (refs = node.document.
|
2126
|
+
if (refs = node.document.catalog[:refs])
|
2042
2127
|
if ::Asciidoctor::AbstractNode === (ref = refs[refid])
|
2043
2128
|
text = ref.xreftext((@xrefstyle ||= (node.document.attr 'xrefstyle')))
|
2044
2129
|
end
|
2045
2130
|
else
|
2046
2131
|
# Asciidoctor < 1.5.6
|
2047
|
-
text = node.document.
|
2132
|
+
text = node.document.catalog[:ids][refid]
|
2048
2133
|
end
|
2049
2134
|
end
|
2050
|
-
%(<a anchor="#{derive_anchor_from_id refid}">#{text || "[#{refid}]"}</a>)
|
2135
|
+
%(<a anchor="#{derive_anchor_from_id refid}">#{text || "[#{refid}]"}</a>).gsub ']', ']'
|
2051
2136
|
else
|
2052
|
-
%(<a anchor="#{node.document.attr 'pdf-anchor'}">#{node.text || '[^top
|
2137
|
+
%(<a anchor="#{node.document.attr 'pdf-anchor'}">#{node.text || '[^top]'}</a>)
|
2053
2138
|
end
|
2054
2139
|
when :ref
|
2055
2140
|
# NOTE destination is created inside callback registered by FormattedTextTransform#build_fragment
|
@@ -2058,9 +2143,14 @@ class Converter < ::Prawn::Document
|
|
2058
2143
|
when :bibref
|
2059
2144
|
# NOTE destination is created inside callback registered by FormattedTextTransform#build_fragment
|
2060
2145
|
# NOTE technically node.text should be node.reftext, but subs have already been applied to text
|
2061
|
-
# NOTE
|
2146
|
+
# NOTE reftext is no longer enclosed in [] starting in Asciidoctor 2.0.0
|
2062
2147
|
# NOTE id is used instead of target starting in Asciidoctor 2.0.0
|
2063
|
-
|
2148
|
+
if (reftext = node.reftext)
|
2149
|
+
reftext = %([#{reftext}]) unless reftext.start_with? '['
|
2150
|
+
else
|
2151
|
+
reftext = %([#{node.target || node.id}])
|
2152
|
+
end
|
2153
|
+
%(<a name="#{node.target || node.id}">#{DummyText}</a>#{reftext})
|
2064
2154
|
else
|
2065
2155
|
logger.warn %(unknown anchor type: #{node.type.inspect})
|
2066
2156
|
end
|
@@ -2166,7 +2256,7 @@ class Converter < ::Prawn::Document
|
|
2166
2256
|
node.type == :visible ? node.text : ''
|
2167
2257
|
else
|
2168
2258
|
dest = {
|
2169
|
-
anchor: (anchor_name =
|
2259
|
+
anchor: (anchor_name = @index.next_anchor_name)
|
2170
2260
|
# NOTE page number is added in InlineDestinationMarker
|
2171
2261
|
}
|
2172
2262
|
anchor = %(<a name="#{anchor_name}" type="indexterm">#{DummyText}</a>)
|
@@ -2270,9 +2360,7 @@ class Converter < ::Prawn::Document
|
|
2270
2360
|
relative_to_imagesdir = false
|
2271
2361
|
end
|
2272
2362
|
# HACK quick fix to resolve image path relative to theme
|
2273
|
-
unless doc.attr? 'title-logo-image'
|
2274
|
-
logo_image_path = ThemeLoader.resolve_theme_asset logo_image_path, (doc.attr 'pdf-stylesdir')
|
2275
|
-
end
|
2363
|
+
logo_image_path = ThemeLoader.resolve_theme_asset logo_image_path, (doc.attr 'pdf-stylesdir') unless doc.attr? 'title-logo-image'
|
2276
2364
|
logo_image_attrs['target'] = logo_image_path
|
2277
2365
|
logo_image_attrs['align'] ||= (@theme.title_page_logo_align || title_align.to_s)
|
2278
2366
|
# QUESTION should we allow theme to turn logo image off?
|
@@ -2287,7 +2375,9 @@ class Converter < ::Prawn::Document
|
|
2287
2375
|
# FIXME add API to Asciidoctor for creating blocks like this (extract from extensions module?)
|
2288
2376
|
image_block = ::Asciidoctor::Block.new doc, :image, content_model: :empty, attributes: logo_image_attrs
|
2289
2377
|
# NOTE pinned option keeps image on same page
|
2290
|
-
|
2378
|
+
indent (@theme.title_page_logo_margin_left || 0), (@theme.title_page_logo_margin_right || 0) do
|
2379
|
+
convert_image image_block, relative_to_imagesdir: relative_to_imagesdir, pinned: true
|
2380
|
+
end
|
2291
2381
|
@y = initial_y
|
2292
2382
|
end
|
2293
2383
|
|
@@ -2304,34 +2394,40 @@ class Converter < ::Prawn::Document
|
|
2304
2394
|
@y = title_top
|
2305
2395
|
end
|
2306
2396
|
move_down(@theme.title_page_title_margin_top || 0)
|
2307
|
-
|
2308
|
-
|
2309
|
-
|
2310
|
-
|
2311
|
-
|
2397
|
+
indent (@theme.title_page_title_margin_left || 0), (@theme.title_page_title_margin_right || 0) do
|
2398
|
+
theme_font :title_page_title do
|
2399
|
+
layout_heading doctitle.main,
|
2400
|
+
align: title_align,
|
2401
|
+
margin: 0,
|
2402
|
+
line_height: @theme.title_page_title_line_height
|
2403
|
+
end
|
2312
2404
|
end
|
2313
2405
|
move_down(@theme.title_page_title_margin_bottom || 0)
|
2314
2406
|
if doctitle.subtitle
|
2315
2407
|
move_down(@theme.title_page_subtitle_margin_top || 0)
|
2316
|
-
|
2317
|
-
|
2318
|
-
|
2319
|
-
|
2320
|
-
|
2408
|
+
indent (@theme.title_page_subtitle_margin_left || 0), (@theme.title_page_subtitle_margin_right || 0) do
|
2409
|
+
theme_font :title_page_subtitle do
|
2410
|
+
layout_heading doctitle.subtitle,
|
2411
|
+
align: title_align,
|
2412
|
+
margin: 0,
|
2413
|
+
line_height: @theme.title_page_subtitle_line_height
|
2414
|
+
end
|
2321
2415
|
end
|
2322
2416
|
move_down(@theme.title_page_subtitle_margin_bottom || 0)
|
2323
2417
|
end
|
2324
2418
|
if doc.attr? 'authors'
|
2325
2419
|
move_down(@theme.title_page_authors_margin_top || 0)
|
2326
|
-
|
2327
|
-
|
2328
|
-
doc.attr
|
2329
|
-
|
2330
|
-
|
2331
|
-
|
2332
|
-
|
2333
|
-
|
2334
|
-
|
2420
|
+
indent (@theme.title_page_authors_margin_left || 0), (@theme.title_page_authors_margin_right || 0) do
|
2421
|
+
# TODO provide an API in core to get authors as an array
|
2422
|
+
authors = (1..(doc.attr 'authorcount', 1).to_i).map {|idx|
|
2423
|
+
doc.attr(idx == 1 ? 'author' : %(author_#{idx}))
|
2424
|
+
} * (@theme.title_page_authors_delimiter || ', ')
|
2425
|
+
theme_font :title_page_authors do
|
2426
|
+
layout_prose authors,
|
2427
|
+
align: title_align,
|
2428
|
+
margin: 0,
|
2429
|
+
normalize: false
|
2430
|
+
end
|
2335
2431
|
end
|
2336
2432
|
move_down(@theme.title_page_authors_margin_bottom || 0)
|
2337
2433
|
end
|
@@ -2339,11 +2435,13 @@ class Converter < ::Prawn::Document
|
|
2339
2435
|
unless revision_info.empty?
|
2340
2436
|
move_down(@theme.title_page_revision_margin_top || 0)
|
2341
2437
|
revision_text = revision_info * (@theme.title_page_revision_delimiter || ', ')
|
2342
|
-
|
2343
|
-
|
2344
|
-
|
2345
|
-
|
2346
|
-
|
2438
|
+
indent (@theme.title_page_revision_margin_left || 0), (@theme.title_page_revision_margin_right || 0) do
|
2439
|
+
theme_font :title_page_revision do
|
2440
|
+
layout_prose revision_text,
|
2441
|
+
align: title_align,
|
2442
|
+
margin: 0,
|
2443
|
+
normalize: false
|
2444
|
+
end
|
2347
2445
|
end
|
2348
2446
|
move_down(@theme.title_page_revision_margin_bottom || 0)
|
2349
2447
|
end
|
@@ -2505,8 +2603,8 @@ class Converter < ::Prawn::Document
|
|
2505
2603
|
layout_heading((doc.attr 'toc-title'), align: toc_title_align)
|
2506
2604
|
end
|
2507
2605
|
end
|
2508
|
-
# QUESTION should we skip this whole method if num_levels
|
2509
|
-
|
2606
|
+
# QUESTION should we skip this whole method if num_levels < 0?
|
2607
|
+
unless num_levels < 0
|
2510
2608
|
dot_leader = theme_font :toc do
|
2511
2609
|
# TODO we could simplify by using nested theme_font :toc_dot_leader
|
2512
2610
|
if (dot_leader_font_style = (@theme.toc_dot_leader_font_style || :normal).to_sym) != font_style
|
@@ -2618,7 +2716,8 @@ class Converter < ::Prawn::Document
|
|
2618
2716
|
|
2619
2717
|
# TODO delegate to layout_page_header and layout_page_footer per page
|
2620
2718
|
def layout_running_content periphery, doc, opts = {}
|
2621
|
-
skip = opts[:skip] || 1
|
2719
|
+
skip, skip_pagenums, body_start_page_number = opts[:skip] || [1, 1]
|
2720
|
+
body_start_page_number = opts[:body_start_page_number] || 1
|
2622
2721
|
# NOTE find and advance to first non-imported content page to use as model page
|
2623
2722
|
return unless (content_start_page = state.pages[skip..-1].index {|p| !p.imported_page? })
|
2624
2723
|
content_start_page += (skip + 1)
|
@@ -2640,7 +2739,7 @@ class Converter < ::Prawn::Document
|
|
2640
2739
|
section_start_pages = {}
|
2641
2740
|
trailing_section_start_pages = {}
|
2642
2741
|
sections.each do |sect|
|
2643
|
-
page_num = (sect.attr 'pdf-page-start').to_i -
|
2742
|
+
page_num = (sect.attr 'pdf-page-start').to_i - skip_pagenums
|
2644
2743
|
if is_book && ((sect_is_part = sect.part?) || sect.chapter?)
|
2645
2744
|
if sect_is_part
|
2646
2745
|
part_start_pages[page_num] ||= (sect.numbered_title formal: true)
|
@@ -2663,8 +2762,8 @@ class Converter < ::Prawn::Document
|
|
2663
2762
|
sections_by_page = {}
|
2664
2763
|
# QUESTION should the default part be the doctitle?
|
2665
2764
|
last_part = nil
|
2666
|
-
# QUESTION should we enforce that the preamble is preface?
|
2667
|
-
last_chap = is_book ?
|
2765
|
+
# QUESTION should we enforce that the preamble is a preface?
|
2766
|
+
last_chap = is_book ? :pre : nil
|
2668
2767
|
last_sect = nil
|
2669
2768
|
sect_search_threshold = 1
|
2670
2769
|
(1..num_pages).each do |num|
|
@@ -2691,7 +2790,17 @@ class Converter < ::Prawn::Document
|
|
2691
2790
|
end
|
2692
2791
|
end
|
2693
2792
|
parts_by_page[num] = last_part
|
2694
|
-
|
2793
|
+
if last_chap == :pre
|
2794
|
+
if num == 1
|
2795
|
+
chapters_by_page[num] = doc.doctitle
|
2796
|
+
elsif num >= body_start_page_number
|
2797
|
+
chapters_by_page[num] = is_book ? (doc.attr 'preface-title', 'Preface') : nil
|
2798
|
+
else
|
2799
|
+
chapters_by_page[num] = doc.attr 'toc-title'
|
2800
|
+
end
|
2801
|
+
else
|
2802
|
+
chapters_by_page[num] = last_chap
|
2803
|
+
end
|
2695
2804
|
sections_by_page[num] = last_sect
|
2696
2805
|
end
|
2697
2806
|
|
@@ -2709,7 +2818,7 @@ class Converter < ::Prawn::Document
|
|
2709
2818
|
trim_top = page_height
|
2710
2819
|
# NOTE height is required atm
|
2711
2820
|
trim_height = @theme.header_height || page_margin_top
|
2712
|
-
trim_padding = @theme.header_padding ||
|
2821
|
+
trim_padding = inflate_padding @theme.header_padding || 0
|
2713
2822
|
trim_bg_color = resolve_theme_color :header_background_color
|
2714
2823
|
trim_border_width = @theme.header_border_width || @theme.base_border_width
|
2715
2824
|
trim_border_style = (@theme.header_border_style || :solid).to_sym
|
@@ -2720,7 +2829,7 @@ class Converter < ::Prawn::Document
|
|
2720
2829
|
trim_line_metrics = calc_line_metrics(@theme.footer_line_height || @theme.base_line_height)
|
2721
2830
|
# NOTE height is required atm
|
2722
2831
|
trim_top = trim_height = @theme.footer_height || page_margin_bottom
|
2723
|
-
trim_padding = @theme.footer_padding ||
|
2832
|
+
trim_padding = inflate_padding @theme.footer_padding || 0
|
2724
2833
|
trim_bg_color = resolve_theme_color :footer_background_color
|
2725
2834
|
trim_border_width = @theme.footer_border_width || @theme.base_border_width
|
2726
2835
|
trim_border_style = (@theme.footer_border_style || :solid).to_sym
|
@@ -2804,21 +2913,25 @@ class Converter < ::Prawn::Document
|
|
2804
2913
|
ColumnPositions.each do |position|
|
2805
2914
|
unless (val = @theme[%(#{periphery}_#{side}_#{position}_content)]).nil_or_empty?
|
2806
2915
|
# TODO support image URL (using resolve_image_path)
|
2807
|
-
if (val.include? ':') && val =~ ImageAttributeValueRx
|
2808
|
-
|
2809
|
-
|
2810
|
-
|
2811
|
-
|
2812
|
-
|
2813
|
-
|
2814
|
-
|
2815
|
-
|
2816
|
-
|
2817
|
-
|
2916
|
+
if (val.include? ':') && val =~ ImageAttributeValueRx
|
2917
|
+
if ::File.readable?(path = (ThemeLoader.resolve_theme_asset $1, (doc.attr 'pdf-stylesdir')))
|
2918
|
+
attrs = (AttributeList.new $2).parse
|
2919
|
+
col_width = colspec_dict[side][position][:width]
|
2920
|
+
if (fit = attrs['fit']) == 'contain'
|
2921
|
+
width = col_width
|
2922
|
+
else
|
2923
|
+
unless (width = resolve_explicit_width attrs, col_width)
|
2924
|
+
# QUESTION should we lookup and scale intrinsic width if explicit width is not given?
|
2925
|
+
# NOTE failure message will be reported later when image is rendered
|
2926
|
+
width = (to_pt intrinsic_image_dimensions(path)[:width], :px) rescue 0
|
2927
|
+
end
|
2928
|
+
width = col_width if fit == 'scale-down' && width > col_width
|
2818
2929
|
end
|
2819
|
-
|
2930
|
+
side_content[position] = { path: path, width: width, fit: !!fit }
|
2931
|
+
else
|
2932
|
+
logger.warn %(image to embed not found or not readable: #{path})
|
2933
|
+
side_content[position] = val
|
2820
2934
|
end
|
2821
|
-
side_content[position] = { path: path, width: width, fit: !!fit }
|
2822
2935
|
else
|
2823
2936
|
side_content[position] = val
|
2824
2937
|
end
|
@@ -2875,7 +2988,8 @@ class Converter < ::Prawn::Document
|
|
2875
2988
|
repeat((content_start_page..page_count), dynamic: true) do
|
2876
2989
|
# NOTE don't write on pages which are imported / inserts (otherwise we can get a corrupt PDF)
|
2877
2990
|
next if page.imported_page?
|
2878
|
-
pgnum_label = page_number -
|
2991
|
+
pgnum_label = page_number - skip_pagenums
|
2992
|
+
pgnum_label = (RomanNumeral.new page_number, :lower) if pgnum_label < 1
|
2879
2993
|
side = page_side((folio_basis == :physical ? page_number : pgnum_label), invert_folio)
|
2880
2994
|
# FIXME we need to have a content setting for chapter pages
|
2881
2995
|
content_by_position, colspec_by_position = content_dict[side], colspec_dict[side]
|
@@ -2943,13 +3057,13 @@ class Converter < ::Prawn::Document
|
|
2943
3057
|
doc.set_attr 'attribute-missing', 'skip' unless attribute_missing_doc == 'skip'
|
2944
3058
|
if (content = doc.apply_subs content).include? '{'
|
2945
3059
|
# NOTE must use { in place of {, not \{, to escape attribute reference
|
2946
|
-
content = content.split(LF).delete_if {|line| SimpleAttributeRefRx
|
3060
|
+
content = content.split(LF).delete_if {|line| SimpleAttributeRefRx.match? line } * LF
|
2947
3061
|
end
|
2948
3062
|
doc.set_attr 'attribute-missing', attribute_missing_doc unless attribute_missing_doc == 'skip'
|
2949
3063
|
end
|
2950
3064
|
theme_font %(#{periphery}_#{side}_#{position}) do
|
2951
3065
|
formatted_text_box parse_text(content, color: @font_color, inline_format: [normalize: true]),
|
2952
|
-
at: [colspec[:x],
|
3066
|
+
at: [colspec[:x], trim_top - trim_padding[0] + (trim_valign == :center ? font.descender * 0.5 : 0)],
|
2953
3067
|
width: colspec[:width],
|
2954
3068
|
height: trim_content_height,
|
2955
3069
|
align: colspec[:align],
|
@@ -3540,6 +3654,8 @@ class Converter < ::Prawn::Document
|
|
3540
3654
|
|
3541
3655
|
# QUESTION move to prawn/extensions.rb?
|
3542
3656
|
def init_scratch_prototype
|
3657
|
+
@save_state = nil
|
3658
|
+
@scratch_depth = 0
|
3543
3659
|
# IMPORTANT don't set font before using Marshal, it causes serialization to fail
|
3544
3660
|
@prototype = ::Marshal.load ::Marshal.dump self
|
3545
3661
|
@prototype.state.store.info.data[:Scratch] = true
|
@@ -3547,6 +3663,23 @@ class Converter < ::Prawn::Document
|
|
3547
3663
|
#@prototype.start_new_page if @prototype.page_number == 0
|
3548
3664
|
end
|
3549
3665
|
|
3666
|
+
def push_scratch doc
|
3667
|
+
if (@scratch_depth += 1) == 1
|
3668
|
+
@save_state = {
|
3669
|
+
catalog: {}.tap {|accum| doc.catalog.each {|k, v| accum[k] = v.dup } },
|
3670
|
+
attributes: doc.attributes.dup,
|
3671
|
+
}
|
3672
|
+
end
|
3673
|
+
end
|
3674
|
+
|
3675
|
+
def pop_scratch doc
|
3676
|
+
if (@scratch_depth -= 1) == 0
|
3677
|
+
doc.catalog.replace @save_state[:catalog]
|
3678
|
+
doc.attributes.replace @save_state[:attributes]
|
3679
|
+
@save_state = nil
|
3680
|
+
end
|
3681
|
+
end
|
3682
|
+
|
3550
3683
|
=begin
|
3551
3684
|
# TODO could assign pdf-anchor attributes here too
|
3552
3685
|
def assign_missing_section_ids doc
|