mirror of
https://github.com/atom/atom.git
synced 2026-01-25 06:48:28 -05:00
Merge pull request #12448 from atom/as-editor-auto-width
Introduce autoWidth for TextEditors
This commit is contained in:
@@ -4368,6 +4368,33 @@ describe('TextEditorComponent', function () {
|
||||
})
|
||||
})
|
||||
|
||||
describe('width', function () {
|
||||
it('sizes the editor element according to the content width when auto width is true, or according to the container width otherwise', function () {
|
||||
contentNode.style.width = '600px'
|
||||
component.measureDimensions()
|
||||
editor.setText("abcdefghi")
|
||||
runAnimationFrames()
|
||||
expect(wrapperNode.offsetWidth).toBe(contentNode.offsetWidth)
|
||||
|
||||
editor.update({autoWidth: true})
|
||||
runAnimationFrames()
|
||||
const editorWidth1 = wrapperNode.offsetWidth
|
||||
expect(editorWidth1).toBeGreaterThan(0)
|
||||
expect(editorWidth1).toBeLessThan(contentNode.offsetWidth)
|
||||
|
||||
editor.setText("abcdefghijkl")
|
||||
editor.update({autoWidth: true})
|
||||
runAnimationFrames()
|
||||
const editorWidth2 = wrapperNode.offsetWidth
|
||||
expect(editorWidth2).toBeGreaterThan(editorWidth1)
|
||||
expect(editorWidth2).toBeLessThan(contentNode.offsetWidth)
|
||||
|
||||
editor.update({autoWidth: false})
|
||||
runAnimationFrames()
|
||||
expect(wrapperNode.offsetWidth).toBe(contentNode.offsetWidth)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when the "mini" property is true', function () {
|
||||
beforeEach(function () {
|
||||
editor.setMini(true)
|
||||
|
||||
@@ -425,6 +425,13 @@ describe "TextEditorPresenter", ->
|
||||
editor.setMini(false)
|
||||
expect(getState(presenter).horizontalScrollbar.visible).toBe true
|
||||
|
||||
it "is false when `editor.autoWidth` is true", ->
|
||||
editor.update({autoWidth: true})
|
||||
presenter = buildPresenter(explicitHeight: 10, contentFrameWidth: 30, verticalScrollbarWidth: 7, baseCharacterWidth: 10)
|
||||
getState(presenter) # trigger a state update to store state in the presenter
|
||||
editor.setText('abcdefghijklm')
|
||||
expect(getState(presenter).horizontalScrollbar.visible).toBe(false)
|
||||
|
||||
describe ".height", ->
|
||||
it "tracks the value of ::horizontalScrollbarHeight", ->
|
||||
presenter = buildPresenter(horizontalScrollbarHeight: 10)
|
||||
@@ -538,6 +545,21 @@ describe "TextEditorPresenter", ->
|
||||
presenter.setScrollLeft(10)
|
||||
expect(getState(presenter).content.scrollLeft).toBe 0
|
||||
|
||||
it "is always 0 when `editor.autoWidth` is true", ->
|
||||
editor.update({autoWidth: true})
|
||||
editor.setText('abcdefghijklm')
|
||||
presenter = buildPresenter(explicitHeight: 10, contentFrameWidth: 30, verticalScrollbarWidth: 15, baseCharacterWidth: 10)
|
||||
getState(presenter) # trigger a state update to store state in the presenter
|
||||
|
||||
editor.setCursorBufferPosition([0, Infinity])
|
||||
editor.insertText('n')
|
||||
expect(getState(presenter).content.scrollLeft).toBe(0)
|
||||
|
||||
editor.setText('abcdefghijklm\nnopqrstuvwxy') # make the vertical scrollbar appear
|
||||
editor.setCursorBufferPosition([1, Infinity])
|
||||
editor.insertText('z')
|
||||
expect(getState(presenter).content.scrollLeft).toBe(0)
|
||||
|
||||
describe ".verticalScrollbar", ->
|
||||
describe ".visible", ->
|
||||
it "is true if the scrollHeight exceeds the computed client height", ->
|
||||
@@ -755,6 +777,39 @@ describe "TextEditorPresenter", ->
|
||||
expect(getState(presenter).hiddenInput.width).toBe 2
|
||||
|
||||
describe ".content", ->
|
||||
describe '.width', ->
|
||||
describe "when `editor.autoWidth` is false (the default)", ->
|
||||
it "equals to the max width between the content frame width and the content width + the vertical scrollbar width", ->
|
||||
editor.setText('abc\ndef\nghi\njkl')
|
||||
presenter = buildPresenter(explicitHeight: 10, contentFrameWidth: 33, verticalScrollbarWidth: 7, baseCharacterWidth: 10)
|
||||
expect(getState(presenter).content.width).toBe(3 * 10 + 7 + 1)
|
||||
presenter.setContentFrameWidth(50)
|
||||
expect(getState(presenter).content.width).toBe(50)
|
||||
presenter.setVerticalScrollbarWidth(27)
|
||||
expect(getState(presenter).content.width).toBe(3 * 10 + 27 + 1)
|
||||
|
||||
describe "when `editor.autoWidth` is true", ->
|
||||
it "equals to the content width + the vertical scrollbar width", ->
|
||||
editor.setText('abc\ndef\nghi\njkl')
|
||||
presenter = buildPresenter(explicitHeight: 10, contentFrameWidth: 300, verticalScrollbarWidth: 7, baseCharacterWidth: 10)
|
||||
expectStateUpdate presenter, -> editor.update({autoWidth: true})
|
||||
expect(getState(presenter).content.width).toBe(3 * 10 + 7 + 1)
|
||||
editor.setText('abcdefghi\n')
|
||||
expect(getState(presenter).content.width).toBe(9 * 10 + 7 + 1)
|
||||
|
||||
it "ignores the vertical scrollbar width when it is unset", ->
|
||||
editor.setText('abcdef\nghijkl')
|
||||
presenter = buildPresenter(explicitHeight: 10, contentFrameWidth: 33, verticalScrollbarWidth: 7, baseCharacterWidth: 10)
|
||||
presenter.setVerticalScrollbarWidth(null)
|
||||
expect(getState(presenter).content.width).toBe(6 * 10 + 1)
|
||||
|
||||
it "ignores the content frame width when it is unset", ->
|
||||
editor.setText('abc\ndef\nghi\njkl')
|
||||
presenter = buildPresenter(explicitHeight: 10, contentFrameWidth: 33, verticalScrollbarWidth: 7, baseCharacterWidth: 10)
|
||||
getState(presenter) # trigger a state update, causing verticalScrollbarWidth to be stored in the presenter
|
||||
presenter.setContentFrameWidth(null)
|
||||
expect(getState(presenter).content.width).toBe(3 * 10 + 7 + 1)
|
||||
|
||||
describe ".maxHeight", ->
|
||||
it "changes based on boundingClientRect", ->
|
||||
presenter = buildPresenter(scrollTop: 0, lineHeight: 10)
|
||||
@@ -2664,6 +2719,17 @@ describe "TextEditorPresenter", ->
|
||||
pixelPosition: {top: 10, left: 0}
|
||||
}
|
||||
|
||||
describe ".width", ->
|
||||
it "is null when `editor.autoWidth` is false (the default)", ->
|
||||
presenter = buildPresenter(explicitHeight: 50, gutterWidth: 20, contentFrameWidth: 300, baseCharacterWidth: 10)
|
||||
expect(getState(presenter).width).toBeNull()
|
||||
|
||||
it "equals to sum of .content.width and the width of the gutter when `editor.autoWidth` is true", ->
|
||||
editor.setText('abcdef')
|
||||
editor.update({autoWidth: true})
|
||||
presenter = buildPresenter(explicitHeight: 50, gutterWidth: 20, contentFrameWidth: 300, baseCharacterWidth: 10)
|
||||
expect(getState(presenter).width).toBe(20 + 6 * 10 + 1)
|
||||
|
||||
describe ".height", ->
|
||||
it "updates model's rows per page when it changes", ->
|
||||
presenter = buildPresenter(explicitHeight: 50, lineHeightInPixels: 10, horizontalScrollbarHeight: 10)
|
||||
|
||||
@@ -5516,6 +5516,14 @@ describe "TextEditor", ->
|
||||
editor.update({autoHeight: true})
|
||||
expect(editor.getAutoHeight()).toBe(true)
|
||||
|
||||
describe "auto width", ->
|
||||
it "returns false by default but can be customized", ->
|
||||
expect(editor.getAutoWidth()).toBe(false)
|
||||
editor.update({autoWidth: true})
|
||||
expect(editor.getAutoWidth()).toBe(true)
|
||||
editor.update({autoWidth: false})
|
||||
expect(editor.getAutoWidth()).toBe(false)
|
||||
|
||||
describe '.get/setPlaceholderText()', ->
|
||||
it 'can be created with placeholderText', ->
|
||||
newEditor = atom.workspace.buildTextEditor(
|
||||
|
||||
@@ -129,7 +129,7 @@ class TextEditorComponent
|
||||
updateSync: ->
|
||||
@updateSyncPreMeasurement()
|
||||
|
||||
@oldState ?= {}
|
||||
@oldState ?= {width: null}
|
||||
@newState = @presenter.getPostMeasurementState()
|
||||
|
||||
if @editor.getLastSelection()? and not @editor.getLastSelection().isEmpty()
|
||||
@@ -149,6 +149,13 @@ class TextEditorComponent
|
||||
else
|
||||
@domNode.style.height = ''
|
||||
|
||||
if @newState.width isnt @oldState.width
|
||||
if @newState.width?
|
||||
@hostElement.style.width = @newState.width + 'px'
|
||||
else
|
||||
@hostElement.style.width = ''
|
||||
@oldState.width = @newState.width
|
||||
|
||||
if @newState.gutters.length
|
||||
@mountGutterContainerComponent() unless @gutterContainerComponent?
|
||||
@gutterContainerComponent.updateSync(@newState)
|
||||
|
||||
@@ -110,13 +110,14 @@ class TextEditorPresenter
|
||||
|
||||
@updateLines()
|
||||
|
||||
@updateFocusedState()
|
||||
@updateHeightState()
|
||||
@updateVerticalScrollState()
|
||||
@updateHorizontalScrollState()
|
||||
@updateScrollbarsState()
|
||||
@updateHiddenInputState()
|
||||
@updateContentState()
|
||||
@updateFocusedState()
|
||||
@updateHeightState()
|
||||
@updateWidthState()
|
||||
@updateHighlightDecorations() if @shouldUpdateDecorations
|
||||
@updateTilesState()
|
||||
@updateCursorsState()
|
||||
@@ -224,6 +225,12 @@ class TextEditorPresenter
|
||||
else
|
||||
@state.height = null
|
||||
|
||||
updateWidthState: ->
|
||||
if @model.getAutoWidth()
|
||||
@state.width = @state.content.width + @gutterWidth
|
||||
else
|
||||
@state.width = null
|
||||
|
||||
updateVerticalScrollState: ->
|
||||
@state.content.scrollHeight = @scrollHeight
|
||||
@sharedGutterStyles.scrollHeight = @scrollHeight
|
||||
@@ -269,7 +276,13 @@ class TextEditorPresenter
|
||||
@sharedGutterStyles.maxHeight = @boundingClientRect.height
|
||||
@state.content.maxHeight = @boundingClientRect.height
|
||||
|
||||
@state.content.width = Math.max(@contentWidth + @verticalScrollbarWidth, @contentFrameWidth)
|
||||
verticalScrollbarWidth = @verticalScrollbarWidth ? 0
|
||||
contentFrameWidth = @contentFrameWidth ? 0
|
||||
contentWidth = @contentWidth ? 0
|
||||
if @model.getAutoWidth()
|
||||
@state.content.width = contentWidth + verticalScrollbarWidth
|
||||
else
|
||||
@state.content.width = Math.max(contentWidth + verticalScrollbarWidth, contentFrameWidth)
|
||||
@state.content.scrollWidth = @scrollWidth
|
||||
@state.content.scrollLeft = @scrollLeft
|
||||
@state.content.backgroundColor = if @model.isMini() then null else @backgroundColor
|
||||
@@ -662,6 +675,7 @@ class TextEditorPresenter
|
||||
|
||||
if @contentWidth isnt oldContentWidth
|
||||
@updateScrollbarDimensions()
|
||||
@updateClientWidth()
|
||||
@updateScrollWidth()
|
||||
|
||||
updateClientHeight: ->
|
||||
@@ -678,7 +692,11 @@ class TextEditorPresenter
|
||||
updateClientWidth: ->
|
||||
return unless @contentFrameWidth? and @verticalScrollbarWidth?
|
||||
|
||||
clientWidth = @contentFrameWidth - @verticalScrollbarWidth
|
||||
if @model.getAutoWidth()
|
||||
clientWidth = @contentWidth
|
||||
else
|
||||
clientWidth = @contentFrameWidth - @verticalScrollbarWidth
|
||||
|
||||
@model.setWidth(clientWidth, true) unless @editorWidthInChars
|
||||
|
||||
unless @clientWidth is clientWidth
|
||||
@@ -720,20 +738,23 @@ class TextEditorPresenter
|
||||
return unless @measuredVerticalScrollbarWidth? and @measuredHorizontalScrollbarHeight?
|
||||
return unless @contentWidth? and @contentHeight?
|
||||
|
||||
clientWidthWithoutVerticalScrollbar = @contentFrameWidth
|
||||
clientWidthWithVerticalScrollbar = clientWidthWithoutVerticalScrollbar - @measuredVerticalScrollbarWidth
|
||||
clientHeightWithoutHorizontalScrollbar = @height
|
||||
clientHeightWithHorizontalScrollbar = clientHeightWithoutHorizontalScrollbar - @measuredHorizontalScrollbarHeight
|
||||
if @model.getAutoWidth()
|
||||
clientWidthWithVerticalScrollbar = @contentWidth + @measuredVerticalScrollbarWidth
|
||||
else
|
||||
clientWidthWithVerticalScrollbar = @contentFrameWidth
|
||||
clientWidthWithoutVerticalScrollbar = clientWidthWithVerticalScrollbar - @measuredVerticalScrollbarWidth
|
||||
clientHeightWithHorizontalScrollbar = @height
|
||||
clientHeightWithoutHorizontalScrollbar = clientHeightWithHorizontalScrollbar - @measuredHorizontalScrollbarHeight
|
||||
|
||||
horizontalScrollbarVisible =
|
||||
not @model.isMini() and
|
||||
(@contentWidth > clientWidthWithoutVerticalScrollbar or
|
||||
@contentWidth > clientWidthWithVerticalScrollbar and @contentHeight > clientHeightWithoutHorizontalScrollbar)
|
||||
(@contentWidth > clientWidthWithVerticalScrollbar or
|
||||
@contentWidth > clientWidthWithoutVerticalScrollbar and @contentHeight > clientHeightWithHorizontalScrollbar)
|
||||
|
||||
verticalScrollbarVisible =
|
||||
not @model.isMini() and
|
||||
(@contentHeight > clientHeightWithoutHorizontalScrollbar or
|
||||
@contentHeight > clientHeightWithHorizontalScrollbar and @contentWidth > clientWidthWithoutVerticalScrollbar)
|
||||
(@contentHeight > clientHeightWithHorizontalScrollbar or
|
||||
@contentHeight > clientHeightWithoutHorizontalScrollbar and @contentWidth > clientWidthWithVerticalScrollbar)
|
||||
|
||||
horizontalScrollbarHeight =
|
||||
if horizontalScrollbarVisible
|
||||
@@ -896,6 +917,9 @@ class TextEditorPresenter
|
||||
@updateScrollHeight()
|
||||
@updateEndRow()
|
||||
|
||||
didChangeAutoWidth: ->
|
||||
@emitDidUpdateState()
|
||||
|
||||
setContentFrameWidth: (contentFrameWidth) ->
|
||||
if @contentFrameWidth isnt contentFrameWidth or @editorWidthInChars?
|
||||
oldContentFrameWidth = @contentFrameWidth
|
||||
|
||||
@@ -127,7 +127,7 @@ class TextEditor extends Model
|
||||
@softTabs, @firstVisibleScreenRow, @firstVisibleScreenColumn, initialLine, initialColumn, tabLength,
|
||||
@softWrapped, @decorationManager, @selectionsMarkerLayer, @buffer, suppressCursorCreation,
|
||||
@mini, @placeholderText, lineNumberGutterVisible, @largeFileMode, @clipboard,
|
||||
@assert, grammar, @showInvisibles, @autoHeight, @scrollPastEnd, @editorWidthInChars,
|
||||
@assert, grammar, @showInvisibles, @autoHeight, @autoWidth, @scrollPastEnd, @editorWidthInChars,
|
||||
@tokenizedBuffer, @displayLayer, @invisibles, @showIndentGuide, @softWrapHangingIndentLength,
|
||||
@softWrapped, @softWrapAtPreferredLineLength, @preferredLineLength
|
||||
} = params
|
||||
@@ -144,6 +144,7 @@ class TextEditor extends Model
|
||||
@selections = []
|
||||
@hasTerminatedPendingState = false
|
||||
|
||||
@autoWidth ?= false
|
||||
@autoHeight ?= true
|
||||
@mini ?= false
|
||||
@scrollPastEnd ?= true
|
||||
@@ -320,6 +321,10 @@ class TextEditor extends Model
|
||||
@autoHeight = value
|
||||
@editorElement?.didChangeAutoHeight()
|
||||
|
||||
when 'autoWidth'
|
||||
if value isnt @autoWidth
|
||||
@autoWidth = value
|
||||
@presenter?.didChangeAutoWidth()
|
||||
else
|
||||
throw new TypeError("Invalid TextEditor parameter: '#{param}'")
|
||||
|
||||
@@ -3552,6 +3557,9 @@ class TextEditor extends Model
|
||||
Grim.deprecate("This is now a view method. Call TextEditorElement::getWidth instead.")
|
||||
@width
|
||||
|
||||
getAutoWidth: ->
|
||||
@autoWidth
|
||||
|
||||
# Experimental: Scroll the editor such that the given screen row is at the
|
||||
# top of the visible area.
|
||||
setFirstVisibleScreenRow: (screenRow, fromView) ->
|
||||
|
||||
Reference in New Issue
Block a user