mirror of
https://github.com/atom/atom.git
synced 2026-02-14 00:25:08 -05:00
Measure DOM dimensions before rendering elements that depend on them
This commit breaks the initial render of the editor component into two stages. The first stage just renders the shell of the editor so the height, width, line height, and default character width can be measured. Nothing that depends on these values is rendered on the first render pass. Once the editor component is mounted, all these values are measured and we force another update, which fills in the lines, line numbers, selections, etc. We also refrain from assigning an explicit height and width on the model if these values aren't explicitly styled in the DOM, and just assume the editor will stretch to accommodate its contents.
This commit is contained in:
@@ -11,26 +11,28 @@ LinesComponent = React.createClass
|
||||
displayName: 'LinesComponent'
|
||||
|
||||
render: ->
|
||||
{editor, visibleRowRange, preservedScreenRow, showIndentGuide} = @props
|
||||
if @isMounted()
|
||||
{editor, visibleRowRange, preservedScreenRow, showIndentGuide} = @props
|
||||
[startRow, endRow] = visibleRowRange
|
||||
|
||||
[startRow, endRow] = visibleRowRange
|
||||
lineHeightInPixels = editor.getLineHeight()
|
||||
paddingTop = startRow * lineHeightInPixels
|
||||
paddingBottom = (editor.getScreenLineCount() - endRow) * lineHeightInPixels
|
||||
style =
|
||||
paddingTop: startRow * editor.getLineHeight()
|
||||
paddingBottom: (editor.getScreenLineCount() - endRow) * editor.getLineHeight()
|
||||
|
||||
lines =
|
||||
for tokenizedLine, i in editor.linesForScreenRows(startRow, endRow - 1)
|
||||
LineComponent({key: tokenizedLine.id, tokenizedLine, showIndentGuide, screenRow: startRow + i})
|
||||
lines =
|
||||
for tokenizedLine, i in editor.linesForScreenRows(startRow, endRow - 1)
|
||||
LineComponent({key: tokenizedLine.id, tokenizedLine, showIndentGuide, screenRow: startRow + i})
|
||||
|
||||
if preservedScreenRow? and (preservedScreenRow < startRow or endRow <= preservedScreenRow)
|
||||
lines.push(LineComponent({key: editor.lineForScreenRow(preservedScreenRow).id, preserved: true}))
|
||||
if preservedScreenRow? and (preservedScreenRow < startRow or endRow <= preservedScreenRow)
|
||||
lines.push(LineComponent({key: editor.lineForScreenRow(preservedScreenRow).id, preserved: true}))
|
||||
|
||||
div className: 'lines', ref: 'lines', style: {paddingTop, paddingBottom},
|
||||
lines
|
||||
div {className: 'lines', style}, lines
|
||||
|
||||
componentWillMount: ->
|
||||
@measuredLines = new WeakSet
|
||||
|
||||
componentDidMount: ->
|
||||
@measuredLines = new WeakSet
|
||||
@updateModelDimensions()
|
||||
@measureLineHeightAndCharWidth()
|
||||
|
||||
shouldComponentUpdate: (newProps) ->
|
||||
return true unless isEqualForProperties(newProps, @props, 'visibleRowRange', 'preservedScreenRow', 'fontSize', 'fontFamily', 'lineHeight', 'showIndentGuide')
|
||||
@@ -42,31 +44,28 @@ LinesComponent = React.createClass
|
||||
false
|
||||
|
||||
componentDidUpdate: (prevProps) ->
|
||||
@updateModelDimensions() unless isEqualForProperties(prevProps, @props, 'fontSize', 'fontFamily', 'lineHeight')
|
||||
@measureLineHeightAndCharWidth() unless isEqualForProperties(prevProps, @props, 'fontSize', 'fontFamily', 'lineHeight')
|
||||
@clearScopedCharWidths() unless isEqualForProperties(prevProps, @props, 'fontSize', 'fontFamily')
|
||||
@measureCharactersInNewLines() unless @props.preservedScreenRow?
|
||||
|
||||
updateModelDimensions: ->
|
||||
{editor} = @props
|
||||
{lineHeightInPixels, charWidth} = @measureLineDimensions()
|
||||
editor.setLineHeight(lineHeightInPixels)
|
||||
editor.setDefaultCharWidth(charWidth)
|
||||
|
||||
measureLineDimensions: ->
|
||||
linesNode = @refs.lines.getDOMNode()
|
||||
linesNode.appendChild(DummyLineNode)
|
||||
lineHeightInPixels = DummyLineNode.getBoundingClientRect().height
|
||||
measureLineHeightAndCharWidth: ->
|
||||
node = @getDOMNode()
|
||||
node.appendChild(DummyLineNode)
|
||||
lineHeight = DummyLineNode.getBoundingClientRect().height
|
||||
charWidth = DummyLineNode.firstChild.getBoundingClientRect().width
|
||||
linesNode.removeChild(DummyLineNode)
|
||||
{lineHeightInPixels, charWidth}
|
||||
node.removeChild(DummyLineNode)
|
||||
|
||||
{editor} = @props
|
||||
editor.setLineHeight(lineHeight)
|
||||
editor.setDefaultCharWidth(charWidth)
|
||||
|
||||
measureCharactersInNewLines: ->
|
||||
[visibleStartRow, visibleEndRow] = @props.visibleRowRange
|
||||
linesNode = @refs.lines.getDOMNode()
|
||||
node = @getDOMNode()
|
||||
|
||||
for tokenizedLine, i in @props.editor.linesForScreenRows(visibleStartRow, visibleEndRow - 1)
|
||||
unless @measuredLines.has(tokenizedLine)
|
||||
lineNode = linesNode.children[i]
|
||||
lineNode = node.children[i]
|
||||
@measureCharactersInLine(tokenizedLine, lineNode)
|
||||
|
||||
measureCharactersInLine: (tokenizedLine, lineNode) ->
|
||||
|
||||
Reference in New Issue
Block a user