ESPTerm web interface submodule, separated to make testing and development easier
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
espterm-front-end/js/term/upload.js

183 lines
4.5 KiB

const $ = require('../lib/chibi')
const { qs } = require('../utils')
const modal = require('../modal')
/** File upload utility */
module.exports = function (conn, input, screen) {
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)
// lines longer than this are split to chunks
// sending a super-ling string through the socket is not a good idea
const MAX_LINE_LEN = 128
function openUploadDialog () {
updateStatus('Ready...')
modal.show('#fu_modal', onDialogClose)
$('#fu_form').toggleClass('busy', false)
input.blockKeys(true)
}
function onDialogClose () {
console.log('Upload modal closed.')
clearTimeout(fuTout)
line_i = 0
input.blockKeys(false)
}
function updateStatus (msg) {
qs('#fu_prog').textContent = msg
}
function startUpload () {
let 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)
updateStatus('Starting...')
uploadLine()
}
function uploadLine () {
if (!$('#fu_modal').hasClass('visible')) {
// Modal is closed, cancel
return
}
if (!conn.canSend()) {
// postpone
fuTout = setTimeout(uploadLine, 1)
return
}
if (inline_pos === 0) {
curLine = ''
if (line_i === 0) {
if (screen.bracketedPaste) {
curLine = '\x1b[200~'
}
}
curLine += lines[line_i++] + nl_str
if (line_i === lines.length) {
if (screen.bracketedPaste) {
curLine += '\x1b[201~'
}
}
}
let maxChunk = +qs('#fu_chunk').value
if (maxChunk === 0 || maxChunk > MAX_LINE_LEN) {
maxChunk = MAX_LINE_LEN
}
let chunk
if ((curLine.length - inline_pos) <= maxChunk) {
chunk = curLine.substr(inline_pos, maxChunk)
inline_pos = 0
} else {
chunk = curLine.substr(inline_pos, maxChunk)
inline_pos += maxChunk
}
if (!input.sendString(chunk)) {
updateStatus('FAILED!')
return
}
let pt = Math.round((line_i / lines.length) * 1000) / 10
updateStatus(`${line_i} / ${lines.length} (${pt}%)`)
if (lines.length > line_i || inline_pos > 0) {
fuTout = setTimeout(uploadLine, send_delay_ms)
} else {
closeWhenReady()
}
}
function closeWhenReady () {
if (!conn.canSend()) {
// stuck in XOFF still, wait to process...
updateStatus('Waiting for Tx buffer...')
setTimeout(closeWhenReady, 100)
} else {
updateStatus('Done.')
// delay to show it
fuClose()
}
}
function fuClose () {
modal.hide('#fu_modal')
}
return {
init: function () {
qs('#fu_file').addEventListener('change', function (evt) {
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 (!window.confirm(`This does not look like a text file: ${ftype}\nReally load?`)) {
qs('#fu_file').value = ''
return
}
}
reader.onload = function (e) {
const txt = e.target.result.replace(/[\r\n]+/, '\n')
qs('#fu_text').value = txt
}
console.log('Loading file...')
reader.readAsText(file)
}, false)
qs('#term-fu-open').addEventListener('click', e => {
e.preventDefault()
openUploadDialog()
})
qs('#term-fu-start').addEventListener('click', e => {
e.preventDefault()
startUpload()
})
qs('#term-fu-close').addEventListener('click', e => {
e.preventDefault()
fuClose()
})
},
open: openUploadDialog,
setContent (content) {
qs('#fu_text').value = content
}
}
}