@atlaskit/editor-plugin-collab-edit 1.8.3 → 1.8.5
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 +17 -0
- package/dist/cjs/plugin.js +20 -2
- package/dist/cjs/track-steps.js +177 -0
- package/dist/cjs/utils.js +4 -4
- package/dist/es2019/plugin.js +16 -0
- package/dist/es2019/track-steps.js +153 -0
- package/dist/es2019/utils.js +1 -1
- package/dist/esm/plugin.js +18 -0
- package/dist/esm/track-steps.js +170 -0
- package/dist/esm/utils.js +1 -1
- package/dist/types/track-steps.d.ts +77 -0
- package/dist/types-ts4.5/track-steps.d.ts +77 -0
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# @atlaskit/editor-plugin-collab-edit
|
|
2
2
|
|
|
3
|
+
## 1.8.5
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#117769](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/117769)
|
|
8
|
+
[`a59c5cd45160c`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/a59c5cd45160c) -
|
|
9
|
+
[No Issue] Track how many steps a editorSession is creating
|
|
10
|
+
|
|
11
|
+
## 1.8.4
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- [#117973](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/117973)
|
|
16
|
+
[`6e37bac62083f`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/6e37bac62083f) -
|
|
17
|
+
moved one const, added new entry point for other and deprecated
|
|
18
|
+
- Updated dependencies
|
|
19
|
+
|
|
3
20
|
## 1.8.3
|
|
4
21
|
|
|
5
22
|
### Patch Changes
|
package/dist/cjs/plugin.js
CHANGED
|
@@ -6,17 +6,22 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
});
|
|
7
7
|
exports.collabEditPlugin = void 0;
|
|
8
8
|
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
|
|
9
|
+
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
9
10
|
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
|
|
10
11
|
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
|
|
12
|
+
var _analytics = require("@atlaskit/editor-common/analytics");
|
|
11
13
|
var _transform = require("@atlaskit/editor-prosemirror/transform");
|
|
12
14
|
var _prosemirrorCollab = require("@atlaskit/prosemirror-collab");
|
|
13
|
-
var
|
|
15
|
+
var _analytics2 = require("./analytics");
|
|
14
16
|
var _sendTransaction = require("./events/send-transaction");
|
|
15
17
|
var _main = require("./pm-plugins/main");
|
|
16
18
|
var _pluginKey = require("./pm-plugins/main/plugin-key");
|
|
17
19
|
var _nativeCollabProviderPlugin = require("./pm-plugins/native-collab-provider-plugin");
|
|
18
20
|
var _trackNcsInitialization = require("./pm-plugins/track-ncs-initialization");
|
|
21
|
+
var _trackSteps = require("./track-steps");
|
|
19
22
|
var _utils = require("./utils");
|
|
23
|
+
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
24
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
20
25
|
var providerBuilder = function providerBuilder(collabEditProviderPromise) {
|
|
21
26
|
return /*#__PURE__*/function () {
|
|
22
27
|
var _ref = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(codeToExecute, onError) {
|
|
@@ -164,7 +169,7 @@ var collabEditPlugin = exports.collabEditPlugin = function collabEditPlugin(_ref
|
|
|
164
169
|
},
|
|
165
170
|
onEditorViewStateUpdated: function onEditorViewStateUpdated(props) {
|
|
166
171
|
var _api$analytics, _api$editorViewMode, _options$useNativePlu;
|
|
167
|
-
var addErrorAnalytics = (0,
|
|
172
|
+
var addErrorAnalytics = (0, _analytics2.addSynchronyErrorAnalytics)(props.newEditorState, props.newEditorState.tr, featureFlags, api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions);
|
|
168
173
|
var viewMode = api === null || api === void 0 || (_api$editorViewMode = api.editorViewMode) === null || _api$editorViewMode === void 0 || (_api$editorViewMode = _api$editorViewMode.sharedState.currentState()) === null || _api$editorViewMode === void 0 ? void 0 : _api$editorViewMode.mode;
|
|
169
174
|
executeProviderCode((0, _sendTransaction.sendTransaction)({
|
|
170
175
|
originalTransaction: props.originalTransaction,
|
|
@@ -174,6 +179,19 @@ var collabEditPlugin = exports.collabEditPlugin = function collabEditPlugin(_ref
|
|
|
174
179
|
useNativePlugin: (_options$useNativePlu = options === null || options === void 0 ? void 0 : options.useNativePlugin) !== null && _options$useNativePlu !== void 0 ? _options$useNativePlu : false,
|
|
175
180
|
viewMode: viewMode
|
|
176
181
|
}), addErrorAnalytics);
|
|
182
|
+
(0, _trackSteps.track)(_objectSpread(_objectSpread({}, props), {}, {
|
|
183
|
+
onTrackDataProcessed: function onTrackDataProcessed(steps) {
|
|
184
|
+
var _api$analytics2;
|
|
185
|
+
api === null || api === void 0 || (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 || (_api$analytics2 = _api$analytics2.actions) === null || _api$analytics2 === void 0 || _api$analytics2.fireAnalyticsEvent({
|
|
186
|
+
action: _analytics.ACTION.STEPS_TRACKED,
|
|
187
|
+
actionSubject: _analytics.ACTION_SUBJECT.COLLAB,
|
|
188
|
+
attributes: {
|
|
189
|
+
steps: steps
|
|
190
|
+
},
|
|
191
|
+
eventType: _analytics.EVENT_TYPE.OPERATIONAL
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
}));
|
|
177
195
|
}
|
|
178
196
|
};
|
|
179
197
|
};
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.track = exports.task = exports.sanitizeStep = exports.groupSteps = void 0;
|
|
8
|
+
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
|
|
9
|
+
var _transform = require("@atlaskit/editor-prosemirror/transform");
|
|
10
|
+
var _prosemirrorCollab = require("@atlaskit/prosemirror-collab");
|
|
11
|
+
function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
|
|
12
|
+
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
|
|
13
|
+
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
|
|
14
|
+
function groupBy(array, keyGetter) {
|
|
15
|
+
// Check group by exists, and that it's a function. If so, use the native browser code
|
|
16
|
+
if ('groupBy' in Object && typeof Object.groupBy === 'function') {
|
|
17
|
+
// @ts-ignore TS2322 - Type 'Partial<Record<string, T[]>>' is not assignable to type 'Record<string, T[]>'.
|
|
18
|
+
return Object.groupBy(array, keyGetter);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Fallback to custom implementation
|
|
22
|
+
var map = {};
|
|
23
|
+
array.forEach(function (item) {
|
|
24
|
+
var key = keyGetter(item);
|
|
25
|
+
if (!map[key]) {
|
|
26
|
+
map[key] = [];
|
|
27
|
+
}
|
|
28
|
+
map[key].push(item);
|
|
29
|
+
});
|
|
30
|
+
return map;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Sanitizes a given ProseMirror step by extracting its type and non-UCG relevant attributes.
|
|
34
|
+
*
|
|
35
|
+
* @param {Step} step - The ProseMirror step to be sanitized.
|
|
36
|
+
* @returns {SanitizedStep} - The sanitized step with only necessary information.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```
|
|
40
|
+
* const step = new AttrStep(10, 'colwidth', [123, 451] );
|
|
41
|
+
* const sanitized = sanitizeStep(step);
|
|
42
|
+
*
|
|
43
|
+
* // Output: { stepType: 'attr', attr: 'example' }
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
var sanitizeStep = exports.sanitizeStep = function sanitizeStep(step) {
|
|
47
|
+
var serializedStep = step.toJSON();
|
|
48
|
+
var sanitizedStep = {
|
|
49
|
+
stepType: serializedStep.stepType
|
|
50
|
+
};
|
|
51
|
+
if (step instanceof _transform.AttrStep || step instanceof _transform.DocAttrStep) {
|
|
52
|
+
sanitizedStep.attr = step.attr;
|
|
53
|
+
} else if (step instanceof _transform.AddMarkStep || step instanceof _transform.RemoveMarkStep || step instanceof _transform.RemoveNodeMarkStep || step instanceof _transform.AddNodeMarkStep) {
|
|
54
|
+
sanitizedStep.markType = step.mark.type.name;
|
|
55
|
+
}
|
|
56
|
+
return sanitizedStep;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Groups sanitized steps by their type and counts their occurrences.
|
|
61
|
+
*
|
|
62
|
+
* @param {SanitizedStep[]} sanitizedSteps - An array of sanitized steps.
|
|
63
|
+
* @returns {Record<string, number>} - An object where keys are step types and values are their counts.
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```
|
|
67
|
+
* const input = [
|
|
68
|
+
* { stepType: 'attr', attr: 'colwidth' },
|
|
69
|
+
* { stepType: 'mark', markType: 'bold' },
|
|
70
|
+
* { stepType: 'attr', attr: 'colwidth' }
|
|
71
|
+
* ];
|
|
72
|
+
*
|
|
73
|
+
* const grouped = groupSteps(input);
|
|
74
|
+
* // Output: { 'attr_example': 2, 'mark_bold': 1 }
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
var groupSteps = exports.groupSteps = function groupSteps(sanitizedSteps) {
|
|
78
|
+
var grouped = groupBy(sanitizedSteps, function (e) {
|
|
79
|
+
return Object.values(e).join('_');
|
|
80
|
+
});
|
|
81
|
+
return Object.entries(grouped).reduce(function (acc, _ref) {
|
|
82
|
+
var _ref2 = (0, _slicedToArray2.default)(_ref, 2),
|
|
83
|
+
key = _ref2[0],
|
|
84
|
+
value = _ref2[1];
|
|
85
|
+
acc[key] = Array.isArray(value) ? value.length : 0;
|
|
86
|
+
return acc;
|
|
87
|
+
}, {});
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Processes the steps metadata from the cache and calls the callback function with the processed data.
|
|
92
|
+
*
|
|
93
|
+
* @param {CacheType} cache - A cache containing steps metadata.
|
|
94
|
+
* @param {(data: StepMetadataAnalytics[]) => void} onTrackDataProcessed - Callback function to be called with the processed data.
|
|
95
|
+
*/
|
|
96
|
+
var task = exports.task = function task(cache, onTrackDataProcessed) {
|
|
97
|
+
var stepsMetadata = [];
|
|
98
|
+
var _iterator = _createForOfIteratorHelper(cache.values()),
|
|
99
|
+
_step;
|
|
100
|
+
try {
|
|
101
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
102
|
+
var entry = _step.value;
|
|
103
|
+
var startedAt = entry.startedAt,
|
|
104
|
+
endedAt = entry.endedAt,
|
|
105
|
+
steps = entry.steps;
|
|
106
|
+
var stepTypesAmount = groupSteps(steps.map(sanitizeStep));
|
|
107
|
+
stepsMetadata.push({
|
|
108
|
+
startedAt: startedAt,
|
|
109
|
+
endedAt: endedAt,
|
|
110
|
+
stepTypesAmount: stepTypesAmount
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
} catch (err) {
|
|
114
|
+
_iterator.e(err);
|
|
115
|
+
} finally {
|
|
116
|
+
_iterator.f();
|
|
117
|
+
}
|
|
118
|
+
cache.clear();
|
|
119
|
+
if (stepsMetadata.length > 0) {
|
|
120
|
+
onTrackDataProcessed(stepsMetadata);
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
var stepsSentCache = new Map();
|
|
124
|
+
// Every ten seconds we will try to process the step data.
|
|
125
|
+
var LOW_PRIORITY_DELAY = 10000;
|
|
126
|
+
|
|
127
|
+
// See https://developer.mozilla.org/en-US/docs/Web/API/Scheduler/
|
|
128
|
+
|
|
129
|
+
var getScheduler = function getScheduler(obj) {
|
|
130
|
+
if (!obj) {
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
if ('scheduler' in obj) {
|
|
134
|
+
return obj.scheduler;
|
|
135
|
+
}
|
|
136
|
+
return null;
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Tracks the steps sent by the client by storing them in a cache and scheduling a task to process them. Once the steps are processed, the onTrackDataProcessed callabck will be called.
|
|
141
|
+
*
|
|
142
|
+
* This is a non-critical code. If the browser doesn't support the Scheduler API https://developer.mozilla.org/en-US/docs/Web/API/Scheduler/
|
|
143
|
+
*
|
|
144
|
+
* @param {TrackProps} props - The properties required for tracking steps.
|
|
145
|
+
* @param {EditorState} props.newEditorState - The new editor state.
|
|
146
|
+
* @param {Readonly<Transaction[]>} props.transactions - The transactions that contain the steps.
|
|
147
|
+
* @param {(data: StepMetadataAnalytics[]) => void} props.onTrackDataProcessed - Callback function to be called with the processed data.
|
|
148
|
+
*/
|
|
149
|
+
var track = exports.track = function track(_ref3) {
|
|
150
|
+
var newEditorState = _ref3.newEditorState,
|
|
151
|
+
transactions = _ref3.transactions,
|
|
152
|
+
onTrackDataProcessed = _ref3.onTrackDataProcessed;
|
|
153
|
+
var newSteps = transactions.flatMap(function (t) {
|
|
154
|
+
return t.steps;
|
|
155
|
+
});
|
|
156
|
+
var collabState = (0, _prosemirrorCollab.sendableSteps)(newEditorState);
|
|
157
|
+
var scheduler = getScheduler(window);
|
|
158
|
+
if (!newSteps.length || !scheduler || !collabState) {
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
var version = collabState.version;
|
|
162
|
+
var buffer = stepsSentCache.get(version);
|
|
163
|
+
var startedAt = (buffer === null || buffer === void 0 ? void 0 : buffer.startedAt) || Date.now();
|
|
164
|
+
var endedAt = Date.now();
|
|
165
|
+
var steps = ((buffer === null || buffer === void 0 ? void 0 : buffer.steps) || []).concat(newSteps);
|
|
166
|
+
stepsSentCache.set(version, {
|
|
167
|
+
startedAt: startedAt,
|
|
168
|
+
endedAt: endedAt,
|
|
169
|
+
steps: steps
|
|
170
|
+
});
|
|
171
|
+
scheduler.postTask(function () {
|
|
172
|
+
return task(stepsSentCache, onTrackDataProcessed);
|
|
173
|
+
}, {
|
|
174
|
+
priority: 'background',
|
|
175
|
+
delay: LOW_PRIORITY_DELAY
|
|
176
|
+
});
|
|
177
|
+
};
|
package/dist/cjs/utils.js
CHANGED
|
@@ -9,7 +9,7 @@ exports.getAvatarColor = getAvatarColor;
|
|
|
9
9
|
exports.scrollToCollabCursor = exports.replaceDocument = exports.getPositionOfTelepointer = void 0;
|
|
10
10
|
var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));
|
|
11
11
|
var _analytics = require("@atlaskit/editor-common/analytics");
|
|
12
|
-
var
|
|
12
|
+
var _whitespace = require("@atlaskit/editor-common/whitespace");
|
|
13
13
|
var _state = require("@atlaskit/editor-prosemirror/state");
|
|
14
14
|
var _view = require("@atlaskit/editor-prosemirror/view");
|
|
15
15
|
var _consts = require("@atlaskit/editor-shared-styles/consts");
|
|
@@ -52,11 +52,11 @@ var createTelepointers = exports.createTelepointers = function createTelepointer
|
|
|
52
52
|
}));
|
|
53
53
|
}
|
|
54
54
|
var spaceJoinerBefore = document.createElement('span');
|
|
55
|
-
spaceJoinerBefore.textContent =
|
|
55
|
+
spaceJoinerBefore.textContent = _whitespace.ZERO_WIDTH_JOINER;
|
|
56
56
|
var spaceJoinerAfter = document.createElement('span');
|
|
57
|
-
spaceJoinerAfter.textContent =
|
|
57
|
+
spaceJoinerAfter.textContent = _whitespace.ZERO_WIDTH_JOINER;
|
|
58
58
|
var cursor = document.createElement('span');
|
|
59
|
-
cursor.textContent =
|
|
59
|
+
cursor.textContent = _whitespace.ZERO_WIDTH_JOINER;
|
|
60
60
|
cursor.className = "telepointer color-".concat(color, " telepointer-selection-badge");
|
|
61
61
|
cursor.style.cssText = "".concat(style({
|
|
62
62
|
color: avatarColor.color
|
package/dist/es2019/plugin.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ACTION, ACTION_SUBJECT, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
|
|
1
2
|
import { AddMarkStep, AddNodeMarkStep } from '@atlaskit/editor-prosemirror/transform';
|
|
2
3
|
import { collab } from '@atlaskit/prosemirror-collab';
|
|
3
4
|
import { addSynchronyErrorAnalytics } from './analytics';
|
|
@@ -6,6 +7,7 @@ import { createPlugin } from './pm-plugins/main';
|
|
|
6
7
|
import { pluginKey as mainPluginKey } from './pm-plugins/main/plugin-key';
|
|
7
8
|
import { nativeCollabProviderPlugin } from './pm-plugins/native-collab-provider-plugin';
|
|
8
9
|
import { createPlugin as createTrackNCSInitializationPlugin, trackNCSInitializationPluginKey } from './pm-plugins/track-ncs-initialization';
|
|
10
|
+
import { track } from './track-steps';
|
|
9
11
|
import { getAvatarColor } from './utils';
|
|
10
12
|
const providerBuilder = collabEditProviderPromise => async (codeToExecute, onError) => {
|
|
11
13
|
try {
|
|
@@ -132,6 +134,20 @@ export const collabEditPlugin = ({
|
|
|
132
134
|
useNativePlugin: (_options$useNativePlu = options === null || options === void 0 ? void 0 : options.useNativePlugin) !== null && _options$useNativePlu !== void 0 ? _options$useNativePlu : false,
|
|
133
135
|
viewMode
|
|
134
136
|
}), addErrorAnalytics);
|
|
137
|
+
track({
|
|
138
|
+
...props,
|
|
139
|
+
onTrackDataProcessed: steps => {
|
|
140
|
+
var _api$analytics2, _api$analytics2$actio;
|
|
141
|
+
api === null || api === void 0 ? void 0 : (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 ? void 0 : (_api$analytics2$actio = _api$analytics2.actions) === null || _api$analytics2$actio === void 0 ? void 0 : _api$analytics2$actio.fireAnalyticsEvent({
|
|
142
|
+
action: ACTION.STEPS_TRACKED,
|
|
143
|
+
actionSubject: ACTION_SUBJECT.COLLAB,
|
|
144
|
+
attributes: {
|
|
145
|
+
steps
|
|
146
|
+
},
|
|
147
|
+
eventType: EVENT_TYPE.OPERATIONAL
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
});
|
|
135
151
|
}
|
|
136
152
|
};
|
|
137
153
|
};
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { AddMarkStep, AddNodeMarkStep, AttrStep, DocAttrStep, RemoveMarkStep, RemoveNodeMarkStep } from '@atlaskit/editor-prosemirror/transform';
|
|
2
|
+
import { sendableSteps } from '@atlaskit/prosemirror-collab';
|
|
3
|
+
function groupBy(array, keyGetter) {
|
|
4
|
+
// Check group by exists, and that it's a function. If so, use the native browser code
|
|
5
|
+
if ('groupBy' in Object && typeof Object.groupBy === 'function') {
|
|
6
|
+
// @ts-ignore TS2322 - Type 'Partial<Record<string, T[]>>' is not assignable to type 'Record<string, T[]>'.
|
|
7
|
+
return Object.groupBy(array, keyGetter);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// Fallback to custom implementation
|
|
11
|
+
const map = {};
|
|
12
|
+
array.forEach(item => {
|
|
13
|
+
const key = keyGetter(item);
|
|
14
|
+
if (!map[key]) {
|
|
15
|
+
map[key] = [];
|
|
16
|
+
}
|
|
17
|
+
map[key].push(item);
|
|
18
|
+
});
|
|
19
|
+
return map;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Sanitizes a given ProseMirror step by extracting its type and non-UCG relevant attributes.
|
|
23
|
+
*
|
|
24
|
+
* @param {Step} step - The ProseMirror step to be sanitized.
|
|
25
|
+
* @returns {SanitizedStep} - The sanitized step with only necessary information.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```
|
|
29
|
+
* const step = new AttrStep(10, 'colwidth', [123, 451] );
|
|
30
|
+
* const sanitized = sanitizeStep(step);
|
|
31
|
+
*
|
|
32
|
+
* // Output: { stepType: 'attr', attr: 'example' }
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export const sanitizeStep = step => {
|
|
36
|
+
const serializedStep = step.toJSON();
|
|
37
|
+
const sanitizedStep = {
|
|
38
|
+
stepType: serializedStep.stepType
|
|
39
|
+
};
|
|
40
|
+
if (step instanceof AttrStep || step instanceof DocAttrStep) {
|
|
41
|
+
sanitizedStep.attr = step.attr;
|
|
42
|
+
} else if (step instanceof AddMarkStep || step instanceof RemoveMarkStep || step instanceof RemoveNodeMarkStep || step instanceof AddNodeMarkStep) {
|
|
43
|
+
sanitizedStep.markType = step.mark.type.name;
|
|
44
|
+
}
|
|
45
|
+
return sanitizedStep;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Groups sanitized steps by their type and counts their occurrences.
|
|
50
|
+
*
|
|
51
|
+
* @param {SanitizedStep[]} sanitizedSteps - An array of sanitized steps.
|
|
52
|
+
* @returns {Record<string, number>} - An object where keys are step types and values are their counts.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```
|
|
56
|
+
* const input = [
|
|
57
|
+
* { stepType: 'attr', attr: 'colwidth' },
|
|
58
|
+
* { stepType: 'mark', markType: 'bold' },
|
|
59
|
+
* { stepType: 'attr', attr: 'colwidth' }
|
|
60
|
+
* ];
|
|
61
|
+
*
|
|
62
|
+
* const grouped = groupSteps(input);
|
|
63
|
+
* // Output: { 'attr_example': 2, 'mark_bold': 1 }
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
export const groupSteps = sanitizedSteps => {
|
|
67
|
+
const grouped = groupBy(sanitizedSteps, e => Object.values(e).join('_'));
|
|
68
|
+
return Object.entries(grouped).reduce((acc, [key, value]) => {
|
|
69
|
+
acc[key] = Array.isArray(value) ? value.length : 0;
|
|
70
|
+
return acc;
|
|
71
|
+
}, {});
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Processes the steps metadata from the cache and calls the callback function with the processed data.
|
|
76
|
+
*
|
|
77
|
+
* @param {CacheType} cache - A cache containing steps metadata.
|
|
78
|
+
* @param {(data: StepMetadataAnalytics[]) => void} onTrackDataProcessed - Callback function to be called with the processed data.
|
|
79
|
+
*/
|
|
80
|
+
export const task = (cache, onTrackDataProcessed) => {
|
|
81
|
+
const stepsMetadata = [];
|
|
82
|
+
for (let entry of cache.values()) {
|
|
83
|
+
const {
|
|
84
|
+
startedAt,
|
|
85
|
+
endedAt,
|
|
86
|
+
steps
|
|
87
|
+
} = entry;
|
|
88
|
+
const stepTypesAmount = groupSteps(steps.map(sanitizeStep));
|
|
89
|
+
stepsMetadata.push({
|
|
90
|
+
startedAt,
|
|
91
|
+
endedAt,
|
|
92
|
+
stepTypesAmount
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
cache.clear();
|
|
96
|
+
if (stepsMetadata.length > 0) {
|
|
97
|
+
onTrackDataProcessed(stepsMetadata);
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
const stepsSentCache = new Map();
|
|
101
|
+
// Every ten seconds we will try to process the step data.
|
|
102
|
+
const LOW_PRIORITY_DELAY = 10000;
|
|
103
|
+
|
|
104
|
+
// See https://developer.mozilla.org/en-US/docs/Web/API/Scheduler/
|
|
105
|
+
|
|
106
|
+
const getScheduler = obj => {
|
|
107
|
+
if (!obj) {
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
if ('scheduler' in obj) {
|
|
111
|
+
return obj.scheduler;
|
|
112
|
+
}
|
|
113
|
+
return null;
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Tracks the steps sent by the client by storing them in a cache and scheduling a task to process them. Once the steps are processed, the onTrackDataProcessed callabck will be called.
|
|
118
|
+
*
|
|
119
|
+
* This is a non-critical code. If the browser doesn't support the Scheduler API https://developer.mozilla.org/en-US/docs/Web/API/Scheduler/
|
|
120
|
+
*
|
|
121
|
+
* @param {TrackProps} props - The properties required for tracking steps.
|
|
122
|
+
* @param {EditorState} props.newEditorState - The new editor state.
|
|
123
|
+
* @param {Readonly<Transaction[]>} props.transactions - The transactions that contain the steps.
|
|
124
|
+
* @param {(data: StepMetadataAnalytics[]) => void} props.onTrackDataProcessed - Callback function to be called with the processed data.
|
|
125
|
+
*/
|
|
126
|
+
export const track = ({
|
|
127
|
+
newEditorState,
|
|
128
|
+
transactions,
|
|
129
|
+
onTrackDataProcessed
|
|
130
|
+
}) => {
|
|
131
|
+
const newSteps = transactions.flatMap(t => t.steps);
|
|
132
|
+
const collabState = sendableSteps(newEditorState);
|
|
133
|
+
const scheduler = getScheduler(window);
|
|
134
|
+
if (!newSteps.length || !scheduler || !collabState) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
const {
|
|
138
|
+
version
|
|
139
|
+
} = collabState;
|
|
140
|
+
const buffer = stepsSentCache.get(version);
|
|
141
|
+
const startedAt = (buffer === null || buffer === void 0 ? void 0 : buffer.startedAt) || Date.now();
|
|
142
|
+
const endedAt = Date.now();
|
|
143
|
+
const steps = ((buffer === null || buffer === void 0 ? void 0 : buffer.steps) || []).concat(newSteps);
|
|
144
|
+
stepsSentCache.set(version, {
|
|
145
|
+
startedAt,
|
|
146
|
+
endedAt,
|
|
147
|
+
steps
|
|
148
|
+
});
|
|
149
|
+
scheduler.postTask(() => task(stepsSentCache, onTrackDataProcessed), {
|
|
150
|
+
priority: 'background',
|
|
151
|
+
delay: LOW_PRIORITY_DELAY
|
|
152
|
+
});
|
|
153
|
+
};
|
package/dist/es2019/utils.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ACTION, ACTION_SUBJECT, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
|
|
2
|
-
import { ZERO_WIDTH_JOINER } from '@atlaskit/editor-common/
|
|
2
|
+
import { ZERO_WIDTH_JOINER } from '@atlaskit/editor-common/whitespace';
|
|
3
3
|
import { Selection, TextSelection } from '@atlaskit/editor-prosemirror/state';
|
|
4
4
|
import { Decoration } from '@atlaskit/editor-prosemirror/view';
|
|
5
5
|
import { avatarColors } from '@atlaskit/editor-shared-styles/consts';
|
package/dist/esm/plugin.js
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
|
+
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
1
2
|
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
|
|
2
3
|
import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
|
|
4
|
+
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
5
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
3
6
|
import _regeneratorRuntime from "@babel/runtime/regenerator";
|
|
7
|
+
import { ACTION, ACTION_SUBJECT, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
|
|
4
8
|
import { AddMarkStep, AddNodeMarkStep } from '@atlaskit/editor-prosemirror/transform';
|
|
5
9
|
import { collab } from '@atlaskit/prosemirror-collab';
|
|
6
10
|
import { addSynchronyErrorAnalytics } from './analytics';
|
|
@@ -9,6 +13,7 @@ import { createPlugin } from './pm-plugins/main';
|
|
|
9
13
|
import { pluginKey as mainPluginKey } from './pm-plugins/main/plugin-key';
|
|
10
14
|
import { nativeCollabProviderPlugin } from './pm-plugins/native-collab-provider-plugin';
|
|
11
15
|
import { createPlugin as createTrackNCSInitializationPlugin, trackNCSInitializationPluginKey } from './pm-plugins/track-ncs-initialization';
|
|
16
|
+
import { track } from './track-steps';
|
|
12
17
|
import { getAvatarColor } from './utils';
|
|
13
18
|
var providerBuilder = function providerBuilder(collabEditProviderPromise) {
|
|
14
19
|
return /*#__PURE__*/function () {
|
|
@@ -167,6 +172,19 @@ export var collabEditPlugin = function collabEditPlugin(_ref4) {
|
|
|
167
172
|
useNativePlugin: (_options$useNativePlu = options === null || options === void 0 ? void 0 : options.useNativePlugin) !== null && _options$useNativePlu !== void 0 ? _options$useNativePlu : false,
|
|
168
173
|
viewMode: viewMode
|
|
169
174
|
}), addErrorAnalytics);
|
|
175
|
+
track(_objectSpread(_objectSpread({}, props), {}, {
|
|
176
|
+
onTrackDataProcessed: function onTrackDataProcessed(steps) {
|
|
177
|
+
var _api$analytics2;
|
|
178
|
+
api === null || api === void 0 || (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 || (_api$analytics2 = _api$analytics2.actions) === null || _api$analytics2 === void 0 || _api$analytics2.fireAnalyticsEvent({
|
|
179
|
+
action: ACTION.STEPS_TRACKED,
|
|
180
|
+
actionSubject: ACTION_SUBJECT.COLLAB,
|
|
181
|
+
attributes: {
|
|
182
|
+
steps: steps
|
|
183
|
+
},
|
|
184
|
+
eventType: EVENT_TYPE.OPERATIONAL
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
}));
|
|
170
188
|
}
|
|
171
189
|
};
|
|
172
190
|
};
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
|
|
2
|
+
function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
|
|
3
|
+
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
|
|
4
|
+
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
|
|
5
|
+
import { AddMarkStep, AddNodeMarkStep, AttrStep, DocAttrStep, RemoveMarkStep, RemoveNodeMarkStep } from '@atlaskit/editor-prosemirror/transform';
|
|
6
|
+
import { sendableSteps } from '@atlaskit/prosemirror-collab';
|
|
7
|
+
function groupBy(array, keyGetter) {
|
|
8
|
+
// Check group by exists, and that it's a function. If so, use the native browser code
|
|
9
|
+
if ('groupBy' in Object && typeof Object.groupBy === 'function') {
|
|
10
|
+
// @ts-ignore TS2322 - Type 'Partial<Record<string, T[]>>' is not assignable to type 'Record<string, T[]>'.
|
|
11
|
+
return Object.groupBy(array, keyGetter);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Fallback to custom implementation
|
|
15
|
+
var map = {};
|
|
16
|
+
array.forEach(function (item) {
|
|
17
|
+
var key = keyGetter(item);
|
|
18
|
+
if (!map[key]) {
|
|
19
|
+
map[key] = [];
|
|
20
|
+
}
|
|
21
|
+
map[key].push(item);
|
|
22
|
+
});
|
|
23
|
+
return map;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Sanitizes a given ProseMirror step by extracting its type and non-UCG relevant attributes.
|
|
27
|
+
*
|
|
28
|
+
* @param {Step} step - The ProseMirror step to be sanitized.
|
|
29
|
+
* @returns {SanitizedStep} - The sanitized step with only necessary information.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```
|
|
33
|
+
* const step = new AttrStep(10, 'colwidth', [123, 451] );
|
|
34
|
+
* const sanitized = sanitizeStep(step);
|
|
35
|
+
*
|
|
36
|
+
* // Output: { stepType: 'attr', attr: 'example' }
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export var sanitizeStep = function sanitizeStep(step) {
|
|
40
|
+
var serializedStep = step.toJSON();
|
|
41
|
+
var sanitizedStep = {
|
|
42
|
+
stepType: serializedStep.stepType
|
|
43
|
+
};
|
|
44
|
+
if (step instanceof AttrStep || step instanceof DocAttrStep) {
|
|
45
|
+
sanitizedStep.attr = step.attr;
|
|
46
|
+
} else if (step instanceof AddMarkStep || step instanceof RemoveMarkStep || step instanceof RemoveNodeMarkStep || step instanceof AddNodeMarkStep) {
|
|
47
|
+
sanitizedStep.markType = step.mark.type.name;
|
|
48
|
+
}
|
|
49
|
+
return sanitizedStep;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Groups sanitized steps by their type and counts their occurrences.
|
|
54
|
+
*
|
|
55
|
+
* @param {SanitizedStep[]} sanitizedSteps - An array of sanitized steps.
|
|
56
|
+
* @returns {Record<string, number>} - An object where keys are step types and values are their counts.
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```
|
|
60
|
+
* const input = [
|
|
61
|
+
* { stepType: 'attr', attr: 'colwidth' },
|
|
62
|
+
* { stepType: 'mark', markType: 'bold' },
|
|
63
|
+
* { stepType: 'attr', attr: 'colwidth' }
|
|
64
|
+
* ];
|
|
65
|
+
*
|
|
66
|
+
* const grouped = groupSteps(input);
|
|
67
|
+
* // Output: { 'attr_example': 2, 'mark_bold': 1 }
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
export var groupSteps = function groupSteps(sanitizedSteps) {
|
|
71
|
+
var grouped = groupBy(sanitizedSteps, function (e) {
|
|
72
|
+
return Object.values(e).join('_');
|
|
73
|
+
});
|
|
74
|
+
return Object.entries(grouped).reduce(function (acc, _ref) {
|
|
75
|
+
var _ref2 = _slicedToArray(_ref, 2),
|
|
76
|
+
key = _ref2[0],
|
|
77
|
+
value = _ref2[1];
|
|
78
|
+
acc[key] = Array.isArray(value) ? value.length : 0;
|
|
79
|
+
return acc;
|
|
80
|
+
}, {});
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Processes the steps metadata from the cache and calls the callback function with the processed data.
|
|
85
|
+
*
|
|
86
|
+
* @param {CacheType} cache - A cache containing steps metadata.
|
|
87
|
+
* @param {(data: StepMetadataAnalytics[]) => void} onTrackDataProcessed - Callback function to be called with the processed data.
|
|
88
|
+
*/
|
|
89
|
+
export var task = function task(cache, onTrackDataProcessed) {
|
|
90
|
+
var stepsMetadata = [];
|
|
91
|
+
var _iterator = _createForOfIteratorHelper(cache.values()),
|
|
92
|
+
_step;
|
|
93
|
+
try {
|
|
94
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
95
|
+
var entry = _step.value;
|
|
96
|
+
var startedAt = entry.startedAt,
|
|
97
|
+
endedAt = entry.endedAt,
|
|
98
|
+
steps = entry.steps;
|
|
99
|
+
var stepTypesAmount = groupSteps(steps.map(sanitizeStep));
|
|
100
|
+
stepsMetadata.push({
|
|
101
|
+
startedAt: startedAt,
|
|
102
|
+
endedAt: endedAt,
|
|
103
|
+
stepTypesAmount: stepTypesAmount
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
} catch (err) {
|
|
107
|
+
_iterator.e(err);
|
|
108
|
+
} finally {
|
|
109
|
+
_iterator.f();
|
|
110
|
+
}
|
|
111
|
+
cache.clear();
|
|
112
|
+
if (stepsMetadata.length > 0) {
|
|
113
|
+
onTrackDataProcessed(stepsMetadata);
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
var stepsSentCache = new Map();
|
|
117
|
+
// Every ten seconds we will try to process the step data.
|
|
118
|
+
var LOW_PRIORITY_DELAY = 10000;
|
|
119
|
+
|
|
120
|
+
// See https://developer.mozilla.org/en-US/docs/Web/API/Scheduler/
|
|
121
|
+
|
|
122
|
+
var getScheduler = function getScheduler(obj) {
|
|
123
|
+
if (!obj) {
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
if ('scheduler' in obj) {
|
|
127
|
+
return obj.scheduler;
|
|
128
|
+
}
|
|
129
|
+
return null;
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Tracks the steps sent by the client by storing them in a cache and scheduling a task to process them. Once the steps are processed, the onTrackDataProcessed callabck will be called.
|
|
134
|
+
*
|
|
135
|
+
* This is a non-critical code. If the browser doesn't support the Scheduler API https://developer.mozilla.org/en-US/docs/Web/API/Scheduler/
|
|
136
|
+
*
|
|
137
|
+
* @param {TrackProps} props - The properties required for tracking steps.
|
|
138
|
+
* @param {EditorState} props.newEditorState - The new editor state.
|
|
139
|
+
* @param {Readonly<Transaction[]>} props.transactions - The transactions that contain the steps.
|
|
140
|
+
* @param {(data: StepMetadataAnalytics[]) => void} props.onTrackDataProcessed - Callback function to be called with the processed data.
|
|
141
|
+
*/
|
|
142
|
+
export var track = function track(_ref3) {
|
|
143
|
+
var newEditorState = _ref3.newEditorState,
|
|
144
|
+
transactions = _ref3.transactions,
|
|
145
|
+
onTrackDataProcessed = _ref3.onTrackDataProcessed;
|
|
146
|
+
var newSteps = transactions.flatMap(function (t) {
|
|
147
|
+
return t.steps;
|
|
148
|
+
});
|
|
149
|
+
var collabState = sendableSteps(newEditorState);
|
|
150
|
+
var scheduler = getScheduler(window);
|
|
151
|
+
if (!newSteps.length || !scheduler || !collabState) {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
var version = collabState.version;
|
|
155
|
+
var buffer = stepsSentCache.get(version);
|
|
156
|
+
var startedAt = (buffer === null || buffer === void 0 ? void 0 : buffer.startedAt) || Date.now();
|
|
157
|
+
var endedAt = Date.now();
|
|
158
|
+
var steps = ((buffer === null || buffer === void 0 ? void 0 : buffer.steps) || []).concat(newSteps);
|
|
159
|
+
stepsSentCache.set(version, {
|
|
160
|
+
startedAt: startedAt,
|
|
161
|
+
endedAt: endedAt,
|
|
162
|
+
steps: steps
|
|
163
|
+
});
|
|
164
|
+
scheduler.postTask(function () {
|
|
165
|
+
return task(stepsSentCache, onTrackDataProcessed);
|
|
166
|
+
}, {
|
|
167
|
+
priority: 'background',
|
|
168
|
+
delay: LOW_PRIORITY_DELAY
|
|
169
|
+
});
|
|
170
|
+
};
|
package/dist/esm/utils.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import _typeof from "@babel/runtime/helpers/typeof";
|
|
2
2
|
import { ACTION, ACTION_SUBJECT, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
|
|
3
|
-
import { ZERO_WIDTH_JOINER } from '@atlaskit/editor-common/
|
|
3
|
+
import { ZERO_WIDTH_JOINER } from '@atlaskit/editor-common/whitespace';
|
|
4
4
|
import { Selection, TextSelection } from '@atlaskit/editor-prosemirror/state';
|
|
5
5
|
import { Decoration } from '@atlaskit/editor-prosemirror/view';
|
|
6
6
|
import { avatarColors } from '@atlaskit/editor-shared-styles/consts';
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type { EditorState, Transaction } from '@atlaskit/editor-prosemirror/state';
|
|
2
|
+
import type { Step } from '@atlaskit/editor-prosemirror/transform';
|
|
3
|
+
export type SanitizedStep = {
|
|
4
|
+
stepType: string;
|
|
5
|
+
attr?: string;
|
|
6
|
+
markType?: string;
|
|
7
|
+
};
|
|
8
|
+
export type StepMetadataAnalytics = {
|
|
9
|
+
startedAt: number;
|
|
10
|
+
endedAt: number;
|
|
11
|
+
stepTypesAmount: {
|
|
12
|
+
[key: string]: number;
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Sanitizes a given ProseMirror step by extracting its type and non-UCG relevant attributes.
|
|
17
|
+
*
|
|
18
|
+
* @param {Step} step - The ProseMirror step to be sanitized.
|
|
19
|
+
* @returns {SanitizedStep} - The sanitized step with only necessary information.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```
|
|
23
|
+
* const step = new AttrStep(10, 'colwidth', [123, 451] );
|
|
24
|
+
* const sanitized = sanitizeStep(step);
|
|
25
|
+
*
|
|
26
|
+
* // Output: { stepType: 'attr', attr: 'example' }
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare const sanitizeStep: (step: Step) => SanitizedStep;
|
|
30
|
+
/**
|
|
31
|
+
* Groups sanitized steps by their type and counts their occurrences.
|
|
32
|
+
*
|
|
33
|
+
* @param {SanitizedStep[]} sanitizedSteps - An array of sanitized steps.
|
|
34
|
+
* @returns {Record<string, number>} - An object where keys are step types and values are their counts.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```
|
|
38
|
+
* const input = [
|
|
39
|
+
* { stepType: 'attr', attr: 'colwidth' },
|
|
40
|
+
* { stepType: 'mark', markType: 'bold' },
|
|
41
|
+
* { stepType: 'attr', attr: 'colwidth' }
|
|
42
|
+
* ];
|
|
43
|
+
*
|
|
44
|
+
* const grouped = groupSteps(input);
|
|
45
|
+
* // Output: { 'attr_example': 2, 'mark_bold': 1 }
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export declare const groupSteps: (sanitizedSteps: SanitizedStep[]) => Record<string, number>;
|
|
49
|
+
/**
|
|
50
|
+
* Processes the steps metadata from the cache and calls the callback function with the processed data.
|
|
51
|
+
*
|
|
52
|
+
* @param {CacheType} cache - A cache containing steps metadata.
|
|
53
|
+
* @param {(data: StepMetadataAnalytics[]) => void} onTrackDataProcessed - Callback function to be called with the processed data.
|
|
54
|
+
*/
|
|
55
|
+
export declare const task: (cache: CacheType, onTrackDataProcessed: (data: StepMetadataAnalytics[]) => void) => void;
|
|
56
|
+
export type CacheType = Map<number, {
|
|
57
|
+
steps: ReadonlyArray<Step>;
|
|
58
|
+
startedAt: number;
|
|
59
|
+
endedAt: number;
|
|
60
|
+
}>;
|
|
61
|
+
type TrackProps = {
|
|
62
|
+
newEditorState: EditorState;
|
|
63
|
+
transactions: Readonly<Transaction[]>;
|
|
64
|
+
onTrackDataProcessed: (data: StepMetadataAnalytics[]) => void;
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Tracks the steps sent by the client by storing them in a cache and scheduling a task to process them. Once the steps are processed, the onTrackDataProcessed callabck will be called.
|
|
68
|
+
*
|
|
69
|
+
* This is a non-critical code. If the browser doesn't support the Scheduler API https://developer.mozilla.org/en-US/docs/Web/API/Scheduler/
|
|
70
|
+
*
|
|
71
|
+
* @param {TrackProps} props - The properties required for tracking steps.
|
|
72
|
+
* @param {EditorState} props.newEditorState - The new editor state.
|
|
73
|
+
* @param {Readonly<Transaction[]>} props.transactions - The transactions that contain the steps.
|
|
74
|
+
* @param {(data: StepMetadataAnalytics[]) => void} props.onTrackDataProcessed - Callback function to be called with the processed data.
|
|
75
|
+
*/
|
|
76
|
+
export declare const track: ({ newEditorState, transactions, onTrackDataProcessed }: TrackProps) => void;
|
|
77
|
+
export {};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type { EditorState, Transaction } from '@atlaskit/editor-prosemirror/state';
|
|
2
|
+
import type { Step } from '@atlaskit/editor-prosemirror/transform';
|
|
3
|
+
export type SanitizedStep = {
|
|
4
|
+
stepType: string;
|
|
5
|
+
attr?: string;
|
|
6
|
+
markType?: string;
|
|
7
|
+
};
|
|
8
|
+
export type StepMetadataAnalytics = {
|
|
9
|
+
startedAt: number;
|
|
10
|
+
endedAt: number;
|
|
11
|
+
stepTypesAmount: {
|
|
12
|
+
[key: string]: number;
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Sanitizes a given ProseMirror step by extracting its type and non-UCG relevant attributes.
|
|
17
|
+
*
|
|
18
|
+
* @param {Step} step - The ProseMirror step to be sanitized.
|
|
19
|
+
* @returns {SanitizedStep} - The sanitized step with only necessary information.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```
|
|
23
|
+
* const step = new AttrStep(10, 'colwidth', [123, 451] );
|
|
24
|
+
* const sanitized = sanitizeStep(step);
|
|
25
|
+
*
|
|
26
|
+
* // Output: { stepType: 'attr', attr: 'example' }
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare const sanitizeStep: (step: Step) => SanitizedStep;
|
|
30
|
+
/**
|
|
31
|
+
* Groups sanitized steps by their type and counts their occurrences.
|
|
32
|
+
*
|
|
33
|
+
* @param {SanitizedStep[]} sanitizedSteps - An array of sanitized steps.
|
|
34
|
+
* @returns {Record<string, number>} - An object where keys are step types and values are their counts.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```
|
|
38
|
+
* const input = [
|
|
39
|
+
* { stepType: 'attr', attr: 'colwidth' },
|
|
40
|
+
* { stepType: 'mark', markType: 'bold' },
|
|
41
|
+
* { stepType: 'attr', attr: 'colwidth' }
|
|
42
|
+
* ];
|
|
43
|
+
*
|
|
44
|
+
* const grouped = groupSteps(input);
|
|
45
|
+
* // Output: { 'attr_example': 2, 'mark_bold': 1 }
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export declare const groupSteps: (sanitizedSteps: SanitizedStep[]) => Record<string, number>;
|
|
49
|
+
/**
|
|
50
|
+
* Processes the steps metadata from the cache and calls the callback function with the processed data.
|
|
51
|
+
*
|
|
52
|
+
* @param {CacheType} cache - A cache containing steps metadata.
|
|
53
|
+
* @param {(data: StepMetadataAnalytics[]) => void} onTrackDataProcessed - Callback function to be called with the processed data.
|
|
54
|
+
*/
|
|
55
|
+
export declare const task: (cache: CacheType, onTrackDataProcessed: (data: StepMetadataAnalytics[]) => void) => void;
|
|
56
|
+
export type CacheType = Map<number, {
|
|
57
|
+
steps: ReadonlyArray<Step>;
|
|
58
|
+
startedAt: number;
|
|
59
|
+
endedAt: number;
|
|
60
|
+
}>;
|
|
61
|
+
type TrackProps = {
|
|
62
|
+
newEditorState: EditorState;
|
|
63
|
+
transactions: Readonly<Transaction[]>;
|
|
64
|
+
onTrackDataProcessed: (data: StepMetadataAnalytics[]) => void;
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Tracks the steps sent by the client by storing them in a cache and scheduling a task to process them. Once the steps are processed, the onTrackDataProcessed callabck will be called.
|
|
68
|
+
*
|
|
69
|
+
* This is a non-critical code. If the browser doesn't support the Scheduler API https://developer.mozilla.org/en-US/docs/Web/API/Scheduler/
|
|
70
|
+
*
|
|
71
|
+
* @param {TrackProps} props - The properties required for tracking steps.
|
|
72
|
+
* @param {EditorState} props.newEditorState - The new editor state.
|
|
73
|
+
* @param {Readonly<Transaction[]>} props.transactions - The transactions that contain the steps.
|
|
74
|
+
* @param {(data: StepMetadataAnalytics[]) => void} props.onTrackDataProcessed - Callback function to be called with the processed data.
|
|
75
|
+
*/
|
|
76
|
+
export declare const track: ({ newEditorState, transactions, onTrackDataProcessed }: TrackProps) => void;
|
|
77
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/editor-plugin-collab-edit",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.5",
|
|
4
4
|
"description": "Collab Edit plugin for @atlaskit/editor-core",
|
|
5
5
|
"author": "Atlassian Pty Ltd",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@atlaskit/adf-schema": "^39.0.3",
|
|
36
36
|
"@atlaskit/custom-steps": "^0.4.0",
|
|
37
|
-
"@atlaskit/editor-common": "^84.
|
|
37
|
+
"@atlaskit/editor-common": "^84.3.0",
|
|
38
38
|
"@atlaskit/editor-plugin-analytics": "1.4.2",
|
|
39
39
|
"@atlaskit/editor-plugin-editor-viewmode": "^2.0.0",
|
|
40
40
|
"@atlaskit/editor-plugin-feature-flags": "^1.1.0",
|