Much better wifi config, added display for IP etc, improved "connecting" page

pull/30/head
Ondřej Hruška 8 years ago
parent 78c2f9ee52
commit 0f7fb9430c
  1. 2
      build_web.sh
  2. 129
      html/css/app.css
  3. 188
      html/js/app.js
  4. 53
      html/wifi.tpl
  5. 26
      html/wifi_conn.tpl
  6. 129
      html_orig/css/app.css
  7. 189
      html_orig/js/app.js
  8. 4
      html_orig/jssrc/appcommon.js
  9. 42
      html_orig/jssrc/chibi.js
  10. 41
      html_orig/jssrc/modal.js
  11. 101
      html_orig/jssrc/wifi.js
  12. 1
      html_orig/packjs.sh
  13. 13
      html_orig/sass/_layout.scss
  14. 78
      html_orig/sass/_modal.scss
  15. 1
      html_orig/sass/app.scss
  16. 2
      html_orig/sass/form/_buttons.scss
  17. 8
      html_orig/sass/form/_index.scss
  18. 5
      html_orig/sass/pages/_term.scss
  19. 21
      html_orig/sass/pages/_wifi.scss
  20. 53
      html_orig/wifi.html
  21. 60
      html_orig/wifi1.html
  22. 26
      html_orig/wifi_conn.html
  23. 2
      libesphttpd
  24. 3
      user/routes.c
  25. 2
      user/screen.c

@ -6,6 +6,7 @@ echo "-- Preparing WWW files --"
DD=html_orig/jssrc DD=html_orig/jssrc
cat $DD/chibi.js \ cat $DD/chibi.js \
$DD/utils.js \ $DD/utils.js \
$DD/modal.js \
$DD/appcommon.js \ $DD/appcommon.js \
$DD/term.js \ $DD/term.js \
$DD/wifi.js > html/js/app.js $DD/wifi.js > html/js/app.js
@ -14,5 +15,6 @@ cat $DD/chibi.js \
cp html_orig/css/app.css html/css/app.css cp html_orig/css/app.css html/css/app.css
cp html_orig/term.html html/term.tpl cp html_orig/term.html html/term.tpl
cp html_orig/wifi.html html/wifi.tpl cp html_orig/wifi.html html/wifi.tpl
cp html_orig/wifi_conn.html html/wifi_conn.tpl
cp html_orig/img/loader.gif html/img/loader.gif cp html_orig/img/loader.gif html/img/loader.gif
cp html_orig/favicon.ico html/favicon.ico cp html_orig/favicon.ico html/favicon.ico

