diff --git a/spec/editor-component-spec.coffee b/spec/editor-component-spec.coffee index 17e068541..cca28a6cb 100644 --- a/spec/editor-component-spec.coffee +++ b/spec/editor-component-spec.coffee @@ -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' diff --git a/src/editor-component.coffee b/src/editor-component.coffee index 57d25623a..52898665f 100644 --- a/src/editor-component.coffee +++ b/src/editor-component.coffee @@ -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 diff --git a/src/gutter-component.coffee b/src/gutter-component.coffee index ef3529e79..16903d5fd 100644 --- a/src/gutter-component.coffee +++ b/src/gutter-component.coffee @@ -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(' ', maxDigits - lineNumber.length) + {lineNumber, maxLineNumberDigits} = @props + if lineNumber.length < maxLineNumberDigits + padding = multiplyString(' ', maxLineNumberDigits - lineNumber.length) padding + lineNumber + @iconDivHTML else lineNumber + @iconDivHTML @@ -76,4 +84,4 @@ LineNumberComponent = React.createClass iconDivHTML: '
' shouldComponentUpdate: (newProps) -> - not isEqualForProperties(newProps, @props, 'lineHeight', 'screenRow', 'maxDigits') + not isEqualForProperties(newProps, @props, 'lineHeight', 'screenRow', 'maxLineNumberDigits')