ftml/render/html/element/
math.rs1use super::prelude::*;
22use cfg_if::cfg_if;
23use std::num::NonZeroUsize;
24
25cfg_if! {
26 if #[cfg(feature = "mathml")] {
27 use latex2mathml::{latex_to_mathml, DisplayStyle};
28 } else {
29 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
31 enum DisplayStyle {
32 Block,
33 Inline,
34 }
35 }
36}
37
38pub fn render_math_block(ctx: &mut HtmlContext, name: Option<&str>, latex_source: &str) {
39 debug!(
40 "Rendering math block (name '{}', source '{}')",
41 name.unwrap_or("<none>"),
42 latex_source,
43 );
44
45 let index = ctx.next_equation_index();
46
47 render_latex(ctx, name, Some(index), latex_source, DisplayStyle::Block);
48}
49
50pub fn render_math_inline(ctx: &mut HtmlContext, latex_source: &str) {
51 debug!("Rendering math inline (source '{latex_source}'");
52 render_latex(ctx, None, None, latex_source, DisplayStyle::Inline);
53}
54
55fn render_latex(
56 ctx: &mut HtmlContext,
57 name: Option<&str>,
58 index: Option<NonZeroUsize>,
59 latex_source: &str,
60 display: DisplayStyle,
61) {
62 let (html_tag, wj_type, _error_type) = match display {
64 DisplayStyle::Block => ("div", "wj-math-block", "wj-error-block"),
65 DisplayStyle::Inline => ("span", "wj-math-inline", "wj-error-inline"),
66 };
67
68 ctx.html()
70 .tag(html_tag)
71 .attr(attr!(
72 "class" => "wj-math " wj_type,
73 "data-name" => name.unwrap_or(""); if name.is_some(),
74 ))
75 .inner(|ctx| {
76 if let Some(index) = index {
78 ctx.html()
79 .span()
80 .attr(attr!("class" => "wj-equation-number"))
81 .inner(|ctx| {
82 ctx.html()
84 .span()
85 .attr(attr!(
86 "class" => "wj-equation-paren wj-equation-paren-open",
87 ))
88 .contents("(");
89
90 str_write!(ctx, "{index}");
91
92 ctx.html()
94 .span()
95 .attr(attr!(
96 "class" => "wj-equation-paren wj-equation-paren-close",
97 ))
98 .contents(")");
99 });
100 }
101
102 ctx.html()
105 .code()
106 .attr(attr!(
107 "class" => "wj-math-source wj-hidden",
108 "aria-hidden" => "true",
109 ))
110 .contents(latex_source);
111
112 cfg_if! {
114 if #[cfg(feature = "mathml")] {
115 match latex_to_mathml(latex_source, display) {
116 Ok(mathml) => {
117 debug!("Processed LaTeX -> MathML");
118
119 ctx.html()
121 .element("wj-math-ml")
122 .attr(attr!("class" => "wj-math-ml"))
123 .inner(|ctx| ctx.push_raw_str(&mathml));
124 }
125 Err(error) => {
126 warn!("Error processing LaTeX -> MathML: {error}");
127 let error = str!(error);
128
129 ctx.html()
130 .span()
131 .attr(attr!("class" => _error_type))
132 .contents(error);
133 }
134 }
135 }
136 }
137 });
138}
139
140pub fn render_equation_reference(ctx: &mut HtmlContext, name: &str) {
141 debug!("Rendering equation reference (name '{name}')");
142
143 ctx.html()
144 .span()
145 .attr(attr!("class" => "wj-equation-ref"))
146 .inner(|ctx| {
147 ctx.html()
149 .element("wj-equation-ref-marker")
150 .attr(attr!(
151 "class" => "wj-equation-ref-marker",
152 "type" => "button",
153 "data-name" => name,
154 ))
155 .contents(name);
156
157 ctx.html().span().attr(attr!(
159 "class" => "wj-equation-ref-tooltip",
160 "aria-hidden" => "true",
161 ));
162 });
164}