Add Buffer.observeMarkerRange

This commit is contained in:
Nathan Sobo
2013-02-04 11:27:39 -07:00
parent df4ea9293d
commit 44e48d42ea
3 changed files with 76 additions and 3 deletions

View File

@@ -739,6 +739,37 @@ describe 'Buffer', ->
buffer.setMarkerHeadPosition(marker, [6, 2])
expect(observeHandler).not.toHaveBeenCalled()
describe ".observeMarkerRange(marker, callback)", ->
[observeHandler, marker] = []
beforeEach ->
observeHandler = jasmine.createSpy("observeHandler")
marker = buffer.markRange([[4, 20], [4, 23]])
buffer.observeMarkerRange(marker, observeHandler)
it "calls the callback when the marker's head position changes", ->
buffer.setMarkerHeadPosition(marker, [6, 2])
expect(observeHandler).toHaveBeenCalled()
expect(observeHandler.argsForCall[0][0]).toEqual { oldRange: [[4, 20], [4, 23]], newRange: [[4, 20], [6, 2]], bufferChanged: false }
observeHandler.reset()
buffer.insert([6, 0], '...')
expect(observeHandler.argsForCall[0][0]).toEqual { oldRange: [[4, 20], [6, 2]], newRange: [[4, 20], [6, 5]], bufferChanged: true }
it "calls the given callback when the marker's tail position changes", ->
buffer.setMarkerTailPosition(marker, [6, 2])
expect(observeHandler).toHaveBeenCalled()
expect(observeHandler.argsForCall[0][0]).toEqual { oldRange: [[4, 20], [4, 23]], newRange: [[4, 23], [6, 2]], bufferChanged: false }
observeHandler.reset()
buffer.insert([6, 0], '...')
expect(observeHandler.argsForCall[0][0]).toEqual { oldRange: [[4, 23], [6, 2]], newRange: [[4, 23], [6, 5]], bufferChanged: true }
it "only calls the callback once when both the marker's head and tail positions change due to the same operation", ->
buffer.insert([4, 0], '...')
expect(observeHandler.callCount).toBe 1
expect(observeHandler.argsForCall[0][0]).toEqual { oldRange: [[4, 20], [4, 23]], newRange: [[4, 23], [4, 26]], bufferChanged: true }
describe "marker destruction", ->
marker = null

View File

@@ -7,10 +7,13 @@ class BufferMarker
headPosition: null
tailPosition: null
headPositionObservers: null
rangeObservers: null
disableRangeChanged: false
stayValid: false
constructor: ({@id, @buffer, range, @stayValid, noTail, reverse}) ->
@headPositionObservers = []
@rangeObservers = []
@setRange(range, {noTail, reverse})
setRange: (range, options={}) ->
@@ -37,16 +40,38 @@ class BufferMarker
setHeadPosition: (headPosition, options={}) ->
oldPosition = @headPosition
oldRange = @getRange()
@headPosition = Point.fromObject(headPosition)
@headPosition = @buffer.clipPosition(@headPosition) if options.clip ? true
newPosition = @headPosition
newRange = @getRange()
bufferChanged = !!options.bufferChanged
observer({oldPosition, newPosition, bufferChanged}) for observer in @headPositionObservers
unless newPosition.isEqual(oldPosition)
@headPositionChanged({oldPosition, newPosition, bufferChanged})
@rangeChanged({oldRange, newRange, bufferChanged})
@headPosition
headPositionChanged: ({oldPosition, newPosition, bufferChanged}) ->
observer({oldPosition, newPosition, bufferChanged}) for observer in @getHeadPositionObservers()
getHeadPositionObservers: ->
new Array(@headPositionObservers...)
rangeChanged: ({oldRange, newRange, bufferChanged}) ->
unless @disableRangeChanged
observer({oldRange, newRange, bufferChanged}) for observer in @getRangeObservers()
getRangeObservers: ->
new Array(@rangeObservers...)
setTailPosition: (tailPosition, options={}) ->
oldRange = @getRange()
@tailPosition = Point.fromObject(tailPosition)
@tailPosition = @buffer.clipPosition(@tailPosition) if options.clip ? true
newRange = @getRange()
bufferChanged = !!options.bufferChanged
@rangeChanged({oldRange, newRange, bufferChanged}) unless newRange.isEqual(oldRange)
@tailPosition
getStartPosition: ->
@getRange().start
@@ -62,8 +87,17 @@ class BufferMarker
observeHeadPosition: (callback) ->
@headPositionObservers.push(callback)
cancel: =>
_.remove(@headPositionObservers, callback)
cancel: => @unobserveHeadPosition(callback)
unobserveHeadPosition: (callback) ->
_.remove(@headPositionObservers, callback)
observeRange: (callback) ->
@rangeObservers.push(callback)
cancel: => @unobserveRange(callback)
unobserveRange: (callback) ->
_.remove(@rangeObservers, callback)
tryToInvalidate: (oldRange) ->
containsStart = oldRange.containsPoint(@getStartPosition(), exclusive: true)
@@ -84,8 +118,13 @@ class BufferMarker
[@id]
handleBufferChange: (bufferChange) ->
@disableRangeChanged = true
oldRange = @getRange()
@setHeadPosition(@updatePosition(@headPosition, bufferChange, false), clip: false, bufferChanged: true)
@setTailPosition(@updatePosition(@tailPosition, bufferChange, true), clip: false, bufferChanged: true) if @tailPosition
newRange = @getRange()
@disableRangeChanged = false
@rangeChanged({oldRange, newRange, bufferChanged: true}) unless newRange.isEqual(oldRange)
updatePosition: (position, bufferChange, isFirstPoint) ->
{ oldRange, newRange } = bufferChange

View File

@@ -323,6 +323,9 @@ class Buffer
observeMarkerHeadPosition: (id, callback) ->
@validMarkers[id]?.observeHeadPosition(callback)
observeMarkerRange: (id, callback) ->
@validMarkers[id]?.observeRange(callback)
getAnchors: -> new Array(@anchors...)
addAnchor: (options) ->