From 192e7c6b637420714376fb171504cbfbf465c365 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 28 Feb 2017 20:17:53 -0700 Subject: [PATCH] Handle direct focus of hidden input and avoid redundant focus renders --- spec/text-editor-component-spec.js | 12 ++++++++++- src/text-editor-component.js | 33 +++++++++++++++++++++--------- 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/spec/text-editor-component-spec.js b/spec/text-editor-component-spec.js index ba068fa75..9892a4c1e 100644 --- a/spec/text-editor-component-spec.js +++ b/spec/text-editor-component-spec.js @@ -197,7 +197,6 @@ describe('TextEditorComponent', () => { element.focus() // focusing back to the element does not blur expect(document.activeElement).toBe(hiddenInput) - await component.getNextUpdatePromise() expect(element.classList.contains('is-focused')).toBe(true) document.body.focus() @@ -206,6 +205,17 @@ describe('TextEditorComponent', () => { expect(element.classList.contains('is-focused')).toBe(false) }) + it('updates the component when the hidden input is focused directly', async () => { + const {component, element, editor} = buildComponent() + const {hiddenInput} = component.refs + expect(element.classList.contains('is-focused')).toBe(false) + expect(document.activeElement).not.toBe(hiddenInput) + + hiddenInput.focus() + await component.getNextUpdatePromise() + expect(element.classList.contains('is-focused')).toBe(true) + }) + it('gracefully handles a focus event that occurs prior to the attachedCallback of the element', () => { const {component, element, editor} = buildComponent({attach: false}) const parent = document.createElement('text-editor-component-test-element') diff --git a/src/text-editor-component.js b/src/text-editor-component.js index cbee96c94..1b85025f5 100644 --- a/src/text-editor-component.js +++ b/src/text-editor-component.js @@ -383,7 +383,8 @@ class TextEditorComponent { key: 'hiddenInput', className: 'hidden-input', on: { - blur: this.didBlur, + blur: this.didBlurHiddenInput, + focus: this.didFocusHiddenInput, textInput: this.didTextInput, keydown: this.didKeydown, keyup: this.didKeyup, @@ -496,17 +497,22 @@ class TextEditorComponent { // against that case. if (!this.attached) this.didAttach() - const {hiddenInput} = this.refs + if (!this.focused) { + this.focused = true + this.scheduleUpdate() + } - // Ensure the input is in the visible part of the scrolled content to avoid - // the browser trying to auto-scroll to the form-field. + // Transfer focus to the hidden input, but first ensure the input is in the + // visible part of the scrolled content to avoid the browser trying to + // auto-scroll to the form-field. + const {hiddenInput} = this.refs hiddenInput.style.top = this.getScrollTop() + 'px' hiddenInput.style.left = this.getScrollLeft() + 'px' hiddenInput.focus() - this.focused = true - // Restore the previous position of the field now that it is focused. + // Restore the previous position of the field now that it is already focused + // and won't cause unwanted scrolling. const currentHiddenInputState = this.getHiddenInputState() if (currentHiddenInputState) { hiddenInput.style.top = currentHiddenInputState.pixelTop + 'px' @@ -515,19 +521,26 @@ class TextEditorComponent { hiddenInput.style.top = 0 hiddenInput.style.left = 0 } - - this.scheduleUpdate() } - didBlur (event) { + didBlurHiddenInput (event) { if (this.element !== event.relatedTarget && !this.element.contains(event.relatedTarget)) { + console.log('blur hi'); this.focused = false this.scheduleUpdate() } } + didFocusHiddenInput () { + if (!this.focused) { + console.log('focus hi'); + this.focused = true + this.scheduleUpdate() + } + } + didScroll () { - if (this.measureScrollPosition()) { + if (this.measureScrollPosition(true)) { this.updateSync() } }