summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Allen <dan.j.allen@gmail.com>2022-06-25 12:27:12 -0600
committerDan Allen <dan.j.allen@gmail.com>2022-06-25 12:33:50 -0600
commite22f2fc64271e1721fbfb46e5b9ca926d42c88e9 (patch)
treeb9ff81150888088feb33307eb68b9eff46b3b235
parentb11a2651fed6aafd29e891fb3eb6a2474039f23a (diff)
backport fix for #2263 apply text-tranform from custom role on phrase after attributes have been resolved
-rw-r--r--CHANGELOG.adoc1
-rw-r--r--lib/asciidoctor/pdf/converter.rb8
-rw-r--r--lib/asciidoctor/pdf/ext/prawn/extensions.rb23
-rw-r--r--lib/asciidoctor/pdf/formatted_text/transform.rb35
-rw-r--r--lib/asciidoctor/pdf/index_catalog.rb2
-rw-r--r--lib/asciidoctor/pdf/text_transformer.rb23
-rw-r--r--spec/formatted_text_formatter_spec.rb30
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 &amp; 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,