@ -319,6 +319,78 @@ html {
[onclick] { [onclick] {
cursor: pointer; } cursor: pointer; }
.Modal {
position: fixed;
width: 100%;
height: 100%;
left: 0;
top: 0;
right: 0;
bottom: 0;
display: flex;
justify-content: center;
align-items: center;
transition: opacity .5s;
background: rgba(0, 0, 0, 0.65);
opacity: 0; }
.Modal.visible {
opacity: 1; }
.Modal.hidden {
display: none; }
.Dialog {
margin: 0.61805rem;
padding: 1rem;
overflow: hidden;
max-width: 100%;
max-height: 100%;
flex: 0 1 30rem;
background: #1c1c1e;
border-left: 6px solid #2972ba;
border-right: 6px solid #2972ba;
box-shadow: 0 0 2px 0 #434349, 0 0 6px 0 black;
border-radius: 6px; }
.Dialog h1, .Dialog h2 {
margin-top: 0; }
.Dialog p:last-child {
margin-bottom: 0; }
/*
// "toast"
.NotifyMsg {
position: fixed;
bottom: dist(2);
padding: dist(-1) dist(0);
// center horizontally
left: 50%;
@include translate(-50%,0);
// hack to remove blur in chrome
-webkit-font-smoothing: subpixel-antialiased;
-webkit-transform: translateZ(0) scale(1.0, 1.0);
background: #37a349;
&.error {
background: #d03e42;
}
color: white;
text-shadow: 0 0 2px black;
box-shadow: 0 0 6px 0 rgba(black, .6);
border-radius: 5px;
max-width: 80%;
@include media($phone) {
width: calc(100% - 1rem);
}
transition: opacity .5s;
opacity: 0;
&.visible { opacity: 1 }
&.hidden { display: none }
}
*/
html { html {
font-family: Arial, sans-serif; font-family: Arial, sans-serif;
color: #D0D0D0; color: #D0D0D0;
@ -353,6 +425,8 @@ a:hover {
.Box { .Box {
margin-top: 0.61805rem; margin-top: 0.61805rem;
padding: 0.23608rem 0.38198rem; } } padding: 0.23608rem 0.38198rem; } }
.Box p:first-child {
margin-top: 0; }
body { body {
position: relative; position: relative;
@ -376,6 +450,11 @@ body {
@media screen and (min-width: 545px) and (max-width: 1000px) { @media screen and (min-width: 545px) and (max-width: 1000px) {
body h1 { body h1 {
font-size: 1.80203em; } } font-size: 1.80203em; } }
body h2 {
font-size: 1.26563em;
margin-bottom: 0.61805rem; }
body h2:first-child {
margin-top: 0; }
body td, body th { body td, body th {
padding: 0.38198rem; padding: 0.38198rem;
white-space: nowrap; } white-space: nowrap; }
@ -408,7 +487,7 @@ body {
#loader.show { #loader.show {
opacity: 1; } opacity: 1; }
button, input[type=submit] { button, input[type=submit], .button {
text-align: center; text-align: center;
cursor: pointer; cursor: pointer;
display: inline-block; display: inline-block;
@ -428,22 +507,22 @@ button, input[type=submit] {
background-color: #3983cd; background-color: #3983cd;
box-shadow: 0 3px 0 #265f98; box-shadow: 0 3px 0 #265f98;
text-decoration: none !important; } text-decoration: none !important; }
button:active, input[type=submit]:active { button:active, input[type=submit]:active, .button:active {
position: relative; position: relative;
top: 2px; } top: 2px; }
button.narrow, input[type=submit].narrow { button.narrow, input[type=submit].narrow, .button.narrow {
min-width: initial; } min-width: initial; }
button, button:link, button:visited, input[type=submit], input[type=submit]:link, input[type=submit]:visited { button, button:link, button:visited, input[type=submit], input[type=submit]:link, input[type=submit]:visited, .button, .button:link, .button:visited {
color: #FEFEFE; } color: #FEFEFE; }
button:hover, button:active, button.active, button.selected, input[type=submit]:hover, input[type=submit]:active, input[type=submit].active, input[type=submit].selected { button:hover, button:active, button.active, button.selected, input[type=submit]:hover, input[type=submit]:active, input[type=submit].active, input[type=submit].selected, .button:hover, .button:active, .button.active, .button.selected {
background-color: #2076C6; background-color: #2076C6;
color: #FEFEFE; } color: #FEFEFE; }
button:hover, button.selected, button.active, input[type=submit]:hover, input[type=submit].selected, input[type=submit].active { button:hover, button.selected, button.active, input[type=submit]:hover, input[type=submit].selected, input[type=submit].active, .button:hover, .button.selected, .button.active {
box-shadow: 0 3px 0 #154c80; } box-shadow: 0 3px 0 #154c80; }
button:active, input[type=submit]:active { button:active, input[type=submit]:active, .button:active {
box-shadow: 0 1px 0 #154c80; } box-shadow: 0 1px 0 #154c80; }
button, input[type=submit] { button, input[type=submit], .button {
text-align: center; text-align: center;
cursor: pointer; cursor: pointer;
display: inline-block; display: inline-block;
@ -463,19 +542,19 @@ button, input[type=submit] {
background-color: #3983cd; background-color: #3983cd;
box-shadow: 0 3px 0 #265f98; box-shadow: 0 3px 0 #265f98;
text-decoration: none !important; } text-decoration: none !important; }
button:active, input[type=submit]:active { button:active, input[type=submit]:active, .button:active {
position: relative; position: relative;
top: 2px; } top: 2px; }
button.narrow, input[type=submit].narrow { button.narrow, input[type=submit].narrow, .button.narrow {
min-width: initial; } min-width: initial; }
button, button:link, button:visited, input[type=submit], input[type=submit]:link, input[type=submit]:visited { button, button:link, button:visited, input[type=submit], input[type=submit]:link, input[type=submit]:visited, .button, .button:link, .button:visited {
color: #FEFEFE; } color: #FEFEFE; }
button:hover, button:active, button.active, button.selected, input[type=submit]:hover, input[type=submit]:active, input[type=submit].active, input[type=submit].selected { button:hover, button:active, button.active, button.selected, input[type=submit]:hover, input[type=submit]:active, input[type=submit].active, input[type=submit].selected, .button:hover, .button:active, .button.active, .button.selected {
background-color: #2076C6; background-color: #2076C6;
color: #FEFEFE; } color: #FEFEFE; }
button:hover, button.selected, button.active, input[type=submit]:hover, input[type=submit].selected, input[type=submit].active { button:hover, button.selected, button.active, input[type=submit]:hover, input[type=submit].selected, input[type=submit].active, .button:hover, .button.selected, .button.active {
box-shadow: 0 3px 0 #154c80; } box-shadow: 0 3px 0 #154c80; }
button:active, input[type=submit]:active { button:active, input[type=submit]:active, .button:active {
box-shadow: 0 1px 0 #154c80; } box-shadow: 0 1px 0 #154c80; }
input[type="number"], input[type="password"], input[type="text"], textarea, select { input[type="number"], input[type="password"], input[type="text"], textarea, select {
@ -491,6 +570,11 @@ input[type="number"], input[type="password"], input[type="text"], textarea, sele
input[type="number"]:focus, input[type="number"]:hover, input[type="password"]:focus, input[type="password"]:hover, input[type="text"]:focus, input[type="text"]:hover, textarea:focus, textarea:hover, select:focus, select:hover { input[type="number"]:focus, input[type="number"]:hover, input[type="password"]:focus, input[type="password"]:hover, input[type="text"]:focus, input[type="text"]:hover, textarea:focus, textarea:hover, select:focus, select:hover {
border-bottom-color: #2972ba; } border-bottom-color: #2972ba; }
#psk-modal form > *, #wificonfbox form > * {
margin-right: 0.38198rem; }
#psk-modal form > *:last-child, #wificonfbox form > *:last-child {
margin-right: 0; }
#ap-list { #ap-list {
column-count: 3; column-count: 3;
column-gap: 0; column-gap: 0;
@ -502,15 +586,25 @@ input[type="number"], input[type="password"], input[type="text"], textarea, sele
#ap-list { #ap-list {
column-count: 1; } } column-count: 1; } }
#ap-loader { #ap-loader, #ap-noscan {
background: rgba(255, 255, 255, 0.1); background: rgba(255, 255, 255, 0.1);
border-radius: 5px; border-radius: 5px;
padding: 0.38198rem; padding: 0.38198rem;
margin-bottom: 0.38198rem; } margin-bottom: 0.38198rem; }
#ap-noscan {
font-weight: bold; }
#ap-box { #ap-box {
padding-bottom: 0.38198rem; } padding-bottom: 0.38198rem; }
#psk-modal form {
display: flex;
align-items: center;
margin: 0.38198rem; }
#psk-modal form input[type=password] {
min-width: 5rem; }
.AP { .AP {
break-inside: avoid-column; break-inside: avoid-column;
max-width: 500px; max-width: 500px;
@ -569,7 +663,10 @@ input[type="number"], input[type="password"], input[type="text"], textarea, sele
white-space: pre; white-space: pre;
cursor: pointer; } cursor: pointer; }
.page-term #screen span:hover { .page-term #screen span:hover {
outline: 1px solid rgba(255, 255, 255, 0.5); } outline: 1px solid rgba(255, 255, 255, 0.4); }
@media screen and (max-width: 1000px) {
.page-term #screen span:hover {
outline: 0 none; } }
.page-term #buttons { .page-term #buttons {
margin-top: 10px; margin-top: 10px;
white-space: nowrap; } white-space: nowrap; }

@ -170,18 +170,35 @@
classarray = classes.split(/\s+/); classarray = classes.split(/\s+/);
nodeLoop(function (elm) { nodeLoop(function (elm) {
for (i = 0; i < classarray.length; i += 1) { for (i = 0; i < classarray.length; i += 1) {
search = new RegExp('\\b' + classarray[i] + '\\b', 'g'); var clz = classarray[i];
replace = new RegExp(' *' + classarray[i] + '\\b', 'g');
if (action === 'remove') { if (action === 'remove') {
elm.className = elm.className.replace(search, ''); elm.classList.remove(clz);
} else if (action === 'toggle') { }
elm.className = (elm.className.match(search)) ? elm.className.replace(replace, '') : elm.className + ' ' + classarray[i]; else if (action === 'add') {
} else if (action === 'has') { elm.classList.add(clz);
if (elm.className.match(search)) { }
else if (action === 'toggle') {
elm.classList.toggle(clz);
}
else if (action === 'has') {
if (elm.classList.contains(clz)) {
has = true; has = true;
break; break;
} }
} }
// search = new RegExp('\\b' + classarray[i] + '\\b', 'g');
// replace = new RegExp(' *' + classarray[i] + '\\b', 'g');
// if (action === 'remove') {
// elm.className = elm.className.replace(search, '');
// } else if (action === 'toggle') {
// elm.className = (elm.className.match(search)) ? elm.className.replace(replace, '') : elm.className + ' ' + classarray[i];
// } else if (action === 'has') {
// if (elm.className.match(search)) {
// has = true;
// break;
// }
// }
} }
}, nodes); }, nodes);
} }
@ -362,11 +379,12 @@
}; };
// Add class // Add class
cb.addClass = function (classes) { cb.addClass = function (classes) {
if (classes) { classHelper(classes, 'add', nodes);
nodeLoop(function (elm) { // if (classes) {
elm.className += ' ' + classes; // nodeLoop(function (elm) {
}, nodes); // elm.className += ' ' + classes;
} // }, nodes);
// }
return cb; return cb;
}; };
// Remove class // Remove class
@ -777,6 +795,47 @@ String.prototype.format = function () {
return out; return out;
}; };
/** Module for toggling a modal overlay */
(function () {
var modal = {};
modal.show = function (sel) {
var $m = $(sel);
$m.removeClass('hidden visible');
setTimeout(function () {
$m.addClass('visible');
}, 1);
};
modal.hide = function (sel) {
var $m = $(sel);
$m.removeClass('visible');
setTimeout(function () {
$m.addClass('hidden');
}, 500); // transition time
};
modal.init = function () {
// close modal by click outside the dialog
$('.Modal').on('click', function () {
if ($(this).hasClass('no-close')) return; // this is a no-close modal
modal.hide(this);
});
$('.Dialog').on('click', function (e) {
e.stopImmediatePropagation();
});
// Hide all modals on esc
$(window).on('keydown', function (e) {
if (e.which == 27) {
modal.hide('.Modal');
}
});
};
window.Modal = modal;
})();
/** Global generic init */ /** Global generic init */
$.ready(function () { $.ready(function () {
// loader dots... // loader dots...
@ -789,6 +848,7 @@ $.ready(function () {
}); });
}, 1000); }, 1000);
// flipping number boxes with the mouse wheel
$('input[type=number]').on('mousewheel', function(e) { $('input[type=number]').on('mousewheel', function(e) {
var val = +$(this).val(); var val = +$(this).val();
if (isNaN(val)) val = 1; if (isNaN(val)) val = 1;
@ -816,10 +876,11 @@ $.ready(function () {
e.preventDefault(); e.preventDefault();
}); });
Modal.init();
}); });
$._loader = function(vis) { $._loader = function(vis) {
console.log("loader fn", vis);
if(vis) if(vis)
$('#loader').addClass('show'); $('#loader').addClass('show');
else else
@ -1202,24 +1263,18 @@ $._loader = function(vis) {
$item.on('click', function () { $item.on('click', function () {
var $th = $(this); var $th = $(this);
var ssid = $th.data('ssid'); // populate the form
var pass = ''; $('#conn-essid').val($th.data('ssid'));
$('#conn-passwd').val(''); // clear
if ($th.data('pwd')) { if ($th.data('pwd')) {
// this AP needs a password // this AP needs a password
pass = prompt("Password for \""+ssid+"\":"); Modal.show('#psk-modal');
if (pass === null) { } else {
return; Modal.show('#reset-modal');
} $('#conn-form').submit();
}
$.post('http://'+_root+'/wifi/connect', null, {
data: {
essid: ssid,
passwd: pass
} }
}); });
});
item.appendChild(inner); item.appendChild(inner);
@ -1229,7 +1284,7 @@ $._loader = function(vis) {
/** Ask the CGI what APs are visible (async) */ /** Ask the CGI what APs are visible (async) */
function scanAPs() { function scanAPs() {
$.get('http://'+_root+'/wifi/scan', onScan); $.get('/wifi/scan', onScan);
} }
function rescan(time) { function rescan(time) {
@ -1248,8 +1303,85 @@ $._loader = function(vis) {
// } // }
//}; //};
curSSID = obj.curSSID; // Hide what should be hidden in this mode
$('.x-hide-'+obj.mode).addClass('hidden');
obj.mode = +obj.mode;
// Channel writable only in AP mode
if (obj.mode != 2) $('#channel').attr('readonly', 1);
curSSID = obj.staSSID;
// add SSID to the opmode field
if (curSSID) {
var box = $('#opmodebox');
box.html(box.html() + ' (' + curSSID + ')');
}
// hide IP if IP not received
if (!obj.staIP) $('.x-hide-noip').addClass('hidden');
// scan if not AP
if (obj.mode != 2) {
scanAPs(); scanAPs();
}
$('#modeswitch').html([
'<a class="button" href="/wifi/setmode?mode=3">Client+AP</a>&nbsp;<a class="button" href="/wifi/setmode?mode=2">AP only</a>',
'<a class="button" href="/wifi/setmode?mode=3">Client+AP</a>',
'<a class="button" href="/wifi/setmode?mode=1">Client only</a>&nbsp;<a class="button" href="/wifi/setmode?mode=2">AP only</a>'
][obj.mode-1]);
};
window.wifiConn = function () {
var xhr = new XMLHttpRequest();
var abortTmeo;
function getStatus() {
xhr.open("GET", "/wifi/connstatus");
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status >= 200 && xhr.status < 300) {
clearTimeout(abortTmeo);
var data = JSON.parse(xhr.responseText);
var done = false;
var msg = '...';
if (data.status == "idle") {
msg = "Preparing to connect";
}
else if (data.status == "success") {
msg = "Connected! Received IP " + data.ip + ".";
done = true;
}
else if (data.status == "working") {
msg = "Connecting to selected AP";
}
else if (data.status == "fail") {
msg = "Connection failed, check your password and try again.";
done = true;
}
$("#status").html(msg);
if (done) {
$('#backbtn').removeClass('hidden');
$('.anim-dots').addClass('hidden');
} else {
window.setTimeout(getStatus, 1000);
}
}
};
abortTmeo = setTimeout(function () {
xhr.abort();
$("#status").html("Telemetry lost, try reconnecting to the AP.");
$('#backbtn').removeClass('hidden');
$('.anim-dots').addClass('hidden');
}, 4000);
xhr.send();
}
getStatus();
}; };
})(); })();

