1
0
mirror of https://github.com/s00500/ESPUI.git synced 2025-11-27 23:03:16 +00:00

Merge pull request #333 from emmby/master

User-defined JavaScript
This commit is contained in:
2025-11-26 21:15:57 +01:00
committed by GitHub
6 changed files with 49 additions and 3 deletions

View File

@@ -667,6 +667,25 @@ All the example sketches include the DNS related code and will work as captive p
ESPUI.captivePortal = false; ESPUI.captivePortal = false;
``` ```
### User-defined JavaScript
You can add your own custom JavaScript to the UI. This allows you to create custom controls, handle events, or otherwise extend the functionality of the UI.
To add custom JavaScript, call `ESPUI.setCustomJS()` before `ESPUI.begin()`. The argument to `setCustomJS()` is a C-string containing the JavaScript code. This string must remain valid for the lifetime of the ESPUIClass instance.
```cpp
const char* myCustomJS = "alert('Hello from custom JS!');";
void setup() {
// ...
ESPUI.setCustomJS(myCustomJS);
ESPUI.begin("ESPUI Control");
// ...
}
```
The custom JavaScript is served at `/js/custom.js` and is automatically included in the `index.htm` file.
# Notes for Development # Notes for Development

View File

@@ -16,6 +16,7 @@
<script src="/js/graph.js"></script> <script src="/js/graph.js"></script>
<script src="/js/controls.js"></script> <script src="/js/controls.js"></script>
<script src="/js/tabbedcontent.js"></script> <script src="/js/tabbedcontent.js"></script>
<script src="/js/custom.js"></script>
</head> </head>
<body onload="javascript:start();"> <body onload="javascript:start();">

View File

@@ -1 +1 @@
<!doctype html><meta charset=utf-8><title>Control</title><meta content="width=device-width,initial-scale=1" name=viewport><link rel="shortcut icon" href=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAPFBMVEUAAACA1VWR21qQ2liR3FqR3FqS3VuR3VqR3VuR3VqO21mS21uS3FqS3FqS21uJ2GKQ21qR3FuR3FoAAAB/3Gu7AAAAEnRSTlMABoA3kPBwz8i5Kzioxg4NVcU3uEJHAAAAAWJLR0QAiAUdSAAAAAlwSFlzAAAN1wAADdcBQiibeAAAAAd0SU1FB+EFEhcEM+HpYwQAAABYSURBVBjThY/JDsAgCESt4lpX/v9jLQZJ6qF9t3khAyj1xXUKbQ4BVowDwqOYgExkkW4iY6lPaF06RqM8YItOuRbMaz6xjbsusDAW/drplBg47jP696cXE8bPA1eUDeK2AAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE3LTA1LTE4VDIzOjA0OjUxKzAyOjAwxE59ewAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNy0wNS0xOFQyMzowNDo1MSswMjowMLUTxccAAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb7jwaAAAAAElFTkSuQmCC><link href=/css/normalize.css rel=stylesheet><link href=/css/style.css rel=stylesheet><script src=/js/zepto.min.js></script><script src=/js/slider.js></script><script src=/js/graph.js></script><script src=/js/controls.js></script><script src=/js/tabbedcontent.js></script><body onload=javascript:start();><div><h4><div id=mainHeader>Control</div> <span class=label id=conStatus>Offline</span></h4></div><hr><div class=container><div class="row u-full-width" id=row></div><ul class="navigation navigation-tabs u-full-width" id=tabsnav></ul><div class="tabscontent u-full-width" id=tabscontent></div></div> <!DOCTYPE html><html> <head><meta charset=utf-8><title>Control</title><meta name=viewport content="width=device-width, initial-scale=1"><link rel="shortcut icon" href=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAPFBMVEUAAACA1VWR21qQ2liR3FqR3FqS3VuR3VqR3VuR3VqO21mS21uS3FqS3FqS21uJ2GKQ21qR3FuR3FoAAAB/3Gu7AAAAEnRSTlMABoA3kPBwz8i5Kzioxg4NVcU3uEJHAAAAAWJLR0QAiAUdSAAAAAlwSFlzAAAN1wAADdcBQiibeAAAAAd0SU1FB+EFEhcEM+HpYwQAAABYSURBVBjThY/JDsAgCESt4lpX/v9jLQZJ6qF9t3khAyj1xXUKbQ4BVowDwqOYgExkkW4iY6lPaF06RqM8YItOuRbMaz6xjbsusDAW/drplBg47jP696cXE8bPA1eUDeK2AAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE3LTA1LTE4VDIzOjA0OjUxKzAyOjAwxE59ewAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNy0wNS0xOFQyMzowNDo1MSswMjowMLUTxccAAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb7jwaAAAAAElFTkSuQmCC><link rel=stylesheet href=/css/normalize.css><link rel=stylesheet href=/css/style.css><script src=/js/zepto.min.js></script><script src=/js/slider.js></script><script src=/js/graph.js></script><script src=/js/controls.js></script><script src=/js/tabbedcontent.js></script><script src=/js/custom.js></script></head> <body onload=javascript:start();> <div> <h4> <div id=mainHeader>Control</div> <span id=conStatus class=label>Offline</span> </h4> </div> <hr> <div class=container> <div id=row class="row u-full-width"></div> <ul id=tabsnav class="navigation navigation-tabs u-full-width"></ul> <div id=tabscontent class="tabscontent u-full-width"></div> </div> </body> </html>

