Use presenter to render flashes

Signed-off-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
This commit is contained in:
Nathan Sobo
2015-01-23 17:44:42 -07:00
parent 8ebd057b0c
commit 49bf3bb14e
5 changed files with 52 additions and 45 deletions

View File

@@ -923,7 +923,6 @@ describe "TextEditorComponent", ->
it "will flash the selection when flash:true is passed to editor::setSelectedBufferRange", ->
editor.setSelectedBufferRange([[1, 6], [1, 10]], flash: true)
nextAnimationFrame()
nextAnimationFrame() # flash starts on its own frame
selectionNode = componentNode.querySelector('.selection')
expect(selectionNode.classList.contains('flash')).toBe true
@@ -1183,6 +1182,8 @@ describe "TextEditorComponent", ->
advanceClock(2)
decoration.flash('flash-class', 10)
nextAnimationFrame()
# Removed for 1 frame to force CSS transition to restart
expect(highlightNode.classList.contains('flash-class')).toBe false

View File

@@ -5,11 +5,11 @@ React = require 'react-atom-fork'
module.exports =
HighlightComponent = React.createClass
displayName: 'HighlightComponent'
lastFlashCount: 0
lastFlashClass: null
currentFlashCount: 0
currentFlashClass: null
render: ->
{editor, state} = @props
{state} = @props
className = 'highlight'
className += " #{state.class}" if state.class?
@@ -20,30 +20,31 @@ HighlightComponent = React.createClass
regionClassName += " #{state.deprecatedRegionClass}" if state.deprecatedRegionClass?
div className: regionClassName, key: i, style: region
componentDidUpdate: ->
if @props.state.flashCount > @lastFlashCount
@startFlashAnimation()
@lastFlashCount = @props.state.flashCount
@lastFlashClass = @props.state.flashClass
componentDidMount: ->
{key} = @props
presenter.onDidFlashHighlight @startFlashAnimation.bind(this)
@flashIfRequested()
componentWillUnmount: ->
@decorationDisposable?.dispose()
@decorationDisposable = null
componentDidUpdate: ->
@flashIfRequested()
startFlashAnimation: ->
node = @getDOMNode()
flashIfRequested: ->
if @props.state.flashCount > @currentFlashCount
@currentFlashCount = @props.state.flashCount
if @lastFlashClass?
clearTimeout(@flashTimeoutId)
node.classList.remove(@lastFlashClass)
@lastFlashClass = null
node = @getDOMNode()
{flashClass, flashDuration} = @props.state
requestAnimationFrame =>
flashClass = @props.state.flashClass
node.classList.add(flashClass)
removeFlashClass = -> node.classList.remove(flashClass)
@flashTimeoutId = setTimeout(removeFlashClass, flash.duration)
addFlashClass = =>
node.classList.add(flashClass)
@currentFlashClass = flashClass
@flashTimeoutId = setTimeout(removeFlashClass, flashDuration)
removeFlashClass = =>
node.classList.remove(@currentFlashClass)
@currentFlashClass = null
clearTimeout(@flashTimeoutId)
if @currentFlashClass?
removeFlashClass()
requestAnimationFrame(addFlashClass)
else
addFlashClass()

View File

@@ -15,7 +15,7 @@ HighlightsComponent = React.createClass
{editor, presenter} = @props
highlightComponents = []
for key, state of presenter.state.content.highlights
highlightComponents.push(HighlightComponent({editor, key, state}))
highlightComponents.push(HighlightComponent({key, state}))
highlightComponents
componentDidMount: ->
@@ -23,6 +23,3 @@ HighlightsComponent = React.createClass
insertionPoint = document.createElement('content')
insertionPoint.setAttribute('select', '.underlayer')
@getDOMNode().appendChild(insertionPoint)
shouldComponentUpdate: (newProps) ->
not isEqualForProperties(newProps, @props, 'highlightDecorations', 'lineHeightInPixels', 'defaultCharWidth', 'scopedCharacterWidthsChangeCount')

View File

@@ -37,11 +37,7 @@ LinesComponent = React.createClass
div className: 'placeholder-text', placeholderText if placeholderText?
CursorsComponent {presenter}
HighlightsComponent {
editor, highlightDecorations, lineHeightInPixels, defaultCharWidth,
scopedCharacterWidthsChangeCount, performedInitialMeasurement, presenter
}
HighlightsComponent {presenter, performedInitialMeasurement}
getTransform: ->
{scrollTop, scrollLeft} = @newState

View File

@@ -110,9 +110,11 @@ class TextEditorPresenter
@emitter.emit 'did-update-state'
updateHighlightsState: ->
@state.content.highlights ?= {}
startRow = @getStartRow()
endRow = @getEndRow()
@state.content.highlights = {}
visibleHighlights = {}
for decoration in @model.getHighlightDecorations()
continue unless decoration.getMarker().isValid()
@@ -125,13 +127,23 @@ class TextEditorPresenter
screenRange.end.row = endRow
screenRange.end.column = 0
continue if screenRange.isEmpty()
@state.content.highlights[decoration.id] =
class: decoration.getProperties().class
deprecatedRegionClass: decoration.getProperties().deprecatedRegionClass
regions: @buildHighlightRegions(screenRange)
visibleHighlights[decoration.id] = true
@state.content.highlights[decoration.id] ?= {
flashCount: 0
flashDuration: null
flashClass: null
}
highlightState = @state.content.highlights[decoration.id]
highlightState.class = decoration.getProperties().class
highlightState.deprecatedRegionClass = decoration.getProperties().deprecatedRegionClass
highlightState.regions = @buildHighlightRegions(screenRange)
for id of @state.content.highlights
unless visibleHighlights.hasOwnProperty(id)
delete @state.content.highlights[id]
@emitter.emit 'did-update-state'
buildHighlightRegions: (screenRange) ->
@@ -356,11 +368,11 @@ class TextEditorPresenter
highlightDidFlash: (decoration) ->
flash = decoration.consumeNextFlash()
decorationState = @state.content.highlights[decoration.id]
decorationState.flashCount++
decorationState.flashClass = flash.class
decorationState.flashDuration = flash.duration
@emitter.emit "did-update-state"
if decorationState = @state.content.highlights[decoration.id]
decorationState.flashCount++
decorationState.flashClass = flash.class
decorationState.flashDuration = flash.duration
@emitter.emit "did-update-state"
didAddDecoration: (decoration) ->
if decoration.isType('line')