@ -15,46 +15,69 @@
<h1 onclick="location.href='/'">WiFi settings</h1> <h1 onclick="location.href='/'">WiFi settings</h1>
<div class="Box"> <div class="Box" id="wificonfbox">
<table> <table>
<tr> <tr>
<th>WiFi mode:</th> <th>WiFi mode</th>
<td>%WiFiMode%</td> <td id="opmodebox">%WiFiMode%</td>
</tr> </tr>
<tr> <tr class="x-hide-noip x-hide-2">
<th></th> <th>IP</th>
<td>%WiFiapwarn%</td> <td>%StaIP%</td>
</tr> </tr>
<tr> <tr>
<th><label for="channel">AP channel:</label></th> <th>Switch to</th>
<td id="modeswitch"></td>
</tr>
<tr class="x-hide-1">
<th><label for="channel">AP channel</label></th>
<td> <td>
<form action="/wifi/setchannel" method="GET"> <form action="/wifi/setchannel" method="GET">
<input name="ch" id="channel" type="number" step=1 min=1 max=14 value="%WiFiChannel%">&nbsp; <input name="ch" id="channel" type="number" step=1 min=1 max=14 value="%WiFiChannel%"><!--
<input type="submit" value="Set" class="narrow btn-green"> --><input type="submit" value="Set" class="narrow btn-green x-hide-3">
</form> </form>
</td> </td>
</tr> </tr>
<tr> <tr class="x-hide-1">
<th><label for="channel">AP name:</label></th> <th><label for="channel">AP name</label></th>
<td> <td>
<form action="/wifi/setname" method="GET"> <form action="/wifi/setname" method="GET">
<input name="name" type="text" value="%APName%">&nbsp; <input name="name" type="text" value="%APName%"><!--
<input type="submit" value="Set" class="narrow btn-green"> --><input type="submit" value="Set" class="narrow btn-green">
</form> </form>
</td> </td>
</tr> </tr>
<tr><td colspan=2 style="white-space: normal;">
<p>Some changes require a reboot, dropping connection. It can take a while to re-connect.</p>
<p>
<b>If you lose access</b>, connect GPIO0 to GND for 5 seconds to enter Client+AP mode.
If that fails, try the UART factory reset command "<code>\e]FR\a</code>".
<p>
</td></tr>
</table> </table>
</div> </div>
<div class="Box" id="ap-box"> <div class="Box" id="ap-box">
<h2>Select AP to join</h2> <h2>Select AP to join</h2>
<div id="ap-loader">Scanning<span class="anim-dots">.</span></div> <div id="ap-loader" class="x-hide-2">Scanning<span class="anim-dots">.</span></div>
<div id="ap-noscan" class="x-hide-1 x-hide-3">Can't scan in AP-only mode.</div>
<div id="ap-list" style="display:none"></div> <div id="ap-list" style="display:none"></div>
</div> </div>
<div class="Modal hidden" id="psk-modal">
<div class="Dialog">
<form action="/wifi/connect" method="post" id="conn-form">
<input type="hidden" id="conn-essid" name="essid"><!--
--><label for="conn-passwd">Password:</label><!--
--><input type="password" id="conn-passwd" name="passwd"><!--
--><input type="submit" value="Connect!">
</form>
</div>
</div>
<script> <script>
_root = window.location.host; _root = window.location.host;
wifiInit({curSSID: '%currSsid%'}); wifiInit({staSSID: '%StaSSID%', staIP: '%StaIP%', mode: '%WiFiModeNum%'});
</script> </script>
</body> </body>
</html> </html>

