eslint all the things

cpsdqs/unified-input
Ondřej Hruška 7 years ago
parent 7e1611ff7a
commit 79664f56a6
  1. 10
      .eslintrc
  2. 36
      build.sh
  3. 0
      compile_html.php
  4. 5
      dump_js_lang.php
  5. 195
      jssrc/appcommon.js
  6. 10
      jssrc/lang.js
  7. 0
      jssrc/lib/chibi.js
  8. 0
      jssrc/lib/keymaster.js
  9. 63
      jssrc/lib/polyfills.js
  10. 48
      jssrc/modal.js
  11. 43
      jssrc/notif.js
  12. 82
      jssrc/soft_keyboard.js
  13. 1144
      jssrc/td/WebAudio.d.ts
  14. 8
      jssrc/term.js
  15. 152
      jssrc/term_conn.js
  16. 449
      jssrc/term_input.js
  17. 893
      jssrc/term_screen.js
  18. 138
      jssrc/term_upload.js
  19. 134
      jssrc/utils.js
  20. 181
      jssrc/wifi.js
  21. 4
      pages/term.php

@ -45,7 +45,7 @@
"curly": ["error", "multi-line"],
"dot-location": ["error", "property"],
"eol-last": "error",
"eqeqeq": ["error", "always", { "null": "ignore" }],
"eqeqeq": ["off", "always", { "null": "ignore" }],
"func-call-spacing": ["error", "never"],
"generator-star-spacing": ["error", { "before": true, "after": true }],
"handle-callback-err": ["error", "^(err|error)$" ],
@ -72,7 +72,7 @@
"no-empty-pattern": "error",
"no-eval": "error",
"no-ex-assign": "error",
"no-extend-native": "error",
"no-extend-native": "warn",
"no-extra-bind": "error",
"no-extra-boolean-cast": "error",
"no-extra-parens": ["error", "functions"],
@ -87,7 +87,7 @@
"no-iterator": "error",
"no-label-var": "error",
"no-labels": ["error", { "allowLoop": false, "allowSwitch": false }],
"no-lone-blocks": "error",
"no-lone-blocks": "warn",
"no-mixed-operators": ["error", {
"groups": [
["==", "!=", "===", "!==", ">", ">=", "<", "<="],
@ -134,8 +134,8 @@
"no-unreachable": "error",
"no-unsafe-finally": "error",
"no-unsafe-negation": "error",
"no-unused-expressions": ["error", { "allowShortCircuit": true, "allowTernary": true, "allowTaggedTemplates": true }],
"no-unused-vars": ["error", { "vars": "all", "args": "none", "ignoreRestSiblings": true }],
"no-unused-expressions": ["warn", { "allowShortCircuit": true, "allowTernary": true, "allowTaggedTemplates": true }],
"no-unused-vars": ["off", { "vars": "local", "args": "none", "ignoreRestSiblings": true }],
"no-use-before-define": ["error", { "functions": false, "classes": false, "variables": false }],
"no-useless-call": "error",
"no-useless-computed-key": "error",

@ -1,25 +1,29 @@
#!/bin/bash
echo "Packing JS..."
echo 'Packing JS...'
cat jssrc/chibi.js \
jssrc/keymaster.js \
jssrc/utils.js \
jssrc/modal.js \
jssrc/notif.js \
jssrc/appcommon.js \
jssrc/lang.js \
jssrc/wifi.js \
jssrc/term_* \
jssrc/term.js \
jssrc/soft_keyboard.js | npm run --silent minify > js/app.js
echo ';' > ';'
cat jssrc/lib/chibi.js ';' \
jssrc/lib/keymaster.js ';' \
jssrc/lib/polyfills.js ';' \
jssrc/utils.js ';' \
jssrc/modal.js ';' \
jssrc/notif.js ';' \
jssrc/appcommon.js ';' \
jssrc/lang.js ';' \
jssrc/wifi.js ';' \
jssrc/term_* ';' \
jssrc/term.js ';' \
jssrc/soft_keyboard.js | npm run --silent minify > js/app.js
rm ';'
echo "Building CSS..."
echo 'Building CSS...'
npm run sass -- --output-style compressed sass/app.scss css/app.css
echo "Building HTML..."
echo 'Building HTML...'
php ./build_html.php
php ./dump_js_lang.php
php ./compile_html.php
echo "ESPTerm front-end ready"
echo 'ESPTerm front-end ready'

@ -8,7 +8,6 @@ $selected = [
'wifi.connected_ip_is',
'wifi.not_conn',
'wifi.enter_passwd',
'wifi.passwd_saved',
];
$out = [];
@ -18,6 +17,6 @@ foreach ($selected as $key) {
file_put_contents(__DIR__. '/jssrc/lang.js',
"// Generated from PHP locale file\n" .
'var _tr = ' . json_encode($out, JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE) . ";\n\n" .
"function tr(key) { return _tr[key] || '?'+key+'?'; }\n"
'let _tr = ' . json_encode($out, JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE) . ";\n\n" .
"function tr (key) { return _tr[key] || '?' + key + '?' }\n"
);

@ -2,189 +2,124 @@
$.ready(function () {
// Checkbox UI (checkbox CSS and hidden input with int value)
$('.Row.checkbox').forEach(function (x) {
var inp = x.querySelector('input');
var box = x.querySelector('.box');
let inp = x.querySelector('input')
let box = x.querySelector('.box')
$(box).toggleClass('checked', inp.value);
$(box).toggleClass('checked', inp.value)
var hdl = function () {
inp.value = 1 - inp.value;
let hdl = function () {
inp.value = 1 - inp.value
$(box).toggleClass('checked', inp.value)
};
}
$(x).on('click', hdl).on('keypress', cr(hdl));
});
$(x).on('click', hdl).on('keypress', cr(hdl))
})
// Expanding boxes on mobile
$('.Box.mobcol,.Box.fold').forEach(function (x) {
var h = x.querySelector('h2');
let h = x.querySelector('h2')
var hdl = function () {
$(x).toggleClass('expanded');
};
$(h).on('click', hdl).on('keypress', cr(hdl));
});
let hdl = function () {
$(x).toggleClass('expanded')
}
$(h).on('click', hdl).on('keypress', cr(hdl))
})
$('form').forEach(function (x) {
$(x).on('keypress', function (e) {
if ((e.keyCode == 10 || e.keyCode == 13) && e.ctrlKey) {
x.submit();
x.submit()
}
})
});
})
// loader dots...
setInterval(function () {
$('.anim-dots').each(function (x) {
var $x = $(x);
var dots = $x.html() + '.';
if (dots.length == 5) dots = '.';
$x.html(dots);
});
}, 1000);
let $x = $(x)
let dots = $x.html() + '.'
if (dots.length == 5) dots = '.'
$x.html(dots)
})
}, 1000)
// flipping number boxes with the mouse wheel
$('input[type=number]').on('mousewheel', function (e) {
var $this = $(this);
var val = +$this.val();
if (isNaN(val)) val = 1;
let $this = $(this)
let val = +$this.val()
if (isNaN(val)) val = 1
var step = +($this.attr('step') || 1);
var min = +$this.attr('min');
var max = +$this.attr('max');
const step = +($this.attr('step') || 1)
const min = +$this.attr('min')
const max = +$this.attr('max')
if (e.wheelDelta > 0) {
val += step;
val += step
} else {
val -= step;
val -= step
}
if (typeof min != 'undefined') val = Math.max(val, +min);
if (typeof max != 'undefined') val = Math.min(val, +max);
$this.val(val);
if (typeof min != 'undefined') val = Math.max(val, +min)
if (typeof max != 'undefined') val = Math.min(val, +max)
$this.val(val)
if ("createEvent" in document) {
var evt = document.createEvent("HTMLEvents");
evt.initEvent("change", false, true);
$this[0].dispatchEvent(evt);
if ('createEvent' in document) {
let evt = document.createEvent('HTMLEvents')
evt.initEvent('change', false, true)
$this[0].dispatchEvent(evt)
} else {
$this[0].fireEvent("onchange");
$this[0].fireEvent('onchange')
}
e.preventDefault();
});
e.preventDefault()
})
var errAt = location.search.indexOf('err=');
let errAt = location.search.indexOf('err=')
if (errAt !== -1 && qs('.Box.errors')) {
var errs = location.search.substr(errAt + 4).split(',');
var hres = [];
let errs = location.search.substr(errAt + 4).split(',')
let hres = []
errs.forEach(function (er) {
var lbl = qs('label[for="' + er + '"]');
let lbl = qs('label[for="' + er + '"]')
if (lbl) {
lbl.classList.add('error');
hres.push(lbl.childNodes[0].textContent.trim().replace(/: ?$/, ''));
lbl.classList.add('error')
hres.push(lbl.childNodes[0].textContent.trim().replace(/: ?$/, ''))
} else {
hres.push(er);
hres.push(er)
}
});
})
qs('.Box.errors .list').innerHTML = hres.join(', ');
qs('.Box.errors').classList.remove('hidden');
qs('.Box.errors .list').innerHTML = hres.join(', ')
qs('.Box.errors').classList.remove('hidden')
}
Modal.init();
Notify.init();
Modal.init()
Notify.init()
// remove tabindixes from h2 if wide
if (window.innerWidth > 550) {
$('.Box h2').forEach(function (x) {
x.removeAttribute('tabindex');
});
x.removeAttribute('tabindex')
})
// brand works as a link back to term in widescreen mode
var br = qs('#brand');
let br = qs('#brand')
br && br.addEventListener('click', function () {
location.href = '/'; // go to terminal
});
location.href = '/' // go to terminal
})
}
});
})
$._loader = function (vis) {
$('#loader').toggleClass('show', vis);
};
$('#loader').toggleClass('show', vis)
}
function showPage() {
$('#content').addClass('load');
function showPage () {
$('#content').addClass('load')
}
$.ready(function () {
if (window.noAutoShow !== true) {
setTimeout(function () {
showPage();
}, 1);
showPage()
}, 1)
}
});
/*! http://mths.be/fromcodepoint v0.1.0 by @mathias */
if (!String.fromCodePoint) {
(function () {
var defineProperty = (function () {
// IE 8 only supports `Object.defineProperty` on DOM elements
try {
var object = {};
var $defineProperty = Object.defineProperty;
var result = $defineProperty(object, object, object) && $defineProperty;
} catch (error) {
}
return result;
}());
var stringFromCharCode = String.fromCharCode;
var floor = Math.floor;
var fromCodePoint = function () {
var MAX_SIZE = 0x4000;
var codeUnits = [];
var highSurrogate;
var lowSurrogate;
var index = -1;
var length = arguments.length;
if (!length) {
return '';
}
var result = '';
while (++index < length) {
var codePoint = Number(arguments[index]);
if (
!isFinite(codePoint) || // `NaN`, `+Infinity`, or `-Infinity`
codePoint < 0 || // not a valid Unicode code point
codePoint > 0x10FFFF || // not a valid Unicode code point
floor(codePoint) != codePoint // not an integer
) {
throw RangeError('Invalid code point: ' + codePoint);
}
if (codePoint <= 0xFFFF) { // BMP code point
codeUnits.push(codePoint);
} else { // Astral code point; split in surrogate halves
// http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
codePoint -= 0x10000;
highSurrogate = (codePoint >> 10) + 0xD800;
lowSurrogate = (codePoint % 0x400) + 0xDC00;
codeUnits.push(highSurrogate, lowSurrogate);
}
if (index + 1 == length || codeUnits.length > MAX_SIZE) {
result += stringFromCharCode.apply(null, codeUnits);
codeUnits.length = 0;
}
}
return result;
};
if (defineProperty) {
defineProperty(String, 'fromCodePoint', {
'value': fromCodePoint,
'configurable': true,
'writable': true
});
} else {
String.fromCodePoint = fromCodePoint;
}
}());
}
})

