From d5d3cfc5a938e1669d14c08dd05f1e615e2546a0 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 23 Mar 2017 13:43:02 -0600 Subject: [PATCH] Adjust left position of scroll container when gutter container resizes --- spec/text-editor-component-spec.js | 26 +++++++++++++++ src/text-editor-component.js | 53 +++++++++++++++++++++++++++--- 2 files changed, 75 insertions(+), 4 deletions(-) diff --git a/spec/text-editor-component-spec.js b/spec/text-editor-component-spec.js index 14f2c14c9..d8d80ecec 100644 --- a/spec/text-editor-component-spec.js +++ b/spec/text-editor-component-spec.js @@ -990,6 +990,32 @@ describe('TextEditorComponent', () => { ]) }) + it('adjusts the left edge of the scroll container based on changes to the gutter container width', async () => { + const {component, element, editor} = buildComponent() + const {scrollContainer, gutterContainer} = component.refs + + expect(scrollContainer.getBoundingClientRect().left).toBe(gutterContainer.getBoundingClientRect().right) + const gutterA = editor.addGutter({name: 'a'}) + await component.getNextUpdatePromise() + expect(scrollContainer.getBoundingClientRect().left).toBe(gutterContainer.getBoundingClientRect().right) + + const gutterB = editor.addGutter({name: 'b'}) + await component.getNextUpdatePromise() + expect(scrollContainer.getBoundingClientRect().left).toBe(gutterContainer.getBoundingClientRect().right) + + gutterA.getElement().style.width = 100 + 'px' + await component.getNextUpdatePromise() + expect(scrollContainer.getBoundingClientRect().left).toBe(gutterContainer.getBoundingClientRect().right) + + gutterA.destroy() + await component.getNextUpdatePromise() + expect(scrollContainer.getBoundingClientRect().left).toBe(gutterContainer.getBoundingClientRect().right) + + gutterB.destroy() + await component.getNextUpdatePromise() + expect(scrollContainer.getBoundingClientRect().left).toBe(gutterContainer.getBoundingClientRect().right) + }) + it('allows the element of custom gutters to be retrieved before being rendered in the editor component', async () => { const {component, element, editor} = buildComponent() const [lineNumberGutter] = editor.getGutters() diff --git a/src/text-editor-component.js b/src/text-editor-component.js index 91889e7c1..29eef8f3e 100644 --- a/src/text-editor-component.js +++ b/src/text-editor-component.js @@ -74,6 +74,7 @@ class TextEditorComponent { this.lastKeydown = null this.lastKeydownBeforeKeypress = null this.accentedCharacterMenuIsOpen = false + this.remeasureGutterContainer = false this.guttersToRender = [] this.decorationsToRender = { lineNumbers: new Map(), @@ -88,10 +89,13 @@ class TextEditorComponent { cursors: [] } + etch.updateSync(this) + this.observeModel() getElementResizeDetector().listenTo(this.element, this.didResize.bind(this)) - - etch.updateSync(this) + if (this.refs.gutterContainer) { + getElementResizeDetector().listenTo(this.refs.gutterContainer, this.didResizeGutterContainer.bind(this)) + } } update (props) { @@ -146,6 +150,10 @@ class TextEditorComponent { measureContentDuringUpdateSync () { this.measureHorizontalPositions() this.updateAbsolutePositionedDecorations() + if (this.remeasureGutterContainer) { + this.measureGutterDimensions() + this.remeasureGutterContainer = false + } const wasHorizontalScrollbarVisible = this.isHorizontalScrollbarVisible() this.measureLongestLineWidth() if (this.pendingAutoscroll) { @@ -636,7 +644,19 @@ class TextEditorComponent { } queryGuttersToRender () { + const oldGuttersToRender = this.guttersToRender this.guttersToRender = this.props.model.getGutters() + + if (!oldGuttersToRender || oldGuttersToRender.length !== this.guttersToRender.length) { + this.remeasureGutterContainer = true + } else { + for (let i = 0, length = this.guttersToRender.length; i < length; i++) { + if (this.guttersToRender[i] !== oldGuttersToRender[i]) { + this.remeasureGutterContainer = true + break + } + } + } } queryDecorationsToRender () { @@ -1006,6 +1026,13 @@ class TextEditorComponent { } } + didResizeGutterContainer () { + console.log('didResizeGutterContainer'); + if (this.measureGutterDimensions()) { + this.scheduleUpdate() + } + } + didScrollDummyScrollbar () { let scrollTopChanged = false let scrollLeftChanged = false @@ -1436,11 +1463,29 @@ class TextEditorComponent { } measureGutterDimensions () { + let dimensionsChanged = false + + if (this.refs.gutterContainer) { + const gutterContainerWidth = this.refs.gutterContainer.offsetWidth + if (gutterContainerWidth !== this.measurements.gutterContainerWidth) { + dimensionsChanged = true + this.measurements.gutterContainerWidth = gutterContainerWidth + } + } else { + this.measurements.gutterContainerWidth = 0 + } + if (this.refs.lineNumberGutter) { - this.measurements.lineNumberGutterWidth = this.refs.lineNumberGutter.offsetWidth + const lineNumberGutterWidth = this.refs.lineNumberGutter.offsetWidth + if (lineNumberGutterWidth !== this.measurements.lineNumberGutterWidth) { + dimensionsChanged = true + this.measurements.lineNumberGutterWidth = this.refs.lineNumberGutter.offsetWidth + } } else { this.measurements.lineNumberGutterWidth = 0 } + + return dimensionsChanged } measureClientContainerDimensions () { @@ -1763,7 +1808,7 @@ class TextEditorComponent { } getGutterContainerWidth () { - return this.getLineNumberGutterWidth() + return this.measurements.gutterContainerWidth } getLineNumberGutterWidth () {