@ -0,0 +1,26 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,shrink-to-fit=no,user-scalable=no,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0">
<title>Connecting…</title>
<link rel="stylesheet" href="css/app.css">
<script src="js/app.js"></script>
</head>
<body>
<h1>Connecting to network</h1>
<div class="Box">
<p><b>Status:</b><br><span id="status"></span><span class="anim-dots">.</span></p>
<a href="/wifi" id="backbtn" class="hidden button">Back to WiFi config</a>
</div>
<script>
_root = window.location.host;
wifiConn();
</script>
</body>
</html>

@ -319,6 +319,78 @@ html {
[onclick] { [onclick] {
cursor: pointer; } cursor: pointer; }
.Modal {
position: fixed;
width: 100%;
height: 100%;
left: 0;
top: 0;
right: 0;
bottom: 0;
display: flex;
justify-content: center;
align-items: center;
transition: opacity .5s;
background: rgba(0, 0, 0, 0.65);
opacity: 0; }
.Modal.visible {
opacity: 1; }
.Modal.hidden {
display: none; }
.Dialog {
margin: 0.61805rem;
padding: 1rem;
overflow: hidden;
max-width: 100%;
max-height: 100%;
flex: 0 1 30rem;
background: #1c1c1e;
border-left: 6px solid #2972ba;
border-right: 6px solid #2972ba;
box-shadow: 0 0 2px 0 #434349, 0 0 6px 0 black;
border-radius: 6px; }
.Dialog h1, .Dialog h2 {
margin-top: 0; }
.Dialog p:last-child {
margin-bottom: 0; }
/*
// "toast"
.NotifyMsg {
position: fixed;
bottom: dist(2);
padding: dist(-1) dist(0);
// center horizontally
left: 50%;
@include translate(-50%,0);
// hack to remove blur in chrome
-webkit-font-smoothing: subpixel-antialiased;
-webkit-transform: translateZ(0) scale(1.0, 1.0);
background: #37a349;
&.error {
background: #d03e42;
}
color: white;
text-shadow: 0 0 2px black;
box-shadow: 0 0 6px 0 rgba(black, .6);
border-radius: 5px;
max-width: 80%;
@include media($phone) {
width: calc(100% - 1rem);
}
transition: opacity .5s;
opacity: 0;
&.visible { opacity: 1 }
&.hidden { display: none }
}
*/
html { html {
font-family: Arial, sans-serif; font-family: Arial, sans-serif;
color: #D0D0D0; color: #D0D0D0;
@ -353,6 +425,8 @@ a:hover {
.Box { .Box {
margin-top: 0.61805rem; margin-top: 0.61805rem;
padding: 0.23608rem 0.38198rem; } } padding: 0.23608rem 0.38198rem; } }
.Box p:first-child {
margin-top: 0; }
body { body {
position: relative; position: relative;
@ -376,6 +450,11 @@ body {
@media screen and (min-width: 545px) and (max-width: 1000px) { @media screen and (min-width: 545px) and (max-width: 1000px) {
body h1 { body h1 {
font-size: 1.80203em; } } font-size: 1.80203em; } }
body h2 {
font-size: 1.26563em;
margin-bottom: 0.61805rem; }
body h2:first-child {
margin-top: 0; }
body td, body th { body td, body th {
padding: 0.38198rem; padding: 0.38198rem;
white-space: nowrap; } white-space: nowrap; }
@ -408,7 +487,7 @@ body {
#loader.show { #loader.show {
opacity: 1; } opacity: 1; }
button, input[type=submit] { button, input[type=submit], .button {
text-align: center; text-align: center;
cursor: pointer; cursor: pointer;
display: inline-block; display: inline-block;
@ -428,22 +507,22 @@ button, input[type=submit] {
background-color: #3983cd; background-color: #3983cd;
box-shadow: 0 3px 0 #265f98; box-shadow: 0 3px 0 #265f98;
text-decoration: none !important; } text-decoration: none !important; }
button:active, input[type=submit]:active { button:active, input[type=submit]:active, .button:active {
position: relative; position: relative;
top: 2px; } top: 2px; }
button.narrow, input[type=submit].narrow { button.narrow, input[type=submit].narrow, .button.narrow {
min-width: initial; } min-width: initial; }
button, button:link, button:visited, input[type=submit], input[type=submit]:link, input[type=submit]:visited { button, button:link, button:visited, input[type=submit], input[type=submit]:link, input[type=submit]:visited, .button, .button:link, .button:visited {
color: #FEFEFE; } color: #FEFEFE; }
button:hover, button:active, button.active, button.selected, input[type=submit]:hover, input[type=submit]:active, input[type=submit].active, input[type=submit].selected { button:hover, button:active, button.active, button.selected, input[type=submit]:hover, input[type=submit]:active, input[type=submit].active, input[type=submit].selected, .button:hover, .button:active, .button.active, .button.selected {
background-color: #2076C6; background-color: #2076C6;
color: #FEFEFE; } color: #FEFEFE; }
button:hover, button.selected, button.active, input[type=submit]:hover, input[type=submit].selected, input[type=submit].active { button:hover, button.selected, button.active, input[type=submit]:hover, input[type=submit].selected, input[type=submit].active, .button:hover, .button.selected, .button.active {
box-shadow: 0 3px 0 #154c80; } box-shadow: 0 3px 0 #154c80; }
button:active, input[type=submit]:active { button:active, input[type=submit]:active, .button:active {
box-shadow: 0 1px 0 #154c80; } box-shadow: 0 1px 0 #154c80; }
button, input[type=submit] { button, input[type=submit], .button {
text-align: center; text-align: center;
cursor: pointer; cursor: pointer;
display: inline-block; display: inline-block;
@ -463,19 +542,19 @@ button, input[type=submit] {
background-color: #3983cd; background-color: #3983cd;
box-shadow: 0 3px 0 #265f98; box-shadow: 0 3px 0 #265f98;
text-decoration: none !important; } text-decoration: none !important; }
button:active, input[type=submit]:active { button:active, input[type=submit]:active, .button:active {
position: relative; position: relative;
top: 2px; } top: 2px; }
button.narrow, input[type=submit].narrow { button.narrow, input[type=submit].narrow, .button.narrow {
min-width: initial; } min-width: initial; }
button, button:link, button:visited, input[type=submit], input[type=submit]:link, input[type=submit]:visited { button, button:link, button:visited, input[type=submit], input[type=submit]:link, input[type=submit]:visited, .button, .button:link, .button:visited {
color: #FEFEFE; } color: #FEFEFE; }
button:hover, button:active, button.active, button.selected, input[type=submit]:hover, input[type=submit]:active, input[type=submit].active, input[type=submit].selected { button:hover, button:active, button.active, button.selected, input[type=submit]:hover, input[type=submit]:active, input[type=submit].active, input[type=submit].selected, .button:hover, .button:active, .button.active, .button.selected {
background-color: #2076C6; background-color: #2076C6;
color: #FEFEFE; } color: #FEFEFE; }
button:hover, button.selected, button.active, input[type=submit]:hover, input[type=submit].selected, input[type=submit].active { button:hover, button.selected, button.active, input[type=submit]:hover, input[type=submit].selected, input[type=submit].active, .button:hover, .button.selected, .button.active {
box-shadow: 0 3px 0 #154c80; } box-shadow: 0 3px 0 #154c80; }
button:active, input[type=submit]:active { button:active, input[type=submit]:active, .button:active {
box-shadow: 0 1px 0 #154c80; } box-shadow: 0 1px 0 #154c80; }
input[type="number"], input[type="password"], input[type="text"], textarea, select { input[type="number"], input[type="password"], input[type="text"], textarea, select {
@ -491,6 +570,11 @@ input[type="number"], input[type="password"], input[type="text"], textarea, sele
input[type="number"]:focus, input[type="number"]:hover, input[type="password"]:focus, input[type="password"]:hover, input[type="text"]:focus, input[type="text"]:hover, textarea:focus, textarea:hover, select:focus, select:hover { input[type="number"]:focus, input[type="number"]:hover, input[type="password"]:focus, input[type="password"]:hover, input[type="text"]:focus, input[type="text"]:hover, textarea:focus, textarea:hover, select:focus, select:hover {
border-bottom-color: #2972ba; } border-bottom-color: #2972ba; }
#psk-modal form > *, #wificonfbox form > * {
margin-right: 0.38198rem; }
#psk-modal form > *:last-child, #wificonfbox form > *:last-child {
margin-right: 0; }
#ap-list { #ap-list {
column-count: 3; column-count: 3;
column-gap: 0; column-gap: 0;
@ -502,15 +586,25 @@ input[type="number"], input[type="password"], input[type="text"], textarea, sele
#ap-list { #ap-list {
column-count: 1; } } column-count: 1; } }
#ap-loader { #ap-loader, #ap-noscan {
background: rgba(255, 255, 255, 0.1); background: rgba(255, 255, 255, 0.1);
border-radius: 5px; border-radius: 5px;
padding: 0.38198rem; padding: 0.38198rem;
margin-bottom: 0.38198rem; } margin-bottom: 0.38198rem; }
#ap-noscan {
font-weight: bold; }
#ap-box { #ap-box {
padding-bottom: 0.38198rem; } padding-bottom: 0.38198rem; }
#psk-modal form {
display: flex;
align-items: center;
margin: 0.38198rem; }
#psk-modal form input[type=password] {
min-width: 5rem; }
.AP { .AP {
break-inside: avoid-column; break-inside: avoid-column;
max-width: 500px; max-width: 500px;
@ -569,7 +663,10 @@ input[type="number"], input[type="password"], input[type="text"], textarea, sele
white-space: pre; white-space: pre;
cursor: pointer; } cursor: pointer; }
.page-term #screen span:hover { .page-term #screen span:hover {
outline: 1px solid rgba(255, 255, 255, 0.5); } outline: 1px solid rgba(255, 255, 255, 0.4); }
@media screen and (max-width: 1000px) {
.page-term #screen span:hover {
outline: 0 none; } }
.page-term #buttons { .page-term #buttons {
margin-top: 10px; margin-top: 10px;
white-space: nowrap; } white-space: nowrap; }

@ -170,18 +170,35 @@
classarray = classes.split(/\s+/); classarray = classes.split(/\s+/);
nodeLoop(function (elm) { nodeLoop(function (elm) {
for (i = 0; i < classarray.length; i += 1) { for (i = 0; i < classarray.length; i += 1) {
search = new RegExp('\\b' + classarray[i] + '\\b', 'g'); var clz = classarray[i];
replace = new RegExp(' *' + classarray[i] + '\\b', 'g');
if (action === 'remove') { if (action === 'remove') {
elm.className = elm.className.replace(search, ''); elm.classList.remove(clz);
} else if (action === 'toggle') { }
elm.className = (elm.className.match(search)) ? elm.className.replace(replace, '') : elm.className + ' ' + classarray[i]; else if (action === 'add') {
} else if (action === 'has') { elm.classList.add(clz);
if (elm.className.match(search)) { }
else if (action === 'toggle') {
elm.classList.toggle(clz);
}
else if (action === 'has') {
if (elm.classList.contains(clz)) {
has = true; has = true;
break; break;
} }
} }
// search = new RegExp('\\b' + classarray[i] + '\\b', 'g');
// replace = new RegExp(' *' + classarray[i] + '\\b', 'g');
// if (action === 'remove') {
// elm.className = elm.className.replace(search, '');
// } else if (action === 'toggle') {
// elm.className = (elm.className.match(search)) ? elm.className.replace(replace, '') : elm.className + ' ' + classarray[i];
// } else if (action === 'has') {
// if (elm.className.match(search)) {
// has = true;
// break;
// }
// }
} }
}, nodes); }, nodes);
} }
@ -362,11 +379,12 @@
}; };
// Add class // Add class
cb.addClass = function (classes) { cb.addClass = function (classes) {
if (classes) { classHelper(classes, 'add', nodes);
nodeLoop(function (elm) { // if (classes) {
elm.className += ' ' + classes; // nodeLoop(function (elm) {
}, nodes); // elm.className += ' ' + classes;
} // }, nodes);
// }
return cb; return cb;
}; };
// Remove class // Remove class
@ -574,9 +592,6 @@
query = serializeData(opts.data); query = serializeData(opts.data);
} }
console.log(opts);
console.log(query);
if (query && (method === 'GET')) { if (query && (method === 'GET')) {
url += (url.indexOf('?') === -1) ? '?' + query : '&' + query; url += (url.indexOf('?') === -1) ? '?' + query : '&' + query;
query = null; query = null;
@ -780,6 +795,47 @@ String.prototype.format = function () {
return out; return out;
}; };
/** Module for toggling a modal overlay */
(function () {
var modal = {};
modal.show = function (sel) {
var $m = $(sel);
$m.removeClass('hidden visible');
setTimeout(function () {
$m.addClass('visible');
}, 1);
};
modal.hide = function (sel) {
var $m = $(sel);
$m.removeClass('visible');
setTimeout(function () {
$m.addClass('hidden');
}, 500); // transition time
};
modal.init = function () {
// close modal by click outside the dialog
$('.Modal').on('click', function () {
if ($(this).hasClass('no-close')) return; // this is a no-close modal
modal.hide(this);
});
$('.Dialog').on('click', function (e) {
e.stopImmediatePropagation();
});
// Hide all modals on esc
$(window).on('keydown', function (e) {
if (e.which == 27) {
modal.hide('.Modal');
}
});
};
window.Modal = modal;
})();
/** Global generic init */ /** Global generic init */
$.ready(function () { $.ready(function () {
// loader dots... // loader dots...
@ -792,6 +848,7 @@ $.ready(function () {
}); });
}, 1000); }, 1000);
// flipping number boxes with the mouse wheel
$('input[type=number]').on('mousewheel', function(e) { $('input[type=number]').on('mousewheel', function(e) {
var val = +$(this).val(); var val = +$(this).val();
if (isNaN(val)) val = 1; if (isNaN(val)) val = 1;
@ -819,10 +876,11 @@ $.ready(function () {
e.preventDefault(); e.preventDefault();
}); });
Modal.init();
}); });
$._loader = function(vis) { $._loader = function(vis) {
console.log("loader fn", vis);
if(vis) if(vis)
$('#loader').addClass('show'); $('#loader').addClass('show');
else else
@ -1205,21 +1263,17 @@ $._loader = function(vis) {
$item.on('click', function () { $item.on('click', function () {
var $th = $(this); var $th = $(this);
var ssid = $th.data('ssid'); // populate the form
var pass = ''; $('#conn-essid').val($th.data('ssid'));
$('#conn-passwd').val(''); // clear
if ($th.data('pwd')) { if ($th.data('pwd')) {
// this AP needs a password // this AP needs a password
var pass = prompt("Password for \""+ssid+"\":"); Modal.show('#psk-modal');
if (pass === null) { } else {
return; Modal.show('#reset-modal');
} $('#conn-form').submit();
} }
$.post('http://'+_root+'/wifi/connect', null, {
essid: ssid,
passwd: pass
});
}); });
@ -1230,7 +1284,7 @@ $._loader = function(vis) {
/** Ask the CGI what APs are visible (async) */ /** Ask the CGI what APs are visible (async) */
function scanAPs() { function scanAPs() {
$.get('http://'+_root+'/wifi/scan', onScan); $.get('/wifi/scan', onScan);
} }
function rescan(time) { function rescan(time) {
@ -1249,8 +1303,85 @@ $._loader = function(vis) {
// } // }
//}; //};
curSSID = obj.curSSID; // Hide what should be hidden in this mode
$('.x-hide-'+obj.mode).addClass('hidden');
obj.mode = +obj.mode;
// Channel writable only in AP mode
if (obj.mode != 2) $('#channel').attr('readonly', 1);
curSSID = obj.staSSID;
// add SSID to the opmode field
if (curSSID) {
var box = $('#opmodebox');
box.html(box.html() + ' (' + curSSID + ')');
}
// hide IP if IP not received
if (!obj.staIP) $('.x-hide-noip').addClass('hidden');
// scan if not AP
if (obj.mode != 2) {
scanAPs(); scanAPs();
}
$('#modeswitch').html([
'<a class="button" href="/wifi/setmode?mode=3">Client+AP</a>&nbsp;<a class="button" href="/wifi/setmode?mode=2">AP only</a>',
'<a class="button" href="/wifi/setmode?mode=3">Client+AP</a>',
'<a class="button" href="/wifi/setmode?mode=1">Client only</a>&nbsp;<a class="button" href="/wifi/setmode?mode=2">AP only</a>'
][obj.mode-1]);
};
window.wifiConn = function () {
var xhr = new XMLHttpRequest();
var abortTmeo;
function getStatus() {
xhr.open("GET", "/wifi/connstatus");
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status >= 200 && xhr.status < 300) {
clearTimeout(abortTmeo);
var data = JSON.parse(xhr.responseText);
var done = false;
var msg = '...';
if (data.status == "idle") {
msg = "Preparing to connect";
}
else if (data.status == "success") {
msg = "Connected! Received IP " + data.ip + ".";
done = true;
}
else if (data.status == "working") {
msg = "Connecting to selected AP";
}
else if (data.status == "fail") {
msg = "Connection failed, check your password and try again.";
done = true;
}
$("#status").html(msg);
if (done) {
$('#backbtn').removeClass('hidden');
$('.anim-dots').addClass('hidden');
} else {
window.setTimeout(getStatus, 1000);
}
}
};
abortTmeo = setTimeout(function () {
xhr.abort();
$("#status").html("Telemetry lost, try reconnecting to the AP.");
$('#backbtn').removeClass('hidden');
$('.anim-dots').addClass('hidden');
}, 4000);
xhr.send();
}
getStatus();
}; };
})(); })();

