Make each section of presenter state self-contained

This means we have some duplicated values in different parts of the
tree, but it’s cleaner in the view since each component only consumes
a single object. Seems like the presenter should convey the correct
data to the correct locations and minimize the logic in the view. A
few duplicated integers is a reasonable trade-off.
This commit is contained in:
Nathan Sobo
2015-01-29 14:27:53 -07:00
parent da4b3a47ef
commit bbc1a264b5
7 changed files with 238 additions and 110 deletions

View File

@@ -33,50 +33,6 @@ describe "TextEditorPresenter", ->
# These `describe` and `it` blocks mirror the structure of the ::state object.
# Please maintain this structure when adding specs for new state fields.
describe "::state", ->
describe ".scrollHeight", ->
it "is initialized based on the lineHeight, the number of lines, and the height", ->
presenter = new TextEditorPresenter(model: editor, scrollTop: 0, lineHeight: 10)
expect(presenter.state.scrollHeight).toBe editor.getScreenLineCount() * 10
presenter = new TextEditorPresenter(model: editor, scrollTop: 0, lineHeight: 10, height: 500)
expect(presenter.state.scrollHeight).toBe 500
it "updates when the ::lineHeight changes", ->
presenter = new TextEditorPresenter(model: editor, scrollTop: 0, lineHeight: 10)
expectStateUpdate presenter, -> presenter.setLineHeight(20)
expect(presenter.state.scrollHeight).toBe editor.getScreenLineCount() * 20
it "updates when the line count changes", ->
presenter = new TextEditorPresenter(model: editor, scrollTop: 0, lineHeight: 10)
expectStateUpdate presenter, -> editor.getBuffer().append("\n\n\n")
expect(presenter.state.scrollHeight).toBe editor.getScreenLineCount() * 10
it "updates when ::height changes", ->
presenter = new TextEditorPresenter(model: editor, scrollTop: 0, lineHeight: 10)
expectStateUpdate presenter, -> presenter.setHeight(500)
expect(presenter.state.scrollHeight).toBe 500
describe ".scrollTop", ->
it "tracks the value of ::scrollTop", ->
presenter = new TextEditorPresenter(model: editor, scrollTop: 10, lineHeight: 10)
expect(presenter.state.scrollTop).toBe 10
expectStateUpdate presenter, -> presenter.setScrollTop(50)
expect(presenter.state.scrollTop).toBe 50
describe ".scrollingVertically", ->
it "is true for ::stoppedScrollingDelay milliseconds following a changes to ::scrollTop", ->
presenter = new TextEditorPresenter(model: editor, scrollTop: 10, stoppedScrollingDelay: 200)
expect(presenter.state.scrollingVertically).toBe false
expectStateUpdate presenter, -> presenter.setScrollTop(0)
expect(presenter.state.scrollingVertically).toBe true
advanceClock(100)
expect(presenter.state.scrollingVertically).toBe true
presenter.setScrollTop(10)
advanceClock(100)
expect(presenter.state.scrollingVertically).toBe true
expectStateUpdate presenter, -> advanceClock(100)
expect(presenter.state.scrollingVertically).toBe false
describe ".horizontalScrollbar", ->
describe ".visible", ->
it "is true if the scrollWidth exceeds the computed client width", ->
@@ -127,6 +83,58 @@ describe "TextEditorPresenter", ->
presenter.setHeight((editor.getLineCount() * 10) - 1)
expect(state.horizontalScrollbar.right).toBe 10
describe ".scrollWidth", ->
it "is initialized as the max of the ::contentFrameWidth and the width of the longest line", ->
maxLineLength = editor.getMaxScreenLineLength()
presenter = new TextEditorPresenter(model: editor, contentFrameWidth: 50, baseCharacterWidth: 10)
expect(presenter.state.horizontalScrollbar.scrollWidth).toBe 10 * maxLineLength + 1
presenter = new TextEditorPresenter(model: editor, contentFrameWidth: 10 * maxLineLength + 20, baseCharacterWidth: 10)
expect(presenter.state.horizontalScrollbar.scrollWidth).toBe 10 * maxLineLength + 20
it "updates when the ::contentFrameWidth changes", ->
maxLineLength = editor.getMaxScreenLineLength()
presenter = new TextEditorPresenter(model: editor, contentFrameWidth: 50, baseCharacterWidth: 10)
expect(presenter.state.horizontalScrollbar.scrollWidth).toBe 10 * maxLineLength + 1
expectStateUpdate presenter, -> presenter.setContentFrameWidth(10 * maxLineLength + 20)
expect(presenter.state.horizontalScrollbar.scrollWidth).toBe 10 * maxLineLength + 20
it "updates when the ::baseCharacterWidth changes", ->
maxLineLength = editor.getMaxScreenLineLength()
presenter = new TextEditorPresenter(model: editor, contentFrameWidth: 50, baseCharacterWidth: 10)
expect(presenter.state.horizontalScrollbar.scrollWidth).toBe 10 * maxLineLength + 1
expectStateUpdate presenter, -> presenter.setBaseCharacterWidth(15)
expect(presenter.state.horizontalScrollbar.scrollWidth).toBe 15 * maxLineLength + 1
it "updates when the scoped character widths change", ->
waitsForPromise -> atom.packages.activatePackage('language-javascript')
runs ->
maxLineLength = editor.getMaxScreenLineLength()
presenter = new TextEditorPresenter(model: editor, contentFrameWidth: 50, baseCharacterWidth: 10)
expect(presenter.state.horizontalScrollbar.scrollWidth).toBe 10 * maxLineLength + 1
expectStateUpdate presenter, -> presenter.setScopedCharWidth(['source.js', 'support.function.js'], 'p', 20)
expect(presenter.state.horizontalScrollbar.scrollWidth).toBe (10 * (maxLineLength - 2)) + (20 * 2) + 1 # 2 of the characters are 20px wide now instead of 10px wide
it "updates when ::softWrapped changes on the editor", ->
presenter = new TextEditorPresenter(model: editor, contentFrameWidth: 50, baseCharacterWidth: 10)
expect(presenter.state.horizontalScrollbar.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1
expectStateUpdate presenter, -> editor.setSoftWrapped(true)
expect(presenter.state.horizontalScrollbar.scrollWidth).toBe 10 * editor.getMaxScreenLineLength()
expectStateUpdate presenter, -> editor.setSoftWrapped(false)
expect(presenter.state.horizontalScrollbar.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1
describe ".scrollLeft", ->
it "tracks the value of ::scrollLeft", ->
presenter = new TextEditorPresenter(model: editor, scrollLeft: 10, lineHeight: 10, lineOverdrawMargin: 1)
expect(presenter.state.horizontalScrollbar.scrollLeft).toBe 10
expectStateUpdate presenter, -> presenter.setScrollLeft(50)
expect(presenter.state.horizontalScrollbar.scrollLeft).toBe 50
describe ".verticalScrollbar", ->
describe ".visible", ->
it "is true if the scrollHeight exceeds the computed client height", ->
@@ -177,7 +185,74 @@ describe "TextEditorPresenter", ->
presenter.setContentFrameWidth(editor.getMaxScreenLineLength() * 10)
expect(state.verticalScrollbar.bottom).toBe 10
describe ".scrollHeight", ->
it "is initialized based on the lineHeight, the number of lines, and the height", ->
presenter = new TextEditorPresenter(model: editor, scrollTop: 0, lineHeight: 10)
expect(presenter.state.verticalScrollbar.scrollHeight).toBe editor.getScreenLineCount() * 10
presenter = new TextEditorPresenter(model: editor, scrollTop: 0, lineHeight: 10, height: 500)
expect(presenter.state.verticalScrollbar.scrollHeight).toBe 500
it "updates when the ::lineHeight changes", ->
presenter = new TextEditorPresenter(model: editor, scrollTop: 0, lineHeight: 10)
expectStateUpdate presenter, -> presenter.setLineHeight(20)
expect(presenter.state.verticalScrollbar.scrollHeight).toBe editor.getScreenLineCount() * 20
it "updates when the line count changes", ->
presenter = new TextEditorPresenter(model: editor, scrollTop: 0, lineHeight: 10)
expectStateUpdate presenter, -> editor.getBuffer().append("\n\n\n")
expect(presenter.state.verticalScrollbar.scrollHeight).toBe editor.getScreenLineCount() * 10
it "updates when ::height changes", ->
presenter = new TextEditorPresenter(model: editor, scrollTop: 0, lineHeight: 10)
expectStateUpdate presenter, -> presenter.setHeight(500)
expect(presenter.state.verticalScrollbar.scrollHeight).toBe 500
describe ".scrollTop", ->
it "tracks the value of ::scrollTop", ->
presenter = new TextEditorPresenter(model: editor, scrollTop: 10, lineHeight: 10)
expect(presenter.state.verticalScrollbar.scrollTop).toBe 10
expectStateUpdate presenter, -> presenter.setScrollTop(50)
expect(presenter.state.verticalScrollbar.scrollTop).toBe 50
describe ".content", ->
describe ".scrollingVertically", ->
it "is true for ::stoppedScrollingDelay milliseconds following a changes to ::scrollTop", ->
presenter = new TextEditorPresenter(model: editor, scrollTop: 10, stoppedScrollingDelay: 200)
expect(presenter.state.content.scrollingVertically).toBe false
expectStateUpdate presenter, -> presenter.setScrollTop(0)
expect(presenter.state.content.scrollingVertically).toBe true
advanceClock(100)
expect(presenter.state.content.scrollingVertically).toBe true
presenter.setScrollTop(10)
advanceClock(100)
expect(presenter.state.content.scrollingVertically).toBe true
expectStateUpdate presenter, -> advanceClock(100)
expect(presenter.state.content.scrollingVertically).toBe false
describe ".scrollHeight", ->
it "is initialized based on the lineHeight, the number of lines, and the height", ->
presenter = new TextEditorPresenter(model: editor, scrollTop: 0, lineHeight: 10)
expect(presenter.state.content.scrollHeight).toBe editor.getScreenLineCount() * 10
presenter = new TextEditorPresenter(model: editor, scrollTop: 0, lineHeight: 10, height: 500)
expect(presenter.state.content.scrollHeight).toBe 500
it "updates when the ::lineHeight changes", ->
presenter = new TextEditorPresenter(model: editor, scrollTop: 0, lineHeight: 10)
expectStateUpdate presenter, -> presenter.setLineHeight(20)
expect(presenter.state.content.scrollHeight).toBe editor.getScreenLineCount() * 20
it "updates when the line count changes", ->
presenter = new TextEditorPresenter(model: editor, scrollTop: 0, lineHeight: 10)
expectStateUpdate presenter, -> editor.getBuffer().append("\n\n\n")
expect(presenter.state.content.scrollHeight).toBe editor.getScreenLineCount() * 10
it "updates when ::height changes", ->
presenter = new TextEditorPresenter(model: editor, scrollTop: 0, lineHeight: 10)
expectStateUpdate presenter, -> presenter.setHeight(500)
expect(presenter.state.content.scrollHeight).toBe 500
describe ".scrollWidth", ->
it "is initialized as the max of the ::contentFrameWidth and the width of the longest line", ->
maxLineLength = editor.getMaxScreenLineLength()
@@ -223,6 +298,13 @@ describe "TextEditorPresenter", ->
expectStateUpdate presenter, -> editor.setSoftWrapped(false)
expect(presenter.state.content.scrollWidth).toBe 10 * editor.getMaxScreenLineLength() + 1
describe ".scrollTop", ->
it "tracks the value of ::scrollTop", ->
presenter = new TextEditorPresenter(model: editor, scrollTop: 10, lineHeight: 10)
expect(presenter.state.content.scrollTop).toBe 10
expectStateUpdate presenter, -> presenter.setScrollTop(50)
expect(presenter.state.content.scrollTop).toBe 50
describe ".scrollLeft", ->
it "tracks the value of ::scrollLeft", ->
presenter = new TextEditorPresenter(model: editor, scrollLeft: 10, lineHeight: 10, lineOverdrawMargin: 1)
@@ -1236,6 +1318,36 @@ describe "TextEditorPresenter", ->
expect(presenter.state.content.overlays).not.toEqual({})
describe ".gutter", ->
describe ".scrollHeight", ->
it "is initialized based on the lineHeight, the number of lines, and the height", ->
presenter = new TextEditorPresenter(model: editor, scrollTop: 0, lineHeight: 10)
expect(presenter.state.gutter.scrollHeight).toBe editor.getScreenLineCount() * 10
presenter = new TextEditorPresenter(model: editor, scrollTop: 0, lineHeight: 10, height: 500)
expect(presenter.state.gutter.scrollHeight).toBe 500
it "updates when the ::lineHeight changes", ->
presenter = new TextEditorPresenter(model: editor, scrollTop: 0, lineHeight: 10)
expectStateUpdate presenter, -> presenter.setLineHeight(20)
expect(presenter.state.gutter.scrollHeight).toBe editor.getScreenLineCount() * 20
it "updates when the line count changes", ->
presenter = new TextEditorPresenter(model: editor, scrollTop: 0, lineHeight: 10)
expectStateUpdate presenter, -> editor.getBuffer().append("\n\n\n")
expect(presenter.state.gutter.scrollHeight).toBe editor.getScreenLineCount() * 10
it "updates when ::height changes", ->
presenter = new TextEditorPresenter(model: editor, scrollTop: 0, lineHeight: 10)
expectStateUpdate presenter, -> presenter.setHeight(500)
expect(presenter.state.gutter.scrollHeight).toBe 500
describe ".scrollTop", ->
it "tracks the value of ::scrollTop", ->
presenter = new TextEditorPresenter(model: editor, scrollTop: 10, lineHeight: 10)
expect(presenter.state.gutter.scrollTop).toBe 10
expectStateUpdate presenter, -> presenter.setScrollTop(50)
expect(presenter.state.gutter.scrollTop).toBe 50
describe ".backgroundColor", ->
it "is assigned to ::gutterBackgroundColor if present, and to ::backgroundColor otherwise", ->
presenter = new TextEditorPresenter(model: editor, backgroundColor: "rgba(255, 0, 0, 0)", gutterBackgroundColor: "rgba(0, 255, 0, 0)")

View File

@@ -19,16 +19,20 @@ GutterComponent = React.createClass
render: ->
{presenter} = @props
@newState = presenter.state.gutter
@oldState ?= {lineNumbers: {}}
{scrollHeight, backgroundColor} = @newState
div className: 'gutter',
div className: 'line-numbers', ref: 'lineNumbers', style:
height: presenter.state.scrollHeight
height: scrollHeight
WebkitTransform: @getTransform() if presenter.hasRequiredMeasurements()
backgroundColor: presenter.state.gutter.backgroundColor
backgroundColor: backgroundColor
getTransform: ->
{presenter, useHardwareAcceleration} = @props
{scrollTop} = presenter.state
{useHardwareAcceleration} = @props
{scrollTop} = @newState
if useHardwareAcceleration
"translate3d(0px, #{-scrollTop}px, 0px)"
@@ -39,7 +43,7 @@ GutterComponent = React.createClass
@lineNumberNodesById = {}
componentDidMount: ->
{@maxLineNumberDigits} = @props.presenter.state.gutter
{@maxLineNumberDigits} = @newState
@appendDummyLineNumber()
@updateLineNumbers()
@@ -48,7 +52,7 @@ GutterComponent = React.createClass
node.addEventListener 'mousedown', @onMouseDown
componentDidUpdate: (oldProps) ->
{maxLineNumberDigits} = @props.presenter.state.gutter
{maxLineNumberDigits} = @newState
unless maxLineNumberDigits is @maxLineNumberDigits
@maxLineNumberDigits = maxLineNumberDigits
@updateDummyLineNumber()
@@ -69,13 +73,10 @@ GutterComponent = React.createClass
@dummyLineNumberNode.innerHTML = @buildLineNumberInnerHTML(0, false)
updateLineNumbers: ->
{presenter} = @props
@oldState ?= {lineNumbers: {}}
newState = presenter.state.gutter
newLineNumberIds = null
newLineNumbersHTML = null
for id, lineNumberState of newState.lineNumbers
for id, lineNumberState of @newState.lineNumbers
if @oldState.lineNumbers.hasOwnProperty(id)
@updateLineNumberNode(id, lineNumberState)
else
@@ -96,7 +97,7 @@ GutterComponent = React.createClass
node.appendChild(lineNumberNode)
for id, lineNumberState of @oldState.lineNumbers
unless newState.lineNumbers.hasOwnProperty(id)
unless @newState.lineNumbers.hasOwnProperty(id)
@lineNumberNodesById[id].remove()
delete @lineNumberNodesById[id]
delete @oldState.lineNumbers[id]
@@ -113,7 +114,7 @@ GutterComponent = React.createClass
"<div class=\"#{className}\" style=\"#{style}\" data-buffer-row=\"#{bufferRow}\" data-screen-row=\"#{screenRow}\">#{innerHTML}</div>"
buildLineNumberInnerHTML: (bufferRow, softWrapped) ->
{maxLineNumberDigits} = @props.presenter.state.gutter
{maxLineNumberDigits} = @newState
if softWrapped
lineNumber = ""

View File

@@ -18,11 +18,10 @@ LinesComponent = React.createClass
render: ->
{editor, presenter} = @props
@oldState ?= {content: {lines: {}}}
@newState = presenter.state
@oldState ?= {lines: {}}
@newState = presenter.state.content
{scrollHeight} = @newState
{scrollWidth, backgroundColor, placeholderText} = @newState.content
{scrollHeight, scrollWidth, backgroundColor, placeholderText} = @newState
style =
height: scrollHeight
@@ -36,8 +35,7 @@ LinesComponent = React.createClass
HighlightsComponent {presenter}
getTransform: ->
{scrollTop} = @newState
{scrollLeft} = @newState.content
{scrollTop, scrollLeft} = @newState
{useHardwareAcceleration} = @props
if useHardwareAcceleration
@@ -68,41 +66,41 @@ LinesComponent = React.createClass
componentDidUpdate: ->
{visible, presenter} = @props
@removeLineNodes() unless @oldState?.content.indentGuidesVisible is @newState?.content.indentGuidesVisible
@removeLineNodes() unless @oldState?.indentGuidesVisible is @newState?.indentGuidesVisible
@updateLineNodes()
@measureCharactersInNewLines() if visible and not presenter.state.scrollingVertically
@overlayManager?.render(@props)
@oldState.content.indentGuidesVisible = @newState.content.indentGuidesVisible
@oldState.content.scrollWidth = @newState.content.scrollWidth
@oldState.indentGuidesVisible = @newState.indentGuidesVisible
@oldState.scrollWidth = @newState.scrollWidth
clearScreenRowCaches: ->
@screenRowsByLineId = {}
@lineIdsByScreenRow = {}
removeLineNodes: ->
@removeLineNode(id) for id of @oldState.content.lines
@removeLineNode(id) for id of @oldState.lines
removeLineNode: (id) ->
@lineNodesByLineId[id].remove()
delete @lineNodesByLineId[id]
delete @lineIdsByScreenRow[@screenRowsByLineId[id]]
delete @screenRowsByLineId[id]
delete @oldState.content.lines[id]
delete @oldState.lines[id]
updateLineNodes: ->
{presenter} = @props
for id of @oldState.content.lines
unless @newState.content.lines.hasOwnProperty(id)
for id of @oldState.lines
unless @newState.lines.hasOwnProperty(id)
@removeLineNode(id)
newLineIds = null
newLinesHTML = null
for id, lineState of @newState.content.lines
if @oldState.content.lines.hasOwnProperty(id)
for id, lineState of @newState.lines
if @oldState.lines.hasOwnProperty(id)
@updateLineNode(id)
else
newLineIds ?= []
@@ -111,7 +109,7 @@ LinesComponent = React.createClass
newLinesHTML += @buildLineHTML(id)
@screenRowsByLineId[id] = lineState.screenRow
@lineIdsByScreenRow[lineState.screenRow] = id
@oldState.content.lines[id] = _.clone(lineState)
@oldState.lines[id] = _.clone(lineState)
return unless newLineIds?
@@ -125,8 +123,8 @@ LinesComponent = React.createClass
buildLineHTML: (id) ->
{presenter} = @props
{scrollWidth} = @newState.content
{screenRow, tokens, text, top, lineEnding, fold, isSoftWrapped, indentLevel, decorationClasses} = @newState.content.lines[id]
{scrollWidth} = @newState
{screenRow, tokens, text, top, lineEnding, fold, isSoftWrapped, indentLevel, decorationClasses} = @newState.lines[id]
classes = ''
if decorationClasses?
@@ -146,8 +144,8 @@ LinesComponent = React.createClass
lineHTML
buildEmptyLineInnerHTML: (id) ->
{indentGuidesVisible} = @newState.content
{indentLevel, tabLength, endOfLineInvisibles} = @newState.content.lines[id]
{indentGuidesVisible} = @newState
{indentLevel, tabLength, endOfLineInvisibles} = @newState.lines[id]
if indentGuidesVisible and indentLevel > 0
invisibleIndex = 0
@@ -170,8 +168,8 @@ LinesComponent = React.createClass
buildLineInnerHTML: (id) ->
{editor} = @props
{indentGuidesVisible} = @newState.content
{tokens, text} = @newState.content.lines[id]
{indentGuidesVisible} = @newState
{tokens, text} = @newState.lines[id]
innerHTML = ""
scopeStack = []
@@ -187,7 +185,7 @@ LinesComponent = React.createClass
innerHTML
buildEndOfLineHTML: (id) ->
{endOfLineInvisibles} = @newState.content.lines[id]
{endOfLineInvisibles} = @newState.lines[id]
html = ''
if endOfLineInvisibles?
@@ -221,13 +219,13 @@ LinesComponent = React.createClass
"<span class=\"#{scope.replace(/\.+/g, ' ')}\">"
updateLineNode: (id) ->
{scrollWidth} = @newState.content
{screenRow, top} = @newState.content.lines[id]
{scrollWidth} = @newState
{screenRow, top} = @newState.lines[id]
lineNode = @lineNodesByLineId[id]
newDecorationClasses = @newState.content.lines[id].decorationClasses
oldDecorationClasses = @oldState.content.lines[id].decorationClasses
newDecorationClasses = @newState.lines[id].decorationClasses
oldDecorationClasses = @oldState.lines[id].decorationClasses
if oldDecorationClasses?
for decorationClass in oldDecorationClasses
@@ -272,7 +270,7 @@ LinesComponent = React.createClass
node = @getDOMNode()
editor.batchCharacterMeasurement =>
for id, lineState of @oldState.content.lines
for id, lineState of @oldState.lines
unless @measuredLines.has(id)
lineNode = @lineNodesByLineId[id]
@measureCharactersInLine(lineState, lineNode)

View File

@@ -27,8 +27,7 @@ class OverlayManager
itemHeight = item.offsetHeight
{scrollTop} = presenter.state
{scrollLeft} = presenter.state.content
{scrollTop, scrollLeft} = presenter.state.content
left = pixelPosition.left
if left + itemWidth - scrollLeft > presenter.getContentFrameWidth() and left - itemWidth >= scrollLeft

View File

@@ -11,29 +11,29 @@ ScrollbarComponent = React.createClass
switch orientation
when 'vertical'
state = presenter.state.verticalScrollbar
@newState = presenter.state.verticalScrollbar
when 'horizontal'
state = presenter.state.horizontalScrollbar
@newState = presenter.state.horizontalScrollbar
style = {}
style.display = 'none' unless state.visible
style.display = 'none' unless @newState.visible
style.transform = 'translateZ(0)' if useHardwareAcceleration # See atom/atom#3559
switch orientation
when 'vertical'
style.width = state.width
style.bottom = state.bottom
style.width = @newState.width
style.bottom = @newState.bottom
when 'horizontal'
style.left = 0
style.right = state.right
style.height = state.height
style.right = @newState.right
style.height = @newState.height
div {className, style},
switch orientation
when 'vertical'
div className: 'scrollbar-content', style: {height: presenter.state.scrollHeight}
div className: 'scrollbar-content', style: {height: @newState.scrollHeight}
when 'horizontal'
div className: 'scrollbar-content', style: {width: presenter.state.content.scrollWidth}
div className: 'scrollbar-content', style: {width: @newState.scrollWidth}
componentDidMount: ->
{orientation} = @props
@@ -47,14 +47,14 @@ ScrollbarComponent = React.createClass
@getDOMNode().removeEventListener 'scroll', @onScroll
componentDidUpdate: ->
{orientation, presenter} = @props
{orientation} = @props
node = @getDOMNode()
switch orientation
when 'vertical'
node.scrollTop = presenter.state.scrollTop
node.scrollTop = @newState.scrollTop
when 'horizontal'
node.scrollLeft = presenter.state.content.scrollLeft
node.scrollLeft = @newState.scrollLeft
onScroll: ->
{orientation, onScroll} = @props

View File

@@ -34,7 +34,6 @@ TextEditorComponent = React.createClass
scrollSensitivity: 0.4
heightAndWidthMeasurementRequested: false
inputEnabled: true
scopedCharacterWidthsChangeCount: null
domPollingInterval: 100
domPollingIntervalId: null
domPollingPaused: false
@@ -56,7 +55,7 @@ TextEditorComponent = React.createClass
hiddenInputStyle = @getHiddenInputPosition()
hiddenInputStyle.WebkitTransform = 'translateZ(0)' if @useHardwareAcceleration
style.height = @presenter.state.scrollHeight if @autoHeight
style.height = @presenter.state.content.scrollHeight if @autoHeight
if useShadowDOM
className = 'editor-contents--private'
@@ -233,7 +232,6 @@ TextEditorComponent = React.createClass
@subscribe editor.observeGrammar(@onGrammarChanged)
@subscribe editor.observeCursors(@onCursorAdded)
@subscribe editor.observeSelections(@onSelectionAdded)
@subscribe editor.onDidChangeCharacterWidths(@onCharacterWidthsChanged)
@subscribe editor.$scrollTop.changes, @onScrollTopChanged
@subscribe editor.$scrollLeft.changes, @onScrollLeftChanged
@subscribe editor.$verticalScrollbarWidth.changes, @requestUpdate
@@ -579,9 +577,6 @@ TextEditorComponent = React.createClass
@cursorMoved = true
@requestUpdate()
onCharacterWidthsChanged: (@scopedCharacterWidthsChangeCount) ->
@requestUpdate()
handleDragUntilMouseUp: (event, dragHandler) ->
{editor} = @props
dragging = false

View File

@@ -51,10 +51,10 @@ class TextEditorPresenter
buildState: ->
@state =
scrollingVertically: false
horizontalScrollbar: {}
verticalScrollbar: {}
content:
scrollingVertically: false
blinkCursorsOff: false
lines: {}
highlights: {}
@@ -65,6 +65,7 @@ class TextEditorPresenter
updateState: ->
@updateVerticalScrollState()
@updateHorizontalScrollState()
@updateScrollbarsState()
@updateContentState()
@updateLinesState()
@@ -75,8 +76,28 @@ class TextEditorPresenter
@updateLineNumbersState()
updateVerticalScrollState: ->
@state.scrollHeight = @computeScrollHeight()
@state.scrollTop = @getScrollTop()
scrollHeight = @computeScrollHeight()
@state.content.scrollHeight = scrollHeight
@state.gutter.scrollHeight = scrollHeight
@state.verticalScrollbar.scrollHeight = scrollHeight
scrollTop = @getScrollTop()
@state.content.scrollTop = scrollTop
@state.gutter.scrollTop = scrollTop
@state.verticalScrollbar.scrollTop = scrollTop
@emitter.emit 'did-update-state'
updateHorizontalScrollState: ->
scrollWidth = @computeScrollWidth()
@state.content.scrollWidth = scrollWidth
@state.horizontalScrollbar.scrollWidth = scrollWidth
scrollLeft = @getScrollLeft()
@state.content.scrollLeft = @getScrollLeft()
@state.horizontalScrollbar.scrollLeft = @getScrollLeft()
@emitter.emit 'did-update-state'
updateScrollbarsState: ->
contentWidth = @computeContentWidth()
@@ -406,11 +427,11 @@ class TextEditorPresenter
clearTimeout(@stoppedScrollingTimeoutId)
@stoppedScrollingTimeoutId = null
@stoppedScrollingTimeoutId = setTimeout(@didStopScrolling.bind(this), @stoppedScrollingDelay)
@state.scrollingVertically = true
@state.content.scrollingVertically = true
@emitter.emit 'did-update-state'
didStopScrolling: ->
@state.scrollingVertically = false
@state.content.scrollingVertically = false
if @getMouseWheelScreenRow()?
@mouseWheelScreenRow = null
@updateLinesState()
@@ -421,7 +442,7 @@ class TextEditorPresenter
getScrollTop: -> @scrollTop
setScrollLeft: (@scrollLeft) ->
@updateContentState()
@updateHorizontalScrollState()
getScrollLeft: -> @scrollLeft
@@ -447,6 +468,7 @@ class TextEditorPresenter
@height ? @model.getScreenLineCount() * @getLineHeight()
setContentFrameWidth: (@contentFrameWidth) ->
@updateHorizontalScrollState()
@updateScrollbarsState()
@updateContentState()
@updateLinesState()
@@ -511,6 +533,7 @@ class TextEditorPresenter
@characterWidthsChanged() unless @batchingCharacterMeasurement
characterWidthsChanged: ->
@updateHorizontalScrollState()
@updateContentState()
@updateLinesState()
@updateCursorsState()