diff options
| author | Dan Allen <dan.j.allen@gmail.com> | 2022-06-25 12:27:12 -0600 |
|---|---|---|
| committer | Dan Allen <dan.j.allen@gmail.com> | 2022-06-25 12:33:50 -0600 |
| commit | e22f2fc64271e1721fbfb46e5b9ca926d42c88e9 (patch) | |
| tree | b9ff81150888088feb33307eb68b9eff46b3b235 | |
| parent | b11a2651fed6aafd29e891fb3eb6a2474039f23a (diff) | |
backport fix for #2263 apply text-tranform from custom role on phrase after attributes have been resolved
| -rw-r--r-- | CHANGELOG.adoc | 1 | ||||
| -rw-r--r-- | lib/asciidoctor/pdf/converter.rb | 8 | ||||
| -rw-r--r-- | lib/asciidoctor/pdf/ext/prawn/extensions.rb | 23 | ||||
| -rw-r--r-- | lib/asciidoctor/pdf/formatted_text/transform.rb | 35 | ||||
| -rw-r--r-- | lib/asciidoctor/pdf/index_catalog.rb | 2 | ||||
| -rw-r--r-- | lib/asciidoctor/pdf/text_transformer.rb | 23 | ||||
| -rw-r--r-- | spec/formatted_text_formatter_spec.rb | 30 |
7 files changed, 89 insertions, 33 deletions
diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index f82031fc..15337e28 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -14,6 +14,7 @@ Improvements:: Bug Fixes:: * allow alt text for block image, video, and audio to wrap to next line on same page (#2258) +* apply text-tranform from custom role on phrase after attributes have been resolved (#2263) * make URL check more strict so image target containing a colon is not mistaken as a URL == 2.1.3 (2022-06-23) - @mojavelinux diff --git a/lib/asciidoctor/pdf/converter.rb b/lib/asciidoctor/pdf/converter.rb index ac0ae759..77934032 100644 --- a/lib/asciidoctor/pdf/converter.rb +++ b/lib/asciidoctor/pdf/converter.rb @@ -2688,13 +2688,7 @@ module Asciidoctor end if (roles = node.role) - theme = load_theme node.document - roles.split.each do |role| - if (text_transform = theme[%(role_#{role}_text_transform)]) - inner_text = transform_text inner_text, text_transform - end - inner_text = inner_text.gsub DoubleSpaceRx, ' ' + ZeroWidthSpace if role == 'pre-wrap' && (inner_text.include? DoubleSpace) - end + inner_text = inner_text.gsub DoubleSpaceRx, ' ' + ZeroWidthSpace if (node.has_role? 'pre-wrap') && (inner_text.include? DoubleSpace) quoted_text = is_tag ? %(#{open.chop} class="#{roles}">#{inner_text}#{close}) : %(<span class="#{roles}">#{open}#{inner_text}#{close}</span>) else quoted_text = %(#{open}#{inner_text}#{close}) diff --git a/lib/asciidoctor/pdf/ext/prawn/extensions.rb b/lib/asciidoctor/pdf/ext/prawn/extensions.rb index ae024e9f..74c6d11f 100644 --- a/lib/asciidoctor/pdf/ext/prawn/extensions.rb +++ b/lib/asciidoctor/pdf/ext/prawn/extensions.rb @@ -528,29 +528,6 @@ module Asciidoctor end end - # Apply the text transform to the specified text. - # - # Supported transform values are "uppercase", "lowercase", or "none" (passed - # as either a String or a Symbol). When the uppercase transform is applied to - # the text, it correctly uppercases visible text while leaving markup and - # named character entities unchanged. The none transform returns the text - # unmodified. - # - def transform_text text, transform - case transform - when :uppercase, 'uppercase' - uppercase_pcdata text - when :lowercase, 'lowercase' - lowercase_pcdata text - when :capitalize, 'capitalize' - capitalize_words_pcdata text - when :smallcaps, 'smallcaps' - smallcaps_pcdata text - else - text - end - end - def hyphenate_text text, hyphenator hyphenate_words_pcdata text, hyphenator end diff --git a/lib/asciidoctor/pdf/formatted_text/transform.rb b/lib/asciidoctor/pdf/formatted_text/transform.rb index d5fd582b..30f47761 100644 --- a/lib/asciidoctor/pdf/formatted_text/transform.rb +++ b/lib/asciidoctor/pdf/formatted_text/transform.rb @@ -4,6 +4,8 @@ module Asciidoctor module PDF module FormattedText class Transform + include TextTransformer + LF = ?\n ZeroWidthSpace = ?\u200b CharEntityTable = { amp: '&', apos: ?', gt: '>', lt: '<', nbsp: ?\u00a0, quot: '"' } @@ -21,8 +23,8 @@ module Asciidoctor 'font_size' => :size, 'text_decoration_color' => :text_decoration_color, 'text_decoration_width' => :text_decoration_width, + 'text_transform' => :text_transform, } - #DummyText = ?\u0000 def initialize options = {} @merge_adjacent_text_nodes = options[:merge_adjacent_text_nodes] @@ -172,6 +174,11 @@ module Asciidoctor previous_fragment_is_text && ((previous_fragment_text = fragments[-1][:text]).end_with? ' ') fragments[-1][:text] = previous_fragment_text.chop end + if (text_transform = fragment.delete :text_transform) + text = (text_chunks = extract_text pcdata).join + text_io = StringIO.new transform_text text, text_transform + restore_text pcdata, text_chunks.each_with_object([]) {|chunk, accum| accum << (text_io.read chunk.length) } + end # NOTE: decorate child fragments with inherited properties from this element apply pcdata, fragments, fragment previous_fragment_is_text = false @@ -251,6 +258,8 @@ module Asciidoctor fragments end + private + def build_fragment fragment, tag_name, attrs styles = (fragment[:styles] ||= ::Set.new) case tag_name @@ -324,7 +333,6 @@ module Asciidoctor # NOTE: spaces in style value are superfluous for our purpose; split drops record after trailing ; attrs[:style].tr(' ', '').split(';').each do |style| pname, pvalue = style.split ':', 2 - # TODO: text-transform case pname when 'color' # color needed to support syntax highlighters fragment[:color] = pvalue.length == 7 ? (pvalue.slice 1, 6) : (pvalue.slice 1, 3).each_char.map {|c| c * 2 }.join if (pvalue.start_with? '#') && (HexColorRx.match? pvalue) @@ -409,6 +417,29 @@ module Asciidoctor end end end + + def extract_text pcdata + pcdata.reduce [] do |accum, it| + case it[:type] + when :text + accum << it[:value] + when :element + accum += (extract_text it[:pcdata]) if it.key? :pcdata + end + accum + end + end + + def restore_text pcdata, text_chunks + pcdata.each do |it| + case it[:type] + when :text + it[:value] = text_chunks.shift + when :element + restore_text it[:pcdata], text_chunks if it.key? :pcdata + end + end + end end end end diff --git a/lib/asciidoctor/pdf/index_catalog.rb b/lib/asciidoctor/pdf/index_catalog.rb index 6ab022eb..531d68ce 100644 --- a/lib/asciidoctor/pdf/index_catalog.rb +++ b/lib/asciidoctor/pdf/index_catalog.rb @@ -3,7 +3,7 @@ module Asciidoctor module PDF class IndexCatalog - include ::Asciidoctor::PDF::TextTransformer + include TextTransformer LeadingAlphaRx = /^\p{Alpha}/ diff --git a/lib/asciidoctor/pdf/text_transformer.rb b/lib/asciidoctor/pdf/text_transformer.rb index 18dddb9b..61e2e559 100644 --- a/lib/asciidoctor/pdf/text_transformer.rb +++ b/lib/asciidoctor/pdf/text_transformer.rb @@ -64,6 +64,29 @@ module Asciidoctor string.tr LowerAlphaChars, SmallCapsChars end end + + # Apply the text transform to the specified text. + # + # Supported transform values are "uppercase", "lowercase", or "none" (passed + # as either a String or a Symbol). When the uppercase transform is applied to + # the text, it correctly uppercases visible text while leaving markup and + # named character entities unchanged. The none transform returns the text + # unmodified. + # + def transform_text text, transform + case transform + when :uppercase, 'uppercase' + uppercase_pcdata text + when :lowercase, 'lowercase' + lowercase_pcdata text + when :capitalize, 'capitalize' + capitalize_words_pcdata text + when :smallcaps, 'smallcaps' + smallcaps_pcdata text + else + text + end + end end end end diff --git a/spec/formatted_text_formatter_spec.rb b/spec/formatted_text_formatter_spec.rb index 530dd24c..5dd1074d 100644 --- a/spec/formatted_text_formatter_spec.rb +++ b/spec/formatted_text_formatter_spec.rb @@ -887,6 +887,36 @@ describe Asciidoctor::PDF::FormattedText::Formatter do (expect shout_text[:string]).to eql 'SHOUT' end + it 'should apply text transform to value of attribute reference' do + pdf = to_pdf <<~'EOS', pdf_theme: { role_upper_text_transform: 'uppercase' }, analyze: true + :brandname: acme + + [.upper]#{brandname}# + EOS + + lines = pdf.lines + (expect lines).to have_size 1 + (expect lines[0]).to eql 'ACME' + end + + it 'should apply text transform to enclosed formatted text' do + pdf = to_pdf <<~'EOS', pdf_theme: { role_upper_text_transform: 'uppercase' }, analyze: true + [.upper]#_please_ transform *bob & carl* + + to `uppercase`# + EOS + + lines = pdf.lines + (expect lines).to have_size 2 + (expect lines).to eql ['PLEASE TRANSFORM BOB & CARL', 'TO UPPERCASE'] + text = pdf.text + (expect text).to have_size 5 + (expect text[0][:font_name]).to eql 'NotoSerif-Italic' + (expect text[1][:font_name]).to eql 'NotoSerif' + (expect text[2][:font_name]).to eql 'NotoSerif-Bold' + (expect text[3][:font_name]).to eql 'NotoSerif' + (expect text[4][:font_name]).to eql 'mplus1mn-regular' + end + it 'should allow custom role to specify relative font size' do pdf_theme = { heading_h2_font_size: 24, |
