Account for gutter width in scrollWidth of horizontal scrollbar

Because the scrollbar now spans the entire editor but the scrollable
area does not include the gutter, we need to add the current width of
the gutter to the scroll width of the horizontal scrollbar to allow
it to scroll to the end of the longest lines.
This commit is contained in:
Nathan Sobo 2014-04-24 19:07:17 -06:00
parent afb70d0a95
commit 527ada47f9
3 changed files with 34 additions and 12 deletions

View File

@ -580,6 +580,13 @@ describe "EditorComponent", ->
expect(verticalScrollbarNode.style.overflowX).toBe ''
expect(horizontalScrollbarNode.style.overflowY).toBe 'hidden'
it "accounts for the width of the gutter in the scrollWidth of the horizontal scrollbar", ->
gutterNode = node.querySelector('.gutter')
node.style.width = 10 * charWidth + 'px'
component.measureHeightAndWidth()
expect(horizontalScrollbarNode.scrollWidth).toBe gutterNode.offsetWidth + editor.getScrollWidth()
describe "when a mousewheel event occurs on the editor", ->
it "updates the horizontal or vertical scrollbar depending on which delta is greater (x or y)", ->
node.style.height = 4.5 * lineHeightInPixels + 'px'

View File

@ -20,10 +20,13 @@ EditorComponent = React.createClass
cursorsMoved: false
preservedRowRange: null
scrollingVertically: false
gutterWidth: 0
render: ->
{focused, fontSize, lineHeight, fontFamily, showIndentGuide} = @state
{editor, cursorBlinkPeriod, cursorBlinkResumeDelay} = @props
maxLineNumberDigits = editor.getScreenLineCount().toString().length
if @isMounted()
renderedRowRange = @getRenderedRowRange()
scrollHeight = editor.getScrollHeight()
@ -37,8 +40,9 @@ EditorComponent = React.createClass
div className: className, style: {fontSize, lineHeight, fontFamily}, tabIndex: -1,
GutterComponent {
editor, renderedRowRange, scrollTop, scrollHeight,
lineHeight: lineHeightInPixels, @pendingChanges
editor, renderedRowRange, maxLineNumberDigits, scrollTop, scrollHeight,
lineHeight: lineHeightInPixels, fontSize, fontFamily, @pendingChanges,
onWidthChanged: @onGutterWidthChanged
}
EditorScrollViewComponent {
@ -63,7 +67,7 @@ EditorComponent = React.createClass
orientation: 'horizontal'
onScroll: @onHorizontalScroll
scrollLeft: scrollLeft
scrollWidth: scrollWidth
scrollWidth: scrollWidth + @gutterWidth
scrollableInOppositeDirection: editor.verticallyScrollable() if @isMounted()
getRenderedRowRange: ->
@ -327,6 +331,9 @@ EditorComponent = React.createClass
onCursorsMoved: ->
@cursorsMoved = true
onGutterWidthChanged: (@gutterWidth) ->
@requestUpdate()
requestUpdate: ->
if @batchingUpdates
@updateRequested = true

View File

@ -8,18 +8,19 @@ GutterComponent = React.createClass
displayName: 'GutterComponent'
mixins: [SubscriberMixin]
lastMeasuredWidth: null
render: ->
div className: 'gutter',
@renderLineNumbers() if @isMounted()
renderLineNumbers: ->
{editor, renderedRowRange, scrollTop, scrollHeight} = @props
{editor, renderedRowRange, maxLineNumberDigits, scrollTop, scrollHeight} = @props
[startRow, endRow] = renderedRowRange
charWidth = editor.getDefaultCharWidth()
lineHeight = editor.getLineHeight()
maxDigits = editor.getScreenLineCount().toString().length
style =
width: charWidth * (maxDigits + 1.5)
width: charWidth * (maxLineNumberDigits + 1.5)
height: scrollHeight
WebkitTransform: "translate3d(0, #{-scrollTop}px, 0)"
@ -35,7 +36,7 @@ GutterComponent = React.createClass
key = tokenizedLines[i].id
screenRow = startRow + i
lineNumbers.push(LineNumberComponent({key, lineNumber, maxDigits, bufferRow, screenRow, lineHeight}))
lineNumbers.push(LineNumberComponent({key, lineNumber, maxLineNumberDigits, bufferRow, screenRow, lineHeight}))
lastBufferRow = bufferRow
div className: 'line-numbers', style: style,
@ -45,7 +46,7 @@ GutterComponent = React.createClass
# non-zero-delta change to the screen lines has occurred within the current
# visible row range.
shouldComponentUpdate: (newProps) ->
return true unless isEqualForProperties(newProps, @props, 'renderedRowRange', 'scrollTop', 'lineHeight')
return true unless isEqualForProperties(newProps, @props, 'renderedRowRange', 'scrollTop', 'lineHeight', 'fontSize')
{renderedRowRange, pendingChanges} = newProps
for change in pendingChanges when change.screenDelta > 0 or change.bufferDelta > 0
@ -53,6 +54,13 @@ GutterComponent = React.createClass
false
componentDidUpdate: (oldProps) ->
unless @lastMeasuredWidth? and isEqualForProperties(oldProps, @props, 'maxLineNumberDigits', 'fontSize', 'fontFamily')
width = @getDOMNode().offsetWidth
if width isnt @lastMeasuredWidth
@lastMeasuredWidth = width
@props.onWidthChanged(width)
LineNumberComponent = React.createClass
displayName: 'LineNumberComponent'
@ -66,9 +74,9 @@ LineNumberComponent = React.createClass
dangerouslySetInnerHTML: {__html: @buildInnerHTML()}
buildInnerHTML: ->
{lineNumber, maxDigits} = @props
if lineNumber.length < maxDigits
padding = multiplyString('&nbsp;', maxDigits - lineNumber.length)
{lineNumber, maxLineNumberDigits} = @props
if lineNumber.length < maxLineNumberDigits
padding = multiplyString('&nbsp;', maxLineNumberDigits - lineNumber.length)
padding + lineNumber + @iconDivHTML
else
lineNumber + @iconDivHTML
@ -76,4 +84,4 @@ LineNumberComponent = React.createClass
iconDivHTML: '<div class="icon-right"></div>'
shouldComponentUpdate: (newProps) ->
not isEqualForProperties(newProps, @props, 'lineHeight', 'screenRow', 'maxDigits')
not isEqualForProperties(newProps, @props, 'lineHeight', 'screenRow', 'maxLineNumberDigits')