1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 | 'use strict';
|
12 |
|
13 | var DraftEffects = require("./DraftEffects");
|
14 |
|
15 | var DraftJsDebugLogging = require("./DraftJsDebugLogging");
|
16 |
|
17 | var UserAgent = require("fbjs/lib/UserAgent");
|
18 |
|
19 | var containsNode = require("fbjs/lib/containsNode");
|
20 |
|
21 | var getActiveElement = require("fbjs/lib/getActiveElement");
|
22 |
|
23 | var getCorrectDocumentFromNode = require("./getCorrectDocumentFromNode");
|
24 |
|
25 | var invariant = require("fbjs/lib/invariant");
|
26 |
|
27 | var isElement = require("./isElement");
|
28 |
|
29 | var isIE = UserAgent.isBrowser('IE');
|
30 |
|
31 | function getAnonymizedDOM(node, getNodeLabels) {
|
32 | if (!node) {
|
33 | return '[empty]';
|
34 | }
|
35 |
|
36 | var anonymized = anonymizeTextWithin(node, getNodeLabels);
|
37 |
|
38 | if (anonymized.nodeType === Node.TEXT_NODE) {
|
39 | return anonymized.textContent;
|
40 | }
|
41 |
|
42 | !isElement(anonymized) ? process.env.NODE_ENV !== "production" ? invariant(false, 'Node must be an Element if it is not a text node.') : invariant(false) : void 0;
|
43 | var castedElement = anonymized;
|
44 | return castedElement.outerHTML;
|
45 | }
|
46 |
|
47 | function anonymizeTextWithin(node, getNodeLabels) {
|
48 | var labels = getNodeLabels !== undefined ? getNodeLabels(node) : [];
|
49 |
|
50 | if (node.nodeType === Node.TEXT_NODE) {
|
51 | var length = node.textContent.length;
|
52 | return getCorrectDocumentFromNode(node).createTextNode('[text ' + length + (labels.length ? ' | ' + labels.join(', ') : '') + ']');
|
53 | }
|
54 |
|
55 | var clone = node.cloneNode();
|
56 |
|
57 | if (clone.nodeType === 1 && labels.length) {
|
58 | clone.setAttribute('data-labels', labels.join(', '));
|
59 | }
|
60 |
|
61 | var childNodes = node.childNodes;
|
62 |
|
63 | for (var ii = 0; ii < childNodes.length; ii++) {
|
64 | clone.appendChild(anonymizeTextWithin(childNodes[ii], getNodeLabels));
|
65 | }
|
66 |
|
67 | return clone;
|
68 | }
|
69 |
|
70 | function getAnonymizedEditorDOM(node, getNodeLabels) {
|
71 |
|
72 | var currentNode = node;
|
73 |
|
74 | var castedNode = currentNode;
|
75 |
|
76 | while (currentNode) {
|
77 | if (isElement(currentNode) && castedNode.hasAttribute('contenteditable')) {
|
78 |
|
79 | return getAnonymizedDOM(currentNode, getNodeLabels);
|
80 | } else {
|
81 | currentNode = currentNode.parentNode;
|
82 | castedNode = currentNode;
|
83 | }
|
84 | }
|
85 |
|
86 | return 'Could not find contentEditable parent of node';
|
87 | }
|
88 |
|
89 | function getNodeLength(node) {
|
90 | return node.nodeValue === null ? node.childNodes.length : node.nodeValue.length;
|
91 | }
|
92 |
|
93 |
|
94 |
|
95 |
|
96 |
|
97 |
|
98 |
|
99 |
|
100 |
|
101 |
|
102 |
|
103 | function setDraftEditorSelection(selectionState, node, blockKey, nodeStart, nodeEnd) {
|
104 |
|
105 |
|
106 |
|
107 | var documentObject = getCorrectDocumentFromNode(node);
|
108 |
|
109 | if (!containsNode(documentObject.documentElement, node)) {
|
110 | return;
|
111 | }
|
112 |
|
113 | var selection = documentObject.defaultView.getSelection();
|
114 | var anchorKey = selectionState.getAnchorKey();
|
115 | var anchorOffset = selectionState.getAnchorOffset();
|
116 | var focusKey = selectionState.getFocusKey();
|
117 | var focusOffset = selectionState.getFocusOffset();
|
118 | var isBackward = selectionState.getIsBackward();
|
119 |
|
120 | if (!selection.extend && isBackward) {
|
121 | var tempKey = anchorKey;
|
122 | var tempOffset = anchorOffset;
|
123 | anchorKey = focusKey;
|
124 | anchorOffset = focusOffset;
|
125 | focusKey = tempKey;
|
126 | focusOffset = tempOffset;
|
127 | isBackward = false;
|
128 | }
|
129 |
|
130 | var hasAnchor = anchorKey === blockKey && nodeStart <= anchorOffset && nodeEnd >= anchorOffset;
|
131 | var hasFocus = focusKey === blockKey && nodeStart <= focusOffset && nodeEnd >= focusOffset;
|
132 |
|
133 |
|
134 | if (hasAnchor && hasFocus) {
|
135 | selection.removeAllRanges();
|
136 | addPointToSelection(selection, node, anchorOffset - nodeStart, selectionState);
|
137 | addFocusToSelection(selection, node, focusOffset - nodeStart, selectionState);
|
138 | return;
|
139 | }
|
140 |
|
141 | if (!isBackward) {
|
142 |
|
143 | if (hasAnchor) {
|
144 | selection.removeAllRanges();
|
145 | addPointToSelection(selection, node, anchorOffset - nodeStart, selectionState);
|
146 | }
|
147 |
|
148 |
|
149 |
|
150 |
|
151 | if (hasFocus) {
|
152 | addFocusToSelection(selection, node, focusOffset - nodeStart, selectionState);
|
153 | }
|
154 | } else {
|
155 |
|
156 |
|
157 |
|
158 | if (hasFocus) {
|
159 | selection.removeAllRanges();
|
160 | addPointToSelection(selection, node, focusOffset - nodeStart, selectionState);
|
161 | }
|
162 |
|
163 |
|
164 |
|
165 |
|
166 |
|
167 | if (hasAnchor) {
|
168 | var storedFocusNode = selection.focusNode;
|
169 | var storedFocusOffset = selection.focusOffset;
|
170 | selection.removeAllRanges();
|
171 | addPointToSelection(selection, node, anchorOffset - nodeStart, selectionState);
|
172 | addFocusToSelection(selection, storedFocusNode, storedFocusOffset, selectionState);
|
173 | }
|
174 | }
|
175 | }
|
176 |
|
177 |
|
178 |
|
179 |
|
180 |
|
181 | function addFocusToSelection(selection, node, offset, selectionState) {
|
182 | var activeElement = getActiveElement();
|
183 | var extend = selection.extend;
|
184 |
|
185 |
|
186 | if (extend && node != null && containsNode(activeElement, node)) {
|
187 |
|
188 |
|
189 |
|
190 |
|
191 |
|
192 |
|
193 | if (offset > getNodeLength(node)) {
|
194 |
|
195 | DraftJsDebugLogging.logSelectionStateFailure({
|
196 | anonymizedDom: getAnonymizedEditorDOM(node),
|
197 | extraParams: JSON.stringify({
|
198 | offset: offset
|
199 | }),
|
200 | selectionState: JSON.stringify(selectionState.toJS())
|
201 | });
|
202 | }
|
203 |
|
204 |
|
205 | var nodeWasFocus = node === selection.focusNode;
|
206 |
|
207 | try {
|
208 |
|
209 |
|
210 |
|
211 | if (selection.rangeCount > 0 && selection.extend) {
|
212 | selection.extend(node, offset);
|
213 | }
|
214 | } catch (e) {
|
215 | DraftJsDebugLogging.logSelectionStateFailure({
|
216 | anonymizedDom: getAnonymizedEditorDOM(node, function (n) {
|
217 | var labels = [];
|
218 |
|
219 | if (n === activeElement) {
|
220 | labels.push('active element');
|
221 | }
|
222 |
|
223 | if (n === selection.anchorNode) {
|
224 | labels.push('selection anchor node');
|
225 | }
|
226 |
|
227 | if (n === selection.focusNode) {
|
228 | labels.push('selection focus node');
|
229 | }
|
230 |
|
231 | return labels;
|
232 | }),
|
233 | extraParams: JSON.stringify({
|
234 | activeElementName: activeElement ? activeElement.nodeName : null,
|
235 | nodeIsFocus: node === selection.focusNode,
|
236 | nodeWasFocus: nodeWasFocus,
|
237 | selectionRangeCount: selection.rangeCount,
|
238 | selectionAnchorNodeName: selection.anchorNode ? selection.anchorNode.nodeName : null,
|
239 | selectionAnchorOffset: selection.anchorOffset,
|
240 | selectionFocusNodeName: selection.focusNode ? selection.focusNode.nodeName : null,
|
241 | selectionFocusOffset: selection.focusOffset,
|
242 | message: e ? '' + e : null,
|
243 | offset: offset
|
244 | }, null, 2),
|
245 | selectionState: JSON.stringify(selectionState.toJS(), null, 2)
|
246 | });
|
247 |
|
248 |
|
249 | throw e;
|
250 | }
|
251 | } else {
|
252 |
|
253 |
|
254 |
|
255 |
|
256 |
|
257 | if (node && selection.rangeCount > 0) {
|
258 | var range = selection.getRangeAt(0);
|
259 | range.setEnd(node, offset);
|
260 | selection.addRange(range.cloneRange());
|
261 | }
|
262 | }
|
263 | }
|
264 |
|
265 | function addPointToSelection(selection, node, offset, selectionState) {
|
266 | var range = getCorrectDocumentFromNode(node).createRange();
|
267 |
|
268 | if (offset > getNodeLength(node)) {
|
269 |
|
270 | DraftJsDebugLogging.logSelectionStateFailure({
|
271 | anonymizedDom: getAnonymizedEditorDOM(node),
|
272 | extraParams: JSON.stringify({
|
273 | offset: offset
|
274 | }),
|
275 | selectionState: JSON.stringify(selectionState.toJS())
|
276 | });
|
277 | DraftEffects.handleExtensionCausedError();
|
278 | }
|
279 |
|
280 | range.setStart(node, offset);
|
281 |
|
282 | if (isIE) {
|
283 | try {
|
284 | selection.addRange(range);
|
285 | } catch (e) {
|
286 | if (process.env.NODE_ENV !== "production") {
|
287 |
|
288 | console.warn('Call to selection.addRange() threw exception: ', e);
|
289 | }
|
290 | }
|
291 | } else {
|
292 | selection.addRange(range);
|
293 | }
|
294 | }
|
295 |
|
296 | module.exports = {
|
297 | setDraftEditorSelection: setDraftEditorSelection,
|
298 | addFocusToSelection: addFocusToSelection
|
299 | }; |
\ | No newline at end of file |