[web_server] Only add the offline hint without captive_portal

This commit is contained in:
J. Nick Koston
2026-08-19 12:57:58 -05:00
parent 88d6ded5f3
commit 33d9adbef1
2 changed files with 21 additions and 3 deletions
+11 -3
View File
@@ -333,7 +333,7 @@ async def add_entity_config(entity, config):
)
def build_index_html(config) -> str:
def build_index_html(config: ConfigType, offline_hint: bool = True) -> str:
html = "<!DOCTYPE html><html><head><meta charset=UTF-8><link rel=icon href=data:>"
css_include = config.get(CONF_CSS_INCLUDE)
js_include = config.get(CONF_JS_INCLUDE)
@@ -345,7 +345,8 @@ def build_index_html(config) -> str:
if js_include:
html += "<script type=module src=/0.js></script>"
html += "<esp-app></esp-app>"
if js_url := config[CONF_JS_URL]:
js_url = config[CONF_JS_URL]
if js_url and offline_hint:
# The interface is downloaded from the internet. Show a hint instead of a blank
# page when the browser cannot reach it, which is common in WiFi AP mode.
hint = (
@@ -359,6 +360,8 @@ def build_index_html(config) -> str:
hint.replace("\\", "\\\\").replace("'", "\\'"), quote=True
)
html += f'<script src="{js_url}" onerror="document.body.innerText=\'{hint_js}\'"></script>'
elif js_url:
html += f'<script src="{js_url}"></script>'
html += "</body></html>"
return html
@@ -396,7 +399,12 @@ async def to_code(config):
cg.add_define("USE_WEBSERVER_VERSION", version)
if version >= 2:
# Don't compress the index HTML as the data sizes are almost the same.
add_resource_as_progmem("INDEX_HTML", build_index_html(config), compress=False)
# With captive_portal the AP serves its own local page, so the offline hint is
# only useful without it.
index_html = build_index_html(
config, offline_hint="captive_portal" not in CORE.config
)
add_resource_as_progmem("INDEX_HTML", index_html, compress=False)
else:
cg.add(var.set_css_url(config[CONF_CSS_URL]))
cg.add(var.set_js_url(config[CONF_JS_URL]))
@@ -21,6 +21,16 @@ def test_build_index_html_escapes_hint() -> None:
assert "a\\&#x27;b&quot;c.js" in html
def test_build_index_html_hint_disabled() -> None:
"""The plain script tag is kept when the hint is not wanted (captive_portal)."""
html = build_index_html(
{CONF_JS_URL: "https://oi.esphome.io/v2/www.js", CONF_CSS_URL: ""},
offline_hint=False,
)
assert '<script src="https://oi.esphome.io/v2/www.js"></script>' in html
assert "onerror" not in html
def test_build_index_html_without_js_url() -> None:
"""No hosted script and no hint when js_url is empty."""
html = build_index_html({CONF_JS_URL: "", CONF_CSS_URL: ""})