View File

@@ -17,6 +17,18 @@
#include <umm_malloc/umm_heap_select.h> #include <umm_malloc/umm_heap_select.h>
#endif #endif
// Optional user-defined JavaScript to be included in the UI.
// Served at /js/custom.js, which is automatically included in index.htm.
// js: JavaScript code as a C-string. Must remain valid for the lifetime of the ESPUIClass instance.
static const char* customJS = nullptr;
// Set custom JavaScript to be included in the UI.
// js: JavaScript code as a C-string. Must remain valid for the lifetime of the ESPUIClass instance.
void ESPUIClass::setCustomJS(const char* js)
{
customJS = js;
}
static String heapInfo(const __FlashStringHelper* mode) static String heapInfo(const __FlashStringHelper* mode)
{ {
String result; String result;
@@ -1272,6 +1284,15 @@ void ESPUIClass::begin(const char* _title, const char* username, const char* pas
yield(); yield();
}); });
server->on("/js/custom.js", HTTP_GET, [](AsyncWebServerRequest* request) {
if (ESPUI.basicAuth && !request->authenticate(ESPUI.basicAuthUsername, ESPUI.basicAuthPassword))
{
return request->requestAuthentication();
}
request->send(200, "application/javascript", customJS ? customJS : "");
});
server->begin(); server->begin();
#if defined(DEBUG_ESPUI) #if defined(DEBUG_ESPUI)

View File

@@ -201,6 +201,11 @@ public:
void updateVisibility(uint16_t id, bool visibility, int clientId = -1); void updateVisibility(uint16_t id, bool visibility, int clientId = -1);
// Set optional user-defined JavaScript to be included in the UI.
// js: JavaScript code as a C-string. Must remain valid for the lifetime of the ESPUIClass instance.
// This is intentionally not a String to avoid dynamic memory allocation.
void setCustomJS(const char* js);
// Variables // Variables
const char* ui_title = "ESPUI"; // Store UI Title and Header Name const char* ui_title = "ESPUI"; // Store UI Title and Header Name
Control* controls = nullptr; Control* controls = nullptr;

View File

