From f7a9ac5d640f718a269af3521b7754c34206d7bb Mon Sep 17 00:00:00 2001 From: David Warring Date: Wed, 4 Sep 2024 06:22:41 +1200 Subject: [PATCH] Add ability to extend tag-sets --- lib/CSS/TagSet.rakumod | 10 ++---- lib/CSS/TagSet/Pango.rakumod | 37 ++++++++++++---------- lib/CSS/TagSet/TaggedPDF.rakumod | 27 ++++++++-------- lib/CSS/TagSet/XHTML.rakumod | 53 +++++++++++++++++--------------- t/pdf-extra.css | 1 + t/tag-set-pdf.t | 5 +++ t/tag-set-xhtml.t | 5 +++ t/xhtml-extra.css | 1 + 8 files changed, 78 insertions(+), 61 deletions(-) create mode 100644 t/pdf-extra.css create mode 100644 t/xhtml-extra.css diff --git a/lib/CSS/TagSet.rakumod b/lib/CSS/TagSet.rakumod index c570e41..17c1834 100644 --- a/lib/CSS/TagSet.rakumod +++ b/lib/CSS/TagSet.rakumod @@ -5,15 +5,11 @@ use CSS::Media; use CSS::Properties; use CSS::Stylesheet; use CSS::Writer; -use CSS::Units :pt; -sub load-css-tagset($tag-css, Str :$media-type, |c) is export(:load-css-tagset) { - my %asts; +sub load-css-tagset($tag-css, CSS::Media :$media, :%tags, |c) is export(:load-css-tagset) { with $tag-css { # Todo: load via CSS::Stylesheet? my $css = .IO.slurp; - my CSS::Media $media .= new: :type($_), :width(595pt), :height(842pt) - with $media-type; my CSS::Stylesheet $style-sheet .= parse: $css, :$media, |c; for $style-sheet.rules { @@ -30,7 +26,7 @@ sub load-css-tagset($tag-css, Str :$media-type, |c) is export(:load-css-tagset) } my $key = @path == 1 ?? @path.head !! CSS::Writer.write: :selector($_); - %asts{$key}.append: $declarations.map: {:property($_)}; + %tags{$key}.append: $declarations.map: {:property($_)}; } } } @@ -40,7 +36,7 @@ sub load-css-tagset($tag-css, Str :$media-type, |c) is export(:load-css-tagset) note "running with 'raku --doc', I hope" } - %asts; + %tags; } method xpath-init($) {} # override me diff --git a/lib/CSS/TagSet/Pango.rakumod b/lib/CSS/TagSet/Pango.rakumod index 310d4ff..58334cd 100644 --- a/lib/CSS/TagSet/Pango.rakumod +++ b/lib/CSS/TagSet/Pango.rakumod @@ -10,25 +10,11 @@ use CSS::Units; has CSS::Module $.module = CSS::Module::CSS3.module; has CSS::Properties %!props; +has %!tags; -constant %Tags is export(:PangoTags) = load-css-tagset(%?RESOURCES); -method declarations { %Tags } +constant %BaseTags is export(:PangoTags) = load-css-tagset(%?RESOURCES); -method base-style(Str $prop) { - %!props{$prop} //= CSS::Properties.new(:$!module, declarations => %Tags{$prop}) // []; -} - -# mapping of Pango attributes to CSS properties -has %!SpanProp = %( - background => 'background-color', - 'face'|'font_family' => 'font-family', - foreground => 'color', - stretch => 'font-stretch', - style => 'font-style', - weight => 'font-weight', -); submethod TWEAK { - my %CustomProps = %( rise => '-pango-rise' => %( :synopsis, @@ -95,8 +81,25 @@ submethod TWEAK { $!module.extend(:$name, |$meta); %!SpanProp{$att} = $name; } + %!tags = %BaseTags; } +method declarations { %!tags } + +method base-style(Str $tag) { + %!props{$tag} //= CSS::Properties.new(:$!module, declarations => %!tags{$tag}) // []; +} + +# mapping of Pango attributes to CSS properties +has %!SpanProp = %( + background => 'background-color', + 'face'|'font_family' => 'font-family', + foreground => 'color', + stretch => 'font-stretch', + style => 'font-style', + weight => 'font-weight', +); + # Builds CSS properties from an element from a tag name and attributes multi method tag-style('span', *%attrs) { my CSS::Properties $css = self.base-style('span').clone; @@ -115,7 +118,7 @@ multi method tag-style('span', *%attrs) { } multi method tag-style($tag) { - self.base-style($tag); + self.base-style($tag).clone; } =begin pod diff --git a/lib/CSS/TagSet/TaggedPDF.rakumod b/lib/CSS/TagSet/TaggedPDF.rakumod index 6b1be51..ec17064 100644 --- a/lib/CSS/TagSet/TaggedPDF.rakumod +++ b/lib/CSS/TagSet/TaggedPDF.rakumod @@ -3,22 +3,20 @@ unit class CSS::TagSet::TaggedPDF; use CSS::TagSet :&load-css-tagset; also does CSS::TagSet; +use CSS::Media; use CSS::Module; use CSS::Module::CSS3; use CSS::Properties; +use CSS::Units :pt; has CSS::Module $.module = CSS::Module::CSS3.module; has CSS::Properties %!props; +has %!tags; -constant %Tags is export(:PDFTags) = load-css-tagset(%?RESOURCES, :xml, :media-type ); +constant $media = CSS::Media.new: :type, :width(595pt), :height(842pt); +constant %BaseTags is export(:PDFTags) = load-css-tagset(%?RESOURCES, :xml, :$media ); -method declarations { %Tags } - -method base-style(Str $prop) { - %!props{$prop} //= CSS::Properties.new: :$!module, declarations => %Tags{$prop} // []; -} - -submethod TWEAK { +submethod TWEAK(IO() :$style-sheet) { my %CustomProps = %( '-pdf-space-before'|'-pdf-space-after'|'-pdf-start-indent'|'-pdf-end-indent' => %( :synopsis, @@ -30,7 +28,15 @@ submethod TWEAK { for %CustomProps.pairs { $!module.extend(:name(.key), |.value); } + %!tags = %BaseTags; + load-css-tagset($_, :xml, :$media, :%!tags ) + with $style-sheet; +} + +method declarations { %!tags } +method base-style(Str $tag) { + %!props{$tag} //= CSS::Properties.new: :$!module, declarations => %!tags{$tag} // []; } sub snake-case($s) { @@ -72,10 +78,7 @@ our %Layout = %( my subset HashMap of Pair where .value ~~ Associative; # Builds CSS properties from an element from a tag name and attributes -multi method tag-style(Str $tag, *% where !.so) { - self.base-style($tag).clone; -} -multi method tag-style($tag, *%attrs --> CSS::Properties:D) { +method tag-style($tag, *%attrs --> CSS::Properties:D) { my CSS::Properties $css = self.base-style($tag).clone; for %attrs.keys.grep({%Layout{$_}:exists}) -> $key { diff --git a/lib/CSS/TagSet/XHTML.rakumod b/lib/CSS/TagSet/XHTML.rakumod index 028e860..0b12d6f 100644 --- a/lib/CSS/TagSet/XHTML.rakumod +++ b/lib/CSS/TagSet/XHTML.rakumod @@ -11,13 +11,35 @@ use URI; has CSS::Properties %!props; has SetHash %!link-pseudo; has CSS::Module $.module = CSS::Module::CSS3.module; +has %!tags; -constant %Tags is export(:Tags) = load-css-tagset(%?RESOURCES); +constant %BaseTags is export(:Tags) = load-css-tagset(%?RESOURCES); -method declarations { %Tags } +submethod TWEAK(IO() :$style-sheet) { + my %CustomProps = %( + '-xhtml-align' => %( + :like, + ), + '-xhtml-colspan'|'-xhtml-rowspan' => %( + :synopsis, + :default(1), + :coerce(-> Int() $num { :$num }), + ), + ); + + for %CustomProps.pairs { + $!module.extend(:name(.key), |.value); + } + %!tags = %BaseTags; + load-css-tagset($_, :%!tags ) + with $style-sheet; + +} + +method declarations { %!tags } method base-style(Str $prop) { - %!props{$prop} //= CSS::Properties.new(:$!module, declarations => %Tags{$prop} // []); + %!props{$prop} //= CSS::Properties.new(:$!module, declarations => %!tags{$prop} // []); } # mapping of HTML attributes to CSS properties @@ -54,28 +76,12 @@ method xpath-init($xpath-context) { ? ($elem.tag ~~ 'a'|'link'|'area' && self.link-pseudo($name, $elem)); }); } -submethod TWEAK(:$xpath-context) { - my %CustomProps = %( - '-xhtml-align' => %( - :like, - ), - '-xhtml-colspan'|'-xhtml-rowspan' => %( - :synopsis, - :default(1), - :coerce(-> Int() $num { :$num }), - ), - ); - - for %CustomProps.pairs { - $!module.extend(:name(.key), |.value); - } -} # any additional CSS styling based on HTML attributes multi sub tweak-style('bdo', $css) { $css.unicode-bidi //= :keyw; } -multi sub tweak-style($, $,) is default { +multi sub tweak-style($, $,) { } sub matching-media($media, $query) { @@ -122,12 +128,9 @@ method stylesheet-content($doc, :$media, :$links) { } # Builds CSS properties from an element from a tag name and attributes -multi method tag-style(Str $tag, *% where !.so) { - self.base-style($tag).clone; -} -multi method tag-style(Str $tag, :$hidden, *%attrs) { +method tag-style(Str $tag, :$hidden, *%attrs) { my CSS::Properties $css = self.base-style($tag).clone; - $css.display = :keyw with $hidden; + $css.display = :keyw if $hidden; for %attrs.keys.grep({%AttrTags{$_}:exists && $tag ~~ %AttrTags{$_}}) { my $name = %AttrProp{$_} // $_; diff --git a/t/pdf-extra.css b/t/pdf-extra.css new file mode 100644 index 0000000..0b27eb7 --- /dev/null +++ b/t/pdf-extra.css @@ -0,0 +1 @@ +Code { font-size: 0.7em; font-style: italic } diff --git a/t/tag-set-pdf.t b/t/tag-set-pdf.t index 8374ed5..e0054a6 100644 --- a/t/tag-set-pdf.t +++ b/t/tag-set-pdf.t @@ -13,4 +13,9 @@ is $tag-set.tag-style('LI'), 'display:list-item; list-style:none; mar is $tag-set.tag-style('Span', :BorderStyle), 'border:dotted;', ''; is $tag-set.tag-style('Span', :SpaceBefore(5)), '-pdf-space-before:5pt;', ''; +is $tag-set.tag-style('Code'), 'font:0.85em monospace; white-space:pre;', 'Base Code style'; + +$tag-set .= new: :style-sheet; +is $tag-set.tag-style('Code'), 'font:italic 0.7em monospace; white-space:pre;', 'Extended Code style'; + done-testing(); diff --git a/t/tag-set-xhtml.t b/t/tag-set-xhtml.t index 2d1c37d..c9cefb0 100644 --- a/t/tag-set-xhtml.t +++ b/t/tag-set-xhtml.t @@ -17,4 +17,9 @@ is $tag-set.tag-style('small'), 'font-size:0.75em;'; $tag-set.base-style('blah').font-weight = 'bold'; is $tag-set.tag-style('blah'), 'font-weight:bold;'; +is $tag-set.tag-style('kbd'), 'font-family:monospace;', 'Base kbd style'; + +$tag-set .= new: :style-sheet; +is $tag-set.tag-style('kbd'), 'font:0.85em monospace;', 'Extended kbd style'; + done-testing(); diff --git a/t/xhtml-extra.css b/t/xhtml-extra.css new file mode 100644 index 0000000..cfdf838 --- /dev/null +++ b/t/xhtml-extra.css @@ -0,0 +1 @@ +kbd { font-size: .85em }