Render lines inline instead of with separate components
Esse commit está contido em:
@@ -34,20 +34,98 @@ LinesComponent = React.createClass
|
||||
|
||||
lineComponents =
|
||||
for line, i in editor.linesForScreenRows(startRow, endRow - 1)
|
||||
screenRow = startRow + i
|
||||
LineComponent({key: line.id, line, screenRow, lineHeightInPixels, showIndentGuide, mini, invisibles})
|
||||
@renderLine(line, startRow + i)
|
||||
|
||||
if mouseWheelScreenRow? and not (startRow <= mouseWheelScreenRow < endRow)
|
||||
line = editor.lineForScreenRow(mouseWheelScreenRow)
|
||||
lineComponents.push(LineComponent({
|
||||
key: line.id, line, screenRow: mouseWheelScreenRow, screenRowOverride: endRow,
|
||||
lineHeightInPixels, showIndentGuide, mini, invisibles
|
||||
}))
|
||||
lineComponents.push(@renderLine(editor.lineForScreenRow(mouseWheelScreenRow), mouseWheelScreenRow, endRow))
|
||||
|
||||
lineComponents
|
||||
|
||||
renderLine: (line, screenRow, screenRowOverride) ->
|
||||
{lineHeightInPixels} = @props
|
||||
|
||||
style =
|
||||
position: "absolute"
|
||||
top: (screenRowOverride ? screenRow) * lineHeightInPixels
|
||||
|
||||
@lineInnerHTMLByLineId[line.id] ?= @buildLineInnerHTML(line)
|
||||
innerHTML = @lineInnerHTMLByLineId[line.id]
|
||||
|
||||
div key: line.id, className: "line", style: style, 'data-screen-row': screenRow, dangerouslySetInnerHTML: {__html: innerHTML}
|
||||
|
||||
buildLineInnerHTML: (line) ->
|
||||
if line.text is ""
|
||||
@buildEmptyLineInnerHTML(line)
|
||||
else
|
||||
@buildNonEmptyLineInnerHTML(line)
|
||||
|
||||
buildEmptyLineInnerHTML: (line) ->
|
||||
{showIndentGuide} = @props
|
||||
{indentLevel, tabLength} = line
|
||||
|
||||
if showIndentGuide and indentLevel > 0
|
||||
indentSpan = "<span class='indent-guide'>#{multiplyString(' ', tabLength)}</span>"
|
||||
multiplyString(indentSpan, indentLevel + 1)
|
||||
else
|
||||
" "
|
||||
|
||||
buildNonEmptyLineInnerHTML: (line) ->
|
||||
{invisibles, mini, showIndentGuide, invisibles} = @props
|
||||
{tokens, text} = line
|
||||
innerHTML = ""
|
||||
|
||||
scopeStack = []
|
||||
firstTrailingWhitespacePosition = text.search(/\s*$/)
|
||||
lineIsWhitespaceOnly = firstTrailingWhitespacePosition is 0
|
||||
for token in tokens
|
||||
innerHTML += @updateScopeStack(scopeStack, token.scopes)
|
||||
hasIndentGuide = not mini and showIndentGuide and token.hasLeadingWhitespace or (token.hasTrailingWhitespace and lineIsWhitespaceOnly)
|
||||
innerHTML += token.getValueAsHtml({invisibles, hasIndentGuide})
|
||||
|
||||
innerHTML += @popScope(scopeStack) while scopeStack.length > 0
|
||||
innerHTML += @buildEndOfLineHTML(line)
|
||||
innerHTML
|
||||
|
||||
buildEndOfLineHTML: (line) ->
|
||||
{invisibles, mini} = @props
|
||||
return '' if mini or line.isSoftWrapped()
|
||||
|
||||
html = ''
|
||||
if invisibles.cr? and line.lineEnding is '\r\n'
|
||||
html += "<span class='invisible-character'>#{invisibles.cr}</span>"
|
||||
if invisibles.eol?
|
||||
html += "<span class='invisible-character'>#{invisibles.eol}</span>"
|
||||
|
||||
html
|
||||
|
||||
updateScopeStack: (scopeStack, desiredScopes) ->
|
||||
html = ""
|
||||
|
||||
# Find a common prefix
|
||||
for scope, i in desiredScopes
|
||||
break unless scopeStack[i]?.scope is desiredScopes[i]
|
||||
|
||||
# Pop scopes until we're at the common prefx
|
||||
until scopeStack.length is i
|
||||
html += @popScope(scopeStack)
|
||||
|
||||
# Push onto common prefix until scopeStack equals desiredScopes
|
||||
for j in [i...desiredScopes.length]
|
||||
html += @pushScope(scopeStack, desiredScopes[j])
|
||||
|
||||
html
|
||||
|
||||
popScope: (scopeStack) ->
|
||||
scopeStack.pop()
|
||||
"</span>"
|
||||
|
||||
pushScope: (scopeStack, scope) ->
|
||||
scopeStack.push(scope)
|
||||
"<span class=\"#{scope.replace(/\.+/g, ' ')}\">"
|
||||
|
||||
componentWillMount: ->
|
||||
@measuredLines = new WeakSet
|
||||
@lineInnerHTMLByLineId = {}
|
||||
|
||||
componentDidMount: ->
|
||||
@measureLineHeightInPixelsAndCharWidth()
|
||||
@@ -66,6 +144,10 @@ LinesComponent = React.createClass
|
||||
|
||||
false
|
||||
|
||||
componentWillUpdate: (newProps) ->
|
||||
unless isEqualForProperties(newProps, @props, 'invisibles', 'showIndentGuide')
|
||||
@lineInnerHTMLByLineId = {}
|
||||
|
||||
componentDidUpdate: (prevProps) ->
|
||||
@measureLineHeightInPixelsAndCharWidthIfNeeded(prevProps)
|
||||
@clearScopedCharWidths() unless isEqualForProperties(prevProps, @props, 'fontSize', 'fontFamily')
|
||||
@@ -147,94 +229,3 @@ LinesComponent = React.createClass
|
||||
clearScopedCharWidths: ->
|
||||
@measuredLines.clear()
|
||||
@props.editor.clearScopedCharWidths()
|
||||
|
||||
LineComponent = React.createClass
|
||||
displayName: "LineComponent"
|
||||
|
||||
render: ->
|
||||
{screenRow, screenRowOverride, lineHeightInPixels} = @props
|
||||
|
||||
style =
|
||||
position: "absolute"
|
||||
top: (screenRowOverride ? screenRow) * lineHeightInPixels
|
||||
|
||||
div className: "line", style: style, 'data-screen-row': screenRow, dangerouslySetInnerHTML: {__html: @buildInnerHTML()}
|
||||
|
||||
shouldComponentUpdate: (newProps) ->
|
||||
not isEqualForProperties(newProps, @props, 'screenRow', 'lineHeightInPixels', 'showIndentGuide', 'invisibles')
|
||||
|
||||
componentWillUpdate: (newProps) ->
|
||||
unless isEqualForProperties(newProps, @props, 'showIndentGuide', 'invisibles')
|
||||
@innerHTML = null
|
||||
|
||||
buildInnerHTML: ->
|
||||
{line} = @props
|
||||
|
||||
if line.text is ""
|
||||
@innerHTML ?= @buildEmptyInnerHTML()
|
||||
else
|
||||
@innerHTML ?= @buildNonEmptyInnerHTML()
|
||||
|
||||
buildEmptyInnerHTML: ->
|
||||
{line, showIndentGuide} = @props
|
||||
{indentLevel, tabLength} = line
|
||||
|
||||
if showIndentGuide and indentLevel > 0
|
||||
indentSpan = "<span class='indent-guide'>#{multiplyString(' ', tabLength)}</span>"
|
||||
multiplyString(indentSpan, indentLevel + 1)
|
||||
else
|
||||
" "
|
||||
|
||||
buildNonEmptyInnerHTML: ->
|
||||
{line, invisibles, mini, showIndentGuide, invisibles} = @props
|
||||
{tokens, text} = line
|
||||
innerHTML = ""
|
||||
|
||||
scopeStack = []
|
||||
firstTrailingWhitespacePosition = text.search(/\s*$/)
|
||||
lineIsWhitespaceOnly = firstTrailingWhitespacePosition is 0
|
||||
for token in tokens
|
||||
innerHTML += @updateScopeStack(scopeStack, token.scopes)
|
||||
hasIndentGuide = not mini and showIndentGuide and token.hasLeadingWhitespace or (token.hasTrailingWhitespace and lineIsWhitespaceOnly)
|
||||
innerHTML += token.getValueAsHtml({invisibles, hasIndentGuide})
|
||||
|
||||
innerHTML += @popScope(scopeStack) while scopeStack.length > 0
|
||||
innerHTML += @buildEndOfLineHTML(line, invisibles)
|
||||
innerHTML
|
||||
|
||||
buildEndOfLineHTML: ->
|
||||
{line, invisibles, mini} = @props
|
||||
return '' if mini or line.isSoftWrapped()
|
||||
|
||||
html = ''
|
||||
if invisibles.cr? and line.lineEnding is '\r\n'
|
||||
html += "<span class='invisible-character'>#{invisibles.cr}</span>"
|
||||
if invisibles.eol?
|
||||
html += "<span class='invisible-character'>#{invisibles.eol}</span>"
|
||||
|
||||
html
|
||||
|
||||
updateScopeStack: (scopeStack, desiredScopes) ->
|
||||
html = ""
|
||||
|
||||
# Find a common prefix
|
||||
for scope, i in desiredScopes
|
||||
break unless scopeStack[i]?.scope is desiredScopes[i]
|
||||
|
||||
# Pop scopes until we're at the common prefx
|
||||
until scopeStack.length is i
|
||||
html += @popScope(scopeStack)
|
||||
|
||||
# Push onto common prefix until scopeStack equals desiredScopes
|
||||
for j in [i...desiredScopes.length]
|
||||
html += @pushScope(scopeStack, desiredScopes[j])
|
||||
|
||||
html
|
||||
|
||||
popScope: (scopeStack) ->
|
||||
scopeStack.pop()
|
||||
"</span>"
|
||||
|
||||
pushScope: (scopeStack, scope) ->
|
||||
scopeStack.push(scope)
|
||||
"<span class=\"#{scope.replace(/\.+/g, ' ')}\">"
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário