@atlaskit/editor-plugin-metrics 3.2.2 → 3.2.3

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 CHANGED
@@ -1,5 +1,14 @@
1
1
  # @atlaskit/editor-plugin-metrics
2
2
 
3
+ ## 3.2.3
4
+
5
+ ### Patch Changes
6
+
7
+ - [#118316](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/118316)
8
+ [`642dc2d7b337a`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/642dc2d7b337a) -
9
+ ED-26237 Update ease of use metrics to check nodeAttribute changes
10
+ - Updated dependencies
11
+
3
12
  ## 3.2.2
4
13
 
5
14
  ### Patch Changes
@@ -9,11 +9,11 @@ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/de
9
9
  var _bindEventListener = require("bind-event-listener");
10
10
  var _safePlugin = require("@atlaskit/editor-common/safe-plugin");
11
11
  var _state = require("@atlaskit/editor-prosemirror/state");
12
- var _transform = require("@atlaskit/editor-prosemirror/transform");
13
12
  var _activeSessionTimer = require("./utils/active-session-timer");
14
13
  var _analytics = require("./utils/analytics");
15
14
  var _checkTrActionType = require("./utils/check-tr-action-type");
16
15
  var _isNonTextUndo = require("./utils/is-non-text-undo");
16
+ var _isTrWithDocChanges = require("./utils/is-tr-with-doc-changes");
17
17
  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; }
18
18
  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; }
19
19
  var metricsKey = exports.metricsKey = new _state.PluginKey('metricsPlugin');
@@ -32,7 +32,8 @@ var initialPluginState = exports.initialPluginState = {
32
32
  contentMovedCount: 0,
33
33
  nodeDeletionCount: 0,
34
34
  undoCount: 0
35
- }
35
+ },
36
+ repeatedActionCount: 0
36
37
  };
37
38
  var createPlugin = exports.createPlugin = function createPlugin(api) {
38
39
  var timer = new _activeSessionTimer.ActiveSessionTimer(api);
@@ -46,7 +47,7 @@ var createPlugin = exports.createPlugin = function createPlugin(api) {
46
47
  },
47
48
  // eslint-disable-next-line @typescript-eslint/max-params
48
49
  apply: function apply(tr, pluginState, oldState, newState) {
49
- var _meta$shouldPersistAc, _tr$steps;
50
+ var _meta$shouldPersistAc;
50
51
  if (tr.getMeta('isRemote') || tr.getMeta('replaceDocument')) {
51
52
  return pluginState;
52
53
  }
@@ -59,9 +60,7 @@ var createPlugin = exports.createPlugin = function createPlugin(api) {
59
60
  });
60
61
  }
61
62
  var shouldPersistActiveSession = (_meta$shouldPersistAc = meta === null || meta === void 0 ? void 0 : meta.shouldPersistActiveSession) !== null && _meta$shouldPersistAc !== void 0 ? _meta$shouldPersistAc : pluginState.shouldPersistActiveSession;
62
- var hasDocChanges = tr.steps.length > 0 && ((_tr$steps = tr.steps) === null || _tr$steps === void 0 ? void 0 : _tr$steps.some(function (step) {
63
- return step instanceof _transform.ReplaceStep || step instanceof _transform.ReplaceAroundStep || step instanceof _transform.AddMarkStep;
64
- }));
63
+ var hasDocChanges = (0, _isTrWithDocChanges.isTrWithDocChanges)(tr);
65
64
  var intentToStartEditTime = (meta === null || meta === void 0 ? void 0 : meta.intentToStartEditTime) || pluginState.intentToStartEditTime;
66
65
  var now = performance.now();
67
66
  if (!intentToStartEditTime && !hasDocChanges && !tr.storedMarksSet) {
@@ -121,17 +120,35 @@ var createPlugin = exports.createPlugin = function createPlugin(api) {
121
120
  if (timeOfLastTextInput && isTextInput && previousTrType && [_checkTrActionType.ActionType.TEXT_INPUT, _checkTrActionType.ActionType.EMPTY_LINE_ADDED_OR_DELETED, _checkTrActionType.ActionType.UPDATING_NEW_LIST_TYPE_ITEM, _checkTrActionType.ActionType.INSERTING_NEW_LIST_TYPE_NODE].includes(previousTrType.type)) {
122
121
  newTextInputCount = actionTypeCount.textInputCount;
123
122
  }
123
+ var newNodeAttrCount = actionTypeCount.nodeAttributeChangeCount;
124
+ var newRepeatedActionCount = pluginState.repeatedActionCount;
125
+ if ((trType === null || trType === void 0 ? void 0 : trType.type) === _checkTrActionType.ActionType.CHANGING_ATTRS) {
126
+ newNodeAttrCount = newNodeAttrCount + 1;
127
+ if ((previousTrType === null || previousTrType === void 0 ? void 0 : previousTrType.type) === _checkTrActionType.ActionType.CHANGING_ATTRS) {
128
+ var _trType$extraData2 = trType.extraData,
129
+ newAttr = _trType$extraData2.attr,
130
+ newFrom = _trType$extraData2.from,
131
+ newTo = _trType$extraData2.to;
132
+ var _previousTrType$extra2 = previousTrType.extraData,
133
+ prevAttr = _previousTrType$extra2.attr,
134
+ prevFrom = _previousTrType$extra2.from,
135
+ prevTo = _previousTrType$extra2.to;
136
+ newRepeatedActionCount = newAttr === prevAttr && newFrom === prevFrom && newTo === prevTo ? newRepeatedActionCount + 1 : newRepeatedActionCount;
137
+ }
138
+ }
124
139
  var newPluginState = _objectSpread(_objectSpread({}, pluginState), {}, {
125
140
  activeSessionTime: now - intentToStartEditTime,
126
141
  totalActionCount: newTotalActionCount,
127
142
  timeOfLastTextInput: shouldSetTimeOfLastTextInput ? now : undefined,
128
143
  contentSizeChanged: pluginState.contentSizeChanged + (newState.doc.content.size - oldState.doc.content.size),
129
144
  actionTypeCount: _objectSpread(_objectSpread({}, newActionTypeCount), {}, {
130
- textInputCount: newTextInputCount
145
+ textInputCount: newTextInputCount,
146
+ nodeAttributeChangeCount: newNodeAttrCount
131
147
  }),
132
148
  intentToStartEditTime: intentToStartEditTime,
133
149
  shouldPersistActiveSession: shouldPersistActiveSession,
134
- previousTrType: trType
150
+ previousTrType: trType,
151
+ repeatedActionCount: newRepeatedActionCount
135
152
  });
136
153
  return newPluginState;
137
154
  }
@@ -22,7 +22,7 @@ var getPayloadAttributes = exports.getPayloadAttributes = function getPayloadAtt
22
22
  },
23
23
  effectiveness: {
24
24
  undoCount: pluginState.actionTypeCount.undoCount,
25
- repeatedActionCount: 0,
25
+ repeatedActionCount: pluginState.repeatedActionCount,
26
26
  safeInsertCount: 0
27
27
  },
28
28
  contentSizeChanged: contentSizeChanged
@@ -63,7 +63,7 @@ var getAnalyticsPayload = exports.getAnalyticsPayload = function getAnalyticsPay
63
63
  },
64
64
  effectiveness: {
65
65
  undoCount: pluginState.actionTypeCount.undoCount,
66
- repeatedActionCount: 0,
66
+ repeatedActionCount: pluginState.repeatedActionCount,
67
67
  safeInsertCount: 0
68
68
  },
69
69
  contentSizeChanged: pluginState.contentSizeChanged
@@ -6,8 +6,12 @@ Object.defineProperty(exports, "__esModule", {
6
6
  });
7
7
  exports.shouldSkipTr = exports.checkTrActionType = exports.ActionType = void 0;
8
8
  var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
9
+ var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
9
10
  var _steps = require("@atlaskit/adf-schema/steps");
10
11
  var _transform = require("@atlaskit/editor-prosemirror/transform");
12
+ function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, 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 o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
13
+ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
14
+ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
11
15
  var ActionType = exports.ActionType = /*#__PURE__*/function (ActionType) {
12
16
  ActionType["TEXT_INPUT"] = "textInput";
13
17
  ActionType["EMPTY_LINE_ADDED_OR_DELETED"] = "emptyLineAddedOrDeleted";
@@ -16,6 +20,8 @@ var ActionType = exports.ActionType = /*#__PURE__*/function (ActionType) {
16
20
  ActionType["UPDATING_NEW_LIST_TYPE_ITEM"] = "updatingNewListItem";
17
21
  ActionType["ADDING_LINK"] = "addingLink";
18
22
  ActionType["UPDATING_STATUS"] = "updatingStatus";
23
+ ActionType["CHANGING_MARK"] = "changingMark";
24
+ ActionType["CHANGING_ATTRS"] = "changingAttrs";
19
25
  return ActionType;
20
26
  }({});
21
27
  var isTextInput = function isTextInput(step) {
@@ -43,20 +49,104 @@ var isEmptyLineAddedOrDeleted = function isEmptyLineAddedOrDeleted(step) {
43
49
  });
44
50
  return isEmptyLineAdded;
45
51
  };
52
+ var compareAttributes = function compareAttributes(prevAttr, newAttr) {
53
+ var allKeys = new Set([].concat((0, _toConsumableArray2.default)(Object.keys(prevAttr)), (0, _toConsumableArray2.default)(Object.keys(newAttr))));
54
+ var _iterator = _createForOfIteratorHelper(allKeys),
55
+ _step;
56
+ try {
57
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
58
+ var key = _step.value;
59
+ var prevValue = prevAttr[key];
60
+ var newValue = newAttr[key];
61
+ if (prevValue !== newValue) {
62
+ return key;
63
+ }
64
+ }
65
+ } catch (err) {
66
+ _iterator.e(err);
67
+ } finally {
68
+ _iterator.f();
69
+ }
70
+ return undefined;
71
+ };
72
+ var compareMarks = function compareMarks(prevMarks, newMarks) {
73
+ if (!prevMarks && !newMarks) {
74
+ return undefined;
75
+ }
76
+ var previousMarksArr = new Map(prevMarks.map(function (mark) {
77
+ return [mark.type.name, mark.attrs];
78
+ }));
79
+ var newMarksArr = new Map(newMarks.map(function (mark) {
80
+ return [mark.type.name, mark.attrs];
81
+ }));
82
+ var allMarks = new Set([].concat((0, _toConsumableArray2.default)(previousMarksArr.keys()), (0, _toConsumableArray2.default)(newMarksArr.keys())));
83
+ var _iterator2 = _createForOfIteratorHelper(allMarks),
84
+ _step2;
85
+ try {
86
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
87
+ var key = _step2.value;
88
+ var previousValue = previousMarksArr.get(key);
89
+ var newValue = newMarksArr.get(key);
90
+ if (JSON.stringify(previousValue) !== JSON.stringify(newValue)) {
91
+ return key;
92
+ }
93
+ }
94
+ } catch (err) {
95
+ _iterator2.e(err);
96
+ } finally {
97
+ _iterator2.f();
98
+ }
99
+ return undefined;
100
+ };
101
+ var detectNodeAttributeChange = function detectNodeAttributeChange(tr, step) {
102
+ var from = step.from,
103
+ slice = step.slice,
104
+ to = step.to;
105
+ var oldNode = tr.docs[0].nodeAt(from);
106
+ var newNode = slice.content.firstChild;
107
+ if (!oldNode || !newNode) {
108
+ return;
109
+ }
110
+ var changedAttr = compareAttributes(oldNode.attrs, newNode.attrs);
111
+ if (changedAttr) {
112
+ return {
113
+ attr: changedAttr,
114
+ from: from,
115
+ to: to
116
+ };
117
+ }
118
+ var changedMarks = compareMarks(oldNode.marks, newNode.marks);
119
+ if (changedMarks) {
120
+ return {
121
+ attr: changedMarks,
122
+ from: from,
123
+ to: to
124
+ };
125
+ }
126
+ return undefined;
127
+ };
46
128
  var isUpdatingListTypeNode = function isUpdatingListTypeNode(step) {
47
129
  var slice = step.slice;
48
130
  var childCount = slice.content.childCount;
49
131
  if (childCount < 1) {
50
132
  return false;
51
133
  }
52
- var isListTypeNode = false;
53
- slice.content.forEach(function (node) {
54
- isListTypeNode = ['decisionList', 'decisionItem', 'bulletList', 'listItem', 'orderedList', 'taskList', 'taskItem'].includes(node.type.name);
55
- });
56
- if (!isListTypeNode) {
57
- return false;
134
+ var _iterator3 = _createForOfIteratorHelper(slice.content.content),
135
+ _step3;
136
+ try {
137
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
138
+ var node = _step3.value;
139
+ var isListTypeNode = ['decisionList', 'decisionItem', 'bulletList', 'listItem', 'orderedList', 'taskList', 'taskItem'].includes(node.type.name);
140
+ if (isListTypeNode) {
141
+ return childCount === 1 ? ActionType.INSERTING_NEW_LIST_TYPE_NODE : ActionType.UPDATING_NEW_LIST_TYPE_ITEM;
142
+ }
143
+ }
144
+ } catch (err) {
145
+ _iterator3.e(err);
146
+ } finally {
147
+ _iterator3.f();
58
148
  }
59
- return childCount === 1 ? ActionType.INSERTING_NEW_LIST_TYPE_NODE : ActionType.UPDATING_NEW_LIST_TYPE_ITEM;
149
+ return false;
60
150
  };
61
151
  var isUpdatingStatus = function isUpdatingStatus(step) {
62
152
  var slice = step.slice;
@@ -106,6 +196,45 @@ var shouldSkipTr = exports.shouldSkipTr = function shouldSkipTr(tr) {
106
196
  return tr.getMeta('appendedTransaction');
107
197
  }
108
198
  };
