From bf33d96899d39c032bc184fd429f43ee44f1ec05 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Wed, 2 Jul 2014 18:36:29 -0700 Subject: [PATCH] Decorations can be flashed --- spec/editor-component-spec.coffee | 42 ++++++++++++++++++++++++++++--- src/decoration.coffee | 3 +++ src/highlight-component.coffee | 18 +++++++------ src/highlights-component.coffee | 4 +-- 4 files changed, 54 insertions(+), 13 deletions(-) diff --git a/spec/editor-component-spec.coffee b/spec/editor-component-spec.coffee index d68bfc6db..e3bdbac5e 100644 --- a/spec/editor-component-spec.coffee +++ b/spec/editor-component-spec.coffee @@ -887,12 +887,12 @@ describe "EditorComponent", -> expect(lineAndLineNumberHaveClass(3, 'only-non-empty')).toBe false describe "highlight decoration rendering", -> - [marker, decoration, scrollViewClientLeft] = [] + [marker, decoration, decorationParams, scrollViewClientLeft] = [] beforeEach -> scrollViewClientLeft = node.querySelector('.scroll-view').getBoundingClientRect().left marker = editor.displayBuffer.markBufferRange([[2, 13], [3, 15]], invalidate: 'inside') - decoration = {type: 'highlight', class: 'test-highlight'} - editor.addDecorationForMarker(marker, decoration) + decorationParams = {type: 'highlight', class: 'test-highlight'} + decoration = editor.addDecorationForMarker(marker, decorationParams) runSetImmediateCallbacks() it "does not render highlights for off-screen lines until they come on-screen", -> @@ -929,7 +929,7 @@ describe "EditorComponent", -> expect(regions.length).toBe 2 it "removes highlights when a decoration is removed", -> - editor.removeDecorationForMarker(marker, decoration) + editor.removeDecorationForMarker(marker, decorationParams) runSetImmediateCallbacks() regions = node.querySelectorAll('.test-highlight .region') expect(regions.length).toBe 0 @@ -960,6 +960,40 @@ describe "EditorComponent", -> regions = node.querySelectorAll('.test-highlight .region') expect(regions.length).toBe 2 + describe "flashing a decoration via the Decoration.flash()", -> + highlightNode = null + flashClass = 'flashClass' + beforeEach -> + highlightNode = node.querySelector('.test-highlight') + + it "adds and removes the flash class specified in ::flash", -> + expect(highlightNode.classList.contains(flashClass)).toBe false + + decoration.flash(flashClass, 10) + expect(highlightNode.classList.contains(flashClass)).toBe true + + advanceClock(10) + expect(highlightNode.classList.contains(flashClass)).toBe false + + describe "when ::flash is called again before the first has finished", -> + it "removes the class from the decoration highlight before adding it for the second ::flash call", -> + decoration.flash(flashClass, 10) + expect(highlightNode.classList.contains(flashClass)).toBe true + + addClassSpy = spyOn(highlightNode.classList, 'add').andCallThrough() + removeClassSpy = spyOn(highlightNode.classList, 'remove').andCallThrough() + + advanceClock(2) + decoration.flash(flashClass, 10) + + expect(removeClassSpy).toHaveBeenCalledWith(flashClass) + expect(addClassSpy).toHaveBeenCalledWith(flashClass) + + expect(highlightNode.classList.contains(flashClass)).toBe true + + advanceClock(10) + expect(highlightNode.classList.contains(flashClass)).toBe false + describe "when a decoration's marker moves", -> it "moves rendered highlights when the buffer is changed", -> regionStyle = node.querySelector('.test-highlight .region').style diff --git a/src/decoration.coffee b/src/decoration.coffee index 666faf6dc..3949f857d 100644 --- a/src/decoration.coffee +++ b/src/decoration.coffee @@ -30,3 +30,6 @@ class Decoration for key, value of decorationPattern return false if @params[key] != value true + + flash: (klass, duration=500) -> + @emit('flash', klass, duration) diff --git a/src/highlight-component.coffee b/src/highlight-component.coffee index a8eb10e27..20eb3676f 100644 --- a/src/highlight-component.coffee +++ b/src/highlight-component.coffee @@ -19,22 +19,26 @@ HighlightComponent = React.createClass @renderMultiLineRegions() componentDidMount: -> - @startFlashAnimation() if @props.decoration.flash? + {editor, decoration} = @props + if decoration.id? + @decoration = editor.decorationForId(decoration.id) + @decoration.on 'flash', @startFlashAnimation componentDidUpdate: -> @startFlashAnimation() if @props.decoration.flash? - startFlashAnimation: -> - {flash} = @props.decoration + componentWillUnmount: -> + @decoration?.off 'flash', @startFlashAnimation + startFlashAnimation: (klass, duration) -> node = @getDOMNode() - node.classList.remove(flash.class) + node.classList.remove(klass) requestAnimationFrame => - node.classList.add(flash.class) + node.classList.add(klass) clearTimeout(@flashTimeoutId) - removeFlashClass = -> node.classList.remove(flash.class) - @flashTimeoutId = setTimeout(removeFlashClass, flash.duration ? 500) + removeFlashClass = -> node.classList.remove(klass) + @flashTimeoutId = setTimeout(removeFlashClass, duration) renderSingleLineRegions: -> {startPixelPosition, endPixelPosition, lineHeightInPixels} = @props diff --git a/src/highlights-component.coffee b/src/highlights-component.coffee index 23a046387..2cadcb289 100644 --- a/src/highlights-component.coffee +++ b/src/highlights-component.coffee @@ -12,12 +12,12 @@ HighlightsComponent = React.createClass @renderHighlights() if @isMounted() renderHighlights: -> - {highlightDecorations, lineHeightInPixels} = @props + {editor, highlightDecorations, lineHeightInPixels} = @props highlightComponents = [] for markerId, {startPixelPosition, endPixelPosition, decorations} of highlightDecorations for decoration in decorations - highlightComponents.push(HighlightComponent({key: "#{markerId}-#{decoration.class}", startPixelPosition, endPixelPosition, decoration, lineHeightInPixels})) + highlightComponents.push(HighlightComponent({editor, key: "#{markerId}-#{decoration.class}", startPixelPosition, endPixelPosition, decoration, lineHeightInPixels})) highlightComponents