optimize clickable sort. better autofocus. flush on exception.

This commit is contained in:
Christopher Jeffrey 2013-08-01 01:52:28 -05:00
parent b2666ffecb
commit d3c34f6f89
3 changed files with 61 additions and 39 deletions

View File

@ -104,7 +104,9 @@ EventEmitter.prototype.emit = function(type) {
return this._emit(type, args); return this._emit(type, args);
} }
this._emit(type, args); if (this._emit(type, args) === false) {
return false;
}
type = 'element ' + type; type = 'element ' + type;
args.unshift(this); args.unshift(this);
@ -132,6 +134,7 @@ EventEmitter.prototype.emit = function(type) {
// } // }
// //
// this._emit.apply(this, arguments); // this._emit.apply(this, arguments);
// if (this._bubbleStopped) return false;
// //
// args = slice.call(arguments, 1); // args = slice.call(arguments, 1);
// el = this; // el = this;

View File

@ -67,8 +67,16 @@ function Program(options) {
|| 'xterm'; || 'xterm';
this._buf = ''; this._buf = '';
this.__flush = this._flush.bind(this); this._flush = this.flush.bind(this);
process.on('exit', this.__flush);
unshiftEvent(process, 'exit', function() {
// Ensure the buffer is flushed (it should
// always be at this point, but who knows).
self.flush();
// Ensure _exiting is set (could technically
// use process._exiting).
self._exiting = true;
});
if (!Program.global) { if (!Program.global) {
Program.global = this; Program.global = this;
@ -1238,8 +1246,8 @@ Program.prototype._parseChar = function(text, attr) {
}; };
Program.prototype._buffer = function(text) { Program.prototype._buffer = function(text) {
if (process._exiting) { if (this._exiting) {
this._flush(); this.flush();
this.output.write(text); this.output.write(text);
return; return;
} }
@ -1251,10 +1259,10 @@ Program.prototype._buffer = function(text) {
this._buf = text; this._buf = text;
process.nextTick(this.__flush); process.nextTick(this._flush);
}; };
Program.prototype._flush = function(text) { Program.prototype.flush = function(text) {
if (!this._buf) return; if (!this._buf) return;
this.output.write(this._buf); this.output.write(this._buf);
this._buf = ''; this._buf = '';
@ -3526,12 +3534,6 @@ function unshiftEvent(obj, event, listener) {
}); });
}; };
// Ensure _exiting is set for future versions of node that may remove it.
// We need this to be the first listener executed.
unshiftEvent(process, 'exit', function() {
process._exiting = true;
});
/** /**
* Expose * Expose
*/ */

View File

@ -266,6 +266,7 @@ function Screen(options) {
options = { program: options }; options = { program: options };
} }
options.tput = true;
options.buffer = true; options.buffer = true;
options.program = options.program options.program = options.program
|| require('./program').global || require('./program').global
@ -368,6 +369,7 @@ function Screen(options) {
if (self._listenedMouse) { if (self._listenedMouse) {
self.program.disableMouse(); self.program.disableMouse();
} }
self.program.flush();
} }
this._maxListeners = Infinity; this._maxListeners = Infinity;
@ -420,16 +422,15 @@ Screen.prototype.debug = function() {
return this.program.debug.apply(this.program, arguments); return this.program.debug.apply(this.program, arguments);
}; };
// TODO: Bubble and capture events throughout the tree.
Screen.prototype._listenMouse = function(el) { Screen.prototype._listenMouse = function(el) {
var self = this; var self = this;
if (el && !~this.clickable.indexOf(el)) { if (el && !~this.clickable.indexOf(el)) {
el.clickable = true; el.clickable = true;
if (el.options.autoFocus && !el._autoFocused) { // if (el.options.autoFocus !== false && !el._autoFocused) {
el._autoFocused = true; // el._autoFocused = true;
el.on('element click', el.focus.bind(el)); // el.on('element click', el.focus.bind(el));
} // }
this.clickable.push(el); this.clickable.push(el);
} }
@ -438,11 +439,19 @@ Screen.prototype._listenMouse = function(el) {
this.program.enableMouse(); this.program.enableMouse();
this.on('render', function() {
self._needsClickableSort = true;
});
this.program.on('mouse', function(data) { this.program.on('mouse', function(data) {
if (self.lockKeys) return; if (self.lockKeys) return;
var clickable = hsort(self.clickable) if (self._needsClickableSort) {
, i = 0 self.clickable = hsort(self.clickable);
self._needsClickableSort = false;
}
var i = 0
, left , left
, top , top
, width , width
@ -451,19 +460,15 @@ Screen.prototype._listenMouse = function(el) {
, set , set
, ret; , ret;
for (; i < clickable.length; i++) { for (; i < self.clickable.length; i++) {
el = clickable[i]; el = self.clickable[i];
if (!el.visible) continue; if (!el.visible) continue;
// Something like (doesn't work because textbox is usually focused): // if (self.grabMouse && self.focused !== el
// if (self.grabKeys && self.focused !== el
// && !el.hasAncestor(self.focused)) continue; // && !el.hasAncestor(self.focused)) continue;
// Need to use _getCoords() over lpos for when the ret = el.lpos;
// element is obfuscated by a scrollable parent.
ret = el._getCoords();
//ret = el.lpos;
if (!ret) continue; if (!ret) continue;
left = ret.xi; left = ret.xi;
top = ret.yi; top = ret.yi;
@ -506,9 +511,19 @@ Screen.prototype._listenMouse = function(el) {
self.emit('mouse', data); self.emit('mouse', data);
}); });
// Autofocus elements with the appropriate option.
this.on('element click', function(el, data) {
var target;
//do {
if (el.clickable === true && el.options.autoFocus !== false) {
target = el;
}
//} while (el = el.parent);
if (target) target.focus();
});
}; };
// TODO: Bubble and capture events throughout the tree.
Screen.prototype._listenKeys = function(el) { Screen.prototype._listenKeys = function(el) {
var self = this; var self = this;
@ -516,14 +531,14 @@ Screen.prototype._listenKeys = function(el) {
el.keyable = true; el.keyable = true;
// Listen for click, but do not enable // Listen for click, but do not enable
// mouse if it's not enabled yet. // mouse if it's not enabled yet.
if (el.options.autoFocus !== false && !el._autoFocused) { // if (el.options.autoFocus !== false && !el._autoFocused) {
el._autoFocused = true; // el._autoFocused = true;
var lm = this._listenedMouse; // var lm = this._listenedMouse;
this._listenedMouse = true; // this._listenedMouse = true;
this._listenMouse(el); // this._listenMouse(el);
el.on('element click', el.focus.bind(el)); // el.on('element click', el.focus.bind(el));
this._listenedMouse = lm; // this._listenedMouse = lm;
} // }
this.keyable.push(el); this.keyable.push(el);
} }
@ -1131,7 +1146,7 @@ Screen.prototype.draw = function(start, end) {
: '\x1b[?25h'; : '\x1b[?25h';
} }
// this.program._flush(); // this.program.flush();
// this.program.output.write(pre + main + post); // this.program.output.write(pre + main + post);
this.program._write(pre + main + post); this.program._write(pre + main + post);
} }
@ -3911,6 +3926,7 @@ List.prototype.type = 'list';
List.prototype.add = function(item) { List.prototype.add = function(item) {
var self = this; var self = this;
// Note: Could potentially use Button here.
var options = { var options = {
screen: this.screen, screen: this.screen,
content: item, content: item,
@ -3921,7 +3937,8 @@ List.prototype.add = function(item) {
tags: this.parseTags, tags: this.parseTags,
height: 1, height: 1,
hoverEffects: this.mouse ? this.style.item.hover : null, hoverEffects: this.mouse ? this.style.item.hover : null,
focusEffects: this.mouse ? this.style.item.focus : null focusEffects: this.mouse ? this.style.item.focus : null,
autoFocus: false
}; };
if (this.screen.autoPadding) { if (this.screen.autoPadding) {