neo-neo-bblessed
Version:
A fork of neo-blessed (which is a fork of blessed) with bug fixes and maintenance.
184 lines (157 loc) • 4.6 kB
text/typescript
/**
* textbox.js - textbox element for blessed
* Copyright (c) 2013-2015, Christopher Jeffrey and contributors (MIT License).
* https://github.com/chjj/blessed
*/
/**
* Modules
*/
import Node from './node.js';
import textareaFactory from './textarea.js';
const Textarea = textareaFactory.Textarea;
/**
* Type definitions
*/
interface TextboxOptions {
scrollable?: boolean;
secret?: boolean;
censor?: boolean;
ignoreKeys?: string[]; // Array of key names to ignore (e.g., ['tab', 'f1'])
[key: string]: any;
}
interface TextboxKey {
name: string;
}
interface TextboxScreen {
tabc: string;
}
interface TextboxInterface extends Textarea {
type: string;
secret?: boolean;
censor?: boolean;
ignoreKeys?: string[];
value: string;
_value: string;
width: number;
iwidth: number;
screen: TextboxScreen;
__listener?: (ch: string, key: TextboxKey) => void;
__olistener: (ch: string, key: TextboxKey) => any;
_listener: (ch: string, key: TextboxKey) => any;
_done: (err: any, value?: string) => void;
setContent(content: string): void;
_updateCursor(): void;
setValue(value?: string): void;
submit(): any;
}
/**
* Textbox - Modern ES6 Class
*/
class Textbox extends Textarea {
type = 'textbox';
secret?: boolean;
censor?: boolean;
ignoreKeys?: string[];
__olistener: (ch: string, key: TextboxKey) => any;
constructor(options?: TextboxOptions) {
// Handle malformed options gracefully
if (!options || typeof options !== 'object' || Array.isArray(options)) {
options = {};
}
// Force scrollable to false for textbox (single-line input)
options.scrollable = false;
super(options);
this.secret = options.secret;
this.censor = options.censor;
this.ignoreKeys = options.ignoreKeys || [];
}
// Override _listener to handle textbox-specific behavior
_listener(ch: string, key: TextboxKey): void {
// Check if this key should be ignored based on configuration
if (this.ignoreKeys && this.ignoreKeys.length > 0) {
// Check by key name
if (key.name && this.ignoreKeys.includes(key.name)) {
return; // Ignore this key
}
// Also check by character for special chars like tab
if (ch) {
// Map common special characters to their key names
const charToKeyName: { [key: string]: string } = {
'\t': 'tab',
'\x1b': 'escape',
'\r': 'return',
'\n': 'enter',
};
const keyName = charToKeyName[ch];
if (keyName && this.ignoreKeys.includes(keyName)) {
return; // Ignore this character
}
}
}
// Handle enter key for single-line submission (after ignore check)
if (key.name === 'enter') {
if (this._done) {
this._done(null, this.value);
}
return;
}
// Handle backspace for single-line textbox
if (key.name === 'backspace') {
if (this.value.length > 0) {
this.value = this.value.slice(0, -1);
this.setValue(this.value);
}
return;
}
// Handle delete key for single-line textbox
if (key.name === 'delete') {
// For single-line, delete removes character at cursor position
// Since we don't track cursor precisely, just remove from end for now
if (this.value.length > 0) {
this.value = this.value.slice(0, -1);
this.setValue(this.value);
}
return;
}
// For all other keys, call parent's textarea _listener
super._listener(ch, key);
}
setValue(value?: string): void {
let visible: number, val: string;
if (value == null) {
value = this.value;
}
if (this._value !== value) {
// Remove newlines for single-line textbox
value = value.replace(/\n/g, '');
this.value = value;
this._value = value;
if (this.secret) {
this.setContent('');
} else if (this.censor) {
this.setContent(Array(this.value.length + 1).join('*'));
} else {
visible = -(this.width - this.iwidth - 1);
val = this.value.replace(/\t/g, this.screen.tabc);
this.setContent(val.slice(visible));
}
this._updateCursor();
}
}
submit(): any {
if (!this._done) return;
return this._done(null, this.value);
}
}
/**
* Factory function for backward compatibility
*/
function textbox(options?: TextboxOptions): TextboxInterface {
return new Textbox(options) as TextboxInterface;
}
// Attach the class as a property for direct access
textbox.Textbox = Textbox;
/**
* Expose
*/
export default textbox;