UNPKG

8.8 kBJavaScriptView Raw
1/**
2 * Copyright (c) Facebook, Inc. and its affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 *
7 * @format
8 *
9 * @emails oncall+draft_js
10 */
11'use strict';
12
13var _assign = require("object-assign");
14
15function _extends() { _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; }; return _extends.apply(this, arguments); }
16
17function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
18
19function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }
20
21function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
22
23var DraftEditorLeaf = require("./DraftEditorLeaf.react");
24
25var DraftOffsetKey = require("./DraftOffsetKey");
26
27var React = require("react");
28
29var Scroll = require("fbjs/lib/Scroll");
30
31var Style = require("fbjs/lib/Style");
32
33var UnicodeBidi = require("fbjs/lib/UnicodeBidi");
34
35var UnicodeBidiDirection = require("fbjs/lib/UnicodeBidiDirection");
36
37var cx = require("fbjs/lib/cx");
38
39var getElementPosition = require("fbjs/lib/getElementPosition");
40
41var getScrollPosition = require("fbjs/lib/getScrollPosition");
42
43var getViewportDimensions = require("fbjs/lib/getViewportDimensions");
44
45var invariant = require("fbjs/lib/invariant");
46
47var isHTMLElement = require("./isHTMLElement");
48
49var nullthrows = require("fbjs/lib/nullthrows");
50
51var SCROLL_BUFFER = 10;
52
53/**
54 * Return whether a block overlaps with either edge of the `SelectionState`.
55 */
56var isBlockOnSelectionEdge = function isBlockOnSelectionEdge(selection, key) {
57 return selection.getAnchorKey() === key || selection.getFocusKey() === key;
58};
59/**
60 * The default block renderer for a `DraftEditor` component.
61 *
62 * A `DraftEditorBlock` is able to render a given `ContentBlock` to its
63 * appropriate decorator and inline style components.
64 */
65
66
67var DraftEditorBlock = /*#__PURE__*/function (_React$Component) {
68 _inheritsLoose(DraftEditorBlock, _React$Component);
69
70 function DraftEditorBlock() {
71 var _this;
72
73 for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
74 args[_key] = arguments[_key];
75 }
76
77 _this = _React$Component.call.apply(_React$Component, [this].concat(args)) || this;
78
79 _defineProperty(_assertThisInitialized(_this), "_node", void 0);
80
81 return _this;
82 }
83
84 var _proto = DraftEditorBlock.prototype;
85
86 _proto.shouldComponentUpdate = function shouldComponentUpdate(nextProps) {
87 return this.props.block !== nextProps.block || this.props.tree !== nextProps.tree || this.props.direction !== nextProps.direction || isBlockOnSelectionEdge(nextProps.selection, nextProps.block.getKey()) && nextProps.forceSelection;
88 }
89 /**
90 * When a block is mounted and overlaps the selection state, we need to make
91 * sure that the cursor is visible to match native behavior. This may not
92 * be the case if the user has pressed `RETURN` or pasted some content, since
93 * programmatically creating these new blocks and setting the DOM selection
94 * will miss out on the browser natively scrolling to that position.
95 *
96 * To replicate native behavior, if the block overlaps the selection state
97 * on mount, force the scroll position. Check the scroll state of the scroll
98 * parent, and adjust it to align the entire block to the bottom of the
99 * scroll parent.
100 */
101 ;
102
103 _proto.componentDidMount = function componentDidMount() {
104 if (this.props.preventScroll) {
105 return;
106 }
107
108 var selection = this.props.selection;
109 var endKey = selection.getEndKey();
110
111 if (!selection.getHasFocus() || endKey !== this.props.block.getKey()) {
112 return;
113 }
114
115 var blockNode = this._node;
116
117 if (blockNode == null) {
118 return;
119 }
120
121 var scrollParent = Style.getScrollParent(blockNode);
122 var scrollPosition = getScrollPosition(scrollParent);
123 var scrollDelta;
124
125 if (scrollParent === window) {
126 var nodePosition = getElementPosition(blockNode);
127 var nodeBottom = nodePosition.y + nodePosition.height;
128 var viewportHeight = getViewportDimensions().height;
129 scrollDelta = nodeBottom - viewportHeight;
130
131 if (scrollDelta > 0) {
132 window.scrollTo(scrollPosition.x, scrollPosition.y + scrollDelta + SCROLL_BUFFER);
133 }
134 } else {
135 !isHTMLElement(blockNode) ? process.env.NODE_ENV !== "production" ? invariant(false, 'blockNode is not an HTMLElement') : invariant(false) : void 0;
136 var blockBottom = blockNode.offsetHeight + blockNode.offsetTop;
137 var pOffset = scrollParent.offsetTop + scrollParent.offsetHeight;
138 var scrollBottom = pOffset + scrollPosition.y;
139 scrollDelta = blockBottom - scrollBottom;
140
141 if (scrollDelta > 0) {
142 Scroll.setTop(scrollParent, Scroll.getTop(scrollParent) + scrollDelta + SCROLL_BUFFER);
143 }
144 }
145 };
146
147 _proto._renderChildren = function _renderChildren() {
148 var _this2 = this;
149
150 var block = this.props.block;
151 var blockKey = block.getKey();
152 var text = block.getText();
153 var lastLeafSet = this.props.tree.size - 1;
154 var hasSelection = isBlockOnSelectionEdge(this.props.selection, blockKey);
155 return this.props.tree.map(function (leafSet, ii) {
156 var leavesForLeafSet = leafSet.get('leaves'); // T44088704
157
158 if (leavesForLeafSet.size === 0) {
159 return null;
160 }
161
162 var lastLeaf = leavesForLeafSet.size - 1;
163 var leaves = leavesForLeafSet.map(function (leaf, jj) {
164 var offsetKey = DraftOffsetKey.encode(blockKey, ii, jj);
165 var start = leaf.get('start');
166 var end = leaf.get('end');
167 return React.createElement(DraftEditorLeaf, {
168 key: offsetKey,
169 offsetKey: offsetKey,
170 block: block,
171 start: start,
172 selection: hasSelection ? _this2.props.selection : null,
173 forceSelection: _this2.props.forceSelection,
174 text: text.slice(start, end),
175 styleSet: block.getInlineStyleAt(start),
176 customStyleMap: _this2.props.customStyleMap,
177 customStyleFn: _this2.props.customStyleFn,
178 isLast: ii === lastLeafSet && jj === lastLeaf
179 });
180 }).toArray();
181 var decoratorKey = leafSet.get('decoratorKey');
182
183 if (decoratorKey == null) {
184 return leaves;
185 }
186
187 if (!_this2.props.decorator) {
188 return leaves;
189 }
190
191 var decorator = nullthrows(_this2.props.decorator);
192 var DecoratorComponent = decorator.getComponentForKey(decoratorKey);
193
194 if (!DecoratorComponent) {
195 return leaves;
196 }
197
198 var decoratorProps = decorator.getPropsForKey(decoratorKey);
199 var decoratorOffsetKey = DraftOffsetKey.encode(blockKey, ii, 0);
200 var start = leavesForLeafSet.first().get('start');
201 var end = leavesForLeafSet.last().get('end');
202 var decoratedText = text.slice(start, end);
203 var entityKey = block.getEntityAt(leafSet.get('start')); // Resetting dir to the same value on a child node makes Chrome/Firefox
204 // confused on cursor movement. See http://jsfiddle.net/d157kLck/3/
205
206 var dir = UnicodeBidiDirection.getHTMLDirIfDifferent(UnicodeBidi.getDirection(decoratedText), _this2.props.direction);
207 var commonProps = {
208 contentState: _this2.props.contentState,
209 decoratedText: decoratedText,
210 dir: dir,
211 start: start,
212 end: end,
213 blockKey: blockKey,
214 entityKey: entityKey,
215 offsetKey: decoratorOffsetKey
216 };
217 return React.createElement(DecoratorComponent, _extends({}, decoratorProps, commonProps, {
218 key: decoratorOffsetKey
219 }), leaves);
220 }).toArray();
221 };
222
223 _proto.render = function render() {
224 var _this3 = this;
225
226 var _this$props = this.props,
227 direction = _this$props.direction,
228 offsetKey = _this$props.offsetKey;
229 var className = cx({
230 'public/DraftStyleDefault/block': true,
231 'public/DraftStyleDefault/ltr': direction === 'LTR',
232 'public/DraftStyleDefault/rtl': direction === 'RTL'
233 });
234 return React.createElement("div", {
235 "data-offset-key": offsetKey,
236 className: className,
237 ref: function ref(_ref) {
238 return _this3._node = _ref;
239 }
240 }, this._renderChildren());
241 };
242
243 return DraftEditorBlock;
244}(React.Component);
245
246module.exports = DraftEditorBlock;
\No newline at end of file