diff --git a/.eslintrc b/.eslintrc index 63163e3..25f5194 100644 --- a/.eslintrc +++ b/.eslintrc @@ -30,7 +30,7 @@ "accessor-pairs": "error", "arrow-spacing": ["error", { "before": true, "after": true }], "block-spacing": ["error", "always"], - "brace-style": ["error", "1tbs", { "allowSingleLine": true }], + "brace-style": ["warn", "1tbs", { "allowSingleLine": true }], "camelcase": ["off", { "properties": "never" }], "comma-dangle": ["error", { "arrays": "never", @@ -45,7 +45,7 @@ "curly": ["error", "multi-line"], "dot-location": ["error", "property"], "eol-last": "error", - "eqeqeq": ["off", "always", { "null": "ignore" }], + "eqeqeq": ["error", "smart"], "func-call-spacing": ["error", "never"], "generator-star-spacing": ["error", { "before": true, "after": true }], "handle-callback-err": ["error", "^(err|error)$" ], @@ -97,7 +97,7 @@ "allowSamePrecedence": true }], "no-mixed-spaces-and-tabs": "error", - "no-multi-spaces": "off", + "no-multi-spaces": "warn", "no-multi-str": "error", "no-multiple-empty-lines": ["error", { "max": 1, "maxEOF": 0 }], "no-negated-in-lhs": "error", diff --git a/jssrc/appcommon.js b/jssrc/appcommon.js index e1a9514..3fbf120 100644 --- a/jssrc/appcommon.js +++ b/jssrc/appcommon.js @@ -27,7 +27,7 @@ $.ready(function () { $('form').forEach(function (x) { $(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() } }) @@ -38,7 +38,7 @@ $.ready(function () { $('.anim-dots').each(function (x) { let $x = $(x) let dots = $x.html() + '.' - if (dots.length == 5) dots = '.' + if (dots.length === 5) dots = '.' $x.html(dots) }) }, 1000) diff --git a/jssrc/modal.js b/jssrc/modal.js index 9965469..fabc1a7 100644 --- a/jssrc/modal.js +++ b/jssrc/modal.js @@ -34,7 +34,7 @@ // Hide all modals on esc $(window).on('keydown', function (e) { - if (e.which == 27) { + if (e.which === 27) { modal.hide('.Modal') } }) diff --git a/jssrc/soft_keyboard.js b/jssrc/soft_keyboard.js index 006590b..5ad2708 100644 --- a/jssrc/soft_keyboard.js +++ b/jssrc/soft_keyboard.js @@ -15,7 +15,9 @@ $.ready(() => { keyboardOpen = true updateInputPosition() }) + input.addEventListener('blur', () => (keyboardOpen = false)) + Screen.on('cursor-moved', updateInputPosition) window.kbOpen = function openSoftKeyboard (open) { @@ -60,6 +62,7 @@ $.ready(() => { if (e.key === 'Backspace') Input.sendString('\b') else if (e.key === 'Enter') Input.sendString('\x0d') }) + input.addEventListener('input', e => { e.stopPropagation() @@ -73,10 +76,12 @@ $.ready(() => { } } }) + input.addEventListener('compositionstart', e => { lastCompositionString = '' compositing = true }) + input.addEventListener('compositionend', e => { lastCompositionString = '' compositing = false diff --git a/jssrc/term_conn.js b/jssrc/term_conn.js index b4255d5..3208028 100644 --- a/jssrc/term_conn.js +++ b/jssrc/term_conn.js @@ -29,15 +29,8 @@ window.Conn = (function () { try { // . = heartbeat switch (evt.data.charAt(0)) { - case 'B': - case 'T': - case 'S': - case 'G': - Screen.load(evt.data) - if (!pageShown) { - showPage() - pageShown = true - } + case '.': + // heartbeat, no-op message break case '-': @@ -53,6 +46,14 @@ window.Conn = (function () { xoff = false clearTimeout(autoXoffTout) break + + default: + Screen.load(evt.data) + if (!pageShown) { + showPage() + pageShown = true + } + break } heartbeat() } catch (e) { @@ -76,7 +77,7 @@ window.Conn = (function () { } if (!ws) return false // for dry testing - if (ws.readyState != 1) { + if (ws.readyState !== 1) { console.error('Socket not ready') return false } @@ -116,7 +117,7 @@ window.Conn = (function () { pingIv = setInterval(function () { console.log('> ping') $.get('http://' + _root + '/system/ping', function (resp, status) { - if (status == 200) { + if (status === 200) { clearInterval(pingIv) console.info('Server ready, reloading page...') location.reload() diff --git a/jssrc/term_input.js b/jssrc/term_input.js index 96dbf2f..2c8e257 100644 --- a/jssrc/term_input.js +++ b/jssrc/term_input.js @@ -153,6 +153,7 @@ window.Input = (function () { for (let i = 1; i <= 26; i++) { bind('ctrl+' + String.fromCharCode(96 + i), String.fromCharCode(i)) } + /* eslint-disable */ bind('ctrl+]', '\x1b') // alternate way to enter ESC bind('ctrl+\\', '\x1c') bind('ctrl+[', '\x1d') @@ -176,12 +177,13 @@ window.Input = (function () { bind('shift+end', '\x1f[1;2F') // macOS editing commands - bind('⌥+left', '\x1fb') // ⌥← to go back a word (^[b) - bind('⌥+right', '\x1ff') // ⌥→ to go forward one word (^[f) - bind('⌘+left', '\x01') // ⌘← to go to the beginning of a line (^A) - bind('⌘+right', '\x05') // ⌘→ to go to the end of a line (^E) + bind('⌥+left', '\x1fb') // ⌥← to go back a word (^[b) + bind('⌥+right', '\x1ff') // ⌥→ to go forward one word (^[f) + bind('⌘+left', '\x01') // ⌘← to go to the beginning of a line (^A) + bind('⌘+right', '\x05') // ⌘→ to go to the end of a line (^E) bind('⌥+backspace', '\x17') // ⌥⌫ to delete a word (^W, I think) bind('⌘+backspace', '\x15') // ⌘⌫ to delete to the beginning of a line (possibly ^U) + /* eslint-enable */ _bindFnKeys() } @@ -204,15 +206,15 @@ window.Input = (function () { // global mouse state tracking - for motion reporting window.addEventListener('mousedown', function (evt) { - if (evt.button == 0) mb1 = 1 - if (evt.button == 1) mb2 = 1 - if (evt.button == 2) mb3 = 1 + if (evt.button === 0) mb1 = 1 + if (evt.button === 1) mb2 = 1 + if (evt.button === 2) mb3 = 1 }) window.addEventListener('mouseup', function (evt) { - if (evt.button == 0) mb1 = 0 - if (evt.button == 1) mb2 = 0 - if (evt.button == 2) mb3 = 0 + if (evt.button === 0) mb1 = 0 + if (evt.button === 1) mb2 = 0 + if (evt.button === 2) mb3 = 0 }) } @@ -233,7 +235,7 @@ window.Input = (function () { /** Enable alternate key modes (cursors, numpad, fn) */ setAlts: function (cu, np, fn, crlf) { - if (opts.cu_alt != cu || opts.np_alt != np || opts.fn_alt != fn || opts.crlf_mode != crlf) { + 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 @@ -256,6 +258,7 @@ window.Input = (function () { const m = packModifiersForMouse() Conn.send('m' + encode2B(y) + encode2B(x) + encode2B(b) + encode2B(m)) }, + onMouseDown: function (x, y, b) { if (!opts.mt_click) return if (b > 3 || b < 1) return @@ -263,6 +266,7 @@ window.Input = (function () { Conn.send('p' + encode2B(y) + encode2B(x) + encode2B(b) + encode2B(m)) // console.log("B ",b," M ",m); }, + onMouseUp: function (x, y, b) { if (!opts.mt_click) return if (b > 3 || b < 1) return @@ -270,6 +274,7 @@ window.Input = (function () { Conn.send('r' + encode2B(y) + encode2B(x) + encode2B(b) + encode2B(m)) // console.log("B ",b," M ",m); }, + onMouseWheel: function (x, y, dir) { if (!opts.mt_click) return // -1 ... btn 4 (away from user) @@ -279,9 +284,11 @@ window.Input = (function () { Conn.send('p' + encode2B(y) + encode2B(x) + encode2B(b) + encode2B(m)) // console.log("B ",b," M ",m); }, + mouseTracksClicks: function () { return opts.mt_click }, + blockKeys: function (yes) { opts.no_keys = yes } diff --git a/jssrc/term_screen.js b/jssrc/term_screen.js index 6eba873..3537b65 100644 --- a/jssrc/term_screen.js +++ b/jssrc/term_screen.js @@ -43,6 +43,8 @@ const themes = [ ] ] +// TODO move this to the initializer so it's not run on non-terminal pages + // 256color lookup table // should not be used to look up 0-15 (will return transparent) const colorTable256 = new Array(16).fill('rgba(0, 0, 0, 0)') @@ -160,17 +162,20 @@ class TermScreen { this.resetCursorBlink() let selecting = false + let selectStart = (x, y) => { if (selecting) return selecting = true this.selection.start = this.selection.end = this.screenToGrid(x, y) this.scheduleDraw() } + let selectMove = (x, y) => { if (!selecting) return this.selection.end = this.screenToGrid(x, y) this.scheduleDraw() } + let selectEnd = (x, y) => { if (!selecting) return selecting = false @@ -187,9 +192,11 @@ class TermScreen { e.button + 1) } }) + window.addEventListener('mousemove', e => { selectMove(e.offsetX, e.offsetY) }) + window.addEventListener('mouseup', e => { selectEnd(e.offsetX, e.offsetY) }) @@ -198,15 +205,18 @@ class TermScreen { let touchDownTime = 0 let touchSelectMinTime = 500 let touchDidMove = false + let getTouchPositionOffset = touch => { let rect = this.canvas.getBoundingClientRect() return [touch.clientX - rect.left, touch.clientY - rect.top] } + this.canvas.addEventListener('touchstart', e => { touchPosition = getTouchPositionOffset(e.touches[0]) touchDidMove = false touchDownTime = Date.now() }) + this.canvas.addEventListener('touchmove', e => { touchPosition = getTouchPositionOffset(e.touches[0]) @@ -221,10 +231,12 @@ class TermScreen { touchDidMove = true }) + this.canvas.addEventListener('touchend', e => { if (e.touches[0]) { touchPosition = getTouchPositionOffset(e.touches[0]) } + if (selecting) { e.preventDefault() selectEnd(...touchPosition) @@ -282,12 +294,14 @@ class TermScreen { Input.onMouseMove(...this.screenToGrid(e.offsetX, e.offsetY)) } }) + this.canvas.addEventListener('mouseup', e => { if (!selecting) { Input.onMouseUp(...this.screenToGrid(e.offsetX, e.offsetY), e.button + 1) } }) + this.canvas.addEventListener('wheel', e => { if (this.mouseMode.clicks) { Input.onMouseWheel(...this.screenToGrid(e.offsetX, e.offsetY), @@ -297,6 +311,7 @@ class TermScreen { e.preventDefault() } }) + this.canvas.addEventListener('contextmenu', e => { if (this.mouseMode.clicks) { // prevent mouse keys getting stuck @@ -573,7 +588,6 @@ class TermScreen { Notify.show('Copied to clipboard') } else { Notify.show('Failed to copy') - // unsuccessful copy } document.body.removeChild(textarea) } @@ -596,10 +610,8 @@ class TermScreen { drawCellBackground ({ x, y, cellWidth, cellHeight, bg }) { const ctx = this.ctx ctx.fillStyle = this.getColor(bg) - ctx.clearRect(x * cellWidth, y * cellHeight, - Math.ceil(cellWidth), Math.ceil(cellHeight)) - ctx.fillRect(x * cellWidth, y * cellHeight, - Math.ceil(cellWidth), Math.ceil(cellHeight)) + ctx.clearRect(x * cellWidth, y * cellHeight, Math.ceil(cellWidth), Math.ceil(cellHeight)) + ctx.fillRect(x * cellWidth, y * cellHeight, Math.ceil(cellWidth), Math.ceil(cellHeight)) } drawCell ({ x, y, charSize, cellWidth, cellHeight, text, fg, bg, attrs }) { @@ -1020,17 +1032,19 @@ class TermScreen { } showNotification (text) { - console.log(`Notification: ${text}`) - // TODO: request permission earlier - // the requestPermission should be user-triggered; asking upfront seems - // a little awkward + console.info(`Notification: ${text}`) if (Notification && Notification.permission === 'granted') { let notification = new Notification('ESPTerm', { body: text }) notification.addEventListener('click', () => window.focus()) } else { - Notify.show(text) + if (Notification && Notification.permission !== 'denied') { + Notification.requestPermission() + } else { + // Fallback using the built-in notification balloon + Notify.show(text) + } } } @@ -1044,17 +1058,21 @@ class TermScreen { case 'S': this.loadContent(content) break + case 'T': this.loadLabels(content) break + case 'B': this.beep() break + case 'G': this.showNotification(content) break + default: - console.warn(`Bad data message type; ignoring.\n${JSON.stringify(content)}`) + console.warn(`Bad data message type; ignoring.\n${JSON.stringify(str)}`) } } diff --git a/jssrc/term_upload.js b/jssrc/term_upload.js index 5f7d720..bf940fa 100644 --- a/jssrc/term_upload.js +++ b/jssrc/term_upload.js @@ -71,7 +71,7 @@ window.TermUpl = (function () { return } - if (inline_pos == 0) { + if (inline_pos === 0) { curLine = lines[line_i++] + nl_str } diff --git a/jssrc/utils.js b/jssrc/utils.js index 9b53a5b..b3a78e6 100755 --- a/jssrc/utils.js +++ b/jssrc/utils.js @@ -25,7 +25,7 @@ function bool (x) { */ function cr (hdl) { return function (e) { - if (e.which == 10 || e.which == 13 || e.which == 32) { + if (e.which === 10 || e.which === 13 || e.which === 32) { hdl() } } @@ -33,7 +33,7 @@ function cr (hdl) { /** Extend an objects with options */ function extend (defaults, options) { - var target = {} + let target = {} Object.keys(defaults).forEach(function (k) { target[k] = defaults[k] @@ -53,7 +53,7 @@ function rgxe (str) { /** Format number to N decimal places, output as string */ function numfmt (x, places) { - var pow = Math.pow(10, places) + const pow = Math.pow(10, places) return Math.round(x * pow) / pow } diff --git a/jssrc/wifi.js b/jssrc/wifi.js index 3669241..f81da03 100644 --- a/jssrc/wifi.js +++ b/jssrc/wifi.js @@ -12,11 +12,11 @@ $('#sta_ssid').val(name) $('#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 .essid').html(e(name)) - const nopw = undef(password) || password.length == 0 + const nopw = undef(password) || password.length === 0 $('#sta-nw .passwd').toggleClass('hidden', nopw) $('#sta-nw .nopasswd').toggleClass('hidden', !nopw) $('#sta-nw .ip').html(ip.length > 0 ? tr('wifi.connected_ip_is') + ip : tr('wifi.not_conn')) @@ -34,7 +34,7 @@ // } // }; - if (status != 200) { + if (status !== 200) { // bad response rescan(5000) // wait 5sm then retry return @@ -77,7 +77,7 @@ .addClass('AP') // mark current SSID - if (ap.essid == curSSID) { + if (ap.essid === curSSID) { $item.addClass('selected') }