diff --git a/spec/editor-component-spec.coffee b/spec/editor-component-spec.coffee index a477e6cdf..153b0df7e 100644 --- a/spec/editor-component-spec.coffee +++ b/spec/editor-component-spec.coffee @@ -84,7 +84,6 @@ describe "EditorComponent", -> verticalScrollbarNode.scrollTop = 4.5 * lineHeightInPixels verticalScrollbarNode.dispatchEvent(new UIEvent('scroll')) - runSetImmediateCallbacks() expect(linesNode.style['-webkit-transform']).toBe "translate3d(0px, #{-4.5 * lineHeightInPixels}px, 0px)" expect(node.querySelectorAll('.line').length).toBe 6 + 4 # margin above and below @@ -353,7 +352,6 @@ describe "EditorComponent", -> verticalScrollbarNode.scrollTop = 2.5 * lineHeightInPixels verticalScrollbarNode.dispatchEvent(new UIEvent('scroll')) - runSetImmediateCallbacks() expect(node.querySelectorAll('.line-number').length).toBe 6 + 4 + 1 # line overdraw margin above/below + dummy line number @@ -544,7 +542,6 @@ describe "EditorComponent", -> verticalScrollbarNode.dispatchEvent(new UIEvent('scroll')) horizontalScrollbarNode.scrollLeft = 3.5 * charWidth horizontalScrollbarNode.dispatchEvent(new UIEvent('scroll')) - runSetImmediateCallbacks() cursorNodes = node.querySelectorAll('.cursor') expect(cursorNodes.length).toBe 2 @@ -751,11 +748,11 @@ describe "EditorComponent", -> # Add decorations that are out of range marker2 = editor.displayBuffer.markBufferRange([[9, 0], [9, 0]]) editor.addDecorationForMarker(marker2, type: ['gutter', 'line'], class: 'b') + runSetImmediateCallbacks() # Scroll decorations into view verticalScrollbarNode.scrollTop = 2.5 * lineHeightInPixels verticalScrollbarNode.dispatchEvent(new UIEvent('scroll')) - runSetImmediateCallbacks() expect(lineAndLineNumberHaveClass(9, 'b')).toBe true # Fold a line to move the decorations @@ -901,7 +898,6 @@ describe "EditorComponent", -> verticalScrollbarNode.scrollTop = 3.5 * lineHeightInPixels verticalScrollbarNode.dispatchEvent(new UIEvent('scroll')) - runSetImmediateCallbacks() regions = node.querySelectorAll('.some-highlight .region') @@ -1421,36 +1417,30 @@ describe "EditorComponent", -> expect(horizontalScrollbarNode.scrollLeft).toBe 0 node.dispatchEvent(new WheelEvent('mousewheel', wheelDeltaX: -5, wheelDeltaY: -10)) - runSetImmediateCallbacks() expect(verticalScrollbarNode.scrollTop).toBe 10 expect(horizontalScrollbarNode.scrollLeft).toBe 0 node.dispatchEvent(new WheelEvent('mousewheel', wheelDeltaX: -15, wheelDeltaY: -5)) - runSetImmediateCallbacks() expect(verticalScrollbarNode.scrollTop).toBe 10 expect(horizontalScrollbarNode.scrollLeft).toBe 15 it "updates the scrollLeft or scrollTop according to the scroll sensitivity", -> atom.config.set('editor.scrollSensitivity', 50) node.dispatchEvent(new WheelEvent('mousewheel', wheelDeltaX: -5, wheelDeltaY: -10)) - runSetImmediateCallbacks() expect(horizontalScrollbarNode.scrollLeft).toBe 0 node.dispatchEvent(new WheelEvent('mousewheel', wheelDeltaX: -15, wheelDeltaY: -5)) - runSetImmediateCallbacks() expect(verticalScrollbarNode.scrollTop).toBe 5 expect(horizontalScrollbarNode.scrollLeft).toBe 7 it "uses the previous scrollSensitivity when the value is not an int", -> atom.config.set('editor.scrollSensitivity', 'nope') node.dispatchEvent(new WheelEvent('mousewheel', wheelDeltaX: 0, wheelDeltaY: -10)) - runSetImmediateCallbacks() expect(verticalScrollbarNode.scrollTop).toBe 10 it "parses negative scrollSensitivity values as positive", -> atom.config.set('editor.scrollSensitivity', -50) node.dispatchEvent(new WheelEvent('mousewheel', wheelDeltaX: 0, wheelDeltaY: -10)) - runSetImmediateCallbacks() expect(verticalScrollbarNode.scrollTop).toBe 5 describe "when the mousewheel event's target is a line", -> diff --git a/src/editor-component.coffee b/src/editor-component.coffee index d7e9e643a..fccb56775 100644 --- a/src/editor-component.coffee +++ b/src/editor-component.coffee @@ -26,6 +26,8 @@ EditorComponent = React.createClass pendingScrollLeft: null selectOnMouseMove: false updateRequested: false + updatesPaused: false + updateRequestedWhilePaused: false cursorsMoved: false selectionChanged: false selectionAdded: false @@ -44,6 +46,7 @@ EditorComponent = React.createClass inputEnabled: true scrollViewMeasurementInterval: 100 scopedCharacterWidthsChangeCount: null + scrollViewMeasurementPaused: false render: -> {focused, fontSize, lineHeight, fontFamily, showIndentGuide, showInvisibles, showLineNumbers, visible} = @state @@ -163,7 +166,7 @@ EditorComponent = React.createClass componentDidMount: -> {editor} = @props - @scrollViewMeasurementIntervalId = setInterval(@requestScrollViewMeasurement, @scrollViewMeasurementInterval) + @scrollViewMeasurementIntervalId = setInterval(@measureScrollView, @scrollViewMeasurementInterval) @observeEditor() @listenForDOMEvents() @@ -183,8 +186,6 @@ EditorComponent = React.createClass clearInterval(@scrollViewMeasurementIntervalId) @scrollViewMeasurementIntervalId = null - componentWillUpdate: -> - componentDidUpdate: (prevProps, prevState) -> cursorsMoved = @cursorsMoved selectionChanged = @selectionChanged @@ -204,6 +205,10 @@ EditorComponent = React.createClass @remeasureCharacterWidthsIfNeeded(prevState) requestUpdate: -> + if @updatesPaused + @updateRequestedWhilePaused = true + return + if @performSyncUpdates ? EditorComponent.performSyncUpdates @forceUpdate() else unless @updateRequested @@ -212,6 +217,16 @@ EditorComponent = React.createClass @updateRequested = false @forceUpdate() if @isMounted() + requestAnimationFrame: (fn) -> + @updatesPaused = true + @pauseScrollViewMeasurement() + requestAnimationFrame => + fn() + @updatesPaused = false + if @updateRequestedWhilePaused and @isMounted() + @updateRequestedWhilePaused = false + @forceUpdate() + getRenderedRowRange: -> {editor, lineOverdrawMargin} = @props [visibleStartRow, visibleEndRow] = editor.getVisibleRowRange() @@ -515,12 +530,12 @@ EditorComponent = React.createClass onVerticalScroll: (scrollTop) -> {editor} = @props - return if scrollTop is editor.getScrollTop() + return if @updateRequested or scrollTop is editor.getScrollTop() animationFramePending = @pendingScrollTop? @pendingScrollTop = scrollTop unless animationFramePending - requestAnimationFrame => + @requestAnimationFrame => pendingScrollTop = @pendingScrollTop @pendingScrollTop = null @props.editor.setScrollTop(pendingScrollTop) @@ -528,12 +543,12 @@ EditorComponent = React.createClass onHorizontalScroll: (scrollLeft) -> {editor} = @props - return if scrollLeft is editor.getScrollLeft() + return if @updateRequested or scrollLeft is editor.getScrollLeft() animationFramePending = @pendingScrollLeft? @pendingScrollLeft = scrollLeft unless animationFramePending - requestAnimationFrame => + @requestAnimationFrame => @props.editor.setScrollLeft(@pendingScrollLeft) @pendingScrollLeft = null @@ -554,7 +569,7 @@ EditorComponent = React.createClass @clearMouseWheelScreenRowAfterDelay() unless animationFramePending - requestAnimationFrame => + @requestAnimationFrame => {editor} = @props editor.setScrollTop(editor.getScrollTop() + @pendingVerticalScrollDelta) editor.setScrollLeft(editor.getScrollLeft() + @pendingHorizontalScrollDelta) @@ -655,7 +670,7 @@ EditorComponent = React.createClass onScrollTopChanged: -> @scrollingVertically = true @requestUpdate() - @onStoppedScrollingAfterDelay ?= debounce(@onStoppedScrolling, 100) + @onStoppedScrollingAfterDelay ?= debounce(@onStoppedScrolling, 200) @onStoppedScrollingAfterDelay() onStoppedScrolling: -> @@ -682,7 +697,7 @@ EditorComponent = React.createClass dragging = false lastMousePosition = {} animationLoop = => - requestAnimationFrame => + @requestAnimationFrame => if dragging screenPosition = @screenPositionForMouseEvent(lastMousePosition) dragHandler(screenPosition) @@ -709,8 +724,18 @@ EditorComponent = React.createClass window.addEventListener('mousemove', onMouseMove) window.addEventListener('mouseup', onMouseUp) + pauseScrollViewMeasurement: -> + @scrollViewMeasurementPaused = true + @resumeScrollViewMeasurementAfterDelay ?= debounce(@resumeScrollViewMeasurement, 100) + @resumeScrollViewMeasurementAfterDelay() + + resumeScrollViewMeasurement: -> + @scrollViewMeasurementPaused = false + + resumeScrollViewMeasurementAfterDelay: null # created lazily + requestScrollViewMeasurement: -> - return if @measurementPending + return if @scrollViewMeasurementRequested @scrollViewMeasurementRequested = true requestAnimationFrame => @@ -722,6 +747,7 @@ EditorComponent = React.createClass # and use the scrollHeight / scrollWidth as its height and width in # calculations. measureScrollView: -> + return if @scrollViewMeasurementPaused return unless @isMounted() {editor} = @props