2014-04-14 20:11:11 +04:00
|
|
|
React = require 'react'
|
|
|
|
{div} = require 'reactionary'
|
2014-04-15 23:56:58 +04:00
|
|
|
{isEqual, multiplyString} = require 'underscore-plus'
|
|
|
|
SubscriberMixin = require './subscriber-mixin'
|
2014-04-14 20:11:11 +04:00
|
|
|
|
|
|
|
module.exports =
|
|
|
|
GutterComponent = React.createClass
|
2014-04-15 20:39:47 +04:00
|
|
|
displayName: 'GutterComponent'
|
2014-04-15 23:56:58 +04:00
|
|
|
mixins: [SubscriberMixin]
|
2014-04-15 20:39:47 +04:00
|
|
|
|
2014-04-14 20:11:11 +04:00
|
|
|
render: ->
|
|
|
|
{editor, visibleRowRange} = @props
|
|
|
|
[startRow, endRow] = visibleRowRange
|
|
|
|
lineHeightInPixels = editor.getLineHeight()
|
|
|
|
precedingHeight = startRow * lineHeightInPixels
|
|
|
|
followingHeight = (editor.getScreenLineCount() - endRow) * lineHeightInPixels
|
|
|
|
maxDigits = editor.getLastBufferRow().toString().length
|
|
|
|
style =
|
|
|
|
height: editor.getScrollHeight()
|
|
|
|
WebkitTransform: "translateY(#{-editor.getScrollTop()}px)"
|
|
|
|
wrapCount = 0
|
|
|
|
|
2014-04-15 04:07:55 +04:00
|
|
|
lineNumbers = []
|
|
|
|
for bufferRow in @props.editor.bufferRowsForScreenRows(startRow, endRow - 1)
|
|
|
|
if bufferRow is lastBufferRow
|
|
|
|
lineNumber = '•'
|
|
|
|
key = "#{bufferRow}-#{++wrapCount}"
|
|
|
|
else
|
|
|
|
lastBufferRow = bufferRow
|
|
|
|
wrapCount = 0
|
|
|
|
lineNumber = (bufferRow + 1).toString()
|
|
|
|
key = bufferRow.toString()
|
|
|
|
|
|
|
|
lineNumbers.push(LineNumberComponent({lineNumber, maxDigits, bufferRow, key}))
|
|
|
|
lastBufferRow = bufferRow
|
|
|
|
|
2014-04-14 20:11:11 +04:00
|
|
|
div className: 'gutter',
|
|
|
|
div className: 'line-numbers', style: style, [
|
|
|
|
div className: 'spacer', key: 'top-spacer', style: {height: precedingHeight}
|
2014-04-15 04:07:55 +04:00
|
|
|
lineNumbers...
|
2014-04-14 20:11:11 +04:00
|
|
|
div className: 'spacer', key: 'bottom-spacer', style: {height: followingHeight}
|
|
|
|
]
|
|
|
|
|
2014-04-15 23:56:58 +04:00
|
|
|
componentDidMount: ->
|
|
|
|
@pendingChanges = []
|
|
|
|
@subscribe @props.editor, 'screen-lines-changed', @onScreenLinesChanged
|
|
|
|
|
|
|
|
componentWillUnmount: ->
|
|
|
|
@unsubscribe()
|
|
|
|
|
|
|
|
# Only update the gutter if the visible row range has changed or if a
|
|
|
|
# non-zero-delta change to the screen lines has occurred within the current
|
|
|
|
# visible row range.
|
|
|
|
shouldComponentUpdate: (newProps) ->
|
|
|
|
{visibleRowRange} = @props
|
|
|
|
|
|
|
|
return true unless isEqual(newProps.visibleRowRange, visibleRowRange)
|
|
|
|
|
|
|
|
for change in @pendingChanges when change.screenDelta > 0 or change.bufferDelta > 0
|
|
|
|
return true unless change.end <= visibleRowRange.start or visibleRowRange.end <= change.start
|
|
|
|
|
|
|
|
false
|
|
|
|
|
|
|
|
componentDidUpdate: ->
|
|
|
|
@pendingChanges.length = 0
|
|
|
|
|
|
|
|
onScreenLinesChanged: (change) ->
|
|
|
|
@pendingChanges.push(change)
|
|
|
|
|
2014-04-14 20:11:11 +04:00
|
|
|
LineNumberComponent = React.createClass
|
|
|
|
render: ->
|
|
|
|
{bufferRow} = @props
|
|
|
|
div
|
|
|
|
className: "line-number line-number-#{bufferRow}"
|
|
|
|
'data-buffer-row': bufferRow
|
|
|
|
dangerouslySetInnerHTML: {__html: @buildInnerHTML()}
|
|
|
|
|
|
|
|
buildInnerHTML: ->
|
|
|
|
{lineNumber, maxDigits} = @props
|
|
|
|
if lineNumber.length < maxDigits
|
|
|
|
padding = multiplyString(' ', maxDigits - lineNumber.length)
|
|
|
|
padding + lineNumber + @iconDivHTML
|
|
|
|
else
|
|
|
|
lineNumber + @iconDivHTML
|
|
|
|
|
|
|
|
iconDivHTML: '<div class="icon-right"></div>'
|
2014-04-15 04:07:43 +04:00
|
|
|
|
|
|
|
shouldComponentUpdate: -> false
|