From e84bb4b6e6d1220c2b018137f0f18ad5a1fcfc9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20F=C3=A4rber?= <01mf02@gmail.com> Date: Tue, 21 Jan 2025 11:58:41 +0100 Subject: [PATCH] Set `cite` attribute of `blockquote` if attribution is a link. --- crates/typst-library/src/model/quote.rs | 23 +++++++++++++++++----- tests/ref/html/quote-attribution-link.html | 15 ++++++++++++++ tests/suite/model/quote.typ | 8 ++++++++ 3 files changed, 41 insertions(+), 5 deletions(-) create mode 100644 tests/ref/html/quote-attribution-link.html diff --git a/crates/typst-library/src/model/quote.rs b/crates/typst-library/src/model/quote.rs index 5487f1a3e..774384acb 100644 --- a/crates/typst-library/src/model/quote.rs +++ b/crates/typst-library/src/model/quote.rs @@ -4,12 +4,12 @@ use crate::foundations::{ cast, elem, Content, Depth, Label, NativeElement, Packed, Show, ShowSet, Smart, StyleChain, Styles, TargetElem, }; -use crate::html::{tag, HtmlElem}; +use crate::html::{tag, HtmlAttr, HtmlElem}; use crate::introspection::Locatable; use crate::layout::{ Alignment, BlockBody, BlockElem, Em, HElem, PadElem, Spacing, VElem, }; -use crate::model::{CitationForm, CiteElem}; +use crate::model::{CitationForm, CiteElem, Destination, LinkElem, LinkTarget}; use crate::text::{SmartQuoteElem, SmartQuotes, SpaceElem, TextElem}; /// Displays a quote alongside an optional attribution. @@ -186,15 +186,28 @@ impl Show for Packed { .styled(QuoteElem::set_depth(Depth(1))); } + let attribution = self.attribution(styles); + if block { realized = if html { - HtmlElem::new(tag::blockquote).with_body(Some(realized)).pack() + let mut elem = HtmlElem::new(tag::blockquote).with_body(Some(realized)); + if let Some(Attribution::Content(attribution)) = attribution { + if let Some(link) = attribution.to_packed::() { + if let LinkTarget::Dest(Destination::Url(url)) = &link.dest { + elem = elem.with_attr( + HtmlAttr::constant("cite"), + url.clone().into_inner(), + ); + } + } + } + elem.pack() } else { BlockElem::new().with_body(Some(BlockBody::Content(realized))).pack() } .spanned(self.span()); - if let Some(attribution) = self.attribution(styles).as_ref() { + if let Some(attribution) = attribution.as_ref() { let attribution = match attribution { Attribution::Content(content) => content.clone(), Attribution::Label(label) => CiteElem::new(*label) @@ -218,7 +231,7 @@ impl Show for Packed { if !html { realized = PadElem::new(realized).pack(); } - } else if let Some(Attribution::Label(label)) = self.attribution(styles) { + } else if let Some(Attribution::Label(label)) = attribution { realized += SpaceElem::shared().clone() + CiteElem::new(*label).pack().spanned(self.span()); } diff --git a/tests/ref/html/quote-attribution-link.html b/tests/ref/html/quote-attribution-link.html new file mode 100644 index 000000000..4da8b47f5 --- /dev/null +++ b/tests/ref/html/quote-attribution-link.html @@ -0,0 +1,15 @@ + + + + + + + +
+ Compose papers faster +
+

+ — typst.com +

+ + diff --git a/tests/suite/model/quote.typ b/tests/suite/model/quote.typ index 1eeff8b46..d0dcc55dd 100644 --- a/tests/suite/model/quote.typ +++ b/tests/suite/model/quote.typ @@ -99,3 +99,11 @@ And I quote: #quote(attribution: [René Descartes])[cogito, ergo sum]. --- quote-nesting-html html --- When you said that #quote[he surely meant that #quote[she intended to say #quote[I'm sorry]]], I was quite confused. + +--- quote-attribution-link html --- +#quote( + block: true, + attribution: link("https://typst.app/home")[typst.com] +)[ + Compose papers faster +]