Use presenter to render highlights

Signed-off-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
This commit is contained in:
Nathan Sobo
2015-01-23 17:48:27 -07:00
parent 2f526c59c5
commit 8ebd057b0c
6 changed files with 95 additions and 94 deletions

View File

@@ -5,94 +5,45 @@ React = require 'react-atom-fork'
module.exports =
HighlightComponent = React.createClass
displayName: 'HighlightComponent'
lastFlashCount: 0
lastFlashClass: null
render: ->
{startPixelPosition, endPixelPosition, decoration} = @props
{editor, state} = @props
className = 'highlight'
className += " #{decoration.class}" if decoration.class?
className += " #{state.class}" if state.class?
div {className},
if endPixelPosition.top is startPixelPosition.top
@renderSingleLineRegions(decoration.deprecatedRegionClass)
else
@renderMultiLineRegions(decoration.deprecatedRegionClass)
for region, i in state.regions
regionClassName = 'region'
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: ->
{editor, decoration} = @props
if decoration.id?
@decoration = editor.decorationForId(decoration.id)
@decorationDisposable = @decoration.onDidFlash @startFlashAnimation
@startFlashAnimation()
{key} = @props
presenter.onDidFlashHighlight @startFlashAnimation.bind(this)
componentWillUnmount: ->
@decorationDisposable?.dispose()
@decorationDisposable = null
startFlashAnimation: ->
return unless flash = @decoration.consumeNextFlash()
node = @getDOMNode()
node.classList.remove(flash.class)
if @lastFlashClass?
clearTimeout(@flashTimeoutId)
node.classList.remove(@lastFlashClass)
@lastFlashClass = null
requestAnimationFrame =>
node.classList.add(flash.class)
clearTimeout(@flashTimeoutId)
removeFlashClass = -> node.classList.remove(flash.class)
flashClass = @props.state.flashClass
node.classList.add(flashClass)
removeFlashClass = -> node.classList.remove(flashClass)
@flashTimeoutId = setTimeout(removeFlashClass, flash.duration)
renderSingleLineRegions: (regionClass) ->
{startPixelPosition, endPixelPosition, lineHeightInPixels} = @props
className = 'region'
className += " #{regionClass}" if regionClass?
[
div className: className, key: 0, style:
top: startPixelPosition.top
height: lineHeightInPixels
left: startPixelPosition.left
width: endPixelPosition.left - startPixelPosition.left
]
renderMultiLineRegions: (regionClass) ->
{startPixelPosition, endPixelPosition, lineHeightInPixels} = @props
className = 'region'
className += " #{regionClass}" if regionClass?
regions = []
index = 0
# First row, extending from selection start to the right side of screen
regions.push(
div className: className, key: index++, style:
top: startPixelPosition.top
left: startPixelPosition.left
height: lineHeightInPixels
right: 0
)
# Middle rows, extending from left side to right side of screen
if endPixelPosition.top - startPixelPosition.top > lineHeightInPixels
regions.push(
div className: className, key: index++, style:
top: startPixelPosition.top + lineHeightInPixels
height: endPixelPosition.top - startPixelPosition.top - lineHeightInPixels
left: 0
right: 0
)
# Last row, extending from left side of screen to selection end
regions.push(
div className: className, key: index, style:
top: endPixelPosition.top
height: lineHeightInPixels
left: 0
width: endPixelPosition.left
)
regions
shouldComponentUpdate: (newProps) ->
not isEqualForProperties(newProps, @props, 'startPixelPosition', 'endPixelPosition', 'lineHeightInPixels', 'decoration')

View File

@@ -12,13 +12,10 @@ HighlightsComponent = React.createClass
@renderHighlights() if @props.performedInitialMeasurement
renderHighlights: ->
{editor, highlightDecorations, lineHeightInPixels} = @props
{editor, presenter} = @props
highlightComponents = []
for markerId, {startPixelPosition, endPixelPosition, decorations} of highlightDecorations
for decoration in decorations
highlightComponents.push(HighlightComponent({editor, key: "#{markerId}-#{decoration.id}", startPixelPosition, endPixelPosition, decoration, lineHeightInPixels}))
for key, state of presenter.state.content.highlights
highlightComponents.push(HighlightComponent({editor, key, state}))
highlightComponents
componentDidMount: ->

View File

@@ -40,7 +40,7 @@ LinesComponent = React.createClass
HighlightsComponent {
editor, highlightDecorations, lineHeightInPixels, defaultCharWidth,
scopedCharacterWidthsChangeCount, performedInitialMeasurement
scopedCharacterWidthsChangeCount, performedInitialMeasurement, presenter
}
getTransform: ->

View File

@@ -115,6 +115,7 @@ class TextEditorPresenter
@state.content.highlights = {}
for decoration in @model.getHighlightDecorations()
continue unless decoration.getMarker().isValid()
screenRange = decoration.getMarker().getScreenRange()
if screenRange.intersectsRowRange(startRow, endRow - 1)
if screenRange.start.row < startRow
@@ -126,7 +127,12 @@ class TextEditorPresenter
continue if screenRange.isEmpty()
@state.content.highlights[decoration.id] =
class: decoration.getProperties().class
deprecatedRegionClass: decoration.getProperties().deprecatedRegionClass
regions: @buildHighlightRegions(screenRange)
flashCount: 0
flashDuration: null
flashClass: null
@emitter.emit 'did-update-state'
buildHighlightRegions: (screenRange) ->
lineHeightInPixels = @getLineHeight()
@@ -331,24 +337,30 @@ class TextEditorPresenter
{top, left, width, height}
observeLineDecoration: (decoration) ->
markerDidChangeDisposable = decoration.getMarker().onDidChange(@updateLinesState.bind(this))
didDestroyDisposable = decoration.onDidDestroy =>
@disposables.remove(markerDidChangeDisposable)
@disposables.remove(didDestroyDisposable)
decorationDisposables = new CompositeDisposable
decorationDisposables.add decoration.getMarker().onDidChange(@updateLinesState.bind(this))
decorationDisposables.add decoration.onDidDestroy =>
@disposables.remove(decorationDisposables)
@updateLinesState()
@disposables.add(markerDidChangeDisposable)
@disposables.add(didDestroyDisposable)
@disposables.add(decorationDisposables)
observeHighlightDecoration: (decoration) ->
markerDidChangeDisposable = decoration.getMarker().onDidChange(@updateHighlightsState.bind(this))
didDestroyDisposable = decoration.onDidDestroy =>
@disposables.remove(markerDidChangeDisposable)
@disposables.remove(didDestroyDisposable)
decorationDisposables = new CompositeDisposable
decorationDisposables.add decoration.getMarker().onDidChange(@updateHighlightsState.bind(this))
decorationDisposables.add decoration.onDidChangeProperties(@updateHighlightsState.bind(this))
decorationDisposables.add decoration.onDidFlash(@highlightDidFlash.bind(this, decoration))
decorationDisposables.add decoration.onDidDestroy =>
@disposables.remove(decorationDisposables)
@updateHighlightsState()
@disposables.add(decorationDisposables)
@disposables.add(markerDidChangeDisposable)
@disposables.add(didDestroyDisposable)
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"
didAddDecoration: (decoration) ->
if decoration.isType('line')