Merge remote-tracking branch 'origin/work'

pull/2/head
Ondřej Hruška 7 years ago
commit 855d308962
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 11
      base.php
  2. 1
      js/appcommon.js
  3. 220
      js/term/demo.js
  4. 13
      js/term/screen.js
  5. 15
      js/term/screen_attr_bits.js
  6. 63
      js/term/screen_parser.js
  7. 75
      js/term/screen_renderer.js
  8. 3
      lang/cs.php
  9. 1
      lang/en.php
  10. 6
      pages/cfg_term.php
  11. 2
      pages/help/charsets.php
  12. 41
      pages/help/cmd_system.php
  13. 4
      pages/help/sgr_colors.php
  14. 14
      sass/pages/_term.scss

@ -173,9 +173,18 @@ if (!function_exists('load_esp_charsets')) {
$rows = array_map('trim', $rows); $rows = array_map('trim', $rows);
foreach($rows as $j => $v) { foreach($rows as $j => $v) {
$literal = false;
if (strpos($v, '0x') === 0) { if (strpos($v, '0x') === 0) {
// hexa codes
$v = substr($v, 2); $v = substr($v, 2);
$v = hexdec($v); $v = hexdec($v);
} else if (strpos($v, 'u\'\\0\'') === 0) {
// zero
$v = 0;
} else if (strpos($v, 'u\'') === 0) {
// utf8 literals
$v = mb_substr($v, 2, 1, 'utf-8');
$literal = true;
} else { } else {
$v = intval($v); $v = intval($v);
} }
@ -183,7 +192,7 @@ if (!function_exists('load_esp_charsets')) {
$table[] = [ $table[] = [
$ascii, $ascii,
chr($ascii), chr($ascii),
utf8($v==0? $ascii :$v), $literal ? $v : utf8($v==0? $ascii :$v),
]; ];
} }
$cps[$name] = $table; $cps[$name] = $table;

@ -169,6 +169,7 @@ $.ready(function () {
'Server connection failed! Trying again' + 'Server connection failed! Trying again' +
'<span class="anim-dots" style="width:1.5em;text-align:left;display:inline-block">.</span>' '<span class="anim-dots" style="width:1.5em;text-align:left;display:inline-block">.</span>'
qs('#screen').appendChild(bnr) qs('#screen').appendChild(bnr)
qs('#screen').classList.add('failed')
showPage() showPage()
} }
}, 2000) }, 2000)

