diff --git a/lib/events.js b/lib/events.js index 3acb07a..85c6204 100644 --- a/lib/events.js +++ b/lib/events.js @@ -104,7 +104,9 @@ EventEmitter.prototype.emit = function(type) { return this._emit(type, args); } - this._emit(type, args); + if (this._emit(type, args) === false) { + return false; + } type = 'element ' + type; args.unshift(this); @@ -132,6 +134,7 @@ EventEmitter.prototype.emit = function(type) { // } // // this._emit.apply(this, arguments); +// if (this._bubbleStopped) return false; // // args = slice.call(arguments, 1); // el = this; diff --git a/lib/program.js b/lib/program.js index d06c324..5144c5b 100644 --- a/lib/program.js +++ b/lib/program.js @@ -67,8 +67,16 @@ function Program(options) { || 'xterm'; this._buf = ''; - this.__flush = this._flush.bind(this); - process.on('exit', this.__flush); + this._flush = this.flush.bind(this); + + 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) { Program.global = this; @@ -1238,8 +1246,8 @@ Program.prototype._parseChar = function(text, attr) { }; Program.prototype._buffer = function(text) { - if (process._exiting) { - this._flush(); + if (this._exiting) { + this.flush(); this.output.write(text); return; } @@ -1251,10 +1259,10 @@ Program.prototype._buffer = function(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; this.output.write(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 */ diff --git a/lib/widget.js b/lib/widget.js index 3f58a6f..e931ac9 100644 --- a/lib/widget.js +++ b/lib/widget.js @@ -266,6 +266,7 @@ function Screen(options) { options = { program: options }; } + options.tput = true; options.buffer = true; options.program = options.program || require('./program').global @@ -368,6 +369,7 @@ function Screen(options) { if (self._listenedMouse) { self.program.disableMouse(); } + self.program.flush(); } this._maxListeners = Infinity; @@ -420,16 +422,15 @@ Screen.prototype.debug = function() { return this.program.debug.apply(this.program, arguments); }; -// TODO: Bubble and capture events throughout the tree. Screen.prototype._listenMouse = function(el) { var self = this; if (el && !~this.clickable.indexOf(el)) { el.clickable = true; - if (el.options.autoFocus && !el._autoFocused) { - el._autoFocused = true; - el.on('element click', el.focus.bind(el)); - } + // if (el.options.autoFocus !== false && !el._autoFocused) { + // el._autoFocused = true; + // el.on('element click', el.focus.bind(el)); + // } this.clickable.push(el); } @@ -438,11 +439,19 @@ Screen.prototype._listenMouse = function(el) { this.program.enableMouse(); + this.on('render', function() { + self._needsClickableSort = true; + }); + this.program.on('mouse', function(data) { if (self.lockKeys) return; - var clickable = hsort(self.clickable) - , i = 0 + if (self._needsClickableSort) { + self.clickable = hsort(self.clickable); + self._needsClickableSort = false; + } + + var i = 0 , left , top , width @@ -451,19 +460,15 @@ Screen.prototype._listenMouse = function(el) { , set , ret; - for (; i < clickable.length; i++) { - el = clickable[i]; + for (; i < self.clickable.length; i++) { + el = self.clickable[i]; if (!el.visible) continue; - // Something like (doesn't work because textbox is usually focused): - // if (self.grabKeys && self.focused !== el + // if (self.grabMouse && self.focused !== el // && !el.hasAncestor(self.focused)) continue; - // Need to use _getCoords() over lpos for when the - // element is obfuscated by a scrollable parent. - ret = el._getCoords(); - //ret = el.lpos; + ret = el.lpos; if (!ret) continue; left = ret.xi; top = ret.yi; @@ -506,9 +511,19 @@ Screen.prototype._listenMouse = function(el) { 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) { var self = this; @@ -516,14 +531,14 @@ Screen.prototype._listenKeys = function(el) { el.keyable = true; // Listen for click, but do not enable // mouse if it's not enabled yet. - if (el.options.autoFocus !== false && !el._autoFocused) { - el._autoFocused = true; - var lm = this._listenedMouse; - this._listenedMouse = true; - this._listenMouse(el); - el.on('element click', el.focus.bind(el)); - this._listenedMouse = lm; - } + // if (el.options.autoFocus !== false && !el._autoFocused) { + // el._autoFocused = true; + // var lm = this._listenedMouse; + // this._listenedMouse = true; + // this._listenMouse(el); + // el.on('element click', el.focus.bind(el)); + // this._listenedMouse = lm; + // } this.keyable.push(el); } @@ -1131,7 +1146,7 @@ Screen.prototype.draw = function(start, end) { : '\x1b[?25h'; } - // this.program._flush(); + // this.program.flush(); // this.program.output.write(pre + main + post); this.program._write(pre + main + post); } @@ -3911,6 +3926,7 @@ List.prototype.type = 'list'; List.prototype.add = function(item) { var self = this; + // Note: Could potentially use Button here. var options = { screen: this.screen, content: item, @@ -3921,7 +3937,8 @@ List.prototype.add = function(item) { tags: this.parseTags, height: 1, 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) {