@ -1,8 +1,8 @@
// Generated from PHP locale file
var _tr = {
"wifi.connected_ip_is": "Connected, IP is ",
"wifi.not_conn": "Not connected.",
"wifi.enter_passwd": "Enter password for \":ssid:\""
let _tr = {
"wifi.connected_ip_is": "Connected, IP is ",
"wifi.not_conn": "Not connected.",
"wifi.enter_passwd": "Enter password for \":ssid:\""
};
function tr(key) { return _tr[key] || '?'+key+'?'; }
function tr (key) { return _tr[key] || '?' + key + '?' }

@ -0,0 +1,63 @@
/*! http://mths.be/fromcodepoint v0.1.0 by @mathias */
if (!String.fromCodePoint) {
(function () {
var defineProperty = (function () {
// IE 8 only supports `Object.defineProperty` on DOM elements
try {
var object = {};
var $defineProperty = Object.defineProperty;
var result = $defineProperty(object, object, object) && $defineProperty;
} catch (error) {
}
return result;
}());
var stringFromCharCode = String.fromCharCode;
var floor = Math.floor;
var fromCodePoint = function () {
var MAX_SIZE = 0x4000;
var codeUnits = [];
var highSurrogate;
var lowSurrogate;
var index = -1;
var length = arguments.length;
if (!length) {
return '';
}
var result = '';
while (++index < length) {
var codePoint = Number(arguments[index]);
if (
!isFinite(codePoint) || // `NaN`, `+Infinity`, or `-Infinity`
codePoint < 0 || // not a valid Unicode code point
codePoint > 0x10FFFF || // not a valid Unicode code point
floor(codePoint) != codePoint // not an integer
) {
throw RangeError('Invalid code point: ' + codePoint);
}
if (codePoint <= 0xFFFF) { // BMP code point
codeUnits.push(codePoint);
} else { // Astral code point; split in surrogate halves
// http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
codePoint -= 0x10000;
highSurrogate = (codePoint >> 10) + 0xD800;
lowSurrogate = (codePoint % 0x400) + 0xDC00;
codeUnits.push(highSurrogate, lowSurrogate);
}
if (index + 1 == length || codeUnits.length > MAX_SIZE) {
result += stringFromCharCode.apply(null, codeUnits);
codeUnits.length = 0;
}
}
return result;
};
if (defineProperty) {
defineProperty(String, 'fromCodePoint', {
'value': fromCodePoint,
'configurable': true,
'writable': true
});
} else {
String.fromCodePoint = fromCodePoint;
}
}());
}

@ -1,44 +1,44 @@
/** Module for toggling a modal overlay */
(function () {
var modal = {};
var curCloseCb = null;
let modal = {}
let curCloseCb = null
modal.show = function (sel, closeCb) {
var $m = $(sel);
$m.removeClass('hidden visible');
let $m = $(sel)
$m.removeClass('hidden visible')
setTimeout(function () {
$m.addClass('visible');
}, 1);
curCloseCb = closeCb;
};
$m.addClass('visible')
}, 1)
curCloseCb = closeCb
}
modal.hide = function (sel) {
var $m = $(sel);
$m.removeClass('visible');
let $m = $(sel)
$m.removeClass('visible')
setTimeout(function () {
$m.addClass('hidden');
if (curCloseCb) curCloseCb();
}, 500); // transition time
};
$m.addClass('hidden')
if (curCloseCb) curCloseCb()
}, 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);
});
if ($(this).hasClass('no-close')) return // this is a no-close modal
modal.hide(this)
})
$('.Dialog').on('click', function (e) {
e.stopImmediatePropagation();
});
e.stopImmediatePropagation()
})
// Hide all modals on esc
$(window).on('keydown', function (e) {
if (e.which == 27) {
modal.hide('.Modal');
modal.hide('.Modal')
}
});
};
})
}
window.Modal = modal;
})();
window.Modal = modal
})()

