diff --git a/src/core/selection.coffee b/src/core/selection.coffee index 851f0fb6f4..e2103ecbb1 100644 --- a/src/core/selection.coffee +++ b/src/core/selection.coffee @@ -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) diff --git a/src/modules/keyboard.coffee b/src/modules/keyboard.coffee index 66b6c76fd6..19d152b205 100644 --- a/src/modules/keyboard.coffee +++ b/src/modules/keyboard.coffee @@ -73,6 +73,7 @@ class Keyboard @toolbar.setActive(format, value) if @toolbar? return ) + @quill.editor.selection.scrollIntoView() return false ) @@ -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 ) diff --git a/src/modules/paste-manager.coffee b/src/modules/paste-manager.coffee index 67cd5b8177..e141d15993 100644 --- a/src/modules/paste-manager.coffee +++ b/src/modules/paste-manager.coffee @@ -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 = "" ) diff --git a/test/unit/core/selection.coffee b/test/unit/core/selection.coffee index ef48a0b182..3e46f96a70 100644 --- a/test/unit/core/selection.coffee +++ b/test/unit/core/selection.coffee @@ -324,4 +324,49 @@ describe('Selection', -> ) ) ) + + describe('scrollIntoView()', -> + beforeEach( -> + @container.innerHTML = '
a
b
c
d
' + @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) + ) + ) )