       else
         textRange.moveStart(granularity, -1)
       textRange.select()
-    @selectionDidChange(null, direction)
+    @selectionObserver.tick()
+
+  # TODO: Combine with #expandSelectionInDirectionWithGranularity and add IE compatibility
+  adjustSelectionInDirectionWithGranularity: (direction, granularity) ->
+    return unless selection = getDOMSelection()
+    alter = if selection.isCollapsed then "move" else "extend"
+    selection.modify(alter, direction, granularity)
+    @selectionObserver.tick()
 
   lock: ->
     if @lockCount++ is 0

  getDOMRange = ->
    getDOMSelection()?.getRangeAt(0)

  # ClientRect position properties should be relative to the viewport,
  # but in some browsers (like mobile Safari), they're relative to the body.
  getRectTop = ->


  # Selection observer delegate

  selectionDidChange: (range, previousRange) ->
    direction = getDirectionFromDOMRanges(range, previousRange)

    if direction and @rangeWithinElement(range) and
         (domRangesHaveSameCursorPositionForDirection(range, previousRange, direction) or domSelectionIsUneditable())
      @adjustSelectionInDirectionWithGranularity(direction, "character")
    else
      @updateCurrentLocationRange()

  # Private

  updateCurrentLocationRange: (domRange = getDOMRange()) ->
    locationRange = @createLocationRangeFromDOMRange(domRange)