@ -10,6 +10,7 @@ $.ready(function () {
}); });
}, 1000); }, 1000);
// flipping number boxes with the mouse wheel
$('input[type=number]').on('mousewheel', function(e) { $('input[type=number]').on('mousewheel', function(e) {
var val = +$(this).val(); var val = +$(this).val();
if (isNaN(val)) val = 1; if (isNaN(val)) val = 1;
@ -37,10 +38,11 @@ $.ready(function () {
e.preventDefault(); e.preventDefault();
}); });
Modal.init();
}); });
$._loader = function(vis) { $._loader = function(vis) {
console.log("loader fn", vis);
if(vis) if(vis)
$('#loader').addClass('show'); $('#loader').addClass('show');
else else

@ -170,18 +170,35 @@
classarray = classes.split(/\s+/); classarray = classes.split(/\s+/);
nodeLoop(function (elm) { nodeLoop(function (elm) {
for (i = 0; i < classarray.length; i += 1) { for (i = 0; i < classarray.length; i += 1) {
search = new RegExp('\\b' + classarray[i] + '\\b', 'g'); var clz = classarray[i];
replace = new RegExp(' *' + classarray[i] + '\\b', 'g');
if (action === 'remove') { if (action === 'remove') {
elm.className = elm.className.replace(search, ''); elm.classList.remove(clz);
} else if (action === 'toggle') { }
elm.className = (elm.className.match(search)) ? elm.className.replace(replace, '') : elm.className + ' ' + classarray[i]; else if (action === 'add') {
} else if (action === 'has') { elm.classList.add(clz);
if (elm.className.match(search)) { }
else if (action === 'toggle') {
elm.classList.toggle(clz);
}
else if (action === 'has') {
if (elm.classList.contains(clz)) {
has = true; has = true;
break; break;
} }
} }
// search = new RegExp('\\b' + classarray[i] + '\\b', 'g');
// replace = new RegExp(' *' + classarray[i] + '\\b', 'g');
// if (action === 'remove') {
// elm.className = elm.className.replace(search, '');
// } else if (action === 'toggle') {
// elm.className = (elm.className.match(search)) ? elm.className.replace(replace, '') : elm.className + ' ' + classarray[i];
// } else if (action === 'has') {
// if (elm.className.match(search)) {
// has = true;
// break;
// }
// }
} }
}, nodes); }, nodes);
} }
@ -362,11 +379,12 @@
}; };
// Add class // Add class
cb.addClass = function (classes) { cb.addClass = function (classes) {
if (classes) { classHelper(classes, 'add', nodes);
nodeLoop(function (elm) { // if (classes) {
elm.className += ' ' + classes; // nodeLoop(function (elm) {
}, nodes); // elm.className += ' ' + classes;
} // }, nodes);
// }
return cb; return cb;
}; };
// Remove class // Remove class