199
+ var isResizingColumns = function isResizingColumns(tr) {
200
+ var COL_WIDTH_ATTR = 'colwidth';
201
+ var steps = tr.steps;
202
+ var resizingColumnStep = steps.find(function (step) {
203
+ return step instanceof _transform.AttrStep || step instanceof _steps.BatchAttrsStep;
204
+ });
205
+ if (!resizingColumnStep) {
206
+ return undefined;
207
+ }
208
+ var pos;
209
+
210
+ // BatchAttrsStep is used for resizing columns in tables
211
+ if (resizingColumnStep instanceof _steps.BatchAttrsStep) {
212
+ var _resizingColumnStep$d = resizingColumnStep.data[0],
213
+ attrs = _resizingColumnStep$d.attrs,
214
+ nodeType = _resizingColumnStep$d.nodeType,
215
+ position = _resizingColumnStep$d.position;
216
+ if (['tableHeader', 'tableCell'].includes(nodeType) && attrs !== null && attrs !== void 0 && attrs[COL_WIDTH_ATTR]) {
217
+ pos = position;
218
+ }
219
+ } else if (resizingColumnStep instanceof _transform.AttrStep && resizingColumnStep.attr === COL_WIDTH_ATTR) {
220
+ pos = resizingColumnStep.pos;
221
+ }
222
+ if (!pos) {
223
+ return undefined;
224
+ }
225
+ var $pos = tr.doc.resolve(pos);
226
+ var blockRange = $pos.blockRange();
227
+ if (!blockRange) {
228
+ return undefined;
229
+ }
230
+ var from = blockRange.start;
231
+ var to = from + blockRange.parent.content.size;
232
+ return {
233
+ attr: COL_WIDTH_ATTR,
234
+ from: from,
235
+ to: to
236
+ };
237
+ };
109
238
  var checkTrActionType = exports.checkTrActionType = function checkTrActionType(tr) {
110
239
  if (tr.getMeta('input_rule_plugin_transaction')) {
111
240
  return {
@@ -121,10 +250,27 @@ var checkTrActionType = exports.checkTrActionType = function checkTrActionType(t
121
250
  type: ActionType.ADDING_LINK
122
251
  };
123
252
  }
253
+ var isResizingCol = isResizingColumns(tr);
254
+ if (isResizingCol) {
255
+ return {
256
+ type: ActionType.CHANGING_ATTRS,
257
+ extraData: isResizingCol
258
+ };
259
+ }
124
260
  var _tr$steps = (0, _slicedToArray2.default)(tr.steps, 1),
125
261
  firstStep = _tr$steps[0];
126
262
  var isReplaceStep = firstStep instanceof _transform.ReplaceStep;
127
263
  var isReplaceAroundStep = firstStep instanceof _transform.ReplaceAroundStep;
264
+ if (firstStep instanceof _transform.AddMarkStep || firstStep instanceof _transform.RemoveMarkStep) {
265
+ return {
266
+ type: ActionType.CHANGING_MARK,
267
+ extraData: {
268
+ markType: firstStep.mark.type.name,
269
+ from: firstStep.from,
270
+ to: firstStep.to
271
+ }
272
+ };
273
+ }
128
274
  if (!isReplaceStep && !isReplaceAroundStep) {
129
275
  return undefined;
130
276
  }
@@ -155,5 +301,12 @@ var checkTrActionType = exports.checkTrActionType = function checkTrActionType(t
155
301
  type: updatingListTypeNode
156
302
  };
157
303
  }
304
+ var nodeAttributeChange = detectNodeAttributeChange(tr, firstStep);
305
+ if (nodeAttributeChange) {
306
+ return {
307
+ type: ActionType.CHANGING_ATTRS,
308
+ extraData: nodeAttributeChange
309
+ };
310
+ }
158
311
  return undefined;
159
312
  };
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.isTrWithDocChanges = void 0;
7
+ var _steps = require("@atlaskit/adf-schema/steps");
8
+ var _transform = require("@atlaskit/editor-prosemirror/transform");
9
+ var isTrWithDocChanges = exports.isTrWithDocChanges = function isTrWithDocChanges(tr) {
10
+ var _tr$steps;
11
+ return tr.steps.length > 0 && ((_tr$steps = tr.steps) === null || _tr$steps === void 0 ? void 0 : _tr$steps.some(function (step) {
12
+ return step instanceof _transform.ReplaceStep || step instanceof _transform.ReplaceAroundStep || step instanceof _transform.AddMarkStep || step instanceof _transform.AttrStep || step instanceof _transform.RemoveMarkStep || step instanceof _steps.BatchAttrsStep;
13
+ }));
14
+ };
@@ -1,11 +1,11 @@
1
1
  import { bind } from 'bind-event-listener';
2
2
  import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
3
3
  import { PluginKey } from '@atlaskit/editor-prosemirror/state';
4
- import { AddMarkStep, ReplaceAroundStep, ReplaceStep } from '@atlaskit/editor-prosemirror/transform';
5
4
  import { ActiveSessionTimer } from './utils/active-session-timer';
6
5
  import { getAnalyticsPayload } from './utils/analytics';
7
6
  import { ActionType, checkTrActionType, shouldSkipTr } from './utils/check-tr-action-type';
8
7
  import { isNonTextUndo } from './utils/is-non-text-undo';
8
+ import { isTrWithDocChanges } from './utils/is-tr-with-doc-changes';
9
9
  export const metricsKey = new PluginKey('metricsPlugin');
10
10
  export const initialPluginState = {
11
11
  intentToStartEditTime: undefined,
@@ -22,7 +22,8 @@ export const initialPluginState = {
22
22
  contentMovedCount: 0,
23
23
  nodeDeletionCount: 0,
24
24
  undoCount: 0
25
- }
25
+ },
26
+ repeatedActionCount: 0
26
27
  };
