/** * Copyright (c) 2013-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * * @providesModule DraftEditorContentsExperimental.react * @format * * * This file is a fork of DraftEditorContents.react.js for tree nodes * * This is unstable and not part of the public API and should not be used by * production systems. This file may be update/removed without notice. */ 'use strict'; var _assign = require('object-assign'); var _extends = _assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } var DraftEditorBlockNode = require('./DraftEditorBlockNode.react'); var DraftOffsetKey = require('./DraftOffsetKey'); var EditorState = require('./EditorState'); var React = require('react'); var nullthrows = require('fbjs/lib/nullthrows'); /** * `DraftEditorContents` is the container component for all block components * rendered for a `DraftEditor`. It is optimized to aggressively avoid * re-rendering blocks whenever possible. * * This component is separate from `DraftEditor` because certain props * (for instance, ARIA props) must be allowed to update without affecting * the contents of the editor. */ var DraftEditorContentsExperimental = function (_React$Component) { _inherits(DraftEditorContentsExperimental, _React$Component); function DraftEditorContentsExperimental() { _classCallCheck(this, DraftEditorContentsExperimental); return _possibleConstructorReturn(this, _React$Component.apply(this, arguments)); } DraftEditorContentsExperimental.prototype.shouldComponentUpdate = function shouldComponentUpdate(nextProps) { var prevEditorState = this.props.editorState; var nextEditorState = nextProps.editorState; var prevDirectionMap = prevEditorState.getDirectionMap(); var nextDirectionMap = nextEditorState.getDirectionMap(); // Text direction has changed for one or more blocks. We must re-render. if (prevDirectionMap !== nextDirectionMap) { return true; } var didHaveFocus = prevEditorState.getSelection().getHasFocus(); var nowHasFocus = nextEditorState.getSelection().getHasFocus(); if (didHaveFocus !== nowHasFocus) { return true; } var nextNativeContent = nextEditorState.getNativelyRenderedContent(); var wasComposing = prevEditorState.isInCompositionMode(); var nowComposing = nextEditorState.isInCompositionMode(); // If the state is unchanged or we're currently rendering a natively // rendered state, there's nothing new to be done. if (prevEditorState === nextEditorState || nextNativeContent !== null && nextEditorState.getCurrentContent() === nextNativeContent || wasComposing && nowComposing) { return false; } var prevContent = prevEditorState.getCurrentContent(); var nextContent = nextEditorState.getCurrentContent(); var prevDecorator = prevEditorState.getDecorator(); var nextDecorator = nextEditorState.getDecorator(); return wasComposing !== nowComposing || prevContent !== nextContent || prevDecorator !== nextDecorator || nextEditorState.mustForceSelection(); }; DraftEditorContentsExperimental.prototype.render = function render() { var _props = this.props, blockRenderMap = _props.blockRenderMap, blockRendererFn = _props.blockRendererFn, blockStyleFn = _props.blockStyleFn, customStyleMap = _props.customStyleMap, customStyleFn = _props.customStyleFn, editorState = _props.editorState, editorKey = _props.editorKey, textDirectionality = _props.textDirectionality; var content = editorState.getCurrentContent(); var selection = editorState.getSelection(); var forceSelection = editorState.mustForceSelection(); var decorator = editorState.getDecorator(); var directionMap = nullthrows(editorState.getDirectionMap()); var blocksAsArray = content.getBlocksAsArray(); var rootBlock = blocksAsArray[0]; var processedBlocks = []; var nodeBlock = rootBlock; while (nodeBlock) { var blockKey = nodeBlock.getKey(); var blockProps = { blockRenderMap: blockRenderMap, blockRendererFn: blockRendererFn, blockStyleFn: blockStyleFn, contentState: content, customStyleFn: customStyleFn, customStyleMap: customStyleMap, decorator: decorator, editorKey: editorKey, editorState: editorState, forceSelection: forceSelection, selection: selection, block: nodeBlock, direction: textDirectionality ? textDirectionality : directionMap.get(blockKey), tree: editorState.getBlockTree(blockKey) }; var configForType = blockRenderMap.get(nodeBlock.getType()) || blockRenderMap.get('unstyled'); var wrapperTemplate = configForType.wrapper; processedBlocks.push({ block: React.createElement(DraftEditorBlockNode, _extends({ key: blockKey }, blockProps)), wrapperTemplate: wrapperTemplate, key: blockKey, offsetKey: DraftOffsetKey.encode(blockKey, 0, 0) }); var nextBlockKey = nodeBlock.getNextSiblingKey(); nodeBlock = nextBlockKey ? content.getBlockForKey(nextBlockKey) : null; } // Group contiguous runs of blocks that have the same wrapperTemplate var outputBlocks = []; for (var ii = 0; ii < processedBlocks.length;) { var info = processedBlocks[ii]; if (info.wrapperTemplate) { var blocks = []; do { blocks.push(processedBlocks[ii].block); ii++; } while (ii < processedBlocks.length && processedBlocks[ii].wrapperTemplate === info.wrapperTemplate); var wrapperElement = React.cloneElement(info.wrapperTemplate, { key: info.key + '-wrap', 'data-offset-key': info.offsetKey }, blocks); outputBlocks.push(wrapperElement); } else { outputBlocks.push(info.block); ii++; } } return React.createElement( 'div', { 'data-contents': 'true' }, outputBlocks ); }; return DraftEditorContentsExperimental; }(React.Component); module.exports = DraftEditorContentsExperimental;