"
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 += ""
html += ""
- 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''
+ elif js_url:
+ html += f''
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]))
diff --git a/tests/unit_tests/components/test_web_server.py b/tests/unit_tests/components/test_web_server.py
index 6245f9a6f9..021a734109 100644
--- a/tests/unit_tests/components/test_web_server.py
+++ b/tests/unit_tests/components/test_web_server.py
@@ -21,6 +21,16 @@ def test_build_index_html_escapes_hint() -> None:
assert "a\\'b"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 '' 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: ""})