mirror of
https://github.com/pulsar-edit/pulsar.git
synced 2024-09-20 15:37:46 +03:00
Add avoidOverflow: false option for overlays
This commit is contained in:
parent
f2e2475c62
commit
5297e7ab1a
@ -876,17 +876,22 @@ describe('TextEditorComponent', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
describe('overlay decorations', () => {
|
describe('overlay decorations', () => {
|
||||||
it('renders overlay elements at the specified screen position unless it would overflow the window', async () => {
|
function attachFakeWindow (component) {
|
||||||
const {component, element, editor} = buildComponent({width: 200, height: 100, attach: false})
|
|
||||||
const fakeWindow = document.createElement('div')
|
const fakeWindow = document.createElement('div')
|
||||||
fakeWindow.style.position = 'absolute'
|
fakeWindow.style.position = 'absolute'
|
||||||
fakeWindow.style.padding = 20 + 'px'
|
fakeWindow.style.padding = 20 + 'px'
|
||||||
fakeWindow.style.backgroundColor = 'blue'
|
fakeWindow.style.backgroundColor = 'blue'
|
||||||
fakeWindow.appendChild(element)
|
fakeWindow.appendChild(component.element)
|
||||||
jasmine.attachToDOM(fakeWindow)
|
jasmine.attachToDOM(fakeWindow)
|
||||||
|
|
||||||
spyOn(component, 'getWindowInnerWidth').andCallFake(() => fakeWindow.getBoundingClientRect().width)
|
spyOn(component, 'getWindowInnerWidth').andCallFake(() => fakeWindow.getBoundingClientRect().width)
|
||||||
spyOn(component, 'getWindowInnerHeight').andCallFake(() => fakeWindow.getBoundingClientRect().height)
|
spyOn(component, 'getWindowInnerHeight').andCallFake(() => fakeWindow.getBoundingClientRect().height)
|
||||||
|
return fakeWindow
|
||||||
|
}
|
||||||
|
|
||||||
|
it('renders overlay elements at the specified screen position unless it would overflow the window', async () => {
|
||||||
|
const {component, element, editor} = buildComponent({width: 200, height: 100, attach: false})
|
||||||
|
const fakeWindow = attachFakeWindow(component)
|
||||||
|
|
||||||
await setScrollTop(component, 50)
|
await setScrollTop(component, 50)
|
||||||
await setScrollLeft(component, 100)
|
await setScrollLeft(component, 100)
|
||||||
|
|
||||||
@ -949,6 +954,24 @@ describe('TextEditorComponent', () => {
|
|||||||
await component.getNextUpdatePromise()
|
await component.getNextUpdatePromise()
|
||||||
expect(overlayWrapper.classList.contains('b')).toBe(false)
|
expect(overlayWrapper.classList.contains('b')).toBe(false)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('does not attempt to avoid overflowing the window if `avoidOverflow` is false on the decoration', async () => {
|
||||||
|
const {component, element, editor} = buildComponent({width: 200, height: 100, attach: false})
|
||||||
|
const fakeWindow = attachFakeWindow(component)
|
||||||
|
const overlayElement = document.createElement('div')
|
||||||
|
overlayElement.style.width = '50px'
|
||||||
|
overlayElement.style.height = '50px'
|
||||||
|
overlayElement.style.margin = '3px'
|
||||||
|
overlayElement.style.backgroundColor = 'red'
|
||||||
|
const marker = editor.markScreenPosition([4, 25])
|
||||||
|
const decoration = editor.decorateMarker(marker, {type: 'overlay', item: overlayElement, avoidOverflow: false})
|
||||||
|
await component.getNextUpdatePromise()
|
||||||
|
|
||||||
|
await setScrollLeft(component, 30)
|
||||||
|
expect(overlayElement.getBoundingClientRect().right).toBeGreaterThan(fakeWindow.getBoundingClientRect().right)
|
||||||
|
await setScrollLeft(component, 280)
|
||||||
|
expect(overlayElement.getBoundingClientRect().left).toBeLessThan(fakeWindow.getBoundingClientRect().left)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('mouse input', () => {
|
describe('mouse input', () => {
|
||||||
|
@ -576,7 +576,10 @@ class TextEditorComponent {
|
|||||||
|
|
||||||
renderOverlayDecorations () {
|
renderOverlayDecorations () {
|
||||||
return this.decorationsToRender.overlays.map((overlayProps) =>
|
return this.decorationsToRender.overlays.map((overlayProps) =>
|
||||||
$(OverlayComponent, Object.assign({didResize: this.updateSync}, overlayProps))
|
$(OverlayComponent, Object.assign(
|
||||||
|
{key: overlayProps.element, didResize: this.updateSync},
|
||||||
|
overlayProps
|
||||||
|
))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -728,17 +731,14 @@ class TextEditorComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
addOverlayDecorationToRender (decoration, marker) {
|
addOverlayDecorationToRender (decoration, marker) {
|
||||||
const {class: className, item, position} = decoration
|
const {class: className, item, position, avoidOverflow} = decoration
|
||||||
const element = atom.views.getView(item)
|
const element = atom.views.getView(item)
|
||||||
const screenPosition = (position === 'tail')
|
const screenPosition = (position === 'tail')
|
||||||
? marker.getTailScreenPosition()
|
? marker.getTailScreenPosition()
|
||||||
: marker.getHeadScreenPosition()
|
: marker.getHeadScreenPosition()
|
||||||
|
|
||||||
this.requestHorizontalMeasurement(screenPosition.row, screenPosition.column)
|
this.requestHorizontalMeasurement(screenPosition.row, screenPosition.column)
|
||||||
this.decorationsToRender.overlays.push({
|
this.decorationsToRender.overlays.push({className, element, avoidOverflow, screenPosition})
|
||||||
key: element,
|
|
||||||
className, element, screenPosition
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updateAbsolutePositionedDecorations () {
|
updateAbsolutePositionedDecorations () {
|
||||||
@ -792,27 +792,28 @@ class TextEditorComponent {
|
|||||||
const contentClientRect = this.refs.content.getBoundingClientRect()
|
const contentClientRect = this.refs.content.getBoundingClientRect()
|
||||||
for (let i = 0; i < overlayCount; i++) {
|
for (let i = 0; i < overlayCount; i++) {
|
||||||
const decoration = this.decorationsToRender.overlays[i]
|
const decoration = this.decorationsToRender.overlays[i]
|
||||||
const {element, screenPosition} = decoration
|
const {element, screenPosition, avoidOverflow} = decoration
|
||||||
const {row, column} = screenPosition
|
const {row, column} = screenPosition
|
||||||
const computedStyle = window.getComputedStyle(element)
|
|
||||||
|
|
||||||
let wrapperTop = contentClientRect.top + this.pixelTopForRow(row) + this.getLineHeight()
|
let wrapperTop = contentClientRect.top + this.pixelTopForRow(row) + this.getLineHeight()
|
||||||
const elementHeight = element.offsetHeight
|
|
||||||
const elementTop = wrapperTop + parseInt(computedStyle.marginTop)
|
|
||||||
const elementBottom = elementTop + elementHeight
|
|
||||||
const flippedElementTop = wrapperTop - this.getLineHeight() - elementHeight - parseInt(computedStyle.marginBottom)
|
|
||||||
|
|
||||||
if (elementBottom > windowInnerHeight && flippedElementTop >= 0) {
|
|
||||||
wrapperTop -= (elementTop - flippedElementTop)
|
|
||||||
}
|
|
||||||
|
|
||||||
let wrapperLeft = contentClientRect.left + this.pixelLeftForRowAndColumn(row, column)
|
let wrapperLeft = contentClientRect.left + this.pixelLeftForRowAndColumn(row, column)
|
||||||
const elementLeft = wrapperLeft + parseInt(computedStyle.marginLeft)
|
|
||||||
const elementRight = elementLeft + element.offsetWidth
|
if (avoidOverflow !== false) {
|
||||||
if (elementLeft < 0) {
|
const computedStyle = window.getComputedStyle(element)
|
||||||
wrapperLeft -= elementLeft
|
const elementHeight = element.offsetHeight
|
||||||
} else if (elementRight > windowInnerWidth) {
|
const elementTop = wrapperTop + parseInt(computedStyle.marginTop)
|
||||||
wrapperLeft -= (elementRight - windowInnerWidth)
|
const elementBottom = elementTop + elementHeight
|
||||||
|
const flippedElementTop = wrapperTop - this.getLineHeight() - elementHeight - parseInt(computedStyle.marginBottom)
|
||||||
|
const elementLeft = wrapperLeft + parseInt(computedStyle.marginLeft)
|
||||||
|
const elementRight = elementLeft + element.offsetWidth
|
||||||
|
|
||||||
|
if (elementBottom > windowInnerHeight && flippedElementTop >= 0) {
|
||||||
|
wrapperTop -= (elementTop - flippedElementTop)
|
||||||
|
}
|
||||||
|
if (elementLeft < 0) {
|
||||||
|
wrapperLeft -= elementLeft
|
||||||
|
} else if (elementRight > windowInnerWidth) {
|
||||||
|
wrapperLeft -= (elementRight - windowInnerWidth)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
decoration.pixelTop = wrapperTop
|
decoration.pixelTop = wrapperTop
|
||||||
|
Loading…
Reference in New Issue
Block a user