UNPKG

5.33 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
13function _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; }
14
15var UserAgent = require("fbjs/lib/UserAgent");
16
17var findAncestorOffsetKey = require("./findAncestorOffsetKey");
18
19var getWindowForNode = require("./getWindowForNode");
20
21var Immutable = require("immutable");
22
23var invariant = require("fbjs/lib/invariant");
24
25var nullthrows = require("fbjs/lib/nullthrows");
26
27var Map = Immutable.Map;
28// Heavily based on Prosemirror's DOMObserver https://github.com/ProseMirror/prosemirror-view/blob/master/src/domobserver.js
29var DOM_OBSERVER_OPTIONS = {
30 subtree: true,
31 characterData: true,
32 childList: true,
33 characterDataOldValue: false,
34 attributes: false
35}; // IE11 has very broken mutation observers, so we also listen to DOMCharacterDataModified
36
37var USE_CHAR_DATA = UserAgent.isBrowser('IE <= 11');
38
39var DOMObserver = /*#__PURE__*/function () {
40 function DOMObserver(container) {
41 var _this = this;
42
43 _defineProperty(this, "observer", void 0);
44
45 _defineProperty(this, "container", void 0);
46
47 _defineProperty(this, "mutations", void 0);
48
49 _defineProperty(this, "onCharData", void 0);
50
51 this.container = container;
52 this.mutations = Map();
53 var containerWindow = getWindowForNode(container);
54
55 if (containerWindow.MutationObserver && !USE_CHAR_DATA) {
56 this.observer = new containerWindow.MutationObserver(function (mutations) {
57 return _this.registerMutations(mutations);
58 });
59 } else {
60 this.onCharData = function (e) {
61 !(e.target instanceof Node) ? process.env.NODE_ENV !== "production" ? invariant(false, 'Expected target to be an instance of Node') : invariant(false) : void 0;
62
63 _this.registerMutation({
64 type: 'characterData',
65 target: e.target
66 });
67 };
68 }
69 }
70
71 var _proto = DOMObserver.prototype;
72
73 _proto.start = function start() {
74 if (this.observer) {
75 this.observer.observe(this.container, DOM_OBSERVER_OPTIONS);
76 } else {
77 /* $FlowFixMe[incompatible-call] (>=0.68.0 site=www,mobile) This event
78 * type is not defined by Flow's standard library */
79 this.container.addEventListener('DOMCharacterDataModified', this.onCharData);
80 }
81 };
82
83 _proto.stopAndFlushMutations = function stopAndFlushMutations() {
84 var observer = this.observer;
85
86 if (observer) {
87 this.registerMutations(observer.takeRecords());
88 observer.disconnect();
89 } else {
90 /* $FlowFixMe[incompatible-call] (>=0.68.0 site=www,mobile) This event
91 * type is not defined by Flow's standard library */
92 this.container.removeEventListener('DOMCharacterDataModified', this.onCharData);
93 }
94
95 var mutations = this.mutations;
96 this.mutations = Map();
97 return mutations;
98 };
99
100 _proto.registerMutations = function registerMutations(mutations) {
101 for (var i = 0; i < mutations.length; i++) {
102 this.registerMutation(mutations[i]);
103 }
104 };
105
106 _proto.getMutationTextContent = function getMutationTextContent(mutation) {
107 var type = mutation.type,
108 target = mutation.target,
109 removedNodes = mutation.removedNodes;
110
111 if (type === 'characterData') {
112 // When `textContent` is '', there is a race condition that makes
113 // getting the offsetKey from the target not possible.
114 // These events are also followed by a `childList`, which is the one
115 // we are able to retrieve the offsetKey and apply the '' text.
116 if (target.textContent !== '') {
117 // IE 11 considers the enter keypress that concludes the composition
118 // as an input char. This strips that newline character so the draft
119 // state does not receive spurious newlines.
120 if (USE_CHAR_DATA) {
121 return target.textContent.replace('\n', '');
122 }
123
124 return target.textContent;
125 }
126 } else if (type === 'childList') {
127 if (removedNodes && removedNodes.length) {
128 // `characterData` events won't happen or are ignored when
129 // removing the last character of a leaf node, what happens
130 // instead is a `childList` event with a `removedNodes` array.
131 // For this case the textContent should be '' and
132 // `DraftModifier.replaceText` will make sure the content is
133 // updated properly.
134 return '';
135 } else if (target.textContent !== '') {
136 // Typing Chinese in an empty block in MS Edge results in a
137 // `childList` event with non-empty textContent.
138 // See https://github.com/facebook/draft-js/issues/2082
139 return target.textContent;
140 }
141 }
142
143 return null;
144 };
145
146 _proto.registerMutation = function registerMutation(mutation) {
147 var textContent = this.getMutationTextContent(mutation);
148
149 if (textContent != null) {
150 var offsetKey = nullthrows(findAncestorOffsetKey(mutation.target));
151 this.mutations = this.mutations.set(offsetKey, textContent);
152 }
153 };
154
155 return DOMObserver;
156}();
157
158module.exports = DOMObserver;
\No newline at end of file