@ -1,32 +1,35 @@
(function (nt) {
var sel = '#notif';
window.Notify = (function () {
let nt = {}
const sel = '#notif'
var hideTmeo1; // timeout to start hiding (transition)
var hideTmeo2; // timeout to add the hidden class
let hideTmeo1 // timeout to start hiding (transition)
let hideTmeo2 // timeout to add the hidden class
nt.show = function (message, timeout) {
$(sel).html(message);
Modal.show(sel);
$(sel).html(message)
Modal.show(sel)
clearTimeout(hideTmeo1);
clearTimeout(hideTmeo2);
clearTimeout(hideTmeo1)
clearTimeout(hideTmeo2)
if (undef(timeout)) timeout = 2500;
if (undef(timeout)) timeout = 2500
hideTmeo1 = setTimeout(nt.hide, timeout);
};
hideTmeo1 = setTimeout(nt.hide, timeout)
}
nt.hide = function () {
var $m = $(sel);
$m.removeClass('visible');
let $m = $(sel)
$m.removeClass('visible')
hideTmeo2 = setTimeout(function () {
$m.addClass('hidden');
}, 250); // transition time
};
$m.addClass('hidden')
}, 250) // transition time
}
nt.init = function () {
$(sel).on('click', function () {
nt.hide(this);
});
};
})(window.Notify = {});
nt.hide(this)
})
}
return nt
})()

@ -1,87 +1,87 @@
$.ready(() => {
const input = qs('#softkb-input');
if (!input) return; // abort, we're not on the terminal page
const input = qs('#softkb-input')
if (!input) return // abort, we're not on the terminal page
let keyboardOpen = false;
let keyboardOpen = false
let updateInputPosition = function () {
if (!keyboardOpen) return;
if (!keyboardOpen) return
let [x, y] = Screen.gridToScreen(Screen.cursor.x, Screen.cursor.y);
let [x, y] = Screen.gridToScreen(Screen.cursor.x, Screen.cursor.y)
input.style.transform = `translate(${x}px, ${y}px)`
};
}
input.addEventListener('focus', () => {
keyboardOpen = true;
keyboardOpen = true
updateInputPosition()
});
input.addEventListener('blur', () => (keyboardOpen = false));
Screen.on('cursor-moved', updateInputPosition);
})
input.addEventListener('blur', () => (keyboardOpen = false))
Screen.on('cursor-moved', updateInputPosition)
window.kbOpen = function openSoftKeyboard (open) {
keyboardOpen = open;
updateInputPosition();
if (open) input.focus();
keyboardOpen = open
updateInputPosition()
if (open) input.focus()
else input.blur()
};
}
let lastCompositionString = '';
let compositing = false;
let lastCompositionString = ''
let compositing = false
let sendInputDelta = function (newValue) {
let resend = false;
let resend = false
if (newValue.length > lastCompositionString.length) {
if (newValue.startsWith(lastCompositionString)) {
// characters have been added at the end
Input.sendString(newValue.substr(lastCompositionString.length))
} else resend = true;
} else resend = true
} else if (newValue.length < lastCompositionString.length) {
if (lastCompositionString.startsWith(newValue)) {
// characters have been removed at the end
Input.sendString('\b'.repeat(lastCompositionString.length -
newValue.length))
} else resend = true;
} else if (newValue !== lastCompositionString) resend = true;
} else resend = true
} else if (newValue !== lastCompositionString) resend = true
if (resend) {
// the entire string changed; resend everything
Input.sendString('\b'.repeat(lastCompositionString.length) +
newValue)
}
lastCompositionString = newValue;
};
lastCompositionString = newValue
}
input.addEventListener('keydown', e => {
if (e.key === 'Unidentified') return;
if (e.key === 'Unidentified') return
e.preventDefault();
input.value = '';
e.preventDefault()
input.value = ''
if (e.key === 'Backspace') Input.sendString('\b');
if (e.key === 'Backspace') Input.sendString('\b')
else if (e.key === 'Enter') Input.sendString('\x0d')
});
})
input.addEventListener('input', e => {
e.stopPropagation();
e.stopPropagation()
if (e.isComposing) {
sendInputDelta(e.data);
sendInputDelta(e.data)
} else {
if (e.data) Input.sendString(e.data);
if (e.data) Input.sendString(e.data)
else if (e.inputType === 'deleteContentBackward') {
lastCompositionString = '';
sendInputDelta('');
lastCompositionString = ''
sendInputDelta('')
}
}
});
})
input.addEventListener('compositionstart', e => {
lastCompositionString = '';
compositing = true;
});
lastCompositionString = ''
compositing = true
})
input.addEventListener('compositionend', e => {
lastCompositionString = '';
compositing = false;
input.value = '';
});
lastCompositionString = ''
compositing = false
input.value = ''
})
Screen.on('open-soft-keyboard', () => input.focus())
});
})

File diff suppressed because it is too large Load Diff

@ -1,6 +1,6 @@
/** Init the terminal sub-module - called from HTML */
window.termInit = function () {
Conn.init();
Input.init();
TermUpl.init();
};
Conn.init()
Input.init()
TermUpl.init()
}

