error indication via GET arg err=...

pull/30/head
Ondřej Hruška 7 years ago
parent b238390ca8
commit 3c202a1f50
  1. 8
      CMakeLists.txt
  2. 19
      html_orig/css/app.css
  3. 51
      html_orig/js/app.js
  4. 19
      html_orig/jssrc/appcommon.js
  5. 10
      html_orig/lang/en.php
  6. 1
      html_orig/packjs.sh
  7. 5
      html_orig/pages/_head.php
  8. 4
      html_orig/pages/_tail.php
  9. 15
      html_orig/sass/form/_form_layout.scss
  10. 9
      html_orig/sass/layout/_modal.scss
  11. 97
      user/cgi_appcfg.c
  12. 9
      user/cgi_appcfg.h
  13. 12
      user/cgi_wifi.c

@ -93,6 +93,8 @@ set(SOURCE_FILES
user/io.h user/io.h
user/cgi_wifi.c user/cgi_wifi.c
user/cgi_wifi.h user/cgi_wifi.h
user/cgi_appcfg.c
user/cgi_appcfg.h
user/cgi_ping.c user/cgi_ping.c
user/cgi_reset.c user/cgi_reset.c
user/uart_driver.c user/uart_driver.c
@ -113,7 +115,11 @@ set(SOURCE_FILES
user/cgi_sockets.h user/cgi_sockets.h
user/ansi_parser_callbacks.c user/ansi_parser_callbacks.c
user/ansi_parser_callbacks.h user/ansi_parser_callbacks.h
user/user_main.h user/wifimgr.c user/wifimgr.h user/persist.c user/persist.h) user/user_main.h
user/wifimgr.c
user/wifimgr.h
user/persist.c
user/persist.h)
include_directories(include) include_directories(include)
include_directories(user) include_directories(user)

