html: Add support for mathematical messages

According to MSC2191 / Matrix 1.11
This commit is contained in:
Kévin Commaille 2024-06-21 22:11:49 +02:00 committed by Kévin Commaille
parent ba76e0ee3a
commit 002fe2fb3d
4 changed files with 83 additions and 5 deletions

View File

@ -1,5 +1,13 @@
# [unreleased]
Breaking Changes:
- `MatrixElement::Div` is now a newtype variant.
Improvements:
- Add support for mathematical messages, according to MSC2191 / Matrix 1.11
# 0.2.0
Breaking Changes:

View File

@ -152,7 +152,7 @@ pub enum MatrixElement {
/// [`<div>`], a content division element.
///
/// [`<div>`]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/div
Div,
Div(DivData),
/// [`<table>`], a table element.
///
@ -268,7 +268,10 @@ impl MatrixElement {
}
b"hr" => (Self::Hr, attrs.clone()),
b"br" => (Self::Br, attrs.clone()),
b"div" => (Self::Div, attrs.clone()),
b"div" => {
let (data, attrs) = DivData::parse(attrs);
(Self::Div(data), attrs)
}
b"table" => (Self::Table, attrs.clone()),
b"thead" => (Self::Thead, attrs.clone()),
b"tbody" => (Self::Tbody, attrs.clone()),
@ -599,12 +602,23 @@ pub struct SpanData {
///
/// [spoiler message]: https://spec.matrix.org/latest/client-server-api/#spoiler-messages
pub spoiler: Option<StrTendril>,
/// `data-mx-maths`, an inline Matrix [mathematical message].
///
/// The value is the mathematical notation in [LaTeX] format.
///
/// If this attribute is present, the content of the span is the fallback representation of the
/// mathematical notation.
///
/// [mathematical message]: https://spec.matrix.org/latest/client-server-api/#mathematical-messages
/// [LaTeX]: https://www.latex-project.org/
pub maths: Option<StrTendril>,
}
impl SpanData {
/// Construct an empty `SpanData`.
fn new() -> Self {
Self { bg_color: None, color: None, spoiler: None }
Self { bg_color: None, color: None, spoiler: None, maths: None }
}
/// Parse the given attributes to construct a new `SpanData`.
@ -629,6 +643,9 @@ impl SpanData {
b"data-mx-spoiler" => {
data.spoiler = Some(attr.value.clone());
}
b"data-mx-maths" => {
data.maths = Some(attr.value.clone());
}
_ => {
remaining_attrs.insert(attr.clone());
}
@ -722,3 +739,53 @@ impl ImageData {
(data, remaining_attrs)
}
}
/// The supported data of a `<div>` HTML element.
#[derive(Debug, Clone)]
#[non_exhaustive]
pub struct DivData {
/// `data-mx-maths`, a Matrix [mathematical message] block.
///
/// The value is the mathematical notation in [LaTeX] format.
///
/// If this attribute is present, the content of the div is the fallback representation of the
/// mathematical notation.
///
/// [mathematical message]: https://spec.matrix.org/latest/client-server-api/#mathematical-messages
/// [LaTeX]: https://www.latex-project.org/
pub maths: Option<StrTendril>,
}
impl DivData {
/// Construct an empty `DivData`.
fn new() -> Self {
Self { maths: None }
}
/// Parse the given attributes to construct a new `SpanData`.
///
/// Returns a tuple containing the constructed data and the remaining unsupported attributes.
#[allow(clippy::mutable_key_type)]
fn parse(attrs: &BTreeSet<Attribute>) -> (Self, BTreeSet<Attribute>) {
let mut data = Self::new();
let mut remaining_attrs = BTreeSet::new();
for attr in attrs {
if attr.name.ns != ns!() {
remaining_attrs.insert(attr.clone());
continue;
}
match attr.name.local.as_bytes() {
b"data-mx-maths" => {
data.maths = Some(attr.value.clone());
}
_ => {
remaining_attrs.insert(attr.clone());
}
}
}
(data, remaining_attrs)
}
}

View File

@ -28,14 +28,16 @@ static ALLOWED_ATTRIBUTES_STRICT: Map<&str, &Set<&str>> = phf_map! {
"img" => &ALLOWED_ATTRIBUTES_IMG_STRICT,
"ol" => &ALLOWED_ATTRIBUTES_OL_STRICT,
"code" => &ALLOWED_ATTRIBUTES_CODE_STRICT,
"div" => &ALLOWED_ATTRIBUTES_DIV_STRICT,
};
static ALLOWED_ATTRIBUTES_SPAN_STRICT: Set<&str> =
phf_set! { "data-mx-bg-color", "data-mx-color", "data-mx-spoiler" };
phf_set! { "data-mx-bg-color", "data-mx-color", "data-mx-spoiler", "data-mx-maths" };
static ALLOWED_ATTRIBUTES_A_STRICT: Set<&str> = phf_set! { "name", "target", "href" };
static ALLOWED_ATTRIBUTES_IMG_STRICT: Set<&str> =
phf_set! { "width", "height", "alt", "title", "src" };
static ALLOWED_ATTRIBUTES_OL_STRICT: Set<&str> = phf_set! { "start" };
static ALLOWED_ATTRIBUTES_CODE_STRICT: Set<&str> = phf_set! { "class" };
static ALLOWED_ATTRIBUTES_DIV_STRICT: Set<&str> = phf_set! { "data-mx-maths" };
/// Attributes that were previously allowed on HTML elements according to the Matrix specification,
/// with their replacement.

View File

@ -26,7 +26,8 @@ fn elements() {
// `<div>` element.
let div_node = html_children.next().unwrap();
let div_element = div_node.as_element().unwrap().to_matrix();
assert_matches!(div_element.element, MatrixElement::Div);
assert_matches!(div_element.element, MatrixElement::Div(div));
assert_eq!(div.maths, None);
// The `class` attribute is not supported.
assert_eq!(div_element.attrs.len(), 1);