mirror of
https://github.com/atom/atom.git
synced 2026-01-23 05:48:10 -05:00
Merge pull request #2955 from atom/ns-react-mini-editors
Allow React editors to be used as mini-editors with core.useReactMiniEditors option
This commit is contained in:
@@ -15,7 +15,10 @@ unless process.env.ATOM_SHELL_INTERNAL_RUN_AS_NODE
|
||||
module.exports.$ = $
|
||||
module.exports.$$ = $$
|
||||
module.exports.$$$ = $$$
|
||||
module.exports.EditorView = require '../src/editor-view'
|
||||
if atom.config.get('core.useReactMiniEditors')
|
||||
module.exports.EditorView = require '../src/react-editor-view'
|
||||
else
|
||||
module.exports.EditorView = require '../src/editor-view'
|
||||
module.exports.ScrollView = require '../src/scroll-view'
|
||||
module.exports.SelectListView = require '../src/select-list-view'
|
||||
module.exports.Task = require '../src/task'
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,8 @@
|
||||
fs = require 'fs'
|
||||
|
||||
module.exports.runSpecSuite = (specSuite, logFile, logErrors=true) ->
|
||||
{$, $$} = require 'atom'
|
||||
{$, $$} = require '../src/space-pen-extensions'
|
||||
|
||||
window[key] = value for key, value of require '../vendor/jasmine'
|
||||
|
||||
{TerminalReporter} = require 'jasmine-tagged'
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
_ = require 'underscore-plus'
|
||||
fs = require 'fs-plus'
|
||||
{Git} = require 'atom'
|
||||
path = require 'path'
|
||||
require './spec-helper'
|
||||
|
||||
|
||||
@@ -12,14 +12,14 @@ CursorsComponent = React.createClass
|
||||
cursorBlinkIntervalHandle: null
|
||||
|
||||
render: ->
|
||||
{cursorPixelRects, scrollTop, scrollLeft, defaultCharWidth, useHardwareAcceleration} = @props
|
||||
{performedInitialMeasurement, cursorPixelRects, scrollTop, scrollLeft, defaultCharWidth, useHardwareAcceleration} = @props
|
||||
{blinkOff} = @state
|
||||
|
||||
className = 'cursors'
|
||||
className += ' blink-off' if blinkOff
|
||||
|
||||
div {className},
|
||||
if @isMounted()
|
||||
if performedInitialMeasurement
|
||||
for key, pixelRect of cursorPixelRects
|
||||
CursorComponent({key, pixelRect, scrollTop, scrollLeft, defaultCharWidth, useHardwareAcceleration})
|
||||
|
||||
|
||||
@@ -22,6 +22,8 @@ EditorComponent = React.createClass
|
||||
statics:
|
||||
performSyncUpdates: false
|
||||
|
||||
visible: false
|
||||
autoHeight: false
|
||||
pendingScrollTop: null
|
||||
pendingScrollLeft: null
|
||||
selectOnMouseMove: false
|
||||
@@ -35,27 +37,28 @@ EditorComponent = React.createClass
|
||||
gutterWidth: 0
|
||||
refreshingScrollbars: false
|
||||
measuringScrollbars: true
|
||||
pendingVerticalScrollDelta: 0
|
||||
pendingHorizontalScrollDelta: 0
|
||||
mouseWheelScreenRow: null
|
||||
mouseWheelScreenRowClearDelay: 150
|
||||
scrollSensitivity: 0.4
|
||||
scrollViewMeasurementRequested: false
|
||||
heightAndWidthMeasurementRequested: false
|
||||
measureLineHeightAndDefaultCharWidthWhenShown: false
|
||||
remeasureCharacterWidthsIfVisibleAfterNextUpdate: false
|
||||
inputEnabled: true
|
||||
scrollViewMeasurementInterval: 100
|
||||
scopedCharacterWidthsChangeCount: null
|
||||
scrollViewMeasurementPaused: false
|
||||
domPollingInterval: 100
|
||||
domPollingIntervalId: null
|
||||
domPollingPaused: false
|
||||
|
||||
render: ->
|
||||
{focused, fontSize, lineHeight, fontFamily, showIndentGuide, showInvisibles, showLineNumbers, visible} = @state
|
||||
{editor, cursorBlinkPeriod, cursorBlinkResumeDelay} = @props
|
||||
{editor, mini, cursorBlinkPeriod, cursorBlinkResumeDelay} = @props
|
||||
maxLineNumberDigits = editor.getLineCount().toString().length
|
||||
invisibles = if showInvisibles then @state.invisibles else {}
|
||||
invisibles = if showInvisibles and not mini then @state.invisibles else {}
|
||||
hasSelection = editor.getSelection()? and !editor.getSelection().isEmpty()
|
||||
style = {fontSize, fontFamily}
|
||||
style.lineHeight = lineHeight unless mini
|
||||
|
||||
if @isMounted()
|
||||
if @performedInitialMeasurement
|
||||
renderedRowRange = @getRenderedRowRange()
|
||||
[renderedStartRow, renderedEndRow] = renderedRowRange
|
||||
cursorPixelRects = @getCursorPixelRects(renderedRowRange)
|
||||
@@ -63,6 +66,7 @@ EditorComponent = React.createClass
|
||||
decorations = editor.decorationsForScreenRowRange(renderedStartRow, renderedEndRow)
|
||||
highlightDecorations = @getHighlightDecorations(decorations)
|
||||
lineDecorations = @getLineDecorations(decorations)
|
||||
placeholderText = @props.placeholderText if @props.placeholderText? and editor.isEmpty()
|
||||
|
||||
scrollHeight = editor.getScrollHeight()
|
||||
scrollWidth = editor.getScrollWidth()
|
||||
@@ -81,12 +85,14 @@ EditorComponent = React.createClass
|
||||
if @mouseWheelScreenRow? and not (renderedStartRow <= @mouseWheelScreenRow < renderedEndRow)
|
||||
mouseWheelScreenRow = @mouseWheelScreenRow
|
||||
|
||||
className = 'editor-contents editor-colors'
|
||||
style.height = scrollViewHeight if @autoHeight
|
||||
|
||||
className = 'editor-contents'
|
||||
className += ' is-focused' if focused
|
||||
className += ' has-selection' if hasSelection
|
||||
|
||||
div className: className, style: {fontSize, lineHeight, fontFamily}, tabIndex: -1,
|
||||
if showLineNumbers
|
||||
div {className, style, tabIndex: -1},
|
||||
if not mini and showLineNumbers
|
||||
GutterComponent {
|
||||
ref: 'gutter', onMouseDown: @onGutterMouseDown, onWidthChanged: @onGutterWidthChanged,
|
||||
lineDecorations, defaultCharWidth, editor, renderedRowRange, maxLineNumberDigits, scrollViewHeight,
|
||||
@@ -103,14 +109,16 @@ EditorComponent = React.createClass
|
||||
|
||||
CursorsComponent {
|
||||
scrollTop, scrollLeft, cursorPixelRects, cursorBlinkPeriod, cursorBlinkResumeDelay,
|
||||
lineHeightInPixels, defaultCharWidth, @scopedCharacterWidthsChangeCount, @useHardwareAcceleration
|
||||
lineHeightInPixels, defaultCharWidth, @scopedCharacterWidthsChangeCount, @useHardwareAcceleration,
|
||||
@performedInitialMeasurement
|
||||
}
|
||||
LinesComponent {
|
||||
ref: 'lines',
|
||||
editor, lineHeightInPixels, defaultCharWidth, lineDecorations, highlightDecorations,
|
||||
showIndentGuide, renderedRowRange, @pendingChanges, scrollTop, scrollLeft,
|
||||
@scrollingVertically, scrollHeight, scrollWidth, mouseWheelScreenRow, invisibles,
|
||||
visible, scrollViewHeight, @scopedCharacterWidthsChangeCount, lineWidth, @useHardwareAcceleration
|
||||
visible, scrollViewHeight, @scopedCharacterWidthsChangeCount, lineWidth, @useHardwareAcceleration,
|
||||
placeholderText, @performedInitialMeasurement
|
||||
}
|
||||
|
||||
ScrollbarComponent
|
||||
@@ -149,8 +157,7 @@ EditorComponent = React.createClass
|
||||
{editor} = @props
|
||||
Math.max(1, Math.ceil(editor.getHeight() / editor.getLineHeightInPixels()))
|
||||
|
||||
getInitialState: ->
|
||||
visible: true
|
||||
getInitialState: -> {}
|
||||
|
||||
getDefaultProps: ->
|
||||
cursorBlinkPeriod: 800
|
||||
@@ -166,7 +173,7 @@ EditorComponent = React.createClass
|
||||
componentDidMount: ->
|
||||
{editor} = @props
|
||||
|
||||
@scrollViewMeasurementIntervalId = setInterval(@measureScrollView, @scrollViewMeasurementInterval)
|
||||
@domPollingIntervalId = setInterval(@pollDOM, @domPollingInterval)
|
||||
|
||||
@observeEditor()
|
||||
@listenForDOMEvents()
|
||||
@@ -175,17 +182,14 @@ EditorComponent = React.createClass
|
||||
@subscribe atom.themes, 'stylesheet-added stylsheet-removed', @onStylesheetsChanged
|
||||
@subscribe scrollbarStyle.changes, @refreshScrollbars
|
||||
|
||||
editor.setVisible(true)
|
||||
|
||||
@measureLineHeightAndDefaultCharWidth()
|
||||
@measureScrollView()
|
||||
@measureScrollbars()
|
||||
if @visible = @isVisible()
|
||||
@performInitialMeasurement()
|
||||
|
||||
componentWillUnmount: ->
|
||||
@props.parentView.trigger 'editor:will-be-removed', [@props.parentView]
|
||||
@unsubscribe()
|
||||
clearInterval(@scrollViewMeasurementIntervalId)
|
||||
@scrollViewMeasurementIntervalId = null
|
||||
clearInterval(@domPollingIntervalId)
|
||||
@domPollingIntervalId = null
|
||||
|
||||
componentDidUpdate: (prevProps, prevState) ->
|
||||
cursorsMoved = @cursorsMoved
|
||||
@@ -197,13 +201,26 @@ EditorComponent = React.createClass
|
||||
|
||||
if @props.editor.isAlive()
|
||||
@updateParentViewFocusedClassIfNeeded(prevState)
|
||||
@updateParentViewMiniClassIfNeeded(prevState)
|
||||
@props.parentView.trigger 'cursor:moved' if cursorsMoved
|
||||
@props.parentView.trigger 'selection:changed' if selectionChanged
|
||||
@props.parentView.trigger 'editor:display-updated'
|
||||
|
||||
@measureScrollbars() if @measuringScrollbars
|
||||
@measureLineHeightAndCharWidthsIfNeeded(prevState)
|
||||
@remeasureCharacterWidthsIfNeeded(prevState)
|
||||
@visible = @isVisible()
|
||||
if @performedInitialMeasurement
|
||||
@measureScrollbars() if @measuringScrollbars
|
||||
@measureLineHeightAndDefaultCharWidthIfNeeded(prevState)
|
||||
@remeasureCharacterWidthsIfNeeded(prevState)
|
||||
|
||||
performInitialMeasurement: ->
|
||||
@updatesPaused = true
|
||||
@measureLineHeightAndDefaultCharWidth()
|
||||
@measureHeightAndWidth()
|
||||
@measureScrollbars()
|
||||
@props.editor.setVisible(true)
|
||||
@updatesPaused = false
|
||||
@performedInitialMeasurement = true
|
||||
@requestUpdate()
|
||||
|
||||
requestUpdate: ->
|
||||
if @updatesPaused
|
||||
@@ -220,7 +237,7 @@ EditorComponent = React.createClass
|
||||
|
||||
requestAnimationFrame: (fn) ->
|
||||
@updatesPaused = true
|
||||
@pauseScrollViewMeasurement()
|
||||
@pauseDOMPolling()
|
||||
requestAnimationFrame =>
|
||||
fn()
|
||||
@updatesPaused = false
|
||||
@@ -273,7 +290,9 @@ EditorComponent = React.createClass
|
||||
cursorPixelRects
|
||||
|
||||
getLineDecorations: (decorationsByMarkerId) ->
|
||||
{editor} = @props
|
||||
{editor, mini} = @props
|
||||
return {} if mini
|
||||
|
||||
decorationsByScreenRow = {}
|
||||
for markerId, decorations of decorationsByMarkerId
|
||||
marker = editor.getMarker(markerId)
|
||||
@@ -350,7 +369,7 @@ EditorComponent = React.createClass
|
||||
|
||||
scrollViewNode = @refs.scrollView.getDOMNode()
|
||||
scrollViewNode.addEventListener 'scroll', @onScrollViewScroll
|
||||
window.addEventListener 'resize', @requestScrollViewMeasurement
|
||||
window.addEventListener 'resize', @requestHeightAndWidthMeasurement
|
||||
|
||||
@listenForIMEEvents()
|
||||
|
||||
@@ -557,28 +576,23 @@ EditorComponent = React.createClass
|
||||
@pendingScrollLeft = null
|
||||
|
||||
onMouseWheel: (event) ->
|
||||
event.preventDefault()
|
||||
animationFramePending = @pendingHorizontalScrollDelta isnt 0 or @pendingVerticalScrollDelta isnt 0
|
||||
{editor} = @props
|
||||
|
||||
# Only scroll in one direction at a time
|
||||
{wheelDeltaX, wheelDeltaY} = event
|
||||
if Math.abs(wheelDeltaX) > Math.abs(wheelDeltaY)
|
||||
# Scrolling horizontally
|
||||
@pendingHorizontalScrollDelta -= Math.round(wheelDeltaX * @scrollSensitivity)
|
||||
previousScrollLeft = editor.getScrollLeft()
|
||||
editor.setScrollLeft(previousScrollLeft - Math.round(wheelDeltaX * @scrollSensitivity))
|
||||
event.preventDefault() unless previousScrollLeft is editor.getScrollLeft()
|
||||
else
|
||||
# Scrolling vertically
|
||||
@pendingVerticalScrollDelta -= Math.round(wheelDeltaY * @scrollSensitivity)
|
||||
@mouseWheelScreenRow = @screenRowForNode(event.target)
|
||||
@clearMouseWheelScreenRowAfterDelay ?= debounce(@clearMouseWheelScreenRow, @mouseWheelScreenRowClearDelay)
|
||||
@clearMouseWheelScreenRowAfterDelay()
|
||||
|
||||
unless animationFramePending
|
||||
@requestAnimationFrame =>
|
||||
{editor} = @props
|
||||
editor.setScrollTop(editor.getScrollTop() + @pendingVerticalScrollDelta)
|
||||
editor.setScrollLeft(editor.getScrollLeft() + @pendingHorizontalScrollDelta)
|
||||
@pendingVerticalScrollDelta = 0
|
||||
@pendingHorizontalScrollDelta = 0
|
||||
previousScrollTop = editor.getScrollTop()
|
||||
editor.setScrollTop(previousScrollTop - Math.round(wheelDeltaY * @scrollSensitivity))
|
||||
event.preventDefault() unless previousScrollTop is editor.getScrollTop()
|
||||
|
||||
onScrollViewScroll: ->
|
||||
if @isMounted()
|
||||
@@ -656,7 +670,7 @@ EditorComponent = React.createClass
|
||||
onStylesheetsChanged: (stylesheet) ->
|
||||
@refreshScrollbars() if @containsScrollbarSelector(stylesheet)
|
||||
@remeasureCharacterWidthsIfVisibleAfterNextUpdate = true
|
||||
@requestUpdate() if @state.visible
|
||||
@requestUpdate() if @visible
|
||||
|
||||
onScreenLinesChanged: (change) ->
|
||||
{editor} = @props
|
||||
@@ -733,68 +747,87 @@ EditorComponent = React.createClass
|
||||
window.addEventListener('mousemove', onMouseMove)
|
||||
window.addEventListener('mouseup', onMouseUp)
|
||||
|
||||
pauseScrollViewMeasurement: ->
|
||||
@scrollViewMeasurementPaused = true
|
||||
@resumeScrollViewMeasurementAfterDelay ?= debounce(@resumeScrollViewMeasurement, 100)
|
||||
@resumeScrollViewMeasurementAfterDelay()
|
||||
isVisible: ->
|
||||
node = @getDOMNode()
|
||||
node.offsetHeight > 0 or node.offsetWidth > 0
|
||||
|
||||
resumeScrollViewMeasurement: ->
|
||||
@scrollViewMeasurementPaused = false
|
||||
pauseDOMPolling: ->
|
||||
@domPollingPaused = true
|
||||
@resumeDOMPollingAfterDelay ?= debounce(@resumeDOMPolling, 100)
|
||||
@resumeDOMPollingAfterDelay()
|
||||
|
||||
resumeScrollViewMeasurementAfterDelay: null # created lazily
|
||||
resumeDOMPolling: ->
|
||||
@domPollingPaused = false
|
||||
|
||||
requestScrollViewMeasurement: ->
|
||||
return if @scrollViewMeasurementRequested
|
||||
resumeDOMPollingAfterDelay: null # created lazily
|
||||
|
||||
@scrollViewMeasurementRequested = true
|
||||
pollDOM: ->
|
||||
return if @domPollingPaused or not @isMounted()
|
||||
|
||||
wasVisible = @visible
|
||||
if @visible = @isVisible()
|
||||
if wasVisible
|
||||
@measureHeightAndWidth()
|
||||
else
|
||||
@performInitialMeasurement()
|
||||
|
||||
requestHeightAndWidthMeasurement: ->
|
||||
return if @heightAndWidthMeasurementRequested
|
||||
|
||||
@heightAndWidthMeasurementRequested = true
|
||||
requestAnimationFrame =>
|
||||
@scrollViewMeasurementRequested = false
|
||||
@measureScrollView()
|
||||
@heightAndWidthMeasurementRequested = false
|
||||
@measureHeightAndWidth()
|
||||
|
||||
# Measure explicitly-styled height and width and relay them to the model. If
|
||||
# these values aren't explicitly styled, we assume the editor is unconstrained
|
||||
# and use the scrollHeight / scrollWidth as its height and width in
|
||||
# calculations.
|
||||
measureScrollView: ->
|
||||
return if @scrollViewMeasurementPaused
|
||||
measureHeightAndWidth: ->
|
||||
return unless @isMounted()
|
||||
|
||||
{editor} = @props
|
||||
editorNode = @getDOMNode()
|
||||
{editor, parentView} = @props
|
||||
parentNode = parentView.element
|
||||
scrollViewNode = @refs.scrollView.getDOMNode()
|
||||
{position} = getComputedStyle(editorNode)
|
||||
{width, height} = editorNode.style
|
||||
{position} = getComputedStyle(parentNode)
|
||||
{height} = parentNode.style
|
||||
|
||||
if position is 'absolute' or height
|
||||
if @autoHeight
|
||||
@autoHeight = false
|
||||
@forceUpdate()
|
||||
|
||||
clientHeight = scrollViewNode.clientHeight
|
||||
editor.setHeight(clientHeight) if clientHeight > 0
|
||||
else
|
||||
editor.setHeight(null)
|
||||
@autoHeight = true
|
||||
|
||||
if position is 'absolute' or width
|
||||
clientWidth = scrollViewNode.clientWidth
|
||||
paddingLeft = parseInt(getComputedStyle(scrollViewNode).paddingLeft)
|
||||
clientWidth -= paddingLeft
|
||||
editor.setWidth(clientWidth) if clientWidth > 0
|
||||
clientWidth = scrollViewNode.clientWidth
|
||||
paddingLeft = parseInt(getComputedStyle(scrollViewNode).paddingLeft)
|
||||
clientWidth -= paddingLeft
|
||||
editor.setWidth(clientWidth) if clientWidth > 0
|
||||
|
||||
measureLineHeightAndCharWidthsIfNeeded: (prevState) ->
|
||||
measureLineHeightAndDefaultCharWidthIfNeeded: (prevState) ->
|
||||
if not isEqualForProperties(prevState, @state, 'lineHeight', 'fontSize', 'fontFamily')
|
||||
if @state.visible
|
||||
if @visible
|
||||
@measureLineHeightAndDefaultCharWidth()
|
||||
else
|
||||
@measureLineHeightAndDefaultCharWidthWhenShown = true
|
||||
else if @measureLineHeightAndDefaultCharWidthWhenShown and @state.visible and not prevState.visible
|
||||
else if @measureLineHeightAndDefaultCharWidthWhenShown and @visible
|
||||
@measureLineHeightAndDefaultCharWidthWhenShown = false
|
||||
@measureLineHeightAndDefaultCharWidth()
|
||||
|
||||
measureLineHeightAndDefaultCharWidth: ->
|
||||
@measureLineHeightAndDefaultCharWidthWhenShown = false
|
||||
@refs.lines.measureLineHeightAndDefaultCharWidth()
|
||||
|
||||
remeasureCharacterWidthsIfNeeded: (prevState) ->
|
||||
if not isEqualForProperties(prevState, @state, 'fontSize', 'fontFamily')
|
||||
if @state.visible
|
||||
if @visible
|
||||
@remeasureCharacterWidths()
|
||||
else
|
||||
@remeasureCharacterWidthsIfVisibleAfterNextUpdate = true
|
||||
else if @remeasureCharacterWidthsIfVisibleAfterNextUpdate and @state.visible
|
||||
else if @remeasureCharacterWidthsIfVisibleAfterNextUpdate and @visible
|
||||
@remeasureCharacterWidthsIfVisibleAfterNextUpdate = false
|
||||
@remeasureCharacterWidths()
|
||||
|
||||
@@ -805,6 +838,7 @@ EditorComponent = React.createClass
|
||||
@requestUpdate()
|
||||
|
||||
measureScrollbars: ->
|
||||
return unless @visible
|
||||
@measuringScrollbars = false
|
||||
|
||||
{editor} = @props
|
||||
@@ -861,12 +895,6 @@ EditorComponent = React.createClass
|
||||
node = node.parentNode
|
||||
null
|
||||
|
||||
hide: ->
|
||||
@setState(visible: false)
|
||||
|
||||
show: ->
|
||||
@setState(visible: true)
|
||||
|
||||
getFontSize: ->
|
||||
@state.fontSize
|
||||
|
||||
@@ -940,6 +968,10 @@ EditorComponent = React.createClass
|
||||
if prevState.focused isnt @state.focused
|
||||
@props.parentView.toggleClass('is-focused', @props.focused)
|
||||
|
||||
updateParentViewMiniClassIfNeeded: (prevProps) ->
|
||||
if prevProps.mini isnt @props.mini
|
||||
@props.parentView.toggleClass('mini', @props.mini)
|
||||
|
||||
runScrollBenchmark: ->
|
||||
unless process.env.NODE_ENV is 'production'
|
||||
ReactPerf = require 'react-atom-fork/lib/ReactDefaultPerf'
|
||||
|
||||
@@ -518,6 +518,8 @@ class Editor extends Model
|
||||
# {Delegates to: TextBuffer.isModified}
|
||||
isModified: -> @buffer.isModified()
|
||||
|
||||
isEmpty: -> @buffer.isEmpty()
|
||||
|
||||
# Public: Determine whether the user should be prompted to save before closing
|
||||
# this editor.
|
||||
shouldPromptToSave: -> @isModified() and not @buffer.hasMultipleEditors()
|
||||
|
||||
@@ -19,9 +19,7 @@ GutterComponent = React.createClass
|
||||
{scrollHeight, scrollViewHeight, onMouseDown} = @props
|
||||
|
||||
div className: 'gutter', onClick: @onClick, onMouseDown: onMouseDown,
|
||||
# The line-numbers div must have the 'editor-colors' class so it has an
|
||||
# opaque background to avoid sub-pixel anti-aliasing problems on the GPU
|
||||
div className: 'gutter line-numbers editor-colors', ref: 'lineNumbers', style:
|
||||
div className: 'gutter line-numbers', ref: 'lineNumbers', style:
|
||||
height: Math.max(scrollHeight, scrollViewHeight)
|
||||
WebkitTransform: @getTransform()
|
||||
|
||||
@@ -53,6 +51,8 @@ GutterComponent = React.createClass
|
||||
)
|
||||
|
||||
{renderedRowRange, pendingChanges, lineDecorations} = newProps
|
||||
return false unless renderedRowRange?
|
||||
|
||||
for change in pendingChanges when Math.abs(change.screenDelta) > 0 or Math.abs(change.bufferDelta) > 0
|
||||
return true unless change.end <= renderedRowRange.start or renderedRowRange.end <= change.start
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ HighlightsComponent = React.createClass
|
||||
|
||||
render: ->
|
||||
div className: 'highlights',
|
||||
@renderHighlights() if @isMounted()
|
||||
@renderHighlights() if @props.performedInitialMeasurement
|
||||
|
||||
renderHighlights: ->
|
||||
{editor, highlightDecorations, lineHeightInPixels} = @props
|
||||
|
||||
@@ -16,18 +16,19 @@ LinesComponent = React.createClass
|
||||
displayName: 'LinesComponent'
|
||||
|
||||
render: ->
|
||||
if @isMounted()
|
||||
{editor, highlightDecorations, scrollHeight, scrollWidth} = @props
|
||||
{performedInitialMeasurement} = @props
|
||||
|
||||
if performedInitialMeasurement
|
||||
{editor, highlightDecorations, scrollHeight, scrollWidth, placeholderText} = @props
|
||||
{lineHeightInPixels, defaultCharWidth, scrollViewHeight, scopedCharacterWidthsChangeCount} = @props
|
||||
style =
|
||||
height: Math.max(scrollHeight, scrollViewHeight)
|
||||
width: scrollWidth
|
||||
WebkitTransform: @getTransform()
|
||||
|
||||
# The lines div must have the 'editor-colors' class so it has an opaque
|
||||
# background to avoid sub-pixel anti-aliasing problems on the GPU
|
||||
div {className: 'lines editor-colors', style},
|
||||
HighlightsComponent({editor, highlightDecorations, lineHeightInPixels, defaultCharWidth, scopedCharacterWidthsChangeCount})
|
||||
div {className: 'lines', style},
|
||||
div className: 'placeholder-text', placeholderText if placeholderText?
|
||||
HighlightsComponent({editor, highlightDecorations, lineHeightInPixels, defaultCharWidth, scopedCharacterWidthsChangeCount, performedInitialMeasurement})
|
||||
|
||||
getTransform: ->
|
||||
{scrollTop, scrollLeft, useHardwareAcceleration} = @props
|
||||
@@ -48,10 +49,13 @@ LinesComponent = React.createClass
|
||||
return true unless isEqualForProperties(newProps, @props,
|
||||
'renderedRowRange', 'lineDecorations', 'highlightDecorations', 'lineHeightInPixels', 'defaultCharWidth',
|
||||
'scrollTop', 'scrollLeft', 'showIndentGuide', 'scrollingVertically', 'invisibles', 'visible',
|
||||
'scrollViewHeight', 'mouseWheelScreenRow', 'scopedCharacterWidthsChangeCount', 'lineWidth', 'useHardwareAcceleration'
|
||||
'scrollViewHeight', 'mouseWheelScreenRow', 'scopedCharacterWidthsChangeCount', 'lineWidth', 'useHardwareAcceleration',
|
||||
'placeholderText', 'performedInitialMeasurement'
|
||||
)
|
||||
|
||||
{renderedRowRange, pendingChanges} = newProps
|
||||
return false unless renderedRowRange?
|
||||
|
||||
[renderedStartRow, renderedEndRow] = renderedRowRange
|
||||
for change in pendingChanges
|
||||
if change.screenDelta is 0
|
||||
|
||||
@@ -1,15 +1,33 @@
|
||||
{View, $} = require 'space-pen'
|
||||
React = require 'react-atom-fork'
|
||||
EditorComponent = require './editor-component'
|
||||
{defaults} = require 'underscore-plus'
|
||||
TextBuffer = require 'text-buffer'
|
||||
Editor = require './editor'
|
||||
EditorComponent = require './editor-component'
|
||||
|
||||
module.exports =
|
||||
class ReactEditorView extends View
|
||||
@content: -> @div class: 'editor react'
|
||||
@content: (params) ->
|
||||
attributes = params.attributes ? {}
|
||||
attributes.class = 'editor react editor-colors'
|
||||
@div attributes
|
||||
|
||||
focusOnAttach: false
|
||||
|
||||
constructor: (@editor, @props) ->
|
||||
constructor: (editorOrParams, @props) ->
|
||||
if editorOrParams instanceof Editor
|
||||
@editor = editorOrParams
|
||||
else
|
||||
{@editor, mini, placeholderText} = editorOrParams
|
||||
@props ?= {}
|
||||
@props.mini = mini
|
||||
@props.placeholderText = placeholderText
|
||||
@editor ?= new Editor
|
||||
buffer: new TextBuffer
|
||||
softWrap: false
|
||||
tabLength: 2
|
||||
softTabs: true
|
||||
|
||||
super
|
||||
|
||||
getEditor: -> @editor
|
||||
@@ -122,7 +140,7 @@ class ReactEditorView extends View
|
||||
pane?.splitDown(pane?.copyActiveItem()).activeView
|
||||
|
||||
getPane: ->
|
||||
@closest('.pane').view()
|
||||
@parent('.item-views').parents('.pane').view()
|
||||
|
||||
focus: ->
|
||||
if @component?
|
||||
@@ -132,11 +150,18 @@ class ReactEditorView extends View
|
||||
|
||||
hide: ->
|
||||
super
|
||||
@component?.hide()
|
||||
@pollComponentDOM()
|
||||
|
||||
show: ->
|
||||
super
|
||||
@component?.show()
|
||||
@pollComponentDOM()
|
||||
|
||||
pollComponentDOM: ->
|
||||
return unless @component?
|
||||
valueToRestore = @component.performSyncUpdates
|
||||
@component.performSyncUpdates = true
|
||||
@component.pollDOM()
|
||||
@component.performSyncUpdates = valueToRestore
|
||||
|
||||
pageDown: ->
|
||||
@editor.pageDown()
|
||||
@@ -208,3 +233,9 @@ class ReactEditorView extends View
|
||||
resetDisplay: -> # No-op shim for package specs
|
||||
|
||||
redraw: -> # No-op shim
|
||||
|
||||
setPlaceholderText: (placeholderText) ->
|
||||
if @component?
|
||||
@component.setProps({placeholderText})
|
||||
else
|
||||
@props.placeholderText = placeholderText
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
@import "octicon-mixins";
|
||||
|
||||
.editor.react {
|
||||
.editor-contents {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.underlayer {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
@@ -81,15 +85,18 @@
|
||||
}
|
||||
}
|
||||
|
||||
.editor {
|
||||
z-index: 0;
|
||||
font-family: Inconsolata, Monaco, Consolas, 'Courier New', Courier;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.editor, .editor-contents {
|
||||
overflow: hidden;
|
||||
cursor: text;
|
||||
display: -webkit-flex;
|
||||
-webkit-user-select: none;
|
||||
position: relative;
|
||||
z-index: 0;
|
||||
font-family: Inconsolata, Monaco, Consolas, 'Courier New', Courier;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.editor .gutter .line-number.cursor-line {
|
||||
|
||||
Reference in New Issue
Block a user