Fix cursor positioning around fold markers

This commit is contained in:
Antonio Scandurra
2017-04-20 17:16:08 +02:00
parent 1e6a1c61e7
commit 9d79b0189f
2 changed files with 41 additions and 7 deletions

View File

@@ -331,6 +331,20 @@ describe('TextEditorComponent', () => {
expect(element.querySelector('.cursor').offsetWidth).toBe(Math.round(component.getBaseCharacterWidth()))
})
it('positions and sizes cursors correctly when they are located next to a fold marker', async () => {
const {component, element, editor} = buildComponent()
editor.foldBufferRange([[0, 3], [0, 6]])
editor.setCursorScreenPosition([0, 3])
await component.getNextUpdatePromise()
const cursor = element.querySelector('.cursor')
verifyCursorPosition(component, element.querySelector('.cursor'), 0, 3)
editor.setCursorScreenPosition([0, 4])
await component.getNextUpdatePromise()
verifyCursorPosition(component, element.querySelector('.cursor'), 0, 4)
})
it('places the hidden input element at the location of the last cursor if it is visible', async () => {
const {component, element, editor} = buildComponent({height: 60, width: 120, rowsPerTile: 2})
const {hiddenInput} = component.refs
@@ -2893,7 +2907,7 @@ async function setEditorWidthInCharacters (component, widthInCharacters) {
function verifyCursorPosition (component, cursorNode, row, column) {
const rect = cursorNode.getBoundingClientRect()
expect(Math.round(rect.top)).toBe(clientTopForLine(component, row))
expect(Math.round(rect.left)).toBe(clientLeftForCharacter(component, row, column))
expect(Math.round(rect.left)).toBe(Math.round(clientLeftForCharacter(component, row, column)))
}
function clientTopForLine (component, row) {
@@ -2905,7 +2919,7 @@ function clientLeftForCharacter (component, row, column) {
let textNodeStartColumn = 0
for (const textNode of textNodes) {
const textNodeEndColumn = textNodeStartColumn + textNode.textContent.length
if (column <= textNodeEndColumn) {
if (column < textNodeEndColumn) {
const range = document.createRange()
range.setStart(textNode, column - textNodeStartColumn)
range.setEnd(textNode, column - textNodeStartColumn)
@@ -2913,6 +2927,12 @@ function clientLeftForCharacter (component, row, column) {
}
textNodeStartColumn = textNodeEndColumn
}
const lastTextNode = textNodes[textNodes.length - 1]
const range = document.createRange()
range.setStart(lastTextNode, 0)
range.setEnd(lastTextNode, lastTextNode.textContent.length)
return range.getBoundingClientRect().right
}
function clientPositionForCharacter (component, row, column) {

View File

@@ -1981,30 +1981,33 @@ class TextEditorComponent {
let lineNodeClientLeft = -1
let textNodeStartColumn = 0
let textNodesIndex = 0
let lastTextNodeRight = null
columnLoop: // eslint-disable-line no-labels
for (let columnsIndex = 0; columnsIndex < columnsToMeasure.length; columnsIndex++) {
const nextColumnToMeasure = columnsToMeasure[columnsIndex]
while (textNodesIndex < textNodes.length) {
const nextColumnToMeasure = columnsToMeasure[columnsIndex]
if (nextColumnToMeasure === 0) {
positions.set(0, 0)
continue columnLoop // eslint-disable-line no-labels
}
if (nextColumnToMeasure >= lineNode.textContent.length) {
}
if (positions.has(nextColumnToMeasure)) continue columnLoop // eslint-disable-line no-labels
const textNode = textNodes[textNodesIndex]
const textNodeEndColumn = textNodeStartColumn + textNode.textContent.length
if (nextColumnToMeasure <= textNodeEndColumn) {
if (nextColumnToMeasure < textNodeEndColumn) {
let clientPixelPosition
if (nextColumnToMeasure === textNodeStartColumn) {
clientPixelPosition = clientRectForRange(textNode, 0, 1).left
} else {
clientPixelPosition = clientRectForRange(textNode, 0, nextColumnToMeasure - textNodeStartColumn).right
}
if (lineNodeClientLeft === -1) lineNodeClientLeft = lineNode.getBoundingClientRect().left
if (lineNodeClientLeft === -1) {
lineNodeClientLeft = lineNode.getBoundingClientRect().left
}
positions.set(nextColumnToMeasure, Math.round(clientPixelPosition - lineNodeClientLeft))
continue columnLoop // eslint-disable-line no-labels
} else {
@@ -2012,6 +2015,17 @@ class TextEditorComponent {
textNodeStartColumn = textNodeEndColumn
}
}
if (lastTextNodeRight == null) {
const lastTextNode = textNodes[textNodes.length - 1]
lastTextNodeRight = clientRectForRange(lastTextNode, 0, lastTextNode.textContent.length).right
}
if (lineNodeClientLeft === -1) {
lineNodeClientLeft = lineNode.getBoundingClientRect().left
}
positions.set(nextColumnToMeasure, lastTextNodeRight - lineNodeClientLeft)
}
}