@ -0,0 +1,41 @@
/** Module for toggling a modal overlay */
(function () {
var modal = {};
modal.show = function (sel) {
var $m = $(sel);
$m.removeClass('hidden visible');
setTimeout(function () {
$m.addClass('visible');
}, 1);
};
modal.hide = function (sel) {
var $m = $(sel);
$m.removeClass('visible');
setTimeout(function () {
$m.addClass('hidden');
}, 500); // transition time
};
modal.init = function () {
// close modal by click outside the dialog
$('.Modal').on('click', function () {
if ($(this).hasClass('no-close')) return; // this is a no-close modal
modal.hide(this);
});
$('.Dialog').on('click', function (e) {
e.stopImmediatePropagation();
});
// Hide all modals on esc
$(window).on('keydown', function (e) {
if (e.which == 27) {
modal.hide('.Modal');
}
});
};
window.Modal = modal;
})();

@ -54,24 +54,18 @@
$item.on('click', function () { $item.on('click', function () {
var $th = $(this); var $th = $(this);
var ssid = $th.data('ssid'); // populate the form
var pass = ''; $('#conn-essid').val($th.data('ssid'));
$('#conn-passwd').val(''); // clear
if ($th.data('pwd')) { if ($th.data('pwd')) {
// this AP needs a password // this AP needs a password
pass = prompt("Password for \""+ssid+"\":"); Modal.show('#psk-modal');
if (pass === null) { } else {
return; Modal.show('#reset-modal');
} $('#conn-form').submit();
}
$.post('http://'+_root+'/wifi/connect', null, {
data: {
essid: ssid,
passwd: pass
} }
}); });
});
item.appendChild(inner); item.appendChild(inner);
@ -81,7 +75,7 @@
/** Ask the CGI what APs are visible (async) */ /** Ask the CGI what APs are visible (async) */
function scanAPs() { function scanAPs() {
$.get('http://'+_root+'/wifi/scan', onScan); $.get('/wifi/scan', onScan);
} }
function rescan(time) { function rescan(time) {
@ -100,8 +94,85 @@
// } // }
//}; //};
curSSID = obj.curSSID; // Hide what should be hidden in this mode
$('.x-hide-'+obj.mode).addClass('hidden');
obj.mode = +obj.mode;
// Channel writable only in AP mode
if (obj.mode != 2) $('#channel').attr('readonly', 1);
curSSID = obj.staSSID;
// add SSID to the opmode field
if (curSSID) {
var box = $('#opmodebox');
box.html(box.html() + ' (' + curSSID + ')');
}
// hide IP if IP not received
if (!obj.staIP) $('.x-hide-noip').addClass('hidden');
// scan if not AP
if (obj.mode != 2) {
scanAPs(); scanAPs();
}
$('#modeswitch').html([
'<a class="button" href="/wifi/setmode?mode=3">Client+AP</a>&nbsp;<a class="button" href="/wifi/setmode?mode=2">AP only</a>',
'<a class="button" href="/wifi/setmode?mode=3">Client+AP</a>',
'<a class="button" href="/wifi/setmode?mode=1">Client only</a>&nbsp;<a class="button" href="/wifi/setmode?mode=2">AP only</a>'
][obj.mode-1]);
};
window.wifiConn = function () {
var xhr = new XMLHttpRequest();
var abortTmeo;
function getStatus() {
xhr.open("GET", "/wifi/connstatus");
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status >= 200 && xhr.status < 300) {
clearTimeout(abortTmeo);
var data = JSON.parse(xhr.responseText);
var done = false;
var msg = '...';
if (data.status == "idle") {
msg = "Preparing to connect";
}
else if (data.status == "success") {
msg = "Connected! Received IP " + data.ip + ".";
done = true;
}
else if (data.status == "working") {
msg = "Connecting to selected AP";
}
else if (data.status == "fail") {
msg = "Connection failed, check your password and try again.";
done = true;
}
$("#status").html(msg);
if (done) {
$('#backbtn').removeClass('hidden');
$('.anim-dots').addClass('hidden');
} else {
window.setTimeout(getStatus, 1000);
}
}
};
abortTmeo = setTimeout(function () {
xhr.abort();
$("#status").html("Telemetry lost, try reconnecting to the AP.");
$('#backbtn').removeClass('hidden');
$('.anim-dots').addClass('hidden');
}, 4000);
xhr.send();
}
getStatus();
}; };
})(); })();