27
28
  export const createPlugin = api => {
28
29
  const timer = new ActiveSessionTimer(api);
@@ -37,7 +38,7 @@ export const createPlugin = api => {
37
38
  },
38
39
  // eslint-disable-next-line @typescript-eslint/max-params
39
40
  apply(tr, pluginState, oldState, newState) {
40
- var _meta$shouldPersistAc, _tr$steps;
41
+ var _meta$shouldPersistAc;
41
42
  if (tr.getMeta('isRemote') || tr.getMeta('replaceDocument')) {
42
43
  return pluginState;
43
44
  }
@@ -51,7 +52,7 @@ export const createPlugin = api => {
51
52
  };
52
53
  }
53
54
  const shouldPersistActiveSession = (_meta$shouldPersistAc = meta === null || meta === void 0 ? void 0 : meta.shouldPersistActiveSession) !== null && _meta$shouldPersistAc !== void 0 ? _meta$shouldPersistAc : pluginState.shouldPersistActiveSession;
54
- const hasDocChanges = tr.steps.length > 0 && ((_tr$steps = tr.steps) === null || _tr$steps === void 0 ? void 0 : _tr$steps.some(step => step instanceof ReplaceStep || step instanceof ReplaceAroundStep || step instanceof AddMarkStep));
55
+ const hasDocChanges = isTrWithDocChanges(tr);
55
56
  let intentToStartEditTime = (meta === null || meta === void 0 ? void 0 : meta.intentToStartEditTime) || pluginState.intentToStartEditTime;
56
57
  const now = performance.now();
57
58
  if (!intentToStartEditTime && !hasDocChanges && !tr.storedMarksSet) {
@@ -115,6 +116,24 @@ export const createPlugin = api => {
115
116
  if (timeOfLastTextInput && isTextInput && previousTrType && [ActionType.TEXT_INPUT, ActionType.EMPTY_LINE_ADDED_OR_DELETED, ActionType.UPDATING_NEW_LIST_TYPE_ITEM, ActionType.INSERTING_NEW_LIST_TYPE_NODE].includes(previousTrType.type)) {
116
117
  newTextInputCount = actionTypeCount.textInputCount;
117
118
  }
119
+ let newNodeAttrCount = actionTypeCount.nodeAttributeChangeCount;
120
+ let newRepeatedActionCount = pluginState.repeatedActionCount;
121
+ if ((trType === null || trType === void 0 ? void 0 : trType.type) === ActionType.CHANGING_ATTRS) {
122
+ newNodeAttrCount = newNodeAttrCount + 1;
123
+ if ((previousTrType === null || previousTrType === void 0 ? void 0 : previousTrType.type) === ActionType.CHANGING_ATTRS) {
124
+ const {
125
+ attr: newAttr,
126
+ from: newFrom,
127
+ to: newTo
128
+ } = trType.extraData;
129
+ const {
130
+ attr: prevAttr,
131
+ from: prevFrom,
132
+ to: prevTo
133
+ } = previousTrType.extraData;
134
+ newRepeatedActionCount = newAttr === prevAttr && newFrom === prevFrom && newTo === prevTo ? newRepeatedActionCount + 1 : newRepeatedActionCount;
135
+ }
136
+ }
118
137
  const newPluginState = {
119
138
  ...pluginState,
120
139
  activeSessionTime: now - intentToStartEditTime,
@@ -123,11 +142,13 @@ export const createPlugin = api => {
123
142
  contentSizeChanged: pluginState.contentSizeChanged + (newState.doc.content.size - oldState.doc.content.size),
124
143
  actionTypeCount: {
125
144
  ...newActionTypeCount,
126
- textInputCount: newTextInputCount
145
+ textInputCount: newTextInputCount,
146
+ nodeAttributeChangeCount: newNodeAttrCount
127
147
  },
128
148
  intentToStartEditTime,
129
149
  shouldPersistActiveSession,
130
- previousTrType: trType
150
+ previousTrType: trType,
151
+ repeatedActionCount: newRepeatedActionCount
131
152
  };
132
153
  return newPluginState;
133
154
  }
@@ -11,7 +11,7 @@ export const getPayloadAttributes = ({
11
11
  },
12
12
  effectiveness: {
13
13
  undoCount: pluginState.actionTypeCount.undoCount,
14
- repeatedActionCount: 0,
14
+ repeatedActionCount: pluginState.repeatedActionCount,
15
15
  safeInsertCount: 0
16
16
  },
17
17
  contentSizeChanged
@@ -50,7 +50,7 @@ export const getAnalyticsPayload = ({
50
50
  },
51
51
  effectiveness: {
52
52
  undoCount: pluginState.actionTypeCount.undoCount,
53
- repeatedActionCount: 0,
53
+ repeatedActionCount: pluginState.repeatedActionCount,
54
54
  safeInsertCount: 0
55
55
  },
56
56
  contentSizeChanged: pluginState.contentSizeChanged
@@ -1,5 +1,5 @@
1
- import { InsertTypeAheadStep, LinkMetaStep } from '@atlaskit/adf-schema/steps';
2
- import { ReplaceAroundStep, ReplaceStep } from '@atlaskit/editor-prosemirror/transform';
1
+ import { BatchAttrsStep, InsertTypeAheadStep, LinkMetaStep } from '@atlaskit/adf-schema/steps';
2
+ import { AddMarkStep, AttrStep, RemoveMarkStep, ReplaceAroundStep, ReplaceStep } from '@atlaskit/editor-prosemirror/transform';
3
3
  export let ActionType = /*#__PURE__*/function (ActionType) {
4
4
  ActionType["TEXT_INPUT"] = "textInput";
5
5
  ActionType["EMPTY_LINE_ADDED_OR_DELETED"] = "emptyLineAddedOrDeleted";
@@ -8,6 +8,8 @@ export let ActionType = /*#__PURE__*/function (ActionType) {
8
8
  ActionType["UPDATING_NEW_LIST_TYPE_ITEM"] = "updatingNewListItem";
9
9
  ActionType["ADDING_LINK"] = "addingLink";
10
10
  ActionType["UPDATING_STATUS"] = "updatingStatus";
11
+ ActionType["CHANGING_MARK"] = "changingMark";
12
+ ActionType["CHANGING_ATTRS"] = "changingAttrs";
11
13
  return ActionType;
12
14
  }({});
13
15
  const isTextInput = step => {
@@ -41,6 +43,62 @@ const isEmptyLineAddedOrDeleted = step => {
41
43
  });
42
44
  return isEmptyLineAdded;
43
45
  };
46
+ const compareAttributes = (prevAttr, newAttr) => {
47
+ const allKeys = new Set([...Object.keys(prevAttr), ...Object.keys(newAttr)]);
48
+ for (const key of allKeys) {
49
+ const prevValue = prevAttr[key];
50
+ const newValue = newAttr[key];
51
+ if (prevValue !== newValue) {
52
+ return key;
53
+ }
54
+ }
55
+ return undefined;
56
+ };
57
+ const compareMarks = (prevMarks, newMarks) => {
58
+ if (!prevMarks && !newMarks) {
59
+ return undefined;
60
+ }
61
+ const previousMarksArr = new Map(prevMarks.map(mark => [mark.type.name, mark.attrs]));
62
+ const newMarksArr = new Map(newMarks.map(mark => [mark.type.name, mark.attrs]));
63
+ const allMarks = new Set([...previousMarksArr.keys(), ...newMarksArr.keys()]);
64
+ for (const key of allMarks) {
65
+ const previousValue = previousMarksArr.get(key);
66
+ const newValue = newMarksArr.get(key);
67
+ if (JSON.stringify(previousValue) !== JSON.stringify(newValue)) {
68
+ return key;
69
+ }
70
+ }
71
+ return undefined;
72
+ };
73
+ const detectNodeAttributeChange = (tr, step) => {
74
+ const {
75
+ from,
76
+ slice,
77
+ to
78
+ } = step;
79
+ const oldNode = tr.docs[0].nodeAt(from);
80
+ const newNode = slice.content.firstChild;
81
+ if (!oldNode || !newNode) {
82
+ return;
83
+ }
84
+ const changedAttr = compareAttributes(oldNode.attrs, newNode.attrs);
85
+ if (changedAttr) {
86
+ return {
87
+ attr: changedAttr,
88
+ from,
89
+ to
90
+ };
91
+ }
92
+ const changedMarks = compareMarks(oldNode.marks, newNode.marks);
93
+ if (changedMarks) {
94
+ return {
95
+ attr: changedMarks,
96
+ from,
97
+ to
98
+ };
99
+ }
100
+ return undefined;
101
+ };
44
102
  const isUpdatingListTypeNode = step => {
45
103
  const {
46
104
  slice
@@ -49,14 +107,13 @@ const isUpdatingListTypeNode = step => {
49
107
  if (childCount < 1) {
50
108
  return false;
51
109
  }
52
- let isListTypeNode = false;
53
- slice.content.forEach(node => {
54
- isListTypeNode = ['decisionList', 'decisionItem', 'bulletList', 'listItem', 'orderedList', 'taskList', 'taskItem'].includes(node.type.name);
55
- });
56
- if (!isListTypeNode) {
57
- return false;
110
+ for (const node of slice.content.content) {
111
+ const isListTypeNode = ['decisionList', 'decisionItem', 'bulletList', 'listItem', 'orderedList', 'taskList', 'taskItem'].includes(node.type.name);
112
+ if (isListTypeNode) {
113
+ return childCount === 1 ? ActionType.INSERTING_NEW_LIST_TYPE_NODE : ActionType.UPDATING_NEW_LIST_TYPE_ITEM;
114
+ }
58
115
  }
59
- return childCount === 1 ? ActionType.INSERTING_NEW_LIST_TYPE_NODE : ActionType.UPDATING_NEW_LIST_TYPE_ITEM;
116
+ return false;
60
117
  };
61
118
  const isUpdatingStatus = step => {
62
119
  const {
@@ -100,6 +157,44 @@ export const shouldSkipTr = tr => {
100
157
  return tr.getMeta('appendedTransaction');
101
158
  }
102
159
  };
160
+ const isResizingColumns = tr => {
161
+ const COL_WIDTH_ATTR = 'colwidth';
162
+ const steps = tr.steps;
163
+ const resizingColumnStep = steps.find(step => step instanceof AttrStep || step instanceof BatchAttrsStep);
164
+ if (!resizingColumnStep) {
165
+ return undefined;
166
+ }
167
+ let pos;
168
+
169
+ // BatchAttrsStep is used for resizing columns in tables
170
+ if (resizingColumnStep instanceof BatchAttrsStep) {
171
+ const {
172
+ attrs,
173
+ nodeType,
174
+ position
175
+ } = resizingColumnStep.data[0];
176
+ if (['tableHeader', 'tableCell'].includes(nodeType) && attrs !== null && attrs !== void 0 && attrs[COL_WIDTH_ATTR]) {
177
+ pos = position;
178
+ }
179
+ } else if (resizingColumnStep instanceof AttrStep && resizingColumnStep.attr === COL_WIDTH_ATTR) {
180
+ pos = resizingColumnStep.pos;
181
+ }
182
+ if (!pos) {
183
+ return undefined;
184
+ }
185
+ const $pos = tr.doc.resolve(pos);
186
+ const blockRange = $pos.blockRange();
187
+ if (!blockRange) {
188
+ return undefined;
189
+ }
190
+ const from = blockRange.start;
191
+ const to = from + blockRange.parent.content.size;
192
+ return {
193
+ attr: COL_WIDTH_ATTR,
194
+ from,
195
+ to
196
+ };
197
+ };
103
198
  export const checkTrActionType = tr => {
104
199
  if (tr.getMeta('input_rule_plugin_transaction')) {
105
200
  return {
@@ -115,9 +210,26 @@ export const checkTrActionType = tr => {
115
210
  type: ActionType.ADDING_LINK
116
211
  };
117
212
  }
213
+ const isResizingCol = isResizingColumns(tr);
214
+ if (isResizingCol) {
215
+ return {
216
+ type: ActionType.CHANGING_ATTRS,
217
+ extraData: isResizingCol
218
+ };
219
+ }
118
220
  const [firstStep] = tr.steps;
119
221
  const isReplaceStep = firstStep instanceof ReplaceStep;
120
222
  const isReplaceAroundStep = firstStep instanceof ReplaceAroundStep;
223
+ if (firstStep instanceof AddMarkStep || firstStep instanceof RemoveMarkStep) {
224
+ return {
225
+ type: ActionType.CHANGING_MARK,
226
+ extraData: {
227
+ markType: firstStep.mark.type.name,
228
+ from: firstStep.from,
229
+ to: firstStep.to
230
+ }
231
+ };
232
+ }
121
233
  if (!isReplaceStep && !isReplaceAroundStep) {
122
234
  return undefined;
123
235
  }
@@ -148,5 +260,12 @@ export const checkTrActionType = tr => {
148
260
  type: updatingListTypeNode
149
261
  };
150
262
  }
263
+ const nodeAttributeChange = detectNodeAttributeChange(tr, firstStep);
264
+ if (nodeAttributeChange) {
265
+ return {
266
+ type: ActionType.CHANGING_ATTRS,
267
+ extraData: nodeAttributeChange
268
+ };
269
+ }
151
270
  return undefined;
152
271
  };
@@ -0,0 +1,6 @@
1
+ import { BatchAttrsStep } from '@atlaskit/adf-schema/steps';
2
+ import { AddMarkStep, AttrStep, RemoveMarkStep, ReplaceAroundStep, ReplaceStep } from '@atlaskit/editor-prosemirror/transform';
3
+ export const isTrWithDocChanges = tr => {
4
+ var _tr$steps;
5
+ return tr.steps.length > 0 && ((_tr$steps = tr.steps) === null || _tr$steps === void 0 ? void 0 : _tr$steps.some(step => step instanceof ReplaceStep || step instanceof ReplaceAroundStep || step instanceof AddMarkStep || step instanceof AttrStep || step instanceof RemoveMarkStep || step instanceof BatchAttrsStep));
6
+ };
@@ -4,11 +4,11 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
4
4
  import { bind } from 'bind-event-listener';
5
5
  import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
6
6
  import { PluginKey } from '@atlaskit/editor-prosemirror/state';
7
- import { AddMarkStep, ReplaceAroundStep, ReplaceStep } from '@atlaskit/editor-prosemirror/transform';
8
7
  import { ActiveSessionTimer } from './utils/active-session-timer';
9
8
  import { getAnalyticsPayload } from './utils/analytics';
10
9
  import { ActionType, checkTrActionType, shouldSkipTr } from './utils/check-tr-action-type';
11
10
  import { isNonTextUndo } from './utils/is-non-text-undo';
11
+ import { isTrWithDocChanges } from './utils/is-tr-with-doc-changes';
12
12
  export var metricsKey = new PluginKey('metricsPlugin');
13
13
  export var initialPluginState = {
14
14
  intentToStartEditTime: undefined,
@@ -25,7 +25,8 @@ export var initialPluginState = {
25
25
  contentMovedCount: 0,
26
26
  nodeDeletionCount: 0,
27
27
  undoCount: 0
28
- }
28
+ },
29
+ repeatedActionCount: 0
29
30
  };
30
31
  export var createPlugin = function createPlugin(api) {
31
32
  var timer = new ActiveSessionTimer(api);
@@ -39,7 +40,7 @@ export var createPlugin = function createPlugin(api) {
39
40
  },
40
41
  // eslint-disable-next-line @typescript-eslint/max-params
41
42
  apply: function apply(tr, pluginState, oldState, newState) {
42
- var _meta$shouldPersistAc, _tr$steps;
43
+ var _meta$shouldPersistAc;
43
44
  if (tr.getMeta('isRemote') || tr.getMeta('replaceDocument')) {
44
45
  return pluginState;
45
46
  }
@@ -52,9 +53,7 @@ export var createPlugin = function createPlugin(api) {
52
53
  });
53
54
  }
54
55
  var shouldPersistActiveSession = (_meta$shouldPersistAc = meta === null || meta === void 0 ? void 0 : meta.shouldPersistActiveSession) !== null && _meta$shouldPersistAc !== void 0 ? _meta$shouldPersistAc : pluginState.shouldPersistActiveSession;
55
- var hasDocChanges = tr.steps.length > 0 && ((_tr$steps = tr.steps) === null || _tr$steps === void 0 ? void 0 : _tr$steps.some(function (step) {
56
- return step instanceof ReplaceStep || step instanceof ReplaceAroundStep || step instanceof AddMarkStep;
57
- }));
56
+ var hasDocChanges = isTrWithDocChanges(tr);
58
57
  var intentToStartEditTime = (meta === null || meta === void 0 ? void 0 : meta.intentToStartEditTime) || pluginState.intentToStartEditTime;
59
58
  var now = performance.now();
60
59
  if (!intentToStartEditTime && !hasDocChanges && !tr.storedMarksSet) {
@@ -114,17 +113,35 @@ export var createPlugin = function createPlugin(api) {
114
113
  if (timeOfLastTextInput && isTextInput && previousTrType && [ActionType.TEXT_INPUT, ActionType.EMPTY_LINE_ADDED_OR_DELETED, ActionType.UPDATING_NEW_LIST_TYPE_ITEM, ActionType.INSERTING_NEW_LIST_TYPE_NODE].includes(previousTrType.type)) {
115
114
  newTextInputCount = actionTypeCount.textInputCount;
116
115
  }
116
+ var newNodeAttrCount = actionTypeCount.nodeAttributeChangeCount;
117
+ var newRepeatedActionCount = pluginState.repeatedActionCount;
118
+ if ((trType === null || trType === void 0 ? void 0 : trType.type) === ActionType.CHANGING_ATTRS) {
119
+ newNodeAttrCount = newNodeAttrCount + 1;
120
+ if ((previousTrType === null || previousTrType === void 0 ? void 0 : previousTrType.type) === ActionType.CHANGING_ATTRS) {
121
+ var _trType$extraData2 = trType.extraData,
122
+ newAttr = _trType$extraData2.attr,
123
+ newFrom = _trType$extraData2.from,
124
+ newTo = _trType$extraData2.to;
125
+ var _previousTrType$extra2 = previousTrType.extraData,
126
+ prevAttr = _previousTrType$extra2.attr,
127
+ prevFrom = _previousTrType$extra2.from,
128
+ prevTo = _previousTrType$extra2.to;
129
+ newRepeatedActionCount = newAttr === prevAttr && newFrom === prevFrom && newTo === prevTo ? newRepeatedActionCount + 1 : newRepeatedActionCount;
130
+ }
131
+ }
117
132
  var newPluginState = _objectSpread(_objectSpread({}, pluginState), {}, {
118
133
  activeSessionTime: now - intentToStartEditTime,
119
134
  totalActionCount: newTotalActionCount,
120
135
  timeOfLastTextInput: shouldSetTimeOfLastTextInput ? now : undefined,
121
136
  contentSizeChanged: pluginState.contentSizeChanged + (newState.doc.content.size - oldState.doc.content.size),
122
137
  actionTypeCount: _objectSpread(_objectSpread({}, newActionTypeCount), {}, {
123
- textInputCount: newTextInputCount
138
+ textInputCount: newTextInputCount,
139
+ nodeAttributeChangeCount: newNodeAttrCount
124
140
  }),
125
141
  intentToStartEditTime: intentToStartEditTime,
126
142
  shouldPersistActiveSession: shouldPersistActiveSession,
127
- previousTrType: trType
143
+ previousTrType: trType,
144
+ repeatedActionCount: newRepeatedActionCount
128
145
  });
129
146
  return newPluginState;
130
147
  }
@@ -15,7 +15,7 @@ export var getPayloadAttributes = function getPayloadAttributes(_ref) {
15
15
  },
16
16
  effectiveness: {
17
17
  undoCount: pluginState.actionTypeCount.undoCount,
18
- repeatedActionCount: 0,
18
+ repeatedActionCount: pluginState.repeatedActionCount,
19
19
  safeInsertCount: 0
20
20
  },
21
21
  contentSizeChanged: contentSizeChanged
@@ -56,7 +56,7 @@ export var getAnalyticsPayload = function getAnalyticsPayload(_ref2) {
56
56
  },
57
57
  effectiveness: {
58
58
  undoCount: pluginState.actionTypeCount.undoCount,
59
- repeatedActionCount: 0,
59
+ repeatedActionCount: pluginState.repeatedActionCount,
60
60
  safeInsertCount: 0
61
61
  },
62
62
  contentSizeChanged: pluginState.contentSizeChanged
@@ -1,6 +1,10 @@
1
1
  import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
2
- import { InsertTypeAheadStep, LinkMetaStep } from '@atlaskit/adf-schema/steps';
3
- import { ReplaceAroundStep, ReplaceStep } from '@atlaskit/editor-prosemirror/transform';
2
+ import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
3
+ function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, 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 o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
4
+ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
5
+ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
6
+ import { BatchAttrsStep, InsertTypeAheadStep, LinkMetaStep } from '@atlaskit/adf-schema/steps';
7
+ import { AddMarkStep, AttrStep, RemoveMarkStep, ReplaceAroundStep, ReplaceStep } from '@atlaskit/editor-prosemirror/transform';
4
8
  export var ActionType = /*#__PURE__*/function (ActionType) {
5
9
  ActionType["TEXT_INPUT"] = "textInput";
6
10
  ActionType["EMPTY_LINE_ADDED_OR_DELETED"] = "emptyLineAddedOrDeleted";
@@ -9,6 +13,8 @@ export var ActionType = /*#__PURE__*/function (ActionType) {
9
13
  ActionType["UPDATING_NEW_LIST_TYPE_ITEM"] = "updatingNewListItem";
10
14
  ActionType["ADDING_LINK"] = "addingLink";
11
15
  ActionType["UPDATING_STATUS"] = "updatingStatus";
16
+ ActionType["CHANGING_MARK"] = "changingMark";
17
+ ActionType["CHANGING_ATTRS"] = "changingAttrs";
12
18
  return ActionType;
13
19
  }({});
14
20
  var isTextInput = function isTextInput(step) {
@@ -36,20 +42,104 @@ var isEmptyLineAddedOrDeleted = function isEmptyLineAddedOrDeleted(step) {
36
42
  });
37
43
  return isEmptyLineAdded;
38
44
  };
45
+ var compareAttributes = function compareAttributes(prevAttr, newAttr) {
46
+ var allKeys = new Set([].concat(_toConsumableArray(Object.keys(prevAttr)), _toConsumableArray(Object.keys(newAttr))));
47
+ var _iterator = _createForOfIteratorHelper(allKeys),
48
+ _step;
49
+ try {
50
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
51
+ var key = _step.value;
52
+ var prevValue = prevAttr[key];
53
+ var newValue = newAttr[key];
54
+ if (prevValue !== newValue) {
55
+ return key;
56
+ }
57
+ }
58
+ } catch (err) {
59
+ _iterator.e(err);
60
+ } finally {
61
+ _iterator.f();
62
+ }
63
+ return undefined;
64
+ };
65
+ var compareMarks = function compareMarks(prevMarks, newMarks) {
66
+ if (!prevMarks && !newMarks) {
67
+ return undefined;
68
+ }
69
+ var previousMarksArr = new Map(prevMarks.map(function (mark) {
70
+ return [mark.type.name, mark.attrs];
71
+ }));
72
+ var newMarksArr = new Map(newMarks.map(function (mark) {
73
+ return [mark.type.name, mark.attrs];
74
+ }));
75
+ var allMarks = new Set([].concat(_toConsumableArray(previousMarksArr.keys()), _toConsumableArray(newMarksArr.keys())));
76
+ var _iterator2 = _createForOfIteratorHelper(allMarks),
77
+ _step2;
78
+ try {
79
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
80
+ var key = _step2.value;
81
+ var previousValue = previousMarksArr.get(key);
82
+ var newValue = newMarksArr.get(key);
83
+ if (JSON.stringify(previousValue) !== JSON.stringify(newValue)) {
84
+ return key;
85
+ }
86
+ }
87
+ } catch (err) {
88
+ _iterator2.e(err);
89
+ } finally {
90
+ _iterator2.f();
91
+ }
92
+ return undefined;
93
+ };
94
+ var detectNodeAttributeChange = function detectNodeAttributeChange(tr, step) {
95
+ var from = step.from,
96
+ slice = step.slice,
97
+ to = step.to;
98
+ var oldNode = tr.docs[0].nodeAt(from);
99
+ var newNode = slice.content.firstChild;
100
+ if (!oldNode || !newNode) {
101
+ return;
102
+ }
103
+ var changedAttr = compareAttributes(oldNode.attrs, newNode.attrs);
104
+ if (changedAttr) {
105
+ return {
106
+ attr: changedAttr,
107
+ from: from,
108
+ to: to
109
+ };
110
+ }
111
+ var changedMarks = compareMarks(oldNode.marks, newNode.marks);
112
+ if (changedMarks) {
113
+ return {
114
+ attr: changedMarks,
115
+ from: from,
116
+ to: to
117
+ };
118
+ }
119
+ return undefined;
120
+ };
39
121
  var isUpdatingListTypeNode = function isUpdatingListTypeNode(step) {
40
122
  var slice = step.slice;
41
123
  var childCount = slice.content.childCount;
42
124
  if (childCount < 1) {
43
125
  return false;
44
126
  }
45
- var isListTypeNode = false;
46
- slice.content.forEach(function (node) {
47
- isListTypeNode = ['decisionList', 'decisionItem', 'bulletList', 'listItem', 'orderedList', 'taskList', 'taskItem'].includes(node.type.name);
48
- });
49
- if (!isListTypeNode) {
50
- return false;
127
+ var _iterator3 = _createForOfIteratorHelper(slice.content.content),
128
+ _step3;
129
+ try {
130
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
131
+ var node = _step3.value;
132
+ var isListTypeNode = ['decisionList', 'decisionItem', 'bulletList', 'listItem', 'orderedList', 'taskList', 'taskItem'].includes(node.type.name);
133
+ if (isListTypeNode) {
134
+ return childCount === 1 ? ActionType.INSERTING_NEW_LIST_TYPE_NODE : ActionType.UPDATING_NEW_LIST_TYPE_ITEM;
135
+ }
136
+ }
137
+ } catch (err) {
138
+ _iterator3.e(err);
139
+ } finally {
140
+ _iterator3.f();
51
141
  }
52
- return childCount === 1 ? ActionType.INSERTING_NEW_LIST_TYPE_NODE : ActionType.UPDATING_NEW_LIST_TYPE_ITEM;
142
+ return false;
53
143
  };
54
144
  var isUpdatingStatus = function isUpdatingStatus(step) {
55
145
  var slice = step.slice;
@@ -99,6 +189,45 @@ export var shouldSkipTr = function shouldSkipTr(tr) {
99
189
  return tr.getMeta('appendedTransaction');
100
190
  }
101
191
  };
192
+ var isResizingColumns = function isResizingColumns(tr) {
193
+ var COL_WIDTH_ATTR = 'colwidth';
194
+ var steps = tr.steps;
195
+ var resizingColumnStep = steps.find(function (step) {
196
+ return step instanceof AttrStep || step instanceof BatchAttrsStep;
197
+ });
198
+ if (!resizingColumnStep) {
199
+ return undefined;
200
+ }
201
+ var pos;
202
+
203
+ // BatchAttrsStep is used for resizing columns in tables
204
+ if (resizingColumnStep instanceof BatchAttrsStep) {
205
+ var _resizingColumnStep$d = resizingColumnStep.data[0],
206
+ attrs = _resizingColumnStep$d.attrs,
207
+ nodeType = _resizingColumnStep$d.nodeType,
208
+ position = _resizingColumnStep$d.position;
209
+ if (['tableHeader', 'tableCell'].includes(nodeType) && attrs !== null && attrs !== void 0 && attrs[COL_WIDTH_ATTR]) {
210
+ pos = position;
211
+ }
212
+ } else if (resizingColumnStep instanceof AttrStep && resizingColumnStep.attr === COL_WIDTH_ATTR) {
213
+ pos = resizingColumnStep.pos;
214
+ }
215
+ if (!pos) {
216
+ return undefined;
217
+ }
218
+ var $pos = tr.doc.resolve(pos);
219
+ var blockRange = $pos.blockRange();
220
+ if (!blockRange) {
221
+ return undefined;
222
+ }
223
+ var from = blockRange.start;
224
+ var to = from + blockRange.parent.content.size;
225
+ return {
226
+ attr: COL_WIDTH_ATTR,
227
+ from: from,
228
+ to: to
229
+ };
230
+ };
102
231
  export var checkTrActionType = function checkTrActionType(tr) {
103
232
  if (tr.getMeta('input_rule_plugin_transaction')) {
104
233
  return {
@@ -114,10 +243,27 @@ export var checkTrActionType = function checkTrActionType(tr) {
114
243
  type: ActionType.ADDING_LINK
115
244
  };
116
245
  }
246
+ var isResizingCol = isResizingColumns(tr);
247
+ if (isResizingCol) {
248
+ return {
249
+ type: ActionType.CHANGING_ATTRS,
250
+ extraData: isResizingCol
251
+ };
252
+ }
117
253
  var _tr$steps = _slicedToArray(tr.steps, 1),
118
254
  firstStep = _tr$steps[0];
119
255
  var isReplaceStep = firstStep instanceof ReplaceStep;
120
256
  var isReplaceAroundStep = firstStep instanceof ReplaceAroundStep;
257
+ if (firstStep instanceof AddMarkStep || firstStep instanceof RemoveMarkStep) {
258
+ return {
259
+ type: ActionType.CHANGING_MARK,
260
+ extraData: {
261
+ markType: firstStep.mark.type.name,
262
+ from: firstStep.from,
263
+ to: firstStep.to
264
+ }
265
+ };
266
+ }
121
267
  if (!isReplaceStep && !isReplaceAroundStep) {
122
268
  return undefined;
123
269
  }
@@ -148,5 +294,12 @@ export var checkTrActionType = function checkTrActionType(tr) {
148
294
  type: updatingListTypeNode
149
295
  };
150
296
  }
297
+ var nodeAttributeChange = detectNodeAttributeChange(tr, firstStep);
298
+ if (nodeAttributeChange) {
299
+ return {
300
+ type: ActionType.CHANGING_ATTRS,
301
+ extraData: nodeAttributeChange
302
+ };
303
+ }
151
304
  return undefined;
152
305
  };
@@ -0,0 +1,8 @@
1
+ import { BatchAttrsStep } from '@atlaskit/adf-schema/steps';
2
+ import { AddMarkStep, AttrStep, RemoveMarkStep, ReplaceAroundStep, ReplaceStep } from '@atlaskit/editor-prosemirror/transform';
3
+ export var isTrWithDocChanges = function isTrWithDocChanges(tr) {
4
+ var _tr$steps;
5
+ return tr.steps.length > 0 && ((_tr$steps = tr.steps) === null || _tr$steps === void 0 ? void 0 : _tr$steps.some(function (step) {
6
+ return step instanceof ReplaceStep || step instanceof ReplaceAroundStep || step instanceof AddMarkStep || step instanceof AttrStep || step instanceof RemoveMarkStep || step instanceof BatchAttrsStep;
7
+ }));
8
+ };
@@ -16,6 +16,7 @@ export type MetricsState = {
16
16
  shouldPersistActiveSession?: boolean;
17
17
  initialContent?: Fragment;
18
18
  previousTrType?: TrActionType;
19
+ repeatedActionCount: number;
19
20
  };
20
21
  export type ActionByType = {
21
22
  textInputCount: number;
@@ -6,13 +6,33 @@ export declare enum ActionType {
6
6
  INSERTING_NEW_LIST_TYPE_NODE = "insertingNewListTypeNode",
7
7
  UPDATING_NEW_LIST_TYPE_ITEM = "updatingNewListItem",
8
8
  ADDING_LINK = "addingLink",
9
- UPDATING_STATUS = "updatingStatus"
9
+ UPDATING_STATUS = "updatingStatus",
10
+ CHANGING_MARK = "changingMark",
11
+ CHANGING_ATTRS = "changingAttrs"
10
12
  }
11
- export declare const shouldSkipTr: (tr: ReadonlyTransaction) => boolean;
13
+ type AttrChangeActionData = {
14
+ attr: string;
15
+ from: number;
16
+ to: number;
17
+ };
12
18
  export type TrActionType = {
13
- type: ActionType;
14
- extraData?: {
15
- statusId?: string;
19
+ type: ActionType.UPDATING_STATUS;
20
+ extraData: {
21
+ statusId: string;
22
+ };
23
+ } | {
24
+ type: ActionType.CHANGING_MARK;
25
+ extraData: {
26
+ markType: string;
27
+ from: number;
28
+ to: number;
16
29
  };
30
+ } | {
31
+ type: ActionType.CHANGING_ATTRS;
32
+ extraData: AttrChangeActionData;
33
+ } | {
34
+ type: Exclude<ActionType, ActionType.CHANGING_ATTRS | ActionType.CHANGING_MARK | ActionType.UPDATING_STATUS>;
17
35
  } | undefined;
36
+ export declare const shouldSkipTr: (tr: ReadonlyTransaction) => boolean;
18
37
  export declare const checkTrActionType: (tr: ReadonlyTransaction) => TrActionType;
38
+ export {};
@@ -0,0 +1,2 @@
1
+ import { type ReadonlyTransaction } from '@atlaskit/editor-prosemirror/state';
2
+ export declare const isTrWithDocChanges: (tr: ReadonlyTransaction) => boolean;
@@ -16,6 +16,7 @@ export type MetricsState = {
16
16
  shouldPersistActiveSession?: boolean;
17
17
  initialContent?: Fragment;
18
18
  previousTrType?: TrActionType;
19
+ repeatedActionCount: number;
19
20
  };
20
21
  export type ActionByType = {
21
22
  textInputCount: number;
@@ -6,13 +6,33 @@ export declare enum ActionType {
6
6
  INSERTING_NEW_LIST_TYPE_NODE = "insertingNewListTypeNode",
7
7
  UPDATING_NEW_LIST_TYPE_ITEM = "updatingNewListItem",
8
8
  ADDING_LINK = "addingLink",
9
- UPDATING_STATUS = "updatingStatus"
9
+ UPDATING_STATUS = "updatingStatus",
10
+ CHANGING_MARK = "changingMark",
11
+ CHANGING_ATTRS = "changingAttrs"
10
12
  }
11
- export declare const shouldSkipTr: (tr: ReadonlyTransaction) => boolean;
13
+ type AttrChangeActionData = {
14
+ attr: string;
15
+ from: number;
16
+ to: number;
17
+ };
12
18
  export type TrActionType = {
13
- type: ActionType;
14
- extraData?: {
15
- statusId?: string;
19
+ type: ActionType.UPDATING_STATUS;
20
+ extraData: {
21
+ statusId: string;
22
+ };
23
+ } | {
24
+ type: ActionType.CHANGING_MARK;
25
+ extraData: {
26
+ markType: string;
27
+ from: number;
28
+ to: number;
16
29
  };
30
+ } | {
31
+ type: ActionType.CHANGING_ATTRS;
32
+ extraData: AttrChangeActionData;
33
+ } | {
34
+ type: Exclude<ActionType, ActionType.CHANGING_ATTRS | ActionType.CHANGING_MARK | ActionType.UPDATING_STATUS>;
17
35
  } | undefined;
36
+ export declare const shouldSkipTr: (tr: ReadonlyTransaction) => boolean;
18
37
  export declare const checkTrActionType: (tr: ReadonlyTransaction) => TrActionType;
38
+ export {};
@@ -0,0 +1,2 @@
1
+ import { type ReadonlyTransaction } from '@atlaskit/editor-prosemirror/state';
2
+ export declare const isTrWithDocChanges: (tr: ReadonlyTransaction) => boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-metrics",
3
- "version": "3.2.2",
3
+ "version": "3.2.3",
4
4
  "description": "Metrics plugin for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -25,9 +25,9 @@
25
25
  },
26
26
  "dependencies": {
27
27
  "@atlaskit/adf-schema": "^47.2.1",
28
- "@atlaskit/editor-common": "^100.0.0",
28
+ "@atlaskit/editor-common": "^100.2.0",
29
29
  "@atlaskit/editor-plugin-analytics": "^2.0.0",
30
- "@atlaskit/editor-plugin-block-controls": "^3.0.0",
30
+ "@atlaskit/editor-plugin-block-controls": "^3.1.0",
31
31
  "@atlaskit/editor-prosemirror": "7.0.0",
32
32
  "@atlaskit/platform-feature-flags": "^1.1.0",
33
33
  "@babel/runtime": "^7.0.0",