mirror of
https://github.com/jorijn/meshcore-stats.git
synced 2026-03-28 17:42:55 +01:00
feat: add configurable custom HTML head injection
Allow deployers to inject custom HTML into the <head> of every page via the CUSTOM_HEAD_HTML config option, useful for analytics scripts (Plausible, Matomo, etc.) without modifying source. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -148,6 +148,14 @@ RADIO_CODING_RATE=CR8
|
||||
# TELEMETRY_RETRY_ATTEMPTS=2
|
||||
# TELEMETRY_RETRY_BACKOFF_S=4
|
||||
|
||||
# =============================================================================
|
||||
# Custom HTML (Analytics, etc.)
|
||||
# =============================================================================
|
||||
# Inject custom HTML into the <head> of every page.
|
||||
# Useful for analytics scripts (Plausible, Matomo, etc.) without modifying source.
|
||||
# Example for Plausible:
|
||||
# CUSTOM_HEAD_HTML=<script defer data-domain="stats.example.com" src="https://plausible.io/js/script.js"></script>
|
||||
|
||||
# =============================================================================
|
||||
# Paths (Native installation only)
|
||||
# =============================================================================
|
||||
|
||||
@@ -273,6 +273,9 @@ class Config:
|
||||
|
||||
self.html_path = get_str("HTML_PATH", "") or ""
|
||||
|
||||
# Custom HTML injected into <head> (e.g. analytics scripts)
|
||||
self.custom_head_html = get_str("CUSTOM_HEAD_HTML", "") or ""
|
||||
|
||||
# Global config instance
|
||||
_config: Config | None = None
|
||||
|
||||
|
||||
@@ -727,6 +727,9 @@ def build_page_context(
|
||||
"page_title": page_title,
|
||||
"page_subtitle": page_subtitle,
|
||||
"chart_groups": chart_groups,
|
||||
|
||||
# Custom HTML
|
||||
"custom_head_html": cfg.custom_head_html,
|
||||
}
|
||||
|
||||
|
||||
@@ -1304,6 +1307,7 @@ def render_report_page(
|
||||
"monthly_links": monthly_links,
|
||||
"prev_report": prev_report,
|
||||
"next_report": next_report,
|
||||
"custom_head_html": cfg.custom_head_html,
|
||||
}
|
||||
|
||||
template = env.get_template("report.html")
|
||||
@@ -1341,6 +1345,7 @@ def render_reports_index(report_sections: list[dict]) -> str:
|
||||
"css_path": "../",
|
||||
"report_sections": report_sections,
|
||||
"month_abbrs": month_abbrs,
|
||||
"custom_head_html": cfg.custom_head_html,
|
||||
}
|
||||
|
||||
template = env.get_template("report_index.html")
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
<meta name="twitter:description" content="{{ meta_description }}">
|
||||
|
||||
<link rel="stylesheet" href="{{ css_path }}styles.css">
|
||||
{% if custom_head_html %}{{ custom_head_html | safe }}{% endif %}
|
||||
</head>
|
||||
<body>
|
||||
{% block body %}{% endblock %}
|
||||
|
||||
@@ -147,3 +147,28 @@ class TestTemplateRendering:
|
||||
assert "<html" in html
|
||||
assert "<head>" in html
|
||||
assert "<body>" in html
|
||||
|
||||
def test_custom_head_html_rendered_when_set(self):
|
||||
"""Custom head HTML appears in rendered output when provided."""
|
||||
env = get_jinja_env()
|
||||
template = env.get_template("base.html")
|
||||
|
||||
snippet = '<script defer data-domain="example.com" src="https://plausible.io/js/script.js"></script>'
|
||||
html = template.render(
|
||||
title="Test",
|
||||
custom_head_html=snippet,
|
||||
)
|
||||
|
||||
assert snippet in html
|
||||
assert html.index(snippet) < html.index("</head>")
|
||||
|
||||
def test_custom_head_html_absent_when_empty(self):
|
||||
"""No extra content in head when custom_head_html is empty."""
|
||||
env = get_jinja_env()
|
||||
template = env.get_template("base.html")
|
||||
|
||||
html_with = template.render(title="Test", custom_head_html="")
|
||||
html_without = template.render(title="Test")
|
||||
|
||||
# Both should produce identical output (no extra content)
|
||||
assert html_with == html_without
|
||||
|
||||
Reference in New Issue
Block a user