mirror of
https://github.com/alexhopeoconnor/WiFiManager.git
synced 2026-10-04 02:48:13 +10:00
WiFiManager: add DFTE root template and chunked rendering for handleRoot; introduce shared placeholder registry via server singleton; add getMenuOut(String*) overload and menu logic for params/close
This commit is contained in:
@@ -78,6 +78,7 @@ class WiFiManagerHandlers {
|
||||
String getHTTPHead(String title, String classes = "");
|
||||
String getHTTPEnd();
|
||||
String getMenuOut();
|
||||
String getMenuOut(String* outOpt);
|
||||
String getScanItemOut();
|
||||
String getParamOut();
|
||||
String getStaticOut();
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
// DFTE (template engine)
|
||||
#include <TemplateEngine.h>
|
||||
|
||||
// Forward declarations
|
||||
class WiFiManager;
|
||||
|
||||
@@ -46,8 +49,21 @@ const char R_updatedone[] PROGMEM = "/u";
|
||||
|
||||
class WiFiManagerServer {
|
||||
public:
|
||||
// Singleton access
|
||||
static WiFiManagerServer* instance();
|
||||
|
||||
WiFiManagerServer(WiFiManager* wm);
|
||||
|
||||
// Template engine setup and access
|
||||
void setupTemplateEngine();
|
||||
PlaceholderRegistry* getPlaceholderRegistry() { return _tplRegistry.get(); }
|
||||
|
||||
// Static zero-arg getters for DFTE RAM placeholders
|
||||
static const char* tplGetPageTitle();
|
||||
static const char* tplGetSubtitle();
|
||||
static const char* tplGetMenu();
|
||||
static const char* tplGetStatus();
|
||||
|
||||
// Create server instance
|
||||
void createServer(uint16_t port);
|
||||
|
||||
@@ -74,6 +90,12 @@ class WiFiManagerServer {
|
||||
std::unique_ptr<WiFiManagerHandlers> _handlers;
|
||||
std::unique_ptr<AsyncWebServer> server;
|
||||
std::unique_ptr<DNSServer> dnsServer;
|
||||
|
||||
// Shared DFTE placeholder registry
|
||||
std::unique_ptr<PlaceholderRegistry> _tplRegistry;
|
||||
|
||||
// Singleton instance
|
||||
static WiFiManagerServer* s_instance;
|
||||
};
|
||||
|
||||
// Include WiFiManagerHandlers.h after class definition to provide full definition
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Root.h
|
||||
* Whole-document root template for WiFiManager using DFTE placeholders
|
||||
*/
|
||||
|
||||
#ifndef _WM_ROOT_TEMPLATE_H_
|
||||
#define _WM_ROOT_TEMPLATE_H_
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
// Whole document template:
|
||||
// - Injects %SCRIPTS% and %STYLES% (these already include <script>/<style> tags)
|
||||
// - Mirrors existing structure: body class "home" and wrapper div.wrap
|
||||
// - Renders title/subtitle, then menu and status
|
||||
const char WM_ROOT_TEMPLATE[] PROGMEM =
|
||||
"<!DOCTYPE html>"
|
||||
"<html lang='en'>"
|
||||
"<head>"
|
||||
"<meta name='format-detection' content='telephone=no'>"
|
||||
"<meta charset='UTF-8'>"
|
||||
"<meta name='viewport' content='width=device-width,initial-scale=1,user-scalable=no'/>"
|
||||
"<title>%PAGE_TITLE%</title>"
|
||||
"%SCRIPTS%"
|
||||
"%STYLES%"
|
||||
"</head>"
|
||||
"<body class='home'>"
|
||||
"<div class='wrap'>"
|
||||
"<h1>%PAGE_TITLE%</h1>"
|
||||
"<h3>%SUBTITLE%</h3>"
|
||||
"%MENU%"
|
||||
"%STATUS%"
|
||||
"</div>"
|
||||
"</body>"
|
||||
"</html>";
|
||||
|
||||
#endif // _WM_ROOT_TEMPLATE_H_
|
||||
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
#include "templates/HTML.h"
|
||||
#include "templates/CSS.h"
|
||||
#include "templates/JS.h"
|
||||
#include "templates/Root.h"
|
||||
#include <TemplateEngine.h>
|
||||
|
||||
#if defined(ESP8266) || defined(ESP32)
|
||||
|
||||
@@ -38,13 +40,30 @@ String WiFiManagerHandlers::getHTTPEnd() {
|
||||
}
|
||||
|
||||
String WiFiManagerHandlers::getMenuOut(){
|
||||
String page;
|
||||
page += HTML_PORTAL_MENU[0]; // WIFI
|
||||
page += HTML_PORTAL_MENU[2]; // INFO
|
||||
page += HTML_PORTAL_MENU[6]; // EXIT
|
||||
page += HTML_PORTAL_MENU[9]; // SEP
|
||||
page += HTML_PORTAL_MENU[8]; // UPDATE
|
||||
return page;
|
||||
return getMenuOut(nullptr);
|
||||
}
|
||||
|
||||
String WiFiManagerHandlers::getMenuOut(String* outOpt){
|
||||
String local;
|
||||
String &out = outOpt ? *outOpt : local;
|
||||
out += HTML_PORTAL_MENU[0]; // WIFI (scan)
|
||||
|
||||
// Show PARAM (Setup) when params are on their own page
|
||||
if(!_wm->_paramsInWifi && _wm->_paramsCount > 0){
|
||||
out += HTML_PORTAL_MENU[3]; // PARAM
|
||||
}
|
||||
|
||||
out += HTML_PORTAL_MENU[2]; // INFO
|
||||
|
||||
// When captive/config portal is active, offer Close (keeps portal running)
|
||||
if(_wm->configPortalActive){
|
||||
out += HTML_PORTAL_MENU[4]; // CLOSE
|
||||
}
|
||||
|
||||
out += HTML_PORTAL_MENU[6]; // EXIT
|
||||
out += HTML_PORTAL_MENU[9]; // SEP
|
||||
out += HTML_PORTAL_MENU[8]; // UPDATE
|
||||
return out;
|
||||
}
|
||||
|
||||
String WiFiManagerHandlers::getScanItemOut(){
|
||||
@@ -680,19 +699,25 @@ void WiFiManagerHandlers::handleRoot(AsyncWebServerRequest *request) {
|
||||
#endif
|
||||
if (captivePortal(request)) return;
|
||||
handleRequest(request);
|
||||
String page = getHTTPHead(_wm->_title, FPSTR(C_root));
|
||||
// Build root main HTML directly without tokens
|
||||
page += F("<h1>");
|
||||
page += _wm->_title;
|
||||
page += F("</h1><h3>");
|
||||
page += (_wm->configPortalActive ? _wm->_apName : (_wm->getWiFiHostname() + " - " + WiFi.localIP().toString()));
|
||||
page += F("</h3>");
|
||||
page += FPSTR(HTML_PORTAL_OPTIONS);
|
||||
page += getMenuOut();
|
||||
reportStatus(page);
|
||||
page += getHTTPEnd();
|
||||
|
||||
request->send(200, FPSTR(HTTP_HEAD_CT), page);
|
||||
|
||||
// Stream-render the root page using DFTE and the shared registry
|
||||
TemplateContext ctx;
|
||||
if (_wm->_serverManager && _wm->_serverManager->getPlaceholderRegistry()) {
|
||||
ctx.setRegistry(_wm->_serverManager->getPlaceholderRegistry());
|
||||
}
|
||||
TemplateRenderer::initializeContext(ctx, WM_ROOT_TEMPLATE);
|
||||
|
||||
// Keep context alive across chunk calls
|
||||
auto ctxPtr = std::make_shared<TemplateContext>(ctx);
|
||||
|
||||
AsyncWebServerResponse *response = request->beginChunkedResponse(String(FPSTR(HTTP_HEAD_CT)),
|
||||
[ctxPtr](uint8_t *buffer, size_t maxLen, size_t /*index*/) -> size_t {
|
||||
if (!ctxPtr) return 0;
|
||||
size_t written = TemplateRenderer::renderNextChunk(*ctxPtr, buffer, maxLen);
|
||||
return written;
|
||||
}
|
||||
);
|
||||
request->send(response);
|
||||
if(_wm->_preloadwifiscan) _wm->WiFi_scanNetworks(_wm->_scancachetime);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,11 +11,78 @@
|
||||
#include "WiFiManagerServer.h"
|
||||
#include "WiFiManager.h"
|
||||
#include "WiFiManagerHandlers.h" // Full definition needed for unique_ptr
|
||||
#include "templates/CSS.h"
|
||||
#include "templates/JS.h"
|
||||
#include "templates/Root.h"
|
||||
|
||||
#if defined(ESP8266) || defined(ESP32)
|
||||
|
||||
WiFiManagerServer* WiFiManagerServer::s_instance = nullptr;
|
||||
|
||||
WiFiManagerServer* WiFiManagerServer::instance() {
|
||||
return s_instance;
|
||||
}
|
||||
|
||||
WiFiManagerServer::WiFiManagerServer(WiFiManager* wm)
|
||||
: _wm(wm), _handlers(std::make_unique<WiFiManagerHandlers>(wm)) {
|
||||
s_instance = this;
|
||||
}
|
||||
|
||||
// Static getters for RAM placeholders (registry requires zero-arg functions) using singleton
|
||||
const char* WiFiManagerServer::tplGetPageTitle() {
|
||||
auto srv = WiFiManagerServer::instance();
|
||||
if (!srv || !srv->_wm) return "";
|
||||
return srv->_wm->_title.c_str();
|
||||
}
|
||||
|
||||
const char* WiFiManagerServer::tplGetSubtitle() {
|
||||
static String buf;
|
||||
auto srv = WiFiManagerServer::instance();
|
||||
if (!srv || !srv->_wm) { buf = ""; return buf.c_str(); }
|
||||
WiFiManager* wm = srv->_wm;
|
||||
if (wm->configPortalActive) {
|
||||
buf = wm->_apName;
|
||||
} else {
|
||||
buf = wm->getWiFiHostname() + " - " + WiFi.localIP().toString();
|
||||
}
|
||||
return buf.c_str();
|
||||
}
|
||||
|
||||
const char* WiFiManagerServer::tplGetMenu() {
|
||||
static String buf;
|
||||
auto srv = WiFiManagerServer::instance();
|
||||
if (!srv || !srv->_handlers) { buf = ""; return buf.c_str(); }
|
||||
buf = "";
|
||||
srv->_handlers->getMenuOut(&buf);
|
||||
return buf.c_str();
|
||||
}
|
||||
|
||||
const char* WiFiManagerServer::tplGetStatus() {
|
||||
static String buf;
|
||||
auto srv = WiFiManagerServer::instance();
|
||||
if (!srv || !srv->_handlers) { buf = ""; return buf.c_str(); }
|
||||
buf = "";
|
||||
srv->_handlers->reportStatus(buf);
|
||||
return buf.c_str();
|
||||
}
|
||||
|
||||
void WiFiManagerServer::setupTemplateEngine() {
|
||||
// Initialize shared placeholder registry once
|
||||
if (!_tplRegistry) {
|
||||
_tplRegistry = std::unique_ptr<PlaceholderRegistry>(new PlaceholderRegistry(12));
|
||||
} else {
|
||||
_tplRegistry->clear();
|
||||
}
|
||||
|
||||
// Register PROGMEM assets
|
||||
_tplRegistry->registerProgmemData("%STYLES%", CSS_STYLE);
|
||||
_tplRegistry->registerProgmemData("%SCRIPTS%", JS_SCRIPT);
|
||||
|
||||
// Register dynamic RAM getters
|
||||
_tplRegistry->registerRamData("%PAGE_TITLE%", &WiFiManagerServer::tplGetPageTitle);
|
||||
_tplRegistry->registerRamData("%SUBTITLE%", &WiFiManagerServer::tplGetSubtitle);
|
||||
_tplRegistry->registerRamData("%MENU%", &WiFiManagerServer::tplGetMenu);
|
||||
_tplRegistry->registerRamData("%STATUS%", &WiFiManagerServer::tplGetStatus);
|
||||
}
|
||||
|
||||
void WiFiManagerServer::createServer(uint16_t port) {
|
||||
@@ -38,6 +105,9 @@ void WiFiManagerServer::createServer(uint16_t port) {
|
||||
}
|
||||
|
||||
server.reset(new AsyncWebServer(port));
|
||||
|
||||
// Ensure template engine is ready whenever a server is (re)created
|
||||
setupTemplateEngine();
|
||||
}
|
||||
|
||||
void WiFiManagerServer::registerRoutes() {
|
||||
@@ -48,6 +118,11 @@ void WiFiManagerServer::registerRoutes() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure template engine is initialized before routes use it
|
||||
if (!_tplRegistry) {
|
||||
setupTemplateEngine();
|
||||
}
|
||||
|
||||
if (_wm->_webservercallback != NULL) {
|
||||
#ifdef WM_DEBUG_LEVEL
|
||||
_wm->DEBUG_WM(WM_DEBUG_VERBOSE, F("[CB] _webservercallback calling"));
|
||||
@@ -164,6 +239,9 @@ void WiFiManagerServer::shutdownServer() {
|
||||
dnsServer->stop(); // free heap ?
|
||||
dnsServer.reset();
|
||||
}
|
||||
|
||||
// Clear singleton on shutdown
|
||||
if (s_instance == this) s_instance = nullptr;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user