@ -579,17 +579,12 @@ ul > * {
.NotifyMsg { .NotifyMsg {
position: fixed; position: fixed;
bottom: 2.61792rem; top: 1.618rem;
right: 2.61792rem;
padding: 0.61805rem 1rem; padding: 0.61805rem 1rem;
left: 50%;
-webkit-transform: translate(-50%, 0);
-moz-transform: translate(-50%, 0);
-ms-transform: translate(-50%, 0);
-o-transform: translate(-50%, 0);
transform: translate(-50%, 0);
-webkit-font-smoothing: subpixel-antialiased; -webkit-font-smoothing: subpixel-antialiased;
-webkit-transform: translateZ(0) scale(1, 1); -webkit-transform: translateZ(0) scale(1, 1);
background: #37a349; background: #3887d0;
color: white; color: white;
text-shadow: 0 0 2px black; text-shadow: 0 0 2px black;
box-shadow: 0 0 6px 0 rgba(0, 0, 0, 0.6); box-shadow: 0 0 6px 0 rgba(0, 0, 0, 0.6);
@ -740,6 +735,12 @@ input[type="number"], input[type="password"], input[type="text"], textarea, sele
input[type="number"] { input[type="number"] {
width: 125px; } width: 125px; }
.Box.errors .list {
color: crimson;
font-weight: bold; }
.Box.errors .lead {
color: white; }
form .Row { form .Row {
vertical-align: middle; vertical-align: middle;
margin: 12px auto; margin: 12px auto;
@ -794,6 +795,8 @@ form .Row {
user-select: none; user-select: none;
white-space: nowrap; white-space: nowrap;
word-wrap: normal; } word-wrap: normal; }
form .Row label.error {
color: crimson; }
form .Row input[type="range"] { form .Row input[type="range"] {
width: 200px; } width: 200px; }
@media screen and (max-width: 544px) { @media screen and (max-width: 544px) {

@ -852,6 +852,38 @@ function jsp() {
window.Modal = modal; window.Modal = modal;
})(); })();
(function (nt) {
var sel = '#notif';
var hideTmeo1; // timeout to start hiding (transition)
var hideTmeo2; // timeout to add the hidden class
nt.show = function (message, timeout) {
$(sel).html(message);
Modal.show(sel);
clearTimeout(hideTmeo1);
clearTimeout(hideTmeo2);
if (undef(timeout)) timeout = 2500;
hideTmeo1 = setTimeout(nt.hide, timeout);
};
nt.hide = function () {
var $m = $(sel);
$m.removeClass('visible');
hideTmeo2 = setTimeout(function () {
$m.addClass('hidden');
}, 250); // transition time
};
nt.init = function() {
$(sel).on('click', function() {
nt.hide(this);
});
};
})(window.Notify = {});
/** Global generic init */ /** Global generic init */
$.ready(function () { $.ready(function () {
// Checkbox UI (checkbox CSS and hidden input with int value) // Checkbox UI (checkbox CSS and hidden input with int value)
@ -915,7 +947,26 @@ $.ready(function () {
e.preventDefault(); e.preventDefault();
}); });
var errAt = location.search.indexOf('err=');
if (errAt !== -1 && qs('.Box.errors')) {
var errs = location.search.substr(errAt+4).split(',');
var hres = [];
errs.forEach(function(er) {
var lbl = qs('label[for="'+er+'"]');
if (lbl) {
lbl.classList.add('error');
hres.push(lbl.childNodes[0].textContent.trim().replace(/: ?$/, ''));
} else {
hres.push(er);
}
});
qs('.Box.errors .list').innerHTML = hres.join(', ');
qs('.Box.errors').classList.remove('hidden');
}
Modal.init(); Modal.init();
Notify.init();
}); });
$._loader = function(vis) { $._loader = function(vis) {

@ -61,7 +61,26 @@ $.ready(function () {
e.preventDefault(); e.preventDefault();
}); });
var errAt = location.search.indexOf('err=');
if (errAt !== -1 && qs('.Box.errors')) {
var errs = location.search.substr(errAt+4).split(',');
var hres = [];
errs.forEach(function(er) {
var lbl = qs('label[for="'+er+'"]');
if (lbl) {
lbl.classList.add('error');
hres.push(lbl.childNodes[0].textContent.trim().replace(/: ?$/, ''));
} else {
hres.push(er);
}
});
qs('.Box.errors .list').innerHTML = hres.join(', ');
qs('.Box.errors').classList.remove('hidden');
}
Modal.init(); Modal.init();
Notify.init();
}); });
$._loader = function(vis) { $._loader = function(vis) {

@ -13,11 +13,12 @@ return [
'title.term' => 'Terminal', 'title.term' => 'Terminal',
'net.ap' => 'Access Point DHCP Config', 'net.ap' => 'DHCP Server',
'net.sta' => 'Client IP Config', 'net.sta' => 'DHCP Client',
'net.explain_sta' => ' 'net.explain_sta' => '
Those settings affect the built-in DHCP client. Switching it off Those settings affect the built-in DHCP client used for
connecting to an external network. Switching DHCP (dynamic IP) off
makes ESPTerm use the configured static IP. Please double-check makes ESPTerm use the configured static IP. Please double-check
those settings before submitting, setting them incorrectly may those settings before submitting, setting them incorrectly may
make it hard to access ESPTerm via the external network.', make it hard to access ESPTerm via the external network.',
@ -33,7 +34,7 @@ return [
'net.ap_addr_ip' => 'Own IP address', 'net.ap_addr_ip' => 'Own IP address',
'net.ap_addr_mask' => 'Subnet mask', 'net.ap_addr_mask' => 'Subnet mask',
'net.sta_dhcp_enable' => 'Enable DHCP', 'net.sta_dhcp_enable' => 'Use dynamic IP',
'net.sta_addr_ip' => 'ESPTerm static IP', 'net.sta_addr_ip' => 'ESPTerm static IP',
'net.sta_addr_mask' => 'Subnet mask', 'net.sta_addr_mask' => 'Subnet mask',
'net.sta_addr_gw' => 'Gateway IP', 'net.sta_addr_gw' => 'Gateway IP',
@ -77,4 +78,5 @@ return [
'yes' => 'Yes', 'yes' => 'Yes',
'no' => 'No', 'no' => 'No',
'confirm' => 'OK', 'confirm' => 'OK',
'form_errors' => 'Validation errors for:',
]; ];

@ -5,5 +5,6 @@ echo "Packing js..."
cat jssrc/chibi.js \ cat jssrc/chibi.js \
jssrc/utils.js \ jssrc/utils.js \
jssrc/modal.js \ jssrc/modal.js \
jssrc/notif.js \
jssrc/appcommon.js \ jssrc/appcommon.js \
jssrc/term.js > js/app.js jssrc/term.js > js/app.js

@ -23,4 +23,9 @@ if (strpos($_GET['BODYCLASS'], 'cfg') !== false) {
<img src="/img/loader.gif" alt="Loading…" id="loader"> <img src="/img/loader.gif" alt="Loading…" id="loader">
<?php if ($cfg): ?> <?php if ($cfg): ?>
<h1><?= tr('menu.' . $_GET['page']) ?></h1> <h1><?= tr('menu.' . $_GET['page']) ?></h1>
<div class="Box errors hidden">
<span class="lead"><?= tr('form_errors') ?></span>&nbsp;<span class="list"></span>
</div>
<?php endif; ?> <?php endif; ?>

@ -1,5 +1,9 @@
<div class="NotifyMsg hidden" id="notif"></div>
</div> </div>
</div> </div>
</body> </body>
</html> </html>

@ -9,6 +9,17 @@ input[type="number"] {
width: $form-field-w/2; width: $form-field-w/2;
} }
.Box.errors {
.list {
color: crimson;
font-weight: bold;
}
.lead {
color: white;
}
}
form .Row { form .Row {
vertical-align: middle; vertical-align: middle;
margin: 12px auto; margin: 12px auto;
@ -89,6 +100,10 @@ form .Row {
@include nowrap; @include nowrap;
} }
label.error {
color: crimson;
}
//.checkbox-wrap { //.checkbox-wrap {
// display: inline-block; // display: inline-block;
// width: $form-label-w; // width: $form-label-w;

@ -43,17 +43,18 @@
// "toast" // "toast"
.NotifyMsg { .NotifyMsg {
position: fixed; position: fixed;
bottom: dist(2); top: dist(1);
right: dist(2);
padding: dist(-1) dist(0); padding: dist(-1) dist(0);
// center horizontally // center horizontally
left: 50%; //left: 50%;
@include translate(-50%,0); //@include translate(-50%,0);
// hack to remove blur in chrome // hack to remove blur in chrome
-webkit-font-smoothing: subpixel-antialiased; -webkit-font-smoothing: subpixel-antialiased;
-webkit-transform: translateZ(0) scale(1.0, 1.0); -webkit-transform: translateZ(0) scale(1.0, 1.0);
background: #37a349; background: #3887d0;
&.error { &.error {
background: #d03e42; background: #d03e42;
} }

@ -0,0 +1,97 @@
/*
Cgi/template routines for configuring non-wifi settings
*/
#include <esp8266.h>
#include "cgi_wifi.h"
#include "wifimgr.h"
#include "persist.h"
// strcpy that adds 0 at the end of the buffer. Returns void.
#define strncpy_safe(dst, src, n) do { strncpy((char *)(dst), (char *)(src), (n)); (dst)[(n)-1]=0; } while (0)
/**
* Universal CGI endpoint to set WiFi params.
* Note that some may cause a (delayed) restart.
*/
httpd_cgi_state ICACHE_FLASH_ATTR cgiAppCfgSet(HttpdConnData *connData)
{
static ETSTimer timer;
char buff[50];
#define REDIR_BASE_URL "/wifi?err="
char redir_url_buf[300];
char *redir_url = redir_url_buf;
redir_url += sprintf(redir_url, REDIR_BASE_URL);
// we'll test if anything was printed by looking for \0 in failed_keys_buf
if (connData->conn == NULL) {
//Connection aborted. Clean up.
return HTTPD_CGI_DONE;
}
#define GET_ARG(key) (httpdFindArg(connData->getArgs, key, buff, sizeof(buff)) > 0)
// TODO
if (GET_ARG("opmode")) {
dbg("Setting WiFi opmode to: %s", buff);
int mode = atoi(buff);
if (mode > NULL_MODE && mode < MAX_MODE) {
wificonf->opmode = (WIFI_MODE) mode;
} else {
warn("Bad opmode value \"%s\"", buff);
redir_url += sprintf(redir_url, "opmode,");
}
}
if (redir_url_buf[strlen(REDIR_BASE_URL)] == 0) {
// All was OK
info("Set WiFi params - success, applying in 1000 ms");
// Settings are applied only if all was OK
//
// This is so that options that consist of multiple keys sent together are not applied
// only partially if set wrong, which could lead to eg. user losing access and having
// to reset to defaults.
persist_store();
// Delayed settings apply, so the response page has a chance to load.
// If user connects via the Station IF, they may not even notice the connection reset.
os_timer_disarm(&timer);
os_timer_setfn(&timer, applyWifiSettingsLaterCb, NULL);
os_timer_arm(&timer, 1000, false);
httpdRedirect(connData, "/wifi");
} else {
warn("Some WiFi settings did not validate, asking for correction");
// Some errors, appended to the URL as ?err=
httpdRedirect(connData, redir_url_buf);
}
return HTTPD_CGI_DONE;
}
//Template code for the WLAN page.
httpd_cgi_state ICACHE_FLASH_ATTR tplAppCfg(HttpdConnData *connData, char *token, void **arg)
{
char buff[100];
int x;
int connectStatus;
if (token == NULL) {
// We're done
return HTTPD_CGI_DONE;
}
strcpy(buff, ""); // fallback
// TODO
if (streq(token, "opmode_name")) {
strcpy(buff, opmode2str(wificonf->opmode));
}
httpdSend(connData, buff, -1);
return HTTPD_CGI_DONE;
}

@ -0,0 +1,9 @@
#ifndef CGIAPPCFG_H
#define CGIAPPCFG_H
#include "httpd.h"
httpd_cgi_state cgiAppCfgSet(HttpdConnData *connData);
httpd_cgi_state tplAppCfg(HttpdConnData *connData, char *token, void **arg);
#endif

@ -13,17 +13,13 @@ Cgi/template routines for the /wifi url.
* File adapted and improved by Ondřej Hruška <ondra@ondrovo.com> * File adapted and improved by Ondřej Hruška <ondra@ondrovo.com>
*/ */
// TODO convert to work with WiFi Manager
// TODO make changes write to wificonf and apply when a different CGI is run (/wifi/apply or something)
// TODO (connection will trigger this immediately, with some delayto show the connecting page. Then polling cna proceed as usual)
#include <esp8266.h> #include <esp8266.h>
#include "cgi_wifi.h" #include "cgi_wifi.h"
#include "wifimgr.h" #include "wifimgr.h"
#include "persist.h" #include "persist.h"
// strcpy that adds 0 at the end of the buffer. Returns void. // strcpy that adds 0 at the end of the buffer. Returns void.
#define strncpy_safe(dst, src, n) do { strncpy((char *)(dst), (char *)(src), (n)); dst[(n)-1]=0; } while (0) #define strncpy_safe(dst, src, n) do { strncpy((char *)(dst), (char *)(src), (n)); (dst)[(n)-1]=0; } while (0)
/** WiFi access point data */ /** WiFi access point data */
typedef struct { typedef struct {
@ -419,9 +415,11 @@ httpd_cgi_state ICACHE_FLASH_ATTR cgiWiFiSetParams(HttpdConnData *connData)
char buff[50]; char buff[50];
#define REDIR_BASE_URL "/wifi?err="
char redir_url_buf[300]; char redir_url_buf[300];
char *redir_url = redir_url_buf; char *redir_url = redir_url_buf;
redir_url += sprintf(redir_url, "/wifi?err="); redir_url += sprintf(redir_url, REDIR_BASE_URL);
// we'll test if anything was printed by looking for \0 in failed_keys_buf // we'll test if anything was printed by looking for \0 in failed_keys_buf
if (connData->conn == NULL) { if (connData->conn == NULL) {
@ -707,7 +705,7 @@ httpd_cgi_state ICACHE_FLASH_ATTR cgiWiFiSetParams(HttpdConnData *connData)
} }
} }
if (redir_url_buf[10] == 0) { if (redir_url_buf[strlen(REDIR_BASE_URL)] == 0) {
// All was OK // All was OK
info("Set WiFi params - success, applying in 1000 ms"); info("Set WiFi params - success, applying in 1000 ms");

Loading…
Cancel
Save