123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148 |
- import {FocusElement} from 'tui-lib/ui/primitives'
- import * as ansi from 'tui-lib/util/ansi'
- import telc from 'tui-lib/util/telchars'
- import unic from 'tui-lib/util/unichars'
- export default class TextInput extends FocusElement {
- // An element that the user can type in.
- constructor() {
- super()
- this.value = ''
- this.cursorVisible = true
- this.cursorIndex = 0
- this.scrollChars = 0
- }
- drawTo(writable) {
- // There should be room for the cursor so move the "right edge" left a
- // single character.
- const startRange = this.scrollChars
- const endRange = this.scrollChars + this.w - 3
- let str = this.value.slice(startRange, endRange)
- writable.write(ansi.moveCursor(this.absTop, this.absLeft + 1))
- writable.write(str)
- // Ellipsis on left side, if there's more characters behind the visible
- // area.
- if (startRange > 0) {
- writable.write(ansi.moveCursor(this.absTop, this.absLeft))
- writable.write(unic.ELLIPSIS)
- }
- // Ellipsis on the right side, if there's more characters ahead of the
- // visible area.
- if (endRange < this.value.length) {
- writable.write(ansi.moveCursor(this.absTop, this.absRight - 1))
- writable.write(unic.ELLIPSIS.repeat(2))
- }
- this.cursorX = this.cursorIndex - this.scrollChars + 1
- super.drawTo(writable)
- }
- keyPressed(keyBuf) {
- try {
- if (keyBuf[0] === 127) {
- this.value = (
- this.value.slice(0, this.cursorIndex - 1) +
- this.value.slice(this.cursorIndex)
- )
- this.cursorIndex--
- this.root.cursorMoved()
- return false
- } else if (keyBuf[0] === 13) {
- // These are aliases for each other.
- this.emit('value', this.value)
- this.emit('confirm', this.value)
- } else if (keyBuf[0] === 0x1b && keyBuf[1] === 0x5b) {
- // Keyboard navigation
- if (keyBuf[2] === 0x44) {
- this.cursorIndex--
- this.root.cursorMoved()
- } else if (keyBuf[2] === 0x43) {
- this.cursorIndex++
- this.root.cursorMoved()
- }
- return false
- } else if (telc.isEscape(keyBuf)) {
- // ESC is bad and we don't want that in the text input!
- // Also emit a "cancel" event, which doesn't necessarily do anything,
- // but can be listened to.
- this.emit('cancel')
- } else {
- const isTextInput = keyBuf.toString().split('').every(chr => {
- const n = chr.charCodeAt(0)
- return n > 31 && n < 127
- })
- if (isTextInput) {
- this.value = (
- this.value.slice(0, this.cursorIndex) + keyBuf.toString() +
- this.value.slice(this.cursorIndex)
- )
- this.cursorIndex += keyBuf.toString().length
- this.root.cursorMoved()
- this.emit('change', this.value)
- return false
- }
- }
- } finally {
- this.keepCursorInRange()
- }
- }
- setValue(value) {
- this.value = value
- this.moveToEnd()
- }
- moveToEnd() {
- this.cursorIndex = this.value.length
- this.keepCursorInRange()
- }
- keepCursorInRange() {
- // Keep the cursor inside or at the end of the input value.
- if (this.cursorIndex < 0) {
- this.cursorIndex = 0
- }
- if (this.cursorIndex > this.value.length) {
- this.cursorIndex = this.value.length
- }
- // Scroll right, if the cursor is past the right edge of where text is
- // displayed.
- while (this.cursorIndex - this.scrollChars > this.w - 3) {
- this.scrollChars++
- }
- // Scroll left, if the cursor is behind the left edge of where text is
- // displayed.
- while (this.cursorIndex - this.scrollChars < 0) {
- this.scrollChars--
- }
- // Scroll left, if we can see past the end of the text.
- while (this.scrollChars > 0 && (
- this.scrollChars + this.w - 3 > this.value.length)
- ) {
- this.scrollChars--
- }
- }
- get value() { return this.getDep('value') }
- set value(v) { return this.setDep('value', v) }
- get cursorIndex() { return this.getDep('cursorIndex') }
- set cursorIndex(v) { return this.setDep('cursorIndex', v) }
- }
|