diff --git a/spec/text-editor-element-spec.coffee b/spec/text-editor-element-spec.coffee index 446206fe5..7ed4a106f 100644 --- a/spec/text-editor-element-spec.coffee +++ b/spec/text-editor-element-spec.coffee @@ -94,6 +94,23 @@ describe "TextEditorElement", -> document.body.focus() expect(blurCalled).toBe true + it "doesn't trigger a blur event on the editor element when focusing an already focused editor element", -> + blurCalled = false + element = new TextEditorElement + element.addEventListener 'blur', -> blurCalled = true + + jasmineContent.appendChild(element) + expect(document.activeElement).toBe(document.body) + expect(blurCalled).toBe(false) + + element.focus() + expect(document.activeElement).toBe(element.querySelector('input')) + expect(blurCalled).toBe(false) + + element.focus() + expect(document.activeElement).toBe(element.querySelector('input')) + expect(blurCalled).toBe(false) + describe "when focused while a parent node is being attached to the DOM", -> class ElementThatFocusesChild extends HTMLDivElement attachedCallback: -> diff --git a/src/text-editor-element.coffee b/src/text-editor-element.coffee index 230813cb5..99d8ed818 100644 --- a/src/text-editor-element.coffee +++ b/src/text-editor-element.coffee @@ -50,7 +50,7 @@ class TextEditorElement extends HTMLElement @mountComponent() unless @component? @listenForComponentEvents() @component.checkForVisibilityChange() - if this is document.activeElement + if @hasFocus() @focused() @emitter.emit("did-attach") @@ -121,7 +121,7 @@ class TextEditorElement extends HTMLElement @rootElement.appendChild(@component.getDomNode()) inputNode = @component.hiddenInputComponent.getDomNode() inputNode.addEventListener 'focus', @focused.bind(this) - inputNode.addEventListener 'blur', => @dispatchEvent(new FocusEvent('blur', bubbles: false)) + inputNode.addEventListener 'blur', @inputNodeBlurred.bind(this) unmountComponent: -> if @component? @@ -129,24 +129,18 @@ class TextEditorElement extends HTMLElement @component.getDomNode().remove() @component = null - focused: -> + focused: (event) -> @component?.focused() blurred: (event) -> - if event.relatedTarget is @component.hiddenInputComponent.getDomNode() + if event.relatedTarget is @component?.hiddenInputComponent.getDomNode() event.stopImmediatePropagation() return @component?.blurred() - # Work around what seems to be a bug in Chromium. Focus can be stolen from the - # hidden input when clicking on the gutter and transferred to the - # already-focused host element. The host element never gets a 'focus' event - # however, which leaves us in a limbo state where the text editor element is - # focused but the hidden input isn't focused. This always refocuses the hidden - # input if a blur event occurs in the shadow DOM that is transferring focus - # back to the host element. - # shadowRootBlurred: (event) -> - # @component.focused() if event.relatedTarget is this + inputNodeBlurred: (event) -> + if event.relatedTarget isnt this + @dispatchEvent(new FocusEvent('blur', bubbles: false)) addGrammarScopeAttribute: -> @dataset.grammar = @model.getGrammar()?.scopeName?.replace(/\./g, ' ')