1use crate::asset_snapshot::AssetSnapshot;
18use crate::resolve::embed_renderer::html_escape_attr;
19use crate::resolve::title_params::TitleParams;
20
21const CLASS_EMBED: &str = "moss-embed";
24
25#[allow(unused_variables)]
48pub fn synthesize_iframe_html(
49 params: &TitleParams,
50 src: &str,
51 assets: &AssetSnapshot,
52) -> String {
53 let mut full_src = String::from(src);
58 if let Some(q) = params.get("query") {
59 full_src.push('?');
60 full_src.push_str(q);
61 }
62 if let Some(f) = params.get("fragment") {
63 full_src.push('#');
64 full_src.push_str(f);
65 }
66
67 let data_provider_attr = match params.get("data-provider") {
68 Some(p) if !p.is_empty() => format!(r#" data-provider="{}""#, html_escape_attr(p)),
69 _ => String::new(),
70 };
71
72 let data_width_attr = match params.get("data-width") {
73 Some(w) => format!(r#" data-width="{}""#, html_escape_attr(w)),
74 None => String::new(),
75 };
76
77 let title_attr = match params.get("title") {
78 Some(t) => format!(" title=\"{}\"", html_escape_attr(t)),
79 None => String::new(),
80 };
81
82 let width_attr = match params.get("width") {
83 Some(w) => format!(" width=\"{}\"", html_escape_attr(w)),
84 None => String::new(),
85 };
86
87 let height_attr = match params.get("height") {
88 Some(h) => format!(" height=\"{}\"", html_escape_attr(h)),
89 None => String::new(),
90 };
91
92 let allow_attr = match params.get("allow") {
93 Some(a) if !a.is_empty() => format!(" allow=\"{}\"", html_escape_attr(a)),
94 _ => String::new(),
95 };
96
97 let sandbox_attr = match params.get("sandbox") {
98 Some(s) if !s.is_empty() => format!(" sandbox=\"{}\"", html_escape_attr(s)),
99 _ => String::new(),
100 };
101
102 let allowfullscreen_attr = if params.get("allowfullscreen") == Some("true") {
103 " allowfullscreen"
104 } else {
105 ""
106 };
107
108 format!(
109 "<iframe class=\"{}\" data-type=\"iframe\"{}{} src=\"{}\"{}{}{}{}{}{} loading=\"lazy\"></iframe>",
110 CLASS_EMBED,
111 data_provider_attr,
112 data_width_attr,
113 html_escape_attr(&full_src),
114 title_attr,
115 width_attr,
116 height_attr,
117 allow_attr,
118 sandbox_attr,
119 allowfullscreen_attr,
120 )
121}
122
123#[cfg(test)]
124mod tests {
125 use super::*;
126
127 fn empty_snapshot() -> AssetSnapshot {
128 AssetSnapshot::new()
129 }
130
131 fn params_with(kvs: &[(&str, &str)]) -> TitleParams {
132 let mut p = TitleParams::default();
133 for (k, v) in kvs {
134 p.insert(*k, *v);
135 }
136 p
137 }
138
139 #[test]
140 fn iframe_basic_shape() {
141 let p = params_with(&[("kind", "iframe")]);
142 let out = synthesize_iframe_html(&p, "widget.html", &empty_snapshot());
143 assert!(out.contains("<iframe"));
144 assert!(out.contains(r#"src="widget.html""#));
145 assert!(out.contains(r#"loading="lazy""#));
146 assert!(out.contains(r#"class="moss-embed""#));
147 assert!(out.contains(r#"data-type="iframe""#));
148 }
149
150 #[test]
151 fn iframe_with_data_width() {
152 let p = params_with(&[("kind", "iframe"), ("data-width", "wide")]);
153 let out = synthesize_iframe_html(&p, "widget.html", &empty_snapshot());
154 assert!(out.contains(r#"data-width="wide""#), "got: {}", out);
155 }
156
157 #[test]
158 fn iframe_with_query_param() {
159 let p = params_with(&[("kind", "iframe"), ("query", "k=v&x=y")]);
160 let out = synthesize_iframe_html(&p, "widget.html", &empty_snapshot());
161 assert!(
162 out.contains(r#"src="widget.html?k=v"#)
163 || out.contains(r#"src="widget.html?k=v&x=y""#),
164 "expected query in src, got: {}",
165 out
166 );
167 }
168
169 #[test]
170 fn iframe_with_title() {
171 let p = params_with(&[("kind", "iframe"), ("title", "My Widget")]);
172 let out = synthesize_iframe_html(&p, "widget.html", &empty_snapshot());
173 assert!(out.contains(r#"title="My Widget""#));
174 }
175
176 #[test]
177 fn iframe_with_allow_attr() {
178 let p = params_with(&[("allow", "autoplay; encrypted-media")]);
179 let out = synthesize_iframe_html(&p, "x.html", &empty_snapshot());
180 assert!(out.contains(r#"allow="autoplay; encrypted-media""#), "got: {out}");
181 }
182
183 #[test]
184 fn iframe_with_sandbox_attr() {
185 let p = params_with(&[("sandbox", "allow-scripts allow-same-origin")]);
186 let out = synthesize_iframe_html(&p, "x.html", &empty_snapshot());
187 assert!(out.contains(r#"sandbox="allow-scripts allow-same-origin""#), "got: {out}");
188 }
189
190 #[test]
191 fn iframe_with_allowfullscreen() {
192 let p = params_with(&[("allowfullscreen", "true")]);
193 let out = synthesize_iframe_html(&p, "x.html", &empty_snapshot());
194 assert!(out.contains("allowfullscreen"), "got: {out}");
195 }
196
197 #[test]
198 fn iframe_without_allow_omits_attr() {
199 let p = params_with(&[]);
200 let out = synthesize_iframe_html(&p, "x.html", &empty_snapshot());
201 assert!(!out.contains("allow="), "got: {out}");
202 assert!(!out.contains("sandbox="), "got: {out}");
203 assert!(!out.contains("allowfullscreen"), "got: {out}");
204 }
205
206 #[test]
207 fn iframe_allow_empty_string_is_omitted() {
208 let p = params_with(&[("allow", "")]);
210 let out = synthesize_iframe_html(&p, "x.html", &empty_snapshot());
211 assert!(!out.contains("allow="), "got: {out}");
212 }
213
214 #[test]
215 fn iframe_allowfullscreen_false_is_omitted() {
216 let p = params_with(&[("allowfullscreen", "false")]);
218 let out = synthesize_iframe_html(&p, "x.html", &empty_snapshot());
219 assert!(!out.contains("allowfullscreen"), "got: {out}");
220 }
221
222}