Much better wifi config, added display for IP etc, improved "connecting" page
This commit is contained in:
@@ -6,6 +6,7 @@ echo "-- Preparing WWW files --"
|
||||
DD=html_orig/jssrc
|
||||
cat $DD/chibi.js \
|
||||
$DD/utils.js \
|
||||
$DD/modal.js \
|
||||
$DD/appcommon.js \
|
||||
$DD/term.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/term.html html/term.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/favicon.ico html/favicon.ico
|
||||
|
||||
+113
-16
@@ -319,6 +319,78 @@ html {
|
||||
[onclick] {
|
||||
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 {
|
||||
font-family: Arial, sans-serif;
|
||||
color: #D0D0D0;
|
||||
@@ -353,6 +425,8 @@ a:hover {
|
||||
.Box {
|
||||
margin-top: 0.61805rem;
|
||||
padding: 0.23608rem 0.38198rem; } }
|
||||
.Box p:first-child {
|
||||
margin-top: 0; }
|
||||
|
||||
body {
|
||||
position: relative;
|
||||
@@ -376,6 +450,11 @@ body {
|
||||
@media screen and (min-width: 545px) and (max-width: 1000px) {
|
||||
body h1 {
|
||||
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 {
|
||||
padding: 0.38198rem;
|
||||
white-space: nowrap; }
|
||||
@@ -408,7 +487,7 @@ body {
|
||||
#loader.show {
|
||||
opacity: 1; }
|
||||
|
||||
button, input[type=submit] {
|
||||
button, input[type=submit], .button {
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
@@ -428,22 +507,22 @@ button, input[type=submit] {
|
||||
background-color: #3983cd;
|
||||
box-shadow: 0 3px 0 #265f98;
|
||||
text-decoration: none !important; }
|
||||
button:active, input[type=submit]:active {
|
||||
button:active, input[type=submit]:active, .button:active {
|
||||
position: relative;
|
||||
top: 2px; }
|
||||
button.narrow, input[type=submit].narrow {
|
||||
button.narrow, input[type=submit].narrow, .button.narrow {
|
||||
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; }
|
||||
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;
|
||||
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; }
|
||||
button:active, input[type=submit]:active {
|
||||
button:active, input[type=submit]:active, .button:active {
|
||||
box-shadow: 0 1px 0 #154c80; }
|
||||
|
||||
button, input[type=submit] {
|
||||
button, input[type=submit], .button {
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
@@ -463,19 +542,19 @@ button, input[type=submit] {
|
||||
background-color: #3983cd;
|
||||
box-shadow: 0 3px 0 #265f98;
|
||||
text-decoration: none !important; }
|
||||
button:active, input[type=submit]:active {
|
||||
button:active, input[type=submit]:active, .button:active {
|
||||
position: relative;
|
||||
top: 2px; }
|
||||
button.narrow, input[type=submit].narrow {
|
||||
button.narrow, input[type=submit].narrow, .button.narrow {
|
||||
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; }
|
||||
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;
|
||||
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; }
|
||||
button:active, input[type=submit]:active {
|
||||
button:active, input[type=submit]:active, .button:active {
|
||||
box-shadow: 0 1px 0 #154c80; }
|
||||
|
||||
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 {
|
||||
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 {
|
||||
column-count: 3;
|
||||
column-gap: 0;
|
||||
@@ -502,15 +586,25 @@ input[type="number"], input[type="password"], input[type="text"], textarea, sele
|
||||
#ap-list {
|
||||
column-count: 1; } }
|
||||
|
||||
#ap-loader {
|
||||
#ap-loader, #ap-noscan {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border-radius: 5px;
|
||||
padding: 0.38198rem;
|
||||
margin-bottom: 0.38198rem; }
|
||||
|
||||
#ap-noscan {
|
||||
font-weight: bold; }
|
||||
|
||||
#ap-box {
|
||||
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 {
|
||||
break-inside: avoid-column;
|
||||
max-width: 500px;
|
||||
@@ -569,7 +663,10 @@ input[type="number"], input[type="password"], input[type="text"], textarea, sele
|
||||
white-space: pre;
|
||||
cursor: pointer; }
|
||||
.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 {
|
||||
margin-top: 10px;
|
||||
white-space: nowrap; }
|
||||
|
||||
+161
-29
@@ -170,18 +170,35 @@
|
||||
classarray = classes.split(/\s+/);
|
||||
nodeLoop(function (elm) {
|
||||
for (i = 0; i < classarray.length; i += 1) {
|
||||
search = new RegExp('\\b' + classarray[i] + '\\b', 'g');
|
||||
replace = new RegExp(' *' + classarray[i] + '\\b', 'g');
|
||||
var clz = classarray[i];
|
||||
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)) {
|
||||
elm.classList.remove(clz);
|
||||
}
|
||||
else if (action === 'add') {
|
||||
elm.classList.add(clz);
|
||||
}
|
||||
else if (action === 'toggle') {
|
||||
elm.classList.toggle(clz);
|
||||
}
|
||||
else if (action === 'has') {
|
||||
if (elm.classList.contains(clz)) {
|
||||
has = true;
|
||||
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);
|
||||
}
|
||||
@@ -362,11 +379,12 @@
|
||||
};
|
||||
// Add class
|
||||
cb.addClass = function (classes) {
|
||||
if (classes) {
|
||||
nodeLoop(function (elm) {
|
||||
elm.className += ' ' + classes;
|
||||
}, nodes);
|
||||
}
|
||||
classHelper(classes, 'add', nodes);
|
||||
// if (classes) {
|
||||
// nodeLoop(function (elm) {
|
||||
// elm.className += ' ' + classes;
|
||||
// }, nodes);
|
||||
// }
|
||||
return cb;
|
||||
};
|
||||
// Remove class
|
||||
@@ -777,6 +795,47 @@ String.prototype.format = function () {
|
||||
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 */
|
||||
$.ready(function () {
|
||||
// loader dots...
|
||||
@@ -789,6 +848,7 @@ $.ready(function () {
|
||||
});
|
||||
}, 1000);
|
||||
|
||||
// flipping number boxes with the mouse wheel
|
||||
$('input[type=number]').on('mousewheel', function(e) {
|
||||
var val = +$(this).val();
|
||||
if (isNaN(val)) val = 1;
|
||||
@@ -816,10 +876,11 @@ $.ready(function () {
|
||||
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
Modal.init();
|
||||
});
|
||||
|
||||
$._loader = function(vis) {
|
||||
console.log("loader fn", vis);
|
||||
if(vis)
|
||||
$('#loader').addClass('show');
|
||||
else
|
||||
@@ -1202,23 +1263,17 @@ $._loader = function(vis) {
|
||||
$item.on('click', function () {
|
||||
var $th = $(this);
|
||||
|
||||
var ssid = $th.data('ssid');
|
||||
var pass = '';
|
||||
// populate the form
|
||||
$('#conn-essid').val($th.data('ssid'));
|
||||
$('#conn-passwd').val(''); // clear
|
||||
|
||||
if ($th.data('pwd')) {
|
||||
// this AP needs a password
|
||||
pass = prompt("Password for \""+ssid+"\":");
|
||||
if (pass === null) {
|
||||
return;
|
||||
}
|
||||
Modal.show('#psk-modal');
|
||||
} else {
|
||||
Modal.show('#reset-modal');
|
||||
$('#conn-form').submit();
|
||||
}
|
||||
|
||||
$.post('http://'+_root+'/wifi/connect', null, {
|
||||
data: {
|
||||
essid: ssid,
|
||||
passwd: pass
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1229,7 +1284,7 @@ $._loader = function(vis) {
|
||||
|
||||
/** Ask the CGI what APs are visible (async) */
|
||||
function scanAPs() {
|
||||
$.get('http://'+_root+'/wifi/scan', onScan);
|
||||
$.get('/wifi/scan', onScan);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
scanAPs();
|
||||
// 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();
|
||||
}
|
||||
|
||||
$('#modeswitch').html([
|
||||
'<a class="button" href="/wifi/setmode?mode=3">Client+AP</a> <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> <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();
|
||||
};
|
||||
})();
|
||||
|
||||
+38
-15
@@ -15,46 +15,69 @@
|
||||
|
||||
<h1 onclick="location.href='/'">WiFi settings</h1>
|
||||
|
||||
<div class="Box">
|
||||
<div class="Box" id="wificonfbox">
|
||||
<table>
|
||||
<tr>
|
||||
<th>WiFi mode:</th>
|
||||
<td>%WiFiMode%</td>
|
||||
<th>WiFi mode</th>
|
||||
<td id="opmodebox">%WiFiMode%</td>
|
||||
</tr>
|
||||
<tr class="x-hide-noip x-hide-2">
|
||||
<th>IP</th>
|
||||
<td>%StaIP%</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th></th>
|
||||
<td>%WiFiapwarn%</td>
|
||||
<th>Switch to</th>
|
||||
<td id="modeswitch"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><label for="channel">AP channel:</label></th>
|
||||
<tr class="x-hide-1">
|
||||
<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%">
|
||||
<input type="submit" value="Set" class="narrow btn-green">
|
||||
<input name="ch" id="channel" type="number" step=1 min=1 max=14 value="%WiFiChannel%"><!--
|
||||
--><input type="submit" value="Set" class="narrow btn-green x-hide-3">
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><label for="channel">AP name:</label></th>
|
||||
<tr class="x-hide-1">
|
||||
<th><label for="channel">AP name</label></th>
|
||||
<td>
|
||||
<form action="/wifi/setname" method="GET">
|
||||
<input name="name" type="text" value="%APName%">
|
||||
<input type="submit" value="Set" class="narrow btn-green">
|
||||
<input name="name" type="text" value="%APName%"><!--
|
||||
--><input type="submit" value="Set" class="narrow btn-green">
|
||||
</form>
|
||||
</td>
|
||||
</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>
|
||||
</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-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>
|
||||
|
||||
<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>
|
||||
_root = window.location.host;
|
||||
wifiInit({curSSID: '%currSsid%'});
|
||||
wifiInit({staSSID: '%StaSSID%', staIP: '%StaIP%', mode: '%WiFiModeNum%'});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Executable
+26
@@ -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>
|
||||
+113
-16
@@ -319,6 +319,78 @@ html {
|
||||
[onclick] {
|
||||
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 {
|
||||
font-family: Arial, sans-serif;
|
||||
color: #D0D0D0;
|
||||
@@ -353,6 +425,8 @@ a:hover {
|
||||
.Box {
|
||||
margin-top: 0.61805rem;
|
||||
padding: 0.23608rem 0.38198rem; } }
|
||||
.Box p:first-child {
|
||||
margin-top: 0; }
|
||||
|
||||
body {
|
||||
position: relative;
|
||||
@@ -376,6 +450,11 @@ body {
|
||||
@media screen and (min-width: 545px) and (max-width: 1000px) {
|
||||
body h1 {
|
||||
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 {
|
||||
padding: 0.38198rem;
|
||||
white-space: nowrap; }
|
||||
@@ -408,7 +487,7 @@ body {
|
||||
#loader.show {
|
||||
opacity: 1; }
|
||||
|
||||
button, input[type=submit] {
|
||||
button, input[type=submit], .button {
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
@@ -428,22 +507,22 @@ button, input[type=submit] {
|
||||
background-color: #3983cd;
|
||||
box-shadow: 0 3px 0 #265f98;
|
||||
text-decoration: none !important; }
|
||||
button:active, input[type=submit]:active {
|
||||
button:active, input[type=submit]:active, .button:active {
|
||||
position: relative;
|
||||
top: 2px; }
|
||||
button.narrow, input[type=submit].narrow {
|
||||
button.narrow, input[type=submit].narrow, .button.narrow {
|
||||
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; }
|
||||
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;
|
||||
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; }
|
||||
button:active, input[type=submit]:active {
|
||||
button:active, input[type=submit]:active, .button:active {
|
||||
box-shadow: 0 1px 0 #154c80; }
|
||||
|
||||
button, input[type=submit] {
|
||||
button, input[type=submit], .button {
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
@@ -463,19 +542,19 @@ button, input[type=submit] {
|
||||
background-color: #3983cd;
|
||||
box-shadow: 0 3px 0 #265f98;
|
||||
text-decoration: none !important; }
|
||||
button:active, input[type=submit]:active {
|
||||
button:active, input[type=submit]:active, .button:active {
|
||||
position: relative;
|
||||
top: 2px; }
|
||||
button.narrow, input[type=submit].narrow {
|
||||
button.narrow, input[type=submit].narrow, .button.narrow {
|
||||
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; }
|
||||
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;
|
||||
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; }
|
||||
button:active, input[type=submit]:active {
|
||||
button:active, input[type=submit]:active, .button:active {
|
||||
box-shadow: 0 1px 0 #154c80; }
|
||||
|
||||
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 {
|
||||
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 {
|
||||
column-count: 3;
|
||||
column-gap: 0;
|
||||
@@ -502,15 +586,25 @@ input[type="number"], input[type="password"], input[type="text"], textarea, sele
|
||||
#ap-list {
|
||||
column-count: 1; } }
|
||||
|
||||
#ap-loader {
|
||||
#ap-loader, #ap-noscan {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border-radius: 5px;
|
||||
padding: 0.38198rem;
|
||||
margin-bottom: 0.38198rem; }
|
||||
|
||||
#ap-noscan {
|
||||
font-weight: bold; }
|
||||
|
||||
#ap-box {
|
||||
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 {
|
||||
break-inside: avoid-column;
|
||||
max-width: 500px;
|
||||
@@ -569,7 +663,10 @@ input[type="number"], input[type="password"], input[type="text"], textarea, sele
|
||||
white-space: pre;
|
||||
cursor: pointer; }
|
||||
.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 {
|
||||
margin-top: 10px;
|
||||
white-space: nowrap; }
|
||||
|
||||
+161
-30
@@ -170,18 +170,35 @@
|
||||
classarray = classes.split(/\s+/);
|
||||
nodeLoop(function (elm) {
|
||||
for (i = 0; i < classarray.length; i += 1) {
|
||||
search = new RegExp('\\b' + classarray[i] + '\\b', 'g');
|
||||
replace = new RegExp(' *' + classarray[i] + '\\b', 'g');
|
||||
var clz = classarray[i];
|
||||
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)) {
|
||||
elm.classList.remove(clz);
|
||||
}
|
||||
else if (action === 'add') {
|
||||
elm.classList.add(clz);
|
||||
}
|
||||
else if (action === 'toggle') {
|
||||
elm.classList.toggle(clz);
|
||||
}
|
||||
else if (action === 'has') {
|
||||
if (elm.classList.contains(clz)) {
|
||||
has = true;
|
||||
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);
|
||||
}
|
||||
@@ -362,11 +379,12 @@
|
||||
};
|
||||
// Add class
|
||||
cb.addClass = function (classes) {
|
||||
if (classes) {
|
||||
nodeLoop(function (elm) {
|
||||
elm.className += ' ' + classes;
|
||||
}, nodes);
|
||||
}
|
||||
classHelper(classes, 'add', nodes);
|
||||
// if (classes) {
|
||||
// nodeLoop(function (elm) {
|
||||
// elm.className += ' ' + classes;
|
||||
// }, nodes);
|
||||
// }
|
||||
return cb;
|
||||
};
|
||||
// Remove class
|
||||
@@ -574,9 +592,6 @@
|
||||
query = serializeData(opts.data);
|
||||
}
|
||||
|
||||
console.log(opts);
|
||||
console.log(query);
|
||||
|
||||
if (query && (method === 'GET')) {
|
||||
url += (url.indexOf('?') === -1) ? '?' + query : '&' + query;
|
||||
query = null;
|
||||
@@ -780,6 +795,47 @@ String.prototype.format = function () {
|
||||
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 */
|
||||
$.ready(function () {
|
||||
// loader dots...
|
||||
@@ -792,6 +848,7 @@ $.ready(function () {
|
||||
});
|
||||
}, 1000);
|
||||
|
||||
// flipping number boxes with the mouse wheel
|
||||
$('input[type=number]').on('mousewheel', function(e) {
|
||||
var val = +$(this).val();
|
||||
if (isNaN(val)) val = 1;
|
||||
@@ -819,10 +876,11 @@ $.ready(function () {
|
||||
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
Modal.init();
|
||||
});
|
||||
|
||||
$._loader = function(vis) {
|
||||
console.log("loader fn", vis);
|
||||
if(vis)
|
||||
$('#loader').addClass('show');
|
||||
else
|
||||
@@ -1205,21 +1263,17 @@ $._loader = function(vis) {
|
||||
$item.on('click', function () {
|
||||
var $th = $(this);
|
||||
|
||||
var ssid = $th.data('ssid');
|
||||
var pass = '';
|
||||
// populate the form
|
||||
$('#conn-essid').val($th.data('ssid'));
|
||||
$('#conn-passwd').val(''); // clear
|
||||
|
||||
if ($th.data('pwd')) {
|
||||
// this AP needs a password
|
||||
var pass = prompt("Password for \""+ssid+"\":");
|
||||
if (pass === null) {
|
||||
return;
|
||||
}
|
||||
Modal.show('#psk-modal');
|
||||
} else {
|
||||
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) */
|
||||
function scanAPs() {
|
||||
$.get('http://'+_root+'/wifi/scan', onScan);
|
||||
$.get('/wifi/scan', onScan);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
scanAPs();
|
||||
// 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();
|
||||
}
|
||||
|
||||
$('#modeswitch').html([
|
||||
'<a class="button" href="/wifi/setmode?mode=3">Client+AP</a> <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> <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);
|
||||
|
||||
// flipping number boxes with the mouse wheel
|
||||
$('input[type=number]').on('mousewheel', function(e) {
|
||||
var val = +$(this).val();
|
||||
if (isNaN(val)) val = 1;
|
||||
@@ -37,10 +38,11 @@ $.ready(function () {
|
||||
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
Modal.init();
|
||||
});
|
||||
|
||||
$._loader = function(vis) {
|
||||
console.log("loader fn", vis);
|
||||
if(vis)
|
||||
$('#loader').addClass('show');
|
||||
else
|
||||
|
||||
+30
-12
@@ -170,18 +170,35 @@
|
||||
classarray = classes.split(/\s+/);
|
||||
nodeLoop(function (elm) {
|
||||
for (i = 0; i < classarray.length; i += 1) {
|
||||
search = new RegExp('\\b' + classarray[i] + '\\b', 'g');
|
||||
replace = new RegExp(' *' + classarray[i] + '\\b', 'g');
|
||||
var clz = classarray[i];
|
||||
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)) {
|
||||
elm.classList.remove(clz);
|
||||
}
|
||||
else if (action === 'add') {
|
||||
elm.classList.add(clz);
|
||||
}
|
||||
else if (action === 'toggle') {
|
||||
elm.classList.toggle(clz);
|
||||
}
|
||||
else if (action === 'has') {
|
||||
if (elm.classList.contains(clz)) {
|
||||
has = true;
|
||||
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);
|
||||
}
|
||||
@@ -362,11 +379,12 @@
|
||||
};
|
||||
// Add class
|
||||
cb.addClass = function (classes) {
|
||||
if (classes) {
|
||||
nodeLoop(function (elm) {
|
||||
elm.className += ' ' + classes;
|
||||
}, nodes);
|
||||
}
|
||||
classHelper(classes, 'add', nodes);
|
||||
// if (classes) {
|
||||
// nodeLoop(function (elm) {
|
||||
// elm.className += ' ' + classes;
|
||||
// }, nodes);
|
||||
// }
|
||||
return cb;
|
||||
};
|
||||
// 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;
|
||||
})();
|
||||
+87
-16
@@ -54,23 +54,17 @@
|
||||
$item.on('click', function () {
|
||||
var $th = $(this);
|
||||
|
||||
var ssid = $th.data('ssid');
|
||||
var pass = '';
|
||||
// populate the form
|
||||
$('#conn-essid').val($th.data('ssid'));
|
||||
$('#conn-passwd').val(''); // clear
|
||||
|
||||
if ($th.data('pwd')) {
|
||||
// this AP needs a password
|
||||
pass = prompt("Password for \""+ssid+"\":");
|
||||
if (pass === null) {
|
||||
return;
|
||||
}
|
||||
Modal.show('#psk-modal');
|
||||
} else {
|
||||
Modal.show('#reset-modal');
|
||||
$('#conn-form').submit();
|
||||
}
|
||||
|
||||
$.post('http://'+_root+'/wifi/connect', null, {
|
||||
data: {
|
||||
essid: ssid,
|
||||
passwd: pass
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -81,7 +75,7 @@
|
||||
|
||||
/** Ask the CGI what APs are visible (async) */
|
||||
function scanAPs() {
|
||||
$.get('http://'+_root+'/wifi/scan', onScan);
|
||||
$.get('/wifi/scan', onScan);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
scanAPs();
|
||||
// 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();
|
||||
}
|
||||
|
||||
$('#modeswitch').html([
|
||||
'<a class="button" href="/wifi/setmode?mode=3">Client+AP</a> <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> <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 \
|
||||
jssrc/utils.js \
|
||||
jssrc/modal.js \
|
||||
jssrc/appcommon.js \
|
||||
jssrc/term.js \
|
||||
jssrc/wifi.js > js/app.js
|
||||
|
||||
@@ -42,6 +42,10 @@ a:hover {
|
||||
// margin-top: 0;
|
||||
//}
|
||||
|
||||
p:first-child {
|
||||
margin-top:0;
|
||||
}
|
||||
|
||||
border-radius: 3px;
|
||||
background-color: rgba(white, .07);
|
||||
|
||||
@@ -91,10 +95,11 @@ body {
|
||||
}
|
||||
}
|
||||
|
||||
//h2 {
|
||||
// font-size: fsize(3);
|
||||
// margin-bottom: dist(-1);
|
||||
//}
|
||||
h2 {
|
||||
font-size: fsize(2);
|
||||
margin-bottom: dist(-1);
|
||||
&:first-child{margin-top:0}
|
||||
}
|
||||
|
||||
td, th {
|
||||
padding: dist(-2);
|
||||
|
||||
Executable
+78
@@ -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;
|
||||
}
|
||||
|
||||
@import "modal";
|
||||
@import "layout";
|
||||
@import "form/index";
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ $btn-orange-b: #dd8751;
|
||||
$btn-orange-fa: #FEFEFE;
|
||||
$btn-orange-ba: #C6733F;
|
||||
|
||||
button, input[type=submit] {
|
||||
button, input[type=submit], .button {
|
||||
@include fancy-btn-base();
|
||||
|
||||
&.narrow {
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
@import 'fancy_button_mixins';
|
||||
@import 'buttons';
|
||||
@import 'form_elements';
|
||||
|
||||
%form-row-spacing {
|
||||
& > * {
|
||||
margin-right: dist(-2);
|
||||
&:last-child { margin-right: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
//@import 'form_layout';
|
||||
//@import 'select';
|
||||
|
||||
@@ -13,7 +13,10 @@
|
||||
white-space: pre;
|
||||
cursor: pointer;
|
||||
&: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));
|
||||
}
|
||||
|
||||
#ap-loader {
|
||||
#ap-loader, #ap-noscan {
|
||||
background: rgba(white, .1);
|
||||
border-radius: 5px;
|
||||
padding: dist(-2);
|
||||
margin-bottom: dist(-2);
|
||||
}
|
||||
|
||||
#ap-noscan {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#ap-box {
|
||||
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 {
|
||||
// can't use margins inside a column
|
||||
|
||||
|
||||
+38
-15
@@ -15,46 +15,69 @@
|
||||
|
||||
<h1 onclick="location.href='/'">WiFi settings</h1>
|
||||
|
||||
<div class="Box">
|
||||
<div class="Box" id="wificonfbox">
|
||||
<table>
|
||||
<tr>
|
||||
<th>WiFi mode:</th>
|
||||
<td>%WiFiMode%</td>
|
||||
<th>WiFi mode</th>
|
||||
<td id="opmodebox">%WiFiMode%</td>
|
||||
</tr>
|
||||
<tr class="x-hide-noip x-hide-2">
|
||||
<th>IP</th>
|
||||
<td>%StaIP%</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th></th>
|
||||
<td>%WiFiapwarn%</td>
|
||||
<th>Switch to</th>
|
||||
<td id="modeswitch"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><label for="channel">AP channel:</label></th>
|
||||
<tr class="x-hide-1">
|
||||
<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%">
|
||||
<input type="submit" value="Set" class="narrow btn-green">
|
||||
<input name="ch" id="channel" type="number" step=1 min=1 max=14 value="%WiFiChannel%"><!--
|
||||
--><input type="submit" value="Set" class="narrow btn-green x-hide-3">
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><label for="channel">AP name:</label></th>
|
||||
<tr class="x-hide-1">
|
||||
<th><label for="channel">AP name</label></th>
|
||||
<td>
|
||||
<form action="/wifi/setname" method="GET">
|
||||
<input name="name" type="text" value="%APName%">
|
||||
<input type="submit" value="Set" class="narrow btn-green">
|
||||
<input name="name" type="text" value="%APName%"><!--
|
||||
--><input type="submit" value="Set" class="narrow btn-green">
|
||||
</form>
|
||||
</td>
|
||||
</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>
|
||||
</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-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>
|
||||
|
||||
<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>
|
||||
_root = window.location.host;
|
||||
wifiInit({curSSID: '%currSsid%'});
|
||||
wifiInit({staSSID: '%StaSSID%', staIP: '%StaIP%', mode: '%WiFiModeNum%'});
|
||||
</script>
|
||||
</body>
|
||||
</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%">
|
||||
<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%">
|
||||
<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>
|
||||
Executable
+26
@@ -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
Submodule libesphttpd updated: 9ff92faacf...439df03f4b
+2
-1
@@ -23,7 +23,7 @@ static int wifiPassFn(HttpdConnData *connData, int no, char *user, int userLen,
|
||||
*/
|
||||
HttpdBuiltInUrl routes[] = {
|
||||
// redirect func for the captive portal
|
||||
ROUTE_CGI_ARG("*", cgiRedirectApClientToHostname, "esp-remote-term.ap"),
|
||||
ROUTE_CGI_ARG("*", cgiRedirectApClientToHostname, "esp-terminal.ap"),
|
||||
|
||||
// --- Web pages ---
|
||||
ROUTE_TPL_FILE("/", tplScreen, "/term.tpl"),
|
||||
@@ -45,6 +45,7 @@ HttpdBuiltInUrl routes[] = {
|
||||
ROUTE_CGI("/wifi/scan", cgiWiFiScan),
|
||||
ROUTE_CGI("/wifi/connect", cgiWiFiConnect),
|
||||
ROUTE_CGI("/wifi/connstatus", cgiWiFiConnStatus),
|
||||
ROUTE_FILE("/wifi/connecting", "/wifi_conn.tpl"),
|
||||
ROUTE_CGI("/wifi/setmode", cgiWiFiSetMode),
|
||||
ROUTE_CGI("/wifi/setchannel", cgiWiFiSetChannel),
|
||||
ROUTE_CGI("/wifi/setname", cgiWiFiSetSSID),
|
||||
|
||||
+1
-1
@@ -462,7 +462,7 @@ screen_putchar(char ch)
|
||||
default:
|
||||
if (ch < ' ') {
|
||||
// Discard
|
||||
warn("Ignoring control char %d", (int)c);
|
||||
warn("Ignoring control char %d", (int)ch);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user