@ -1,31 +1,31 @@
/** Handle connections */
var Conn = (function () {
var ws;
var heartbeatTout;
var pingIv;
var xoff = false;
var autoXoffTout;
var reconTout;
window.Conn = (function () {
let ws
let heartbeatTout
let pingIv
let xoff = false
let autoXoffTout
let reconTout
var pageShown = false;
let pageShown = false
function onOpen(evt) {
console.log("CONNECTED");
heartbeat();
doSend("i");
function onOpen (evt) {
console.log('CONNECTED')
heartbeat()
doSend('i')
}
function onClose(evt) {
console.warn("SOCKET CLOSED, code " + evt.code + ". Reconnecting...");
clearTimeout(reconTout);
function onClose (evt) {
console.warn('SOCKET CLOSED, code ' + evt.code + '. Reconnecting...')
clearTimeout(reconTout)
reconTout = setTimeout(function () {
init();
}, 2000);
init()
}, 2000)
// this happens when the buffer gets fucked up via invalid unicode.
// we basically use polling instead of socket then
}
function onMessage(evt) {
function onMessage (evt) {
try {
// . = heartbeat
switch (evt.data.charAt(0)) {
@ -33,104 +33,104 @@ var Conn = (function () {
case 'T':
case 'S':
case 'G':
Screen.load(evt.data);
if(!pageShown) {
showPage();
pageShown = true;
Screen.load(evt.data)
if (!pageShown) {
showPage()
pageShown = true
}
break;
break
case '-':
//console.log('xoff');
xoff = true;
// console.log('xoff');
xoff = true
autoXoffTout = setTimeout(function () {
xoff = false;
}, 250);
break;
xoff = false
}, 250)
break
case '+':
//console.log('xon');
xoff = false;
clearTimeout(autoXoffTout);
break;
// console.log('xon');
xoff = false
clearTimeout(autoXoffTout)
break
}
heartbeat();
heartbeat()
} catch (e) {
console.error(e);
console.error(e)
}
}
function canSend() {
return !xoff;
function canSend () {
return !xoff
}
function doSend(message) {
function doSend (message) {
if (_demo) {
console.log("TX: ", message);
return true; // Simulate success
console.log('TX: ', message)
return true // Simulate success
}
if (xoff) {
// TODO queue
console.log("Can't send, flood control.");
return false;
console.log("Can't send, flood control.")
return false
}
if (!ws) return false; // for dry testing
if (!ws) return false // for dry testing
if (ws.readyState != 1) {
console.error("Socket not ready");
return false;
console.error('Socket not ready')
return false
}
if (typeof message != "string") {
message = JSON.stringify(message);
if (typeof message != 'string') {
message = JSON.stringify(message)
}
ws.send(message);
return true;
ws.send(message)
return true
}
function init() {
function init () {
if (_demo) {
console.log("Demo mode!");
Screen.load(_demo_screen);
showPage();
return;
console.log('Demo mode!')
Screen.load(_demo_screen)
showPage()
return
}
clearTimeout(reconTout);
clearTimeout(heartbeatTout);
clearTimeout(reconTout)
clearTimeout(heartbeatTout)
ws = new WebSocket("ws://" + _root + "/term/update.ws");
ws.onopen = onOpen;
ws.onclose = onClose;
ws.onmessage = onMessage;
console.log("Opening socket.");
heartbeat();
ws = new WebSocket('ws://' + _root + '/term/update.ws')
ws.onopen = onOpen
ws.onclose = onClose
ws.onmessage = onMessage
console.log('Opening socket.')
heartbeat()
}
function heartbeat() {
clearTimeout(heartbeatTout);
heartbeatTout = setTimeout(heartbeatFail, 2000);
function heartbeat () {
clearTimeout(heartbeatTout)
heartbeatTout = setTimeout(heartbeatFail, 2000)
}
function heartbeatFail() {
console.error("Heartbeat lost, probing server...");
function heartbeatFail () {
console.error('Heartbeat lost, probing server...')
pingIv = setInterval(function () {
console.log("> ping");
console.log('> ping')
$.get('http://' + _root + '/system/ping', function (resp, status) {
if (status == 200) {
clearInterval(pingIv);
console.info("Server ready, reloading page...");
location.reload();
clearInterval(pingIv)
console.info('Server ready, reloading page...')
location.reload()
}
}, {
timeout: 100,
});
}, 1000);
timeout: 100
})
}, 1000)
}
return {
ws: null,
init: init,
send: doSend,
canSend: canSend, // check flood control
};
})();
canSend: canSend // check flood control
}
})()

@ -14,253 +14,252 @@
* r - mb release
* m - mouse move
*/
var Input = (function() {
var opts = {
np_alt: false,
cu_alt: false,
fn_alt: false,
mt_click: false,
mt_move: false,
no_keys: false,
crlf_mode: false,
};
window.Input = (function () {
let opts = {
np_alt: false,
cu_alt: false,
fn_alt: false,
mt_click: false,
mt_move: false,
no_keys: false,
crlf_mode: false
}
/** Send a literal message */
function sendStrMsg(str) {
return Conn.send("s"+str);
}
/** Send a literal message */
function sendStrMsg (str) {
return Conn.send('s' + str)
}
/** Send a button event */
function sendBtnMsg(n) {
Conn.send("b"+Chr(n));
}
/** Send a button event */
function sendBtnMsg (n) {
Conn.send('b' + Chr(n))
}
/** Fn alt choice for key message */
function fa(alt, normal) {
return opts.fn_alt ? alt : normal;
}
/** Fn alt choice for key message */
function fa (alt, normal) {
return opts.fn_alt ? alt : normal
}
/** Cursor alt choice for key message */
function ca(alt, normal) {
return opts.cu_alt ? alt : normal;
}
/** Cursor alt choice for key message */
function ca (alt, normal) {
return opts.cu_alt ? alt : normal
}
/** Numpad alt choice for key message */
function na(alt, normal) {
return opts.np_alt ? alt : normal;
}
/** Numpad alt choice for key message */
function na (alt, normal) {
return opts.np_alt ? alt : normal
}
function _bindFnKeys() {
var keymap = {
'tab': '\x09',
'backspace': '\x08',
'enter': opts.crlf_mode ? '\x0d\x0a' : '\x0d',
'ctrl+enter': '\x0a',
'esc': '\x1b',
'up': ca('\x1bOA', '\x1b[A'),
'down': ca('\x1bOB', '\x1b[B'),
'right': ca('\x1bOC', '\x1b[C'),
'left': ca('\x1bOD', '\x1b[D'),
'home': ca('\x1bOH', fa('\x1b[H', '\x1b[1~')),
'insert': '\x1b[2~',
'delete': '\x1b[3~',
'end': ca('\x1bOF', fa('\x1b[F', '\x1b[4~')),
'pageup': '\x1b[5~',
'pagedown': '\x1b[6~',
'f1': fa('\x1bOP', '\x1b[11~'),
'f2': fa('\x1bOQ', '\x1b[12~'),
'f3': fa('\x1bOR', '\x1b[13~'),
'f4': fa('\x1bOS', '\x1b[14~'),
'f5': '\x1b[15~', // note the disconnect
'f6': '\x1b[17~',
'f7': '\x1b[18~',
'f8': '\x1b[19~',
'f9': '\x1b[20~',
'f10': '\x1b[21~', // note the disconnect
'f11': '\x1b[23~',
'f12': '\x1b[24~',
'shift+f1': fa('\x1bO1;2P', '\x1b[25~'),
'shift+f2': fa('\x1bO1;2Q', '\x1b[26~'), // note the disconnect
'shift+f3': fa('\x1bO1;2R', '\x1b[28~'),
'shift+f4': fa('\x1bO1;2S', '\x1b[29~'), // note the disconnect
'shift+f5': fa('\x1b[15;2~', '\x1b[31~'),
'shift+f6': fa('\x1b[17;2~', '\x1b[32~'),
'shift+f7': fa('\x1b[18;2~', '\x1b[33~'),
'shift+f8': fa('\x1b[19;2~', '\x1b[34~'),
'shift+f9': fa('\x1b[20;2~', '\x1b[35~'), // 35-38 are not standard - but what is?
'shift+f10': fa('\x1b[21;2~', '\x1b[36~'),
'shift+f11': fa('\x1b[22;2~', '\x1b[37~'),
'shift+f12': fa('\x1b[23;2~', '\x1b[38~'),
'np_0': na('\x1bOp', '0'),
'np_1': na('\x1bOq', '1'),
'np_2': na('\x1bOr', '2'),
'np_3': na('\x1bOs', '3'),
'np_4': na('\x1bOt', '4'),
'np_5': na('\x1bOu', '5'),
'np_6': na('\x1bOv', '6'),
'np_7': na('\x1bOw', '7'),
'np_8': na('\x1bOx', '8'),
'np_9': na('\x1bOy', '9'),
'np_mul': na('\x1bOR', '*'),
'np_add': na('\x1bOl', '+'),
'np_sub': na('\x1bOS', '-'),
'np_point': na('\x1bOn', '.'),
'np_div': na('\x1bOQ', '/'),
// we don't implement numlock key (should change in numpad_alt mode, but it's even more useless than the rest)
};
function _bindFnKeys () {
const keymap = {
'tab': '\x09',
'backspace': '\x08',
'enter': opts.crlf_mode ? '\x0d\x0a' : '\x0d',
'ctrl+enter': '\x0a',
'esc': '\x1b',
'up': ca('\x1bOA', '\x1b[A'),
'down': ca('\x1bOB', '\x1b[B'),
'right': ca('\x1bOC', '\x1b[C'),
'left': ca('\x1bOD', '\x1b[D'),
'home': ca('\x1bOH', fa('\x1b[H', '\x1b[1~')),
'insert': '\x1b[2~',
'delete': '\x1b[3~',
'end': ca('\x1bOF', fa('\x1b[F', '\x1b[4~')),
'pageup': '\x1b[5~',
'pagedown': '\x1b[6~',
'f1': fa('\x1bOP', '\x1b[11~'),
'f2': fa('\x1bOQ', '\x1b[12~'),
'f3': fa('\x1bOR', '\x1b[13~'),
'f4': fa('\x1bOS', '\x1b[14~'),
'f5': '\x1b[15~', // note the disconnect
'f6': '\x1b[17~',
'f7': '\x1b[18~',
'f8': '\x1b[19~',
'f9': '\x1b[20~',
'f10': '\x1b[21~', // note the disconnect
'f11': '\x1b[23~',
'f12': '\x1b[24~',
'shift+f1': fa('\x1bO1;2P', '\x1b[25~'),
'shift+f2': fa('\x1bO1;2Q', '\x1b[26~'), // note the disconnect
'shift+f3': fa('\x1bO1;2R', '\x1b[28~'),
'shift+f4': fa('\x1bO1;2S', '\x1b[29~'), // note the disconnect
'shift+f5': fa('\x1b[15;2~', '\x1b[31~'),
'shift+f6': fa('\x1b[17;2~', '\x1b[32~'),
'shift+f7': fa('\x1b[18;2~', '\x1b[33~'),
'shift+f8': fa('\x1b[19;2~', '\x1b[34~'),
'shift+f9': fa('\x1b[20;2~', '\x1b[35~'), // 35-38 are not standard - but what is?
'shift+f10': fa('\x1b[21;2~', '\x1b[36~'),
'shift+f11': fa('\x1b[22;2~', '\x1b[37~'),
'shift+f12': fa('\x1b[23;2~', '\x1b[38~'),
'np_0': na('\x1bOp', '0'),
'np_1': na('\x1bOq', '1'),
'np_2': na('\x1bOr', '2'),
'np_3': na('\x1bOs', '3'),
'np_4': na('\x1bOt', '4'),
'np_5': na('\x1bOu', '5'),
'np_6': na('\x1bOv', '6'),
'np_7': na('\x1bOw', '7'),
'np_8': na('\x1bOx', '8'),
'np_9': na('\x1bOy', '9'),
'np_mul': na('\x1bOR', '*'),
'np_add': na('\x1bOl', '+'),
'np_sub': na('\x1bOS', '-'),
'np_point': na('\x1bOn', '.'),
'np_div': na('\x1bOQ', '/')
// we don't implement numlock key (should change in numpad_alt mode, but it's even more useless than the rest)
}
for (var k in keymap) {
if (keymap.hasOwnProperty(k)) {
bind(k, keymap[k]);
}
}
}
for (let k in keymap) {
if (keymap.hasOwnProperty(k)) {
bind(k, keymap[k])
}
}
}
/** Bind a keystroke to message */
function bind(combo, str) {
// mac fix - allow also cmd
if (combo.indexOf('ctrl+') !== -1) {
combo += ',' + combo.replace('ctrl', 'command');
}
/** Bind a keystroke to message */
function bind (combo, str) {
// mac fix - allow also cmd
if (combo.indexOf('ctrl+') !== -1) {
combo += ',' + combo.replace('ctrl', 'command')
}
// unbind possible old binding
key.unbind(combo);
// unbind possible old binding
key.unbind(combo)
key(combo, function (e) {
if (opts.no_keys) return;
e.preventDefault();
sendStrMsg(str)
});
}
key(combo, function (e) {
if (opts.no_keys) return
e.preventDefault()
sendStrMsg(str)
})
}
/** Bind/rebind key messages */
function _initKeys() {
// This takes care of text characters typed
window.addEventListener('keypress', function(evt) {
if (opts.no_keys) return;
var str = '';
if (evt.key) str = evt.key;
else if (evt.which) str = String.fromCodePoint(evt.which);
if (str.length>0 && str.charCodeAt(0) >= 32) {
// console.log("Typed ", str);
// prevent space from scrolling
if (evt.which === 32) evt.preventDefault();
sendStrMsg(str);
}
});
/** Bind/rebind key messages */
function _initKeys () {
// This takes care of text characters typed
window.addEventListener('keypress', function (evt) {
if (opts.no_keys) return
let str = ''
if (evt.key) str = evt.key
else if (evt.which) str = String.fromCodePoint(evt.which)
if (str.length > 0 && str.charCodeAt(0) >= 32) {
// console.log("Typed ", str);
// prevent space from scrolling
if (evt.which === 32) evt.preventDefault()
sendStrMsg(str)
}
})
// ctrl-letter codes are sent as simple low ASCII codes
for (var i = 1; i<=26;i++) {
bind('ctrl+' + String.fromCharCode(96+i), String.fromCharCode(i));
}
bind('ctrl+]', '\x1b'); // alternate way to enter ESC
bind('ctrl+\\', '\x1c');
bind('ctrl+[', '\x1d');
bind('ctrl+^', '\x1e');
bind('ctrl+_', '\x1f');
// ctrl-letter codes are sent as simple low ASCII codes
for (let i = 1; i <= 26; i++) {
bind('ctrl+' + String.fromCharCode(96 + i), String.fromCharCode(i))
}
bind('ctrl+]', '\x1b') // alternate way to enter ESC
bind('ctrl+\\', '\x1c')
bind('ctrl+[', '\x1d')
bind('ctrl+^', '\x1e')
bind('ctrl+_', '\x1f')
_bindFnKeys();
}
_bindFnKeys()
}
// mouse button states
var mb1 = 0;
var mb2 = 0;
var mb3 = 0;
// mouse button states
let mb1 = 0
let mb2 = 0
let mb3 = 0
/** Init the Input module */
function init() {
_initKeys();
/** Init the Input module */
function init () {
_initKeys()
// Button presses
$('#action-buttons button').forEach(function(s) {
s.addEventListener('click', function() {
sendBtnMsg(+this.dataset['n']);
});
});
// Button presses
$('#action-buttons button').forEach(function (s) {
s.addEventListener('click', function () {
sendBtnMsg(+this.dataset['n'])
})
})
// global mouse state tracking - for motion reporting
window.addEventListener('mousedown', function(evt) {
if (evt.button == 0) mb1 = 1;
if (evt.button == 1) mb2 = 1;
if (evt.button == 2) mb3 = 1;
});
// global mouse state tracking - for motion reporting
window.addEventListener('mousedown', function (evt) {
if (evt.button == 0) mb1 = 1
if (evt.button == 1) mb2 = 1
if (evt.button == 2) mb3 = 1
})
window.addEventListener('mouseup', function(evt) {
if (evt.button == 0) mb1 = 0;
if (evt.button == 1) mb2 = 0;
if (evt.button == 2) mb3 = 0;
});
}
window.addEventListener('mouseup', function (evt) {
if (evt.button == 0) mb1 = 0
if (evt.button == 1) mb2 = 0
if (evt.button == 2) mb3 = 0
})
}
/** Prepare modifiers byte for mouse message */
function packModifiersForMouse() {
return (key.isModifier('ctrl')?1:0) |
(key.isModifier('shift')?2:0) |
(key.isModifier('alt')?4:0) |
(key.isModifier('meta')?8:0);
}
/** Prepare modifiers byte for mouse message */
function packModifiersForMouse () {
return (key.isModifier('ctrl') ? 1 : 0) |
(key.isModifier('shift') ? 2 : 0) |
(key.isModifier('alt') ? 4 : 0) |
(key.isModifier('meta') ? 8 : 0)
}
return {
/** Init the Input module */
init: init,
return {
/** Init the Input module */
init: init,
/** Send a literal string message */
sendString: sendStrMsg,
/** Send a literal string message */
sendString: sendStrMsg,
/** Enable alternate key modes (cursors, numpad, fn) */
setAlts: function(cu, np, fn, crlf) {
if (opts.cu_alt != cu || opts.np_alt != np || opts.fn_alt != fn || opts.crlf_mode != crlf) {
opts.cu_alt = cu;
opts.np_alt = np;
opts.fn_alt = fn;
opts.crlf_mode = crlf;
/** Enable alternate key modes (cursors, numpad, fn) */
setAlts: function (cu, np, fn, crlf) {
if (opts.cu_alt != cu || opts.np_alt != np || opts.fn_alt != fn || opts.crlf_mode != crlf) {
opts.cu_alt = cu
opts.np_alt = np
opts.fn_alt = fn
opts.crlf_mode = crlf
// rebind keys - codes have changed
_bindFnKeys();
}
},
// rebind keys - codes have changed
_bindFnKeys()
}
},
setMouseMode: function(click, move) {
opts.mt_click = click;
opts.mt_move = move;
},
// Mouse events
onMouseMove: function (x, y) {
if (!opts.mt_move) return;
var b = mb1 ? 1 : mb2 ? 2 : mb3 ? 3 : 0;
var m = packModifiersForMouse();
Conn.send("m" + encode2B(y) + encode2B(x) + encode2B(b) + encode2B(m));
},
onMouseDown: function (x, y, b) {
if (!opts.mt_click) return;
if (b > 3 || b < 1) return;
var m = packModifiersForMouse();
Conn.send("p" + encode2B(y) + encode2B(x) + encode2B(b) + encode2B(m));
// console.log("B ",b," M ",m);
},
onMouseUp: function (x, y, b) {
if (!opts.mt_click) return;
if (b > 3 || b < 1) return;
var m = packModifiersForMouse();
Conn.send("r" + encode2B(y) + encode2B(x) + encode2B(b) + encode2B(m));
// console.log("B ",b," M ",m);
},
onMouseWheel: function (x, y, dir) {
if (!opts.mt_click) return;
// -1 ... btn 4 (away from user)
// +1 ... btn 5 (towards user)
var m = packModifiersForMouse();
var b = (dir < 0 ? 4 : 5);
Conn.send("p" + encode2B(y) + encode2B(x) + encode2B(b) + encode2B(m));
// console.log("B ",b," M ",m);
},
mouseTracksClicks: function() {
return opts.mt_click;
},
blockKeys: function(yes) {
opts.no_keys = yes;
}
};
})();
setMouseMode: function (click, move) {
opts.mt_click = click
opts.mt_move = move
},
// Mouse events
onMouseMove: function (x, y) {
if (!opts.mt_move) return
const b = mb1 ? 1 : mb2 ? 2 : mb3 ? 3 : 0;
const m = packModifiersForMouse()
Conn.send('m' + encode2B(y) + encode2B(x) + encode2B(b) + encode2B(m))
},
onMouseDown: function (x, y, b) {
if (!opts.mt_click) return
if (b > 3 || b < 1) return
const m = packModifiersForMouse()
Conn.send('p' + encode2B(y) + encode2B(x) + encode2B(b) + encode2B(m))
// console.log("B ",b," M ",m);
},
onMouseUp: function (x, y, b) {
if (!opts.mt_click) return
if (b > 3 || b < 1) return
const m = packModifiersForMouse()
Conn.send('r' + encode2B(y) + encode2B(x) + encode2B(b) + encode2B(m))
// console.log("B ",b," M ",m);
},
onMouseWheel: function (x, y, dir) {
if (!opts.mt_click) return
// -1 ... btn 4 (away from user)
// +1 ... btn 5 (towards user)
const m = packModifiersForMouse()
const b = (dir < 0 ? 4 : 5)
Conn.send('p' + encode2B(y) + encode2B(x) + encode2B(b) + encode2B(m))
// console.log("B ",b," M ",m);
},
mouseTracksClicks: function () {
return opts.mt_click
},
blockKeys: function (yes) {
opts.no_keys = yes
}
}
})()

File diff suppressed because it is too large Load Diff

@ -1,146 +1,146 @@
/** File upload utility */
var TermUpl = (function () {
var lines, // array of lines without newlines
window.TermUpl = (function () {
let lines, // array of lines without newlines
line_i, // current line index
fuTout, // timeout handle for line sending
send_delay_ms, // delay between lines (ms)
nl_str, // newline string to use
curLine, // current line (when using fuOil)
inline_pos; // Offset in line (for long lines)
inline_pos // Offset in line (for long lines)
// lines longer than this are split to chunks
// sending a super-ling string through the socket is not a good idea
var MAX_LINE_LEN = 128;
const MAX_LINE_LEN = 128
function fuOpen() {
fuStatus("Ready...");
Modal.show('#fu_modal', onClose);
$('#fu_form').toggleClass('busy', false);
Input.blockKeys(true);
function fuOpen () {
fuStatus('Ready...')
Modal.show('#fu_modal', onClose)
$('#fu_form').toggleClass('busy', false)
Input.blockKeys(true)
}
function onClose() {
console.log("Upload modal closed.");
clearTimeout(fuTout);
line_i = 0;
Input.blockKeys(false);
function onClose () {
console.log('Upload modal closed.')
clearTimeout(fuTout)
line_i = 0
Input.blockKeys(false)
}
function fuStatus(msg) {
qs('#fu_prog').textContent = msg;
function fuStatus (msg) {
qs('#fu_prog').textContent = msg
}
function fuSend() {
var v = qs('#fu_text').value;
function fuSend () {
let v = qs('#fu_text').value
if (!v.length) {
fuClose();
return;
fuClose()
return
}
lines = v.split('\n');
line_i = 0;
inline_pos = 0; // offset in line
send_delay_ms = qs('#fu_delay').value;
lines = v.split('\n')
line_i = 0
inline_pos = 0 // offset in line
send_delay_ms = qs('#fu_delay').value
// sanitize - 0 causes overflows
if (send_delay_ms < 0) {
send_delay_ms = 0;
qs('#fu_delay').value = send_delay_ms;
send_delay_ms = 0
qs('#fu_delay').value = send_delay_ms
}
nl_str = {
'CR': '\r',
'LF': '\n',
'CRLF': '\r\n',
}[qs('#fu_crlf').value];
'CRLF': '\r\n'
}[qs('#fu_crlf').value]
$('#fu_form').toggleClass('busy', true);
fuStatus("Starting...");
fuSendLine();
$('#fu_form').toggleClass('busy', true)
fuStatus('Starting...')
fuSendLine()
}
function fuSendLine() {
function fuSendLine () {
if (!$('#fu_modal').hasClass('visible')) {
// Modal is closed, cancel
return;
return
}
if (!Conn.canSend()) {
// postpone
fuTout = setTimeout(fuSendLine, 1);
return;
fuTout = setTimeout(fuSendLine, 1)
return
}
if (inline_pos == 0) {
curLine = lines[line_i++] + nl_str;
curLine = lines[line_i++] + nl_str
}
var chunk;
let chunk
if ((curLine.length - inline_pos) <= MAX_LINE_LEN) {
chunk = curLine.substr(inline_pos, MAX_LINE_LEN);
inline_pos = 0;
chunk = curLine.substr(inline_pos, MAX_LINE_LEN)
inline_pos = 0
} else {
chunk = curLine.substr(inline_pos, MAX_LINE_LEN);
inline_pos += MAX_LINE_LEN;
chunk = curLine.substr(inline_pos, MAX_LINE_LEN)
inline_pos += MAX_LINE_LEN
}
if (!Input.sendString(chunk)) {
fuStatus("FAILED!");
return;
fuStatus('FAILED!')
return
}
var all = lines.length;
let all = lines.length
fuStatus(line_i + " / " + all + " (" + (Math.round((line_i / all) * 1000) / 10) + "%)");
fuStatus(line_i + ' / ' + all + ' (' + (Math.round((line_i / all) * 1000) / 10) + '%)')
if (lines.length > line_i || inline_pos > 0) {
fuTout = setTimeout(fuSendLine, send_delay_ms);
fuTout = setTimeout(fuSendLine, send_delay_ms)
} else {
closeWhenReady();
closeWhenReady()
}
}
function closeWhenReady() {
function closeWhenReady () {
if (!Conn.canSend()) {
// stuck in XOFF still, wait to process...
fuStatus("Waiting for Tx buffer...");
setTimeout(closeWhenReady, 100);
fuStatus('Waiting for Tx buffer...')
setTimeout(closeWhenReady, 100)
} else {
fuStatus("Done.");
fuStatus('Done.')
// delay to show it
setTimeout(function () {
fuClose();
}, 100);
fuClose()
}, 100)
}
}
function fuClose() {
Modal.hide('#fu_modal');
function fuClose () {
Modal.hide('#fu_modal')
}
return {
init: function () {
qs('#fu_file').addEventListener('change', function (evt) {
var reader = new FileReader();
var file = evt.target.files[0];
console.log("Selected file type: " + file.type);
let reader = new FileReader()
let file = evt.target.files[0]
console.log('Selected file type: ' + file.type)
if (!file.type.match(/text\/.*|application\/(json|csv|.*xml.*|.*script.*)/)) {
// Deny load of blobs like img - can crash browser and will get corrupted anyway
if (!confirm("This does not look like a text file: " + file.type + "\nReally load?")) {
qs('#fu_file').value = '';
return;
if (!confirm('This does not look like a text file: ' + file.type + '\nReally load?')) {
qs('#fu_file').value = ''
return
}
}
reader.onload = function (e) {
var txt = e.target.result.replace(/[\r\n]+/, '\n');
qs('#fu_text').value = txt;
};
console.log("Loading file...");
reader.readAsText(file);
}, false);
const txt = e.target.result.replace(/[\r\n]+/, '\n')
qs('#fu_text').value = txt
}
console.log('Loading file...')
reader.readAsText(file)
}, false)
},
close: fuClose,
start: fuSend,
open: fuOpen,
open: fuOpen
}
})();
})()

@ -1,21 +1,21 @@
/** Make a node */
function mk(e) {
function mk (e) {
return document.createElement(e)
}
/** Find one by query */
function qs(s) {
function qs (s) {
return document.querySelector(s)
}
/** Find all by query */
function qsa(s) {
function qsa (s) {
return document.querySelectorAll(s)
}
/** Convert any to bool safely */
function bool(x) {
return (x === 1 || x === '1' || x === true || x === 'true');
function bool (x) {
return (x === 1 || x === '1' || x === true || x === 'true')
}
/**
@ -23,54 +23,54 @@ function bool(x) {
* and when they're pressed, fire the callback.
* use $(...).on('keypress', cr(handler))
*/
function cr(hdl) {
function cr (hdl) {
return function (e) {
if (e.which == 10 || e.which == 13 || e.which == 32) {
hdl();
hdl()
}
};
}
}
/** Extend an objects with options */
function extend(defaults, options) {
var target = {};
function extend (defaults, options) {
var target = {}
Object.keys(defaults).forEach(function (k) {
target[k] = defaults[k];
});
target[k] = defaults[k]
})
Object.keys(options).forEach(function (k) {
target[k] = options[k];
});
target[k] = options[k]
})
return target;
return target
}
/** Escape string for use as literal in RegExp */
function rgxe(str) {
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
function rgxe (str) {
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&')
}
/** Format number to N decimal places, output as string */
function numfmt(x, places) {
var pow = Math.pow(10, places);
return Math.round(x * pow) / pow;
function numfmt (x, places) {
var pow = Math.pow(10, places)
return Math.round(x * pow) / pow
}
/** Get millisecond timestamp */
function msNow() {
return +(new Date);
function msNow () {
return +(new Date())
}
/** Get ms elapsed since msNow() */
function msElapsed(start) {
return msNow() - start;
function msElapsed (start) {
return msNow() - start
}
/** Shim for log base 10 */
Math.log10 = Math.log10 || function (x) {
return Math.log(x) / Math.LN10;
};
return Math.log(x) / Math.LN10
}
/**
* Perform a substitution in the given string.
@ -84,84 +84,84 @@ Math.log10 = Math.log10 || function (x) {
* @returns {String} result
*/
String.prototype.format = function () {
var out = this;
var repl = arguments;
let out = this
let repl = arguments
if (arguments.length == 1 && (Array.isArray(arguments[0]) || typeof arguments[0] == 'object')) {
repl = arguments[0];
repl = arguments[0]
}
for (var ph in repl) {
for (let ph in repl) {
if (repl.hasOwnProperty(ph)) {
var ph_orig = ph;
const ph_orig = ph
if (!ph.match(/^\{.*\}$/)) {
ph = '{' + ph + '}';
ph = '{' + ph + '}'
}
// replace all occurrences
var pattern = new RegExp(rgxe(ph), "g");
out = out.replace(pattern, repl[ph_orig]);
const pattern = new RegExp(rgxe(ph), 'g')
out = out.replace(pattern, repl[ph_orig])
}
}
return out;
};
return out
}
/** HTML escape */
function e(str) {
return $.htmlEscape(str);
function e (str) {
return $.htmlEscape(str)
}
/** Check for undefined */
function undef(x) {
return typeof x == 'undefined';
function undef (x) {
return typeof x == 'undefined'
}
/** Safe json parse */
function jsp(str) {
function jsp (str) {
try {
return JSON.parse(str);
return JSON.parse(str)
} catch (e) {
console.error(e);
return null;
console.error(e)
return null
}
}
/** Create a character from ASCII code */
function Chr(n) {
return String.fromCharCode(n);
function Chr (n) {
return String.fromCharCode(n)
}
/** Decode number from 2B encoding */
function parse2B(s, i = 0) {
return (s.charCodeAt(i++) - 1) + (s.charCodeAt(i) - 1) * 127;
function parse2B (s, i = 0) {
return (s.charCodeAt(i++) - 1) + (s.charCodeAt(i) - 1) * 127
}
/** Decode number from 3B encoding */
function parse3B(s, i = 0) {
return (s.charCodeAt(i) - 1) + (s.charCodeAt(i + 1) - 1) * 127 + (s.charCodeAt(i + 2) - 1) * 127 * 127;
function parse3B (s, i = 0) {
return (s.charCodeAt(i) - 1) + (s.charCodeAt(i + 1) - 1) * 127 + (s.charCodeAt(i + 2) - 1) * 127 * 127
}
/** Encode using 2B encoding, returns string. */
function encode2B(n) {
var lsb, msb;
lsb = (n % 127);
n = ((n - lsb) / 127);
lsb += 1;
msb = (n + 1);
return Chr(lsb) + Chr(msb);
function encode2B (n) {
let lsb, msb
lsb = (n % 127)
n = ((n - lsb) / 127)
lsb += 1
msb = (n + 1)
return Chr(lsb) + Chr(msb)
}
/** Encode using 3B encoding, returns string. */
function encode3B(n) {
var lsb, msb, xsb;
lsb = (n % 127);
n = (n - lsb) / 127;
lsb += 1;
msb = (n % 127);
n = (n - msb) / 127;
msb += 1;
xsb = (n + 1);
return Chr(lsb) + Chr(msb) + Chr(xsb);
function encode3B (n) {
let lsb, msb, xsb
lsb = (n % 127)
n = (n - lsb) / 127
lsb += 1
msb = (n % 127)
n = (n - msb) / 127
msb += 1
xsb = (n + 1)
return Chr(lsb) + Chr(msb) + Chr(xsb)
}

@ -1,163 +1,162 @@
(function (w) {
var authStr = ['Open', 'WEP', 'WPA', 'WPA2', 'WPA/WPA2'];
var curSSID;
const authStr = ['Open', 'WEP', 'WPA', 'WPA2', 'WPA/WPA2']
let curSSID
// Get XX % for a slider input
function rangePt(inp) {
return Math.round(((inp.value / inp.max) * 100)) + '%';
function rangePt (inp) {
return Math.round(((inp.value / inp.max) * 100)) + '%'
}
// Display selected STA SSID etc
function selectSta(name, password, ip) {
$('#sta_ssid').val(name);
$('#sta_password').val(password);
$('#sta-nw').toggleClass('hidden', name.length == 0);
$('#sta-nw-nil').toggleClass('hidden', name.length > 0);
$('#sta-nw .essid').html(e(name));
var nopw = undef(password) || password.length == 0;
$('#sta-nw .passwd').toggleClass('hidden', nopw);
$('#sta-nw .nopasswd').toggleClass('hidden', !nopw);
$('#sta-nw .ip').html(ip.length > 0 ? tr('wifi.connected_ip_is') + ip : tr('wifi.not_conn'));
function selectSta (name, password, ip) {
$('#sta_ssid').val(name)
$('#sta_password').val(password)
$('#sta-nw').toggleClass('hidden', name.length == 0)
$('#sta-nw-nil').toggleClass('hidden', name.length > 0)
$('#sta-nw .essid').html(e(name))
const nopw = undef(password) || password.length == 0
$('#sta-nw .passwd').toggleClass('hidden', nopw)
$('#sta-nw .nopasswd').toggleClass('hidden', !nopw)
$('#sta-nw .ip').html(ip.length > 0 ? tr('wifi.connected_ip_is') + ip : tr('wifi.not_conn'))
}
/** Update display for received response */
function onScan(resp, status) {
//var ap_json = {
// "result": {
// "inProgress": "0",
// "APs": [
// {"essid": "Chlivek", "bssid": "88:f7:c7:52:b3:99", "rssi": "204", "enc": "4", "channel": "1"},
// {"essid": "TyNikdy", "bssid": "5c:f4:ab:0d:f1:1b", "rssi": "164", "enc": "3", "channel": "1"},
// ]
// }
//};
function onScan (resp, status) {
// var ap_json = {
// "result": {
// "inProgress": "0",
// "APs": [
// {"essid": "Chlivek", "bssid": "88:f7:c7:52:b3:99", "rssi": "204", "enc": "4", "channel": "1"},
// {"essid": "TyNikdy", "bssid": "5c:f4:ab:0d:f1:1b", "rssi": "164", "enc": "3", "channel": "1"},
// ]
// }
// };
if (status != 200) {
// bad response
rescan(5000); // wait 5sm then retry
return;
rescan(5000) // wait 5sm then retry
return
}
try {
resp = JSON.parse(resp);
resp = JSON.parse(resp)
} catch (e) {
console.log(e);
rescan(5000);
return;
console.log(e)
rescan(5000)
return
}
var done = !bool(resp.result.inProgress) && (resp.result.APs.length > 0);
rescan(done ? 15000 : 1000);
if (!done) return; // no redraw yet
const done = !bool(resp.result.inProgress) && (resp.result.APs.length > 0)
rescan(done ? 15000 : 1000)
if (!done) return // no redraw yet
// clear the AP list
var $list = $('#ap-list');
let $list = $('#ap-list')
// remove old APs
$('#ap-list .AP').remove();
$('#ap-list .AP').remove()
$list.toggleClass('hidden', !done);
$('#ap-loader').toggleClass('hidden', done);
$list.toggleClass('hidden', !done)
$('#ap-loader').toggleClass('hidden', done)
// scan done
resp.result.APs.sort(function (a, b) {
return b.rssi - a.rssi;
return b.rssi - a.rssi
}).forEach(function (ap) {
ap.enc = parseInt(ap.enc);
ap.enc = parseInt(ap.enc)
if (ap.enc > 4) return; // hide unsupported auths
if (ap.enc > 4) return // hide unsupported auths
var item = mk('div');
let item = mk('div')
var $item = $(item)
let $item = $(item)
.data('ssid', ap.essid)
.data('pwd', ap.enc)
.attr('tabindex', 0)
.addClass('AP');
.addClass('AP')
// mark current SSID
if (ap.essid == curSSID) {
$item.addClass('selected');
$item.addClass('selected')
}
var inner = mk('div');
let inner = mk('div')
$(inner).addClass('inner')
.htmlAppend('<div class="rssi">{0}</div>'.format(ap.rssi_perc))
.htmlAppend('<div class="essid" title="{0}">{0}</div>'.format($.htmlEscape(ap.essid)))
.htmlAppend('<div class="auth">{0}</div>'.format(authStr[ap.enc]));
.htmlAppend('<div class="auth">{0}</div>'.format(authStr[ap.enc]))
$item.on('click', function () {
var $th = $(this);
let $th = $(this)
var conn_ssid = $th.data('ssid');
var conn_pass = '';
const conn_ssid = $th.data('ssid')
let conn_pass = ''
if (+$th.data('pwd')) {
// this AP needs a password
conn_pass = prompt(tr("wifi.enter_passwd").replace(":ssid:", conn_ssid));
if (!conn_pass) return;
conn_pass = prompt(tr('wifi.enter_passwd').replace(':ssid:', conn_ssid))
if (!conn_pass) return
}
$('#sta_password').val(conn_pass);
$('#sta_ssid').val(conn_ssid);
selectSta(conn_ssid, conn_pass, '');
});
$('#sta_password').val(conn_pass)
$('#sta_ssid').val(conn_ssid)
selectSta(conn_ssid, conn_pass, '')
})
item.appendChild(inner);
$list[0].appendChild(item);
});
item.appendChild(inner)
$list[0].appendChild(item)
})
}
function startScanning() {
$('#ap-loader').removeClass('hidden');
$('#ap-scan').addClass('hidden');
$('#ap-loader .anim-dots').html('.');
function startScanning () {
$('#ap-loader').removeClass('hidden')
$('#ap-scan').addClass('hidden')
$('#ap-loader .anim-dots').html('.')
scanAPs();
scanAPs()
}
/** Ask the CGI what APs are visible (async) */
function scanAPs() {
function scanAPs () {
if (_demo) {
onScan(_demo_aps, 200);
onScan(_demo_aps, 200)
} else {
$.get('http://' + _root + '/cfg/wifi/scan', onScan);
$.get('http://' + _root + '/cfg/wifi/scan', onScan)
}
}
function rescan(time) {
setTimeout(scanAPs, time);
function rescan (time) {
setTimeout(scanAPs, time)
}
/** Set up the WiFi page */
function wifiInit(cfg) {
function wifiInit (cfg) {
// Update slider value displays
$('.Row.range').forEach(function (x) {
var inp = x.querySelector('input');
var disp1 = x.querySelector('.x-disp1');
var disp2 = x.querySelector('.x-disp2');
var t = rangePt(inp);
$(disp1).html(t);
$(disp2).html(t);
let inp = x.querySelector('input')
let disp1 = x.querySelector('.x-disp1')
let disp2 = x.querySelector('.x-disp2')
let t = rangePt(inp)
$(disp1).html(t)
$(disp2).html(t)
$(inp).on('input', function () {
t = rangePt(inp);
$(disp1).html(t);
$(disp2).html(t);
});
});
t = rangePt(inp)
$(disp1).html(t)
$(disp2).html(t)
})
})
// Forget STA credentials
$('#forget-sta').on('click', function () {
selectSta('', '', '');
return false;
});
selectSta('', '', '')
return false
})
selectSta(cfg.sta_ssid, cfg.sta_password, cfg.sta_active_ip);
curSSID = cfg.sta_active_ssid;
selectSta(cfg.sta_ssid, cfg.sta_password, cfg.sta_active_ip)
curSSID = cfg.sta_active_ssid
}
w.init = wifiInit;
w.startScanning = startScanning;
})(window.WiFi = {});
w.init = wifiInit
w.startScanning = startScanning
})(window.WiFi = {})

@ -1,3 +1,4 @@
<?php if (!DEBUG): ?>
<script>
// Workaround for badly loaded page
setTimeout(function() {
@ -7,6 +8,7 @@
}
}, 3000);
</script>
<?php endif; ?>
<div class="Modal light hidden" id="fu_modal">
<div id="fu_form" class="Dialog">
@ -74,9 +76,11 @@
Screen.load('%j:labels_seq%');
} catch(e) {
console.error(e);
<?php if (!DEBUG): ?>
console.error("Fail, reloading in 3s…");
setTimeout(function() {
location.reload(true);
}, 3000);
<?php endif; ?>
}
</script>

Loading…
Cancel
Save