add multiline textareas. remove old hoverBg code.
This commit is contained in:
parent
6355b1259f
commit
06400d089f
26
README.md
26
README.md
|
@ -221,6 +221,7 @@ The screen on which every other node renders.
|
|||
blessed app after exit.
|
||||
- **exec(file, args, options, callback)** - spawn a process in the foreground,
|
||||
return to blessed app after exit. executes callback on error or exit.
|
||||
- **readEditor([options], callback)** - read data from text editor.
|
||||
|
||||
|
||||
#### Element (from Node)
|
||||
|
@ -447,6 +448,31 @@ A box which allows text input.
|
|||
the resulting file. takes a callback which receives the final value.
|
||||
|
||||
|
||||
#### Textarea (from Input/ScrollableText)
|
||||
|
||||
A box which allows multiline text input.
|
||||
|
||||
##### Options:
|
||||
|
||||
- inherits all from Input/ScrollableText.
|
||||
|
||||
##### Properties:
|
||||
|
||||
- inherits all from Input/ScrollableText.
|
||||
|
||||
##### Events:
|
||||
|
||||
- inherits all from Input/ScrollableText.
|
||||
|
||||
##### Methods:
|
||||
|
||||
- inherits all from Input/ScrollableText.
|
||||
- **readInput(callback)** - grab key events and start reading text from the
|
||||
keyboard. takes a callback which receives the final value.
|
||||
- **readEditor(callback)** - open text editor in `$EDITOR`, read the output from
|
||||
the resulting file. takes a callback which receives the final value.
|
||||
|
||||
|
||||
#### Button (from Input)
|
||||
|
||||
A button which can be focused and allows key and mouse input.
|
||||
|
|
376
lib/widget.js
376
lib/widget.js
|
@ -880,9 +880,21 @@ Screen.prototype.exec = function(file, args, options, callback) {
|
|||
return ps;
|
||||
};
|
||||
|
||||
Screen.prototype.readEditor = function(callback) {
|
||||
var fs = require('fs')
|
||||
, editor = process.env.EDITOR || 'vi'
|
||||
Screen.prototype.readEditor = function(options, callback) {
|
||||
if (typeof options === 'string') {
|
||||
options = { editor: options };
|
||||
}
|
||||
|
||||
if (!callback) {
|
||||
callback = options;
|
||||
options = null;
|
||||
}
|
||||
|
||||
options = options || {};
|
||||
|
||||
var self = this
|
||||
, fs = require('fs')
|
||||
, editor = options.editor || process.env.EDITOR || 'vi'
|
||||
, file = '/tmp/blessed.' + Math.random().toString(36)
|
||||
, args = [file]
|
||||
, opt;
|
||||
|
@ -893,12 +905,19 @@ Screen.prototype.readEditor = function(callback) {
|
|||
cwd: process.env.HOME
|
||||
};
|
||||
|
||||
return this.exec(editor, args, opt, function(err, success) {
|
||||
if (err) return callback(err);
|
||||
return fs.readFile(file, 'utf8', function(err, data) {
|
||||
return fs.unlink(file, function() {
|
||||
if (err) return callback(err);
|
||||
return callback(null, data);
|
||||
function writeFile(callback) {
|
||||
if (!options.value) return callback();
|
||||
return fs.writeFile(file, options.value, callback);
|
||||
}
|
||||
|
||||
return writeFile(function() {
|
||||
return self.exec(editor, args, opt, function(err, success) {
|
||||
if (err) return callback(err);
|
||||
return fs.readFile(file, 'utf8', function(err, data) {
|
||||
return fs.unlink(file, function() {
|
||||
if (err) return callback(err);
|
||||
return callback(null, data);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -992,9 +1011,9 @@ function Element(options) {
|
|||
}
|
||||
});
|
||||
|
||||
//this.onScreenEvent('resize', function() {
|
||||
// self.parseContent();
|
||||
//});
|
||||
// this.onScreenEvent('resize', function() {
|
||||
// self.parseContent();
|
||||
// });
|
||||
|
||||
this.on('resize', function() {
|
||||
self.parseContent();
|
||||
|
@ -1004,27 +1023,32 @@ function Element(options) {
|
|||
self.parseContent();
|
||||
});
|
||||
|
||||
// if (this.options.hoverBg != null) {
|
||||
// var hoverBg = convert(this.options.hoverBg);
|
||||
//
|
||||
// this.on('mouseover', function() {
|
||||
// // XXX Possibly a better alternative for the below workaround.
|
||||
// self._bg = self.bg;
|
||||
// //if (self._bg == null) self._bg = self.bg;
|
||||
// self.bg = hoverBg;
|
||||
// self.screen.render();
|
||||
// });
|
||||
//
|
||||
// this.on('mouseout', function() {
|
||||
// // XXX Workaround
|
||||
// // if (self.parent.type === 'list'
|
||||
// // && self === self.parent.items[self.parent.selected]
|
||||
// // && self.bg === self.parent.selectedBg) {
|
||||
// // return;
|
||||
// // }
|
||||
// if (self._bg != null) self.bg = self._bg;
|
||||
// self.screen.render();
|
||||
// });
|
||||
// }
|
||||
|
||||
if (this.options.hoverBg != null) {
|
||||
var hoverBg = convert(this.options.hoverBg);
|
||||
|
||||
this.on('mouseover', function() {
|
||||
// XXX Possibly a better alternative for the below workaround.
|
||||
self._bg = self.bg;
|
||||
//if (self._bg == null) self._bg = self.bg;
|
||||
self.bg = hoverBg;
|
||||
self.screen.render();
|
||||
});
|
||||
|
||||
this.on('mouseout', function() {
|
||||
// XXX Workaround
|
||||
// if (self.parent.type === 'list'
|
||||
// && self === self.parent.items[self.parent.selected]
|
||||
// && self.bg === self.parent.selectedBg) {
|
||||
// return;
|
||||
// }
|
||||
if (self._bg != null) self.bg = self._bg;
|
||||
self.screen.render();
|
||||
});
|
||||
this.options.hoverEffects = this.options.hoverEffects || {};
|
||||
this.options.hoverEffects.bg = this.options.hoverBg;
|
||||
}
|
||||
|
||||
if (this.options.hoverEffects) {
|
||||
|
@ -1036,13 +1060,13 @@ function Element(options) {
|
|||
}
|
||||
});
|
||||
|
||||
this.__h = {};
|
||||
this._htemp = {};
|
||||
|
||||
this.on('mouseover', function() {
|
||||
Object.keys(effects).forEach(function(key) {
|
||||
var val = effects[key];
|
||||
if (self.__h[key] == null) {
|
||||
self.__h[key] = self[key];
|
||||
if (self._htemp[key] == null) {
|
||||
self._htemp[key] = self[key];
|
||||
}
|
||||
self[key] = val;
|
||||
});
|
||||
|
@ -1051,8 +1075,8 @@ function Element(options) {
|
|||
|
||||
this.on('mouseout', function() {
|
||||
Object.keys(effects).forEach(function(key) {
|
||||
if (self.__h[key] != null) {
|
||||
self[key] = self.__h[key];
|
||||
if (self._htemp[key] != null) {
|
||||
self[key] = self._htemp[key];
|
||||
}
|
||||
});
|
||||
self.screen.render();
|
||||
|
@ -2534,86 +2558,7 @@ Textbox.prototype.setEditor = function(callback) {
|
|||
|
||||
this.focus();
|
||||
|
||||
self.screen.program.normalBuffer();
|
||||
self.screen.program.showCursor();
|
||||
var _listenedMouse = self.screen._listenedMouse;
|
||||
if (self.screen._listenedMouse) {
|
||||
self.screen.program.disableMouse();
|
||||
}
|
||||
|
||||
return readEditor(function(err, value) {
|
||||
self.screen.program.alternateBuffer();
|
||||
self.screen.program.hideCursor();
|
||||
if (_listenedMouse) {
|
||||
self.screen.program.enableMouse();
|
||||
}
|
||||
self.screen.alloc();
|
||||
self.screen.render();
|
||||
if (err) return callback(err);
|
||||
value = value.replace(/[\r\n]/g, '');
|
||||
self.value = value;
|
||||
|
||||
////if (self.censor) {
|
||||
//// self.setContent(Array(self.value.length + 1).join('*'));
|
||||
////} else
|
||||
//if (!self.secret) {
|
||||
// self.setContent(value);
|
||||
//}
|
||||
//return callback(null, value);
|
||||
|
||||
return self.setInput(callback);
|
||||
});
|
||||
};
|
||||
|
||||
Textbox.prototype.editor =
|
||||
Textbox.prototype.readEditor =
|
||||
Textbox.prototype.setEditor = function(callback) {
|
||||
var self = this;
|
||||
|
||||
this.focus();
|
||||
|
||||
var fs = require('fs')
|
||||
, editor = process.env.EDITOR || 'vi'
|
||||
, file = '/tmp/blessed.' + Math.random().toString(36)
|
||||
, args = [file]
|
||||
, opt;
|
||||
|
||||
opt = {
|
||||
stdio: 'inherit',
|
||||
env: process.env,
|
||||
cwd: process.env.HOME
|
||||
};
|
||||
|
||||
return this.screen.exec(editor, args, opt, function(err, success) {
|
||||
if (err) return callback(err);
|
||||
return fs.readFile(file, 'utf8', function(err, data) {
|
||||
fs.unlink(file);
|
||||
|
||||
if (err) return callback(err);
|
||||
value = value.replace(/[\r\n]/g, '');
|
||||
self.value = value;
|
||||
|
||||
////if (self.censor) {
|
||||
//// self.setContent(Array(self.value.length + 1).join('*'));
|
||||
////} else
|
||||
//if (!self.secret) {
|
||||
// self.setContent(value);
|
||||
//}
|
||||
//return callback(null, value);
|
||||
|
||||
return self.setInput(callback);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Textbox.prototype.editor =
|
||||
Textbox.prototype.readEditor =
|
||||
Textbox.prototype.setEditor = function(callback) {
|
||||
var self = this;
|
||||
|
||||
this.focus();
|
||||
|
||||
return this.screen.readEditor(function(err, value) {
|
||||
return this.screen.readEditor({ value: this.value }, function(err, value) {
|
||||
if (err) return callback(err);
|
||||
value = value.replace(/[\r\n]/g, '');
|
||||
self.value = value;
|
||||
|
@ -2638,13 +2583,160 @@ function Textarea(options) {
|
|||
if (!(this instanceof Textarea)) {
|
||||
return new Textarea(options);
|
||||
}
|
||||
Input.call(this, options);
|
||||
|
||||
ScrollableText.call(this, options);
|
||||
|
||||
this.screen._listenKeys(this);
|
||||
|
||||
this.value = options.value || '';
|
||||
|
||||
this.__updateCursor = this.updateCursor.bind(this);
|
||||
this.on('resize', this.__updateCursor);
|
||||
this.on('move', this.__updateCursor);
|
||||
}
|
||||
|
||||
Textarea.prototype.__proto__ = Input.prototype;
|
||||
Textarea.prototype.__proto__ = ScrollableText.prototype;
|
||||
|
||||
Textarea.prototype.type = 'textarea';
|
||||
|
||||
Textarea.prototype.updateCursor = function() {
|
||||
if (this.screen.focused !== this) return;
|
||||
|
||||
var clen = this._clines.length;
|
||||
|
||||
var last = this._clines[this._clines.length-1];
|
||||
if (last.length === this.width - (this.border ? 2 : 0)) {
|
||||
last = '';
|
||||
clen++;
|
||||
}
|
||||
|
||||
var line = Math.min(
|
||||
clen - 1 - this.childBase,
|
||||
this.height - (this.border ? 2 : 0));
|
||||
|
||||
this.screen.program.cup(
|
||||
this.top + 1 + (this.border ? 1 : 0) + line,
|
||||
this.left + 1 + (this.border ? 1 : 0) + last.length);
|
||||
};
|
||||
|
||||
Textarea.prototype.input =
|
||||
Textarea.prototype.readInput =
|
||||
Textarea.prototype.setInput = function(callback) {
|
||||
var self = this;
|
||||
|
||||
if (this._timeout != null) {
|
||||
clearTimeout(this._timeout);
|
||||
delete this._timeout;
|
||||
}
|
||||
|
||||
this.focus();
|
||||
|
||||
this.screen.grabKeys = true;
|
||||
|
||||
this.updateCursor();
|
||||
this.screen.program.showCursor();
|
||||
this.screen.program.sgr('normal');
|
||||
|
||||
this._callback = function(err, value) {
|
||||
self.screen.program.hideCursor();
|
||||
self._timeout = setTimeout(function() {
|
||||
self.screen.grabKeys = false;
|
||||
}, 1);
|
||||
return err
|
||||
? callback(err)
|
||||
: callback(null, value);
|
||||
};
|
||||
|
||||
this.__listener = this._listener.bind(this);
|
||||
this.on('keypress', this.__listener);
|
||||
};
|
||||
|
||||
Textarea.prototype._listener = function(ch, key) {
|
||||
var callback = this._callback
|
||||
, value = this.value;
|
||||
|
||||
if (key.name === 'enter') {
|
||||
ch = '\n';
|
||||
}
|
||||
|
||||
// TODO: Handle directional keys.
|
||||
if (key.name === 'left' || key.name === 'right'
|
||||
|| key.name === 'up' || key.name === 'down') {
|
||||
;
|
||||
}
|
||||
|
||||
// if (key.name === 'escape' || key.name === 'enter') {
|
||||
if (key.name === 'escape') {
|
||||
delete this._callback;
|
||||
this.removeListener('keypress', this.__listener);
|
||||
delete this.__listener;
|
||||
callback(null, key.name === 'enter' ? value : null);
|
||||
} else if (key.name === 'backspace') {
|
||||
if (this.value.length) {
|
||||
this.value = this.value.slice(0, -1);
|
||||
/*
|
||||
var last = this._clines[this._clines.length-1];
|
||||
if (last.length === this.width - (this.border ? 2 : 0)) {
|
||||
last = '';
|
||||
}
|
||||
if (last.length === 0) {
|
||||
this.screen.program.cuu();
|
||||
this.screen.program.cuf(this.width - (this.border ? 2 : 0));
|
||||
} else {
|
||||
this.screen.program.cub();
|
||||
}
|
||||
*/
|
||||
}
|
||||
} else {
|
||||
if (ch) {
|
||||
this.value += ch;
|
||||
/*
|
||||
var last = this._clines[this._clines.length-1];
|
||||
if (last.length === this.width - (this.border ? 2 : 0)) {
|
||||
last = '';
|
||||
}
|
||||
if (last.length < this.width - (this.border ? 2 : 0) - 1) {
|
||||
this.screen.program.cuf();
|
||||
} else {
|
||||
this.screen.program.cud();
|
||||
this.screen.program.cub(this.width - (this.border ? 2 : 0));
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
if (this.value !== value) {
|
||||
this.setContent(this.value);
|
||||
this.updateCursor();
|
||||
this.screen.render();
|
||||
}
|
||||
};
|
||||
|
||||
Textarea.prototype.submit = function() {
|
||||
// return this._listener(null, { name: 'enter' });
|
||||
return this._listener('\x1b', { name: 'escape' });
|
||||
};
|
||||
|
||||
Textarea.prototype.cancel = function() {
|
||||
return this._listener('\x1b', { name: 'escape' });
|
||||
};
|
||||
|
||||
Textarea.prototype.editor =
|
||||
Textarea.prototype.readEditor =
|
||||
Textarea.prototype.setEditor = function(callback) {
|
||||
var self = this;
|
||||
|
||||
this.focus();
|
||||
|
||||
return this.screen.readEditor({ value: this.value }, function(err, value) {
|
||||
if (err) return callback(err);
|
||||
self.value = value;
|
||||
self.setContent(self.value);
|
||||
self.screen.render();
|
||||
return self.setInput(callback);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Button
|
||||
*/
|
||||
|
@ -2859,52 +2951,6 @@ function attrCode(code, cur) {
|
|||
return (flags << 18) | (fg << 9) | bg;
|
||||
}
|
||||
|
||||
function readEditor(callback) {
|
||||
var spawn = require('child_process').spawn
|
||||
, fs = require('fs')
|
||||
, editor = process.env.EDITOR || 'vi'
|
||||
, file = '/tmp/blessed.' + Math.random().toString(36);
|
||||
|
||||
var write = process.stdout.write;
|
||||
process.stdout.write = function() {};
|
||||
|
||||
try {
|
||||
process.stdin.pause();
|
||||
} catch (e) {
|
||||
;
|
||||
}
|
||||
|
||||
var resume = function() {
|
||||
try {
|
||||
process.stdin.resume();
|
||||
} catch (e) {
|
||||
;
|
||||
}
|
||||
process.stdout.write = write;
|
||||
};
|
||||
|
||||
var ps = spawn(editor, [file], {
|
||||
stdio: 'inherit',
|
||||
env: process.env,
|
||||
cwd: process.env.HOME
|
||||
});
|
||||
|
||||
ps.on('error', function(err) {
|
||||
resume();
|
||||
return callback(err);
|
||||
});
|
||||
|
||||
ps.on('exit', function(code) {
|
||||
resume();
|
||||
return fs.readFile(file, 'utf8', function(err, data) {
|
||||
return fs.unlink(file, function() {
|
||||
if (err) return callback(err);
|
||||
return callback(null, data);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function sp(line, width, align) {
|
||||
if (!align) return line;
|
||||
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
var blessed = require('blessed');
|
||||
|
||||
var screen = blessed.screen({
|
||||
tput: true
|
||||
});
|
||||
|
||||
var box = blessed.textarea({
|
||||
parent: screen,
|
||||
// Possibly support:
|
||||
// align: 'center',
|
||||
bg: 'blue',
|
||||
height: 'half',
|
||||
width: 'half',
|
||||
top: 'center',
|
||||
left: 'center'
|
||||
});
|
||||
|
||||
screen.render();
|
||||
|
||||
screen.key('q', function() {
|
||||
process.exit(0);
|
||||
});
|
||||
|
||||
screen.key('i', function() {
|
||||
box.readInput(function() {});
|
||||
});
|
||||
|
||||
screen.key('e', function() {
|
||||
box.readEditor(function() {});
|
||||
});
|
Loading…
Reference in New Issue