Make term work with webpack

box-drawing
cpsdqs 7 years ago
parent 540c93a4bd
commit ef249ebc79
Signed by untrusted user: cpsdqs
GPG Key ID: 3F59586BB7448DD1
  1. 2
      .eslintrc
  2. 3
      _build_js.sh
  3. 2
      dump_js_lang.php
  4. 28
      js/appcommon.js
  5. 6
      js/debug_screen.js
  6. 3
      js/demo.js
  7. 70
      js/event_emitter.js
  8. 12
      js/index.js
  9. 2
      js/lang.js
  10. 22
      js/modal.js
  11. 42
      js/notif.js
  12. 7
      js/soft_keyboard.js
  13. 25
      js/term.js
  14. 16
      js/term_conn.js
  15. 5
      js/term_input.js
  16. 40
      js/term_screen.js
  17. 14
      js/term_upload.js
  18. 50
      js/utils.js
  19. 18
      js/wifi.js
  20. 3
      package.json
  21. 6
      pages/term.php

@ -135,7 +135,7 @@
"no-unsafe-finally": "error",
"no-unsafe-negation": "error",
"no-unused-expressions": ["warn", { "allowShortCircuit": true, "allowTernary": true, "allowTaggedTemplates": true }],
"no-unused-vars": ["error", { "vars": "local", "args": "none", "ignoreRestSiblings": true }],
"no-unused-vars": ["warn", { "vars": "local", "args": "none", "ignoreRestSiblings": true }],
"no-use-before-define": ["error", { "functions": false, "classes": false, "variables": false }],
"no-useless-call": "error",
"no-useless-computed-key": "error",

@ -6,6 +6,9 @@ echo 'Generating lang.js...'
php ./dump_js_lang.php
echo 'Processing JS...'
npm run webpack
exit
if [[ $ESP_PROD ]]; then
smarg=
demofile=

