mirror of
https://github.com/typst/typst
synced 2025-05-14 17:15:28 +08:00
Transform high level headings to HTML (#5525)
This commit is contained in:
parent
8b1e0d3a23
commit
75273937f7
@ -122,8 +122,8 @@ impl HtmlTag {
|
|||||||
let bytes = string.as_bytes();
|
let bytes = string.as_bytes();
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
while i < bytes.len() {
|
while i < bytes.len() {
|
||||||
if !bytes[i].is_ascii_alphanumeric() {
|
if !bytes[i].is_ascii() || !charsets::is_valid_in_tag_name(bytes[i] as char) {
|
||||||
panic!("constant tag name must be ASCII alphanumeric");
|
panic!("not all characters are valid in a tag name");
|
||||||
}
|
}
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
@ -220,8 +220,10 @@ impl HtmlAttr {
|
|||||||
let bytes = string.as_bytes();
|
let bytes = string.as_bytes();
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
while i < bytes.len() {
|
while i < bytes.len() {
|
||||||
if !bytes[i].is_ascii_alphanumeric() {
|
if !bytes[i].is_ascii()
|
||||||
panic!("constant attribute name must be ASCII alphanumeric");
|
|| !charsets::is_valid_in_attribute_name(bytes[i] as char)
|
||||||
|
{
|
||||||
|
panic!("not all characters are valid in an attribute name");
|
||||||
}
|
}
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
@ -621,5 +623,9 @@ pub mod attr {
|
|||||||
href
|
href
|
||||||
name
|
name
|
||||||
value
|
value
|
||||||
|
role
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
pub const aria_level: HtmlAttr = HtmlAttr::constant("aria-level");
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
use std::num::NonZeroUsize;
|
use std::num::NonZeroUsize;
|
||||||
|
|
||||||
|
use ecow::eco_format;
|
||||||
use typst_utils::NonZeroExt;
|
use typst_utils::NonZeroExt;
|
||||||
|
|
||||||
use crate::diag::SourceResult;
|
use crate::diag::{warning, SourceResult};
|
||||||
use crate::engine::Engine;
|
use crate::engine::Engine;
|
||||||
use crate::foundations::{
|
use crate::foundations::{
|
||||||
elem, Content, NativeElement, Packed, Resolve, Show, ShowSet, Smart, StyleChain,
|
elem, Content, NativeElement, Packed, Resolve, Show, ShowSet, Smart, StyleChain,
|
||||||
Styles, Synthesize, TargetElem,
|
Styles, Synthesize, TargetElem,
|
||||||
};
|
};
|
||||||
use crate::html::{tag, HtmlElem};
|
use crate::html::{attr, tag, HtmlElem};
|
||||||
use crate::introspection::{
|
use crate::introspection::{
|
||||||
Count, Counter, CounterUpdate, Locatable, Locator, LocatorLink,
|
Count, Counter, CounterUpdate, Locatable, Locator, LocatorLink,
|
||||||
};
|
};
|
||||||
@ -272,9 +273,26 @@ impl Show for Packed<HeadingElem> {
|
|||||||
// Meanwhile, a level 1 Typst heading is a section heading. For this
|
// Meanwhile, a level 1 Typst heading is a section heading. For this
|
||||||
// reason, levels are offset by one: A Typst level 1 heading becomes
|
// reason, levels are offset by one: A Typst level 1 heading becomes
|
||||||
// a `<h2>`.
|
// a `<h2>`.
|
||||||
let level = self.resolve_level(styles);
|
let level = self.resolve_level(styles).get();
|
||||||
let t = [tag::h2, tag::h3, tag::h4, tag::h5, tag::h6][level.get().min(5) - 1];
|
if level >= 6 {
|
||||||
HtmlElem::new(t).with_body(Some(realized)).pack().spanned(span)
|
engine.sink.warn(warning!(span,
|
||||||
|
"heading of level {} was transformed to \
|
||||||
|
<div role=\"heading\" aria-level=\"{}\">, which is not \
|
||||||
|
supported by all assistive technology",
|
||||||
|
level, level + 1;
|
||||||
|
hint: "HTML only supports <h1> to <h6>, not <h{}>", level + 1;
|
||||||
|
hint: "you may want to restructure your document so that \
|
||||||
|
it doesn't contain deep headings"));
|
||||||
|
HtmlElem::new(tag::div)
|
||||||
|
.with_body(Some(realized))
|
||||||
|
.with_attr(attr::role, "heading")
|
||||||
|
.with_attr(attr::aria_level, eco_format!("{}", level + 1))
|
||||||
|
.pack()
|
||||||
|
.spanned(span)
|
||||||
|
} else {
|
||||||
|
let t = [tag::h2, tag::h3, tag::h4, tag::h5, tag::h6][level - 1];
|
||||||
|
HtmlElem::new(t).with_body(Some(realized)).pack().spanned(span)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
let realized = BlockBody::Content(realized);
|
let realized = BlockBody::Content(realized);
|
||||||
BlockElem::new().with_body(Some(realized)).pack().spanned(span)
|
BlockElem::new().with_body(Some(realized)).pack().spanned(span)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user