Add bounds checking for overlay decorations

This commit is contained in:
Ben Ogle
2014-11-11 15:46:27 -08:00
parent 661b09ab1c
commit 9dfaa8a4e5
2 changed files with 115 additions and 5 deletions

View File

@@ -1262,6 +1262,106 @@ describe "TextEditorComponent", ->
expect(overlay.style.left).toBe position.left + 'px' expect(overlay.style.left).toBe position.left + 'px'
expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px' expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px'
describe "positioning the overlay when near the edge of the window", ->
[itemWidth, itemHeight] = []
beforeEach ->
itemWidth = 4 * editor.getDefaultCharWidth()
itemHeight = 4 * editor.getLineHeightInPixels()
gutterWidth = componentNode.querySelector('.gutter').offsetWidth
windowWidth = gutterWidth + 30 * editor.getDefaultCharWidth()
windowHeight = 9 * editor.getLineHeightInPixels()
item.style.width = itemWidth + 'px'
item.style.height = itemHeight + 'px'
wrapperNode.style.width = windowWidth + 'px'
wrapperNode.style.height = windowHeight + 'px'
editor.setScrollTop(0)
editor.setScrollLeft(0)
component.measureHeightAndWidth()
nextAnimationFrame()
it "flips horizontally when near the right edge", ->
marker = editor.displayBuffer.markBufferRange([[0, 26], [0, 26]], invalidate: 'never')
decoration = editor.decorateMarker(marker, {type: 'overlay', item})
nextAnimationFrame()
position = editor.pixelPositionForBufferPosition([0, 26])
overlay = component.getTopmostDOMNode().querySelector('atom-overlay')
expect(overlay.style.left).toBe position.left + 'px'
expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px'
editor.insertText('a')
nextAnimationFrame()
position = editor.pixelPositionForBufferPosition([0, 27])
expect(overlay.style.left).toBe position.left - itemWidth + 'px'
expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px'
it "flips vertically when near the bottom edge", ->
marker = editor.displayBuffer.markBufferRange([[4, 0], [4, 0]], invalidate: 'never')
decoration = editor.decorateMarker(marker, {type: 'overlay', item})
nextAnimationFrame()
position = editor.pixelPositionForBufferPosition([4, 0])
overlay = component.getTopmostDOMNode().querySelector('atom-overlay')
expect(overlay.style.left).toBe position.left + 'px'
expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px'
editor.insertNewline()
nextAnimationFrame()
position = editor.pixelPositionForBufferPosition([5, 0])
expect(overlay.style.left).toBe position.left + 'px'
expect(overlay.style.top).toBe position.top - itemHeight + 'px'
describe "when editor position is not 0", ->
it "flips horizontally when near the right edge", ->
editor.setScrollLeft(2 * editor.getDefaultCharWidth())
marker = editor.displayBuffer.markBufferRange([[0, 28], [0, 28]], invalidate: 'never')
decoration = editor.decorateMarker(marker, {type: 'overlay', item})
nextAnimationFrame()
position = editor.pixelPositionForBufferPosition([0, 28])
overlay = component.getTopmostDOMNode().querySelector('atom-overlay')
expect(overlay.style.left).toBe position.left + 'px'
expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px'
editor.insertText('a')
nextAnimationFrame()
position = editor.pixelPositionForBufferPosition([0, 29])
expect(overlay.style.left).toBe position.left - itemWidth + 'px'
expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px'
it "flips vertically when near the bottom edge", ->
editor.setScrollTop(2 * editor.getLineHeightInPixels())
marker = editor.displayBuffer.markBufferRange([[6, 0], [6, 0]], invalidate: 'never')
decoration = editor.decorateMarker(marker, {type: 'overlay', item})
nextAnimationFrame()
position = editor.pixelPositionForBufferPosition([6, 0])
overlay = component.getTopmostDOMNode().querySelector('atom-overlay')
expect(overlay.style.left).toBe position.left + 'px'
expect(overlay.style.top).toBe position.top + editor.getLineHeightInPixels() + 'px'
editor.insertNewline()
nextAnimationFrame()
position = editor.pixelPositionForBufferPosition([7, 0])
expect(overlay.style.left).toBe position.left + 'px'
expect(overlay.style.top).toBe position.top - itemHeight + 'px'
describe "hidden input field", -> describe "hidden input field", ->
it "renders the hidden input field at the position of the last cursor if the cursor is on screen and the editor is focused", -> it "renders the hidden input field at the position of the last cursor if the cursor is on screen and the editor is focused", ->
editor.setVerticalScrollMargin(0) editor.setVerticalScrollMargin(0)

View File

@@ -13,7 +13,7 @@ class OverlayManager
startPixelPosition startPixelPosition
else else
endPixelPosition endPixelPosition
@renderOverlay(hostElement, decoration, pixelPosition, lineHeightInPixels) @renderOverlay(editor, hostElement, decoration, pixelPosition, lineHeightInPixels)
existingDecorations ?= {} existingDecorations ?= {}
existingDecorations[decoration.id] = true existingDecorations[decoration.id] = true
@@ -25,11 +25,21 @@ class OverlayManager
return return
renderOverlay: (hostElement, decoration, pixelPosition, lineHeightInPixels) -> renderOverlay: (editor, hostElement, decoration, pixelPosition, lineHeightInPixels) ->
item = atom.views.getView(decoration.item)
unless overlay = @overlays[decoration.id] unless overlay = @overlays[decoration.id]
overlay = @overlays[decoration.id] = document.createElement('atom-overlay') overlay = @overlays[decoration.id] = document.createElement('atom-overlay')
overlay.appendChild(atom.views.getView(decoration.item)) overlay.appendChild(item)
hostElement.appendChild(overlay) hostElement.appendChild(overlay)
overlay.style.top = pixelPosition.top + lineHeightInPixels + 'px' itemWidth = item.offsetWidth
overlay.style.left = pixelPosition.left + 'px' itemHeight = item.offsetHeight
left = pixelPosition.left
left -= itemWidth if left + itemWidth - editor.getScrollLeft() > editor.getWidth()
top = pixelPosition.top + lineHeightInPixels
top -= itemHeight + lineHeightInPixels if top + itemHeight - editor.getScrollTop() > editor.getHeight()
overlay.style.top = top + 'px'
overlay.style.left = left + 'px'