@atlaskit/editor-core 188.8.0 → 188.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/dist/cjs/composable-editor/editor-internal.js +2 -2
- package/dist/cjs/create-editor/ReactEditorView.js +796 -8
- package/dist/cjs/labs/next/presets/universal.js +7 -4
- package/dist/cjs/plugins/index.js +0 -21
- package/dist/cjs/version-wrapper.js +1 -1
- package/dist/es2019/composable-editor/editor-internal.js +1 -1
- package/dist/es2019/create-editor/ReactEditorView.js +753 -2
- package/dist/es2019/labs/next/presets/universal.js +4 -1
- package/dist/es2019/plugins/index.js +0 -3
- package/dist/es2019/version-wrapper.js +1 -1
- package/dist/esm/composable-editor/editor-internal.js +1 -1
- package/dist/esm/create-editor/ReactEditorView.js +797 -8
- package/dist/esm/labs/next/presets/universal.js +4 -1
- package/dist/esm/plugins/index.js +0 -3
- package/dist/esm/version-wrapper.js +1 -1
- package/dist/types/create-editor/ReactEditorView.d.ts +119 -5
- package/dist/types/plugins/index.d.ts +0 -3
- package/dist/types/plugins/insert-block/types.d.ts +1 -1
- package/dist/types/plugins/view-update-subscription/subscribe/toolbarAndPickerUpdates.d.ts +1 -1
- package/dist/types-ts4.5/create-editor/ReactEditorView.d.ts +119 -5
- package/dist/types-ts4.5/plugins/index.d.ts +0 -3
- package/dist/types-ts4.5/plugins/insert-block/types.d.ts +1 -1
- package/dist/types-ts4.5/plugins/view-update-subscription/subscribe/toolbarAndPickerUpdates.d.ts +1 -1
- package/package.json +5 -3
- package/dist/cjs/create-editor/ReactEditorViewInternal.js +0 -812
- package/dist/cjs/create-editor/ReactEditorViewNext.js +0 -15
- package/dist/cjs/plugins/save-on-enter/index.js +0 -70
- package/dist/cjs/plugins/scroll-into-view/index.js +0 -55
- package/dist/cjs/plugins/status/actions.js +0 -158
- package/dist/cjs/plugins/status/analytics.js +0 -31
- package/dist/cjs/plugins/status/index.js +0 -143
- package/dist/cjs/plugins/status/keymap.js +0 -22
- package/dist/cjs/plugins/status/nodeviews/status.js +0 -58
- package/dist/cjs/plugins/status/plugin-key.js +0 -9
- package/dist/cjs/plugins/status/plugin.js +0 -133
- package/dist/cjs/plugins/status/types.js +0 -5
- package/dist/cjs/plugins/status/ui/statusPicker.js +0 -314
- package/dist/cjs/plugins/status/utils.js +0 -22
- package/dist/es2019/create-editor/ReactEditorViewInternal.js +0 -753
- package/dist/es2019/create-editor/ReactEditorViewNext.js +0 -7
- package/dist/es2019/plugins/save-on-enter/index.js +0 -63
- package/dist/es2019/plugins/scroll-into-view/index.js +0 -44
- package/dist/es2019/plugins/status/actions.js +0 -144
- package/dist/es2019/plugins/status/analytics.js +0 -18
- package/dist/es2019/plugins/status/index.js +0 -135
- package/dist/es2019/plugins/status/keymap.js +0 -13
- package/dist/es2019/plugins/status/nodeviews/status.js +0 -60
- package/dist/es2019/plugins/status/plugin-key.js +0 -3
- package/dist/es2019/plugins/status/plugin.js +0 -113
- package/dist/es2019/plugins/status/types.js +0 -1
- package/dist/es2019/plugins/status/ui/statusPicker.js +0 -293
- package/dist/es2019/plugins/status/utils.js +0 -12
- package/dist/esm/create-editor/ReactEditorViewInternal.js +0 -806
- package/dist/esm/create-editor/ReactEditorViewNext.js +0 -7
- package/dist/esm/plugins/save-on-enter/index.js +0 -63
- package/dist/esm/plugins/scroll-into-view/index.js +0 -50
- package/dist/esm/plugins/status/actions.js +0 -151
- package/dist/esm/plugins/status/analytics.js +0 -24
- package/dist/esm/plugins/status/index.js +0 -136
- package/dist/esm/plugins/status/keymap.js +0 -15
- package/dist/esm/plugins/status/nodeviews/status.js +0 -51
- package/dist/esm/plugins/status/plugin-key.js +0 -3
- package/dist/esm/plugins/status/plugin.js +0 -115
- package/dist/esm/plugins/status/types.js +0 -1
- package/dist/esm/plugins/status/ui/statusPicker.js +0 -308
- package/dist/esm/plugins/status/utils.js +0 -16
- package/dist/types/create-editor/ReactEditorViewInternal.d.ts +0 -119
- package/dist/types/create-editor/ReactEditorViewNext.d.ts +0 -8
- package/dist/types/plugins/save-on-enter/index.d.ts +0 -10
- package/dist/types/plugins/scroll-into-view/index.d.ts +0 -14
- package/dist/types/plugins/status/actions.d.ts +0 -16
- package/dist/types/plugins/status/analytics.d.ts +0 -4
- package/dist/types/plugins/status/index.d.ts +0 -15
- package/dist/types/plugins/status/keymap.d.ts +0 -3
- package/dist/types/plugins/status/nodeviews/status.d.ts +0 -25
- package/dist/types/plugins/status/plugin-key.d.ts +0 -4
- package/dist/types/plugins/status/plugin.d.ts +0 -7
- package/dist/types/plugins/status/types.d.ts +0 -18
- package/dist/types/plugins/status/ui/statusPicker.d.ts +0 -63
- package/dist/types/plugins/status/utils.d.ts +0 -5
- package/dist/types-ts4.5/create-editor/ReactEditorViewInternal.d.ts +0 -119
- package/dist/types-ts4.5/create-editor/ReactEditorViewNext.d.ts +0 -8
- package/dist/types-ts4.5/plugins/save-on-enter/index.d.ts +0 -10
- package/dist/types-ts4.5/plugins/scroll-into-view/index.d.ts +0 -14
- package/dist/types-ts4.5/plugins/status/actions.d.ts +0 -16
- package/dist/types-ts4.5/plugins/status/analytics.d.ts +0 -4
- package/dist/types-ts4.5/plugins/status/index.d.ts +0 -17
- package/dist/types-ts4.5/plugins/status/keymap.d.ts +0 -3
- package/dist/types-ts4.5/plugins/status/nodeviews/status.d.ts +0 -25
- package/dist/types-ts4.5/plugins/status/plugin-key.d.ts +0 -4
- package/dist/types-ts4.5/plugins/status/plugin.d.ts +0 -7
- package/dist/types-ts4.5/plugins/status/types.d.ts +0 -18
- package/dist/types-ts4.5/plugins/status/ui/statusPicker.d.ts +0 -63
- package/dist/types-ts4.5/plugins/status/utils.d.ts +0 -5
|
@@ -1,4 +1,755 @@
|
|
|
1
|
-
import
|
|
1
|
+
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
|
+
import React from 'react';
|
|
2
3
|
import { injectIntl } from 'react-intl-next';
|
|
3
|
-
|
|
4
|
+
import PropTypes from 'prop-types';
|
|
5
|
+
import { EditorState, Selection, TextSelection } from '@atlaskit/editor-prosemirror/state';
|
|
6
|
+
import { EditorView } from '@atlaskit/editor-prosemirror/view';
|
|
7
|
+
import { editorMessages } from './messages';
|
|
8
|
+
import { browser, getAnalyticsEventSeverity, getResponseEndTime, measureRender, startMeasure, stopMeasure, shouldForceTracking, processRawValue, analyticsEventKey } from '@atlaskit/editor-common/utils';
|
|
9
|
+
import { ExperienceStore, EditorExperience, RELIABILITY_INTERVAL } from '@atlaskit/editor-common/ufo';
|
|
10
|
+
import { createDispatch, EventDispatcher } from '../event-dispatcher';
|
|
11
|
+
import { freezeUnsafeTransactionProperties } from '../utils/performance/safer-transactions';
|
|
12
|
+
import { RenderTracking } from '../utils/performance/components/RenderTracking';
|
|
13
|
+
import { findChangedNodesFromTransaction, validateNodes, validNode } from '../utils/nodes';
|
|
14
|
+
import { ACTION, ACTION_SUBJECT, EVENT_TYPE, fireAnalyticsEvent, FULL_WIDTH_MODE, PLATFORMS, getAnalyticsEventsFromTransaction } from '@atlaskit/editor-common/analytics';
|
|
15
|
+
import { createFeatureFlagsFromProps } from './feature-flags-from-props';
|
|
16
|
+
import { getEnabledFeatureFlagKeys } from '@atlaskit/editor-common/normalize-feature-flags';
|
|
17
|
+
import { createErrorReporter, createPMPlugins, processPluginsList } from './create-editor';
|
|
18
|
+
import { getDocStructure } from '../utils/document-logger';
|
|
19
|
+
import { isFullPage } from '../utils/is-full-page';
|
|
20
|
+
import measurements from '../utils/performance/measure-enum';
|
|
21
|
+
import { getNodesCount } from '../utils/document';
|
|
22
|
+
import { createSchema } from './create-schema';
|
|
23
|
+
import { PluginPerformanceObserver } from '../utils/performance/plugin-performance-observer';
|
|
24
|
+
import { getParticipantsCount } from '../plugins/collab-edit/get-participants-count';
|
|
25
|
+
import { EVENT_NAME_DISPATCH_TRANSACTION, EVENT_NAME_STATE_APPLY, EVENT_NAME_UPDATE_STATE, EVENT_NAME_VIEW_STATE_UPDATED, EVENT_NAME_ON_CHANGE, TransactionTracker } from '../utils/performance/track-transactions';
|
|
26
|
+
import { countNodes } from '@atlaskit/editor-common/utils';
|
|
27
|
+
import createPluginsList from './create-plugins-list';
|
|
28
|
+
import { PROSEMIRROR_RENDERED_NORMAL_SEVERITY_THRESHOLD, PROSEMIRROR_RENDERED_DEGRADED_SEVERITY_THRESHOLD, DEFAULT_SAMPLING_RATE_VALID_TRANSACTIONS } from './consts';
|
|
29
|
+
import ReactEditorViewContext from './ReactEditorViewContext';
|
|
30
|
+
import { EditorPluginInjectionAPI } from '@atlaskit/editor-common/preset';
|
|
31
|
+
import { EDIT_AREA_ID } from '@atlaskit/editor-common/ui';
|
|
32
|
+
function handleEditorFocus(view) {
|
|
33
|
+
if (view.hasFocus()) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
return window.setTimeout(() => {
|
|
37
|
+
if (view.hasFocus()) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (!window.getSelection) {
|
|
41
|
+
view.focus();
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const domSelection = window.getSelection();
|
|
45
|
+
if (!domSelection || domSelection.rangeCount === 0) {
|
|
46
|
+
view.focus();
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const range = domSelection.getRangeAt(0);
|
|
50
|
+
// if selection is outside editor focus and exit
|
|
51
|
+
if (range.startContainer.contains(view.dom)) {
|
|
52
|
+
view.focus();
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
// set cursor/selection and focus
|
|
56
|
+
const anchor = view.posAtDOM(range.startContainer, range.startOffset);
|
|
57
|
+
const head = view.posAtDOM(range.endContainer, range.endOffset);
|
|
58
|
+
// if anchor or head < 0 focus and exit
|
|
59
|
+
if (anchor < 0 || head < 0) {
|
|
60
|
+
view.focus();
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const selection = TextSelection.create(view.state.doc, anchor, head);
|
|
64
|
+
const tr = view.state.tr.setSelection(selection);
|
|
65
|
+
view.dispatch(tr);
|
|
66
|
+
view.focus();
|
|
67
|
+
}, 0);
|
|
68
|
+
}
|
|
69
|
+
export class ReactEditorView extends React.Component {
|
|
70
|
+
get transactionTracking() {
|
|
71
|
+
var _this$props$editorPro, _this$props$editorPro2;
|
|
72
|
+
return (_this$props$editorPro = (_this$props$editorPro2 = this.props.editorProps.performanceTracking) === null || _this$props$editorPro2 === void 0 ? void 0 : _this$props$editorPro2.transactionTracking) !== null && _this$props$editorPro !== void 0 ? _this$props$editorPro : {
|
|
73
|
+
enabled: false
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
getPluginNames() {
|
|
77
|
+
return this.editorState.plugins.map(p => p.key);
|
|
78
|
+
}
|
|
79
|
+
countNodes() {
|
|
80
|
+
return countNodes(this.editorState);
|
|
81
|
+
}
|
|
82
|
+
isTransactionTrackingExplicitlyDisabled() {
|
|
83
|
+
var _this$props$editorPro3, _this$props$editorPro4, _this$props$editorPro5;
|
|
84
|
+
// ED-16320: Check for explicit disable so that by default
|
|
85
|
+
// it will still be enabled as it currently is. Then we can
|
|
86
|
+
// progressively opt out synthetic tenants.
|
|
87
|
+
return ((_this$props$editorPro3 = this.props.editorProps) === null || _this$props$editorPro3 === void 0 ? void 0 : (_this$props$editorPro4 = _this$props$editorPro3.performanceTracking) === null || _this$props$editorPro4 === void 0 ? void 0 : (_this$props$editorPro5 = _this$props$editorPro4.transactionTracking) === null || _this$props$editorPro5 === void 0 ? void 0 : _this$props$editorPro5.enabled) === false;
|
|
88
|
+
}
|
|
89
|
+
constructor(props, context) {
|
|
90
|
+
var _props$setEditorApi, _props$editorProps, _props$editorProps$pe, _props$editorProps$pe2;
|
|
91
|
+
super(props, context);
|
|
92
|
+
_defineProperty(this, "editorRef", /*#__PURE__*/React.createRef());
|
|
93
|
+
// ProseMirror is instantiated prior to the initial React render cycle,
|
|
94
|
+
// so we allow transactions by default, to avoid discarding the initial one.
|
|
95
|
+
_defineProperty(this, "canDispatchTransactions", true);
|
|
96
|
+
_defineProperty(this, "onPluginObservation", (report, editorState) => {
|
|
97
|
+
this.dispatchAnalyticsEvent({
|
|
98
|
+
action: ACTION.TRANSACTION_DISPATCHED,
|
|
99
|
+
actionSubject: ACTION_SUBJECT.EDITOR,
|
|
100
|
+
eventType: EVENT_TYPE.OPERATIONAL,
|
|
101
|
+
attributes: {
|
|
102
|
+
report,
|
|
103
|
+
participants: getParticipantsCount(editorState)
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
_defineProperty(this, "getEditorState", () => {
|
|
108
|
+
var _this$view;
|
|
109
|
+
return (_this$view = this.view) === null || _this$view === void 0 ? void 0 : _this$view.state;
|
|
110
|
+
});
|
|
111
|
+
_defineProperty(this, "getEditorView", () => this.view);
|
|
112
|
+
_defineProperty(this, "formatFullWidthAppearance", appearance => {
|
|
113
|
+
if (appearance === 'full-width') {
|
|
114
|
+
return FULL_WIDTH_MODE.FULL_WIDTH;
|
|
115
|
+
}
|
|
116
|
+
return FULL_WIDTH_MODE.FIXED_WIDTH;
|
|
117
|
+
});
|
|
118
|
+
_defineProperty(this, "resetEditorState", ({
|
|
119
|
+
doc,
|
|
120
|
+
shouldScrollToBottom
|
|
121
|
+
}) => {
|
|
122
|
+
var _this$props$editorPro6, _this$props$editorPro7;
|
|
123
|
+
if (!this.view) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// We cannot currently guarentee when all the portals will have re-rendered during a reconfigure
|
|
128
|
+
// so we blur here to stop ProseMirror from trying to apply selection to detached nodes or
|
|
129
|
+
// nodes that haven't been re-rendered to the document yet.
|
|
130
|
+
this.blur();
|
|
131
|
+
this.featureFlags = createFeatureFlagsFromProps(this.props.editorProps);
|
|
132
|
+
this.editorState = this.createEditorState({
|
|
133
|
+
props: this.props,
|
|
134
|
+
context: this.context,
|
|
135
|
+
doc: doc,
|
|
136
|
+
resetting: true,
|
|
137
|
+
selectionAtStart: !shouldScrollToBottom
|
|
138
|
+
});
|
|
139
|
+
this.view.updateState(this.editorState);
|
|
140
|
+
(_this$props$editorPro6 = (_this$props$editorPro7 = this.props.editorProps).onChange) === null || _this$props$editorPro6 === void 0 ? void 0 : _this$props$editorPro6.call(_this$props$editorPro7, this.view, {
|
|
141
|
+
source: 'local'
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
_defineProperty(this, "blur", () => {
|
|
145
|
+
if (!this.view) {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
if (this.view.dom instanceof HTMLElement && this.view.hasFocus()) {
|
|
149
|
+
this.view.dom.blur();
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// The selectionToDOM method uses the document selection to determine currently selected node
|
|
153
|
+
// We need to mimic blurring this as it seems doing the above is not enough.
|
|
154
|
+
// @ts-expect-error
|
|
155
|
+
const sel = this.view.root.getSelection();
|
|
156
|
+
if (sel) {
|
|
157
|
+
sel.removeAllRanges();
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
_defineProperty(this, "handleAnalyticsEvent", payload => {
|
|
161
|
+
fireAnalyticsEvent(this.props.createAnalyticsEvent)(payload);
|
|
162
|
+
});
|
|
163
|
+
_defineProperty(this, "editorPlugins", []);
|
|
164
|
+
_defineProperty(this, "createEditorState", options => {
|
|
165
|
+
let schema;
|
|
166
|
+
if (this.view) {
|
|
167
|
+
if (options.resetting) {
|
|
168
|
+
/**
|
|
169
|
+
* ReactEditorView currently does NOT handle dynamic schema,
|
|
170
|
+
* We are reusing the existing schema, and rely on #reconfigureState
|
|
171
|
+
* to update `this.config`
|
|
172
|
+
*/
|
|
173
|
+
schema = this.view.state.schema;
|
|
174
|
+
} else {
|
|
175
|
+
/**
|
|
176
|
+
* There's presently a number of issues with changing the schema of a
|
|
177
|
+
* editor inflight. A significant issue is that we lose the ability
|
|
178
|
+
* to keep track of a user's history as the internal plugin state
|
|
179
|
+
* keeps a list of Steps to undo/redo (which are tied to the schema).
|
|
180
|
+
* Without a good way to do work around this, we prevent this for now.
|
|
181
|
+
*/
|
|
182
|
+
// eslint-disable-next-line no-console
|
|
183
|
+
console.warn('The editor does not support changing the schema dynamically.');
|
|
184
|
+
return this.editorState;
|
|
185
|
+
}
|
|
186
|
+
} else {
|
|
187
|
+
this.config = processPluginsList(this.getPlugins(options.props.preset));
|
|
188
|
+
schema = createSchema(this.config);
|
|
189
|
+
}
|
|
190
|
+
const {
|
|
191
|
+
contentTransformerProvider
|
|
192
|
+
} = options.props.editorProps;
|
|
193
|
+
const plugins = createPMPlugins({
|
|
194
|
+
schema,
|
|
195
|
+
dispatch: this.dispatch,
|
|
196
|
+
errorReporter: this.errorReporter,
|
|
197
|
+
editorConfig: this.config,
|
|
198
|
+
eventDispatcher: this.eventDispatcher,
|
|
199
|
+
providerFactory: options.props.providerFactory,
|
|
200
|
+
portalProviderAPI: this.props.portalProviderAPI,
|
|
201
|
+
reactContext: () => options.context,
|
|
202
|
+
dispatchAnalyticsEvent: this.dispatchAnalyticsEvent,
|
|
203
|
+
performanceTracking: this.props.editorProps.performanceTracking,
|
|
204
|
+
transactionTracker: this.transactionTracker,
|
|
205
|
+
featureFlags: this.featureFlags,
|
|
206
|
+
getIntl: () => this.props.intl
|
|
207
|
+
});
|
|
208
|
+
this.contentTransformer = contentTransformerProvider ? contentTransformerProvider(schema) : undefined;
|
|
209
|
+
let doc;
|
|
210
|
+
if (options.doc) {
|
|
211
|
+
doc = processRawValue(schema, options.doc, options.props.providerFactory, options.props.editorProps.sanitizePrivateContent, this.contentTransformer, this.dispatchAnalyticsEvent);
|
|
212
|
+
}
|
|
213
|
+
let selection;
|
|
214
|
+
if (doc) {
|
|
215
|
+
selection = options.selectionAtStart ? Selection.atStart(doc) : Selection.atEnd(doc);
|
|
216
|
+
}
|
|
217
|
+
// Workaround for ED-3507: When media node is the last element, scrollIntoView throws an error
|
|
218
|
+
const patchedSelection = selection ? Selection.findFrom(selection.$head, -1, true) || undefined : undefined;
|
|
219
|
+
return EditorState.create({
|
|
220
|
+
schema,
|
|
221
|
+
plugins: plugins,
|
|
222
|
+
doc,
|
|
223
|
+
selection: patchedSelection
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
_defineProperty(this, "onEditorViewStateUpdated", ({
|
|
227
|
+
originalTransaction,
|
|
228
|
+
transactions,
|
|
229
|
+
oldEditorState,
|
|
230
|
+
newEditorState
|
|
231
|
+
}) => {
|
|
232
|
+
const {
|
|
233
|
+
enabled: trackinEnabled
|
|
234
|
+
} = this.transactionTracking;
|
|
235
|
+
this.config.onEditorViewStateUpdatedCallbacks.forEach(entry => {
|
|
236
|
+
trackinEnabled && startMeasure(`🦉 ${entry.pluginName}::onEditorViewStateUpdated`);
|
|
237
|
+
entry.callback({
|
|
238
|
+
originalTransaction,
|
|
239
|
+
transactions,
|
|
240
|
+
oldEditorState,
|
|
241
|
+
newEditorState
|
|
242
|
+
});
|
|
243
|
+
trackinEnabled && stopMeasure(`🦉 ${entry.pluginName}::onEditorViewStateUpdated`);
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
_defineProperty(this, "trackValidTransactions", () => {
|
|
247
|
+
const {
|
|
248
|
+
editorProps
|
|
249
|
+
} = this.props;
|
|
250
|
+
if (!this.isTransactionTrackingExplicitlyDisabled() && editorProps !== null && editorProps !== void 0 && editorProps.trackValidTransactions) {
|
|
251
|
+
this.validTransactionCount++;
|
|
252
|
+
const samplingRate = typeof editorProps.trackValidTransactions === 'object' && editorProps.trackValidTransactions.samplingRate || DEFAULT_SAMPLING_RATE_VALID_TRANSACTIONS;
|
|
253
|
+
if (this.validTransactionCount >= samplingRate) {
|
|
254
|
+
this.dispatchAnalyticsEvent({
|
|
255
|
+
action: ACTION.DISPATCHED_VALID_TRANSACTION,
|
|
256
|
+
actionSubject: ACTION_SUBJECT.EDITOR,
|
|
257
|
+
eventType: EVENT_TYPE.OPERATIONAL
|
|
258
|
+
});
|
|
259
|
+
this.validTransactionCount = 0;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
_defineProperty(this, "dispatchTransaction", unsafeTransaction => {
|
|
264
|
+
if (!this.view) {
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
this.transactionTracker.bumpDispatchCounter(this.transactionTracking);
|
|
268
|
+
const {
|
|
269
|
+
startMeasure,
|
|
270
|
+
stopMeasure
|
|
271
|
+
} = this.transactionTracker.getMeasureHelpers(this.transactionTracking);
|
|
272
|
+
startMeasure(EVENT_NAME_DISPATCH_TRANSACTION);
|
|
273
|
+
if (this.transactionTracker.shouldTrackTransaction(this.transactionTracking)) {
|
|
274
|
+
var _this$experienceStore;
|
|
275
|
+
(_this$experienceStore = this.experienceStore) === null || _this$experienceStore === void 0 ? void 0 : _this$experienceStore.start(EditorExperience.interaction);
|
|
276
|
+
}
|
|
277
|
+
const nodes = findChangedNodesFromTransaction(unsafeTransaction);
|
|
278
|
+
const changedNodesValid = validateNodes(nodes);
|
|
279
|
+
const transaction = this.featureFlags.saferDispatchedTransactions || this.featureFlags.saferDispatchedTransactionsAnalyticsOnly ? new Proxy(unsafeTransaction, freezeUnsafeTransactionProperties({
|
|
280
|
+
dispatchAnalyticsEvent: this.dispatchAnalyticsEvent,
|
|
281
|
+
pluginKey: 'unknown-reacteditorview',
|
|
282
|
+
analyticsOnly: this.featureFlags.saferDispatchedTransactionsAnalyticsOnly
|
|
283
|
+
})) : unsafeTransaction;
|
|
284
|
+
if (changedNodesValid) {
|
|
285
|
+
const oldEditorState = this.view.state;
|
|
286
|
+
|
|
287
|
+
// go ahead and update the state now we know the transaction is good
|
|
288
|
+
startMeasure(EVENT_NAME_STATE_APPLY);
|
|
289
|
+
const {
|
|
290
|
+
state: editorState,
|
|
291
|
+
transactions
|
|
292
|
+
} = this.view.state.applyTransaction(transaction);
|
|
293
|
+
stopMeasure(EVENT_NAME_STATE_APPLY, (duration, startTime) => {
|
|
294
|
+
var _this$experienceStore2;
|
|
295
|
+
(_this$experienceStore2 = this.experienceStore) === null || _this$experienceStore2 === void 0 ? void 0 : _this$experienceStore2.mark(EditorExperience.interaction, 'stateApply', startTime + duration);
|
|
296
|
+
});
|
|
297
|
+
this.trackValidTransactions();
|
|
298
|
+
if (editorState === oldEditorState) {
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
startMeasure(EVENT_NAME_UPDATE_STATE);
|
|
302
|
+
this.view.updateState(editorState);
|
|
303
|
+
stopMeasure(EVENT_NAME_UPDATE_STATE, (duration, startTime) => {
|
|
304
|
+
var _this$experienceStore3;
|
|
305
|
+
(_this$experienceStore3 = this.experienceStore) === null || _this$experienceStore3 === void 0 ? void 0 : _this$experienceStore3.mark(EditorExperience.interaction, 'viewUpdateState', startTime + duration);
|
|
306
|
+
});
|
|
307
|
+
this.pluginInjectionAPI.onEditorViewUpdated({
|
|
308
|
+
newEditorState: editorState,
|
|
309
|
+
oldEditorState
|
|
310
|
+
});
|
|
311
|
+
startMeasure(EVENT_NAME_VIEW_STATE_UPDATED);
|
|
312
|
+
this.onEditorViewStateUpdated({
|
|
313
|
+
originalTransaction: transaction,
|
|
314
|
+
transactions,
|
|
315
|
+
oldEditorState,
|
|
316
|
+
newEditorState: editorState
|
|
317
|
+
});
|
|
318
|
+
stopMeasure(EVENT_NAME_VIEW_STATE_UPDATED, (duration, startTime) => {
|
|
319
|
+
var _this$experienceStore4;
|
|
320
|
+
(_this$experienceStore4 = this.experienceStore) === null || _this$experienceStore4 === void 0 ? void 0 : _this$experienceStore4.mark(EditorExperience.interaction, 'onEditorViewStateUpdated', startTime + duration);
|
|
321
|
+
});
|
|
322
|
+
if (this.props.editorProps.onChange && transaction.docChanged) {
|
|
323
|
+
const source = transaction.getMeta('isRemote') ? 'remote' : 'local';
|
|
324
|
+
startMeasure(EVENT_NAME_ON_CHANGE);
|
|
325
|
+
this.props.editorProps.onChange(this.view, {
|
|
326
|
+
source
|
|
327
|
+
});
|
|
328
|
+
stopMeasure(EVENT_NAME_ON_CHANGE, (duration, startTime) => {
|
|
329
|
+
var _this$experienceStore5, _this$props$editorPro8, _this$props$editorPro9;
|
|
330
|
+
(_this$experienceStore5 = this.experienceStore) === null || _this$experienceStore5 === void 0 ? void 0 : _this$experienceStore5.mark(EditorExperience.interaction, 'onChange', startTime + duration);
|
|
331
|
+
if (((_this$props$editorPro8 = this.props.editorProps.performanceTracking) === null || _this$props$editorPro8 === void 0 ? void 0 : (_this$props$editorPro9 = _this$props$editorPro8.onChangeCallbackTracking) === null || _this$props$editorPro9 === void 0 ? void 0 : _this$props$editorPro9.enabled) !== true) {
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
this.dispatchAnalyticsEvent({
|
|
335
|
+
action: ACTION.ON_CHANGE_CALLBACK,
|
|
336
|
+
actionSubject: ACTION_SUBJECT.EDITOR,
|
|
337
|
+
eventType: EVENT_TYPE.OPERATIONAL,
|
|
338
|
+
attributes: {
|
|
339
|
+
duration,
|
|
340
|
+
startTime
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
this.editorState = editorState;
|
|
346
|
+
stopMeasure(EVENT_NAME_DISPATCH_TRANSACTION, (duration, startTime) => {
|
|
347
|
+
var _this$experienceStore6, _this$experienceStore7;
|
|
348
|
+
(_this$experienceStore6 = this.experienceStore) === null || _this$experienceStore6 === void 0 ? void 0 : _this$experienceStore6.mark(EditorExperience.interaction, 'dispatchTransaction', startTime + duration);
|
|
349
|
+
(_this$experienceStore7 = this.experienceStore) === null || _this$experienceStore7 === void 0 ? void 0 : _this$experienceStore7.success(EditorExperience.interaction);
|
|
350
|
+
});
|
|
351
|
+
} else {
|
|
352
|
+
var _this$experienceStore8;
|
|
353
|
+
const invalidNodes = nodes.filter(node => !validNode(node)).map(node => getDocStructure(node, {
|
|
354
|
+
compact: true
|
|
355
|
+
}));
|
|
356
|
+
if (!this.isTransactionTrackingExplicitlyDisabled()) {
|
|
357
|
+
this.dispatchAnalyticsEvent({
|
|
358
|
+
action: ACTION.DISPATCHED_INVALID_TRANSACTION,
|
|
359
|
+
actionSubject: ACTION_SUBJECT.EDITOR,
|
|
360
|
+
eventType: EVENT_TYPE.OPERATIONAL,
|
|
361
|
+
attributes: {
|
|
362
|
+
analyticsEventPayloads: getAnalyticsEventsFromTransaction(transaction),
|
|
363
|
+
invalidNodes
|
|
364
|
+
}
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
(_this$experienceStore8 = this.experienceStore) === null || _this$experienceStore8 === void 0 ? void 0 : _this$experienceStore8.fail(EditorExperience.interaction, {
|
|
368
|
+
reason: 'invalid transaction',
|
|
369
|
+
invalidNodes: invalidNodes.toString()
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
});
|
|
373
|
+
_defineProperty(this, "getDirectEditorProps", state => {
|
|
374
|
+
return {
|
|
375
|
+
state: state || this.editorState,
|
|
376
|
+
dispatchTransaction: tr => {
|
|
377
|
+
// Block stale transactions:
|
|
378
|
+
// Prevent runtime exeptions from async transactions that would attempt to
|
|
379
|
+
// update the DOM after React has unmounted the Editor.
|
|
380
|
+
if (this.canDispatchTransactions) {
|
|
381
|
+
this.dispatchTransaction(tr);
|
|
382
|
+
}
|
|
383
|
+
},
|
|
384
|
+
// Disables the contentEditable attribute of the editor if the editor is disabled
|
|
385
|
+
editable: _state => !this.props.editorProps.disabled,
|
|
386
|
+
attributes: {
|
|
387
|
+
'data-gramm': 'false'
|
|
388
|
+
}
|
|
389
|
+
};
|
|
390
|
+
});
|
|
391
|
+
_defineProperty(this, "createEditorView", node => {
|
|
392
|
+
measureRender(measurements.PROSEMIRROR_RENDERED, ({
|
|
393
|
+
duration,
|
|
394
|
+
startTime,
|
|
395
|
+
distortedDuration
|
|
396
|
+
}) => {
|
|
397
|
+
var _this$props$editorPro10, _this$props$editorPro11, _proseMirrorRenderedT, _proseMirrorRenderedT2;
|
|
398
|
+
const proseMirrorRenderedTracking = (_this$props$editorPro10 = this.props.editorProps) === null || _this$props$editorPro10 === void 0 ? void 0 : (_this$props$editorPro11 = _this$props$editorPro10.performanceTracking) === null || _this$props$editorPro11 === void 0 ? void 0 : _this$props$editorPro11.proseMirrorRenderedTracking;
|
|
399
|
+
const forceSeverityTracking = typeof proseMirrorRenderedTracking === 'undefined' && shouldForceTracking();
|
|
400
|
+
this.proseMirrorRenderedSeverity = !!forceSeverityTracking || proseMirrorRenderedTracking !== null && proseMirrorRenderedTracking !== void 0 && proseMirrorRenderedTracking.trackSeverity ? getAnalyticsEventSeverity(duration, (_proseMirrorRenderedT = proseMirrorRenderedTracking === null || proseMirrorRenderedTracking === void 0 ? void 0 : proseMirrorRenderedTracking.severityNormalThreshold) !== null && _proseMirrorRenderedT !== void 0 ? _proseMirrorRenderedT : PROSEMIRROR_RENDERED_NORMAL_SEVERITY_THRESHOLD, (_proseMirrorRenderedT2 = proseMirrorRenderedTracking === null || proseMirrorRenderedTracking === void 0 ? void 0 : proseMirrorRenderedTracking.severityDegradedThreshold) !== null && _proseMirrorRenderedT2 !== void 0 ? _proseMirrorRenderedT2 : PROSEMIRROR_RENDERED_DEGRADED_SEVERITY_THRESHOLD) : undefined;
|
|
401
|
+
if (this.view) {
|
|
402
|
+
var _this$pluginInjection, _this$experienceStore10;
|
|
403
|
+
const nodes = getNodesCount(this.view.state.doc);
|
|
404
|
+
const ttfb = getResponseEndTime();
|
|
405
|
+
const contextIdentifier = (_this$pluginInjection = this.pluginInjectionAPI.api().base) === null || _this$pluginInjection === void 0 ? void 0 : _this$pluginInjection.sharedState.currentState();
|
|
406
|
+
this.dispatchAnalyticsEvent({
|
|
407
|
+
action: ACTION.PROSEMIRROR_RENDERED,
|
|
408
|
+
actionSubject: ACTION_SUBJECT.EDITOR,
|
|
409
|
+
attributes: {
|
|
410
|
+
duration,
|
|
411
|
+
startTime,
|
|
412
|
+
nodes,
|
|
413
|
+
ttfb,
|
|
414
|
+
severity: this.proseMirrorRenderedSeverity,
|
|
415
|
+
objectId: contextIdentifier === null || contextIdentifier === void 0 ? void 0 : contextIdentifier.objectId,
|
|
416
|
+
distortedDuration
|
|
417
|
+
},
|
|
418
|
+
eventType: EVENT_TYPE.OPERATIONAL
|
|
419
|
+
});
|
|
420
|
+
if (!distortedDuration) {
|
|
421
|
+
var _this$experienceStore9;
|
|
422
|
+
(_this$experienceStore9 = this.experienceStore) === null || _this$experienceStore9 === void 0 ? void 0 : _this$experienceStore9.mark(EditorExperience.loadEditor, ACTION.PROSEMIRROR_RENDERED, startTime + duration);
|
|
423
|
+
}
|
|
424
|
+
(_this$experienceStore10 = this.experienceStore) === null || _this$experienceStore10 === void 0 ? void 0 : _this$experienceStore10.addMetadata(EditorExperience.loadEditor, {
|
|
425
|
+
nodes,
|
|
426
|
+
ttfb
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
// Creates the editor-view from this.editorState. If an editor has been mounted
|
|
432
|
+
// previously, this will contain the previous state of the editor.
|
|
433
|
+
this.view = new EditorView({
|
|
434
|
+
mount: node
|
|
435
|
+
}, this.getDirectEditorProps());
|
|
436
|
+
this.pluginInjectionAPI.onEditorViewUpdated({
|
|
437
|
+
newEditorState: this.view.state,
|
|
438
|
+
oldEditorState: undefined
|
|
439
|
+
});
|
|
440
|
+
});
|
|
441
|
+
_defineProperty(this, "handleEditorViewRef", node => {
|
|
442
|
+
if (!this.view && node) {
|
|
443
|
+
this.createEditorView(node);
|
|
444
|
+
const view = this.view;
|
|
445
|
+
this.props.onEditorCreated({
|
|
446
|
+
view,
|
|
447
|
+
config: this.config,
|
|
448
|
+
eventDispatcher: this.eventDispatcher,
|
|
449
|
+
transformer: this.contentTransformer
|
|
450
|
+
});
|
|
451
|
+
if (this.props.editorProps.shouldFocus && view.props.editable && view.props.editable(view.state)) {
|
|
452
|
+
this.focusTimeoutId = handleEditorFocus(view);
|
|
453
|
+
}
|
|
454
|
+
if (this.featureFlags.ufo) {
|
|
455
|
+
this.experienceStore = ExperienceStore.getInstance(view);
|
|
456
|
+
this.experienceStore.start(EditorExperience.editSession);
|
|
457
|
+
this.experienceStore.addMetadata(EditorExperience.editSession, {
|
|
458
|
+
reliabilityInterval: RELIABILITY_INTERVAL
|
|
459
|
+
});
|
|
460
|
+
this.reliabilityInterval = window.setInterval(() => {
|
|
461
|
+
var _this$experienceStore11, _this$experienceStore12;
|
|
462
|
+
(_this$experienceStore11 = this.experienceStore) === null || _this$experienceStore11 === void 0 ? void 0 : (_this$experienceStore12 = _this$experienceStore11.success(EditorExperience.editSession)) === null || _this$experienceStore12 === void 0 ? void 0 : _this$experienceStore12.finally(() => {
|
|
463
|
+
var _this$experienceStore13, _this$experienceStore14;
|
|
464
|
+
(_this$experienceStore13 = this.experienceStore) === null || _this$experienceStore13 === void 0 ? void 0 : _this$experienceStore13.start(EditorExperience.editSession);
|
|
465
|
+
(_this$experienceStore14 = this.experienceStore) === null || _this$experienceStore14 === void 0 ? void 0 : _this$experienceStore14.addMetadata(EditorExperience.editSession, {
|
|
466
|
+
reliabilityInterval: RELIABILITY_INTERVAL
|
|
467
|
+
});
|
|
468
|
+
});
|
|
469
|
+
const reliabilityEvent = {
|
|
470
|
+
action: ACTION.UFO_SESSION_COMPLETE,
|
|
471
|
+
actionSubject: ACTION_SUBJECT.EDITOR,
|
|
472
|
+
attributes: {
|
|
473
|
+
interval: RELIABILITY_INTERVAL
|
|
474
|
+
},
|
|
475
|
+
eventType: EVENT_TYPE.OPERATIONAL
|
|
476
|
+
};
|
|
477
|
+
this.dispatchAnalyticsEvent(reliabilityEvent);
|
|
478
|
+
}, RELIABILITY_INTERVAL);
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
// Force React to re-render so consumers get a reference to the editor view
|
|
482
|
+
this.forceUpdate();
|
|
483
|
+
} else if (this.view && !node) {
|
|
484
|
+
// When the appearance is changed, React will call handleEditorViewRef with node === null
|
|
485
|
+
// to destroy the old EditorView, before calling this method again with node === div to
|
|
486
|
+
// create the new EditorView
|
|
487
|
+
this.props.onEditorDestroyed({
|
|
488
|
+
view: this.view,
|
|
489
|
+
config: this.config,
|
|
490
|
+
eventDispatcher: this.eventDispatcher,
|
|
491
|
+
transformer: this.contentTransformer
|
|
492
|
+
});
|
|
493
|
+
|
|
494
|
+
// Allows us to dispatch analytics within the plugin view.destory methods
|
|
495
|
+
const analyticsConnected = this.eventDispatcher.has(analyticsEventKey, this.handleAnalyticsEvent);
|
|
496
|
+
if (!analyticsConnected) {
|
|
497
|
+
this.eventDispatcher.on(analyticsEventKey, this.handleAnalyticsEvent);
|
|
498
|
+
}
|
|
499
|
+
this.view.destroy(); // Destroys the dom node & all node views
|
|
500
|
+
|
|
501
|
+
if (!analyticsConnected) {
|
|
502
|
+
this.eventDispatcher.off(analyticsEventKey, this.handleAnalyticsEvent);
|
|
503
|
+
}
|
|
504
|
+
this.view = undefined;
|
|
505
|
+
}
|
|
506
|
+
});
|
|
507
|
+
_defineProperty(this, "dispatchAnalyticsEvent", payload => {
|
|
508
|
+
if (this.eventDispatcher) {
|
|
509
|
+
const dispatch = createDispatch(this.eventDispatcher);
|
|
510
|
+
dispatch(analyticsEventKey, {
|
|
511
|
+
payload
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
});
|
|
515
|
+
_defineProperty(this, "createEditor", assistiveLabel => {
|
|
516
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
517
|
+
className: getUAPrefix(),
|
|
518
|
+
key: "ProseMirror",
|
|
519
|
+
ref: this.handleEditorViewRef,
|
|
520
|
+
"aria-label": assistiveLabel || this.props.intl.formatMessage(editorMessages.editorAssistiveLabel)
|
|
521
|
+
// setting aria-multiline to true when not mobile appearance.
|
|
522
|
+
// because somehow mobile tests are failing when it set.
|
|
523
|
+
// don't know why that is happening.
|
|
524
|
+
// Created https://product-fabric.atlassian.net/jira/servicedesk/projects/DTR/queues/issue/DTR-1675
|
|
525
|
+
// to investigate further.
|
|
526
|
+
,
|
|
527
|
+
"aria-multiline": this.props.editorProps.appearance !== 'mobile' ? true : false,
|
|
528
|
+
role: "textbox",
|
|
529
|
+
id: EDIT_AREA_ID
|
|
530
|
+
});
|
|
531
|
+
});
|
|
532
|
+
_defineProperty(this, "editor", this.createEditor(this.props.editorProps.assistiveLabel));
|
|
533
|
+
this.pluginInjectionAPI = new EditorPluginInjectionAPI({
|
|
534
|
+
getEditorState: this.getEditorState,
|
|
535
|
+
getEditorView: this.getEditorView
|
|
536
|
+
});
|
|
537
|
+
(_props$setEditorApi = props.setEditorApi) === null || _props$setEditorApi === void 0 ? void 0 : _props$setEditorApi.call(props, this.pluginInjectionAPI.api());
|
|
538
|
+
this.eventDispatcher = new EventDispatcher();
|
|
539
|
+
this.dispatch = createDispatch(this.eventDispatcher);
|
|
540
|
+
this.errorReporter = createErrorReporter(props.editorProps.errorReporterHandler);
|
|
541
|
+
this.transactionTracker = new TransactionTracker();
|
|
542
|
+
this.pluginPerformanceObserver = new PluginPerformanceObserver(report => this.onPluginObservation(report, this.editorState)).withPlugins(() => this.getPluginNames()).withNodeCounts(() => this.countNodes()).withOptions(() => this.transactionTracking).withTransactionTracker(() => this.transactionTracker);
|
|
543
|
+
this.validTransactionCount = 0;
|
|
544
|
+
this.featureFlags = createFeatureFlagsFromProps(this.props.editorProps);
|
|
545
|
+
const featureFlagsEnabled = this.featureFlags ? getEnabledFeatureFlagKeys(this.featureFlags) : [];
|
|
546
|
+
|
|
547
|
+
// START TEMPORARY CODE ED-10584
|
|
548
|
+
if (this.props.createAnalyticsEvent) {
|
|
549
|
+
this.props.createAnalyticsEvent.__queueAnalytics = this.featureFlags.queueAnalytics;
|
|
550
|
+
}
|
|
551
|
+
// END TEMPORARY CODE ED-10584
|
|
552
|
+
|
|
553
|
+
// This needs to be before initialising editorState because
|
|
554
|
+
// we dispatch analytics events in plugin initialisation
|
|
555
|
+
this.eventDispatcher.on(analyticsEventKey, this.handleAnalyticsEvent);
|
|
556
|
+
this.eventDispatcher.on('resetEditorState', this.resetEditorState);
|
|
557
|
+
this.editorState = this.createEditorState({
|
|
558
|
+
props,
|
|
559
|
+
context,
|
|
560
|
+
doc: props.editorProps.defaultValue,
|
|
561
|
+
// ED-4759: Don't set selection at end for full-page editor - should be at start.
|
|
562
|
+
selectionAtStart: isFullPage(props.editorProps.appearance)
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
// ED-16320: Check for explicit disable so that by default
|
|
566
|
+
// it will still be enabled as it currently is. Then we can
|
|
567
|
+
// progressively opt out synthetic tenants.
|
|
568
|
+
const isEditorStartedExplicitlyDisabled = ((_props$editorProps = props.editorProps) === null || _props$editorProps === void 0 ? void 0 : (_props$editorProps$pe = _props$editorProps.performanceTracking) === null || _props$editorProps$pe === void 0 ? void 0 : (_props$editorProps$pe2 = _props$editorProps$pe.startedTracking) === null || _props$editorProps$pe2 === void 0 ? void 0 : _props$editorProps$pe2.enabled) === false;
|
|
569
|
+
if (!isEditorStartedExplicitlyDisabled) {
|
|
570
|
+
this.dispatchAnalyticsEvent({
|
|
571
|
+
action: ACTION.STARTED,
|
|
572
|
+
actionSubject: ACTION_SUBJECT.EDITOR,
|
|
573
|
+
attributes: {
|
|
574
|
+
platform: PLATFORMS.WEB,
|
|
575
|
+
featureFlags: featureFlagsEnabled
|
|
576
|
+
},
|
|
577
|
+
eventType: EVENT_TYPE.UI
|
|
578
|
+
});
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
UNSAFE_componentWillReceiveProps(nextProps) {
|
|
582
|
+
// START TEMPORARY CODE ED-10584
|
|
583
|
+
if (nextProps.createAnalyticsEvent && nextProps.createAnalyticsEvent !== this.props.createAnalyticsEvent) {
|
|
584
|
+
const featureFlags = createFeatureFlagsFromProps(nextProps.editorProps);
|
|
585
|
+
nextProps.createAnalyticsEvent.__queueAnalytics = featureFlags.queueAnalytics;
|
|
586
|
+
}
|
|
587
|
+
// END TEMPORARY CODE ED-10584
|
|
588
|
+
|
|
589
|
+
if (this.view && this.props.editorProps.disabled !== nextProps.editorProps.disabled) {
|
|
590
|
+
// Disables the contentEditable attribute of the editor if the editor is disabled
|
|
591
|
+
this.view.setProps({
|
|
592
|
+
editable: _state => !nextProps.editorProps.disabled
|
|
593
|
+
});
|
|
594
|
+
if (!nextProps.editorProps.disabled && nextProps.editorProps.shouldFocus) {
|
|
595
|
+
this.focusTimeoutId = handleEditorFocus(this.view);
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
const {
|
|
599
|
+
appearance
|
|
600
|
+
} = this.props.editorProps;
|
|
601
|
+
const {
|
|
602
|
+
appearance: nextAppearance
|
|
603
|
+
} = nextProps.editorProps;
|
|
604
|
+
if (this.props.preset !== nextProps.preset) {
|
|
605
|
+
this.reconfigureState(nextProps);
|
|
606
|
+
}
|
|
607
|
+
if (nextAppearance !== appearance) {
|
|
608
|
+
if (nextAppearance === 'full-width' || appearance === 'full-width') {
|
|
609
|
+
this.dispatchAnalyticsEvent({
|
|
610
|
+
action: ACTION.CHANGED_FULL_WIDTH_MODE,
|
|
611
|
+
actionSubject: ACTION_SUBJECT.EDITOR,
|
|
612
|
+
eventType: EVENT_TYPE.TRACK,
|
|
613
|
+
attributes: {
|
|
614
|
+
previousMode: this.formatFullWidthAppearance(appearance),
|
|
615
|
+
newMode: this.formatFullWidthAppearance(nextAppearance)
|
|
616
|
+
}
|
|
617
|
+
});
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
if (!this.transactionTracking.enabled) {
|
|
621
|
+
this.pluginPerformanceObserver.disconnect();
|
|
622
|
+
}
|
|
623
|
+
if (nextProps.editorProps.assistiveLabel !== this.props.editorProps.assistiveLabel) {
|
|
624
|
+
this.editor = this.createEditor(nextProps.editorProps.assistiveLabel);
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
reconfigureState(props) {
|
|
628
|
+
if (!this.view) {
|
|
629
|
+
return;
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
// We cannot currently guarentee when all the portals will have re-rendered during a reconfigure
|
|
633
|
+
// so we blur here to stop ProseMirror from trying to apply selection to detached nodes or
|
|
634
|
+
// nodes that haven't been re-rendered to the document yet.
|
|
635
|
+
this.blur();
|
|
636
|
+
const editorPlugins = this.getPlugins(props.preset);
|
|
637
|
+
this.config = processPluginsList(editorPlugins);
|
|
638
|
+
const state = this.editorState;
|
|
639
|
+
const plugins = createPMPlugins({
|
|
640
|
+
schema: state.schema,
|
|
641
|
+
dispatch: this.dispatch,
|
|
642
|
+
errorReporter: this.errorReporter,
|
|
643
|
+
editorConfig: this.config,
|
|
644
|
+
eventDispatcher: this.eventDispatcher,
|
|
645
|
+
providerFactory: props.providerFactory,
|
|
646
|
+
portalProviderAPI: props.portalProviderAPI,
|
|
647
|
+
reactContext: () => this.context,
|
|
648
|
+
dispatchAnalyticsEvent: this.dispatchAnalyticsEvent,
|
|
649
|
+
performanceTracking: props.editorProps.performanceTracking,
|
|
650
|
+
transactionTracker: this.transactionTracker,
|
|
651
|
+
featureFlags: createFeatureFlagsFromProps(props.editorProps),
|
|
652
|
+
getIntl: () => this.props.intl
|
|
653
|
+
});
|
|
654
|
+
const newState = state.reconfigure({
|
|
655
|
+
plugins: plugins
|
|
656
|
+
});
|
|
657
|
+
|
|
658
|
+
// need to update the state first so when the view builds the nodeviews it is
|
|
659
|
+
// using the latest plugins
|
|
660
|
+
this.view.updateState(newState);
|
|
661
|
+
return this.view.update({
|
|
662
|
+
...this.view.props,
|
|
663
|
+
state: newState
|
|
664
|
+
});
|
|
665
|
+
}
|
|
666
|
+
componentDidMount() {
|
|
667
|
+
// Transaction dispatching is already enabled by default prior to
|
|
668
|
+
// mounting, but we reset it here, just in case the editor view
|
|
669
|
+
// instance is ever recycled (mounted again after unmounting) with
|
|
670
|
+
// the same key.
|
|
671
|
+
// Although storing mounted state is an anti-pattern in React,
|
|
672
|
+
// we do so here so that we can intercept and abort asynchronous
|
|
673
|
+
// ProseMirror transactions when a dismount is imminent.
|
|
674
|
+
this.canDispatchTransactions = true;
|
|
675
|
+
if (this.transactionTracking.enabled) {
|
|
676
|
+
this.pluginPerformanceObserver.observe();
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
/**
|
|
681
|
+
* Clean up any non-PM resources when the editor is unmounted
|
|
682
|
+
*/
|
|
683
|
+
componentWillUnmount() {
|
|
684
|
+
// We can ignore any transactions from this point onwards.
|
|
685
|
+
// This serves to avoid potential runtime exceptions which could arise
|
|
686
|
+
// from an async dispatched transaction after it's unmounted.
|
|
687
|
+
this.canDispatchTransactions = false;
|
|
688
|
+
clearTimeout(this.focusTimeoutId);
|
|
689
|
+
if (this.reliabilityInterval) {
|
|
690
|
+
clearInterval(this.reliabilityInterval);
|
|
691
|
+
}
|
|
692
|
+
this.pluginPerformanceObserver.disconnect();
|
|
693
|
+
if (this.view) {
|
|
694
|
+
// Destroy the state if the Editor is being unmounted
|
|
695
|
+
const editorState = this.view.state;
|
|
696
|
+
editorState.plugins.forEach(plugin => {
|
|
697
|
+
const state = plugin.getState(editorState);
|
|
698
|
+
if (state && state.destroy) {
|
|
699
|
+
state.destroy();
|
|
700
|
+
}
|
|
701
|
+
});
|
|
702
|
+
}
|
|
703
|
+
this.eventDispatcher.destroy();
|
|
704
|
+
// this.view will be destroyed when React unmounts in handleEditorViewRef
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
// Helper to allow tests to inject plugins directly
|
|
708
|
+
getPlugins(preset) {
|
|
709
|
+
const plugins = createPluginsList(preset, this.props.editorProps, this.pluginInjectionAPI);
|
|
710
|
+
this.editorPlugins = plugins;
|
|
711
|
+
return this.editorPlugins;
|
|
712
|
+
}
|
|
713
|
+
render() {
|
|
714
|
+
var _this$props$editorPro12, _this$props$editorPro13;
|
|
715
|
+
const renderTracking = (_this$props$editorPro12 = this.props.editorProps.performanceTracking) === null || _this$props$editorPro12 === void 0 ? void 0 : (_this$props$editorPro13 = _this$props$editorPro12.renderTracking) === null || _this$props$editorPro13 === void 0 ? void 0 : _this$props$editorPro13.reactEditorView;
|
|
716
|
+
const renderTrackingEnabled = renderTracking === null || renderTracking === void 0 ? void 0 : renderTracking.enabled;
|
|
717
|
+
const useShallow = renderTracking === null || renderTracking === void 0 ? void 0 : renderTracking.useShallow;
|
|
718
|
+
return /*#__PURE__*/React.createElement(ReactEditorViewContext.Provider, {
|
|
719
|
+
value: {
|
|
720
|
+
editorRef: this.editorRef,
|
|
721
|
+
editorView: this.view
|
|
722
|
+
}
|
|
723
|
+
}, renderTrackingEnabled && /*#__PURE__*/React.createElement(RenderTracking, {
|
|
724
|
+
componentProps: this.props,
|
|
725
|
+
action: ACTION.RE_RENDERED,
|
|
726
|
+
actionSubject: ACTION_SUBJECT.REACT_EDITOR_VIEW,
|
|
727
|
+
handleAnalyticsEvent: this.handleAnalyticsEvent,
|
|
728
|
+
useShallow: useShallow
|
|
729
|
+
}), this.props.render ? this.props.render({
|
|
730
|
+
editor: this.editor,
|
|
731
|
+
view: this.view,
|
|
732
|
+
config: this.config,
|
|
733
|
+
eventDispatcher: this.eventDispatcher,
|
|
734
|
+
transformer: this.contentTransformer,
|
|
735
|
+
dispatchAnalyticsEvent: this.dispatchAnalyticsEvent,
|
|
736
|
+
editorRef: this.editorRef
|
|
737
|
+
}) : this.editor);
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
_defineProperty(ReactEditorView, "contextTypes", {
|
|
741
|
+
getAtlaskitAnalyticsEventHandlers: PropTypes.func
|
|
742
|
+
});
|
|
743
|
+
function getUAPrefix() {
|
|
744
|
+
if (browser.chrome) {
|
|
745
|
+
return 'ua-chrome';
|
|
746
|
+
} else if (browser.ie) {
|
|
747
|
+
return 'ua-ie';
|
|
748
|
+
} else if (browser.gecko) {
|
|
749
|
+
return 'ua-firefox';
|
|
750
|
+
} else if (browser.safari) {
|
|
751
|
+
return 'ua-safari';
|
|
752
|
+
}
|
|
753
|
+
return '';
|
|
754
|
+
}
|
|
4
755
|
export default injectIntl(ReactEditorView);
|