parent
7e1611ff7a
commit
79664f56a6
@ -1,25 +1,29 @@ |
||||
#!/bin/bash |
||||
|
||||
echo "Packing JS..." |
||||
echo 'Packing JS...' |
||||
|
||||
cat jssrc/chibi.js \ |
||||
jssrc/keymaster.js \ |
||||
jssrc/utils.js \ |
||||
jssrc/modal.js \ |
||||
jssrc/notif.js \ |
||||
jssrc/appcommon.js \ |
||||
jssrc/lang.js \ |
||||
jssrc/wifi.js \ |
||||
jssrc/term_* \ |
||||
jssrc/term.js \ |
||||
echo ';' > ';' |
||||
cat jssrc/lib/chibi.js ';' \ |
||||
jssrc/lib/keymaster.js ';' \ |
||||
jssrc/lib/polyfills.js ';' \ |
||||
jssrc/utils.js ';' \ |
||||
jssrc/modal.js ';' \ |
||||
jssrc/notif.js ';' \ |
||||
jssrc/appcommon.js ';' \ |
||||
jssrc/lang.js ';' \ |
||||
jssrc/wifi.js ';' \ |
||||
jssrc/term_* ';' \ |
||||
jssrc/term.js ';' \ |
||||
jssrc/soft_keyboard.js | npm run --silent minify > js/app.js |
||||
rm ';' |
||||
|
||||
echo "Building CSS..." |
||||
echo 'Building CSS...' |
||||
|
||||
npm run sass -- --output-style compressed sass/app.scss css/app.css |
||||
|
||||
echo "Building HTML..." |
||||
echo 'Building HTML...' |
||||
|
||||
php ./build_html.php |
||||
php ./dump_js_lang.php |
||||
php ./compile_html.php |
||||
|
||||
echo "ESPTerm front-end ready" |
||||
echo 'ESPTerm front-end ready' |
||||
|
@ -1,8 +1,8 @@ |
||||
// Generated from PHP locale file
|
||||
var _tr = { |
||||
let _tr = { |
||||
"wifi.connected_ip_is": "Connected, IP is ", |
||||
"wifi.not_conn": "Not connected.", |
||||
"wifi.enter_passwd": "Enter password for \":ssid:\"" |
||||
}; |
||||
|
||||
function tr(key) { return _tr[key] || '?'+key+'?'; } |
||||
function tr (key) { return _tr[key] || '?' + key + '?' } |
||||
|
@ -0,0 +1,63 @@ |
||||
/*! http://mths.be/fromcodepoint v0.1.0 by @mathias */ |
||||
if (!String.fromCodePoint) { |
||||
(function () { |
||||
var defineProperty = (function () { |
||||
// IE 8 only supports `Object.defineProperty` on DOM elements
|
||||
try { |
||||
var object = {}; |
||||
var $defineProperty = Object.defineProperty; |
||||
var result = $defineProperty(object, object, object) && $defineProperty; |
||||
} catch (error) { |
||||
} |
||||
return result; |
||||
}()); |
||||
var stringFromCharCode = String.fromCharCode; |
||||
var floor = Math.floor; |
||||
var fromCodePoint = function () { |
||||
var MAX_SIZE = 0x4000; |
||||
var codeUnits = []; |
||||
var highSurrogate; |
||||
var lowSurrogate; |
||||
var index = -1; |
||||
var length = arguments.length; |
||||
if (!length) { |
||||
return ''; |
||||
} |
||||
var result = ''; |
||||
while (++index < length) { |
||||
var codePoint = Number(arguments[index]); |
||||
if ( |
||||
!isFinite(codePoint) || // `NaN`, `+Infinity`, or `-Infinity`
|
||||
codePoint < 0 || // not a valid Unicode code point
|
||||
codePoint > 0x10FFFF || // not a valid Unicode code point
|
||||
floor(codePoint) != codePoint // not an integer
|
||||
) { |
||||
throw RangeError('Invalid code point: ' + codePoint); |
||||
} |
||||
if (codePoint <= 0xFFFF) { // BMP code point
|
||||
codeUnits.push(codePoint); |
||||
} else { // Astral code point; split in surrogate halves
|
||||
// http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
|
||||
codePoint -= 0x10000; |
||||
highSurrogate = (codePoint >> 10) + 0xD800; |
||||
lowSurrogate = (codePoint % 0x400) + 0xDC00; |
||||
codeUnits.push(highSurrogate, lowSurrogate); |
||||
} |
||||
if (index + 1 == length || codeUnits.length > MAX_SIZE) { |
||||
result += stringFromCharCode.apply(null, codeUnits); |
||||
codeUnits.length = 0; |
||||
} |
||||
} |
||||
return result; |
||||
}; |
||||
if (defineProperty) { |
||||
defineProperty(String, 'fromCodePoint', { |
||||
'value': fromCodePoint, |
||||
'configurable': true, |
||||
'writable': true |
||||
}); |
||||
} else { |
||||
String.fromCodePoint = fromCodePoint; |
||||
} |
||||
}()); |
||||
} |
@ -1,44 +1,44 @@ |
||||
/** Module for toggling a modal overlay */ |
||||
(function () { |
||||
var modal = {}; |
||||
var curCloseCb = null; |
||||
let modal = {} |
||||
let curCloseCb = null |
||||
|
||||
modal.show = function (sel, closeCb) { |
||||
var $m = $(sel); |
||||
$m.removeClass('hidden visible'); |
||||
let $m = $(sel) |
||||
$m.removeClass('hidden visible') |
||||
setTimeout(function () { |
||||
$m.addClass('visible'); |
||||
}, 1); |
||||
curCloseCb = closeCb; |
||||
}; |
||||
$m.addClass('visible') |
||||
}, 1) |
||||
curCloseCb = closeCb |
||||
} |
||||
|
||||
modal.hide = function (sel) { |
||||
var $m = $(sel); |
||||
$m.removeClass('visible'); |
||||
let $m = $(sel) |
||||
$m.removeClass('visible') |
||||
setTimeout(function () { |
||||
$m.addClass('hidden'); |
||||
if (curCloseCb) curCloseCb(); |
||||
}, 500); // transition time
|
||||
}; |
||||
$m.addClass('hidden') |
||||
if (curCloseCb) curCloseCb() |
||||
}, 500) // transition time
|
||||
} |
||||
|
||||
modal.init = function () { |
||||
// close modal by click outside the dialog
|
||||
$('.Modal').on('click', function () { |
||||
if ($(this).hasClass('no-close')) return; // this is a no-close modal
|
||||
modal.hide(this); |
||||
}); |
||||
if ($(this).hasClass('no-close')) return // this is a no-close modal
|
||||
modal.hide(this) |
||||
}) |
||||
|
||||
$('.Dialog').on('click', function (e) { |
||||
e.stopImmediatePropagation(); |
||||
}); |
||||
e.stopImmediatePropagation() |
||||
}) |
||||
|
||||
// Hide all modals on esc
|
||||
$(window).on('keydown', function (e) { |
||||
if (e.which == 27) { |
||||
modal.hide('.Modal'); |
||||
modal.hide('.Modal') |
||||
} |
||||
}) |
||||
} |
||||
}); |
||||
}; |
||||
|
||||
window.Modal = modal; |
||||
})(); |
||||
window.Modal = modal |
||||
})() |
||||
|
@ -1,32 +1,35 @@ |
||||
(function (nt) { |
||||
var sel = '#notif'; |
||||
window.Notify = (function () { |
||||
let nt = {} |
||||
const sel = '#notif' |
||||
|
||||
var hideTmeo1; // timeout to start hiding (transition)
|
||||
var hideTmeo2; // timeout to add the hidden class
|
||||
let hideTmeo1 // timeout to start hiding (transition)
|
||||
let hideTmeo2 // timeout to add the hidden class
|
||||
|
||||
nt.show = function (message, timeout) { |
||||
$(sel).html(message); |
||||
Modal.show(sel); |
||||
$(sel).html(message) |
||||
Modal.show(sel) |
||||
|
||||
clearTimeout(hideTmeo1); |
||||
clearTimeout(hideTmeo2); |
||||
clearTimeout(hideTmeo1) |
||||
clearTimeout(hideTmeo2) |
||||
|
||||
if (undef(timeout)) timeout = 2500; |
||||
if (undef(timeout)) timeout = 2500 |
||||
|
||||
hideTmeo1 = setTimeout(nt.hide, timeout); |
||||
}; |
||||
hideTmeo1 = setTimeout(nt.hide, timeout) |
||||
} |
||||
|
||||
nt.hide = function () { |
||||
var $m = $(sel); |
||||
$m.removeClass('visible'); |
||||
let $m = $(sel) |
||||
$m.removeClass('visible') |
||||
hideTmeo2 = setTimeout(function () { |
||||
$m.addClass('hidden'); |
||||
}, 250); // transition time
|
||||
}; |
||||
$m.addClass('hidden') |
||||
}, 250) // transition time
|
||||
} |
||||
|
||||
nt.init = function () { |
||||
$(sel).on('click', function () { |
||||
nt.hide(this); |
||||
}); |
||||
}; |
||||
})(window.Notify = {}); |
||||
nt.hide(this) |
||||
}) |
||||
} |
||||
|
||||
return nt |
||||
})() |
||||
|
@ -1,87 +1,87 @@ |
||||
$.ready(() => { |
||||
const input = qs('#softkb-input'); |
||||
if (!input) return; // abort, we're not on the terminal page
|
||||
const input = qs('#softkb-input') |
||||
if (!input) return // abort, we're not on the terminal page
|
||||
|
||||
let keyboardOpen = false; |
||||
let keyboardOpen = false |
||||
|
||||
let updateInputPosition = function () { |
||||
if (!keyboardOpen) return; |
||||
if (!keyboardOpen) return |
||||
|
||||
let [x, y] = Screen.gridToScreen(Screen.cursor.x, Screen.cursor.y); |
||||
let [x, y] = Screen.gridToScreen(Screen.cursor.x, Screen.cursor.y) |
||||
input.style.transform = `translate(${x}px, ${y}px)` |
||||
}; |
||||
} |
||||
|
||||
input.addEventListener('focus', () => { |
||||
keyboardOpen = true; |
||||
keyboardOpen = true |
||||
updateInputPosition() |
||||
}); |
||||
input.addEventListener('blur', () => (keyboardOpen = false)); |
||||
Screen.on('cursor-moved', updateInputPosition); |
||||
}) |
||||
input.addEventListener('blur', () => (keyboardOpen = false)) |
||||
Screen.on('cursor-moved', updateInputPosition) |
||||
|
||||
window.kbOpen = function openSoftKeyboard (open) { |
||||
keyboardOpen = open; |
||||
updateInputPosition(); |
||||
if (open) input.focus(); |
||||
keyboardOpen = open |
||||
updateInputPosition() |
||||
if (open) input.focus() |
||||
else input.blur() |
||||
}; |
||||
} |
||||
|
||||
let lastCompositionString = ''; |
||||
let compositing = false; |
||||
let lastCompositionString = '' |
||||
let compositing = false |
||||
|
||||
let sendInputDelta = function (newValue) { |
||||
let resend = false; |
||||
let resend = false |
||||
if (newValue.length > lastCompositionString.length) { |
||||
if (newValue.startsWith(lastCompositionString)) { |
||||
// characters have been added at the end
|
||||
Input.sendString(newValue.substr(lastCompositionString.length)) |
||||
} else resend = true; |
||||
} else resend = true |
||||
} else if (newValue.length < lastCompositionString.length) { |
||||
if (lastCompositionString.startsWith(newValue)) { |
||||
// characters have been removed at the end
|
||||
Input.sendString('\b'.repeat(lastCompositionString.length - |
||||
newValue.length)) |
||||
} else resend = true; |
||||
} else if (newValue !== lastCompositionString) resend = true; |
||||
} else resend = true |
||||
} else if (newValue !== lastCompositionString) resend = true |
||||
|
||||
if (resend) { |
||||
// the entire string changed; resend everything
|
||||
Input.sendString('\b'.repeat(lastCompositionString.length) + |
||||
newValue) |
||||
} |
||||
lastCompositionString = newValue; |
||||
}; |
||||
lastCompositionString = newValue |
||||
} |
||||
|
||||
input.addEventListener('keydown', e => { |
||||
if (e.key === 'Unidentified') return; |
||||
if (e.key === 'Unidentified') return |
||||
|
||||
e.preventDefault(); |
||||
input.value = ''; |
||||
e.preventDefault() |
||||
input.value = '' |
||||
|
||||
if (e.key === 'Backspace') Input.sendString('\b'); |
||||
if (e.key === 'Backspace') Input.sendString('\b') |
||||
else if (e.key === 'Enter') Input.sendString('\x0d') |
||||
}); |
||||
}) |
||||
input.addEventListener('input', e => { |
||||
e.stopPropagation(); |
||||
e.stopPropagation() |
||||
|
||||
if (e.isComposing) { |
||||
sendInputDelta(e.data); |
||||
sendInputDelta(e.data) |
||||
} else { |
||||
if (e.data) Input.sendString(e.data); |
||||
if (e.data) Input.sendString(e.data) |
||||
else if (e.inputType === 'deleteContentBackward') { |
||||
lastCompositionString = ''; |
||||
sendInputDelta(''); |
||||
lastCompositionString = '' |
||||
sendInputDelta('') |
||||
} |
||||
} |
||||
}); |
||||
}) |
||||
input.addEventListener('compositionstart', e => { |
||||
lastCompositionString = ''; |
||||
compositing = true; |
||||
}); |
||||
lastCompositionString = '' |
||||
compositing = true |
||||
}) |
||||
input.addEventListener('compositionend', e => { |
||||
lastCompositionString = ''; |
||||
compositing = false; |
||||
input.value = ''; |
||||
}); |
||||
lastCompositionString = '' |
||||
compositing = false |
||||
input.value = '' |
||||
}) |
||||
|
||||
Screen.on('open-soft-keyboard', () => input.focus()) |
||||
}); |
||||
}) |
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@ |
||||
/** Init the terminal sub-module - called from HTML */ |
||||
window.termInit = function () { |
||||
Conn.init(); |
||||
Input.init(); |
||||
TermUpl.init(); |
||||
}; |
||||
Conn.init() |
||||
Input.init() |
||||
TermUpl.init() |
||||
} |
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,146 +1,146 @@ |
||||
/** File upload utility */ |
||||
var TermUpl = (function () { |
||||
var lines, // array of lines without newlines
|
||||
window.TermUpl = (function () { |
||||
let lines, // array of lines without newlines
|
||||
line_i, // current line index
|
||||
fuTout, // timeout handle for line sending
|
||||
send_delay_ms, // delay between lines (ms)
|
||||
nl_str, // newline string to use
|
||||
curLine, // current line (when using fuOil)
|
||||
inline_pos; // Offset in line (for long lines)
|
||||
inline_pos // Offset in line (for long lines)
|
||||
|
||||
// lines longer than this are split to chunks
|
||||
// sending a super-ling string through the socket is not a good idea
|
||||
var MAX_LINE_LEN = 128; |
||||
const MAX_LINE_LEN = 128 |
||||
|
||||
function fuOpen() { |
||||
fuStatus("Ready..."); |
||||
Modal.show('#fu_modal', onClose); |
||||
$('#fu_form').toggleClass('busy', false); |
||||
Input.blockKeys(true); |
||||
function fuOpen () { |
||||
fuStatus('Ready...') |
||||
Modal.show('#fu_modal', onClose) |
||||
$('#fu_form').toggleClass('busy', false) |
||||
Input.blockKeys(true) |
||||
} |
||||
|
||||
function onClose() { |
||||
console.log("Upload modal closed."); |
||||
clearTimeout(fuTout); |
||||
line_i = 0; |
||||
Input.blockKeys(false); |
||||
function onClose () { |
||||
console.log('Upload modal closed.') |
||||
clearTimeout(fuTout) |
||||
line_i = 0 |
||||
Input.blockKeys(false) |
||||
} |
||||
|
||||
function fuStatus(msg) { |
||||
qs('#fu_prog').textContent = msg; |
||||
function fuStatus (msg) { |
||||
qs('#fu_prog').textContent = msg |
||||
} |
||||
|
||||
function fuSend() { |
||||
var v = qs('#fu_text').value; |
||||
function fuSend () { |
||||
let v = qs('#fu_text').value |
||||
if (!v.length) { |
||||
fuClose(); |
||||
return; |
||||
fuClose() |
||||
return |
||||
} |
||||
|
||||
lines = v.split('\n'); |
||||
line_i = 0; |
||||
inline_pos = 0; // offset in line
|
||||
send_delay_ms = qs('#fu_delay').value; |
||||
lines = v.split('\n') |
||||
line_i = 0 |
||||
inline_pos = 0 // offset in line
|
||||
send_delay_ms = qs('#fu_delay').value |
||||
|
||||
// sanitize - 0 causes overflows
|
||||
if (send_delay_ms < 0) { |
||||
send_delay_ms = 0; |
||||
qs('#fu_delay').value = send_delay_ms; |
||||
send_delay_ms = 0 |
||||
qs('#fu_delay').value = send_delay_ms |
||||
} |
||||
|
||||
nl_str = { |
||||
'CR': '\r', |
||||
'LF': '\n', |
||||
'CRLF': '\r\n', |
||||
}[qs('#fu_crlf').value]; |
||||
'CRLF': '\r\n' |
||||
}[qs('#fu_crlf').value] |
||||
|
||||
$('#fu_form').toggleClass('busy', true); |
||||
fuStatus("Starting..."); |
||||
fuSendLine(); |
||||
$('#fu_form').toggleClass('busy', true) |
||||
fuStatus('Starting...') |
||||
fuSendLine() |
||||
} |
||||
|
||||
function fuSendLine() { |
||||
function fuSendLine () { |
||||
if (!$('#fu_modal').hasClass('visible')) { |
||||
// Modal is closed, cancel
|
||||
return; |
||||
return |
||||
} |
||||
|
||||
if (!Conn.canSend()) { |
||||
// postpone
|
||||
fuTout = setTimeout(fuSendLine, 1); |
||||
return; |
||||
fuTout = setTimeout(fuSendLine, 1) |
||||
return |
||||
} |
||||
|
||||
if (inline_pos == 0) { |
||||
curLine = lines[line_i++] + nl_str; |
||||
curLine = lines[line_i++] + nl_str |
||||
} |
||||
|
||||
var chunk; |
||||
let chunk |
||||
if ((curLine.length - inline_pos) <= MAX_LINE_LEN) { |
||||
chunk = curLine.substr(inline_pos, MAX_LINE_LEN); |
||||
inline_pos = 0; |
||||
chunk = curLine.substr(inline_pos, MAX_LINE_LEN) |
||||
inline_pos = 0 |
||||
} else { |
||||
chunk = curLine.substr(inline_pos, MAX_LINE_LEN); |
||||
inline_pos += MAX_LINE_LEN; |
||||
chunk = curLine.substr(inline_pos, MAX_LINE_LEN) |
||||
inline_pos += MAX_LINE_LEN |
||||
} |
||||
|
||||
if (!Input.sendString(chunk)) { |
||||
fuStatus("FAILED!"); |
||||
return; |
||||
fuStatus('FAILED!') |
||||
return |
||||
} |
||||
|
||||
var all = lines.length; |
||||
let all = lines.length |
||||
|
||||
fuStatus(line_i + " / " + all + " (" + (Math.round((line_i / all) * 1000) / 10) + "%)"); |
||||
fuStatus(line_i + ' / ' + all + ' (' + (Math.round((line_i / all) * 1000) / 10) + '%)') |
||||
|
||||
if (lines.length > line_i || inline_pos > 0) { |
||||
fuTout = setTimeout(fuSendLine, send_delay_ms); |
||||
fuTout = setTimeout(fuSendLine, send_delay_ms) |
||||
} else { |
||||
closeWhenReady(); |
||||
closeWhenReady() |
||||
} |
||||
} |
||||
|
||||
function closeWhenReady() { |
||||
function closeWhenReady () { |
||||
if (!Conn.canSend()) { |
||||
// stuck in XOFF still, wait to process...
|
||||
fuStatus("Waiting for Tx buffer..."); |
||||
setTimeout(closeWhenReady, 100); |
||||
fuStatus('Waiting for Tx buffer...') |
||||
setTimeout(closeWhenReady, 100) |
||||
} else { |
||||
fuStatus("Done."); |
||||
fuStatus('Done.') |
||||
// delay to show it
|
||||
setTimeout(function () { |
||||
fuClose(); |
||||
}, 100); |
||||
fuClose() |
||||
}, 100) |
||||
} |
||||
} |
||||
|
||||
function fuClose() { |
||||
Modal.hide('#fu_modal'); |
||||
function fuClose () { |
||||
Modal.hide('#fu_modal') |
||||
} |
||||
|
||||
return { |
||||
init: function () { |
||||
qs('#fu_file').addEventListener('change', function (evt) { |
||||
var reader = new FileReader(); |
||||
var file = evt.target.files[0]; |
||||
console.log("Selected file type: " + file.type); |
||||
let reader = new FileReader() |
||||
let file = evt.target.files[0] |
||||
console.log('Selected file type: ' + file.type) |
||||
if (!file.type.match(/text\/.*|application\/(json|csv|.*xml.*|.*script.*)/)) { |
||||
// Deny load of blobs like img - can crash browser and will get corrupted anyway
|
||||
if (!confirm("This does not look like a text file: " + file.type + "\nReally load?")) { |
||||
qs('#fu_file').value = ''; |
||||
return; |
||||
if (!confirm('This does not look like a text file: ' + file.type + '\nReally load?')) { |
||||
qs('#fu_file').value = '' |
||||
return |
||||
} |
||||
} |
||||
reader.onload = function (e) { |
||||
var txt = e.target.result.replace(/[\r\n]+/, '\n'); |
||||
qs('#fu_text').value = txt; |
||||
}; |
||||
console.log("Loading file..."); |
||||
reader.readAsText(file); |
||||
}, false); |
||||
const txt = e.target.result.replace(/[\r\n]+/, '\n') |
||||
qs('#fu_text').value = txt |
||||
} |
||||
console.log('Loading file...') |
||||
reader.readAsText(file) |
||||
}, false) |
||||
}, |
||||
close: fuClose, |
||||
start: fuSend, |
||||
open: fuOpen, |
||||
open: fuOpen |
||||
} |
||||
})(); |
||||
})() |
||||
|
Loading…
Reference in new issue