From 8ae3761cd768414eb53c019ce8419e73895617f3 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 19 Aug 2015 11:50:14 -0600 Subject: [PATCH] Terminate selection drag on text input MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On recent versions of OS X Yosemite, there is a delay before we receive the `mouseup` event when dragging selections with the trackpad. This means that we’re frequently accidentally inserting text before the selection process terminates, leading to unexpected selections after the text insertion. This fixes that behavior and makes the behavior more straightforward even in the case where the mouse button is remains held down during text insertion. --- spec/text-editor-component-spec.coffee | 36 ++++++++++++++++++++++++++ src/text-editor-component.coffee | 9 ++++--- 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/spec/text-editor-component-spec.coffee b/spec/text-editor-component-spec.coffee index 22562032c..9f8d5dfec 100644 --- a/spec/text-editor-component-spec.coffee +++ b/spec/text-editor-component-spec.coffee @@ -1792,6 +1792,24 @@ describe "TextEditorComponent", -> expect(nextAnimationFrame).toBe noAnimationFrame expect(editor.getSelectedScreenRange()).toEqual [[2, 4], [6, 8]] + it "stops selecting if a textInput event occurs during the drag", -> + linesNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenPosition([2, 4]), which: 1)) + linesNode.dispatchEvent(buildMouseEvent('mousemove', clientCoordinatesForScreenPosition([6, 8]), which: 1)) + nextAnimationFrame() + expect(editor.getSelectedScreenRange()).toEqual [[2, 4], [6, 8]] + + inputEvent = new Event('textInput') + inputEvent.data = 'x' + Object.defineProperty(inputEvent, 'target', get: -> componentNode.querySelector('.hidden-input')) + componentNode.dispatchEvent(inputEvent) + nextAnimationFrame() + + expect(editor.getSelectedScreenRange()).toEqual [[2, 5], [2, 5]] + + linesNode.dispatchEvent(buildMouseEvent('mousemove', clientCoordinatesForScreenPosition([8, 0]), which: 1)) + expect(nextAnimationFrame).toBe noAnimationFrame + expect(editor.getSelectedScreenRange()).toEqual [[2, 5], [2, 5]] + describe "when the command key is held down", -> it "adds a new selection and selects to the nearest screen position, then merges intersecting selections when the mouse button is released", -> editor.setSelectedScreenRange([[4, 4], [4, 9]]) @@ -1979,6 +1997,24 @@ describe "TextEditorComponent", -> nextAnimationFrame() expect(editor.getScrollTop()).toBe maxScrollTop + it "stops selecting if a textInput event occurs during the drag", -> + gutterNode.dispatchEvent(buildMouseEvent('mousedown', clientCoordinatesForScreenRowInGutter(2))) + gutterNode.dispatchEvent(buildMouseEvent('mousemove', clientCoordinatesForScreenRowInGutter(6))) + nextAnimationFrame() + expect(editor.getSelectedScreenRange()).toEqual [[2, 0], [7, 0]] + + inputEvent = new Event('textInput') + inputEvent.data = 'x' + Object.defineProperty(inputEvent, 'target', get: -> componentNode.querySelector('.hidden-input')) + componentNode.dispatchEvent(inputEvent) + nextAnimationFrame() + + expect(editor.getSelectedScreenRange()).toEqual [[2, 1], [2, 1]] + + gutterNode.dispatchEvent(buildMouseEvent('mousemove', clientCoordinatesForScreenRowInGutter(12))) + expect(nextAnimationFrame).toBe noAnimationFrame + expect(editor.getSelectedScreenRange()).toEqual [[2, 1], [2, 1]] + describe "when the gutter is meta-clicked and dragged", -> beforeEach -> editor.setSelectedScreenRange([[3, 0], [3, 2]]) diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index a46b352a3..af0b71f3b 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -523,15 +523,17 @@ class TextEditorComponent onMouseUp() if event.which is 0 onMouseUp = (event) => - stopDragging() - @editor.finalizeSelections() - @editor.mergeIntersectingSelections() + if dragging + stopDragging() + @editor.finalizeSelections() + @editor.mergeIntersectingSelections() pasteSelectionClipboard(event) stopDragging = -> dragging = false window.removeEventListener('mousemove', onMouseMove) window.removeEventListener('mouseup', onMouseUp) + willInsertTextSubscription.dispose() pasteSelectionClipboard = (event) => if event?.which is 2 and process.platform is 'linux' @@ -540,6 +542,7 @@ class TextEditorComponent window.addEventListener('mousemove', onMouseMove) window.addEventListener('mouseup', onMouseUp) + willInsertTextSubscription = @editor.onWillInsertText(onMouseUp) isVisible: -> @domNode.offsetHeight > 0 or @domNode.offsetWidth > 0