diff --git a/internal_packages/composer/lib/composer-editor.jsx b/internal_packages/composer/lib/composer-editor.jsx index 42ffaacba..3ed72957b 100644 --- a/internal_packages/composer/lib/composer-editor.jsx +++ b/internal_packages/composer/lib/composer-editor.jsx @@ -136,43 +136,63 @@ class ComposerEditor extends Component { // quoted text that is visible. (as in forwarded messages.) // this.refs.contenteditable.atomicEdit( ({editor})=> { - const walker = document.createTreeWalker(editor.rootNode, NodeFilter.SHOW_TEXT); - const nodesBelowUserBody = editor.rootNode.querySelectorAll('.nylas-n1-signature, .gmail_quote, blockquote'); - - let lastNode = null; - let node = walker.nextNode(); - - while (node != null) { - let belowUserBody = false; - for (let i = 0; i < nodesBelowUserBody.length; ++i) { - if (nodesBelowUserBody[i].contains(node)) { - belowUserBody = true; - break; - } - } - if (belowUserBody) { - break; - } - lastNode = node; - node = walker.nextNode(); - } - editor.rootNode.focus(); - - if (lastNode) { - const range = document.createRange(); - range.selectNodeContents(lastNode); - range.collapse(false); - const selection = window.getSelection(); - selection.removeAllRanges(); - selection.addRange(range); - } + const lastNode = this._findLastNodeBeforeQuoteOrSignature(editor) + this._selectEndOfNode(lastNode) }); } - nativeFocus() { + _findLastNodeBeforeQuoteOrSignature(editor) { + const walker = document.createTreeWalker(editor.rootNode, NodeFilter.SHOW_TEXT); + const nodesBelowUserBody = editor.rootNode.querySelectorAll('.nylas-n1-signature, .gmail_quote, blockquote'); + + let lastNode = null; + let node = walker.nextNode(); + + while (node != null) { + let belowUserBody = false; + for (let i = 0; i < nodesBelowUserBody.length; ++i) { + if (nodesBelowUserBody[i].contains(node)) { + belowUserBody = true; + break; + } + } + if (belowUserBody) { + break; + } + lastNode = node; + node = walker.nextNode(); + } + return lastNode + } + + _findAbsoluteLastNode(editor) { + const walker = document.createTreeWalker(editor.rootNode, NodeFilter.SHOW_TEXT); + let lastNode = null; + let node = walker.nextNode(); + while (node) { + lastNode = node; + node = walker.nextNode(); + } + return lastNode; + } + + _selectEndOfNode(node) { + if (node) { + const range = document.createRange(); + range.selectNodeContents(node); + range.collapse(false); + const selection = window.getSelection(); + selection.removeAllRanges(); + selection.addRange(range); + } + } + + focusAbsoluteEnd() { this.refs.contenteditable.atomicEdit( ({editor})=> { editor.rootNode.focus(); + const lastNode = this._findAbsoluteLastNode(editor) + this._selectEndOfNode(lastNode) }); } diff --git a/internal_packages/composer/lib/composer-view.cjsx b/internal_packages/composer/lib/composer-view.cjsx index bb1cfbbdc..e9fb78244 100644 --- a/internal_packages/composer/lib/composer-view.cjsx +++ b/internal_packages/composer/lib/composer-view.cjsx @@ -334,7 +334,7 @@ class ComposerView extends React.Component onComponentDidRender={@_onEditorBodyDidRender} requiredMethods={[ 'focus' - 'nativeFocus' + 'focusAbsoluteEnd' 'getCurrentSelection' 'getPreviousSelection' '_onDOMMutated' @@ -473,7 +473,7 @@ class ComposerView extends React.Component # We don't set state directly here because we want the native # contenteditable focus behavior. When the contenteditable gets focused # the focused field state will be properly set via editor.onFocus - @refs[Fields.Body].nativeFocus() + @refs[Fields.Body].focusAbsoluteEnd() @_mouseDownTarget = null # When a user focuses the composer, it's possible that no input is