Skip to content

Commit 1a55851

Browse files
committed
Amazing scrolling action
1 parent 64eaf78 commit 1a55851

File tree

2 files changed

+86
-22
lines changed

2 files changed

+86
-22
lines changed

plugins/editor/index.js

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,7 @@ function editor(app, opts, done){
4141
function refreshConsole(){
4242
const { lines } = consoleStore.getState();
4343
scroller.setLines(lines);
44-
45-
if(outputConsole){
46-
requestAnimationFrame(scroller.refresh);
47-
}
44+
scroller.requestRefresh();
4845
}
4946

5047
function highlighter(position, length) {

plugins/editor/scroller.js

Lines changed: 85 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,127 @@
11
'use strict';
22

3-
function generateContent(lines, num) {
4-
return lines.slice(-num).join('\n');
3+
var _ = require('lodash');
4+
5+
function generateContent(lines, start, minLength) {
6+
return _(lines)
7+
.slice(start)
8+
.thru(function(array){
9+
if(array.length < minLength){
10+
// pad whitespace at top of array
11+
return _(new Array(minLength - array.length))
12+
.fill('\u2009')
13+
.concat(array)
14+
.value();
15+
}else{
16+
return array;
17+
}
18+
})
19+
.map(function(line){
20+
if(line.length === 0){
21+
// insert a blank space to prevent pre omitting a trailing newline,
22+
// even though pre/pre-nowrap/pre-line are specified.
23+
return '\u2009';
24+
}
25+
return line;
26+
})
27+
.join('\n');
528
}
629

730
var Scroller = function() {
831
this.lines = [];
932
this.minVisible = 30;
10-
this.visibleCount = this.minVisible;
33+
this.startPosition = 0;
34+
this.animateRequest = null;
1135
this.sticky = true;
36+
this.jumpToBottom = true;
1237
this.dirty = false;
1338
this.console = null;
1439
this.refresh = this.renderVisible.bind(this);
1540
this.scroll = this.onScroll.bind(this);
41+
this.expand = _.throttle(this._expand.bind(this), 100, {
42+
leading: true,
43+
trailing: false
44+
});
1645
};
1746

18-
Scroller.prototype.setLines = function(lines) {
47+
Scroller.prototype.setLines = function(newLines) {
48+
var len = newLines.length;
1949
if(this.sticky){
20-
this.visibleCount = this.minVisible;
21-
}else{
22-
//keep sticky position within view
23-
this.visibleCount += Math.max(0, lines.length - this.lines.length);
50+
this.startPosition = Math.max(0, len - this.minVisible);
2451
}
25-
this.lines = lines;
52+
this.lines = newLines;
53+
this.dirty = true;
54+
};
55+
56+
Scroller.prototype.reset = function(clearLines){
57+
this.visibleCount = this.minVisible;
58+
this.sticky = true;
2659
this.dirty = true;
60+
if(clearLines){
61+
this.lines = [];
62+
this.startPosition = 0;
63+
}
64+
if(this.console){
65+
this.animateRequest = requestAnimationFrame(this.refresh);
66+
}
67+
};
68+
69+
Scroller.prototype.requestRefresh = function(){
70+
if(this.console){
71+
this.animateRequest = requestAnimationFrame(this.refresh);
72+
}
2773
};
2874

2975
Scroller.prototype.renderVisible = function(){
76+
this.animateRequest = null;
3077
if(this.dirty && this.console){
31-
this.console.innerHTML = generateContent(this.lines, this.visibleCount);
3278
if(this.sticky){
79+
this.startPosition = Math.max(0, this.lines.length - this.minVisible);
80+
}
81+
this.console.innerHTML = generateContent(this.lines, this.startPosition, this.minVisible);
82+
if(this.jumpToBottom){
3383
this.console.scrollTop = 350000;
84+
this.jumpToBottom = false;
3485
}
3586
this.dirty = false;
3687
}
3788
};
3889

90+
Scroller.prototype._expand = function(){
91+
this.startPosition = Math.max(0, this.startPosition - this.minVisible);
92+
this.sticky = false;
93+
if(this.console){
94+
var scrollHeight = this.console.scrollHeight;
95+
var scrollTop = this.console.scrollTop;
96+
97+
// do an inline scroll to avoid potential scroll interleaving
98+
this.console.innerHTML = generateContent(this.lines, this.startPosition, this.minVisible);
99+
var newScrollHeight = this.console.scrollHeight;
100+
this.console.scrollTop = scrollTop + newScrollHeight - scrollHeight;
101+
102+
this.dirty = false;
103+
}
104+
if(!this.animateRequest){
105+
this.animateRequest = requestAnimationFrame(this.refresh);
106+
}
107+
};
108+
39109
Scroller.prototype.onScroll = function(){
40110
var height = this.console.offsetHeight;
41111
var scrollHeight = this.console.scrollHeight;
42112
var scrollTop = this.console.scrollTop;
43-
if(scrollTop < 30 && this.visibleCount < this.lines.length){
44-
this.visibleCount += this.minVisible;
45-
this.sticky = false;
46-
this.dirty = true;
47-
}else if(scrollTop + height > scrollHeight - 30){
113+
if(scrollTop < 15 && this.startPosition > 0){
114+
this.expand();
115+
}else if(scrollTop + height > scrollHeight - 15){
48116
if(!this.sticky){
117+
this.jumpToBottom = true;
49118
this.sticky = true;
50119
this.dirty = true;
51120
}
52-
}else{
53-
this.sicky = false;
54121
}
55122

56123
if(this.dirty){
57-
requestAnimationFrame(this.refresh);
124+
this.animateRequest = requestAnimationFrame(this.refresh);
58125
}
59126
};
60127

0 commit comments

Comments
 (0)