refactor wrapContent. fix/use/improve getCoords(), scroll(), hide().

This commit is contained in:
Christopher Jeffrey 2013-07-23 15:26:57 -05:00
parent 76cc6d37e7
commit da49a89b28
1 changed files with 62 additions and 43 deletions

View File

@ -439,7 +439,9 @@ Screen.prototype._listenMouse = function(el) {
// if (self.grabKeys && self.focused !== el // if (self.grabKeys && self.focused !== el
// && !el.hasAncestor(self.focused)) continue; // && !el.hasAncestor(self.focused)) continue;
ret = el.lpos; // Need to use _getCoords() over lpos for when the
// element is obfuscated by a scrollable parent.
ret = el._getCoords();
if (!ret) continue; if (!ret) continue;
left = ret.xi; left = ret.xi;
top = ret.yi; top = ret.yi;
@ -1777,8 +1779,8 @@ Element.prototype.onScreenEvent = function(type, listener) {
Element.prototype.hide = function() { Element.prototype.hide = function() {
if (this.hidden) return; if (this.hidden) return;
this.hidden = true;
this.clearPos(); this.clearPos();
this.hidden = true;
this.emit('hide'); this.emit('hide');
var below = this.screen.history[this.screen.history.length-2]; var below = this.screen.history[this.screen.history.length-2];
if (below && this.screen.focused === this) below.focus(); if (below && this.screen.focused === this) below.focus();
@ -1833,9 +1835,9 @@ Element.prototype._focus = function() {
}; };
Element.prototype.setContent = function(content, noClear) { Element.prototype.setContent = function(content, noClear) {
if (!noClear) this.clearPos();
this.content = content || ''; this.content = content || '';
this.parseContent(); this.parseContent();
if (!noClear) this.clearPos();
}; };
Element.prototype.parseContent = function() { Element.prototype.parseContent = function() {
@ -1950,10 +1952,20 @@ Element.prototype._wrapContent = function(content, width) {
, margin = 0 , margin = 0
, rtof = [] , rtof = []
, ftor = [] , ftor = []
, fake = []; , fake = []
, out = []
, no = 0
, line
, align
, cap
, total
, i
, part
, esc
, j
, lines;
var lines = content.split('\n') lines = content.split('\n');
, out = [];
if (!content) { if (!content) {
out.push(content); out.push(content);
@ -1968,9 +1980,15 @@ Element.prototype._wrapContent = function(content, width) {
if (this.type === 'textarea') margin++; if (this.type === 'textarea') margin++;
if (width > margin) width -= margin; if (width > margin) width -= margin;
lines.forEach(function(line, no) { for (; no < lines.length; no++) {
var align = state line = lines[no];
, cap; align = state;
//cap = null;
//total = null;
//i = null;
//part = null;
//esc = null;
//j = null;
ftor.push([]); ftor.push([]);
@ -2000,11 +2018,6 @@ Element.prototype._wrapContent = function(content, width) {
} }
} }
var total
, i
, part
, esc;
if (!wrap && line.length > width) { if (!wrap && line.length > width) {
line = line.slice(0, width); line = line.slice(0, width);
} }
@ -2018,7 +2031,7 @@ Element.prototype._wrapContent = function(content, width) {
if (++total === width) { if (++total === width) {
// Try to find a space to break on: // Try to find a space to break on:
if (line[i] !== ' ') { if (line[i] !== ' ') {
var j = i; j = i;
while (j > i - 10 && j > 0 && line[j] !== ' ') j--; while (j > i - 10 && j > 0 && line[j] !== ' ') j--;
if (line[j] === ' ') i = j + 1; if (line[j] === ' ') i = j + 1;
else i++; else i++;
@ -2050,19 +2063,19 @@ Element.prototype._wrapContent = function(content, width) {
// Make sure we didn't wrap the line to the very end, otherwise // Make sure we didn't wrap the line to the very end, otherwise
// we get a pointless empty line after a newline. // we get a pointless empty line after a newline.
if (line === '') return; if (line === '') continue;
} }
// If only an escape code got cut off, at it to `part`. // If only an escape code got cut off, at it to `part`.
if (/^(?:\x1b[\[\d;]*m)+$/.test(line)) { if (/^(?:\x1b[\[\d;]*m)+$/.test(line)) {
out[out.length-1] += line; out[out.length-1] += line;
return; continue;
} }
out.push(self._align(line, width, align)); out.push(self._align(line, width, align));
ftor[no].push(out.length - 1); ftor[no].push(out.length - 1);
rtof.push(no); rtof.push(no);
}); }
out.rtof = rtof; out.rtof = rtof;
out.ftor = ftor; out.ftor = ftor;
@ -2103,14 +2116,16 @@ Element.prototype.removeKey = function() {
}; };
Element.prototype.clearPos = function() { Element.prototype.clearPos = function() {
// if (this.lpos && !this.lpos.cleared) {
// // optimize by making sure we only clear once.
// this.lpos.cleared = true;
// this.screen.clearRegion(
// this.lpos.xi, this.lpos.xl,
// this.lpos.yi, this.lpos.yl);
// }
if (this.detached) return; if (this.detached) return;
// Need to use _getCoords() over lpos here to avoid clearing
// elements which are obfuscated by a scrollable parent.
// NOTE: COULD USE THIS MULTIPLE PLACES - explanation:
// We could use this.lpos because we don't want
// to clear coordinates that may have changed and may
// not be what/where is actually rendered.
// var lpos = this._getCoords() && this.lpos;
var lpos = this._getCoords(); var lpos = this._getCoords();
if (!lpos) return; if (!lpos) return;
this.screen.clearRegion( this.screen.clearRegion(
@ -3298,7 +3313,11 @@ ScrollableBox.prototype.scroll = function(offset, always) {
, d , d
, p , p
, t , t
, b; , b
, i
, max
, emax
, l;
if (this.alwaysScroll || always) { if (this.alwaysScroll || always) {
// Semi-workaround // Semi-workaround
@ -3328,15 +3347,7 @@ ScrollableBox.prototype.scroll = function(offset, always) {
// Find max "bottom" value for // Find max "bottom" value for
// content and descendant elements. // content and descendant elements.
// Scroll the content if necessary. // Scroll the content if necessary.
var diff = this.childBase - base if (this.childBase === base) {
, w
, i
, max
, emax
, t
, l;
if (diff === 0) {
return this.emit('scroll'); return this.emit('scroll');
} }
@ -3351,7 +3362,6 @@ ScrollableBox.prototype.scroll = function(offset, always) {
if (emax < 0) emax = 0; if (emax < 0) emax = 0;
this.childBase = Math.min(this.childBase, Math.max(emax, max)); this.childBase = Math.min(this.childBase, Math.max(emax, max));
diff = this.childBase - base;
if (this.childBase < 0) { if (this.childBase < 0) {
this.childBase = 0; this.childBase = 0;
@ -3359,20 +3369,26 @@ ScrollableBox.prototype.scroll = function(offset, always) {
this.childBase = this.baseLimit; this.childBase = this.baseLimit;
} }
if (diff > 0) { if (this.childBase > base) {
l = Math.min(this.childBase, this._clines.length); l = Math.min(this.childBase, this._clines.length);
for (i = base; i < l; i++) { for (i = base; i < l; i++) {
this.contentIndex += this._clines[i].length + 1; this.contentIndex += this._clines[i].length + 1;
} }
} else { } else if (this.childBase < base) {
b = Math.min(base, this._clines.length);
l = Math.min(this.childBase, this._clines.length); l = Math.min(this.childBase, this._clines.length);
for (i = base - 1; i >= l; i--) { for (i = b - 1; i >= l; i--) {
this.contentIndex -= this._clines[i].length + 1; this.contentIndex -= this._clines[i].length + 1;
} }
} }
// Optimize scrolling with CSR + IL/DL. // Optimize scrolling with CSR + IL/DL.
p = this.lpos; p = this.lpos;
// Only really need _getCoords() if we want
// to allow nestable scrolling elements...
// or if we **really** want shrinkable
// scrolling elements.
// p = this._getCoords();
if (this.childBase !== base && this.screen.cleanSides(this)) { if (this.childBase !== base && this.screen.cleanSides(this)) {
t = p.yi + this.itop; t = p.yi + this.itop;
b = p.yl - this.ibottom - 1; b = p.yl - this.ibottom - 1;
@ -4013,8 +4029,6 @@ Textbox.prototype.type = 'textbox';
Textbox.prototype.updateCursor = function() { Textbox.prototype.updateCursor = function() {
if (this.screen.focused !== this) return; if (this.screen.focused !== this) return;
//this.screen.program.cup(this.top + this.itop,
// this.left + this.ileft + this.value.length);
var lpos = this._getCoords(); var lpos = this._getCoords();
if (!lpos) return; if (!lpos) return;
this.screen.program.cup(lpos.yi + this.itop, this.screen.program.cup(lpos.yi + this.itop,
@ -5329,8 +5343,11 @@ Listbar.prototype.render = function() {
}; };
Listbar.prototype.select = function(offset) { Listbar.prototype.select = function(offset) {
var lpos = this._getCoords();
if (!lpos) return;
var self = this var self = this
, width = this.lpos ? this.lpos.xl - this.lpos.xi : this.width , width = lpos.xl - lpos.xi
, drawn = 0 , drawn = 0
, visible = 0 , visible = 0
, el; , el;
@ -5345,7 +5362,9 @@ Listbar.prototype.select = function(offset) {
this.items.forEach(function(el, i) { this.items.forEach(function(el, i) {
if (i < self.leftBase) return; if (i < self.leftBase) return;
drawn += (el.lpos ? el.lpos.xl - el.lpos.xi : el.width) + 3; var lpos = el._getCoords();
if (!lpos) return;
drawn += (lpos.xl - lpos.xi) + 3;
if (drawn <= width) visible++; if (drawn <= width) visible++;
}); });