From f7428cc93ccf740d764253f602ddacc4dc61ab4e Mon Sep 17 00:00:00 2001 From: Ian Storm Taylor Date: Wed, 16 Nov 2016 17:26:12 -0800 Subject: [PATCH] fix style, refactor noop --- src/components/content.js | 61 +++++-------------------------- src/components/editor.js | 9 +---- src/components/leaf.js | 77 ++++++++++++++++++++------------------- src/components/void.js | 9 +---- src/utils/noop.js | 14 +++++++ 5 files changed, 64 insertions(+), 106 deletions(-) create mode 100644 src/utils/noop.js diff --git a/src/components/content.js b/src/components/content.js index 7957c5a60..a2eb6f4ff 100644 --- a/src/components/content.js +++ b/src/components/content.js @@ -11,6 +11,7 @@ import TYPES from '../constants/types' import getWindow from 'get-window' import includes from 'lodash/includes' import keycode from 'keycode' +import noop from '../utils/noop' import { IS_FIREFOX, IS_MAC } from '../constants/environment' /** @@ -21,45 +22,6 @@ import { IS_FIREFOX, IS_MAC } from '../constants/environment' const debug = Debug('slate:content') -/** - * Noop. - * - * @type {Function} - */ - -function noop() {} - -/** - * Find the deepest descendant of a DOM `element`. - * - * @param {Element} node - * @return {Element} - */ - -function findDeepestNode(element) { - return element.firstChild - ? findDeepestNode(element.firstChild) - : element -} - -/** - * Tests if the child is a descendant of parent. - * - * @param parent - * @param child - * @returns {boolean} - */ - -function isDescendant(parent, child) { - if (!child || !parent) return false - let node = child.parentNode - while (node != null) { - if (node == parent) return true - node = node.parentNode - } - return false -} - /** * Content. * @@ -154,8 +116,8 @@ class Content extends React.Component { } /** - * When finished rendering, move the `isRendering` flag on next tick and clean up the DOM's activeElement - * if neccessary. + * When finished rendering, move the `isRendering` flag on next tick and + * clean up the DOM's activeElement if neccessary. * * @param {Object} prevProps * @param {Object} prevState @@ -166,21 +128,16 @@ class Content extends React.Component { this.tmp.isRendering = false }, 1) - // If this component was focused last render, but is not now we might need to clean up the activeElement. + // If the state is blurred now, but was focused before, and the DOM still + // has a node inside the editor selected, we need to blur it. if (this.props.state.isBlurred && prevProps.state.isFocused) { - // Get the current selection - const ref = ReactDOM.findDOMNode(this) - const el = findDeepestNode(ref) + const el = ReactDOM.findDOMNode(this) const window = getWindow(el) const native = window.getSelection() + if (!el.contains(native.anchorNode)) return - // We need to make sure that the selection from our state is up-to-date with the native selection. - // We can do this by checking if native.anchorNode is a descendant of our this node. - if (isDescendant(ref, native.anchorNode)) { - // The selection was blurred, but the DOM selection state has not changed so we need to do this manually: - native.removeAllRanges() - if (ref) ref.blur() - } + native.removeAllRanges() + el.blur() } } diff --git a/src/components/editor.js b/src/components/editor.js index 68680b590..0c9b70c9c 100644 --- a/src/components/editor.js +++ b/src/components/editor.js @@ -6,6 +6,7 @@ import React from 'react' import Schema from '../models/schema' import State from '../models/state' import isReactComponent from '../utils/is-react-component' +import noop from '../utils/noop' import typeOf from 'type-of' /** @@ -14,14 +15,6 @@ import typeOf from 'type-of' const debug = Debug('slate:editor') -/** - * Noop. - * - * @type {Function} - */ - -function noop() {} - /** * Event handlers to mix in to the editor. * diff --git a/src/components/leaf.js b/src/components/leaf.js index 947296302..d1c24368b 100644 --- a/src/components/leaf.js +++ b/src/components/leaf.js @@ -162,9 +162,10 @@ class Leaf extends React.Component { const native = window.getSelection() const parent = ref.closest('[contenteditable]') - // In firefox it is not enough to create a range, you also need to focus the contenteditable element. + // COMPAT: In Firefox, it's not enough to create a range, you also need to + // focus the contenteditable element. (2016/11/16) function focus() { - if (parent) setTimeout(() => parent.focus(), 0) + if (parent) setTimeout(() => parent.focus()) } // If both the start and end are here, set the selection all at once. @@ -175,45 +176,45 @@ class Leaf extends React.Component { native.addRange(range) native.extend(el, focusOffset - start) focus() - return } - // If the selection is forward, we can set things in sequence. In - // the first leaf to render, reset the selection and set the new start. And - // then in the second leaf to render, extend to the new end. - if (selection.isForward) { - if (hasAnchor) { - native.removeAllRanges() - const range = window.document.createRange() - range.setStart(el, anchorOffset - start) - native.addRange(range) - focus() - } else if (hasFocus) { - native.extend(el, focusOffset - start) - focus() - } - } - - // Otherwise, if the selection is backward, we need to hack the order a bit. - // In the first leaf to render, set a phony start anchor to store the true - // end position. And then in the second leaf to render, set the start and - // extend the end to the stored value. + // Otherwise we need to set the selection across two different leaves. else { - if (hasFocus) { - native.removeAllRanges() - const range = window.document.createRange() - range.setStart(el, focusOffset - start) - native.addRange(range) - focus() - } else if (hasAnchor) { - const endNode = native.focusNode - const endOffset = native.focusOffset - native.removeAllRanges() - const range = window.document.createRange() - range.setStart(el, anchorOffset - start) - native.addRange(range) - native.extend(endNode, endOffset) - focus() + // If the selection is forward, we can set things in sequence. In the + // first leaf to render, reset the selection and set the new start. And + // then in the second leaf to render, extend to the new end. + if (selection.isForward) { + if (hasAnchor) { + native.removeAllRanges() + const range = window.document.createRange() + range.setStart(el, anchorOffset - start) + native.addRange(range) + } else if (hasFocus) { + native.extend(el, focusOffset - start) + focus() + } + } + + // Otherwise, if the selection is backward, we need to hack the order a bit. + // In the first leaf to render, set a phony start anchor to store the true + // end position. And then in the second leaf to render, set the start and + // extend the end to the stored value. + else { + if (hasFocus) { + native.removeAllRanges() + const range = window.document.createRange() + range.setStart(el, focusOffset - start) + native.addRange(range) + } else if (hasAnchor) { + const endNode = native.focusNode + const endOffset = native.focusOffset + native.removeAllRanges() + const range = window.document.createRange() + range.setStart(el, anchorOffset - start) + native.addRange(range) + native.extend(endNode, endOffset) + focus() + } } } diff --git a/src/components/void.js b/src/components/void.js index b727c35be..2abc602c4 100644 --- a/src/components/void.js +++ b/src/components/void.js @@ -5,16 +5,9 @@ import OffsetKey from '../utils/offset-key' import React from 'react' import ReactDOM from 'react-dom' import keycode from 'keycode' +import noop from '../utils/noop' import { IS_FIREFOX } from '../constants/environment' -/** - * Noop. - * - * @type {Function} - */ - -function noop() {} - /** * Void. * diff --git a/src/utils/noop.js b/src/utils/noop.js new file mode 100644 index 000000000..2ef804c31 --- /dev/null +++ b/src/utils/noop.js @@ -0,0 +1,14 @@ + +/** + * Noop. + * + * @return {Undefined} + */ + +function noop() {} + +/** + * Export. + */ + +export default noop