@ -143,6 +143,8 @@ class ScrollingTerminal {
this.cursor = { x: 0, y: 0, style: 1, visible: true } this.cursor = { x: 0, y: 0, style: 1, visible: true }
this.trackMouse = false this.trackMouse = false
this.theme = 0 this.theme = 0
this.defaultFG = 7
this.defaultBG = 0
this.rainbow = this.superRainbow = false this.rainbow = this.superRainbow = false
this.parser.reset() this.parser.reset()
this.clear() this.clear()
@ -274,10 +276,10 @@ class ScrollingTerminal {
data += encodeAsCodePoint(25) data += encodeAsCodePoint(25)
data += encodeAsCodePoint(80) data += encodeAsCodePoint(80)
data += encodeAsCodePoint(this.theme) data += encodeAsCodePoint(this.theme)
data += encodeAsCodePoint(7) data += encodeAsCodePoint(this.defaultFG & 0xFFFF)
data += encodeAsCodePoint(0) data += encodeAsCodePoint(this.defaultFG >> 16)
data += encodeAsCodePoint(0) data += encodeAsCodePoint(this.defaultBG & 0xFFFF)
data += encodeAsCodePoint(0) data += encodeAsCodePoint(this.defaultBG >> 16)
let attributes = +this.cursor.visible let attributes = +this.cursor.visible
attributes |= (3 << 5) * +this.trackMouse // track mouse controls both attributes |= (3 << 5) * +this.trackMouse // track mouse controls both
attributes |= 3 << 7 // buttons/links always visible attributes |= 3 << 7 // buttons/links always visible
@ -647,37 +649,203 @@ let demoshIndex = {
} }
}, },
themes: class ShowThemes extends Process { themes: class ShowThemes extends Process {
color (hex) { constructor (shell) {
hex = parseInt(hex.substr(1), 16) super()
let r = hex >> 16 this.shell = shell
let g = (hex >> 8) & 0xFF this.parser = new ANSIParser((...args) => this.handler(...args))
let b = hex & 0xFF
this.emit('write', `\x1b[48;2;${r};${g};${b}m`)
if (((r + g + b) / 3) > 127) {
this.emit('write', '\x1b[38;5;16m')
} else {
this.emit('write', '\x1b[38;5;255m')
}
} }
destroy () {
this.shell.terminal.cursor.style = this.savedCursorStyle
this.emit('write', '\n\n')
super.destroy()
}
run (...args) { run (...args) {
for (let i in themes) { this.savedCursorStyle = this.shell.terminal.cursor.style
let theme = themes[i] this.shell.terminal.cursor.style = 3
this.fgType = 0
this.bgType = 0
let get24FG = () => this.shell.terminal.defaultFG - 256
let set24FG = v => { this.shell.terminal.defaultFG = v + 256 }
let get24BG = () => this.shell.terminal.defaultBG - 256
let set24BG = v => { this.shell.terminal.defaultBG = v + 256 }
let make24Control = (label, index, getValue, setValue, type) => {
index *= 4
return {
label,
length: 1,
getValue: () => (getValue() >> index) & 0xF,
getDisplay: () => ((getValue() >> index) & 0xF).toString(16),
setValue: value => {
setValue((getValue() & (0xFFFFFF ^ (0xF << index))) | ((value & 0xF) << index))
},
shouldShow: () => this[type + 'Type'] === 1,
parseValue: input => {
return parseInt(input, 16) & 0xF
},
moveAfterInput: index !== 0
}
}
this.controls = [
{
label: 'Theme: ',
length: themes.length.toString().length,
getValue: () => this.shell.terminal.theme,
setValue: value => {
let count = themes.length
this.shell.terminal.theme = ((value % count) + count) % count
}
},
{
label: ' Default Foreground: ',
length: 6,
getValue: () => this.fgType,
getDisplay: () => this.fgType === 0 ? '256' : '24-bit',
setValue: value => {
this.fgType = ((value % 2) + 2) % 2
}
},
{
label: ' ',
length: 3,
getValue: () => this.shell.terminal.defaultFG & 0xFF,
setValue: value => {
this.shell.terminal.defaultFG = value & 0xFF
},
shouldShow: () => this.fgType === 0,
parseValue: input => parseInt(input, 16)
},
make24Control(' #', 5, get24FG, set24FG, 'fg'),
make24Control('', 4, get24FG, set24FG, 'fg'),
make24Control('', 3, get24FG, set24FG, 'fg'),
make24Control('', 2, get24FG, set24FG, 'fg'),
make24Control('', 1, get24FG, set24FG, 'fg'),
make24Control('', 0, get24FG, set24FG, 'fg'),
{
label: ' Default Background: ',
length: 6,
getValue: () => this.bgType,
getDisplay: () => this.bgType === 0 ? '256' : '24-bit',
setValue: value => {
this.bgType = ((value % 2) + 2) % 2
}
},
{
label: ' ',
length: 3,
getValue: () => this.shell.terminal.defaultBG & 0xFF,
setValue: value => {
this.shell.terminal.defaultBG = value & 0xFF
},
shouldShow: () => this.bgType === 0,
parseValue: input => parseInt(input, 16)
},
make24Control(' #', 5, get24BG, set24BG, 'bg'),
make24Control('', 4, get24BG, set24BG, 'bg'),
make24Control('', 3, get24BG, set24BG, 'bg'),
make24Control('', 2, get24BG, set24BG, 'bg'),
make24Control('', 1, get24BG, set24BG, 'bg'),
make24Control('', 0, get24BG, set24BG, 'bg')
]
this.selection = 0
this.emit('write', '\x1b[1mThemes\x1b[m\n\n\n\n\x1b[2A')
this.render()
}
render () {
this.emit('write', '\x1b[m\r')
// no ^[2K implementation, here's a hack
this.emit('write', ' '.repeat(this.shell.terminal.width - 1) + '\r')
let name = ` ${i}`.substr(-2) let index = 0
let selectedX = 0
for (let control of this.controls) {
if (control.shouldShow && !control.shouldShow()) continue
if (control.label) {
this.emit('write', `\x1b[1m${control.label}\x1b[m`)
}
// TODO: colors
this.emit('write', '\x1b[38;5;255m\x1b[48;5;16m')
let value = control.getDisplay ? control.getDisplay() : control.getValue().toString()
this.emit('write', (control.fill || ' ').repeat(Math.max(0, control.length - value.length)))
this.emit('write', value.substr(0, control.length))
this.emit('write', '\x1b[m')
this.emit('write', `Theme ${name}: `) if (index === this.selection) {
selectedX = this.shell.terminal.cursor.x - 1
for (let col = 0; col < 16; col++) { // draw arrows
let text = ` ${col}`.substr(-2) this.emit('write', '\x1b[m\x1b[D\x1b[A▲\x1b[D\x1b[2B▼\x1b[A')
this.color(theme[col]) } else {
this.emit('write', text) // clear arrows if they were there
this.emit('write', '\x1b[m ') this.emit('write', '\x1b[m\x1b[D\x1b[A \x1b[D\x1b[2B \x1b[A')
} }
this.emit('write', '\n') index++
} }
this.destroy() this.shell.terminal.cursor.x = selectedX
}
write (data) {
this.parser.write(data)
}
getControlCount () {
let count = 0
for (let control of this.controls) {
if (control.shouldShow && !control.shouldShow()) continue
count++
}
return count
}
getSelectedControl () {
let selected = null
let index = 0
for (let control of this.controls) {
if (control.shouldShow && !control.shouldShow()) continue
if (index === this.selection) {
selected = control
break
}
index++
}
return selected
}
handler (action, ...args) {
console.log(action, ...args)
if (action === 'move-cursor-x') {
this.selection += args[0]
let count = this.getControlCount()
this.selection = ((this.selection % count) + count) % count
} else if (action === 'move-cursor-y') {
let control = this.getSelectedControl()
if (control) control.setValue(control.getValue() - args[0])
} else if (action === 'write') {
let control = this.getSelectedControl()
if (control && control.parseValue) {
let parsed = control.parseValue(args[0])
if (Number.isFinite(parsed)) {
control.setValue(parsed)
if (control.moveAfterInput) {
if (this.selection < this.getControlCount() - 1) this.selection++
}
}
}
}
this.render()
} }
}, },
cursor: class SetCursor extends Process { cursor: class SetCursor extends Process {

@ -305,6 +305,19 @@ module.exports = class TermScreen extends EventEmitter {
this._scheduledSizeUpdate = setTimeout(() => this.updateSize(), 1) this._scheduledSizeUpdate = setTimeout(() => this.updateSize(), 1)
} }
get backgroundImage () {
return this.canvas.style.backgroundImage
}
set backgroundImage (value) {
this.canvas.style.backgroundImage = value ? `url(${value})` : ''
if (this.renderer.backgroundImage !== !!value) {
this.renderer.backgroundImage = !!value
this.renderer.resetDrawn()
this.renderer.scheduleDraw('background-image')
}
}
/** /**
* Returns a CSS font string with this TermScreen's font settings and the * Returns a CSS font string with this TermScreen's font settings and the
* font modifiers. * font modifiers.

@ -0,0 +1,15 @@
// Bits in the cell attribs word
/* eslint-disable no-multi-spaces */
exports.ATTR_FG = (1 << 0) // 1 if not using default background color (ignore cell bg) - color extension bit
exports.ATTR_BG = (1 << 1) // 1 if not using default foreground color (ignore cell fg) - color extension bit
exports.ATTR_BOLD = (1 << 2) // Bold font
exports.ATTR_UNDERLINE = (1 << 3) // Underline decoration
exports.ATTR_INVERSE = (1 << 4) // Invert colors - this is useful so we can clear then with SGR manipulation commands
exports.ATTR_BLINK = (1 << 5) // Blinking
exports.ATTR_ITALIC = (1 << 6) // Italic font
exports.ATTR_STRIKE = (1 << 7) // Strike-through decoration
exports.ATTR_OVERLINE = (1 << 8) // Over-line decoration
exports.ATTR_FAINT = (1 << 9) // Faint foreground color (reduced alpha)
exports.ATTR_FRAKTUR = (1 << 10) // Fraktur font (unicode substitution)
/* eslint-enable no-multi-spaces */

@ -1,6 +1,17 @@
const $ = require('../lib/chibi') const $ = require('../lib/chibi')
const { qs } = require('../utils') const { qs } = require('../utils')
const {
ATTR_FG,
ATTR_BG,
ATTR_BOLD,
ATTR_UNDERLINE,
ATTR_BLINK,
ATTR_STRIKE,
ATTR_OVERLINE,
ATTR_FAINT
} = require('./screen_attr_bits')
// constants for decoding the update blob // constants for decoding the update blob
const SEQ_SKIP = 1 const SEQ_SKIP = 1
const SEQ_REPEAT = 2 const SEQ_REPEAT = 2
@ -24,6 +35,7 @@ const TOPIC_BUTTONS = 'B'
const TOPIC_CURSOR = 'C' const TOPIC_CURSOR = 'C'
const TOPIC_INTERNAL = 'D' const TOPIC_INTERNAL = 'D'
const TOPIC_BELL = '!' const TOPIC_BELL = '!'
const TOPIC_BACKDROP = 'W'
const OPT_CURSOR_VISIBLE = (1 << 0) const OPT_CURSOR_VISIBLE = (1 << 0)
const OPT_DEBUGBAR = (1 << 1) const OPT_DEBUGBAR = (1 << 1)
@ -39,17 +51,6 @@ const OPT_CRLF_MODE = (1 << 12)
const OPT_BRACKETED_PASTE = (1 << 13) const OPT_BRACKETED_PASTE = (1 << 13)
const OPT_REVERSE_VIDEO = (1 << 14) const OPT_REVERSE_VIDEO = (1 << 14)
const ATTR_FG = (1 << 0) // 1 if not using default background color (ignore cell bg) - color extension bit
const ATTR_BG = (1 << 1) // 1 if not using default foreground color (ignore cell fg) - color extension bit
const ATTR_BOLD = (1 << 2) // Bold font
const ATTR_UNDERLINE = (1 << 3) // Underline decoration
const ATTR_INVERSE = (1 << 4) // Invert colors - this is useful so we can clear then with SGR manipulation commands
const ATTR_BLINK = (1 << 5) // Blinking
const ATTR_ITALIC = (1 << 6) // Italic font
const ATTR_STRIKE = (1 << 7) // Strike-through decoration
const ATTR_OVERLINE = (1 << 8) // Over-line decoration
const ATTR_FAINT = (1 << 9) // Faint foreground color (reduced alpha)
const ATTR_FRAKTUR = (1 << 10) // Fraktur font (unicode substitution)
/* eslint-enable no-multi-spaces */ /* eslint-enable no-multi-spaces */
module.exports = class ScreenParser { module.exports = class ScreenParser {
@ -65,7 +66,9 @@ module.exports = class ScreenParser {
*/ */
hideLoadFailedMsg () { hideLoadFailedMsg () {
if (!this.contentLoaded) { if (!this.contentLoaded) {
let scr = qs('#screen')
let errmsg = qs('#load-failed') let errmsg = qs('#load-failed')
if (scr) scr.classList.remove('failed')
if (errmsg) errmsg.parentNode.removeChild(errmsg) if (errmsg) errmsg.parentNode.removeChild(errmsg)
this.contentLoaded = true this.contentLoaded = true
} }
@ -82,6 +85,20 @@ module.exports = class ScreenParser {
const topics = du(strArray[ci++]) const topics = du(strArray[ci++])
// this.screen.cursor.hanging = !!(attributes & (1 << 1)) // this.screen.cursor.hanging = !!(attributes & (1 << 1))
let collectOneTerminatedString = () => {
// TODO optimize this
text = ''
while (ci < strArray.length) {
let c = strArray[ci++]
if (c !== '\x01') {
text += c
} else {
break
}
}
return text
}
while (ci < strArray.length) { while (ci < strArray.length) {
const topic = strArray[ci++] const topic = strArray[ci++]
@ -177,17 +194,7 @@ module.exports = class ScreenParser {
this.screen.renderer.scheduleDraw('cursor-moved') this.screen.renderer.scheduleDraw('cursor-moved')
} else if (topic === TOPIC_TITLE) { } else if (topic === TOPIC_TITLE) {
// TODO optimize this text = collectOneTerminatedString()
text = ''
while (ci < strArray.length) {
let c = strArray[ci++]
if (c !== '\x01') {
text += c
} else {
break
}
}
qs('#screen-title').textContent = text qs('#screen-title').textContent = text
if (text.length === 0) text = 'Terminal' if (text.length === 0) text = 'Terminal'
qs('title').textContent = `${text} :: ESPTerm` qs('title').textContent = `${text} :: ESPTerm`
@ -197,16 +204,16 @@ module.exports = class ScreenParser {
let labels = [] let labels = []
for (let j = 0; j < count; j++) { for (let j = 0; j < count; j++) {
text = '' text = collectOneTerminatedString()
while (ci < strArray.length) {
let c = strArray[ci++]
if (c === '\x01') break
text += c
}
labels.push(text) labels.push(text)
} }
this.screen.emit('button-labels', labels) this.screen.emit('button-labels', labels)
} else if (topic === TOPIC_BACKDROP) {
text = collectOneTerminatedString()
this.screen.backgroundImage = text
} else if (topic === TOPIC_BELL) { } else if (topic === TOPIC_BELL) {
this.screen.beep() this.screen.beep()

@ -1,4 +1,22 @@
const { themes, buildColorTable, SELECTION_FG, SELECTION_BG } = require('./themes') const {
themes,
buildColorTable,
SELECTION_FG, SELECTION_BG
} = require('./themes')
const {
ATTR_FG,
ATTR_BG,
ATTR_BOLD,
ATTR_UNDERLINE,
ATTR_INVERSE,
ATTR_BLINK,
ATTR_ITALIC,
ATTR_STRIKE,
ATTR_OVERLINE,
ATTR_FAINT,
ATTR_FRAKTUR
} = require('./screen_attr_bits')
// Some non-bold Fraktur symbols are outside the contiguous block // Some non-bold Fraktur symbols are outside the contiguous block
const frakturExceptions = { const frakturExceptions = {
@ -9,21 +27,6 @@ const frakturExceptions = {
'Z': '\u2128' 'Z': '\u2128'
} }
// TODO do not repeat - this is also defined in screen_parser ...
/* eslint-disable no-multi-spaces */
const ATTR_FG = (1 << 0) // 1 if not using default background color (ignore cell bg) - color extension bit
const ATTR_BG = (1 << 1) // 1 if not using default foreground color (ignore cell fg) - color extension bit
const ATTR_BOLD = (1 << 2) // Bold font
const ATTR_UNDERLINE = (1 << 3) // Underline decoration
const ATTR_INVERSE = (1 << 4) // Invert colors - this is useful so we can clear then with SGR manipulation commands
const ATTR_BLINK = (1 << 5) // Blinking
const ATTR_ITALIC = (1 << 6) // Italic font
const ATTR_STRIKE = (1 << 7) // Strike-through decoration
const ATTR_OVERLINE = (1 << 8) // Over-line decoration
const ATTR_FAINT = (1 << 9) // Faint foreground color (reduced alpha)
const ATTR_FRAKTUR = (1 << 10) // Fraktur font (unicode substitution)
/* eslint-enable no-multi-spaces */
module.exports = class ScreenRenderer { module.exports = class ScreenRenderer {
constructor (screen) { constructor (screen) {
this.screen = screen this.screen = screen
@ -89,6 +92,9 @@ module.exports = class ScreenRenderer {
this.defaultFgNum = fg this.defaultFgNum = fg
this.defaultBgNum = bg this.defaultBgNum = bg
this.scheduleDraw('default-colors') this.scheduleDraw('default-colors')
// full bg with default color (goes behind the image)
this.screen.canvas.style.backgroundColor = this.getColor(bg)
} }
} }
@ -180,8 +186,9 @@ module.exports = class ScreenRenderer {
* @param {number} options.cellWidth - cell width in pixels * @param {number} options.cellWidth - cell width in pixels
* @param {number} options.cellHeight - cell height in pixels * @param {number} options.cellHeight - cell height in pixels
* @param {number} options.bg - the background color * @param {number} options.bg - the background color
* @param {number} options.isDefaultBG - if true, will draw image background if available
*/ */
drawBackground ({ x, y, cellWidth, cellHeight, bg }) { drawBackground ({ x, y, cellWidth, cellHeight, bg, isDefaultBG }) {
const ctx = this.ctx const ctx = this.ctx
const { width, height } = this.screen.window const { width, height } = this.screen.window
const padding = Math.round(this.screen._padding) const padding = Math.round(this.screen._padding)
@ -189,6 +196,8 @@ module.exports = class ScreenRenderer {
let screenX = x * cellWidth + padding let screenX = x * cellWidth + padding
let screenY = y * cellHeight + padding let screenY = y * cellHeight + padding
let isBorderCell = x === 0 || y === 0 || x === width - 1 || y === height - 1 let isBorderCell = x === 0 || y === 0 || x === width - 1 || y === height - 1
let fillX, fillY, fillWidth, fillHeight
if (isBorderCell) { if (isBorderCell) {
let left = screenX let left = screenX
let top = screenY let top = screenY
@ -198,11 +207,22 @@ module.exports = class ScreenRenderer {
else if (x === width - 1) right += padding else if (x === width - 1) right += padding
if (y === 0) top -= padding if (y === 0) top -= padding
else if (y === height - 1) bottom += padding else if (y === height - 1) bottom += padding
ctx.clearRect(left, top, right - left, bottom - top)
ctx.fillRect(left, top, right - left, bottom - top) fillX = left
fillY = top
fillWidth = right - left
fillHeight = bottom - top
} else { } else {
ctx.clearRect(screenX, screenY, cellWidth, cellHeight) fillX = screenX
ctx.fillRect(screenX, screenY, cellWidth, cellHeight) fillY = screenY
fillWidth = cellWidth
fillHeight = cellHeight
}
ctx.clearRect(fillX, fillY, fillWidth, fillHeight)
if (!isDefaultBG || bg < 0 || !this.backgroundImage) {
ctx.fillRect(fillX, fillY, fillWidth, fillHeight)
} }
} }
@ -497,8 +517,13 @@ module.exports = class ScreenRenderer {
let bg = this.screen.screenBG[cell] | 0 let bg = this.screen.screenBG[cell] | 0
let attrs = this.screen.screenAttrs[cell] | 0 let attrs = this.screen.screenAttrs[cell] | 0
let isDefaultBG = false
if (!(attrs & ATTR_FG)) fg = this.defaultFgNum if (!(attrs & ATTR_FG)) fg = this.defaultFgNum
if (!(attrs & ATTR_BG)) bg = this.defaultBgNum if (!(attrs & ATTR_BG)) {
bg = this.defaultBgNum
isDefaultBG = true
}
if (attrs & ATTR_INVERSE) [fg, bg] = [bg, fg] // swap - reversed character colors if (attrs & ATTR_INVERSE) [fg, bg] = [bg, fg] // swap - reversed character colors
if (this.screen.reverseVideo) [fg, bg] = [bg, fg] // swap - reversed all screen if (this.screen.reverseVideo) [fg, bg] = [bg, fg] // swap - reversed all screen
@ -525,7 +550,7 @@ module.exports = class ScreenRenderer {
let font = attrs & FONT_MASK let font = attrs & FONT_MASK
if (!fontGroups.has(font)) fontGroups.set(font, []) if (!fontGroups.has(font)) fontGroups.set(font, [])
fontGroups.get(font).push({ cell, x, y, text, fg, bg, attrs, isCursor, inSelection }) fontGroups.get(font).push({ cell, x, y, text, fg, bg, attrs, isCursor, inSelection, isDefaultBG })
updateMap.set(cell, didUpdate) updateMap.set(cell, didUpdate)
} }
@ -595,10 +620,10 @@ module.exports = class ScreenRenderer {
// pass 1: backgrounds // pass 1: backgrounds
for (let font of fontGroups.keys()) { for (let font of fontGroups.keys()) {
for (let data of fontGroups.get(font)) { for (let data of fontGroups.get(font)) {
let { cell, x, y, text, bg } = data let { cell, x, y, text, bg, isDefaultBG } = data
if (redrawMap.get(cell)) { if (redrawMap.get(cell)) {
this.drawBackground({ x, y, cellWidth, cellHeight, bg }) this.drawBackground({ x, y, cellWidth, cellHeight, bg, isDefaultBG })
if (this.screen.window.debug && this.screen._debug) { if (this.screen.window.debug && this.screen._debug) {
// set cell flags // set cell flags

@ -4,7 +4,7 @@ return [
'menu.cfg_wifi' => 'Nastavení WiFi', 'menu.cfg_wifi' => 'Nastavení WiFi',
'menu.cfg_network' => 'Nastavení sítě', 'menu.cfg_network' => 'Nastavení sítě',
'menu.cfg_term' => 'Nastavení terminalu', 'menu.cfg_term' => 'Nastavení terminalu',
'menu.about' => 'About', 'menu.about' => 'O programu',
'menu.help' => 'Nápověda', 'menu.help' => 'Nápověda',
'menu.term' => 'Zpět k terminálu', 'menu.term' => 'Zpět k terminálu',
'menu.cfg_system' => 'Nastavení systému', 'menu.cfg_system' => 'Nastavení systému',
@ -80,6 +80,7 @@ return [
'term.colors_preview' => '', 'term.colors_preview' => '',
'term.debugbar' => 'Rozšířené ladění', 'term.debugbar' => 'Rozšířené ladění',
'term.ascii_debug' => 'Ladění vstupních dat', 'term.ascii_debug' => 'Ladění vstupních dat',
'term.backdrop' => 'URL obrázku na pozadí',
'cursor.block_blink' => 'Blok, blikající', 'cursor.block_blink' => 'Blok, blikající',
'cursor.block_steady' => 'Blok, stálý', 'cursor.block_steady' => 'Blok, stálý',

@ -79,6 +79,7 @@ return [
'term.colors_preview' => '', 'term.colors_preview' => '',
'term.debugbar' => 'Debug internal state', 'term.debugbar' => 'Debug internal state',
'term.ascii_debug' => 'Display control codes', 'term.ascii_debug' => 'Display control codes',
'term.backdrop' => 'Background image URL',
'cursor.block_blink' => 'Block, blinking', 'cursor.block_blink' => 'Block, blinking',
'cursor.block_steady' => 'Block, steady', 'cursor.block_steady' => 'Block, steady',

@ -172,6 +172,11 @@
<input class="tiny" type="text" name="bm5" id="bm5" value="%h:bm5%"> <input class="tiny" type="text" name="bm5" id="bm5" value="%h:bm5%">
</div> </div>
<div class="Row">
<label for="backdrop"><?= tr('term.backdrop') ?></label>
<input type="text" name="backdrop" id="backdrop" value="%h:backdrop%" required>
</div>
<div class="Row checkbox" > <div class="Row checkbox" >
<label><?= tr('term.crlf_mode') ?></label><!-- <label><?= tr('term.crlf_mode') ?></label><!--
--><span class="box" tabindex=0 role=checkbox></span> --><span class="box" tabindex=0 role=checkbox></span>
@ -282,7 +287,6 @@
<input type="hidden" id="ascii_debug" name="ascii_debug" value="%ascii_debug%"> <input type="hidden" id="ascii_debug" name="ascii_debug" value="%ascii_debug%">
</div> </div>
<div class="Row checkbox" > <div class="Row checkbox" >
<label><?= tr('term.fn_alt_mode') ?></label><!-- <label><?= tr('term.fn_alt_mode') ?></label><!--
--><span class="box" tabindex=0 role=checkbox></span> --><span class="box" tabindex=0 role=checkbox></span>

@ -21,6 +21,8 @@
<li>`A` - UK ASCII: # replaced with £</li> <li>`A` - UK ASCII: # replaced with £</li>
<li>`0` - Symbols and basic line drawing (standard DEC alternate character set)</li> <li>`0` - Symbols and basic line drawing (standard DEC alternate character set)</li>
<li>`1` - Symbols and advanced line drawing (based on DOS codepage 437, ESPTerm specific)</li> <li>`1` - Symbols and advanced line drawing (based on DOS codepage 437, ESPTerm specific)</li>
<li>`2` - Block characters and thick line drawing (ESPTerm specific)</li>
<li>`3` - Extra line drawing (ESPTerm specific)</li>
</ul> </ul>
<p> <p>

@ -11,11 +11,28 @@
<table class="ansiref w100"> <table class="ansiref w100">
<thead><tr><th>Code</th><th>Meaning</th></tr></thead> <thead><tr><th>Code</th><th>Meaning</th></tr></thead>
<tbody> <tbody>
<tr>
<td>_CAN_ (24)</td>
<td>
This ASCII code is sent by ESPTerm when it becomes ready to receive commands.
When this code is received on the UART, it means ESPTerm has restarted and is ready.
Use this to detect spontaneous restarts which require a full screen repaint.
As a control character sent to ESPTerm, CAN aborts any currently received commands
and clears the parser.
</td>
</tr>
<tr>
<td>_ENQ_ (5)</td>
<td>
ESPTerm responds to this control characters with an "answerback message".
This message contains the curretn version, unique ID, and the IP address if in Client mode.
</td>
</tr>
<tr> <tr>
<td>`\ec`</td> <td>`\ec`</td>
<td> <td>
Clear screen, reset attributes and cursor. This command also restores the default Clear screen, reset attributes and cursor. This command also restores the default
screen size, title, button labels and messages. screen size, title, button labels and messages and the background URL.
</td> </td>
</tr> </tr>
<tr> <tr>
@ -29,14 +46,6 @@
Can be used to check if the terminal has booted up and is ready to receive commands. Can be used to check if the terminal has booted up and is ready to receive commands.
</td> </td>
</tr> </tr>
<tr>
<td>_CAN_ (24)</td>
<td>
This ASCII code is not a command, but is sent by ESPTerm when it becomes ready to receive commands.
When this code is received on the UART, it means ESPTerm has restarted and is ready. Use this to detect
spontaneous restarts which require a full screen repaint.
</td>
</tr>
<tr> <tr>
<td>`\e[<i>n</i> q`</td> <td>`\e[<i>n</i> q`</td>
<td> <td>
@ -50,6 +59,16 @@
<td>`\e]0;<i>t</i>\a`</td> <td>`\e]0;<i>t</i>\a`</td>
<td>Set screen title to _t_ (this is a standard OSC command)</td> <td>Set screen title to _t_ (this is a standard OSC command)</td>
</tr> </tr>
<tr>
<td>`\e]70;<i>u</i>\a`</td>
<td>
Set background image to URL _u_ (including protocol)
that can be resolved by the user's browser. The image will be scaled
to fit the screen, preserving aspect ratio. A certain border must be added
to account for the screen margins. Use empty string to disable the image feature.
Note that this *won't work for users connected to the built-in AP*.
</td>
</tr>
<tr> <tr>
<td> <td>
<code> <code>
@ -68,8 +87,8 @@
</code> </code>
</td> </td>
<td> <td>
Set message for button 1-5 (code 91-95) to _m_ - e.g.`\e]94;*\a` Set message for button 1-5 (code 91-95) to _m_ - e.g.`\e]94;+\a`
sets the 3rd button to send "*" when pressed. The message can be up to sets the 3rd button to send "+" when pressed. The message can be up to
10 bytes long. 10 bytes long.
</td> </td>
</tr> </tr>

@ -16,6 +16,10 @@
can be selected in <a href="<?= url('cfg_term') ?>">Terminal Settings</a>. can be selected in <a href="<?= url('cfg_term') ?>">Terminal Settings</a>.
</p> </p>
<p>
Background image can be set using `\e]70;<i>url</i>\a` (see section System Functions).
</p>
<h3>Foreground colors</h3> <h3>Foreground colors</h3>
<div class="colorprev"> <div class="colorprev">

@ -25,6 +25,12 @@ body.term {
cursor: default; cursor: default;
canvas {
background-repeat: no-repeat;
background-position: center center;
background-size: contain;
}
canvas.selectable { canvas.selectable {
cursor: text; cursor: text;
} }
@ -140,7 +146,13 @@ body.term {
color: red; color: red;
font-size: 18px; font-size: 18px;
font-weight: bold; font-weight: bold;
margin: 10px 5px 14px 5px; margin: 20px 15px;
}
#screen.failed {
canvas, .screen-margin {
display: none;
}
} }
#term-nav { #term-nav {

Loading…
Cancel
Save