diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7fa43d7..2701a1e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -93,6 +93,8 @@ set(SOURCE_FILES
user/io.h
user/cgi_wifi.c
user/cgi_wifi.h
+ user/cgi_appcfg.c
+ user/cgi_appcfg.h
user/cgi_ping.c
user/cgi_reset.c
user/uart_driver.c
@@ -113,7 +115,11 @@ set(SOURCE_FILES
user/cgi_sockets.h
user/ansi_parser_callbacks.c
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(user)
diff --git a/html_orig/css/app.css b/html_orig/css/app.css
index 79949aa..f425e9a 100644
--- a/html_orig/css/app.css
+++ b/html_orig/css/app.css
@@ -579,17 +579,12 @@ ul > * {
.NotifyMsg {
position: fixed;
- bottom: 2.61792rem;
+ top: 1.618rem;
+ right: 2.61792rem;
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-transform: translateZ(0) scale(1, 1);
- background: #37a349;
+ background: #3887d0;
color: white;
text-shadow: 0 0 2px black;
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"] {
width: 125px; }
+.Box.errors .list {
+ color: crimson;
+ font-weight: bold; }
+.Box.errors .lead {
+ color: white; }
+
form .Row {
vertical-align: middle;
margin: 12px auto;
@@ -794,6 +795,8 @@ form .Row {
user-select: none;
white-space: nowrap;
word-wrap: normal; }
+ form .Row label.error {
+ color: crimson; }
form .Row input[type="range"] {
width: 200px; }
@media screen and (max-width: 544px) {
diff --git a/html_orig/js/app.js b/html_orig/js/app.js
index fc1db8c..204e008 100644
--- a/html_orig/js/app.js
+++ b/html_orig/js/app.js
@@ -852,6 +852,38 @@ function jsp() {
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 */
$.ready(function () {
// Checkbox UI (checkbox CSS and hidden input with int value)
@@ -915,7 +947,26 @@ $.ready(function () {
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();
+ Notify.init();
});
$._loader = function(vis) {
diff --git a/html_orig/jssrc/appcommon.js b/html_orig/jssrc/appcommon.js
index a40faa6..ee4569c 100644
--- a/html_orig/jssrc/appcommon.js
+++ b/html_orig/jssrc/appcommon.js
@@ -61,7 +61,26 @@ $.ready(function () {
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();
+ Notify.init();
});
$._loader = function(vis) {
diff --git a/html_orig/lang/en.php b/html_orig/lang/en.php
index 08bfd23..f866c36 100644
--- a/html_orig/lang/en.php
+++ b/html_orig/lang/en.php
@@ -13,11 +13,12 @@ return [
'title.term' => 'Terminal',
- 'net.ap' => 'Access Point DHCP Config',
- 'net.sta' => 'Client IP Config',
+ 'net.ap' => 'DHCP Server',
+ 'net.sta' => 'DHCP Client',
'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
those settings before submitting, setting them incorrectly may
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_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_mask' => 'Subnet mask',
'net.sta_addr_gw' => 'Gateway IP',
@@ -77,4 +78,5 @@ return [
'yes' => 'Yes',
'no' => 'No',
'confirm' => 'OK',
+ 'form_errors' => 'Validation errors for:',
];
diff --git a/html_orig/packjs.sh b/html_orig/packjs.sh
index 53c9e69..f1652fd 100755
--- a/html_orig/packjs.sh
+++ b/html_orig/packjs.sh
@@ -5,5 +5,6 @@ echo "Packing js..."
cat jssrc/chibi.js \
jssrc/utils.js \
jssrc/modal.js \
+ jssrc/notif.js \
jssrc/appcommon.js \
jssrc/term.js > js/app.js
diff --git a/html_orig/pages/_head.php b/html_orig/pages/_head.php
index 3134c1c..a6d428d 100644
--- a/html_orig/pages/_head.php
+++ b/html_orig/pages/_head.php
@@ -23,4 +23,9 @@ if (strpos($_GET['BODYCLASS'], 'cfg') !== false) {