From 036a58ce125de8e2c2d26d5cd4b00d7c57ba6fac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sun, 10 Sep 2017 00:41:04 +0200 Subject: [PATCH] updated to latest backend, cursor variants setting, reformat some files --- jssrc/appcommon.js | 349 +++++++++++++++++++++-------------------- jssrc/lang.js | 6 +- jssrc/modal.js | 70 ++++----- jssrc/notif.js | 46 +++--- jssrc/soft_keyboard.js | 40 ++--- jssrc/term_input.js | 8 +- jssrc/term_screen.js | 122 ++++++++------ jssrc/term_upload.js | 288 +++++++++++++++++----------------- jssrc/utils.js | 144 +++++++++-------- jssrc/wifi.js | 324 +++++++++++++++++++------------------- lang/en.php | 9 ++ pages/cfg_term.php | 19 +++ 12 files changed, 741 insertions(+), 684 deletions(-) diff --git a/jssrc/appcommon.js b/jssrc/appcommon.js index 6b1fad6..b5d09d5 100644 --- a/jssrc/appcommon.js +++ b/jssrc/appcommon.js @@ -1,189 +1,190 @@ /** Global generic init */ $.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'); - - $(box).toggleClass('checked', inp.value); - - var hdl = function() { - inp.value = 1 - inp.value; - $(box).toggleClass('checked', inp.value) - }; - - $(x).on('click', hdl).on('keypress', cr(hdl)); - }); - - // Expanding boxes on mobile - $('.Box.mobcol,.Box.fold').forEach(function(x) { - var h = x.querySelector('h2'); - - var 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(); - } - }) - }); - - // 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); - - // 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; - - var step = +($this.attr('step') || 1); - var min = +$this.attr('min'); - var max = +$this.attr('max'); - if(e.wheelDelta > 0) { - val += step; - } else { - val -= step; - } - - 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); - } else { - $this[0].fireEvent("onchange"); - } - - e.preventDefault(); - }); - - var errAt = location.search.indexOf('err='); - if (errAt !== -1 && qs('.Box.errors')) { - var errs = location.search.substr(errAt+4).split(','); - var hres = []; - errs.forEach(function(er) { - var lbl = qs('label[for="'+er+'"]'); - if (lbl) { - lbl.classList.add('error'); - hres.push(lbl.childNodes[0].textContent.trim().replace(/: ?$/, '')); - } else { - hres.push(er); - } - }); - - qs('.Box.errors .list').innerHTML = hres.join(', '); - qs('.Box.errors').classList.remove('hidden'); - } - - Modal.init(); - Notify.init(); - - // remove tabindixes from h2 if wide - if (window.innerWidth > 550) { - $('.Box h2').forEach(function (x) { - x.removeAttribute('tabindex'); - }); - - // brand works as a link back to term in widescreen mode - var br = qs('#brand'); - br && br.addEventListener('click', function() { - location.href='/'; // go to terminal - }); - } + // 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'); + + $(box).toggleClass('checked', inp.value); + + var hdl = function () { + inp.value = 1 - inp.value; + $(box).toggleClass('checked', inp.value) + }; + + $(x).on('click', hdl).on('keypress', cr(hdl)); + }); + + // Expanding boxes on mobile + $('.Box.mobcol,.Box.fold').forEach(function (x) { + var h = x.querySelector('h2'); + + var 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(); + } + }) + }); + + // 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); + + // 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; + + var step = +($this.attr('step') || 1); + var min = +$this.attr('min'); + var max = +$this.attr('max'); + if (e.wheelDelta > 0) { + val += step; + } else { + val -= step; + } + + 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); + } else { + $this[0].fireEvent("onchange"); + } + + e.preventDefault(); + }); + + var errAt = location.search.indexOf('err='); + if (errAt !== -1 && qs('.Box.errors')) { + var errs = location.search.substr(errAt + 4).split(','); + var hres = []; + errs.forEach(function (er) { + var lbl = qs('label[for="' + er + '"]'); + if (lbl) { + lbl.classList.add('error'); + hres.push(lbl.childNodes[0].textContent.trim().replace(/: ?$/, '')); + } else { + hres.push(er); + } + }); + + qs('.Box.errors .list').innerHTML = hres.join(', '); + qs('.Box.errors').classList.remove('hidden'); + } + + Modal.init(); + Notify.init(); + + // remove tabindixes from h2 if wide + if (window.innerWidth > 550) { + $('.Box h2').forEach(function (x) { + x.removeAttribute('tabindex'); + }); + + // brand works as a link back to term in widescreen mode + var br = qs('#brand'); + br && br.addEventListener('click', function () { + location.href = '/'; // go to terminal + }); + } }); -$._loader = function(vis) { - $('#loader').toggleClass('show', vis); +$._loader = function (vis) { + $('#loader').toggleClass('show', vis); }; function showPage() { - $('#content').addClass('load'); + $('#content').addClass('load'); } -$.ready(function() { - if (window.noAutoShow !== true) { - setTimeout(function () { - showPage(); - }, 1); - } +$.ready(function () { + if (window.noAutoShow !== true) { + setTimeout(function () { + 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; - } - }()); + (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; + } + }()); } diff --git a/jssrc/lang.js b/jssrc/lang.js index 327dae9..866025c 100644 --- a/jssrc/lang.js +++ b/jssrc/lang.js @@ -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:\"" + "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+'?'; } diff --git a/jssrc/modal.js b/jssrc/modal.js index ce623cd..d012ef1 100644 --- a/jssrc/modal.js +++ b/jssrc/modal.js @@ -1,44 +1,44 @@ /** Module for toggling a modal overlay */ (function () { - var modal = {}; - var curCloseCb = null; + var modal = {}; + var curCloseCb = null; - modal.show = function (sel, closeCb) { - var $m = $(sel); - $m.removeClass('hidden visible'); - setTimeout(function () { - $m.addClass('visible'); - }, 1); - curCloseCb = closeCb; - }; + modal.show = function (sel, closeCb) { + var $m = $(sel); + $m.removeClass('hidden visible'); + setTimeout(function () { + $m.addClass('visible'); + }, 1); + curCloseCb = closeCb; + }; - modal.hide = function (sel) { - var $m = $(sel); - $m.removeClass('visible'); - setTimeout(function () { - $m.addClass('hidden'); - if (curCloseCb) curCloseCb(); - }, 500); // transition time - }; + modal.hide = function (sel) { + var $m = $(sel); + $m.removeClass('visible'); + setTimeout(function () { + $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); - }); + modal.init = function () { + // close modal by click outside the dialog + $('.Modal').on('click', function () { + if ($(this).hasClass('no-close')) return; // this is a no-close modal + modal.hide(this); + }); - $('.Dialog').on('click', function (e) { - e.stopImmediatePropagation(); - }); + $('.Dialog').on('click', function (e) { + e.stopImmediatePropagation(); + }); - // Hide all modals on esc - $(window).on('keydown', function (e) { - if (e.which == 27) { - modal.hide('.Modal'); - } - }); - }; + // Hide all modals on esc + $(window).on('keydown', function (e) { + if (e.which == 27) { + modal.hide('.Modal'); + } + }); + }; - window.Modal = modal; + window.Modal = modal; })(); diff --git a/jssrc/notif.js b/jssrc/notif.js index ad08e51..ca19224 100644 --- a/jssrc/notif.js +++ b/jssrc/notif.js @@ -1,32 +1,32 @@ (function (nt) { - var sel = '#notif'; + var sel = '#notif'; - var hideTmeo1; // timeout to start hiding (transition) - var hideTmeo2; // timeout to add the hidden class + var hideTmeo1; // timeout to start hiding (transition) + var hideTmeo2; // timeout to add the hidden class - nt.show = function (message, timeout) { - $(sel).html(message); - Modal.show(sel); + nt.show = function (message, timeout) { + $(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'); - hideTmeo2 = setTimeout(function () { - $m.addClass('hidden'); - }, 250); // transition time - }; + nt.hide = function () { + var $m = $(sel); + $m.removeClass('visible'); + hideTmeo2 = setTimeout(function () { + $m.addClass('hidden'); + }, 250); // transition time + }; - nt.init = function() { - $(sel).on('click', function() { - nt.hide(this); - }); - }; + nt.init = function () { + $(sel).on('click', function () { + nt.hide(this); + }); + }; })(window.Notify = {}); diff --git a/jssrc/soft_keyboard.js b/jssrc/soft_keyboard.js index 3bdcdc2..b21b9e4 100644 --- a/jssrc/soft_keyboard.js +++ b/jssrc/soft_keyboard.js @@ -1,27 +1,29 @@ $.ready(() => { - const input = qs('#softkb-input') - let keyboardOpen = false + const input = qs('#softkb-input'); + if (!input) return; // abort, we're not on the terminal page + + 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; @@ -47,7 +49,7 @@ $.ready(() => { newValue) } lastCompositionString = newValue; - } + }; input.addEventListener('keydown', e => { if (e.key === 'Unidentified') return; @@ -55,9 +57,9 @@ $.ready(() => { 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(); @@ -66,11 +68,11 @@ $.ready(() => { } else { if (e.data) Input.sendString(e.data); else if (e.inputType === 'deleteContentBackward') { - lastCompositionString + lastCompositionString = ''; sendInputDelta(''); } } - }) + }); input.addEventListener('compositionstart', e => { lastCompositionString = ''; compositing = true; @@ -82,4 +84,4 @@ $.ready(() => { }); Screen.on('open-soft-keyboard', () => input.focus()) -}) +}); diff --git a/jssrc/term_input.js b/jssrc/term_input.js index 6df0535..367c06e 100644 --- a/jssrc/term_input.js +++ b/jssrc/term_input.js @@ -22,6 +22,7 @@ var Input = (function() { mt_click: false, mt_move: false, no_keys: false, + crlf_mode: false, }; /** Send a literal message */ @@ -53,7 +54,7 @@ var Input = (function() { var keymap = { 'tab': '\x09', 'backspace': '\x08', - 'enter': '\x0d', + 'enter': opts.crlf_mode ? '\x0d\x0a' : '\x0d', 'ctrl+enter': '\x0a', 'esc': '\x1b', 'up': ca('\x1bOA', '\x1b[A'), @@ -207,11 +208,12 @@ var Input = (function() { sendString: sendStrMsg, /** Enable alternate key modes (cursors, numpad, fn) */ - setAlts: function(cu, np, fn) { - if (opts.cu_alt != cu || opts.np_alt != np || opts.fn_alt != 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(); diff --git a/jssrc/term_screen.js b/jssrc/term_screen.js index 2bb56e1..9679d9d 100644 --- a/jssrc/term_screen.js +++ b/jssrc/term_screen.js @@ -64,6 +64,7 @@ class TermScreen { visible: true, hanging: false, style: 'block', + blinkEnable: true, blinkInterval: 0, }; @@ -205,17 +206,17 @@ class TermScreen { e.preventDefault(); selectEnd(...touchPosition); - let touchSelectMenu = qs('#touch-select-menu') + let touchSelectMenu = qs('#touch-select-menu'); touchSelectMenu.classList.add('open'); - let rect = touchSelectMenu.getBoundingClientRect() + let rect = touchSelectMenu.getBoundingClientRect(); // use middle position for x and one line above for y let selectionPos = this.gridToScreen( (this.selection.start[0] + this.selection.end[0]) / 2, this.selection.start[1] - 1 ); - selectionPos[0] -= rect.width / 2 - selectionPos[1] -= rect.height / 2 + selectionPos[0] -= rect.width / 2; + selectionPos[1] -= rect.height / 2; touchSelectMenu.style.transform = `translate(${selectionPos[0]}px, ${ selectionPos[1]}px)` } @@ -242,13 +243,15 @@ class TermScreen { e.preventDefault(); this.emit('open-soft-keyboard'); } - }) + }); $.ready(() => { - let copyButton = qs('#touch-select-copy-btn') - copyButton.addEventListener('click', () => { - this.copySelectionToClipboard(); - }); + let copyButton = qs('#touch-select-copy-btn'); + if (copyButton) { + copyButton.addEventListener('click', () => { + this.copySelectionToClipboard(); + }); + } }); this.canvas.addEventListener('mousemove', e => { @@ -274,7 +277,7 @@ class TermScreen { this.canvas.addEventListener('contextmenu', e => { // prevent mouse keys getting stuck e.preventDefault(); - }) + }); // bind ctrl+shift+c to copy key('⌃+⇧+c', e => { @@ -333,8 +336,8 @@ class TermScreen { } getColor (i) { - if (i === -1) return SELECTION_FG - if (i === -2) return SELECTION_BG + if (i === -1) return SELECTION_FG; + if (i === -2) return SELECTION_BG; return this.colors[i] } @@ -398,29 +401,32 @@ class TermScreen { const cellSize = this.getCellSize(); // real height of the canvas element in pixels - let realWidth = width * cellSize.width - let realHeight = height * cellSize.height + let realWidth = width * cellSize.width; + let realHeight = height * cellSize.height; if (fitIntoWidth && fitIntoHeight) { if (realWidth > fitIntoWidth || realHeight > fitIntoHeight) { - let terminalAspect = realWidth / realHeight - let fitAspect = fitIntoWidth / fitIntoHeight + let terminalAspect = realWidth / realHeight; + let fitAspect = fitIntoWidth / fitIntoHeight; if (terminalAspect < fitAspect) { // align heights - realHeight = fitIntoHeight + realHeight = fitIntoHeight; realWidth = realHeight * terminalAspect - } else { + } + else { // align widths - realWidth = fitIntoWidth + realWidth = fitIntoWidth; realHeight = realWidth / terminalAspect } } - } else if (fitIntoWidth && realWidth > fitIntoWidth) { - realHeight = fitIntoWidth / (realWidth / realHeight) + } + else if (fitIntoWidth && realWidth > fitIntoWidth) { + realHeight = fitIntoWidth / (realWidth / realHeight); realWidth = fitIntoWidth - } else if (fitIntoHeight && realHeight > fitIntoHeight) { - realWidth = fitIntoHeight * (realWidth / realHeight) + } + else if (fitIntoHeight && realHeight > fitIntoHeight) { + realWidth = fitIntoHeight * (realWidth / realHeight); realHeight = fitIntoHeight } @@ -552,11 +558,11 @@ class TermScreen { let underline = false; let blink = false; let strike = false; - if (attrs & 1 << 1) ctx.globalAlpha = 0.5; - if (attrs & 1 << 3) underline = true; - if (attrs & 1 << 4) blink = true; - if (attrs & 1 << 5) text = TermScreen.alphaToFraktur(text); - if (attrs & 1 << 6) strike = true; + if (attrs & (1 << 1)) ctx.globalAlpha = 0.5; + if (attrs & (1 << 3)) underline = true; + if (attrs & (1 << 4)) blink = true; + if (attrs & (1 << 5)) text = TermScreen.alphaToFraktur(text); + if (attrs & (1 << 6)) strike = true; if (!blink || this.window.blinkStyleOn) { ctx.fillStyle = this.getColor(fg); @@ -618,14 +624,18 @@ class TermScreen { // Map of (cell index) -> boolean, whether or not a cell needs to be redrawn const updateMap = new Map(); + const cursorActive = (this.cursor.blinkOn || !this.cursor.blinkEnable); + for (let cell = 0; cell < screenLength; cell++) { let x = cell % width; let y = Math.floor(cell / width); - let isCursor = this.cursor.x === x && this.cursor.y === y && - !this.cursor.hanging; - let invertForCursor = isCursor && this.cursor.blinkOn && - this.cursor.style === 'block'; - let inSelection = this.isInSelection(x, y) + let isCursor = !this.cursor.hanging + && this.cursor.x === x + && this.cursor.y === y; + + let invertForCursor = isCursor && cursorActive && this.cursor.style === 'block'; + + let inSelection = this.isInSelection(x, y); let text = this.screen[cell]; let fg = invertForCursor ? this.screenBG[cell] : this.screenFG[cell]; @@ -636,7 +646,7 @@ class TermScreen { if (invertForCursor && fg === bg) bg = fg === 0 ? 7 : 0; if (inSelection) { - fg = -1 + fg = -1; bg = -2 } @@ -695,7 +705,7 @@ class TermScreen { this.drawnScreenAttrs[cell] = attrs; } - if (isCursor && this.cursor.blinkOn && this.cursor.style !== 'block') { + if (isCursor && cursorActive && this.cursor.style !== 'block') { ctx.save(); ctx.beginPath(); if (this.cursor.style === 'bar') { @@ -748,20 +758,21 @@ class TermScreen { } // attributes - let attributes = parse2B(str, i); - i += 2; + let attributes = parse3B(str, i); + i += 3; this.cursor.visible = !!(attributes & 1); - this.cursor.hanging = !!(attributes & 1 << 1); + this.cursor.hanging = !!(attributes & (1 << 1)); Input.setAlts( - !!(attributes & 1 << 2), // cursors alt - !!(attributes & 1 << 3), // numpad alt - !!(attributes & 1 << 4) // fn keys alt + !!(attributes & (1 << 2)), // cursors alt + !!(attributes & (1 << 3)), // numpad alt + !!(attributes & (1 << 4)), // fn keys alt + !!(attributes & (1 << 12)) // crlf mode ); - let trackMouseClicks = !!(attributes & 1 << 5); - let trackMouseMovement = !!(attributes & 1 << 6); + let trackMouseClicks = !!(attributes & (1 << 5)); + let trackMouseMovement = !!(attributes & (1 << 6)); Input.setMouseMode(trackMouseClicks, trackMouseMovement); this.selection.selectable = !trackMouseMovement; @@ -771,12 +782,19 @@ class TermScreen { movement: trackMouseMovement }; - let showButtons = !!(attributes & 1 << 7); - let showConfigLinks = !!(attributes & 1 << 8); + let showButtons = !!(attributes & (1 << 7)); + let showConfigLinks = !!(attributes & (1 << 8)); $('.x-term-conf-btn').toggleClass('hidden', !showConfigLinks); $('#action-buttons').toggleClass('hidden', !showButtons); + let cursorStyle = (attributes >> 9) & 0x07; + // 0 - Block blink, 2 - Block steady + // 3 - Under blink, 4 - Under steady + // 5 - I-bar blink, 6 - I-bar steady + this.cursor.style = cursorStyle<3?'block':cursorStyle<5?'line':'bar'; + this.cursor.blinkEnable = cursorStyle === 0 || cursorStyle === 3 || cursorStyle === 5; + // content let fg = 7; let bg = 0; @@ -932,23 +950,23 @@ Screen.once('load', () => { } }); -let fitScreen = false +let fitScreen = false; function fitScreenIfNeeded () { - Screen.window.fitIntoWidth = fitScreen ? window.innerWidth : 0 + Screen.window.fitIntoWidth = fitScreen ? window.innerWidth : 0; Screen.window.fitIntoHeight = fitScreen ? window.innerHeight : 0 } fitScreenIfNeeded(); -window.addEventListener('resize', fitScreenIfNeeded) +window.addEventListener('resize', fitScreenIfNeeded); window.toggleFitScreen = function () { fitScreen = !fitScreen; - const resizeButtonIcon = qs('#resize-button-icon') + const resizeButtonIcon = qs('#resize-button-icon'); if (fitScreen) { - resizeButtonIcon.classList.remove('icn-resize-small') + resizeButtonIcon.classList.remove('icn-resize-small'); resizeButtonIcon.classList.add('icn-resize-full') } else { - resizeButtonIcon.classList.remove('icn-resize-full') + resizeButtonIcon.classList.remove('icn-resize-full'); resizeButtonIcon.classList.add('icn-resize-small') } fitScreenIfNeeded(); -} +}; diff --git a/jssrc/term_upload.js b/jssrc/term_upload.js index 2c92110..5d138d1 100644 --- a/jssrc/term_upload.js +++ b/jssrc/term_upload.js @@ -1,146 +1,146 @@ /** File upload utility */ -var TermUpl = (function() { - var 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) - - // 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; - - 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 fuStatus(msg) { - qs('#fu_prog').textContent = msg; - } - - function fuSend() { - var v = qs('#fu_text').value; - if (!v.length) { - fuClose(); - return; - } - - 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; - } - - nl_str = { - 'CR': '\r', - 'LF': '\n', - 'CRLF': '\r\n', - }[qs('#fu_crlf').value]; - - $('#fu_form').toggleClass('busy', true); - fuStatus("Starting..."); - fuSendLine(); - } - - function fuSendLine() { - if (!$('#fu_modal').hasClass('visible')) { - // Modal is closed, cancel - return; - } - - if (!Conn.canSend()) { - // postpone - fuTout = setTimeout(fuSendLine, 1); - return; - } - - if (inline_pos == 0) { - curLine = lines[line_i++] + nl_str; - } - - var chunk; - if ((curLine.length - inline_pos) <= MAX_LINE_LEN) { - 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; - } - - if (!Input.sendString(chunk)) { - fuStatus("FAILED!"); - return; - } - - var all = lines.length; - - 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); - } else { - closeWhenReady(); - } - } - - function closeWhenReady() { - if (!Conn.canSend()) { - // stuck in XOFF still, wait to process... - fuStatus("Waiting for Tx buffer..."); - setTimeout(closeWhenReady, 100); - } else { - fuStatus("Done."); - // delay to show it - setTimeout(function() { - fuClose(); - }, 100); - } - } - - 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); - 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; - } - } - 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); - }, - close: fuClose, - start: fuSend, - open: fuOpen, - } +var TermUpl = (function () { + var 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) + + // 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; + + 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 fuStatus(msg) { + qs('#fu_prog').textContent = msg; + } + + function fuSend() { + var v = qs('#fu_text').value; + if (!v.length) { + fuClose(); + return; + } + + 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; + } + + nl_str = { + 'CR': '\r', + 'LF': '\n', + 'CRLF': '\r\n', + }[qs('#fu_crlf').value]; + + $('#fu_form').toggleClass('busy', true); + fuStatus("Starting..."); + fuSendLine(); + } + + function fuSendLine() { + if (!$('#fu_modal').hasClass('visible')) { + // Modal is closed, cancel + return; + } + + if (!Conn.canSend()) { + // postpone + fuTout = setTimeout(fuSendLine, 1); + return; + } + + if (inline_pos == 0) { + curLine = lines[line_i++] + nl_str; + } + + var chunk; + if ((curLine.length - inline_pos) <= MAX_LINE_LEN) { + 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; + } + + if (!Input.sendString(chunk)) { + fuStatus("FAILED!"); + return; + } + + var all = lines.length; + + 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); + } else { + closeWhenReady(); + } + } + + function closeWhenReady() { + if (!Conn.canSend()) { + // stuck in XOFF still, wait to process... + fuStatus("Waiting for Tx buffer..."); + setTimeout(closeWhenReady, 100); + } else { + fuStatus("Done."); + // delay to show it + setTimeout(function () { + fuClose(); + }, 100); + } + } + + 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); + 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; + } + } + 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); + }, + close: fuClose, + start: fuSend, + open: fuOpen, + } })(); diff --git a/jssrc/utils.js b/jssrc/utils.js index 3bb5574..dcd35fa 100755 --- a/jssrc/utils.js +++ b/jssrc/utils.js @@ -1,15 +1,21 @@ /** Make a node */ -function mk(e) {return document.createElement(e)} +function mk(e) { + return document.createElement(e) +} /** Find one by query */ -function qs(s) {return document.querySelector(s)} +function qs(s) { + return document.querySelector(s) +} /** Find all by query */ -function qsa(s) {return document.querySelectorAll(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'); + return (x === 1 || x === '1' || x === true || x === 'true'); } /** @@ -18,52 +24,52 @@ function bool(x) { * use $(...).on('keypress', cr(handler)) */ function cr(hdl) { - return function(e) { - if (e.which == 10 || e.which == 13 || e.which == 32) { - hdl(); - } - }; + return function (e) { + if (e.which == 10 || e.which == 13 || e.which == 32) { + hdl(); + } + }; } /** Extend an objects with options */ function extend(defaults, options) { - var target = {}; + var target = {}; - Object.keys(defaults).forEach(function(k){ - target[k] = defaults[k]; - }); + Object.keys(defaults).forEach(function (k) { + target[k] = defaults[k]; + }); - Object.keys(options).forEach(function(k){ - target[k] = options[k]; - }); + Object.keys(options).forEach(function (k) { + target[k] = options[k]; + }); - return target; + return target; } /** Escape string for use as literal in RegExp */ function rgxe(str) { - return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); + 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; + var pow = Math.pow(10, places); + return Math.round(x * pow) / pow; } /** Get millisecond timestamp */ function msNow() { - return +(new Date); + return +(new Date); } /** Get ms elapsed since msNow() */ function msElapsed(start) { - return msNow() - start; + return msNow() - start; } /** Shim for log base 10 */ -Math.log10 = Math.log10 || function(x) { - return Math.log(x) / Math.LN10; +Math.log10 = Math.log10 || function (x) { + return Math.log(x) / Math.LN10; }; /** @@ -78,84 +84,84 @@ Math.log10 = Math.log10 || function(x) { * @returns {String} result */ String.prototype.format = function () { - var out = this; - var repl = arguments; + var out = this; + var repl = arguments; - if (arguments.length == 1 && (Array.isArray(arguments[0]) || typeof arguments[0] == 'object')) { - repl = arguments[0]; - } + if (arguments.length == 1 && (Array.isArray(arguments[0]) || typeof arguments[0] == 'object')) { + repl = arguments[0]; + } - for (var ph in repl) { - if (repl.hasOwnProperty(ph)) { - var ph_orig = ph; + for (var ph in repl) { + if (repl.hasOwnProperty(ph)) { + var ph_orig = ph; - if (!ph.match(/^\{.*\}$/)) { - ph = '{' + ph + '}'; - } + if (!ph.match(/^\{.*\}$/)) { + ph = '{' + ph + '}'; + } - // replace all occurrences - var pattern = new RegExp(rgxe(ph), "g"); - out = out.replace(pattern, repl[ph_orig]); - } - } + // replace all occurrences + var 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); + return $.htmlEscape(str); } /** Check for undefined */ function undef(x) { - return typeof x == 'undefined'; + return typeof x == 'undefined'; } /** Safe json parse */ function jsp(str) { - try { - return JSON.parse(str); - } catch(e) { - console.error(e); - return null; - } + try { + return JSON.parse(str); + } catch (e) { + console.error(e); + return null; + } } /** Create a character from ASCII code */ function Chr(n) { - return String.fromCharCode(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); + var 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); + 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); } diff --git a/jssrc/wifi.js b/jssrc/wifi.js index ebed158..62f7b1c 100644 --- a/jssrc/wifi.js +++ b/jssrc/wifi.js @@ -1,163 +1,163 @@ -(function(w) { - var authStr = ['Open', 'WEP', 'WPA', 'WPA2', 'WPA/WPA2']; - var curSSID; - - // Get XX % for a slider input - 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')); - } - - /** 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"}, - // ] - // } - //}; - - if (status != 200) { - // bad response - rescan(5000); // wait 5sm then retry - return; - } - - try { - resp = JSON.parse(resp); - } catch (e) { - 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 - - // clear the AP list - var $list = $('#ap-list'); - // remove old APs - $('#ap-list .AP').remove(); - - $list.toggleClass('hidden', !done); - $('#ap-loader').toggleClass('hidden', done); - - // scan done - resp.result.APs.sort(function (a, b) { - return b.rssi - a.rssi; - }).forEach(function (ap) { - ap.enc = parseInt(ap.enc); - - if (ap.enc > 4) return; // hide unsupported auths - - var item = mk('div'); - - var $item = $(item) - .data('ssid', ap.essid) - .data('pwd', ap.enc) - .attr('tabindex', 0) - .addClass('AP'); - - // mark current SSID - if (ap.essid == curSSID) { - $item.addClass('selected'); - } - - var inner = mk('div'); - $(inner).addClass('inner') - .htmlAppend('
{0}
'.format(ap.rssi_perc)) - .htmlAppend('
{0}
'.format($.htmlEscape(ap.essid))) - .htmlAppend('
{0}
'.format(authStr[ap.enc])); - - $item.on('click', function () { - var $th = $(this); - - var conn_ssid = $th.data('ssid'); - var 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; - } - - $('#sta_password').val(conn_pass); - $('#sta_ssid').val(conn_ssid); - selectSta(conn_ssid, conn_pass, ''); - }); - - - item.appendChild(inner); - $list[0].appendChild(item); - }); - } - - function startScanning() { - $('#ap-loader').removeClass('hidden'); - $('#ap-scan').addClass('hidden'); - $('#ap-loader .anim-dots').html('.'); - - scanAPs(); - } - - /** Ask the CGI what APs are visible (async) */ - function scanAPs() { - if (_demo) { - onScan(_demo_aps, 200); - } else { - $.get('http://' + _root + '/cfg/wifi/scan', onScan); - } - } - - function rescan(time) { - setTimeout(scanAPs, time); - } - - /** Set up the WiFi page */ - 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); - $(inp).on('input', function() { - t = rangePt(inp); - $(disp1).html(t); - $(disp2).html(t); - }); - }); - - // Forget STA credentials - $('#forget-sta').on('click', function() { - selectSta('', '', ''); - return false; - }); - - selectSta(cfg.sta_ssid, cfg.sta_password, cfg.sta_active_ip); - curSSID = cfg.sta_active_ssid; - } - - w.init = wifiInit; - w.startScanning = startScanning; +(function (w) { + var authStr = ['Open', 'WEP', 'WPA', 'WPA2', 'WPA/WPA2']; + var curSSID; + + // Get XX % for a slider input + 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')); + } + + /** 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"}, + // ] + // } + //}; + + if (status != 200) { + // bad response + rescan(5000); // wait 5sm then retry + return; + } + + try { + resp = JSON.parse(resp); + } catch (e) { + 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 + + // clear the AP list + var $list = $('#ap-list'); + // remove old APs + $('#ap-list .AP').remove(); + + $list.toggleClass('hidden', !done); + $('#ap-loader').toggleClass('hidden', done); + + // scan done + resp.result.APs.sort(function (a, b) { + return b.rssi - a.rssi; + }).forEach(function (ap) { + ap.enc = parseInt(ap.enc); + + if (ap.enc > 4) return; // hide unsupported auths + + var item = mk('div'); + + var $item = $(item) + .data('ssid', ap.essid) + .data('pwd', ap.enc) + .attr('tabindex', 0) + .addClass('AP'); + + // mark current SSID + if (ap.essid == curSSID) { + $item.addClass('selected'); + } + + var inner = mk('div'); + $(inner).addClass('inner') + .htmlAppend('
{0}
'.format(ap.rssi_perc)) + .htmlAppend('
{0}
'.format($.htmlEscape(ap.essid))) + .htmlAppend('
{0}
'.format(authStr[ap.enc])); + + $item.on('click', function () { + var $th = $(this); + + var conn_ssid = $th.data('ssid'); + var 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; + } + + $('#sta_password').val(conn_pass); + $('#sta_ssid').val(conn_ssid); + selectSta(conn_ssid, conn_pass, ''); + }); + + + item.appendChild(inner); + $list[0].appendChild(item); + }); + } + + function startScanning() { + $('#ap-loader').removeClass('hidden'); + $('#ap-scan').addClass('hidden'); + $('#ap-loader .anim-dots').html('.'); + + scanAPs(); + } + + /** Ask the CGI what APs are visible (async) */ + function scanAPs() { + if (_demo) { + onScan(_demo_aps, 200); + } else { + $.get('http://' + _root + '/cfg/wifi/scan', onScan); + } + } + + function rescan(time) { + setTimeout(scanAPs, time); + } + + /** Set up the WiFi page */ + 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); + $(inp).on('input', function () { + t = rangePt(inp); + $(disp1).html(t); + $(disp2).html(t); + }); + }); + + // Forget STA credentials + $('#forget-sta').on('click', function () { + selectSta('', '', ''); + return false; + }); + + selectSta(cfg.sta_ssid, cfg.sta_password, cfg.sta_active_ip); + curSSID = cfg.sta_active_ssid; + } + + w.init = wifiInit; + w.startScanning = startScanning; })(window.WiFi = {}); diff --git a/lang/en.php b/lang/en.php index 3e63611..e099ce2 100644 --- a/lang/en.php +++ b/lang/en.php @@ -51,6 +51,7 @@ return [ 'term.default_fg_bg' => 'Text / background', 'term.buttons' => 'Button labels', 'term.theme' => 'Color scheme', + 'term.cursor_shape' => 'Cursor style', 'term.parser_tout_ms' => 'Parser timeout', 'term.display_tout_ms' => 'Redraw delay', 'term.display_cooldown_ms' => 'Redraw cooldown', @@ -58,8 +59,16 @@ return [ 'term.show_config_links' => 'Show nav links', 'term.show_buttons' => 'Show buttons', 'term.loopback' => 'Local Echo', + 'term.crlf_mode' => 'Enter sends CR+LF', 'term.button_msgs' => 'Button codes
(ASCII, dec, CSV)', + 'cursor.block_blink' => 'Block, blinking', + 'cursor.block_steady' => 'Block, steady', + 'cursor.underline_blink' => 'Underline, blinking', + 'cursor.underline_steady' => 'Underline, steady', + 'cursor.bar_blink' => 'I-bar, blinking', + 'cursor.bar_steady' => 'I-bar, steady', + // terminal color labels 'color.0' => 'Black', 'color.1' => 'Red', diff --git a/pages/cfg_term.php b/pages/cfg_term.php index 5f38f25..10ed719 100644 --- a/pages/cfg_term.php +++ b/pages/cfg_term.php @@ -108,6 +108,18 @@ +
+ + +
+
@@ -153,6 +165,12 @@ +
+ + +
+
@@ -179,6 +197,7 @@