From 9d79b0189fb4c31df647fd4eb58d5552ee483e17 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 20 Apr 2017 17:16:08 +0200 Subject: [PATCH] Fix cursor positioning around fold markers --- spec/text-editor-component-spec.js | 24 ++++++++++++++++++++++-- src/text-editor-component.js | 24 +++++++++++++++++++----- 2 files changed, 41 insertions(+), 7 deletions(-) diff --git a/spec/text-editor-component-spec.js b/spec/text-editor-component-spec.js index 1f2f05d6c..9bb8bd646 100644 --- a/spec/text-editor-component-spec.js +++ b/spec/text-editor-component-spec.js @@ -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) { diff --git a/src/text-editor-component.js b/src/text-editor-component.js index bdcc88b9b..5f66f5f51 100644 --- a/src/text-editor-component.js +++ b/src/text-editor-component.js @@ -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) } }