From 49bf3bb14e1b61d1744fe92a69c98660ae48adbe Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 23 Jan 2015 17:44:42 -0700 Subject: [PATCH] Use presenter to render flashes Signed-off-by: Max Brunsfeld --- spec/text-editor-component-spec.coffee | 3 +- src/highlight-component.coffee | 51 +++++++++++++------------- src/highlights-component.coffee | 5 +-- src/lines-component.coffee | 6 +-- src/text-editor-presenter.coffee | 32 +++++++++++----- 5 files changed, 52 insertions(+), 45 deletions(-) diff --git a/spec/text-editor-component-spec.coffee b/spec/text-editor-component-spec.coffee index 0c84703eb..17a37f064 100644 --- a/spec/text-editor-component-spec.coffee +++ b/spec/text-editor-component-spec.coffee @@ -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 diff --git a/src/highlight-component.coffee b/src/highlight-component.coffee index 53075ab0a..ef090ea7b 100644 --- a/src/highlight-component.coffee +++ b/src/highlight-component.coffee @@ -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() diff --git a/src/highlights-component.coffee b/src/highlights-component.coffee index e4d465b67..91602b597 100644 --- a/src/highlights-component.coffee +++ b/src/highlights-component.coffee @@ -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') diff --git a/src/lines-component.coffee b/src/lines-component.coffee index 37d6339df..4c80659ec 100644 --- a/src/lines-component.coffee +++ b/src/lines-component.coffee @@ -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 diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index d096e6266..ce807ea5f 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -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')