@ -18,5 +18,5 @@ foreach ($selected as $key) {
file_put_contents(__DIR__. '/js/lang.js',
"// Generated from PHP locale file\n" .
'let _tr = ' . json_encode($out, JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE) . ";\n\n" .
"function tr (key) { return _tr[key] || '?' + key + '?' }\n"
"module.exports = function tr (key) { return _tr[key] || '?' + key + '?' }\n"
);

@ -1,4 +1,20 @@
const $ = require('./lib/chibi')
const { mk, qs } = require('./utils')
const modal = require('./modal')
const notify = require('./notif')
/**
* Filter 'spacebar' and 'return' from keypress handler,
* and when they're pressed, fire the callback.
* use $(...).on('keypress', cr(handler))
*/
function cr (hdl) {
return function (e) {
if (e.which === 10 || e.which === 13 || e.which === 32) {
hdl()
}
}
}
/** Global generic init */
$.ready(function () {
@ -60,8 +76,8 @@ $.ready(function () {
val -= step
}
if (undef(min)) val = Math.max(val, +min)
if (undef(max)) val = Math.min(val, +max)
if (!Number.isFinite(min)) val = Math.max(val, +min)
if (!Number.isFinite(max)) val = Math.min(val, +max)
$this.val(val)
if ('createEvent' in document) {
@ -96,8 +112,8 @@ $.ready(function () {
qs('.Box.errors').classList.remove('hidden')
}
Modal.init()
Notify.init()
modal.init()
notify.init()
// remove tabindices from h2 if wide
if (window.innerWidth > 550) {
@ -108,7 +124,7 @@ $.ready(function () {
// brand works as a link back to term in widescreen mode
let br = qs('#brand')
br && br.addEventListener('click', function () {
location.href = '/' // go to terminal
window.location.href = '/' // go to terminal
})
}
})
@ -124,6 +140,8 @@ function showPage () {
pageShown = true
$('#content').addClass('load')
}
// HACKITY HACK: fix this later
window.showPage = showPage
// Auto reveal pages other than the terminal (sets window.noAutoShow)
$.ready(function () {

@ -1,4 +1,6 @@
window.attachDebugScreen = function (screen) {
const { mk } = require('./utils')
module.exports = function attachDebugScreen (screen) {
const debugCanvas = mk('canvas')
const ctx = debugCanvas.getContext('2d')
@ -73,7 +75,7 @@ window.attachDebugScreen = function (screen) {
let isDrawing = false
let drawLoop = function () {
if (isDrawing) requestAnimationFrame(drawLoop)
if (isDrawing) window.requestAnimationFrame(drawLoop)
let { devicePixelRatio, width, height } = screen.window
let { width: cellWidth, height: cellHeight } = screen.getCellSize()

@ -1,3 +1,6 @@
const EventEmitter = require('events')
const { encode2B, encode3B, parse2B } = require('./utils')
class ANSIParser {
constructor (handler) {
this.reset()

@ -1,70 +0,0 @@
if (!('EventEmitter' in window)) {
window.EventEmitter = class EventEmitter {
constructor () {
this._listeners = {}
}
/**
* Bind an event listener to an event
* @param {string} event - the event name
* @param {Function} listener - the event listener
*/
on (event, listener) {
if (!this._listeners[event]) this._listeners[event] = []
this._listeners[event].push({ listener })
}
/**
* Bind an event listener to be run only once the next time the event fires
* @param {string} event - the event name
* @param {Function} listener - the event listener
*/
once (event, listener) {
if (!this._listeners[event]) this._listeners[event] = []
this._listeners[event].push({ listener, once: true })
}
/**
* Remove an event listener
* @param {string} event - the event name
* @param {Function} listener - the event listener
*/
off (event, listener) {
let listeners = this._listeners[event]
if (listeners) {
for (let i in listeners) {
if (listeners[i].listener === listener) {
listeners.splice(i, 1)
break
}
}
}
}
/**
* Emits an event
* @param {string} event - the event name
* @param {...any} args - arguments passed to all listeners
*/
emit (event, ...args) {
let listeners = this._listeners[event]
if (listeners) {
let remove = []
for (let listener of listeners) {
try {
listener.listener(...args)
if (listener.once) remove.push(listener)
} catch (err) {
console.error(err)
}
}
// this needs to be done in this roundabout way because for loops
// do not like arrays with changing lengths
for (let listener of remove) {
listeners.splice(listeners.indexOf(listener), 1)
}
}
}
}
}

@ -1,17 +1,7 @@
require('./lib/chibi')
require('./lib/polyfills')
require('./event_emitter')
require('./utils')
require('./modal')
require('./notif')
require('./appcommon')
require('./demo')
require('./lang')
require('./wifi')
require('./term_conn')
require('./term_input')
require('./term_screen')
require('./term_upload')
require('./debug_screen')
require('./soft_keyboard')
require('./term')
window.termInit = require('./term')

@ -5,4 +5,4 @@ let _tr = {
"wifi.enter_passwd": "Enter password for \":ssid:\""
};
function tr (key) { return _tr[key] || '?' + key + '?' }
module.exports = function tr (key) { return _tr[key] || '?' + key + '?' }

@ -1,27 +1,28 @@
const $ = require('./lib/chibi')
/** Module for toggling a modal overlay */
(function () {
let modal = {}
let curCloseCb = null
let modal = {}
let curCloseCb = null
modal.show = function (sel, closeCb) {
modal.show = function (sel, closeCb) {
let $m = $(sel)
$m.removeClass('hidden visible')
setTimeout(function () {
$m.addClass('visible')
}, 1)
curCloseCb = closeCb
}
}
modal.hide = function (sel) {
modal.hide = function (sel) {
let $m = $(sel)
$m.removeClass('visible')
setTimeout(function () {
$m.addClass('hidden')
if (curCloseCb) curCloseCb()
}, 500) // transition time
}
}
modal.init = function () {
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
@ -38,7 +39,6 @@
modal.hide('.Modal')
}
})
}
}
window.Modal = modal
})()
module.exports = modal

@ -1,45 +1,46 @@
window.Notify = (function () {
let nt = {}
const sel = '#notif'
let $balloon
const $ = require('./lib/chibi')
const modal = require('./modal')
let timerHideBegin // timeout to start hiding (transition)
let timerHideEnd // timeout to add the hidden class
let timerCanCancel
let canCancel = false
let nt = {}
const sel = '#notif'
let $balloon
let stopTimeouts = function () {
let timerHideBegin // timeout to start hiding (transition)
let timerHideEnd // timeout to add the hidden class
let canCancel = false
let stopTimeouts = function () {
clearTimeout(timerHideBegin)
clearTimeout(timerHideEnd)
}
}
nt.show = function (message, timeout, isError) {
nt.show = function (message, timeout, isError) {
$balloon.toggleClass('error', isError === true)
$balloon.html(message)
Modal.show($balloon)
modal.show($balloon)
stopTimeouts()
if (undef(timeout) || timeout === null || timeout <= 0) {
if (!timeout || timeout <= 0) {
timeout = 2500
}
timerHideBegin = setTimeout(nt.hide, timeout)
canCancel = false
timerCanCancel = setTimeout(function () {
setTimeout(() => {
canCancel = true
}, 500)
}
}
nt.hide = function () {
nt.hide = function () {
let $m = $(sel)
$m.removeClass('visible')
timerHideEnd = setTimeout(function () {
$m.addClass('hidden')
}, 250) // transition time
}
}
nt.init = function () {
nt.init = function () {
$balloon = $(sel)
// close by click outside
@ -59,7 +60,6 @@ window.Notify = (function () {
stopTimeouts()
$balloon.removeClass('hidden').addClass('visible')
})
}
}
return nt
})()
module.exports = nt

@ -1,4 +1,6 @@
window.initSoftKeyboard = function (screen, input) {
const { qs } = require('./utils')
module.exports = function (screen, input) {
const keyInput = qs('#softkb-input')
if (!keyInput) return // abort, we're not on the terminal page
@ -33,7 +35,6 @@ window.initSoftKeyboard = function (screen, input) {
// that deals with the input composition events.
let lastCompositionString = ''
let compositing = false
// sends the difference between the last and the new composition string
let sendInputDelta = function (newValue) {
@ -96,12 +97,10 @@ window.initSoftKeyboard = function (screen, input) {
keyInput.addEventListener('compositionstart', e => {
lastCompositionString = ''
compositing = true
})
keyInput.addEventListener('compositionend', e => {
lastCompositionString = ''
compositing = false
keyInput.value = ''
})

@ -1,9 +1,18 @@
const { qs, mk } = require('./utils')
const Notify = require('./notif')
const TermScreen = require('./term_screen')
const TermConnection = require('./term_conn')
const TermInput = require('./term_input')
const TermUpload = require('./term_upload')
const initSoftKeyboard = require('./soft_keyboard')
const attachDebugScreen = require('./debug_screen')
/** Init the terminal sub-module - called from HTML */
window.termInit = function ({ labels, theme, allFn }) {
module.exports = function ({ labels, theme, allFn }) {
const screen = new TermScreen()
const conn = new Conn(screen)
const input = Input(conn, screen)
const termUpload = TermUpl(conn, input, screen)
const conn = new TermConnection(screen)
const input = TermInput(conn, screen)
const termUpload = TermUpload(conn, input, screen)
screen.input = input
input.termUpload = termUpload
@ -39,8 +48,8 @@ window.termInit = function ({ labels, theme, allFn }) {
qs('#screen').appendChild(screen.canvas)
screen.load(labels, theme) // load labels and theme
window.initSoftKeyboard(screen, input)
if (window.attachDebugScreen) window.attachDebugScreen(screen)
initSoftKeyboard(screen, input)
if (attachDebugScreen) attachDebugScreen(screen)
let isFullscreen = false
let fitScreen = false
@ -75,10 +84,10 @@ window.termInit = function ({ labels, theme, allFn }) {
})
// add fullscreen mode & button
if (Element.prototype.requestFullscreen || Element.prototype.webkitRequestFullscreen) {
if (window.Element.prototype.requestFullscreen || window.Element.prototype.webkitRequestFullscreen) {
let checkForFullscreen = function () {
// document.fullscreenElement is not really supported yet, so here's a hack
if (isFullscreen && (innerWidth !== window.screen.width || innerHeight !== window.screen.height)) {
if (isFullscreen && (window.innerWidth !== window.screen.width || window.innerHeight !== window.screen.height)) {
isFullscreen = false
fitScreenIfNeeded()
}

@ -1,5 +1,9 @@
const EventEmitter = require('events')
const $ = require('./lib/chibi')
const demo = require('./demo')
/** Handle connections */
window.Conn = class TermConnection extends EventEmitter {
module.exports = class TermConnection extends EventEmitter {
constructor (screen) {
super()
@ -94,7 +98,7 @@ window.Conn = class TermConnection extends EventEmitter {
send (message) {
if (window._demo) {
if (typeof window.demoInterface !== 'undefined') {
demoInterface.input(message)
demo.input(message)
} else {
console.log(`TX: ${JSON.stringify(message)}`)
}
@ -130,9 +134,9 @@ window.Conn = class TermConnection extends EventEmitter {
init () {
if (window._demo) {
if (typeof window.demoInterface === 'undefined') {
alert('Demoing non-demo build!') // this will catch mistakes when deploying to the website
window.alert('Demoing non-demo build!') // this will catch mistakes when deploying to the website
} else {
demoInterface.init(this.screen)
demo.init(this.screen)
showPage()
}
return
@ -143,7 +147,7 @@ window.Conn = class TermConnection extends EventEmitter {
this.closeSocket()
this.ws = new WebSocket('ws://' + _root + '/term/update.ws')
this.ws = new window.WebSocket('ws://' + window._root + '/term/update.ws')
this.ws.addEventListener('open', (...args) => this.onWSOpen(...args))
this.ws.addEventListener('close', (...args) => this.onWSClose(...args))
this.ws.addEventListener('message', (...args) => this.onWSMessage(...args))
@ -167,7 +171,7 @@ window.Conn = class TermConnection extends EventEmitter {
this.pingInterval = setInterval(() => {
console.log('> ping')
this.emit('ping')
$.get('http://' + _root + '/system/ping', (resp, status) => {
$.get('http://' + window._root + '/system/ping', (resp, status) => {
if (status === 200) {
clearInterval(this.pingInterval)
console.info('Server ready, opening socket…')

@ -1,3 +1,6 @@
const $ = require('./lib/chibi')
const { encode2B } = require('./utils')
/**
* User input
*
@ -14,7 +17,7 @@
* r - mb release
* m - mouse move
*/
window.Input = function (conn, screen) {
module.exports = function (conn, screen) {
// handle for input object
let input

@ -1,3 +1,8 @@
const EventEmitter = require('events')
const $ = require('./lib/chibi')
const { mk, qs, parse2B, parse3B } = require('./utils')
const notify = require('./notif')
// constants for decoding the update blob
const SEQ_REPEAT = 2
const SEQ_SET_COLORS = 3
@ -8,7 +13,7 @@ const SEQ_SET_BG = 6
const SELECTION_BG = '#b2d7fe'
const SELECTION_FG = '#333'
window.TermScreen = class TermScreen extends EventEmitter {
module.exports = class TermScreen extends EventEmitter {
constructor () {
super()
@ -472,8 +477,6 @@ window.TermScreen = class TermScreen extends EventEmitter {
const {
width,
height,
gridScaleX,
gridScaleY,
fitIntoWidth,
fitIntoHeight
} = this.window
@ -632,9 +635,9 @@ window.TermScreen = class TermScreen extends EventEmitter {
textarea.value = selectedText
textarea.select()
if (document.execCommand('copy')) {
Notify.show('Copied to clipboard')
notify.show('Copied to clipboard')
} else {
Notify.show('Failed to copy')
notify.show('Failed to copy')
}
document.body.removeChild(textarea)
}
@ -899,8 +902,6 @@ window.TermScreen = class TermScreen extends EventEmitter {
width,
height,
devicePixelRatio,
gridScaleX,
gridScaleY,
statusScreen
} = this.window
@ -913,8 +914,6 @@ window.TermScreen = class TermScreen extends EventEmitter {
const charSize = this.getCharSize()
const { width: cellWidth, height: cellHeight } = this.getCellSize()
const screenWidth = width * cellWidth
const screenHeight = height * cellHeight
const screenLength = width * height
ctx.setTransform(devicePixelRatio, 0, 0, devicePixelRatio, 0, 0)
@ -1042,7 +1041,7 @@ window.TermScreen = class TermScreen extends EventEmitter {
// pass 1: backgrounds
for (let font of fontGroups.keys()) {
for (let data of fontGroups.get(font)) {
let [cell, x, y, text, fg, bg, attrs, isCursor] = data
let [cell, x, y, text, , bg] = data
if (redrawMap.get(cell)) {
this.drawBackground({ x, y, cellWidth, cellHeight, bg })
@ -1128,7 +1127,8 @@ window.TermScreen = class TermScreen extends EventEmitter {
const {
fontFamily,
width,
height
height,
devicePixelRatio
} = this.window
// reset drawnScreen to force redraw when statusScreen is disabled
@ -1185,7 +1185,7 @@ window.TermScreen = class TermScreen extends EventEmitter {
drawTimerLoop (threadID) {
if (!threadID || threadID !== this._drawTimerThread) return
requestAnimationFrame(() => this.drawTimerLoop(threadID))
window.requestAnimationFrame(() => this.drawTimerLoop(threadID))
this.draw('draw-loop')
}
@ -1296,7 +1296,7 @@ window.TermScreen = class TermScreen extends EventEmitter {
this.screenAttrs = new Array(screenLength).fill(' ')
}
let strArray = !undef(Array.from) ? Array.from(str) : str.split('')
let strArray = Array.from ? Array.from(str) : str.split('')
const MASK_LINE_ATTR = 0xC8
const MASK_BLINK = 1 << 4
@ -1392,7 +1392,7 @@ window.TermScreen = class TermScreen extends EventEmitter {
let label = pieces[i + 1].trim()
// if empty string, use the "dim" effect and put nbsp instead to
// stretch the button vertically
button.innerHTML = label ? esc(label) : '&nbsp;'
button.innerHTML = label ? $.htmlEscape(label) : '&nbsp;'
button.style.opacity = label ? 1 : 0.2
})
}
@ -1403,17 +1403,17 @@ window.TermScreen = class TermScreen extends EventEmitter {
*/
showNotification (text) {
console.info(`Notification: ${text}`)
if (Notification && Notification.permission === 'granted') {
let notification = new Notification('ESPTerm', {
if (window.Notification && window.Notification.permission === 'granted') {
let notification = new window.Notification('ESPTerm', {
body: text
})
notification.addEventListener('click', () => window.focus())
} else {
if (Notification && Notification.permission !== 'denied') {
Notification.requestPermission()
if (window.Notification && window.Notification.permission !== 'denied') {
window.Notification.requestPermission()
} else {
// Fallback using the built-in notification balloon
Notify.show(text)
notify.show(text)
}
}
}
@ -1500,7 +1500,7 @@ window.TermScreen = class TermScreen extends EventEmitter {
surrOsc.stop(startTime + 0.8)
let loop = function () {
if (audioCtx.currentTime < startTime + 0.8) requestAnimationFrame(loop)
if (audioCtx.currentTime < startTime + 0.8) window.requestAnimationFrame(loop)
mainGain.gain.value *= 0.8
surrGain.gain.value *= 0.8
}

@ -1,5 +1,9 @@
const $ = require('./lib/chibi')
const { qs } = require('./utils')
const modal = require('./modal')
/** File upload utility */
window.TermUpl = function (conn, input, screen) {
module.exports = function (conn, input, screen) {
let lines, // array of lines without newlines
line_i, // current line index
fuTout, // timeout handle for line sending
@ -14,7 +18,7 @@ window.TermUpl = function (conn, input, screen) {
function openUploadDialog () {
updateStatus('Ready...')
Modal.show('#fu_modal', onDialogClose)
modal.show('#fu_modal', onDialogClose)
$('#fu_form').toggleClass('busy', false)
input.blockKeys(true)
}
@ -125,19 +129,19 @@ window.TermUpl = function (conn, input, screen) {
}
function fuClose () {
Modal.hide('#fu_modal')
modal.hide('#fu_modal')
}
return {
init: function () {
qs('#fu_file').addEventListener('change', function (evt) {
let reader = new FileReader()
let reader = new window.FileReader()
let file = evt.target.files[0]
let ftype = file.type || 'application/octet-stream'
console.log('Selected file type: ' + ftype)
if (!ftype.match(/text\/.*|application\/(json|csv|.*xml.*|.*script.*|x-php)/)) {
// Deny load of blobs like img - can crash browser and will get corrupted anyway
if (!confirm(`This does not look like a text file: ${ftype}\nReally load?`)) {
if (!window.confirm(`This does not look like a text file: ${ftype}\nReally load?`)) {
qs('#fu_file').value = ''
return
}

@ -1,48 +1,25 @@
/** Make a node */
function mk (e) {
exports.mk = function mk (e) {
return document.createElement(e)
}
/** Find one by query */
function qs (s) {
exports.qs = function qs (s) {
return document.querySelector(s)
}
/** Find all by query */
function qsa (s) {
exports.qsa = function qsa (s) {
return document.querySelectorAll(s)
}
/** Convert any to bool safely */
function bool (x) {
exports.bool = function bool (x) {
return (x === 1 || x === '1' || x === true || x === 'true')
}
/**
* Filter 'spacebar' and 'return' from keypress handler,
* and when they're pressed, fire the callback.
* use $(...).on('keypress', cr(handler))
*/
function cr (hdl) {
return function (e) {
if (e.which === 10 || e.which === 13 || e.which === 32) {
hdl()
}
}
}
/** HTML escape */
function esc (str) {
return $.htmlEscape(str)
}
/** Check for undefined */
function undef (x) {
return typeof x == 'undefined'
}
/** Safe json parse */
function jsp (str) {
exports.jsp = function jsp (str) {
try {
return JSON.parse(str)
} catch (e) {
@ -51,33 +28,28 @@ function jsp (str) {
}
}
/** Create a character from ASCII code */
function Chr (n) {
return String.fromCharCode(n)
}
/** Decode number from 2B encoding */
function parse2B (s, i = 0) {
exports.parse2B = 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) {
exports.parse3B = 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) {
exports.encode2B = function encode2B (n) {
let lsb, msb
lsb = (n % 127)
n = ((n - lsb) / 127)
lsb += 1
msb = (n + 1)
return Chr(lsb) + Chr(msb)
return String.fromCharCode(lsb) + String.fromCharCode(msb)
}
/** Encode using 3B encoding, returns string. */
function encode3B (n) {
exports.encode3B = function encode3B (n) {
let lsb, msb, xsb
lsb = (n % 127)
n = (n - lsb) / 127
@ -86,5 +58,5 @@ function encode3B (n) {
n = (n - msb) / 127
msb += 1
xsb = (n + 1)
return Chr(lsb) + Chr(msb) + Chr(xsb)
return String.fromCharCode(lsb) + String.fromCharCode(msb) + String.fromCharCode(xsb)
}

@ -1,4 +1,8 @@
(function (w) {
const $ = require('./lib/chibi')
const { mk, bool } = require('./utils')
const tr = require('./lang')
;(function (w) {
const authStr = ['Open', 'WEP', 'WPA', 'WPA2', 'WPA/WPA2']
let curSSID
@ -15,8 +19,8 @@
$('#sta-nw').toggleClass('hidden', name.length === 0)
$('#sta-nw-nil').toggleClass('hidden', name.length > 0)
$('#sta-nw .essid').html(esc(name))
const nopw = undef(password) || password.length === 0
$('#sta-nw .essid').html($.htmlEscape(name))
const nopw = !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'))
@ -96,7 +100,7 @@
if (+$th.data('pwd')) {
// this AP needs a password
conn_pass = prompt(tr('wifi.enter_passwd').replace(':ssid:', conn_ssid))
conn_pass = window.prompt(tr('wifi.enter_passwd').replace(':ssid:', conn_ssid))
if (!conn_pass) return
}
@ -120,10 +124,10 @@
/** Ask the CGI what APs are visible (async) */
function scanAPs () {
if (_demo) {
onScan(_demo_aps, 200)
if (window._demo) {
onScan(window._demo_aps, 200)
} else {
$.get('http://' + _root + '/cfg/wifi/scan', onScan)
$.get('http://' + window._root + '/cfg/wifi/scan', onScan)
}
}

@ -13,8 +13,7 @@
"webpack": "^3.6.0"
},
"scripts": {
"babel": "babel $@",
"minify": "babel-minify $@",
"webpack": "webpack $@",
"sass": "node-sass $@"
}
}

@ -2,9 +2,9 @@
<script>
// Workaround for badly loaded page
setTimeout(function() {
if (typeof termInit == 'undefined' || typeof $ == 'undefined') {
console.error("Page load failed, refreshing…");
location.reload(true);
if (typeof termInit == 'undefined') {
console.error("Page load failed, refreshing…")
location.reload(true)
}
}, 3000);
</script>

Loading…
Cancel
Save