Align line number nodes with line nodes

This commit is contained in:
Antonio Scandurra
2017-04-10 15:45:45 +02:00
parent 7474b4b678
commit b264d4764a
2 changed files with 111 additions and 47 deletions

View File

@@ -1171,12 +1171,11 @@ describe('TextEditorComponent', () => {
editor.getScreenLineCount() * component.getLineHeight() +
getElementHeight(item1) + getElementHeight(item2)
)
expect(tileNodeForScreenRow(component, 0).offsetHeight).toBe(
3 * component.getLineHeight() + getElementHeight(item1) + getElementHeight(item2)
)
expect(tileNodeForScreenRow(component, 3).offsetHeight).toBe(
3 * component.getLineHeight()
)
assertTilesAreSizedAndPositionedCorrectly(component, [
{tileStartRow: 0, height: 3 * component.getLineHeight() + getElementHeight(item1) + getElementHeight(item2)},
{tileStartRow: 3, height: 3 * component.getLineHeight()}
])
assertLinesAreAlignedWithLineNumbers(component)
expect(element.querySelectorAll('.line').length).toBe(6)
expect(item1.previousSibling).toBeNull()
expect(item1.nextSibling).toBe(lineNodeForScreenRow(component, 0))
@@ -1196,12 +1195,11 @@ describe('TextEditorComponent', () => {
getElementHeight(item1) + getElementHeight(item2) + getElementHeight(item3) +
getElementHeight(item4) + getElementHeight(item5) + getElementHeight(item6)
)
expect(tileNodeForScreenRow(component, 0).offsetHeight).toBe(
3 * component.getLineHeight() + getElementHeight(item1) + getElementHeight(item2)
)
expect(tileNodeForScreenRow(component, 3).offsetHeight).toBe(
3 * component.getLineHeight() + getElementHeight(item3)
)
assertTilesAreSizedAndPositionedCorrectly(component, [
{tileStartRow: 0, height: 3 * component.getLineHeight() + getElementHeight(item1) + getElementHeight(item2)},
{tileStartRow: 3, height: 3 * component.getLineHeight() + getElementHeight(item3)}
])
assertLinesAreAlignedWithLineNumbers(component)
expect(element.querySelectorAll('.line').length).toBe(6)
expect(item1.previousSibling).toBeNull()
expect(item1.nextSibling).toBe(lineNodeForScreenRow(component, 0))
@@ -1222,12 +1220,11 @@ describe('TextEditorComponent', () => {
getElementHeight(item1) + getElementHeight(item2) + getElementHeight(item3) +
getElementHeight(item4) + getElementHeight(item5) + getElementHeight(item6)
)
expect(tileNodeForScreenRow(component, 3).offsetHeight).toBe(
3 * component.getLineHeight() + getElementHeight(item3)
)
expect(tileNodeForScreenRow(component, 6).offsetHeight).toBe(
3 * component.getLineHeight() + getElementHeight(item4) + getElementHeight(item5)
)
assertTilesAreSizedAndPositionedCorrectly(component, [
{tileStartRow: 3, height: 3 * component.getLineHeight() + getElementHeight(item3)},
{tileStartRow: 6, height: 3 * component.getLineHeight() + getElementHeight(item4) + getElementHeight(item5)}
])
assertLinesAreAlignedWithLineNumbers(component)
expect(element.querySelectorAll('.line').length).toBe(6)
expect(element.contains(item1)).toBe(false)
expect(element.contains(item2)).toBe(false)
@@ -1250,12 +1247,11 @@ describe('TextEditorComponent', () => {
getElementHeight(item2) + getElementHeight(item3) +
getElementHeight(item4) + getElementHeight(item5) + getElementHeight(item6)
)
expect(tileNodeForScreenRow(component, 0).offsetHeight).toBe(
3 * component.getLineHeight() + getElementHeight(item2)
)
expect(tileNodeForScreenRow(component, 3).offsetHeight).toBe(
3 * component.getLineHeight() + getElementHeight(item3)
)
assertTilesAreSizedAndPositionedCorrectly(component, [
{tileStartRow: 0, height: 3 * component.getLineHeight() + getElementHeight(item2)},
{tileStartRow: 3, height: 3 * component.getLineHeight() + getElementHeight(item3)}
])
assertLinesAreAlignedWithLineNumbers(component)
expect(element.querySelectorAll('.line').length).toBe(6)
expect(element.contains(item1)).toBe(false)
expect(item2.previousSibling).toBe(lineNodeForScreenRow(component, 1))
@@ -1277,12 +1273,11 @@ describe('TextEditorComponent', () => {
getElementHeight(item2) + getElementHeight(item3) +
getElementHeight(item4) + getElementHeight(item5) + getElementHeight(item6)
)
expect(tileNodeForScreenRow(component, 0).offsetHeight).toBe(
3 * component.getLineHeight() + getElementHeight(item2) + getElementHeight(item3)
)
expect(tileNodeForScreenRow(component, 3).offsetHeight).toBe(
3 * component.getLineHeight()
)
assertTilesAreSizedAndPositionedCorrectly(component, [
{tileStartRow: 0, height: 3 * component.getLineHeight() + getElementHeight(item2) + getElementHeight(item3)},
{tileStartRow: 3, height: 3 * component.getLineHeight()}
])
assertLinesAreAlignedWithLineNumbers(component)
expect(element.querySelectorAll('.line').length).toBe(6)
expect(element.contains(item1)).toBe(false)
expect(item2.previousSibling).toBe(lineNodeForScreenRow(component, 0))
@@ -1303,12 +1298,11 @@ describe('TextEditorComponent', () => {
getElementHeight(item2) + getElementHeight(item3) +
getElementHeight(item4) + getElementHeight(item5) + getElementHeight(item6)
)
expect(tileNodeForScreenRow(component, 0).offsetHeight).toBe(
3 * component.getLineHeight() + getElementHeight(item3)
)
expect(tileNodeForScreenRow(component, 3).offsetHeight).toBe(
3 * component.getLineHeight() + getElementHeight(item2)
)
assertTilesAreSizedAndPositionedCorrectly(component, [
{tileStartRow: 0, height: 3 * component.getLineHeight() + getElementHeight(item3)},
{tileStartRow: 3, height: 3 * component.getLineHeight() + getElementHeight(item2)}
])
assertLinesAreAlignedWithLineNumbers(component)
expect(element.querySelectorAll('.line').length).toBe(6)
expect(element.contains(item1)).toBe(false)
expect(item2.previousSibling).toBeNull()
@@ -1329,12 +1323,11 @@ describe('TextEditorComponent', () => {
getElementHeight(item2) + getElementHeight(item3) +
getElementHeight(item4) + getElementHeight(item5) + getElementHeight(item6)
)
expect(tileNodeForScreenRow(component, 0).offsetHeight).toBe(
3 * component.getLineHeight() + getElementHeight(item2) + getElementHeight(item3)
)
expect(tileNodeForScreenRow(component, 3).offsetHeight).toBe(
3 * component.getLineHeight()
)
assertTilesAreSizedAndPositionedCorrectly(component, [
{tileStartRow: 0, height: 3 * component.getLineHeight() + getElementHeight(item2) + getElementHeight(item3)},
{tileStartRow: 3, height: 3 * component.getLineHeight()}
])
assertLinesAreAlignedWithLineNumbers(component)
expect(element.querySelectorAll('.line').length).toBe(6)
expect(element.contains(item1)).toBe(false)
expect(item2.previousSibling).toBe(lineNodeForScreenRow(component, 0))
@@ -1355,6 +1348,33 @@ describe('TextEditorComponent', () => {
const decoration = editor.decorateMarker(marker, {type: 'block', item, position})
return {item, decoration}
}
function assertTilesAreSizedAndPositionedCorrectly (component, tiles) {
let top = 0
for (let tile of tiles) {
const linesTileElement = lineNodeForScreenRow(component, tile.tileStartRow).parentElement
const linesTileBoundingRect = linesTileElement.getBoundingClientRect()
expect(linesTileBoundingRect.height).toBe(tile.height)
expect(linesTileBoundingRect.top).toBe(top)
const lineNumbersTileElement = lineNumberNodeForScreenRow(component, tile.tileStartRow).parentElement
const lineNumbersTileBoundingRect = lineNumbersTileElement.getBoundingClientRect()
expect(lineNumbersTileBoundingRect.height).toBe(tile.height)
expect(lineNumbersTileBoundingRect.top).toBe(top)
top += tile.height
}
}
function assertLinesAreAlignedWithLineNumbers (component) {
const startRow = component.getRenderedStartRow()
const endRow = component.getRenderedEndRow()
for (let row = startRow; row < endRow; row++) {
const lineNode = lineNodeForScreenRow(component, row)
const lineNumberNode = lineNumberNodeForScreenRow(component, row)
expect(lineNumberNode.getBoundingClientRect().top).toBe(lineNode.getBoundingClientRect().top)
}
}
})
describe('mouse input', () => {
@@ -2125,10 +2145,6 @@ function lineNumberNodeForScreenRow (component, row) {
return gutterElement.children[tileIndex + 1].children[row - tileStartRow]
}
function tileNodeForScreenRow (component, row) {
return lineNodeForScreenRow(component, row).parentElement
}
function lineNodeForScreenRow (component, row) {
const renderedScreenLine = component.renderedScreenLineForRow(row)
return component.lineNodesByScreenLineId.get(renderedScreenLine.id)

View File

@@ -383,6 +383,7 @@ class TextEditorComponent {
numbers: numbers,
foldableFlags: foldableFlags,
decorations: this.decorationsToRender.lineNumbers,
blockDecorations: this.decorationsToRender.blocks,
height: this.getScrollHeight(),
width: this.getLineNumberGutterWidth(),
lineHeight: this.getLineHeight(),
@@ -2335,7 +2336,17 @@ class LineNumberGutterComponent {
if (number === -1) number = '•'
number = NBSP_CHARACTER.repeat(maxDigits - number.length) + number
tileChildren[row - tileStartRow] = $.div({key, className},
let lineNumberProps = {key, className}
if (row === 0 || i > 0) {
let currentRowTop = parentComponent.pixelPositionAfterBlocksForRow(row)
let previousRowBottom = parentComponent.pixelPositionAfterBlocksForRow(row - 1) + lineHeight
if (currentRowTop > previousRowBottom) {
lineNumberProps.style = {marginTop: (currentRowTop - previousRowBottom) + 'px'}
}
}
tileChildren[row - tileStartRow] = $.div(lineNumberProps,
number,
$.div({className: 'icon-right'})
)
@@ -2394,6 +2405,43 @@ class LineNumberGutterComponent {
if (!arraysEqual(oldProps.numbers, newProps.numbers)) return true
if (!arraysEqual(oldProps.foldableFlags, newProps.foldableFlags)) return true
if (!arraysEqual(oldProps.decorations, newProps.decorations)) return true
let oldTileStartRow = oldProps.startRow
let newTileStartRow = newProps.startRow
while (oldTileStartRow < oldProps.endRow || newTileStartRow < newProps.endRow) {
let oldTileBlockDecorations = oldProps.blockDecorations.get(oldTileStartRow)
let newTileBlockDecorations = newProps.blockDecorations.get(newTileStartRow)
if (oldTileBlockDecorations && newTileBlockDecorations) {
if (oldTileBlockDecorations.size !== newTileBlockDecorations.size) return true
let blockDecorationsChanged = false
oldTileBlockDecorations.forEach((oldDecorations, screenLineId) => {
if (!blockDecorationsChanged) {
const newDecorations = newTileBlockDecorations.get(screenLineId)
blockDecorationsChanged = (newDecorations == null || !arraysEqual(oldDecorations, newDecorations))
}
})
if (blockDecorationsChanged) return true
newTileBlockDecorations.forEach((newDecorations, screenLineId) => {
if (!blockDecorationsChanged) {
const oldDecorations = oldTileBlockDecorations.get(screenLineId)
blockDecorationsChanged = (oldDecorations == null)
}
})
if (blockDecorationsChanged) return true
} else if (oldTileBlockDecorations) {
return true
} else if (newTileBlockDecorations) {
return true
}
oldTileStartRow += oldProps.rowsPerTile
newTileStartRow += newProps.rowsPerTile
}
return false
}