From 350d0890aec6dd01067be462b43270a4fd189022 Mon Sep 17 00:00:00 2001 From: Matthew Shepard Date: Thu, 16 Jul 2015 16:48:42 -0700 Subject: [PATCH 01/14] Implement tx/rx flash with manual dom elements --- plugins/editor/indicators.js | 77 ++++++++++++++++++++++++++---- plugins/editor/styles.js | 4 +- plugins/editor/transmission-bar.js | 22 +++------ 3 files changed, 75 insertions(+), 28 deletions(-) diff --git a/plugins/editor/indicators.js b/plugins/editor/indicators.js index da33017..f5d1862 100644 --- a/plugins/editor/indicators.js +++ b/plugins/editor/indicators.js @@ -1,29 +1,86 @@ 'use strict'; +const _ = require('lodash'); const React = require('react'); +const { createContainer } = require('sovereign'); const styles = require('./styles'); +const transmissionStore = require('../../src/stores/transmission'); class Indicators extends React.Component { - render() { - const { flashRx, flashTx } = this.props; + componentDidMount() { + var parent = React.findDOMNode(this); + var tx = this.tx = document.createElement('span'); + var rx = this.rx = document.createElement('span'); + this.txLabel = document.createTextNode('TX'); + this.rxLabel = document.createTextNode(' RX'); + parent.appendChild(this.txLabel); + parent.appendChild(tx); + parent.appendChild(this.rxLabel); + parent.appendChild(rx); + _.forEach(styles.indicator, function(style, name){ + tx.style[name] = style; + rx.style[name] = style; + }); + console.log('componentDidMount', tx, rx, tx.style); + } - let indicatorRx = [styles.indicator]; - let indicatorTx = [styles.indicator]; - if(flashRx) { - indicatorRx.push(styles.rx); + componentWillUnmount() { + console.log('componentWillUnmount'); + var parent = React.findDOMNode(this); + parent.removeChild(this.tx); + parent.removeChild(this.rx); + this.tx = null; + this.rx = null; + } + + shouldComponentUpdate(nextProps) { + const { flashRx, flashTx } = this.props; + if(this.rx != null && nextProps.flashRx !== flashRx){ + if(nextProps.flashRx){ + this.rx.style.backgroundColor = styles.rx.backgroundColor; + }else{ + this.rx.style.backgroundColor = styles.indicator.backgroundColor; + } } - if(flashTx) { - indicatorTx.push(styles.tx); + if(this.tx != null && nextProps.flashTx !== flashTx){ + if(nextProps.flashTx){ + this.tx.style.backgroundColor = styles.tx.backgroundColor; + }else{ + this.tx.style.backgroundColor = styles.indicator.backgroundColor; + } } + return false; + } + + render() { + // const { flashRx, flashTx } = this.props; + // let indicatorRx = [styles.indicator]; + // let indicatorTx = [styles.indicator]; + // if(flashRx) { + // indicatorRx.push(styles.rx); + // } + // if(flashTx) { + // indicatorTx.push(styles.tx); + // } + //TX RX return ( - TXRX ); } } -module.exports = Indicators; +module.exports = createContainer(Indicators, { + getStores(){ + return { + deviceStore: transmissionStore + }; + }, + + getPropsFromStores() { + return transmissionStore.getState(); + } +}); diff --git a/plugins/editor/styles.js b/plugins/editor/styles.js index 9e46829..a346857 100644 --- a/plugins/editor/styles.js +++ b/plugins/editor/styles.js @@ -20,8 +20,8 @@ const styles = { }, indicator: { backgroundColor: grey, - height: 10, - width: 10, + height: '10px', + width: '10px', borderRadius: '100%', margin: '0px 10px', display: 'inline-block' diff --git a/plugins/editor/transmission-bar.js b/plugins/editor/transmission-bar.js index 17f4081..b1305a0 100644 --- a/plugins/editor/transmission-bar.js +++ b/plugins/editor/transmission-bar.js @@ -1,33 +1,23 @@ 'use strict'; const React = require('react'); -const { createContainer } = require('sovereign'); const Indicators = require('./indicators'); const styles = require('./styles'); -const transmissionStore = require('../../src/stores/transmission'); class TransmissionBar extends React.Component { - render() { - const { flashRx, flashTx } = this.props; + shouldComponentUpdate() { + return false; + } + render() { return (
- +
); } } -module.exports = createContainer(TransmissionBar, { - getStores(){ - return { - deviceStore: transmissionStore - }; - }, - - getPropsFromStores() { - return transmissionStore.getState(); - } -}); +module.exports = TransmissionBar; From b411a9990d4d37cf2226e802cadb01815c06533a Mon Sep 17 00:00:00 2001 From: Blaine Bublitz Date: Thu, 16 Jul 2015 17:30:00 -0700 Subject: [PATCH 02/14] ct and speeds --- plugins/editor/indicators.js | 67 ++++++++++++--------------------- plugins/editor/transmit-pane.js | 5 +++ 2 files changed, 29 insertions(+), 43 deletions(-) diff --git a/plugins/editor/indicators.js b/plugins/editor/indicators.js index f5d1862..a7f34f3 100644 --- a/plugins/editor/indicators.js +++ b/plugins/editor/indicators.js @@ -2,13 +2,30 @@ const _ = require('lodash'); const React = require('react'); -const { createContainer } = require('sovereign'); const styles = require('./styles'); const transmissionStore = require('../../src/stores/transmission'); class Indicators extends React.Component { + constructor(){ + this._updateIndicators = this._updateIndicators.bind(this); + } + + _updateIndicators(){ + const { flashRx, flashTx } = transmissionStore.getState(); + if(flashRx){ + this.rx.style.backgroundColor = styles.rx.backgroundColor; + } else { + this.rx.style.backgroundColor = styles.indicator.backgroundColor; + } + if(flashTx){ + this.tx.style.backgroundColor = styles.tx.backgroundColor; + } else { + this.tx.style.backgroundColor = styles.indicator.backgroundColor; + } + } + componentDidMount() { var parent = React.findDOMNode(this); var tx = this.tx = document.createElement('span'); @@ -23,64 +40,28 @@ class Indicators extends React.Component { tx.style[name] = style; rx.style[name] = style; }); - console.log('componentDidMount', tx, rx, tx.style); + + transmissionStore.listen(this._updateIndicators); } componentWillUnmount() { - console.log('componentWillUnmount'); var parent = React.findDOMNode(this); parent.removeChild(this.tx); parent.removeChild(this.rx); this.tx = null; this.rx = null; + transmissionStore.unlisten(this._updateIndicators); } - shouldComponentUpdate(nextProps) { - const { flashRx, flashTx } = this.props; - if(this.rx != null && nextProps.flashRx !== flashRx){ - if(nextProps.flashRx){ - this.rx.style.backgroundColor = styles.rx.backgroundColor; - }else{ - this.rx.style.backgroundColor = styles.indicator.backgroundColor; - } - } - if(this.tx != null && nextProps.flashTx !== flashTx){ - if(nextProps.flashTx){ - this.tx.style.backgroundColor = styles.tx.backgroundColor; - }else{ - this.tx.style.backgroundColor = styles.indicator.backgroundColor; - } - } + shouldComponentUpdate() { return false; } render() { - // const { flashRx, flashTx } = this.props; - - // let indicatorRx = [styles.indicator]; - // let indicatorTx = [styles.indicator]; - // if(flashRx) { - // indicatorRx.push(styles.rx); - // } - // if(flashTx) { - // indicatorTx.push(styles.tx); - // } - //TX RX return ( - - + ); } } -module.exports = createContainer(Indicators, { - getStores(){ - return { - deviceStore: transmissionStore - }; - }, - - getPropsFromStores() { - return transmissionStore.getState(); - } -}); +module.exports = Indicators; diff --git a/plugins/editor/transmit-pane.js b/plugins/editor/transmit-pane.js index eec4802..0f0d616 100644 --- a/plugins/editor/transmit-pane.js +++ b/plugins/editor/transmit-pane.js @@ -38,6 +38,11 @@ class TransmitPane extends React.Component { transmitInput(data); } + shouldComponentUpdate(nextProps){ + const { connected, text } = this.props; + return (connected !== nextProps.connected || text !== nextProps.text); + } + render() { const { connected, text } = this.props; return ( From a0a35a0a035bcf95622c32e3bd9151049418366a Mon Sep 17 00:00:00 2001 From: Blaine Bublitz Date: Thu, 16 Jul 2015 19:25:15 -0700 Subject: [PATCH 03/14] attempt to raf the scrollTop --- plugins/editor/index.js | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/plugins/editor/index.js b/plugins/editor/index.js index 9e55fd3..65b7d81 100644 --- a/plugins/editor/index.js +++ b/plugins/editor/index.js @@ -34,16 +34,29 @@ function editor(app, opts, done){ var outputConsole; var transmission; var transmitPane; + var scrollDown = false; function refreshConsole(){ const { text } = consoleStore.getState(); if(outputConsole){ + scrollDown = true; outputConsole.innerHTML = text; - outputConsole.scrollTop = outputConsole.scrollHeight; + // outputConsole.scrollTop = outputConsole.scrollHeight; } } + function updateScroll(){ + requestAnimationFrame(updateScroll); + + if(outputConsole && scrollDown){ + scrollDown = false; + outputConsole.scrollTop = 350000; + } + } + + requestAnimationFrame(updateScroll); + function highlighter(position, length) { if(!codeEditor){ return; From 64eaf78db571a44addd720dbd22b2b1e86a9fb40 Mon Sep 17 00:00:00 2001 From: Matthew Shepard Date: Fri, 17 Jul 2015 17:22:12 -0700 Subject: [PATCH 04/14] Experimental auto-expanding console --- plugins/editor/index.js | 26 ++++++--------- plugins/editor/scroller.js | 65 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 16 deletions(-) create mode 100644 plugins/editor/scroller.js diff --git a/plugins/editor/index.js b/plugins/editor/index.js index 65b7d81..b6c93d3 100644 --- a/plugins/editor/index.js +++ b/plugins/editor/index.js @@ -28,35 +28,25 @@ const TransmitPane = require('./transmit-pane'); const makeToasts = require('../../src/lib/toasts'); +const Scroller = require('./scroller'); + function editor(app, opts, done){ var codeEditor; var outputConsole; var transmission; var transmitPane; - var scrollDown = false; + var scroller = new Scroller(); function refreshConsole(){ - const { text } = consoleStore.getState(); + const { lines } = consoleStore.getState(); + scroller.setLines(lines); if(outputConsole){ - scrollDown = true; - outputConsole.innerHTML = text; - // outputConsole.scrollTop = outputConsole.scrollHeight; - } - } - - function updateScroll(){ - requestAnimationFrame(updateScroll); - - if(outputConsole && scrollDown){ - scrollDown = false; - outputConsole.scrollTop = 350000; + requestAnimationFrame(scroller.refresh); } } - requestAnimationFrame(updateScroll); - function highlighter(position, length) { if(!codeEditor){ return; @@ -140,6 +130,10 @@ function editor(app, opts, done){ outputConsole.style.overflow = 'auto'; outputConsole.style.whiteSpace = 'pre-wrap'; el.appendChild(outputConsole); + + scroller.setConsole(outputConsole); + + outputConsole.addEventListener('scroll', scroller.scroll, false); } if(!transmission) { transmission = document.createElement('div'); diff --git a/plugins/editor/scroller.js b/plugins/editor/scroller.js new file mode 100644 index 0000000..8f7e341 --- /dev/null +++ b/plugins/editor/scroller.js @@ -0,0 +1,65 @@ +'use strict'; + +function generateContent(lines, num) { + return lines.slice(-num).join('\n'); +} + +var Scroller = function() { + this.lines = []; + this.minVisible = 30; + this.visibleCount = this.minVisible; + this.sticky = true; + this.dirty = false; + this.console = null; + this.refresh = this.renderVisible.bind(this); + this.scroll = this.onScroll.bind(this); +}; + +Scroller.prototype.setLines = function(lines) { + if(this.sticky){ + this.visibleCount = this.minVisible; + }else{ + //keep sticky position within view + this.visibleCount += Math.max(0, lines.length - this.lines.length); + } + this.lines = lines; + this.dirty = true; +}; + +Scroller.prototype.renderVisible = function(){ + if(this.dirty && this.console){ + this.console.innerHTML = generateContent(this.lines, this.visibleCount); + if(this.sticky){ + this.console.scrollTop = 350000; + } + this.dirty = false; + } +}; + +Scroller.prototype.onScroll = function(){ + var height = this.console.offsetHeight; + var scrollHeight = this.console.scrollHeight; + var scrollTop = this.console.scrollTop; + if(scrollTop < 30 && this.visibleCount < this.lines.length){ + this.visibleCount += this.minVisible; + this.sticky = false; + this.dirty = true; + }else if(scrollTop + height > scrollHeight - 30){ + if(!this.sticky){ + this.sticky = true; + this.dirty = true; + } + }else{ + this.sicky = false; + } + + if(this.dirty){ + requestAnimationFrame(this.refresh); + } +}; + +Scroller.prototype.setConsole = function(console){ + this.console = console; +}; + +module.exports = Scroller; From 1a558514a3716f1bb152fd8f99acafcebe611ba5 Mon Sep 17 00:00:00 2001 From: Matthew Shepard Date: Mon, 20 Jul 2015 14:02:08 -0700 Subject: [PATCH 05/14] Amazing scrolling action --- plugins/editor/index.js | 5 +- plugins/editor/scroller.js | 103 ++++++++++++++++++++++++++++++------- 2 files changed, 86 insertions(+), 22 deletions(-) diff --git a/plugins/editor/index.js b/plugins/editor/index.js index b6c93d3..2129cdb 100644 --- a/plugins/editor/index.js +++ b/plugins/editor/index.js @@ -41,10 +41,7 @@ function editor(app, opts, done){ function refreshConsole(){ const { lines } = consoleStore.getState(); scroller.setLines(lines); - - if(outputConsole){ - requestAnimationFrame(scroller.refresh); - } + scroller.requestRefresh(); } function highlighter(position, length) { diff --git a/plugins/editor/scroller.js b/plugins/editor/scroller.js index 8f7e341..c0ee383 100644 --- a/plugins/editor/scroller.js +++ b/plugins/editor/scroller.js @@ -1,60 +1,127 @@ 'use strict'; -function generateContent(lines, num) { - return lines.slice(-num).join('\n'); +var _ = require('lodash'); + +function generateContent(lines, start, minLength) { + return _(lines) + .slice(start) + .thru(function(array){ + if(array.length < minLength){ + // pad whitespace at top of array + return _(new Array(minLength - array.length)) + .fill('\u2009') + .concat(array) + .value(); + }else{ + return array; + } + }) + .map(function(line){ + if(line.length === 0){ + // insert a blank space to prevent pre omitting a trailing newline, + // even though pre/pre-nowrap/pre-line are specified. + return '\u2009'; + } + return line; + }) + .join('\n'); } var Scroller = function() { this.lines = []; this.minVisible = 30; - this.visibleCount = this.minVisible; + this.startPosition = 0; + this.animateRequest = null; this.sticky = true; + this.jumpToBottom = true; this.dirty = false; this.console = null; this.refresh = this.renderVisible.bind(this); this.scroll = this.onScroll.bind(this); + this.expand = _.throttle(this._expand.bind(this), 100, { + leading: true, + trailing: false + }); }; -Scroller.prototype.setLines = function(lines) { +Scroller.prototype.setLines = function(newLines) { + var len = newLines.length; if(this.sticky){ - this.visibleCount = this.minVisible; - }else{ - //keep sticky position within view - this.visibleCount += Math.max(0, lines.length - this.lines.length); + this.startPosition = Math.max(0, len - this.minVisible); } - this.lines = lines; + this.lines = newLines; + this.dirty = true; +}; + +Scroller.prototype.reset = function(clearLines){ + this.visibleCount = this.minVisible; + this.sticky = true; this.dirty = true; + if(clearLines){ + this.lines = []; + this.startPosition = 0; + } + if(this.console){ + this.animateRequest = requestAnimationFrame(this.refresh); + } +}; + +Scroller.prototype.requestRefresh = function(){ + if(this.console){ + this.animateRequest = requestAnimationFrame(this.refresh); + } }; Scroller.prototype.renderVisible = function(){ + this.animateRequest = null; if(this.dirty && this.console){ - this.console.innerHTML = generateContent(this.lines, this.visibleCount); if(this.sticky){ + this.startPosition = Math.max(0, this.lines.length - this.minVisible); + } + this.console.innerHTML = generateContent(this.lines, this.startPosition, this.minVisible); + if(this.jumpToBottom){ this.console.scrollTop = 350000; + this.jumpToBottom = false; } this.dirty = false; } }; +Scroller.prototype._expand = function(){ + this.startPosition = Math.max(0, this.startPosition - this.minVisible); + this.sticky = false; + if(this.console){ + var scrollHeight = this.console.scrollHeight; + var scrollTop = this.console.scrollTop; + + // do an inline scroll to avoid potential scroll interleaving + this.console.innerHTML = generateContent(this.lines, this.startPosition, this.minVisible); + var newScrollHeight = this.console.scrollHeight; + this.console.scrollTop = scrollTop + newScrollHeight - scrollHeight; + + this.dirty = false; + } + if(!this.animateRequest){ + this.animateRequest = requestAnimationFrame(this.refresh); + } +}; + Scroller.prototype.onScroll = function(){ var height = this.console.offsetHeight; var scrollHeight = this.console.scrollHeight; var scrollTop = this.console.scrollTop; - if(scrollTop < 30 && this.visibleCount < this.lines.length){ - this.visibleCount += this.minVisible; - this.sticky = false; - this.dirty = true; - }else if(scrollTop + height > scrollHeight - 30){ + if(scrollTop < 15 && this.startPosition > 0){ + this.expand(); + }else if(scrollTop + height > scrollHeight - 15){ if(!this.sticky){ + this.jumpToBottom = true; this.sticky = true; this.dirty = true; } - }else{ - this.sicky = false; } if(this.dirty){ - requestAnimationFrame(this.refresh); + this.animateRequest = requestAnimationFrame(this.refresh); } }; From c3ce123e68bf47c6bca66cfe779de2db2a4fd0d3 Mon Sep 17 00:00:00 2001 From: Matthew Shepard Date: Mon, 20 Jul 2015 14:40:59 -0700 Subject: [PATCH 06/14] Handle reset when console buffer is cleared --- plugins/editor/scroller.js | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/plugins/editor/scroller.js b/plugins/editor/scroller.js index c0ee383..4ef9e5f 100644 --- a/plugins/editor/scroller.js +++ b/plugins/editor/scroller.js @@ -45,25 +45,26 @@ var Scroller = function() { }; Scroller.prototype.setLines = function(newLines) { + // console.log(newLines); var len = newLines.length; + this.lines = newLines; if(this.sticky){ this.startPosition = Math.max(0, len - this.minVisible); + }else if(newLines.length === 1 && newLines[0].length === 0){ + // ^^ `lines` is reset to an array with one empty line. ugh. + + // handle the reset case when lines is replaced with an empty array + // we don't have a direct event that can call this + this.reset(); } - this.lines = newLines; this.dirty = true; }; -Scroller.prototype.reset = function(clearLines){ - this.visibleCount = this.minVisible; +Scroller.prototype.reset = function(){ + this.startPosition = Math.max(0, this.lines.length - this.minVisible); + this.jumpToBottom = true; this.sticky = true; this.dirty = true; - if(clearLines){ - this.lines = []; - this.startPosition = 0; - } - if(this.console){ - this.animateRequest = requestAnimationFrame(this.refresh); - } }; Scroller.prototype.requestRefresh = function(){ @@ -110,14 +111,12 @@ Scroller.prototype.onScroll = function(){ var height = this.console.offsetHeight; var scrollHeight = this.console.scrollHeight; var scrollTop = this.console.scrollTop; - if(scrollTop < 15 && this.startPosition > 0){ + if(!this.jumpToBottom && scrollTop < 15 && this.startPosition > 0){ this.expand(); - }else if(scrollTop + height > scrollHeight - 15){ - if(!this.sticky){ - this.jumpToBottom = true; - this.sticky = true; - this.dirty = true; - } + }else if(!this.sticky && scrollTop + height > scrollHeight - 15){ + this.jumpToBottom = true; + this.sticky = true; + this.dirty = true; } if(this.dirty){ From 6b53a0998dfc5a611520a63f2620f7a893f02327 Mon Sep 17 00:00:00 2001 From: Matthew Shepard Date: Mon, 20 Jul 2015 14:54:50 -0700 Subject: [PATCH 07/14] Misc cleanup --- plugins/editor/scroller.js | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/plugins/editor/scroller.js b/plugins/editor/scroller.js index 4ef9e5f..dc7441c 100644 --- a/plugins/editor/scroller.js +++ b/plugins/editor/scroller.js @@ -36,8 +36,10 @@ var Scroller = function() { this.jumpToBottom = true; this.dirty = false; this.console = null; - this.refresh = this.renderVisible.bind(this); - this.scroll = this.onScroll.bind(this); + + //pre-bind functions and throttle expansion + this.refresh = this._renderVisible.bind(this); + this.scroll = this._onScroll.bind(this); this.expand = _.throttle(this._expand.bind(this), 100, { leading: true, trailing: false @@ -45,7 +47,6 @@ var Scroller = function() { }; Scroller.prototype.setLines = function(newLines) { - // console.log(newLines); var len = newLines.length; this.lines = newLines; if(this.sticky){ @@ -73,7 +74,7 @@ Scroller.prototype.requestRefresh = function(){ } }; -Scroller.prototype.renderVisible = function(){ +Scroller.prototype._renderVisible = function(){ this.animateRequest = null; if(this.dirty && this.console){ if(this.sticky){ @@ -102,12 +103,9 @@ Scroller.prototype._expand = function(){ this.dirty = false; } - if(!this.animateRequest){ - this.animateRequest = requestAnimationFrame(this.refresh); - } }; -Scroller.prototype.onScroll = function(){ +Scroller.prototype._onScroll = function(){ var height = this.console.offsetHeight; var scrollHeight = this.console.scrollHeight; var scrollTop = this.console.scrollTop; From 695912d214751b8bb1afa7419188d7641633ddaf Mon Sep 17 00:00:00 2001 From: Matthew Shepard Date: Mon, 20 Jul 2015 15:34:41 -0700 Subject: [PATCH 08/14] Smooth transition from sticky/backscroll and prevent scroll hitting top before exhausting console --- plugins/editor/scroller.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/plugins/editor/scroller.js b/plugins/editor/scroller.js index dc7441c..cd9bb5f 100644 --- a/plugins/editor/scroller.js +++ b/plugins/editor/scroller.js @@ -75,6 +75,7 @@ Scroller.prototype.requestRefresh = function(){ }; Scroller.prototype._renderVisible = function(){ + var top = this.console.scrollTop; this.animateRequest = null; if(this.dirty && this.console){ if(this.sticky){ @@ -84,6 +85,9 @@ Scroller.prototype._renderVisible = function(){ if(this.jumpToBottom){ this.console.scrollTop = 350000; this.jumpToBottom = false; + }else if(!this.sticky && this.startPosition > 0 && top === 0){ + //cover the situation where the window was fully scrolled faster than expand could keep up and locked to the top + this.console.scrollTop = 1; } this.dirty = false; } @@ -111,13 +115,15 @@ Scroller.prototype._onScroll = function(){ var scrollTop = this.console.scrollTop; if(!this.jumpToBottom && scrollTop < 15 && this.startPosition > 0){ this.expand(); - }else if(!this.sticky && scrollTop + height > scrollHeight - 15){ + }else if(!this.sticky && scrollTop + height > scrollHeight - 20){ this.jumpToBottom = true; this.sticky = true; this.dirty = true; + }else if(this.sticky && scrollTop + height < scrollHeight - 40){ + this.sticky = false; } - if(this.dirty){ + if(this.dirty && !this.animateRequest){ this.animateRequest = requestAnimationFrame(this.refresh); } }; From a1c2fd85cbfbcb76858619968a3e3ede77c6a9c8 Mon Sep 17 00:00:00 2001 From: Matthew Shepard Date: Mon, 20 Jul 2015 15:39:22 -0700 Subject: [PATCH 09/14] Fix accidental overlap --- plugins/editor/scroller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/editor/scroller.js b/plugins/editor/scroller.js index cd9bb5f..42d2cd1 100644 --- a/plugins/editor/scroller.js +++ b/plugins/editor/scroller.js @@ -119,7 +119,7 @@ Scroller.prototype._onScroll = function(){ this.jumpToBottom = true; this.sticky = true; this.dirty = true; - }else if(this.sticky && scrollTop + height < scrollHeight - 40){ + }else if(this.sticky && scrollTop + height - 40 < scrollHeight){ this.sticky = false; } From f7c2856fa45769e320b62b2d9faa128fbc9e2f19 Mon Sep 17 00:00:00 2001 From: Matthew Shepard Date: Mon, 20 Jul 2015 15:53:06 -0700 Subject: [PATCH 10/14] Remove gap between sitcky/back states --- plugins/editor/scroller.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/editor/scroller.js b/plugins/editor/scroller.js index 42d2cd1..823a920 100644 --- a/plugins/editor/scroller.js +++ b/plugins/editor/scroller.js @@ -40,9 +40,9 @@ var Scroller = function() { //pre-bind functions and throttle expansion this.refresh = this._renderVisible.bind(this); this.scroll = this._onScroll.bind(this); - this.expand = _.throttle(this._expand.bind(this), 100, { + this.expand = _.throttle(this._expand.bind(this), 150, { leading: true, - trailing: false + trailing: true }); }; @@ -87,7 +87,7 @@ Scroller.prototype._renderVisible = function(){ this.jumpToBottom = false; }else if(!this.sticky && this.startPosition > 0 && top === 0){ //cover the situation where the window was fully scrolled faster than expand could keep up and locked to the top - this.console.scrollTop = 1; + requestAnimationFrame(this.expand); } this.dirty = false; } @@ -115,11 +115,11 @@ Scroller.prototype._onScroll = function(){ var scrollTop = this.console.scrollTop; if(!this.jumpToBottom && scrollTop < 15 && this.startPosition > 0){ this.expand(); - }else if(!this.sticky && scrollTop + height > scrollHeight - 20){ + }else if(!this.sticky && scrollTop + height > scrollHeight - 30){ this.jumpToBottom = true; this.sticky = true; this.dirty = true; - }else if(this.sticky && scrollTop + height - 40 < scrollHeight){ + }else if(this.sticky && scrollTop + height < scrollHeight - 30){ this.sticky = false; } From 8bd8717d724e97feb36d5a2c79cf9d3fc6f162e0 Mon Sep 17 00:00:00 2001 From: Matthew Shepard Date: Mon, 20 Jul 2015 16:27:45 -0700 Subject: [PATCH 11/14] Fix edge case where rolling buffer would jump in console. --- plugins/editor/scroller.js | 40 +++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/plugins/editor/scroller.js b/plugins/editor/scroller.js index 823a920..e736d7d 100644 --- a/plugins/editor/scroller.js +++ b/plugins/editor/scroller.js @@ -2,9 +2,9 @@ var _ = require('lodash'); -function generateContent(lines, start, minLength) { +function generateContent(lines, start, end, minLength) { return _(lines) - .slice(start) + .slice(start, end) .thru(function(array){ if(array.length < minLength){ // pad whitespace at top of array @@ -51,12 +51,15 @@ Scroller.prototype.setLines = function(newLines) { this.lines = newLines; if(this.sticky){ this.startPosition = Math.max(0, len - this.minVisible); - }else if(newLines.length === 1 && newLines[0].length === 0){ + }else if(len === 1 && newLines[0].length === 0){ // ^^ `lines` is reset to an array with one empty line. ugh. // handle the reset case when lines is replaced with an empty array // we don't have a direct event that can call this this.reset(); + }else if(len < this.startPosition){ + // handle buffer rollover, where number of lines will go from 2048 to ~1900 + this.startPosition = Math.max(0, len - this.minVisible); } this.dirty = true; }; @@ -81,9 +84,10 @@ Scroller.prototype._renderVisible = function(){ if(this.sticky){ this.startPosition = Math.max(0, this.lines.length - this.minVisible); } - this.console.innerHTML = generateContent(this.lines, this.startPosition, this.minVisible); + console.log('_renderVisible', this.startPosition, this.sticky, top); + this.console.innerHTML = generateContent(this.lines, this.startPosition, this.lines.length, this.minVisible); if(this.jumpToBottom){ - this.console.scrollTop = 350000; + this.console.scrollTop = 2000; this.jumpToBottom = false; }else if(!this.sticky && this.startPosition > 0 && top === 0){ //cover the situation where the window was fully scrolled faster than expand could keep up and locked to the top @@ -101,7 +105,7 @@ Scroller.prototype._expand = function(){ var scrollTop = this.console.scrollTop; // do an inline scroll to avoid potential scroll interleaving - this.console.innerHTML = generateContent(this.lines, this.startPosition, this.minVisible); + this.console.innerHTML = generateContent(this.lines, this.startPosition, this.lines.length, this.minVisible); var newScrollHeight = this.console.scrollHeight; this.console.scrollTop = scrollTop + newScrollHeight - scrollHeight; @@ -110,17 +114,25 @@ Scroller.prototype._expand = function(){ }; Scroller.prototype._onScroll = function(){ + if(this.jumpToBottom){ + // do nothing, prepare to jump + return; + } var height = this.console.offsetHeight; var scrollHeight = this.console.scrollHeight; var scrollTop = this.console.scrollTop; - if(!this.jumpToBottom && scrollTop < 15 && this.startPosition > 0){ - this.expand(); - }else if(!this.sticky && scrollTop + height > scrollHeight - 30){ - this.jumpToBottom = true; - this.sticky = true; - this.dirty = true; - }else if(this.sticky && scrollTop + height < scrollHeight - 30){ - this.sticky = false; + if(this.sticky){ + if(scrollTop + height < scrollHeight - 30){ + this.sticky = false; + } + }else{ + if(scrollTop < 15 && this.startPosition > 0){ + this.expand(); + }else if(scrollTop + height > scrollHeight - 30){ + this.jumpToBottom = true; + this.sticky = true; + this.dirty = true; + } } if(this.dirty && !this.animateRequest){ From 1bf6ff80ea6854886c31d4465977f206d4b0e680 Mon Sep 17 00:00:00 2001 From: Matthew Shepard Date: Mon, 20 Jul 2015 16:29:21 -0700 Subject: [PATCH 12/14] Remove log --- plugins/editor/scroller.js | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/editor/scroller.js b/plugins/editor/scroller.js index e736d7d..8829ec7 100644 --- a/plugins/editor/scroller.js +++ b/plugins/editor/scroller.js @@ -84,7 +84,6 @@ Scroller.prototype._renderVisible = function(){ if(this.sticky){ this.startPosition = Math.max(0, this.lines.length - this.minVisible); } - console.log('_renderVisible', this.startPosition, this.sticky, top); this.console.innerHTML = generateContent(this.lines, this.startPosition, this.lines.length, this.minVisible); if(this.jumpToBottom){ this.console.scrollTop = 2000; From ef22600ad0f3c21a819b5d68939ae05067a4f0e1 Mon Sep 17 00:00:00 2001 From: Matthew Shepard Date: Tue, 21 Jul 2015 11:22:30 -0700 Subject: [PATCH 13/14] Fix edge-case error in renderVisible when render is called before console is registered. --- plugins/editor/scroller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/editor/scroller.js b/plugins/editor/scroller.js index 8829ec7..67ba667 100644 --- a/plugins/editor/scroller.js +++ b/plugins/editor/scroller.js @@ -78,9 +78,9 @@ Scroller.prototype.requestRefresh = function(){ }; Scroller.prototype._renderVisible = function(){ - var top = this.console.scrollTop; this.animateRequest = null; if(this.dirty && this.console){ + var top = this.console.scrollTop; if(this.sticky){ this.startPosition = Math.max(0, this.lines.length - this.minVisible); } From 67716fc7bb26b65c53b03ea436b543362ba38591 Mon Sep 17 00:00:00 2001 From: Matthew Shepard Date: Tue, 21 Jul 2015 11:31:31 -0700 Subject: [PATCH 14/14] Fix scroller fn name --- plugins/editor/scroller.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/editor/scroller.js b/plugins/editor/scroller.js index 67ba667..a7f7ac4 100644 --- a/plugins/editor/scroller.js +++ b/plugins/editor/scroller.js @@ -27,7 +27,7 @@ function generateContent(lines, start, end, minLength) { .join('\n'); } -var Scroller = function() { +function Scroller() { this.lines = []; this.minVisible = 30; this.startPosition = 0; @@ -44,7 +44,7 @@ var Scroller = function() { leading: true, trailing: true }); -}; +} Scroller.prototype.setLines = function(newLines) { var len = newLines.length;