docs, tests, examples, misc, editor.

This commit is contained in:
Christopher Jeffrey 2013-07-03 23:15:09 -05:00
parent 05216eadbb
commit 6355b1259f
4 changed files with 261 additions and 27 deletions

View File

@ -194,6 +194,7 @@ The screen on which every other node renders.
- **mouse** - received on mouse events. - **mouse** - received on mouse events.
- **keypress** - received on key events. - **keypress** - received on key events.
- **element [name]** - global events received for all elements. - **element [name]** - global events received for all elements.
- **key [name]** - received on key event for [name].
##### Methods: ##### Methods:
@ -215,6 +216,11 @@ The screen on which every other node renders.
- **focusPop()/focusLast()** - pop element off the focus stack. - **focusPop()/focusLast()** - pop element off the focus stack.
- **saveFocus()** - save the focused element. - **saveFocus()** - save the focused element.
- **restoreFocus()** - restore the saved focused element. - **restoreFocus()** - restore the saved focused element.
- **key(name, listener)** - bind a keypress listener for a specific key.
- **spawn(file, args, options)** - spawn a process in the foreground, return to
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.
#### Element (from Node) #### Element (from Node)
@ -271,6 +277,7 @@ The base element.
- **keypress** - received on key events for this element. - **keypress** - received on key events for this element.
- **move** - received when the element is moved. - **move** - received when the element is moved.
- **resize** - received when the element is resized. - **resize** - received when the element is resized.
- **key [name]** - received on key event for [name].
##### Methods: ##### Methods:
@ -281,6 +288,7 @@ The base element.
- **show()** - show element. - **show()** - show element.
- **toggle()** - toggle hidden/shown. - **toggle()** - toggle hidden/shown.
- **focus()** - focus element. - **focus()** - focus element.
- **key(name, listener)** - bind a keypress listener for a specific key.
#### Box (from Element) #### Box (from Element)
@ -507,7 +515,7 @@ an element has the `position: absolute` CSS property.
When an element is created, it can be given coordinates in its constructor: When an element is created, it can be given coordinates in its constructor:
``` js ``` js
var box = new blessed.Box({ var box = blessed.box({
left: 'center', left: 'center',
top: 'center', top: 'center',
bg: 'yellow', bg: 'yellow',
@ -604,7 +612,7 @@ it is hard to do this optimization automatically (blessed assumes you may
create any element of any width in any position). So, there is a solution: create any element of any width in any position). So, there is a solution:
``` js ``` js
var box = new blessed.Box(...); var box = blessed.box(...);
box.setContent('line 1\nline 2'); box.setContent('line 1\nline 2');
box.insertBottom('line 3'); box.insertBottom('line 3');
box.insertBottom('line 4'); box.insertBottom('line 4');

View File

@ -41,14 +41,9 @@ function Node(options) {
(options.children || []).forEach(this.append.bind(this)); (options.children || []).forEach(this.append.bind(this));
if (this.type === 'screen' && !this.focused) { // if (this.type === 'screen' && !this.focused) {
this.focused = this.children[0]; // this.focused = this.children[0];
} // }
var self = this;
this.on('keypress', function(ch, key) {
self.emit('key ' + key.name, key);
});
} }
Node.uid = 0; Node.uid = 0;
@ -57,10 +52,6 @@ Node.prototype.__proto__ = EventEmitter.prototype;
Node.prototype.type = 'node'; Node.prototype.type = 'node';
Node.prototype.key = function(name, listener) {
return this.on('key ' + name, listener);
};
Node.prototype.prepend = function(element) { Node.prototype.prepend = function(element) {
var old = element.parent; var old = element.parent;
@ -300,12 +291,9 @@ function Screen(options) {
}); });
this.on('newListener', function fn(type) { this.on('newListener', function fn(type) {
if (type === 'keypress' || type === 'mouse') { if (type === 'keypress' || type.indexOf('key ') === 0 || type === 'mouse') {
if (type === 'keypress') self._listenKeys(); if (type === 'keypress' || type.indexOf('key ') === 0) self._listenKeys();
if (type === 'mouse') self._listenMouse(); if (type === 'mouse') self._listenMouse();
// if (self._listenedKeys && self._listenedMouse) {
// self.removeListener('newListener', fn);
// }
} }
}); });
} }
@ -316,7 +304,7 @@ Screen.prototype.__proto__ = Node.prototype;
Screen.prototype.type = 'screen'; Screen.prototype.type = 'screen';
// TODO: Bubble events. // TODO: Bubble and capture events throughout the tree.
Screen.prototype._listenMouse = function(el) { Screen.prototype._listenMouse = function(el) {
var self = this; var self = this;
@ -431,6 +419,7 @@ Screen.prototype._listenKeys = function(el) {
if (!grabKeys) { if (!grabKeys) {
self.emit('keypress', ch, key); self.emit('keypress', ch, key);
self.emit('key ' + key.name, ch, key);
} }
// If something changed from the screen key handler, stop. // If something changed from the screen key handler, stop.
@ -440,6 +429,8 @@ Screen.prototype._listenKeys = function(el) {
if (~self.input.indexOf(focused)) { if (~self.input.indexOf(focused)) {
focused.emit('keypress', ch, key); focused.emit('keypress', ch, key);
focused.emit('key ' + key.name, ch, key);
// self.emit('element keypress', focused, ch, key);
} }
}); });
}; };
@ -554,6 +545,15 @@ Screen.prototype.insertTop = function(top, bottom) {
return this.insertLine(1, top, top, bottom); return this.insertLine(1, top, top, bottom);
}; };
Screen.prototype.deleteBottom = function(top, bottom) {
return this.clearRegion(0, this.width, bottom, bottom);
};
Screen.prototype.deleteTop = function(top, bottom) {
// return this.insertBottom(top, bottom);
return this.deleteLine(1, top, top, bottom);
};
Screen.prototype.draw = function(start, end) { Screen.prototype.draw = function(start, end) {
var x var x
, y , y
@ -802,6 +802,108 @@ Screen.prototype.fillRegion = function(attr, ch, xi, xl, yi, yl) {
} }
}; };
Screen.prototype.key = function(key, listener) {
return this.on('key ' + key, listener);
};
Screen.prototype.spawn = function(file, args, options) {
if (!Array.isArray(args)) {
options = args;
args = [];
}
var options = options || {}
, spawn = require('child_process').spawn
, screen = this;
options.stdio = 'inherit';
screen.program.normalBuffer();
screen.program.showCursor();
var _listenedMouse = screen._listenedMouse;
if (_listenedMouse) {
screen.program.disableMouse();
}
var write = process.stdout.write;
process.stdout.write = function() {};
try {
process.stdin.pause();
} catch (e) {
;
}
var resume = function() {
if (resume.done) return;
resume.done = true;
try {
process.stdin.resume();
} catch (e) {
;
}
process.stdout.write = write;
screen.program.alternateBuffer();
screen.program.hideCursor();
if (_listenedMouse) {
screen.program.enableMouse();
}
screen.alloc();
screen.render();
};
var ps = spawn(file, args, options);
ps.on('error', resume);
ps.on('exit', resume);
return ps;
};
Screen.prototype.exec = function(file, args, options, callback) {
var callback = arguments[arguments.length-1]
, ps = this.spawn(file, args, options);
ps.on('error', function(err) {
return callback(err, false);
});
ps.on('exit', function(code) {
return callback(null, code === 0);
});
return ps;
};
Screen.prototype.readEditor = function(callback) {
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.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);
});
});
});
};
/** /**
* Element * Element
*/ */
@ -885,7 +987,7 @@ function Element(options) {
|| type === 'wheelup' || type === 'wheelup'
|| type === 'mousemove') { || type === 'mousemove') {
self.screen._listenMouse(self); self.screen._listenMouse(self);
} else if (type === 'keypress') { } else if (type === 'keypress' || type.indexOf('key ') === 0) {
self.screen._listenKeys(self); self.screen._listenKeys(self);
} }
}); });
@ -1365,6 +1467,11 @@ Element.prototype.__defineSetter__('rright', function(val) {
Element.prototype.__defineSetter__('rtop', function(val) { Element.prototype.__defineSetter__('rtop', function(val) {
if (this.position.top === val) return; if (this.position.top === val) return;
this.emit('move'); this.emit('move');
// if (this._lastPos) {
// this.screen.clearRegion(
// this._lastPos.xi, this._lastPos.xl,
// this._lastPos.yi, this._lastPos.yl);
// }
this.screen.clearRegion( this.screen.clearRegion(
this.left, this.left + this.width, this.left, this.left + this.width,
this.top, this.top + this.height); this.top, this.top + this.height);
@ -1383,6 +1490,10 @@ Element.prototype.__defineSetter__('rbottom', function(val) {
return this.options.bottom = this.position.bottom = val; return this.options.bottom = this.position.bottom = val;
}); });
Element.prototype.key = function(key, listener) {
return this.on('key ' + key, listener);
};
/** /**
* Box * Box
*/ */
@ -1755,16 +1866,32 @@ Box.prototype.insertTop = function(line) {
if (this._lastPos && this._lastPos.xi === 0 && this._lastPos.xl === this.screen.width) { if (this._lastPos && this._lastPos.xi === 0 && this._lastPos.xl === this.screen.width) {
this.screen.insertTop(this._lastPos.yi, this._lastPos.yl - 1); this.screen.insertTop(this._lastPos.yi, this._lastPos.yl - 1);
} }
this.setContent(line + '\n' + this.content, true); this._clines.splice((this.childBase || 0) + (this.border ? 1 : 0), 0, line);
// this.screen.render(); this.setContent(this._clines.join('\n'), true);
}; };
Box.prototype.insertBottom = function(line) { Box.prototype.insertBottom = function(line) {
if (this._lastPos && this._lastPos.xi === 0 && this._lastPos.xl === this.screen.width) { if (this._lastPos && this._lastPos.xi === 0 && this._lastPos.xl === this.screen.width) {
this.screen.insertBottom(this._lastPos.yi, this._lastPos.yl - 1); this.screen.insertBottom(this._lastPos.yi, this._lastPos.yl - 1);
} }
this.setContent(this.content + '\n' + line, true); this._clines.splice((this.childBase || 0) + this.height - (this.border ? 2 : 0), 0, line);
// this.screen.render(); this.setContent(this._clines.join('\n'), true);
};
Box.prototype.deleteTop = function() {
if (this._lastPos && this._lastPos.xi === 0 && this._lastPos.xl === this.screen.width) {
this.screen.deleteTop(this._lastPos.yi, this._lastPos.yl - 1);
}
this._clines.splice((this.childBase || 0) + (this.border ? 1 : 0), 1);
this.setContent(this._clines.join('\n'), true);
};
Box.prototype.deleteBottom = function() {
if (this._lastPos && this._lastPos.xi === 0 && this._lastPos.xl === this.screen.width) {
this.screen.deleteBottom(this._lastPos.yi, this._lastPos.yl - 1);
}
this._clines.splice((this.childBase || 0) + this.height - (this.border ? 2 : 0), 1);
this.setContent(this._clines.join('\n'), true);
}; };
/** /**
@ -2438,6 +2565,71 @@ Textbox.prototype.setEditor = function(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) {
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);
});
};
/** /**
* Textarea * Textarea
*/ */

31
test/widget-insert.js Normal file
View File

@ -0,0 +1,31 @@
var blessed = require('blessed');
var screen = blessed.screen({
tput: true
});
var box = blessed.box({
parent: screen,
align: 'center',
bg: 'blue',
height: 5,
top: 'center',
left: 0,
content: 'line 1'
});
screen.render();
box.insertBottom('line 2');
box.insertTop('line 0');
screen.render();
setTimeout(function() {
box.deleteTop();
screen.render();
}, 2000);
screen.key('q', function() {
process.exit(0);
});

View File

@ -1,5 +1,8 @@
var blessed = require('blessed') var blessed = require('blessed');
, screen = blessed.Screen({ tput: true });
var screen = new blessed.Screen({
tput: true
});
screen.append(new blessed.Text({ screen.append(new blessed.Text({
top: 0, top: 0,