@ -2,6 +2,7 @@
cat jssrc/chibi.js \ cat jssrc/chibi.js \
jssrc/utils.js \ jssrc/utils.js \
jssrc/modal.js \
jssrc/appcommon.js \ jssrc/appcommon.js \
jssrc/term.js \ jssrc/term.js \
jssrc/wifi.js > js/app.js jssrc/wifi.js > js/app.js

@ -42,6 +42,10 @@ a:hover {
// margin-top: 0; // margin-top: 0;
//} //}
p:first-child {
margin-top:0;
}
border-radius: 3px; border-radius: 3px;
background-color: rgba(white, .07); background-color: rgba(white, .07);
@ -91,10 +95,11 @@ body {
} }
} }
//h2 { h2 {
// font-size: fsize(3); font-size: fsize(2);
// margin-bottom: dist(-1); margin-bottom: dist(-1);
//} &:first-child{margin-top:0}
}
td, th { td, th {
padding: dist(-2); padding: dist(-2);

@ -0,0 +1,78 @@
.Modal {
position: fixed;
width: 100%; height: 100%;
left: 0; top: 0; right: 0; bottom: 0;
display: flex;
justify-content: center;
align-items: center;
transition: opacity .5s;
background: rgba(black, .65);
opacity: 0;
&.visible { opacity: 1 }
&.hidden { display: none }
}
.Dialog {
margin: dist(-1);
padding: dist(0);
overflow: hidden;
max-width: 100%;
max-height: 100%;
flex: 0 1 30rem;
//min-height: 15rem;
background: #1c1c1e;
border-left: 6px solid $c-form-highlight-a;
border-right: 6px solid $c-form-highlight-a;
box-shadow: 0 0 2px 0 #434349, 0 0 6px 0 black;
border-radius: 6px;
h1,h2 {
margin-top:0;
}
p:last-child {
margin-bottom: 0;
}
}
/*
// "toast"
.NotifyMsg {
position: fixed;
bottom: dist(2);
padding: dist(-1) dist(0);
// center horizontally
left: 50%;
@include translate(-50%,0);
// hack to remove blur in chrome
-webkit-font-smoothing: subpixel-antialiased;
-webkit-transform: translateZ(0) scale(1.0, 1.0);
background: #37a349;
&.error {
background: #d03e42;
}
color: white;
text-shadow: 0 0 2px black;
box-shadow: 0 0 6px 0 rgba(black, .6);
border-radius: 5px;
max-width: 80%;
@include media($phone) {
width: calc(100% - #{dist(0)});
}
transition: opacity .5s;
opacity: 0;
&.visible { opacity: 1 }
&.hidden { display: none }
}
*/

@ -32,6 +32,7 @@ $c-form-highlight-a: #2972ba;
cursor: pointer; cursor: pointer;
} }
@import "modal";
@import "layout"; @import "layout";
@import "form/index"; @import "form/index";

