Skip to content

Commit

Permalink
Scrolls to cursor if not visible after enter/deletion/paste, fixing i…
Browse files Browse the repository at this point in the history
…ssue #433
  • Loading branch information
emannes authored and jhchen committed Nov 10, 2015
1 parent dec48b7 commit 846ffd8
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 4 deletions.
14 changes: 14 additions & 0 deletions src/core/selection.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,20 @@ class Selection
else
fn()

scrollIntoView: () ->
return unless @range
editor = @emitter.editor
startBounds = editor.getBounds(@range.start)
endBounds = if @range.isCollapsed() then startBounds else editor.getBounds(@range.end)
containerBounds = editor.root.parentNode.getBoundingClientRect()
containerHeight = containerBounds.bottom - containerBounds.top
if containerHeight < endBounds.top + endBounds.height
[line, offset] = editor.doc.findLineAt(@range.end)
line.node.scrollIntoView(false)
else if startBounds.top < 0
[line, offset] = editor.doc.findLineAt(@range.start)
line.node.scrollIntoView()

setRange: (range, source) ->
if range?
[startNode, startOffset] = this._indexToPosition(range.start)
Expand Down
2 changes: 2 additions & 0 deletions src/modules/keyboard.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ class Keyboard
@toolbar.setActive(format, value) if @toolbar?
return
)
@quill.editor.selection.scrollIntoView()
return false
)

Expand All @@ -91,6 +92,7 @@ class Keyboard
@quill.deleteText(range.start - 1, range.start, Quill.sources.USER)
else if range.start < @quill.getLength() - 1
@quill.deleteText(range.start, range.start + 1, Quill.sources.USER)
@quill.editor.selection.scrollIntoView()
return false
)

Expand Down
5 changes: 1 addition & 4 deletions src/modules/paste-manager.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,7 @@ class PasteManager
@quill.updateContents(delta, 'user')
@quill.setSelection(range.start + lengthAdded, range.start + lengthAdded)
# Make sure bottom of pasted content is visible
[line, offset] = @quill.editor.doc.findLineAt(range.start + lengthAdded)
lineBottom = line.node.getBoundingClientRect().bottom
windowBottom = document.documentElement.clientHeight
line.node.scrollIntoView(false) if lineBottom > windowBottom
@quill.editor.selection.scrollIntoView()
@container.innerHTML = ""
)

Expand Down
45 changes: 45 additions & 0 deletions test/unit/core/selection.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -324,4 +324,49 @@ describe('Selection', ->
)
)
)

describe('scrollIntoView()', ->
beforeEach( ->
@container.innerHTML = '<div><span style="font-size: 36px;">a<br>b<br>c<br>d</span></div>'
@quill = new Quill(@container.firstChild)
@editor = @quill.editor
@selection = @editor.selection
@height = 80
@editor.root.parentNode.style.height = @height.toString() + "px"
@editor.root.parentNode.style.overflow = "auto"
)

it('scrolls down when cursor too low', ->
@selection.setRange(new Quill.Lib.Range(7, 7))
bounds = @editor.getBounds(7)
expect(bounds.top).toBeGreaterThan(@height)
@selection.scrollIntoView()
bounds = @editor.getBounds(7)
expect(bounds.top).not.toBeLessThan(0)
expect(bounds.top + bounds.height).not.toBeGreaterThan(@height)
)

it('scrolls up when cursor too high', ->
@selection.setRange(new Quill.Lib.Range(1, 1))
@editor.root.parentNode.scrollTop = 100
bounds = @editor.getBounds(1)
expect(bounds.top + bounds.height).toBeLessThan(0)
@selection.scrollIntoView()
bounds = @editor.getBounds(1)
expect(bounds.top).not.toBeLessThan(0)
expect(bounds.top + bounds.height).not.toBeGreaterThan(@height)
)

it('does not scroll if cursor in view', ->
@selection.setRange(new Quill.Lib.Range(1, 1))
bounds = @editor.getBounds(1)
expect(bounds.top).not.toBeLessThan(0)
expect(bounds.top + bounds.height).not.toBeGreaterThan(@height)
@selection.scrollIntoView()
newBounds = @editor.getBounds(1)
expect(bounds.top).toBeApproximately(newBounds.top, 1)
expect(bounds.height).toBeApproximately(newBounds.height, 1)
expect(bounds.left).toBeApproximately(newBounds.left, 1)
)
)
)

0 comments on commit 846ffd8

Please sign in to comment.