eslint all the things

cpsdqs/unified-input
Ondřej Hruška 7 years ago
parent 7e1611ff7a
commit 79664f56a6
  1. 10
      .eslintrc
  2. 34
      build.sh
  3. 0
      compile_html.php
  4. 5
      dump_js_lang.php
  5. 195
      jssrc/appcommon.js
  6. 4
      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. 203
      jssrc/term_input.js
  17. 891
      jssrc/term_screen.js
  18. 138
      jssrc/term_upload.js
  19. 134
      jssrc/utils.js
  20. 167
      jssrc/wifi.js
  21. 4
      pages/term.php

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

@ -1,25 +1,29 @@
#!/bin/bash #!/bin/bash
echo "Packing JS..." echo 'Packing JS...'
cat jssrc/chibi.js \ echo ';' > ';'
jssrc/keymaster.js \ cat jssrc/lib/chibi.js ';' \
jssrc/utils.js \ jssrc/lib/keymaster.js ';' \
jssrc/modal.js \ jssrc/lib/polyfills.js ';' \
jssrc/notif.js \ jssrc/utils.js ';' \
jssrc/appcommon.js \ jssrc/modal.js ';' \
jssrc/lang.js \ jssrc/notif.js ';' \
jssrc/wifi.js \ jssrc/appcommon.js ';' \
jssrc/term_* \ jssrc/lang.js ';' \
jssrc/term.js \ jssrc/wifi.js ';' \
jssrc/term_* ';' \
jssrc/term.js ';' \
jssrc/soft_keyboard.js | npm run --silent minify > js/app.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 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.connected_ip_is',
'wifi.not_conn', 'wifi.not_conn',
'wifi.enter_passwd', 'wifi.enter_passwd',
'wifi.passwd_saved',
]; ];
$out = []; $out = [];
@ -18,6 +17,6 @@ foreach ($selected as $key) {
file_put_contents(__DIR__. '/jssrc/lang.js', file_put_contents(__DIR__. '/jssrc/lang.js',
"// Generated from PHP locale file\n" . "// Generated from PHP locale file\n" .
'var _tr = ' . json_encode($out, JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE) . ";\n\n" . 'let _tr = ' . json_encode($out, JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE) . ";\n\n" .
"function tr(key) { return _tr[key] || '?'+key+'?'; }\n" "function tr (key) { return _tr[key] || '?' + key + '?' }\n"
); );

@ -2,189 +2,124 @@
$.ready(function () { $.ready(function () {
// Checkbox UI (checkbox CSS and hidden input with int value) // Checkbox UI (checkbox CSS and hidden input with int value)
$('.Row.checkbox').forEach(function (x) { $('.Row.checkbox').forEach(function (x) {
var inp = x.querySelector('input'); let inp = x.querySelector('input')
var box = x.querySelector('.box'); let box = x.querySelector('.box')
$(box).toggleClass('checked', inp.value); $(box).toggleClass('checked', inp.value)
var hdl = function () { let hdl = function () {
inp.value = 1 - inp.value; inp.value = 1 - inp.value
$(box).toggleClass('checked', 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 // Expanding boxes on mobile
$('.Box.mobcol,.Box.fold').forEach(function (x) { $('.Box.mobcol,.Box.fold').forEach(function (x) {
var h = x.querySelector('h2'); let h = x.querySelector('h2')
var hdl = function () { let hdl = function () {
$(x).toggleClass('expanded'); $(x).toggleClass('expanded')
}; }
$(h).on('click', hdl).on('keypress', cr(hdl)); $(h).on('click', hdl).on('keypress', cr(hdl))
}); })
$('form').forEach(function (x) { $('form').forEach(function (x) {
$(x).on('keypress', function (e) { $(x).on('keypress', function (e) {
if ((e.keyCode == 10 || e.keyCode == 13) && e.ctrlKey) { if ((e.keyCode == 10 || e.keyCode == 13) && e.ctrlKey) {
x.submit(); x.submit()
} }
}) })
}); })
// loader dots... // loader dots...
setInterval(function () { setInterval(function () {
$('.anim-dots').each(function (x) { $('.anim-dots').each(function (x) {
var $x = $(x); let $x = $(x)
var dots = $x.html() + '.'; let dots = $x.html() + '.'
if (dots.length == 5) dots = '.'; if (dots.length == 5) dots = '.'
$x.html(dots); $x.html(dots)
}); })
}, 1000); }, 1000)
// flipping number boxes with the mouse wheel // flipping number boxes with the mouse wheel
$('input[type=number]').on('mousewheel', function (e) { $('input[type=number]').on('mousewheel', function (e) {
var $this = $(this); let $this = $(this)
var val = +$this.val(); let val = +$this.val()
if (isNaN(val)) val = 1; if (isNaN(val)) val = 1
var step = +($this.attr('step') || 1); const step = +($this.attr('step') || 1)
var min = +$this.attr('min'); const min = +$this.attr('min')
var max = +$this.attr('max'); const max = +$this.attr('max')
if (e.wheelDelta > 0) { if (e.wheelDelta > 0) {
val += step; val += step
} else { } else {
val -= step; val -= step
} }
if (typeof min != 'undefined') val = Math.max(val, +min); if (typeof min != 'undefined') val = Math.max(val, +min)
if (typeof max != 'undefined') val = Math.min(val, +max); if (typeof max != 'undefined') val = Math.min(val, +max)
$this.val(val); $this.val(val)
if ("createEvent" in document) { if ('createEvent' in document) {
var evt = document.createEvent("HTMLEvents"); let evt = document.createEvent('HTMLEvents')
evt.initEvent("change", false, true); evt.initEvent('change', false, true)
$this[0].dispatchEvent(evt); $this[0].dispatchEvent(evt)
} else { } 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')) { if (errAt !== -1 && qs('.Box.errors')) {
var errs = location.search.substr(errAt + 4).split(','); let errs = location.search.substr(errAt + 4).split(',')
var hres = []; let hres = []
errs.forEach(function (er) { errs.forEach(function (er) {
var lbl = qs('label[for="' + er + '"]'); let lbl = qs('label[for="' + er + '"]')
if (lbl) { if (lbl) {
lbl.classList.add('error'); lbl.classList.add('error')
hres.push(lbl.childNodes[0].textContent.trim().replace(/: ?$/, '')); hres.push(lbl.childNodes[0].textContent.trim().replace(/: ?$/, ''))
} else { } else {
hres.push(er); hres.push(er)
} }
}); })
qs('.Box.errors .list').innerHTML = hres.join(', '); qs('.Box.errors .list').innerHTML = hres.join(', ')
qs('.Box.errors').classList.remove('hidden'); qs('.Box.errors').classList.remove('hidden')
} }
Modal.init(); Modal.init()
Notify.init(); Notify.init()
// remove tabindixes from h2 if wide // remove tabindixes from h2 if wide
if (window.innerWidth > 550) { if (window.innerWidth > 550) {
$('.Box h2').forEach(function (x) { $('.Box h2').forEach(function (x) {
x.removeAttribute('tabindex'); x.removeAttribute('tabindex')
}); })
// brand works as a link back to term in widescreen mode // brand works as a link back to term in widescreen mode
var br = qs('#brand'); let br = qs('#brand')
br && br.addEventListener('click', function () { br && br.addEventListener('click', function () {
location.href = '/'; // go to terminal location.href = '/' // go to terminal
}); })
} }
}); })
$._loader = function (vis) { $._loader = function (vis) {
$('#loader').toggleClass('show', vis); $('#loader').toggleClass('show', vis)
}; }
function showPage() { function showPage () {
$('#content').addClass('load'); $('#content').addClass('load')
} }
$.ready(function () { $.ready(function () {
if (window.noAutoShow !== true) { if (window.noAutoShow !== true) {
setTimeout(function () { setTimeout(function () {
showPage(); showPage()
}, 1); }, 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 // Generated from PHP locale file
var _tr = { let _tr = {
"wifi.connected_ip_is": "Connected, IP is ", "wifi.connected_ip_is": "Connected, IP is ",
"wifi.not_conn": "Not connected.", "wifi.not_conn": "Not connected.",
"wifi.enter_passwd": "Enter password for \":ssid:\"" "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 */ /** Module for toggling a modal overlay */
(function () { (function () {
var modal = {}; let modal = {}
var curCloseCb = null; let curCloseCb = null
modal.show = function (sel, closeCb) { modal.show = function (sel, closeCb) {
var $m = $(sel); let $m = $(sel)
$m.removeClass('hidden visible'); $m.removeClass('hidden visible')
setTimeout(function () { setTimeout(function () {
$m.addClass('visible'); $m.addClass('visible')
}, 1); }, 1)
curCloseCb = closeCb; curCloseCb = closeCb
}; }
modal.hide = function (sel) { modal.hide = function (sel) {
var $m = $(sel); let $m = $(sel)
$m.removeClass('visible'); $m.removeClass('visible')
setTimeout(function () { setTimeout(function () {
$m.addClass('hidden'); $m.addClass('hidden')
if (curCloseCb) curCloseCb(); if (curCloseCb) curCloseCb()
}, 500); // transition time }, 500) // transition time
}; }
modal.init = function () { modal.init = function () {
// close modal by click outside the dialog // close modal by click outside the dialog
$('.Modal').on('click', function () { $('.Modal').on('click', function () {
if ($(this).hasClass('no-close')) return; // this is a no-close modal if ($(this).hasClass('no-close')) return // this is a no-close modal
modal.hide(this); modal.hide(this)
}); })
$('.Dialog').on('click', function (e) { $('.Dialog').on('click', function (e) {
e.stopImmediatePropagation(); e.stopImmediatePropagation()
}); })
// Hide all modals on esc // Hide all modals on esc
$(window).on('keydown', function (e) { $(window).on('keydown', function (e) {
if (e.which == 27) { if (e.which == 27) {
modal.hide('.Modal'); modal.hide('.Modal')
}
})
} }
});
};
window.Modal = modal; window.Modal = modal
})(); })()

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

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

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

@ -14,44 +14,44 @@
* r - mb release * r - mb release
* m - mouse move * m - mouse move
*/ */
var Input = (function() { window.Input = (function () {
var opts = { let opts = {
np_alt: false, np_alt: false,
cu_alt: false, cu_alt: false,
fn_alt: false, fn_alt: false,
mt_click: false, mt_click: false,
mt_move: false, mt_move: false,
no_keys: false, no_keys: false,
crlf_mode: false, crlf_mode: false
}; }
/** Send a literal message */ /** Send a literal message */
function sendStrMsg(str) { function sendStrMsg (str) {
return Conn.send("s"+str); return Conn.send('s' + str)
} }
/** Send a button event */ /** Send a button event */
function sendBtnMsg(n) { function sendBtnMsg (n) {
Conn.send("b"+Chr(n)); Conn.send('b' + Chr(n))
} }
/** Fn alt choice for key message */ /** Fn alt choice for key message */
function fa(alt, normal) { function fa (alt, normal) {
return opts.fn_alt ? alt : normal; return opts.fn_alt ? alt : normal
} }
/** Cursor alt choice for key message */ /** Cursor alt choice for key message */
function ca(alt, normal) { function ca (alt, normal) {
return opts.cu_alt ? alt : normal; return opts.cu_alt ? alt : normal
} }
/** Numpad alt choice for key message */ /** Numpad alt choice for key message */
function na(alt, normal) { function na (alt, normal) {
return opts.np_alt ? alt : normal; return opts.np_alt ? alt : normal
} }
function _bindFnKeys() { function _bindFnKeys () {
var keymap = { const keymap = {
'tab': '\x09', 'tab': '\x09',
'backspace': '\x08', 'backspace': '\x08',
'enter': opts.crlf_mode ? '\x0d\x0a' : '\x0d', 'enter': opts.crlf_mode ? '\x0d\x0a' : '\x0d',
@ -105,99 +105,99 @@ var Input = (function() {
'np_add': na('\x1bOl', '+'), 'np_add': na('\x1bOl', '+'),
'np_sub': na('\x1bOS', '-'), 'np_sub': na('\x1bOS', '-'),
'np_point': na('\x1bOn', '.'), 'np_point': na('\x1bOn', '.'),
'np_div': na('\x1bOQ', '/'), '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) // 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) { for (let k in keymap) {
if (keymap.hasOwnProperty(k)) { if (keymap.hasOwnProperty(k)) {
bind(k, keymap[k]); bind(k, keymap[k])
} }
} }
} }
/** Bind a keystroke to message */ /** Bind a keystroke to message */
function bind(combo, str) { function bind (combo, str) {
// mac fix - allow also cmd // mac fix - allow also cmd
if (combo.indexOf('ctrl+') !== -1) { if (combo.indexOf('ctrl+') !== -1) {
combo += ',' + combo.replace('ctrl', 'command'); combo += ',' + combo.replace('ctrl', 'command')
} }
// unbind possible old binding // unbind possible old binding
key.unbind(combo); key.unbind(combo)
key(combo, function (e) { key(combo, function (e) {
if (opts.no_keys) return; if (opts.no_keys) return
e.preventDefault(); e.preventDefault()
sendStrMsg(str) sendStrMsg(str)
}); })
} }
/** Bind/rebind key messages */ /** Bind/rebind key messages */
function _initKeys() { function _initKeys () {
// This takes care of text characters typed // This takes care of text characters typed
window.addEventListener('keypress', function(evt) { window.addEventListener('keypress', function (evt) {
if (opts.no_keys) return; if (opts.no_keys) return
var str = ''; let str = ''
if (evt.key) str = evt.key; if (evt.key) str = evt.key
else if (evt.which) str = String.fromCodePoint(evt.which); else if (evt.which) str = String.fromCodePoint(evt.which)
if (str.length>0 && str.charCodeAt(0) >= 32) { if (str.length > 0 && str.charCodeAt(0) >= 32) {
// console.log("Typed ", str); // console.log("Typed ", str);
// prevent space from scrolling // prevent space from scrolling
if (evt.which === 32) evt.preventDefault(); if (evt.which === 32) evt.preventDefault()
sendStrMsg(str); sendStrMsg(str)
} }
}); })
// ctrl-letter codes are sent as simple low ASCII codes // ctrl-letter codes are sent as simple low ASCII codes
for (var i = 1; i<=26;i++) { for (let i = 1; i <= 26; i++) {
bind('ctrl+' + String.fromCharCode(96+i), String.fromCharCode(i)); bind('ctrl+' + String.fromCharCode(96 + i), String.fromCharCode(i))
} }
bind('ctrl+]', '\x1b'); // alternate way to enter ESC bind('ctrl+]', '\x1b') // alternate way to enter ESC
bind('ctrl+\\', '\x1c'); bind('ctrl+\\', '\x1c')
bind('ctrl+[', '\x1d'); bind('ctrl+[', '\x1d')
bind('ctrl+^', '\x1e'); bind('ctrl+^', '\x1e')
bind('ctrl+_', '\x1f'); bind('ctrl+_', '\x1f')
_bindFnKeys(); _bindFnKeys()
} }
// mouse button states // mouse button states
var mb1 = 0; let mb1 = 0
var mb2 = 0; let mb2 = 0
var mb3 = 0; let mb3 = 0
/** Init the Input module */ /** Init the Input module */
function init() { function init () {
_initKeys(); _initKeys()
// Button presses // Button presses
$('#action-buttons button').forEach(function(s) { $('#action-buttons button').forEach(function (s) {
s.addEventListener('click', function() { s.addEventListener('click', function () {
sendBtnMsg(+this.dataset['n']); sendBtnMsg(+this.dataset['n'])
}); })
}); })
// global mouse state tracking - for motion reporting // global mouse state tracking - for motion reporting
window.addEventListener('mousedown', function(evt) { window.addEventListener('mousedown', function (evt) {
if (evt.button == 0) mb1 = 1; if (evt.button == 0) mb1 = 1
if (evt.button == 1) mb2 = 1; if (evt.button == 1) mb2 = 1
if (evt.button == 2) mb3 = 1; if (evt.button == 2) mb3 = 1
}); })
window.addEventListener('mouseup', function(evt) { window.addEventListener('mouseup', function (evt) {
if (evt.button == 0) mb1 = 0; if (evt.button == 0) mb1 = 0
if (evt.button == 1) mb2 = 0; if (evt.button == 1) mb2 = 0
if (evt.button == 2) mb3 = 0; if (evt.button == 2) mb3 = 0
}); })
} }
/** Prepare modifiers byte for mouse message */ /** Prepare modifiers byte for mouse message */
function packModifiersForMouse() { function packModifiersForMouse () {
return (key.isModifier('ctrl')?1:0) | return (key.isModifier('ctrl') ? 1 : 0) |
(key.isModifier('shift')?2:0) | (key.isModifier('shift') ? 2 : 0) |
(key.isModifier('alt')?4:0) | (key.isModifier('alt') ? 4 : 0) |
(key.isModifier('meta')?8:0); (key.isModifier('meta') ? 8 : 0)
} }
return { return {
@ -208,59 +208,58 @@ var Input = (function() {
sendString: sendStrMsg, sendString: sendStrMsg,
/** Enable alternate key modes (cursors, numpad, fn) */ /** Enable alternate key modes (cursors, numpad, fn) */
setAlts: function(cu, np, fn, crlf) { setAlts: function (cu, np, fn, crlf) {
if (opts.cu_alt != cu || opts.np_alt != np || opts.fn_alt != fn || opts.crlf_mode != crlf) { if (opts.cu_alt != cu || opts.np_alt != np || opts.fn_alt != fn || opts.crlf_mode != crlf) {
opts.cu_alt = cu; opts.cu_alt = cu
opts.np_alt = np; opts.np_alt = np
opts.fn_alt = fn; opts.fn_alt = fn
opts.crlf_mode = crlf; opts.crlf_mode = crlf
// rebind keys - codes have changed // rebind keys - codes have changed
_bindFnKeys(); _bindFnKeys()
} }
}, },
setMouseMode: function(click, move) { setMouseMode: function (click, move) {
opts.mt_click = click; opts.mt_click = click
opts.mt_move = move; opts.mt_move = move
}, },
// Mouse events // Mouse events
onMouseMove: function (x, y) { onMouseMove: function (x, y) {
if (!opts.mt_move) return; if (!opts.mt_move) return
var b = mb1 ? 1 : mb2 ? 2 : mb3 ? 3 : 0; const b = mb1 ? 1 : mb2 ? 2 : mb3 ? 3 : 0;
var m = packModifiersForMouse(); const m = packModifiersForMouse()
Conn.send("m" + encode2B(y) + encode2B(x) + encode2B(b) + encode2B(m)); Conn.send('m' + encode2B(y) + encode2B(x) + encode2B(b) + encode2B(m))
}, },
onMouseDown: function (x, y, b) { onMouseDown: function (x, y, b) {
if (!opts.mt_click) return; if (!opts.mt_click) return
if (b > 3 || b < 1) return; if (b > 3 || b < 1) return
var m = packModifiersForMouse(); const m = packModifiersForMouse()
Conn.send("p" + encode2B(y) + encode2B(x) + encode2B(b) + encode2B(m)); Conn.send('p' + encode2B(y) + encode2B(x) + encode2B(b) + encode2B(m))
// console.log("B ",b," M ",m); // console.log("B ",b," M ",m);
}, },
onMouseUp: function (x, y, b) { onMouseUp: function (x, y, b) {
if (!opts.mt_click) return; if (!opts.mt_click) return
if (b > 3 || b < 1) return; if (b > 3 || b < 1) return
var m = packModifiersForMouse(); const m = packModifiersForMouse()
Conn.send("r" + encode2B(y) + encode2B(x) + encode2B(b) + encode2B(m)); Conn.send('r' + encode2B(y) + encode2B(x) + encode2B(b) + encode2B(m))
// console.log("B ",b," M ",m); // console.log("B ",b," M ",m);
}, },
onMouseWheel: function (x, y, dir) { onMouseWheel: function (x, y, dir) {
if (!opts.mt_click) return; if (!opts.mt_click) return
// -1 ... btn 4 (away from user) // -1 ... btn 4 (away from user)
// +1 ... btn 5 (towards user) // +1 ... btn 5 (towards user)
var m = packModifiersForMouse(); const m = packModifiersForMouse()
var b = (dir < 0 ? 4 : 5); const b = (dir < 0 ? 4 : 5)
Conn.send("p" + encode2B(y) + encode2B(x) + encode2B(b) + encode2B(m)); Conn.send('p' + encode2B(y) + encode2B(x) + encode2B(b) + encode2B(m))
// console.log("B ",b," M ",m); // console.log("B ",b," M ",m);
}, },
mouseTracksClicks: function() { mouseTracksClicks: function () {
return opts.mt_click; return opts.mt_click
}, },
blockKeys: function(yes) { blockKeys: function (yes) {
opts.no_keys = yes; opts.no_keys = yes
} }
}; }
})(); })()

File diff suppressed because it is too large Load Diff

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

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

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

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

Loading…
Cancel
Save