lingxia_webview/
error_page.rs1#[derive(Debug, Clone, Copy)]
3pub struct LoadErrorPage<'a> {
4 pub title: &'a str,
5 pub message: &'a str,
6 pub retry_label: &'a str,
7 pub retry_url: &'a str,
8}
9
10pub fn render_load_error_page(content: LoadErrorPage<'_>) -> String {
13 let title = html_text(content.title);
14 let message = html_text(content.message);
15 let retry_label = html_text(content.retry_label);
16 let retry_url = html_attribute(content.retry_url);
17 format!(
18 r#"<!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="color-scheme" content="light dark"><style>html,body{{height:100%;margin:0}}body{{display:flex;align-items:center;justify-content:center;padding:24px;font-family:system-ui,sans-serif;background:#f7f8fb;color:#1c2233}}main{{max-width:320px;text-align:center}}h1{{font-size:18px;margin:0 0 8px}}p{{font-size:14px;line-height:1.5;color:#70788f;margin:0 0 20px}}button{{border:0;border-radius:10px;padding:11px 28px;background:#2f6bff;color:white;font:600 15px system-ui;cursor:pointer}}@media (prefers-color-scheme:dark){{body{{background:#16181d;color:#e8eaf0}}p{{color:#9aa2b5}}}}</style></head><body><main><h1>{title}</h1><p>{message}</p><button id="retry" data-url="{retry_url}">{retry_label}</button></main><script>const retry=document.getElementById('retry');retry.addEventListener('click',()=>location.replace(retry.dataset.url));</script></body></html>"#
19 )
20}
21
22fn html_text(value: &str) -> String {
23 value
24 .replace('&', "&")
25 .replace('<', "<")
26 .replace('>', ">")
27}
28
29fn html_attribute(value: &str) -> String {
30 html_text(value)
31 .replace('"', """)
32 .replace('\'', "'")
33}
34
35#[cfg(test)]
36mod tests {
37 use super::*;
38
39 #[test]
40 fn escapes_localized_content_and_retry_url() {
41 let html = render_load_error_page(LoadErrorPage {
42 title: "<offline>",
43 message: "A & B",
44 retry_label: "Retry",
45 retry_url: "https://example.test/?q=\"'><script>",
46 });
47 assert!(html.contains("<offline>"));
48 assert!(html.contains("A & B"));
49 assert!(html.contains(""'><script>"));
50 }
51}