mirror of
https://github.com/pulsar-edit/pulsar.git
synced 2024-09-20 15:37:46 +03:00
Fix gutter specs and update lines when digit counts change
This commit is contained in:
parent
fe82e3e30f
commit
e74dfe3438
@ -151,41 +151,39 @@ describe "EditorComponent", ->
|
||||
node.style.height = 4.5 * lineHeightInPixels + 'px'
|
||||
component.measureHeightAndWidth()
|
||||
|
||||
lineNumberNodes = node.querySelectorAll('.line-number')
|
||||
expect(lineNumberNodes.length).toBe 6
|
||||
expect(lineNumberNodes[0].textContent).toBe "#{nbsp}1"
|
||||
expect(lineNumberNodes[5].textContent).toBe "#{nbsp}6"
|
||||
expect(node.querySelectorAll('.line-number').length).toBe 6 + 2 + 1 # line overdraw margin below + dummy line number
|
||||
expect(component.lineNumberNodeForScreenRow(0).textContent).toBe "#{nbsp}1"
|
||||
expect(component.lineNumberNodeForScreenRow(5).textContent).toBe "#{nbsp}6"
|
||||
|
||||
verticalScrollbarNode.scrollTop = 2.5 * lineHeightInPixels
|
||||
verticalScrollbarNode.dispatchEvent(new UIEvent('scroll'))
|
||||
|
||||
lineNumberNodes = node.querySelectorAll('.line-number')
|
||||
expect(lineNumberNodes.length).toBe 6
|
||||
expect(node.querySelectorAll('.line-number').length).toBe 6 + 4 + 1 # line overdraw margin above/below + dummy line number
|
||||
|
||||
expect(lineNumberNodes[0].textContent).toBe "#{nbsp}3"
|
||||
expect(lineNumberNodes[0].style['-webkit-transform']).toBe "translate3d(0px, #{-.5 * lineHeightInPixels}px, 0px)"
|
||||
expect(lineNumberNodes[5].textContent).toBe "#{nbsp}8"
|
||||
expect(lineNumberNodes[5].style['-webkit-transform']).toBe "translate3d(0px, #{4.5 * lineHeightInPixels}px, 0px)"
|
||||
expect(component.lineNumberNodeForScreenRow(2).textContent).toBe "#{nbsp}3"
|
||||
expect(component.lineNumberNodeForScreenRow(2).offsetTop).toBe 2 * lineHeightInPixels
|
||||
return
|
||||
expect(component.lineNumberNodeForScreenRow(7).textContent).toBe "#{nbsp}8"
|
||||
expect(component.lineNumberNodeForScreenRow(7).offsetTop).toBe 7 * lineHeightInPixels
|
||||
|
||||
it "updates the translation of subsequent line numbers when lines are inserted or removed", ->
|
||||
editor.getBuffer().insert([0, 0], '\n\n')
|
||||
|
||||
lineNumberNodes = node.querySelectorAll('.line-number')
|
||||
expect(lineNumberNodes[0].style['-webkit-transform']).toBe "translate3d(0px, 0px, 0px)"
|
||||
expect(lineNumberNodes[1].style['-webkit-transform']).toBe "translate3d(0px, #{1 * lineHeightInPixels}px, 0px)"
|
||||
expect(lineNumberNodes[2].style['-webkit-transform']).toBe "translate3d(0px, #{2 * lineHeightInPixels}px, 0px)"
|
||||
expect(lineNumberNodes[3].style['-webkit-transform']).toBe "translate3d(0px, #{3 * lineHeightInPixels}px, 0px)"
|
||||
expect(lineNumberNodes[4].style['-webkit-transform']).toBe "translate3d(0px, #{4 * lineHeightInPixels}px, 0px)"
|
||||
expect(component.lineNumberNodeForScreenRow(0).offsetTop).toBe 0
|
||||
expect(component.lineNumberNodeForScreenRow(1).offsetTop).toBe 1 * lineHeightInPixels
|
||||
expect(component.lineNumberNodeForScreenRow(2).offsetTop).toBe 2 * lineHeightInPixels
|
||||
expect(component.lineNumberNodeForScreenRow(3).offsetTop).toBe 3 * lineHeightInPixels
|
||||
expect(component.lineNumberNodeForScreenRow(4).offsetTop).toBe 4 * lineHeightInPixels
|
||||
|
||||
editor.getBuffer().insert([0, 0], '\n\n')
|
||||
lineNumberNodes = node.querySelectorAll('.line-number')
|
||||
expect(lineNumberNodes[0].style['-webkit-transform']).toBe "translate3d(0px, 0px, 0px)"
|
||||
expect(lineNumberNodes[1].style['-webkit-transform']).toBe "translate3d(0px, #{1 * lineHeightInPixels}px, 0px)"
|
||||
expect(lineNumberNodes[2].style['-webkit-transform']).toBe "translate3d(0px, #{2 * lineHeightInPixels}px, 0px)"
|
||||
expect(lineNumberNodes[3].style['-webkit-transform']).toBe "translate3d(0px, #{3 * lineHeightInPixels}px, 0px)"
|
||||
expect(lineNumberNodes[4].style['-webkit-transform']).toBe "translate3d(0px, #{4 * lineHeightInPixels}px, 0px)"
|
||||
expect(lineNumberNodes[5].style['-webkit-transform']).toBe "translate3d(0px, #{5 * lineHeightInPixels}px, 0px)"
|
||||
expect(lineNumberNodes[6].style['-webkit-transform']).toBe "translate3d(0px, #{6 * lineHeightInPixels}px, 0px)"
|
||||
expect(component.lineNumberNodeForScreenRow(0).offsetTop).toBe 0
|
||||
expect(component.lineNumberNodeForScreenRow(1).offsetTop).toBe 1 * lineHeightInPixels
|
||||
expect(component.lineNumberNodeForScreenRow(2).offsetTop).toBe 2 * lineHeightInPixels
|
||||
expect(component.lineNumberNodeForScreenRow(3).offsetTop).toBe 3 * lineHeightInPixels
|
||||
expect(component.lineNumberNodeForScreenRow(4).offsetTop).toBe 4 * lineHeightInPixels
|
||||
expect(component.lineNumberNodeForScreenRow(5).offsetTop).toBe 5 * lineHeightInPixels
|
||||
expect(component.lineNumberNodeForScreenRow(6).offsetTop).toBe 6 * lineHeightInPixels
|
||||
|
||||
it "renders • characters for soft-wrapped lines", ->
|
||||
editor.setSoftWrap(true)
|
||||
@ -193,28 +191,24 @@ describe "EditorComponent", ->
|
||||
node.style.width = 30 * charWidth + 'px'
|
||||
component.measureHeightAndWidth()
|
||||
|
||||
lines = node.querySelectorAll('.line-number')
|
||||
expect(lines.length).toBe 6
|
||||
expect(lines[0].textContent).toBe "#{nbsp}1"
|
||||
expect(lines[1].textContent).toBe "#{nbsp}•"
|
||||
expect(lines[2].textContent).toBe "#{nbsp}2"
|
||||
expect(lines[3].textContent).toBe "#{nbsp}•"
|
||||
expect(lines[4].textContent).toBe "#{nbsp}3"
|
||||
expect(lines[5].textContent).toBe "#{nbsp}•"
|
||||
expect(node.querySelectorAll('.line-number').length).toBe 6 + lineOverdrawMargin + 1 # 1 dummy line node
|
||||
expect(component.lineNumberNodeForScreenRow(0).textContent).toBe "#{nbsp}1"
|
||||
expect(component.lineNumberNodeForScreenRow(1).textContent).toBe "#{nbsp}•"
|
||||
expect(component.lineNumberNodeForScreenRow(2).textContent).toBe "#{nbsp}2"
|
||||
expect(component.lineNumberNodeForScreenRow(3).textContent).toBe "#{nbsp}•"
|
||||
expect(component.lineNumberNodeForScreenRow(4).textContent).toBe "#{nbsp}3"
|
||||
expect(component.lineNumberNodeForScreenRow(5).textContent).toBe "#{nbsp}•"
|
||||
|
||||
it "pads line numbers to be right justified based on the maximum number of line number digits", ->
|
||||
it "pads line numbers to be right-justified based on the maximum number of line number digits", ->
|
||||
editor.getBuffer().setText([1..10].join('\n'))
|
||||
lineNumberNodes = toArray(node.querySelectorAll('.line-number'))
|
||||
|
||||
for node, i in lineNumberNodes[0..8]
|
||||
expect(node.textContent).toBe "#{nbsp}#{i + 1}"
|
||||
expect(lineNumberNodes[9].textContent).toBe '10'
|
||||
for screenRow in [0..8]
|
||||
expect(component.lineNumberNodeForScreenRow(screenRow).textContent).toBe "#{nbsp}#{screenRow + 1}"
|
||||
expect(component.lineNumberNodeForScreenRow(9).textContent).toBe "10"
|
||||
|
||||
# Removes padding when the max number of digits goes down
|
||||
editor.getBuffer().delete([[1, 0], [2, 0]])
|
||||
lineNumberNodes = toArray(node.querySelectorAll('.line-number'))
|
||||
for node, i in lineNumberNodes
|
||||
expect(node.textContent).toBe "#{i + 1}"
|
||||
for screenRow in [0..8]
|
||||
expect(component.lineNumberNodeForScreenRow(screenRow).textContent).toBe "#{screenRow + 1}"
|
||||
|
||||
describe "cursor rendering", ->
|
||||
it "renders the currently visible cursors, translated relative to the scroll position", ->
|
||||
|
@ -51,8 +51,8 @@ EditorComponent = React.createClass
|
||||
|
||||
div className: className, style: {fontSize, lineHeight, fontFamily}, tabIndex: -1,
|
||||
GutterComponent {
|
||||
editor, visibleRowRange, lineOverdrawMargin, maxLineNumberDigits, scrollTop,
|
||||
scrollHeight, lineHeight: lineHeightInPixels, fontSize, fontFamily,
|
||||
ref: 'gutter', editor, visibleRowRange, lineOverdrawMargin, maxLineNumberDigits,
|
||||
scrollTop, scrollHeight, lineHeight: lineHeightInPixels, fontSize, fontFamily,
|
||||
@pendingChanges, onWidthChanged: @onGutterWidthChanged
|
||||
}
|
||||
|
||||
@ -424,3 +424,5 @@ EditorComponent = React.createClass
|
||||
e.abortKeyBinding() unless @props.editor.consolidateSelections()
|
||||
|
||||
lineNodeForScreenRow: (screenRow) -> @refs.scrollView.lineNodeForScreenRow(screenRow)
|
||||
|
||||
lineNumberNodeForScreenRow: (screenRow) -> @refs.gutter.lineNumberNodeForScreenRow(screenRow)
|
||||
|
@ -22,7 +22,8 @@ GutterComponent = React.createClass
|
||||
|
||||
componentWillMount: ->
|
||||
@lineNumberNodesById = {}
|
||||
@lineNumberNodeTopPositions = {}
|
||||
@lineNumberIdsByScreenRow = {}
|
||||
@screenRowsByLineNumberId = {}
|
||||
|
||||
componentDidMount: ->
|
||||
@appendDummyLineNumber()
|
||||
@ -40,10 +41,18 @@ GutterComponent = React.createClass
|
||||
false
|
||||
|
||||
componentDidUpdate: (oldProps) ->
|
||||
@updateDummyLineNumber() if oldProps.maxLineNumberDigits isnt @props.maxLineNumberDigits
|
||||
unless oldProps.maxLineNumberDigits is @props.maxLineNumberDigits
|
||||
@updateDummyLineNumber()
|
||||
@removeLineNumberNodes()
|
||||
|
||||
@measureWidth() unless @lastMeasuredWidth? and isEqualForProperties(oldProps, @props, 'maxLineNumberDigits', 'fontSize', 'fontFamily')
|
||||
@clearScreenRowCaches() unless oldProps.lineHeight is @props.lineHeight
|
||||
@updateLineNumbers()
|
||||
|
||||
clearScreenRowCaches: ->
|
||||
@lineNumberIdsByScreenRow = {}
|
||||
@screenRowsByLineNumberId = {}
|
||||
|
||||
# This dummy line number element holds the gutter to the appropriate width,
|
||||
# since the real line numbers are absolutely positioned for performance reasons.
|
||||
appendDummyLineNumber: ->
|
||||
@ -56,11 +65,11 @@ GutterComponent = React.createClass
|
||||
WrapperDiv.innerHTML = @buildLineNumberInnerHTML(0, false, @props.maxLineNumberDigits)
|
||||
|
||||
updateLineNumbers: ->
|
||||
visibleLineNumberIds = @appendOrUpdateVisibleLineNumberNodes()
|
||||
@removeNonVisibleLineNumberNodes(visibleLineNumberIds)
|
||||
lineNumberIdsToPreserve = @appendOrUpdateVisibleLineNumberNodes()
|
||||
@removeLineNumberNodes(lineNumberIdsToPreserve)
|
||||
|
||||
appendOrUpdateVisibleLineNumberNodes: ->
|
||||
{editor, visibleRowRange, scrollTop, lineHeight, maxLineNumberDigits, lineOverdrawMargin} = @props
|
||||
{editor, visibleRowRange, scrollTop, maxLineNumberDigits, lineOverdrawMargin} = @props
|
||||
[startRow, endRow] = visibleRowRange
|
||||
startRow = Math.max(0, startRow - lineOverdrawMargin)
|
||||
endRow = Math.min(editor.getLineCount(), endRow + lineOverdrawMargin)
|
||||
@ -71,6 +80,8 @@ GutterComponent = React.createClass
|
||||
|
||||
wrapCount = 0
|
||||
for bufferRow, index in editor.bufferRowsForScreenRows(startRow, endRow - 1)
|
||||
screenRow = startRow + index
|
||||
|
||||
if bufferRow is lastBufferRow
|
||||
id = "#{bufferRow}-#{wrapCount++}"
|
||||
else
|
||||
@ -80,17 +91,16 @@ GutterComponent = React.createClass
|
||||
|
||||
visibleLineNumberIds.add(id)
|
||||
|
||||
screenRow = startRow + index
|
||||
top = screenRow * lineHeight
|
||||
|
||||
if @hasLineNumberNode(id)
|
||||
@updateLineNumberNode(id, top)
|
||||
@updateLineNumberNode(id, screenRow)
|
||||
else
|
||||
newLineNumberIds ?= []
|
||||
newLineNumbersHTML ?= ""
|
||||
newLineNumberIds.push(id)
|
||||
newLineNumbersHTML += @buildLineNumberHTML(bufferRow, wrapCount > 0, maxLineNumberDigits, top)
|
||||
@lineNumberNodeTopPositions[id] = top
|
||||
newLineNumbersHTML += @buildLineNumberHTML(bufferRow, wrapCount > 0, maxLineNumberDigits, screenRow)
|
||||
@screenRowsByLineNumberId[id] = screenRow
|
||||
@lineNumberIdsByScreenRow[screenRow] = id
|
||||
|
||||
if newLineNumberIds?
|
||||
WrapperDiv.innerHTML = newLineNumbersHTML
|
||||
@ -104,23 +114,26 @@ GutterComponent = React.createClass
|
||||
|
||||
visibleLineNumberIds
|
||||
|
||||
removeNonVisibleLineNumberNodes: (visibleLineNumberIds) ->
|
||||
removeLineNumberNodes: (lineNumberIdsToPreserve) ->
|
||||
node = @refs.lineNumbers.getDOMNode()
|
||||
for id, lineNumberNode of @lineNumberNodesById when not visibleLineNumberIds.has(id)
|
||||
delete @lineNumberNodesById[id]
|
||||
delete @lineNumberNodeTopPositions[id]
|
||||
for lineNumberId, lineNumberNode of @lineNumberNodesById when not lineNumberIdsToPreserve?.has(lineNumberId)
|
||||
delete @lineNumberNodesById[lineNumberId]
|
||||
screenRow = @screenRowsByLineNumberId[lineNumberId]
|
||||
delete @lineNumberIdsByScreenRow[screenRow] if @lineNumberIdsByScreenRow[screenRow] is lineNumberId
|
||||
delete @screenRowsByLineNumberId[lineNumberId]
|
||||
node.removeChild(lineNumberNode)
|
||||
|
||||
buildLineNumberHTML: (bufferRow, softWrapped, maxLineNumberDigits, top) ->
|
||||
innerHTML = @buildLineNumberInnerHTML(bufferRow, softWrapped, maxLineNumberDigits)
|
||||
if top?
|
||||
style = "position: absolute; top: #{top}px;"
|
||||
buildLineNumberHTML: (bufferRow, softWrapped, maxLineNumberDigits, screenRow) ->
|
||||
if screenRow?
|
||||
{lineHeight} = @props
|
||||
style = "position: absolute; top: #{screenRow * lineHeight}px;"
|
||||
else
|
||||
style = "visibility: hidden;"
|
||||
innerHTML = @buildLineNumberInnerHTML(bufferRow, softWrapped, maxLineNumberDigits)
|
||||
|
||||
"<div class=\"line-number editor-colors\" style=\"#{style}\">#{innerHTML}</div>"
|
||||
|
||||
buildLineNumberInnerHTML: (bufferRow, softWrapped, maxLineNumberDigits, top) ->
|
||||
buildLineNumberInnerHTML: (bufferRow, softWrapped, maxLineNumberDigits) ->
|
||||
if softWrapped
|
||||
lineNumber = "•"
|
||||
else
|
||||
@ -130,16 +143,18 @@ GutterComponent = React.createClass
|
||||
iconHTML = '<div class="icon-right"></div>'
|
||||
padding + lineNumber + iconHTML
|
||||
|
||||
updateLineNumberNode: (lineNumberId, top) ->
|
||||
unless @lineNumberNodeTopPositions[lineNumberId] is top
|
||||
@lineNumberNodesById[lineNumberId].style.top = top + 'px'
|
||||
@lineNumberNodeTopPositions[lineNumberId] = top
|
||||
updateLineNumberNode: (lineNumberId, screenRow) ->
|
||||
unless @screenRowsByLineNumberId[lineNumberId] is screenRow
|
||||
{lineHeight} = @props
|
||||
@lineNumberNodesById[lineNumberId].style.top = screenRow * lineHeight + 'px'
|
||||
@screenRowsByLineNumberId[lineNumberId] = screenRow
|
||||
@lineNumberIdsByScreenRow[screenRow] = lineNumberId
|
||||
|
||||
hasLineNumberNode: (lineNumberId) ->
|
||||
@lineNumberNodesById.hasOwnProperty(lineNumberId)
|
||||
|
||||
buildTranslate3d: (top) ->
|
||||
"translate3d(0px, #{top}px, 0px)"
|
||||
lineNumberNodeForScreenRow: (screenRow) ->
|
||||
@lineNumberNodesById[@lineNumberIdsByScreenRow[screenRow]]
|
||||
|
||||
measureWidth: ->
|
||||
lineNumberNode = @refs.lineNumbers.getDOMNode().firstChild
|
||||
|
Loading…
Reference in New Issue
Block a user