       clientWidth = scrollViewNode.clientWidth
       editor.setWidth(clientWidth) if clientWidth > 0
 
+  measureScrollbars: ->
+    @measuringScrollbars = false
+
+    {editor} = @props
+    scrollbarCornerNode = @refs.scrollbarCorner.getDOMNode()
+    width = (scrollbarCornerNode.offsetWidth - scrollbarCornerNode.clientWidth) or 15
+    height = (scrollbarCornerNode.offsetHeight - scrollbarCornerNode.clientHeight) or 15
+    editor.setVerticalScrollbarWidth(width)
+    editor.setHorizontalScrollbarHeight(height)
+
+  containsScrollbarSelector: (stylesheet) ->
+    for rule in stylesheet.cssRules
+      if rule.selectorText?.indexOf('scrollbar') > -1
+        return true
+    false
+
+  refreshScrollbars: ->
+    # Believe it or not, proper handling of changes to scrollbar styles requires
+    # three DOM updates.
+
+    # Scrollbar style changes won't apply to scrollbars that are already
+    # visible, so first we need to hide scrollbars so we can redisplay them and
+    # force Chromium to apply updates.
+    @refreshingScrollbars = true
+    @requestUpdate()
+
+    # Next, we display only the scrollbar corner so we can measure the new
+    # scrollbar dimensions. The ::measuringScrollbars property will be set back
+    # to false after the scrollbars are measured.
+    @measuringScrollbars = true
+    @requestUpdate()
+
+    # Finally, we restore the scrollbars based on the newly-measured dimensions
+    # if the editor's content and dimensions require them to be visible.
+    @requestUpdate()
+
+  requestUpdate: ->
+    if @batchingUpdates
+      @updateRequested = true
+    else
+      @forceUpdate()
+
+  pauseOverflowChangedEvents: ->
+    @overflowChangedEventsPaused = true
+    @resumeOverflowChangedEventsAfterDelay ?= debounce(@resumeOverflowChangedEvents, 500)
+    @resumeOverflowChangedEventsAfterDelay()
+
+  resumeOverflowChangedEvents: ->
+    if @overflowChangedWhilePaused
+      @overflowChangedWhilePaused = false
+      @requestScrollViewMeasurement()
+
+  resumeOverflowChangedEventsAfterDelay: null
+
+  clearMouseWheelScreenRow: ->
+    if @mouseWheelScreenRow?
+      @mouseWheelScreenRow = null
+      @requestUpdate()
+
+  clearMouseWheelScreenRowAfterDelay: null # created lazily
+
+  consolidateSelections: (e) ->
+    e.abortKeyBinding() unless @props.editor.consolidateSelections()
+
+  lineNodeForScreenRow: (screenRow) -> @refs.lines.lineNodeForScreenRow(screenRow)
+
+  lineNumberNodeForScreenRow: (screenRow) -> @refs.gutter.lineNumberNodeForScreenRow(screenRow)
+
   screenRowForNode: (node) ->
     while node isnt document
       if screenRow = node.dataset.screenRow
         return parseInt(screenRow)
       node = node.parentNode
     null
-
-  onStylesheetsChanged: (stylesheet) ->
-    @refreshScrollbars() if @containsScrollbarSelector(stylesheet)
-
-  containsScrollbarSelector: (stylesheet) ->
-    for rule in stylesheet.cssRules
-      if rule.selectorText?.indexOf('scrollbar') > -1
-        return true
-    false
-
-  refreshScrollbars: ->
-    # Believe it or not, proper handling of changes to scrollbar styles requires
-    # three DOM updates.
-
-    # Scrollbar style changes won't apply to scrollbars that are already
-    # visible, so first we need to hide scrollbars so we can redisplay them and
-    # force Chromium to apply updates.
-    @refreshingScrollbars = true
-    @requestUpdate()
-
-    # Next, we display only the scrollbar corner so we can measure the new
-    # scrollbar dimensions. The ::measuringScrollbars property will be set back
-    # to false after the scrollbars are measured.
-    @measuringScrollbars = true
-    @requestUpdate()
-
-    # Finally, we restore the scrollbars based on the newly-measured dimensions
-    # if the editor's content and dimensions require them to be visible.
-    @requestUpdate()
-
-  onBatchedUpdatesStarted: ->
-    @batchingUpdates = true
-
-  onBatchedUpdatesEnded: ->
-    updateRequested = @updateRequested
-    @updateRequested = false
-    @batchingUpdates = false
-    if updateRequested
-      @requestUpdate()
-
-  onScreenLinesChanged: (change) ->
-    {editor} = @props
-    @pendingChanges.push(change)
-    @requestUpdate() if editor.intersectsVisibleRowRange(change.start, change.end + 1) # TODO: Use closed-open intervals for change events
-
-  onSelectionChanged: (selection) ->
-    {editor} = @props
-    if editor.selectionIntersectsVisibleRowRange(selection)
-      @selectionChanged = true
-      @requestUpdate()
-
-  onSelectionAdded: (selection) ->
-    {editor} = @props
-    if editor.selectionIntersectsVisibleRowRange(selection)
-      @selectionChanged = true
-      @selectionAdded = true
-      @requestUpdate()
-
-  onScrollTopChanged: ->
-    @scrollingVertically = true
-    @requestUpdate()
-    @stopScrollingAfterDelay ?= debounce(@onStoppedScrolling, 100)
-    @stopScrollingAfterDelay()
-
-  onStoppedScrolling: ->
-    @scrollingVertically = false
-    @mouseWheelScreenRow = null
-    @requestUpdate()
-
-  stopScrollingAfterDelay: null # created lazily
-
-  onCursorsMoved: ->
-    @cursorsMoved = true
-
-  onGutterWidthChanged: (@gutterWidth) ->
-    @requestUpdate()
-
-  requestUpdate: ->
-    if @batchingUpdates
-      @updateRequested = true
-    else
-      @forceUpdate()
-
-  requestScrollViewMeasurement: ->
-    return if @measurementPending
-
-    @scrollViewMeasurementRequested = true
-    requestAnimationFrame =>
-      @scrollViewMeasurementRequested = false
-      @measureScrollView()
-
-  pauseOverflowChangedEvents: ->
-    @overflowChangedEventsPaused = true
-    @resumeOverflowChangedEventsAfterDelay ?= debounce(@resumeOverflowChangedEvents, 500)
-    @resumeOverflowChangedEventsAfterDelay()
-
-  resumeOverflowChangedEvents: ->
-    if @overflowChangedWhilePaused
-      @overflowChangedWhilePaused = false
-      @requestScrollViewMeasurement()
-
-  resumeOverflowChangedEventsAfterDelay: null
-
-  consolidateSelections: (e) ->
-    e.abortKeyBinding() unless @props.editor.consolidateSelections()
-
-  lineNodeForScreenRow: (screenRow) -> @refs.lines.lineNodeForScreenRow(screenRow)
-
-  lineNumberNodeForScreenRow: (screenRow) -> @refs.gutter.lineNumberNodeForScreenRow(screenRow)
 
   hide: ->
     @setState(visible: false)


    @selectToMousePositionUntilMouseUp(event)

  selectToMousePositionUntilMouseUp: (event) ->
    {editor} = @props
    dragging = false

  selectToMousePosition: (event) ->
    @props.editor.selectToScreenPosition(@screenPositionForMouseEvent(event))

  requestScrollViewMeasurement: ->
    return if @measurementPending

    @scrollViewMeasurementRequested = true
    requestAnimationFrame =>
      @scrollViewMeasurementRequested = false
      @measureScrollView()

  # 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