@ -24,7 +24,7 @@ $btn-orange-b: #dd8751;
$btn-orange-fa: #FEFEFE; $btn-orange-fa: #FEFEFE;
$btn-orange-ba: #C6733F; $btn-orange-ba: #C6733F;
button, input[type=submit] { button, input[type=submit], .button {
@include fancy-btn-base(); @include fancy-btn-base();
&.narrow { &.narrow {

@ -1,5 +1,13 @@
@import 'fancy_button_mixins'; @import 'fancy_button_mixins';
@import 'buttons'; @import 'buttons';
@import 'form_elements'; @import 'form_elements';
%form-row-spacing {
& > * {
margin-right: dist(-2);
&:last-child { margin-right: 0 }
}
}
//@import 'form_layout'; //@import 'form_layout';
//@import 'select'; //@import 'select';

@ -13,7 +13,10 @@
white-space: pre; white-space: pre;
cursor: pointer; cursor: pointer;
&:hover { &:hover {
outline: 1px solid rgba(#ffffff,0.5); outline: 1px solid rgba(#ffffff,0.4);
@include media($tablet-max) {
outline: 0 none;
}
} }
} }
} }

@ -13,17 +13,36 @@
margin: 0 (- dist(-3)); margin: 0 (- dist(-3));
} }
#ap-loader { #ap-loader, #ap-noscan {
background: rgba(white, .1); background: rgba(white, .1);
border-radius: 5px; border-radius: 5px;
padding: dist(-2); padding: dist(-2);
margin-bottom: dist(-2); margin-bottom: dist(-2);
} }
#ap-noscan {
font-weight: bold;
}
#ap-box { #ap-box {
padding-bottom: dist(-2); padding-bottom: dist(-2);
} }
#psk-modal form {
@extend %form-row-spacing;
display: flex;
align-items: center;
margin: dist(-2);
input[type=password] {
min-width: 5rem;
}
}
#wificonfbox form {
@extend %form-row-spacing;
}
.AP { .AP {
// can't use margins inside a column // can't use margins inside a column

@ -15,46 +15,69 @@
<h1 onclick="location.href='/'">WiFi settings</h1> <h1 onclick="location.href='/'">WiFi settings</h1>
<div class="Box"> <div class="Box" id="wificonfbox">
<table> <table>
<tr> <tr>
<th>WiFi mode:</th> <th>WiFi mode</th>
<td>%WiFiMode%</td> <td id="opmodebox">%WiFiMode%</td>
</tr> </tr>
<tr> <tr class="x-hide-noip x-hide-2">
<th></th> <th>IP</th>
<td>%WiFiapwarn%</td> <td>%StaIP%</td>
</tr> </tr>
<tr> <tr>
<th><label for="channel">AP channel:</label></th> <th>Switch to</th>
<td id="modeswitch"></td>
</tr>
<tr class="x-hide-1">
<th><label for="channel">AP channel</label></th>
<td> <td>
<form action="/wifi/setchannel" method="GET"> <form action="/wifi/setchannel" method="GET">
<input name="ch" id="channel" type="number" step=1 min=1 max=14 value="%WiFiChannel%">&nbsp; <input name="ch" id="channel" type="number" step=1 min=1 max=14 value="%WiFiChannel%"><!--
<input type="submit" value="Set" class="narrow btn-green"> --><input type="submit" value="Set" class="narrow btn-green x-hide-3">
</form> </form>
</td> </td>
</tr> </tr>
<tr> <tr class="x-hide-1">
<th><label for="channel">AP name:</label></th> <th><label for="channel">AP name</label></th>
<td> <td>
<form action="/wifi/setname" method="GET"> <form action="/wifi/setname" method="GET">
<input name="name" type="text" value="%APName%">&nbsp; <input name="name" type="text" value="%APName%"><!--
<input type="submit" value="Set" class="narrow btn-green"> --><input type="submit" value="Set" class="narrow btn-green">
</form> </form>
</td> </td>
</tr> </tr>
<tr><td colspan=2 style="white-space: normal;">
<p>Some changes require a reboot, dropping connection. It can take a while to re-connect.</p>
<p>
<b>If you lose access</b>, connect GPIO0 to GND for 5 seconds to enter Client+AP mode.
If that fails, try the UART factory reset command "<code>\e]FR\a</code>".
<p>
</td></tr>
</table> </table>
</div> </div>
<div class="Box" id="ap-box"> <div class="Box" id="ap-box">
<h2>Select AP to join</h2> <h2>Select AP to join</h2>
<div id="ap-loader">Scanning<span class="anim-dots">.</span></div> <div id="ap-loader" class="x-hide-2">Scanning<span class="anim-dots">.</span></div>
<div id="ap-noscan" class="x-hide-1 x-hide-3">Can't scan in AP-only mode.</div>
<div id="ap-list" style="display:none"></div> <div id="ap-list" style="display:none"></div>
</div> </div>
<div class="Modal hidden" id="psk-modal">
<div class="Dialog">
<form action="/wifi/connect" method="post" id="conn-form">
<input type="hidden" id="conn-essid" name="essid"><!--
--><label for="conn-passwd">Password:</label><!--
--><input type="password" id="conn-passwd" name="passwd"><!--
--><input type="submit" value="Connect!">
</form>
</div>
</div>
<script> <script>
_root = window.location.host; _root = window.location.host;
wifiInit({curSSID: '%currSsid%'}); wifiInit({staSSID: '%StaSSID%', staIP: '%StaIP%', mode: '%WiFiModeNum%'});
</script> </script>
</body> </body>
</html> </html>

@ -1,60 +0,0 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,shrink-to-fit=no,user-scalable=no,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0">
<title>WiFi Settings - ESP8266 Remote Terminal</title>
<link rel="stylesheet" href="css/app.css">
<script src="js/app.js"></script>
</head>
<body class="page-wifi">
<img src="img/loader.gif" alt="Loading…" id="loader">
<h1 onclick="location.href='/'">WiFi settings</h1>
<div class="Box">
<table>
<tr>
<th>WiFi mode:</th>
<td>%WiFiMode%</td>
</tr>
<tr>
<th></th>
<td>%WiFiapwarn%</td>
</tr>
<tr>
<th><label for="channel">AP channel:</label></th>
<td>
<form action="/wifi/setchannel" method="GET">
<input name="ch" id="channel" type="number" step=1 min=1 max=14 value="%WiFiChannel%">&nbsp;
<input type="submit" value="Set" class="narrow btn-green">
</form>
</td>
</tr>
<tr>
<th><label for="channel">AP name:</label></th>
<td>
<form action="/wifi/setname" method="GET" style="display:inline-block;">
<input name="name" type="text" value="%APName%">&nbsp;
<input type="submit" value="Set" class="narrow btn-green">
</form>
</td>
</tr>
</table>
</div>
<div class="Box" id="ap-box">
<h2>Select AP to join</h2>
<div id="ap-loader">Scanning<span class="anim-dots">.</span></div>
<div id="ap-list" style="display:none"></div>
</div>
<script>
_root = window.location.host;
wifiInit({curSSID: '%currSsid%'});
</script>
</body>
</html>

@ -0,0 +1,26 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,shrink-to-fit=no,user-scalable=no,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0">
<title>Connecting…</title>
<link rel="stylesheet" href="css/app.css">
<script src="js/app.js"></script>
</head>
<body>
<h1>Connecting to network</h1>
<div class="Box">
<p><b>Status:</b><br><span id="status"></span><span class="anim-dots">.</span></p>
<a href="/wifi" id="backbtn" class="hidden button">Back to WiFi config</a>
</div>
<script>
_root = window.location.host;
wifiConn();
</script>
</body>
</html>

@ -1 +1 @@
Subproject commit 9ff92faacfd857ee6d1d9c1069dc4752e6b56589 Subproject commit 439df03f4b8e4c1ec5d7dc14695c80a4e35eb7ce

@ -23,7 +23,7 @@ static int wifiPassFn(HttpdConnData *connData, int no, char *user, int userLen,
*/ */
HttpdBuiltInUrl routes[] = { HttpdBuiltInUrl routes[] = {
// redirect func for the captive portal // redirect func for the captive portal
ROUTE_CGI_ARG("*", cgiRedirectApClientToHostname, "esp-remote-term.ap"), ROUTE_CGI_ARG("*", cgiRedirectApClientToHostname, "esp-terminal.ap"),
// --- Web pages --- // --- Web pages ---
ROUTE_TPL_FILE("/", tplScreen, "/term.tpl"), ROUTE_TPL_FILE("/", tplScreen, "/term.tpl"),
@ -45,6 +45,7 @@ HttpdBuiltInUrl routes[] = {
ROUTE_CGI("/wifi/scan", cgiWiFiScan), ROUTE_CGI("/wifi/scan", cgiWiFiScan),
ROUTE_CGI("/wifi/connect", cgiWiFiConnect), ROUTE_CGI("/wifi/connect", cgiWiFiConnect),
ROUTE_CGI("/wifi/connstatus", cgiWiFiConnStatus), ROUTE_CGI("/wifi/connstatus", cgiWiFiConnStatus),
ROUTE_FILE("/wifi/connecting", "/wifi_conn.tpl"),
ROUTE_CGI("/wifi/setmode", cgiWiFiSetMode), ROUTE_CGI("/wifi/setmode", cgiWiFiSetMode),
ROUTE_CGI("/wifi/setchannel", cgiWiFiSetChannel), ROUTE_CGI("/wifi/setchannel", cgiWiFiSetChannel),
ROUTE_CGI("/wifi/setname", cgiWiFiSetSSID), ROUTE_CGI("/wifi/setname", cgiWiFiSetSSID),

@ -462,7 +462,7 @@ screen_putchar(char ch)
default: default:
if (ch < ' ') { if (ch < ' ') {
// Discard // Discard
warn("Ignoring control char %d", (int)c); warn("Ignoring control char %d", (int)ch);
goto done; goto done;
} }
} }

Loading…
Cancel
Save