@@ -1,5 +1,5 @@
const char HTML_INDEX[] PROGMEM = R"=====( const char HTML_INDEX[] PROGMEM = R"=====(
<!doctype html><meta charset=utf-8><title>Control</title><meta content="width=device-width,initial-scale=1" name=viewport><link rel="shortcut icon" href=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAPFBMVEUAAACA1VWR21qQ2liR3FqR3FqS3VuR3VqR3VuR3VqO21mS21uS3FqS3FqS21uJ2GKQ21qR3FuR3FoAAAB/3Gu7AAAAEnRSTlMABoA3kPBwz8i5Kzioxg4NVcU3uEJHAAAAAWJLR0QAiAUdSAAAAAlwSFlzAAAN1wAADdcBQiibeAAAAAd0SU1FB+EFEhcEM+HpYwQAAABYSURBVBjThY/JDsAgCESt4lpX/v9jLQZJ6qF9t3khAyj1xXUKbQ4BVowDwqOYgExkkW4iY6lPaF06RqM8YItOuRbMaz6xjbsusDAW/drplBg47jP696cXE8bPA1eUDeK2AAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE3LTA1LTE4VDIzOjA0OjUxKzAyOjAwxE59ewAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNy0wNS0xOFQyMzowNDo1MSswMjowMLUTxccAAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb7jwaAAAAAElFTkSuQmCC><link href=/css/normalize.css rel=stylesheet><link href=/css/style.css rel=stylesheet><script src=/js/zepto.min.js></script><script src=/js/slider.js></script><script src=/js/graph.js></script><script src=/js/controls.js></script><script src=/js/tabbedcontent.js></script><body onload=javascript:start();><div><h4><div id=mainHeader>Control</div> <span class=label id=conStatus>Offline</span></h4></div><hr><div class=container><div class="row u-full-width" id=row></div><ul class="navigation navigation-tabs u-full-width" id=tabsnav></ul><div class="tabscontent u-full-width" id=tabscontent></div></div> <!DOCTYPE html><html> <head><meta charset=utf-8><title>Control</title><meta name=viewport content="width=device-width, initial-scale=1"><link rel="shortcut icon" href=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAPFBMVEUAAACA1VWR21qQ2liR3FqR3FqS3VuR3VqR3VuR3VqO21mS21uS3FqS3FqS21uJ2GKQ21qR3FuR3FoAAAB/3Gu7AAAAEnRSTlMABoA3kPBwz8i5Kzioxg4NVcU3uEJHAAAAAWJLR0QAiAUdSAAAAAlwSFlzAAAN1wAADdcBQiibeAAAAAd0SU1FB+EFEhcEM+HpYwQAAABYSURBVBjThY/JDsAgCESt4lpX/v9jLQZJ6qF9t3khAyj1xXUKbQ4BVowDwqOYgExkkW4iY6lPaF06RqM8YItOuRbMaz6xjbsusDAW/drplBg47jP696cXE8bPA1eUDeK2AAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE3LTA1LTE4VDIzOjA0OjUxKzAyOjAwxE59ewAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNy0wNS0xOFQyMzowNDo1MSswMjowMLUTxccAAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb7jwaAAAAAElFTkSuQmCC><link rel=stylesheet href=/css/normalize.css><link rel=stylesheet href=/css/style.css><script src=/js/zepto.min.js></script><script src=/js/slider.js></script><script src=/js/graph.js></script><script src=/js/controls.js></script><script src=/js/tabbedcontent.js></script><script src=/js/custom.js></script></head> <body onload=javascript:start();> <div> <h4> <div id=mainHeader>Control</div> <span id=conStatus class=label>Offline</span> </h4> </div> <hr> <div class=container> <div id=row class="row u-full-width"></div> <ul id=tabsnav class="navigation navigation-tabs u-full-width"></ul> <div id=tabscontent class="tabscontent u-full-width"></div> </div> </body> </html>
)====="; )=====";
const uint8_t HTML_INDEX_GZIP[896] PROGMEM = { 31,139,8,0,198,61,36,105,2,255,125,84,109,115,162,58,20,254,43,92,63,221,59,187,45,34,214,182,187,226,76,80,208,170,168,128,224,203,183,0,169,4,195,75,73,16,245,215,223,4,219,217,233,116,167,204,36,57,121,206,115,158,115,56,132,244,255,137,242,144,93,10,36,197,44,37,131,126,138,24,148,194,24,150,20,49,173,98,175,119,79,131,62,195,140,160,193,48,207,88,153,147,190,124,219,190,51,57,136,50,166,181,106,28,177,88,139,208,9,135,232,174,217,252,196,25,102,24,146,59,26,66,130,52,165,37,101,48,69,218,9,163,186,200,75,54,232,19,156,29,165,18,17,173,69,99,14,132,21,147,48,215,107,73,113,137,94,181,8,50,248,11,167,240,128,228,34,59,252,14,32,69,189,238,79,236,235,75,167,110,207,198,135,28,240,103,225,122,177,225,29,184,165,139,45,176,135,192,18,107,62,183,159,215,194,208,199,145,190,246,12,0,230,227,213,80,62,199,186,205,193,161,158,184,230,116,193,189,189,41,143,61,188,112,112,37,244,134,160,199,231,72,68,46,11,161,218,75,249,100,170,195,176,34,198,147,208,91,153,186,229,27,94,195,85,252,141,211,81,222,236,14,193,142,106,190,137,225,170,126,229,168,62,183,111,235,178,163,164,110,71,169,220,198,199,7,183,167,157,241,204,230,113,156,207,57,166,200,171,203,234,184,122,20,250,70,230,184,107,98,1,61,7,234,113,165,215,215,39,252,48,187,226,252,124,232,46,252,208,83,43,99,58,105,222,116,51,157,59,109,27,96,224,69,110,3,144,218,53,201,85,244,68,169,1,24,69,161,110,99,28,160,198,23,181,93,79,49,245,31,134,105,196,161,97,253,152,20,187,90,52,66,223,185,158,163,251,122,178,142,119,242,116,68,193,97,104,184,172,75,138,173,124,122,78,230,246,126,218,123,51,159,153,122,140,193,37,81,206,91,111,22,216,93,221,207,235,81,253,182,220,29,140,243,241,184,233,226,93,143,172,160,217,238,57,111,214,211,238,133,45,43,39,176,224,181,119,78,2,90,209,17,216,200,81,89,16,253,208,125,76,86,189,231,94,184,53,158,130,21,80,144,55,66,179,142,168,110,186,117,204,205,196,57,238,182,14,89,166,139,203,126,99,182,247,54,184,88,35,67,157,175,129,50,95,27,93,127,244,114,93,38,160,189,76,188,243,236,10,46,220,174,207,198,195,51,170,197,167,240,219,142,31,183,247,99,30,183,46,88,208,113,138,125,118,4,86,2,206,139,75,187,94,184,237,243,210,180,47,214,53,175,23,163,92,177,92,90,91,73,94,91,115,111,125,14,67,81,194,62,50,252,93,100,46,78,251,204,81,119,219,41,1,147,72,141,46,15,69,144,178,235,174,99,214,123,247,225,20,166,40,120,76,106,216,180,212,32,230,250,232,86,118,58,28,190,159,228,230,212,202,33,165,114,150,151,41,36,248,138,238,249,174,57,225,148,93,8,162,49,66,236,11,185,113,253,149,72,195,18,23,76,162,101,168,201,9,149,175,168,96,249,125,138,179,251,132,14,250,242,205,251,133,69,9,142,80,249,45,229,80,194,34,254,150,17,222,126,117,250,45,137,193,32,64,209,251,5,240,153,25,228,209,69,202,51,146,195,72,75,224,9,222,240,95,148,193,146,253,251,223,239,65,63,194,167,65,63,238,54,134,132,35,45,133,56,155,32,200,43,255,115,205,8,142,212,167,5,204,164,144,64,74,53,2,3,68,4,155,231,116,25,100,21,29,44,95,95,121,59,17,207,204,105,188,0,33,41,223,196,203,155,248,45,84,84,201,83,160,79,96,171,204,107,169,186,123,173,8,185,221,88,45,33,206,193,15,141,138,124,48,51,120,194,7,200,112,158,73,127,204,59,222,1,250,85,64,160,156,196,69,42,242,41,157,112,188,183,235,239,81,239,206,143,244,205,252,63,223,19,75,188,160,5,0,0 }; const uint8_t HTML_INDEX_GZIP[923] PROGMEM = { 31,139,8,0,111,41,29,105,2,255,133,148,109,115,162,58,20,199,191,10,215,87,247,206,110,139,138,181,237,174,58,19,20,108,85,84,64,240,225,93,128,20,130,225,161,36,136,250,233,55,1,59,221,59,123,167,215,25,146,147,156,223,249,159,228,8,103,240,215,100,53,222,236,215,154,20,177,132,140,6,245,40,13,34,4,131,209,32,65,12,74,126,4,11,138,216,176,100,111,119,79,163,1,195,140,160,209,56,75,89,145,145,129,220,44,27,50,133,9,26,158,48,170,242,172,96,146,207,17,148,178,97,171,194,1,139,134,1,58,97,31,221,213,139,239,18,78,49,195,144,220,81,31,18,52,236,180,70,3,130,211,163,84,32,50,108,209,136,135,251,37,147,48,151,104,73,81,129,222,134,1,100,240,7,78,96,136,228,60,13,127,122,144,162,126,239,59,118,213,149,85,181,231,211,48,3,252,183,180,157,72,115,66,110,169,98,9,204,49,48,196,156,45,204,231,141,48,212,105,160,110,28,13,128,197,116,61,150,207,145,106,242,205,177,26,219,250,108,201,189,253,25,143,13,95,249,230,90,232,141,65,159,143,129,136,92,229,66,181,159,240,65,87,198,126,73,180,39,161,183,214,85,195,213,156,154,237,184,91,171,219,121,55,187,4,91,138,254,46,30,91,113,75,75,113,185,221,204,171,110,39,177,187,157,210,174,125,252,225,246,172,59,157,155,60,142,243,156,209,69,94,85,86,166,229,163,208,215,82,203,222,16,3,168,25,80,142,107,181,186,62,225,135,249,21,103,231,176,183,116,125,71,41,181,217,75,125,211,237,108,97,181,77,128,129,19,216,245,6,169,108,157,92,69,77,58,21,0,147,192,87,77,140,61,84,251,130,182,237,116,116,245,155,166,107,145,175,25,223,94,242,125,37,10,161,238,109,199,82,93,53,222,68,123,121,54,161,32,28,107,54,235,145,124,39,159,158,227,133,121,152,245,223,245,103,166,28,35,112,137,59,231,157,51,247,204,158,234,102,213,164,122,95,237,67,237,124,60,110,123,120,223,39,107,168,183,251,214,187,241,180,127,101,171,210,242,12,120,237,159,99,143,150,116,2,182,114,80,228,68,13,123,143,241,186,255,220,247,119,218,147,183,6,29,228,76,208,188,43,78,55,219,89,250,246,197,58,238,119,22,89,37,203,203,97,171,183,15,38,184,24,19,77,89,108,64,103,177,209,122,238,228,245,186,138,65,123,21,59,231,249,21,92,184,93,157,181,135,103,84,137,191,194,109,91,110,212,62,76,121,220,38,103,94,215,202,15,233,17,24,49,56,47,47,237,106,105,183,207,43,221,188,24,215,172,90,78,178,142,97,211,202,136,179,202,88,56,155,179,239,139,35,28,2,205,221,7,250,242,116,72,45,101,191,155,17,240,18,40,193,229,33,247,18,118,221,119,245,234,96,63,156,252,4,121,143,113,5,235,146,106,68,223,28,237,210,76,198,227,223,222,100,202,46,4,209,8,33,214,188,196,178,79,169,156,102,69,2,9,190,162,123,190,250,63,184,222,108,64,234,23,56,103,18,45,252,161,28,83,249,138,114,150,221,39,56,189,143,185,83,110,188,127,80,148,224,0,21,95,34,97,1,243,232,75,194,111,190,117,250,37,196,160,231,161,224,246,205,127,45,87,82,150,37,255,70,228,186,223,72,3,47,11,46,82,150,146,12,6,195,24,158,96,227,255,65,25,44,216,223,255,252,228,68,128,79,162,61,245,26,83,194,193,48,129,56,125,225,225,168,248,236,74,13,69,115,152,10,130,159,202,102,144,149,84,242,9,164,116,72,160,135,200,104,245,246,198,139,143,248,33,56,198,105,185,22,189,133,70,197,45,65,19,33,238,197,211,160,226,51,109,145,85,55,103,75,152,229,221,91,73,72,211,222,120,55,187,201,148,68,160,188,54,52,133,31,90,45,110,226,16,50,156,165,210,167,121,39,160,63,84,74,242,153,80,0,183,250,126,40,253,190,245,223,7,248,152,68,97,235,59,214,237,253,23,75,224,118,101,245,5,0,0 };