idml 0.7.3 → 0.7.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/TODO.pdf/115-bullet-numbered-lists.md +4 -1
- data/lib/idml/render/list_marker.rb +63 -0
- data/lib/idml/render/style_resolver.rb +24 -1
- data/lib/idml/render.rb +1 -0
- data/lib/idml/version.rb +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2f60e795f4325dcc4006a28915a18baf7069e21767694ca670c41f84db62d98d
|
|
4
|
+
data.tar.gz: 4f1f4846d41050b518c8add338ce431951b45ea58891b2c56154b47e59478bc7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bbf7caac497ce2ab01a8c35af7bad78a24b7a706db6baa582b7d416cae1ce4995f18a3903379c4e994ab49ca1f28efd33e162821dead95250ae8248c041d16cd
|
|
7
|
+
data.tar.gz: ed5d2ae0abf40c0c6bf101d3c05ca35f59bc48aefed14366de7f5ac0f15979ff458ca7cf8493d012c4f6a78b0c1889815f987ea3dc9f24971f31ae34583f6fc4
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
# TODO PDF 115: Bullet and numbered list rendering
|
|
2
2
|
|
|
3
|
-
## Status:
|
|
3
|
+
## Status: DONE for inline marker emission. Hanging-indent layout
|
|
4
|
+
(bullet in a left gutter with wrapped lines indented to align with
|
|
5
|
+
text after marker) is a follow-up — currently the marker sits inline
|
|
6
|
+
before the first run's text.
|
|
4
7
|
|
|
5
8
|
## Problem
|
|
6
9
|
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# frozen_string: true
|
|
2
|
+
|
|
3
|
+
module Idml
|
|
4
|
+
module Render
|
|
5
|
+
# Produces a list-marker string for a paragraph (bullet glyph or
|
|
6
|
+
# numbered-list expression). IDML stores the resolved marker
|
|
7
|
+
# directly on the PSR (BulletCharacterValue as a Unicode codepoint,
|
|
8
|
+
# NumberingExpression as the rendered text), so the renderer
|
|
9
|
+
# doesn't need to maintain its own counter.
|
|
10
|
+
#
|
|
11
|
+
# Used by `StyleResolver` to prepend the marker to the paragraph's
|
|
12
|
+
# first run's text. The marker becomes part of the run's natural
|
|
13
|
+
# text flow — no special positioning needed for MVP.
|
|
14
|
+
#
|
|
15
|
+
# Hanging-indent layout (bullet aligned in a left gutter with
|
|
16
|
+
# wrapped lines indented to align with text after the marker) is
|
|
17
|
+
# a follow-up; for now the marker sits inline before the text.
|
|
18
|
+
module ListMarker
|
|
19
|
+
DEFAULT_BULLET = "•".freeze # BULLET
|
|
20
|
+
DEFAULT_TEXT_AFTER = "\t".freeze
|
|
21
|
+
|
|
22
|
+
# Returns the marker string for the paragraph, or nil when the
|
|
23
|
+
# paragraph isn't part of a list.
|
|
24
|
+
def self.marker_for(paragraph)
|
|
25
|
+
return nil unless paragraph
|
|
26
|
+
|
|
27
|
+
case paragraph.bullets_and_numbering_list_type
|
|
28
|
+
when "BulletList" then bullet_marker(paragraph)
|
|
29
|
+
when "NumberedList" then numbered_marker(paragraph)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def self.bullet_marker(paragraph)
|
|
34
|
+
bullet = bullet_char(paragraph)
|
|
35
|
+
suffix = text_after(paragraph)
|
|
36
|
+
"#{bullet}#{suffix}"
|
|
37
|
+
end
|
|
38
|
+
private_class_method :bullet_marker
|
|
39
|
+
|
|
40
|
+
def self.numbered_marker(paragraph)
|
|
41
|
+
expr = paragraph.numbering_expression
|
|
42
|
+
return nil if expr.nil? || expr.empty?
|
|
43
|
+
|
|
44
|
+
suffix = text_after(paragraph)
|
|
45
|
+
"#{expr}#{suffix}"
|
|
46
|
+
end
|
|
47
|
+
private_class_method :numbered_marker
|
|
48
|
+
|
|
49
|
+
def self.bullet_char(paragraph)
|
|
50
|
+
codepoint = paragraph.bullet_character_value
|
|
51
|
+
return DEFAULT_BULLET unless codepoint&.positive?
|
|
52
|
+
|
|
53
|
+
[codepoint].pack("U")
|
|
54
|
+
end
|
|
55
|
+
private_class_method :bullet_char
|
|
56
|
+
|
|
57
|
+
def self.text_after(paragraph)
|
|
58
|
+
paragraph.bullets_text_after || DEFAULT_TEXT_AFTER
|
|
59
|
+
end
|
|
60
|
+
private_class_method :text_after
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -55,6 +55,10 @@ module Idml
|
|
|
55
55
|
:right_indent,
|
|
56
56
|
:auto_leading,
|
|
57
57
|
:drop_cap_lines,
|
|
58
|
+
:bullets_and_numbering_list_type,
|
|
59
|
+
:bullet_character_value,
|
|
60
|
+
:bullets_text_after,
|
|
61
|
+
:numbering_expression,
|
|
58
62
|
:drop_cap_characters,
|
|
59
63
|
# RuleAbove / RuleBelow — paragraph rules (horizontal lines
|
|
60
64
|
# above/below the paragraph block). Driven by PSR attributes.
|
|
@@ -115,7 +119,7 @@ module Idml
|
|
|
115
119
|
runs = csr_runs(psr, condition_filter: condition_filter)
|
|
116
120
|
next if runs.empty?
|
|
117
121
|
|
|
118
|
-
Paragraph.new(
|
|
122
|
+
paragraph = Paragraph.new(
|
|
119
123
|
runs: runs,
|
|
120
124
|
alignment: runs.first.alignment,
|
|
121
125
|
space_before: psr.space_before,
|
|
@@ -126,6 +130,10 @@ module Idml
|
|
|
126
130
|
auto_leading: psr.auto_leading,
|
|
127
131
|
drop_cap_lines: psr.drop_cap_lines,
|
|
128
132
|
drop_cap_characters: psr.drop_cap_characters,
|
|
133
|
+
bullets_and_numbering_list_type: psr.bullets_and_numbering_list_type,
|
|
134
|
+
bullet_character_value: psr.bullet_character_value,
|
|
135
|
+
bullets_text_after: psr.bullets_text_after,
|
|
136
|
+
numbering_expression: psr.numbering_expression,
|
|
129
137
|
rule_above: psr.rule_above,
|
|
130
138
|
rule_above_line_weight: psr.rule_above_line_weight,
|
|
131
139
|
rule_above_color: psr.stroke_color,
|
|
@@ -143,6 +151,8 @@ module Idml
|
|
|
143
151
|
rule_below_right_indent: psr.rule_below_right_indent,
|
|
144
152
|
rule_below_width: psr.rule_below_width,
|
|
145
153
|
)
|
|
154
|
+
prepend_list_marker(paragraph)
|
|
155
|
+
paragraph
|
|
146
156
|
end
|
|
147
157
|
end
|
|
148
158
|
|
|
@@ -193,6 +203,19 @@ module Idml
|
|
|
193
203
|
end
|
|
194
204
|
private_class_method :alignment_for
|
|
195
205
|
|
|
206
|
+
# Prepends the list marker (bullet glyph or numbered expression)
|
|
207
|
+
# to the paragraph's first run when the paragraph is part of
|
|
208
|
+
# a list. Mutates the first run's text in place.
|
|
209
|
+
def self.prepend_list_marker(paragraph)
|
|
210
|
+
marker = ListMarker.marker_for(paragraph)
|
|
211
|
+
return unless marker
|
|
212
|
+
return if paragraph.runs.empty?
|
|
213
|
+
|
|
214
|
+
first_run = paragraph.runs.first
|
|
215
|
+
first_run.text = "#{marker}#{first_run.text}"
|
|
216
|
+
end
|
|
217
|
+
private_class_method :prepend_list_marker
|
|
218
|
+
|
|
196
219
|
# Concatenate runs into a single block. Used when the renderer
|
|
197
220
|
# can't handle per-run styling (e.g., no font metrics available).
|
|
198
221
|
def self.concatenate(runs)
|
data/lib/idml/render.rb
CHANGED
|
@@ -16,6 +16,7 @@ module Idml
|
|
|
16
16
|
autoload :CharacterStyle, "#{__dir__}/render/character_style"
|
|
17
17
|
autoload :ParagraphRules, "#{__dir__}/render/paragraph_rules"
|
|
18
18
|
autoload :DropCap, "#{__dir__}/render/drop_cap"
|
|
19
|
+
autoload :ListMarker, "#{__dir__}/render/list_marker"
|
|
19
20
|
autoload :StoryChainController, "#{__dir__}/render/story_chain_controller"
|
|
20
21
|
autoload :LayerFilter, "#{__dir__}/render/layer_filter"
|
|
21
22
|
autoload :ConditionFilter, "#{__dir__}/render/condition_filter"
|
data/lib/idml/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: idml
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.7.
|
|
4
|
+
version: 0.7.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose
|
|
@@ -444,6 +444,7 @@ files:
|
|
|
444
444
|
- lib/idml/render/image.rb
|
|
445
445
|
- lib/idml/render/image_collector.rb
|
|
446
446
|
- lib/idml/render/layer_filter.rb
|
|
447
|
+
- lib/idml/render/list_marker.rb
|
|
447
448
|
- lib/idml/render/metadata_builder.rb
|
|
448
449
|
- lib/idml/render/page_item_renderer.rb
|
|
449
450
|
- lib/idml/render/paragraph_rules.rb
|