@atlaskit/editor-plugin-metrics 3.3.1 → 3.4.1

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.
Files changed (92) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/cjs/metricsPlugin.js +20 -11
  3. package/dist/cjs/pm-plugins/main.js +22 -99
  4. package/dist/cjs/pm-plugins/utils/analytics.js +22 -28
  5. package/dist/cjs/pm-plugins/utils/check-tr-actions/check-tr-action-type.js +90 -0
  6. package/dist/cjs/pm-plugins/utils/check-tr-actions/tr-checks/check-content-moved.js +26 -0
  7. package/dist/cjs/pm-plugins/utils/check-tr-actions/tr-checks/check-deleting-content.js +20 -0
  8. package/dist/cjs/pm-plugins/utils/check-tr-actions/tr-checks/check-empty-line-added-or-deleted.js +29 -0
  9. package/dist/cjs/pm-plugins/utils/check-tr-actions/tr-checks/check-list-type-node-changed.js +37 -0
  10. package/dist/cjs/pm-plugins/utils/check-tr-actions/tr-checks/check-mark-changed.js +16 -0
  11. package/dist/cjs/pm-plugins/utils/check-tr-actions/tr-checks/check-node-attribute-changed.js +103 -0
  12. package/dist/cjs/pm-plugins/utils/check-tr-actions/tr-checks/check-status-changed.js +22 -0
  13. package/dist/cjs/pm-plugins/utils/check-tr-actions/tr-checks/check-table-column-resized.js +60 -0
  14. package/dist/cjs/pm-plugins/utils/check-tr-actions/tr-checks/check-text-input.js +23 -0
  15. package/dist/cjs/pm-plugins/utils/check-tr-actions/types.js +23 -0
  16. package/dist/cjs/pm-plugins/utils/get-new-plugin-state.js +103 -0
  17. package/dist/cjs/pm-plugins/utils/is-safe-insert.js +37 -0
  18. package/dist/cjs/pm-plugins/utils/should-skip-tr.js +52 -0
  19. package/dist/es2019/metricsPlugin.js +9 -1
  20. package/dist/es2019/pm-plugins/main.js +22 -109
  21. package/dist/es2019/pm-plugins/utils/analytics.js +11 -19
  22. package/dist/es2019/pm-plugins/utils/check-tr-actions/check-tr-action-type.js +81 -0
  23. package/dist/es2019/pm-plugins/utils/check-tr-actions/tr-checks/check-content-moved.js +20 -0
  24. package/dist/es2019/pm-plugins/utils/check-tr-actions/tr-checks/check-deleting-content.js +17 -0
  25. package/dist/es2019/pm-plugins/utils/check-tr-actions/tr-checks/check-empty-line-added-or-deleted.js +26 -0
  26. package/dist/es2019/pm-plugins/utils/check-tr-actions/tr-checks/check-list-type-node-changed.js +23 -0
  27. package/dist/es2019/pm-plugins/utils/check-tr-actions/tr-checks/check-mark-changed.js +10 -0
  28. package/dist/es2019/pm-plugins/utils/check-tr-actions/tr-checks/check-node-attribute-changed.js +71 -0
  29. package/dist/es2019/pm-plugins/utils/check-tr-actions/tr-checks/check-status-changed.js +18 -0
  30. package/dist/es2019/pm-plugins/utils/check-tr-actions/tr-checks/check-table-column-resized.js +53 -0
  31. package/dist/es2019/pm-plugins/utils/check-tr-actions/tr-checks/check-text-input.js +20 -0
  32. package/dist/es2019/pm-plugins/utils/check-tr-actions/types.js +17 -0
  33. package/dist/es2019/pm-plugins/utils/get-new-plugin-state.js +101 -0
  34. package/dist/es2019/pm-plugins/utils/is-safe-insert.js +28 -0
  35. package/dist/es2019/pm-plugins/utils/should-skip-tr.js +38 -0
  36. package/dist/esm/metricsPlugin.js +20 -11
  37. package/dist/esm/pm-plugins/main.js +21 -98
  38. package/dist/esm/pm-plugins/utils/analytics.js +21 -27
  39. package/dist/esm/pm-plugins/utils/check-tr-actions/check-tr-action-type.js +83 -0
  40. package/dist/esm/pm-plugins/utils/check-tr-actions/tr-checks/check-content-moved.js +20 -0
  41. package/dist/esm/pm-plugins/utils/check-tr-actions/tr-checks/check-deleting-content.js +14 -0
  42. package/dist/esm/pm-plugins/utils/check-tr-actions/tr-checks/check-empty-line-added-or-deleted.js +23 -0
  43. package/dist/esm/pm-plugins/utils/check-tr-actions/tr-checks/check-list-type-node-changed.js +31 -0
  44. package/dist/esm/pm-plugins/utils/check-tr-actions/tr-checks/check-mark-changed.js +10 -0
  45. package/dist/esm/pm-plugins/utils/check-tr-actions/tr-checks/check-node-attribute-changed.js +96 -0
  46. package/dist/esm/pm-plugins/utils/check-tr-actions/tr-checks/check-status-changed.js +16 -0
  47. package/dist/esm/pm-plugins/utils/check-tr-actions/tr-checks/check-table-column-resized.js +54 -0
  48. package/dist/esm/pm-plugins/utils/check-tr-actions/tr-checks/check-text-input.js +17 -0
  49. package/dist/esm/pm-plugins/utils/check-tr-actions/types.js +17 -0
  50. package/dist/esm/pm-plugins/utils/get-new-plugin-state.js +96 -0
  51. package/dist/esm/pm-plugins/utils/is-safe-insert.js +30 -0
  52. package/dist/esm/pm-plugins/utils/should-skip-tr.js +46 -0
  53. package/dist/types/metricsPluginType.d.ts +2 -2
  54. package/dist/types/pm-plugins/main.d.ts +4 -1
  55. package/dist/types/pm-plugins/utils/analytics.d.ts +1 -7
  56. package/dist/types/pm-plugins/utils/check-tr-actions/check-tr-action-type.d.ts +3 -0
  57. package/dist/types/pm-plugins/utils/check-tr-actions/tr-checks/check-content-moved.d.ts +3 -0
  58. package/dist/types/pm-plugins/utils/check-tr-actions/tr-checks/check-deleting-content.d.ts +3 -0
  59. package/dist/types/pm-plugins/utils/check-tr-actions/tr-checks/check-empty-line-added-or-deleted.d.ts +3 -0
  60. package/dist/types/pm-plugins/utils/check-tr-actions/tr-checks/check-list-type-node-changed.d.ts +3 -0
  61. package/dist/types/pm-plugins/utils/check-tr-actions/tr-checks/check-mark-changed.d.ts +3 -0
  62. package/dist/types/pm-plugins/utils/check-tr-actions/tr-checks/check-node-attribute-changed.d.ts +4 -0
  63. package/dist/types/pm-plugins/utils/check-tr-actions/tr-checks/check-status-changed.d.ts +3 -0
  64. package/dist/types/pm-plugins/utils/check-tr-actions/tr-checks/check-table-column-resized.d.ts +3 -0
  65. package/dist/types/pm-plugins/utils/check-tr-actions/tr-checks/check-text-input.d.ts +3 -0
  66. package/dist/types/pm-plugins/utils/check-tr-actions/types.d.ts +44 -0
  67. package/dist/types/pm-plugins/utils/get-new-plugin-state.d.ts +56 -0
  68. package/dist/types/pm-plugins/utils/is-safe-insert.d.ts +3 -0
  69. package/dist/types/pm-plugins/utils/should-skip-tr.d.ts +2 -0
  70. package/dist/types-ts4.5/metricsPluginType.d.ts +2 -3
  71. package/dist/types-ts4.5/pm-plugins/main.d.ts +4 -1
  72. package/dist/types-ts4.5/pm-plugins/utils/analytics.d.ts +1 -7
  73. package/dist/types-ts4.5/pm-plugins/utils/check-tr-actions/check-tr-action-type.d.ts +3 -0
  74. package/dist/types-ts4.5/pm-plugins/utils/check-tr-actions/tr-checks/check-content-moved.d.ts +3 -0
  75. package/dist/types-ts4.5/pm-plugins/utils/check-tr-actions/tr-checks/check-deleting-content.d.ts +3 -0
  76. package/dist/types-ts4.5/pm-plugins/utils/check-tr-actions/tr-checks/check-empty-line-added-or-deleted.d.ts +3 -0
  77. package/dist/types-ts4.5/pm-plugins/utils/check-tr-actions/tr-checks/check-list-type-node-changed.d.ts +3 -0
  78. package/dist/types-ts4.5/pm-plugins/utils/check-tr-actions/tr-checks/check-mark-changed.d.ts +3 -0
  79. package/dist/types-ts4.5/pm-plugins/utils/check-tr-actions/tr-checks/check-node-attribute-changed.d.ts +4 -0
  80. package/dist/types-ts4.5/pm-plugins/utils/check-tr-actions/tr-checks/check-status-changed.d.ts +3 -0
  81. package/dist/types-ts4.5/pm-plugins/utils/check-tr-actions/tr-checks/check-table-column-resized.d.ts +3 -0
  82. package/dist/types-ts4.5/pm-plugins/utils/check-tr-actions/tr-checks/check-text-input.d.ts +3 -0
  83. package/dist/types-ts4.5/pm-plugins/utils/check-tr-actions/types.d.ts +44 -0
  84. package/dist/types-ts4.5/pm-plugins/utils/get-new-plugin-state.d.ts +56 -0
  85. package/dist/types-ts4.5/pm-plugins/utils/is-safe-insert.d.ts +3 -0
  86. package/dist/types-ts4.5/pm-plugins/utils/should-skip-tr.d.ts +2 -0
  87. package/package.json +12 -6
  88. package/dist/cjs/pm-plugins/utils/check-tr-action-type.js +0 -312
  89. package/dist/es2019/pm-plugins/utils/check-tr-action-type.js +0 -271
  90. package/dist/esm/pm-plugins/utils/check-tr-action-type.js +0 -305
  91. package/dist/types/pm-plugins/utils/check-tr-action-type.d.ts +0 -38
  92. package/dist/types-ts4.5/pm-plugins/utils/check-tr-action-type.d.ts +0 -38
@@ -1,21 +1,5 @@
1
1
  import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
2
2
  import { getNodeChanges } from './get-node-changes';
3
- export const getPayloadAttributes = ({
4
- pluginState,
5
- contentSizeChanged
6
- }) => ({
7
- efficiency: {
8
- totalActiveTime: pluginState.activeSessionTime,
9
- totalActionCount: pluginState.totalActionCount,
10
- actionByTypeCount: pluginState.actionTypeCount
11
- },
12
- effectiveness: {
13
- undoCount: pluginState.actionTypeCount.undoCount,
14
- repeatedActionCount: pluginState.repeatedActionCount,
15
- safeInsertCount: 0
16
- },
17
- contentSizeChanged
18
- });
19
3
  export const getAnalyticsPayload = ({
20
4
  currentContent,
21
5
  pluginState
@@ -25,6 +9,13 @@ export const getAnalyticsPayload = ({
25
9
  currentContent,
26
10
  pluginState
27
11
  });
12
+ const getActionCountByTypeSum = () => {
13
+ let actionCountByTypeSum = 0;
14
+ Object.entries(pluginState.actionTypeCount).forEach(([_actionType, count]) => {
15
+ actionCountByTypeSum += count;
16
+ });
17
+ return pluginState.totalActionCount - actionCountByTypeSum;
18
+ };
28
19
  let nodeInsertionCount = 0;
29
20
  let nodeDeletionCount = 0;
30
21
  Object.entries(nodeChanges).forEach(([_, change]) => {
@@ -40,18 +31,19 @@ export const getAnalyticsPayload = ({
40
31
  actionSubjectId: ACTION_SUBJECT_ID.ACTIVITY,
41
32
  attributes: {
42
33
  efficiency: {
43
- totalActiveTime: pluginState.activeSessionTime,
34
+ totalActiveTime: pluginState.activeSessionTime / 1000,
44
35
  totalActionCount: pluginState.totalActionCount,
45
36
  actionByTypeCount: {
46
37
  ...((_pluginState$actionTy = pluginState.actionTypeCount) !== null && _pluginState$actionTy !== void 0 ? _pluginState$actionTy : {}),
47
38
  nodeDeletionCount,
48
- nodeInsertionCount
39
+ nodeInsertionCount,
40
+ other: getActionCountByTypeSum()
49
41
  }
50
42
  },
51
43
  effectiveness: {
52
44
  undoCount: pluginState.actionTypeCount.undoCount,
53
45
  repeatedActionCount: pluginState.repeatedActionCount,
54
- safeInsertCount: 0
46
+ safeInsertCount: pluginState.safeInsertCount
55
47
  },
56
48
  contentSizeChanged: pluginState.contentSizeChanged
57
49
  },
@@ -0,0 +1,81 @@
1
+ import { ReplaceAroundStep, ReplaceStep } from '@atlaskit/editor-prosemirror/transform';
2
+ import { checkContentPastedOrMoved } from './tr-checks/check-content-moved';
3
+ import { checkDeletingContent } from './tr-checks/check-deleting-content';
4
+ import { checkEmptyLineAddedOrDeleted } from './tr-checks/check-empty-line-added-or-deleted';
5
+ import { checkListTypeNodeChanged } from './tr-checks/check-list-type-node-changed';
6
+ import { checkMarkChanged } from './tr-checks/check-mark-changed';
7
+ import { checkNodeAttributeChanged } from './tr-checks/check-node-attribute-changed';
8
+ import { checkStatusChanged } from './tr-checks/check-status-changed';
9
+ import { checkTableColumnResized } from './tr-checks/check-table-column-resized';
10
+ import { checkTextInput } from './tr-checks/check-text-input';
11
+ export const checkTrActionType = tr => {
12
+ const stepsLength = tr.steps.length;
13
+ if (stepsLength <= 0) {
14
+ return undefined;
15
+ }
16
+ const contentPastedOrMoved = checkContentPastedOrMoved(tr);
17
+ if (contentPastedOrMoved) {
18
+ return contentPastedOrMoved;
19
+ }
20
+
21
+ // Resized column data is either AttrStep or BatchAttrsStep, so we want to check it first
22
+ const resizedColumnData = checkTableColumnResized(tr);
23
+ if (resizedColumnData) {
24
+ return resizedColumnData;
25
+ }
26
+
27
+ // Since we are looking at editor actions, we want to look at the first step only
28
+ const [firstStep] = tr.steps;
29
+ const isReplaceStep = firstStep instanceof ReplaceStep;
30
+ const isReplaceAroundStep = firstStep instanceof ReplaceAroundStep;
31
+
32
+ // Check if mark is added or removed, this is for text formatting changes
33
+ const marksChanged = checkMarkChanged(firstStep);
34
+ if (marksChanged) {
35
+ return marksChanged;
36
+ }
37
+
38
+ // Return early if it's not a replace step or replace around step as following checks are for these steps only
39
+ if (!(isReplaceStep || isReplaceAroundStep)) {
40
+ return undefined;
41
+ }
42
+ if (isReplaceStep) {
43
+ // Check if tr is text input as we want to ignore continuous typing actions
44
+ const textInput = checkTextInput(firstStep);
45
+ if (textInput) {
46
+ return textInput;
47
+ }
48
+
49
+ // Check if tr is adding/ removing empty lines as we want to ignore continuous typing actions
50
+ const emptyLineAddedOrDeleted = checkEmptyLineAddedOrDeleted(firstStep);
51
+ if (emptyLineAddedOrDeleted) {
52
+ return emptyLineAddedOrDeleted;
53
+ }
54
+
55
+ //Check if tr is removing content
56
+ const isDeletingContent = checkDeletingContent(firstStep);
57
+ if (isDeletingContent) {
58
+ return isDeletingContent;
59
+ }
60
+
61
+ // Status nodes save status content in attributes and a new transaction is fired each keypress
62
+ // Check if tr is updating status so we can handle actionCount correctly
63
+ const status = checkStatusChanged(firstStep);
64
+ if (status) {
65
+ return status;
66
+ }
67
+ }
68
+
69
+ // Check if tr is updating list type node because we want to ignore continuous typing actions and adding new list items
70
+ const updatingListTypeNode = checkListTypeNodeChanged(firstStep);
71
+ if (updatingListTypeNode) {
72
+ return updatingListTypeNode;
73
+ }
74
+
75
+ // Check if tr is updating node attributes so we can track nodeAttributeChangeCount
76
+ const nodeAttributeChange = checkNodeAttributeChanged(tr, firstStep);
77
+ if (nodeAttributeChange) {
78
+ return nodeAttributeChange;
79
+ }
80
+ return undefined;
81
+ };
@@ -0,0 +1,20 @@
1
+ import { metricsKey } from '../../../main';
2
+ import { ActionType } from '../types';
3
+ const UI_EVENT = 'uiEvent';
4
+ const PASTE_EVENT = 'paste';
5
+ export const checkContentPastedOrMoved = tr => {
6
+ var _tr$getMeta;
7
+ const isContentMoved = (_tr$getMeta = tr.getMeta(metricsKey)) === null || _tr$getMeta === void 0 ? void 0 : _tr$getMeta.contentMoved;
8
+ const isContentPasted = tr.getMeta(UI_EVENT) === PASTE_EVENT;
9
+ if (isContentMoved) {
10
+ return {
11
+ type: ActionType.MOVING_CONTENT
12
+ };
13
+ }
14
+ if (isContentPasted) {
15
+ return {
16
+ type: ActionType.PASTING_CONTENT
17
+ };
18
+ }
19
+ return undefined;
20
+ };
@@ -0,0 +1,17 @@
1
+ import { ActionType } from '../types';
2
+ export const checkDeletingContent = step => {
3
+ const {
4
+ slice: {
5
+ content
6
+ },
7
+ from,
8
+ to
9
+ } = step;
10
+ const isDeletingContent = to !== from && content.childCount === 0;
11
+ if (!isDeletingContent) {
12
+ return undefined;
13
+ }
14
+ return {
15
+ type: ActionType.DELETING_CONTENT
16
+ };
17
+ };
@@ -0,0 +1,26 @@
1
+ import { ActionType } from '../types';
2
+ export const checkEmptyLineAddedOrDeleted = step => {
3
+ const {
4
+ slice: {
5
+ content
6
+ },
7
+ from,
8
+ to
9
+ } = step;
10
+ const isEmptyLineDeleted = to - from === 2 && content.size === 0;
11
+ if (isEmptyLineDeleted) {
12
+ return {
13
+ type: ActionType.EMPTY_LINE_ADDED_OR_DELETED
14
+ };
15
+ }
16
+ let isEmptyLineAdded = false;
17
+ content.forEach(node => {
18
+ isEmptyLineAdded = node.type.name === 'paragraph' && node.content.size === 0;
19
+ });
20
+ if (!isEmptyLineAdded) {
21
+ return undefined;
22
+ }
23
+ return {
24
+ type: ActionType.EMPTY_LINE_ADDED_OR_DELETED
25
+ };
26
+ };
@@ -0,0 +1,23 @@
1
+ import { ActionType } from '../types';
2
+ export const checkListTypeNodeChanged = step => {
3
+ const {
4
+ slice: {
5
+ content
6
+ }
7
+ } = step;
8
+ const childCount = content.childCount;
9
+ if (childCount < 1) {
10
+ return undefined;
11
+ }
12
+ for (const node of content.content) {
13
+ const isListTypeNode = ['decisionList', 'decisionItem', 'bulletList', 'listItem', 'orderedList', 'taskList', 'taskItem'].includes(node.type.name);
14
+ if (isListTypeNode) {
15
+ return childCount === 1 ? {
16
+ type: ActionType.INSERTING_NEW_LIST_TYPE_NODE
17
+ } : {
18
+ type: ActionType.UPDATING_NEW_LIST_TYPE_ITEM
19
+ };
20
+ }
21
+ }
22
+ return undefined;
23
+ };
@@ -0,0 +1,10 @@
1
+ import { AddMarkStep, RemoveMarkStep } from '@atlaskit/editor-prosemirror/transform';
2
+ import { ActionType } from '../types';
3
+ export const checkMarkChanged = step => {
4
+ if (!(step instanceof AddMarkStep || step instanceof RemoveMarkStep)) {
5
+ return undefined;
6
+ }
7
+ return {
8
+ type: ActionType.CHANGING_MARK
9
+ };
10
+ };
@@ -0,0 +1,71 @@
1
+ import { ActionType } from '../types';
2
+ const compareAttributes = (prevAttr, newAttr) => {
3
+ const allKeys = new Set([...Object.keys(prevAttr), ...Object.keys(newAttr)]);
4
+ for (const key of allKeys) {
5
+ const prevValue = prevAttr[key];
6
+ const newValue = newAttr[key];
7
+ if (prevValue !== newValue && key !== 'localId') {
8
+ return key;
9
+ }
10
+ }
11
+ return undefined;
12
+ };
13
+ const compareMarks = (prevMarks, newMarks) => {
14
+ if (!prevMarks && !newMarks) {
15
+ return undefined;
16
+ }
17
+ const previousMarksArr = new Map(prevMarks.map(mark => [mark.type.name, mark.attrs]));
18
+ const newMarksArr = new Map(newMarks.map(mark => [mark.type.name, mark.attrs]));
19
+ const allMarks = new Set([...previousMarksArr.keys(), ...newMarksArr.keys()]);
20
+ for (const key of allMarks) {
21
+ const previousValue = previousMarksArr.get(key);
22
+ const newValue = newMarksArr.get(key);
23
+ if (JSON.stringify(previousValue) !== JSON.stringify(newValue)) {
24
+ return key;
25
+ }
26
+ }
27
+ return undefined;
28
+ };
29
+ export const checkNodeAttributeChanged = (tr, step) => {
30
+ const {
31
+ slice,
32
+ from,
33
+ to
34
+ } = step;
35
+ const oldNode = tr.docs[0].nodeAt(from);
36
+ const newNode = slice.content.firstChild;
37
+ if (!oldNode || !newNode) {
38
+ return undefined;
39
+ }
40
+ if (oldNode.type.name !== newNode.type.name) {
41
+ return undefined;
42
+ }
43
+
44
+ // We need to compare the attributes of the node
45
+ const changedAttr = compareAttributes(oldNode.attrs, newNode.attrs);
46
+ if (changedAttr) {
47
+ return {
48
+ type: ActionType.CHANGING_ATTRS,
49
+ extraData: {
50
+ attr: changedAttr,
51
+ from,
52
+ to
53
+ }
54
+ };
55
+ }
56
+
57
+ // For some changes, we need to compare the marks of the node
58
+ // e.g. Media Border, Links
59
+ const changedMarks = compareMarks(oldNode.marks, newNode.marks);
60
+ if (changedMarks) {
61
+ return {
62
+ type: ActionType.CHANGING_ATTRS,
63
+ extraData: {
64
+ attr: changedMarks,
65
+ from,
66
+ to
67
+ }
68
+ };
69
+ }
70
+ return undefined;
71
+ };
@@ -0,0 +1,18 @@
1
+ import { ActionType } from '../types';
2
+ export const checkStatusChanged = step => {
3
+ const {
4
+ slice
5
+ } = step;
6
+ const firstChild = slice.content.firstChild;
7
+ if (!firstChild) {
8
+ return undefined;
9
+ }
10
+
11
+ // Get statusId so that we can track whether edits are performed on same status node
12
+ return firstChild.type.name === 'status' ? {
13
+ type: ActionType.UPDATING_STATUS,
14
+ extraData: {
15
+ statusId: firstChild.attrs.localId
16
+ }
17
+ } : undefined;
18
+ };
@@ -0,0 +1,53 @@
1
+ import { BatchAttrsStep } from '@atlaskit/adf-schema/steps';
2
+ import { AttrStep } from '@atlaskit/editor-prosemirror/transform';
3
+ import { ActionType } from '../types';
4
+ export const checkTableColumnResized = tr => {
5
+ const COL_WIDTH_ATTR = 'colwidth';
6
+ const steps = tr.steps;
7
+
8
+ // Find the step that is changing the column width
9
+ const resizingColumnStep = steps.find(step => step instanceof AttrStep || step instanceof BatchAttrsStep);
10
+ if (!resizingColumnStep) {
11
+ return undefined;
12
+ }
13
+ let pos;
14
+
15
+ // Find the position of the first column in the step that is being resized
16
+ if (resizingColumnStep instanceof BatchAttrsStep) {
17
+ if (resizingColumnStep.data.length === 0) {
18
+ return undefined;
19
+ }
20
+ const {
21
+ attrs,
22
+ nodeType,
23
+ position
24
+ } = resizingColumnStep.data[0];
25
+ if (['tableHeader', 'tableCell'].includes(nodeType) && attrs !== null && attrs !== void 0 && attrs[COL_WIDTH_ATTR]) {
26
+ pos = position;
27
+ }
28
+ } else if (resizingColumnStep instanceof AttrStep && resizingColumnStep.attr === COL_WIDTH_ATTR) {
29
+ pos = resizingColumnStep.pos;
30
+ }
31
+ if (!pos) {
32
+ return undefined;
33
+ }
34
+
35
+ // Find the range of the table that is being resized
36
+ const $pos = tr.doc.resolve(pos);
37
+ const blockRange = $pos.blockRange();
38
+ if (!blockRange) {
39
+ return undefined;
40
+ }
41
+ const from = blockRange.start;
42
+ const to = from + blockRange.parent.content.size;
43
+
44
+ // Use to and from position of table to check whether column width of same table is being resized
45
+ return {
46
+ type: ActionType.CHANGING_ATTRS,
47
+ extraData: {
48
+ attr: COL_WIDTH_ATTR,
49
+ from,
50
+ to
51
+ }
52
+ };
53
+ };
@@ -0,0 +1,20 @@
1
+ import { ActionType } from '../types';
2
+ export const checkTextInput = step => {
3
+ const {
4
+ slice: {
5
+ content
6
+ },
7
+ from,
8
+ to
9
+ } = step;
10
+ const node = content.firstChild;
11
+ const isAddingCharacter = from === to && content.childCount === 1 && !!node && !!node.text && node.text.length === 1;
12
+ const isDeletingCharacter = to - from === 1 && content.childCount === 0;
13
+ const isTextInput = isAddingCharacter || isDeletingCharacter;
14
+ if (!isTextInput) {
15
+ return undefined;
16
+ }
17
+ return {
18
+ type: ActionType.TEXT_INPUT
19
+ };
20
+ };
@@ -0,0 +1,17 @@
1
+ export let ActionType = /*#__PURE__*/function (ActionType) {
2
+ ActionType["TEXT_INPUT"] = "textInput";
3
+ ActionType["EMPTY_LINE_ADDED_OR_DELETED"] = "emptyLineAddedOrDeleted";
4
+ ActionType["INSERTED_FROM_TYPE_AHEAD"] = "insertedFromTypeAhead";
5
+ ActionType["INSERTING_NEW_LIST_TYPE_NODE"] = "insertingNewListTypeNode";
6
+ ActionType["UPDATING_NEW_LIST_TYPE_ITEM"] = "updatingNewListItem";
7
+ ActionType["ADDING_LINK"] = "addingLink";
8
+ ActionType["UPDATING_STATUS"] = "updatingStatus";
9
+ ActionType["CHANGING_MARK"] = "changingMark";
10
+ ActionType["CHANGING_ATTRS"] = "changingAttrs";
11
+ ActionType["MOVING_CONTENT"] = "contentMoved";
12
+ ActionType["PASTING_CONTENT"] = "contentPasted";
13
+ ActionType["DELETING_CONTENT"] = "deletingContent";
14
+ ActionType["SAFE_INSERT"] = "safeInsert";
15
+ ActionType["UNDO"] = "undo";
16
+ return ActionType;
17
+ }({});
@@ -0,0 +1,101 @@
1
+ import { checkTrActionType } from './check-tr-actions/check-tr-action-type';
2
+ import { ActionType } from './check-tr-actions/types';
3
+ import { isNonTextUndo } from './is-non-text-undo';
4
+ import { isSafeInsert } from './is-safe-insert';
5
+ const textInputActions = [ActionType.TEXT_INPUT, ActionType.EMPTY_LINE_ADDED_OR_DELETED];
6
+ const listActions = [ActionType.UPDATING_NEW_LIST_TYPE_ITEM, ActionType.INSERTING_NEW_LIST_TYPE_NODE];
7
+ const continuousActions = [...textInputActions, ...listActions, ActionType.UPDATING_STATUS];
8
+ const checkIsDesiredAction = (trType, desiredActions) => {
9
+ return trType && desiredActions.includes(trType.type);
10
+ };
11
+ const getNewActionTypeCount = (shouldIncrement, currentCount) => {
12
+ return shouldIncrement ? currentCount + 1 : currentCount;
13
+ };
14
+ export const getNewPluginState = ({
15
+ now,
16
+ intentToStartEditTime,
17
+ shouldPersistActiveSession,
18
+ tr,
19
+ pluginState,
20
+ oldState,
21
+ newState
22
+ }) => {
23
+ var _trType$extraData, _previousTrType$extra;
24
+ const {
25
+ actionTypeCount,
26
+ timeOfLastTextInput,
27
+ totalActionCount,
28
+ previousTrType,
29
+ safeInsertCount,
30
+ contentSizeChanged
31
+ } = pluginState;
32
+ const newPluginState = {
33
+ ...pluginState,
34
+ activeSessionTime: now - intentToStartEditTime,
35
+ contentSizeChanged: contentSizeChanged + Math.abs(newState.doc.content.size - oldState.doc.content.size),
36
+ intentToStartEditTime,
37
+ shouldPersistActiveSession
38
+ };
39
+ const trType = checkTrActionType(tr);
40
+ const newSafeInsertCount = getNewActionTypeCount(isSafeInsert(tr, oldState.tr.selection.from, trType === null || trType === void 0 ? void 0 : trType.type), safeInsertCount);
41
+ const newUndoCount = getNewActionTypeCount(isNonTextUndo(tr), actionTypeCount.undoCount);
42
+ if (!trType) {
43
+ return {
44
+ ...newPluginState,
45
+ totalActionCount: totalActionCount + 1,
46
+ timeOfLastTextInput: undefined,
47
+ actionTypeCount: {
48
+ ...actionTypeCount,
49
+ undoCount: newUndoCount
50
+ },
51
+ previousTrType: trType,
52
+ safeInsertCount: newSafeInsertCount
53
+ };
54
+ }
55
+
56
+ // Below are conditions for special cases which should not increase action count if the previous action was the same or was textInput
57
+ // Check if tr is updating the same status node
58
+ const isNotNewStatus = trType.type === ActionType.UPDATING_STATUS && (previousTrType === null || previousTrType === void 0 ? void 0 : previousTrType.type) === ActionType.UPDATING_STATUS && (trType === null || trType === void 0 ? void 0 : (_trType$extraData = trType.extraData) === null || _trType$extraData === void 0 ? void 0 : _trType$extraData.statusId) === (previousTrType === null || previousTrType === void 0 ? void 0 : (_previousTrType$extra = previousTrType.extraData) === null || _previousTrType$extra === void 0 ? void 0 : _previousTrType$extra.statusId);
59
+
60
+ // Check if tr is adding text after adding a list node
61
+ const isAddingTextToListNode = trType.type === ActionType.TEXT_INPUT && checkIsDesiredAction(previousTrType, listActions);
62
+
63
+ // Check if tr is adding new list item after text input
64
+ const isAddingNewListItemAfterTextInput = (previousTrType === null || previousTrType === void 0 ? void 0 : previousTrType.type) === ActionType.TEXT_INPUT && trType.type === ActionType.UPDATING_NEW_LIST_TYPE_ITEM;
65
+
66
+ // Check if tr is textInput
67
+ const isTextInput = textInputActions.includes(trType.type);
68
+
69
+ // Don't increment action count if tr is text input, not a new status, adding text to list node or adding new list item if timeOfLastTextInput is set
70
+ const shouldNotIncrementActionCount = timeOfLastTextInput && (isTextInput || isNotNewStatus || isAddingTextToListNode || isAddingNewListItemAfterTextInput);
71
+ const newTotalActionCount = getNewActionTypeCount(!shouldNotIncrementActionCount, totalActionCount);
72
+
73
+ // Increment textInputCount if tr is text input and previous action was not text input or list action
74
+ const newTextInputCount = getNewActionTypeCount(isTextInput && !(timeOfLastTextInput && checkIsDesiredAction(previousTrType, [...textInputActions, ...listActions])), actionTypeCount.textInputCount);
75
+ const newNodeAttrCount = getNewActionTypeCount((trType === null || trType === void 0 ? void 0 : trType.type) === ActionType.CHANGING_ATTRS, actionTypeCount.nodeAttributeChangeCount);
76
+ const isRepeatedAttrAction = (trType === null || trType === void 0 ? void 0 : trType.type) === ActionType.CHANGING_ATTRS && (previousTrType === null || previousTrType === void 0 ? void 0 : previousTrType.type) === ActionType.CHANGING_ATTRS && trType.extraData.attr === previousTrType.extraData.attr && trType.extraData.from === previousTrType.extraData.from && trType.extraData.to === previousTrType.extraData.to;
77
+ const newRepeatedActionCount = getNewActionTypeCount(isRepeatedAttrAction, pluginState.repeatedActionCount);
78
+ const contentMoved = getNewActionTypeCount((trType === null || trType === void 0 ? void 0 : trType.type) === ActionType.MOVING_CONTENT, actionTypeCount.contentMovedCount);
79
+ const newMarkChangeCount = getNewActionTypeCount((trType === null || trType === void 0 ? void 0 : trType.type) === ActionType.CHANGING_MARK, actionTypeCount.markChangeCount);
80
+ const newContentDeletedCount = getNewActionTypeCount((trType === null || trType === void 0 ? void 0 : trType.type) === ActionType.DELETING_CONTENT, actionTypeCount.contentDeletedCount);
81
+
82
+ // timeOfLastTextInput should be set if tr includes continuous text input on the same node
83
+ const shouldSetTimeOfLastTextInput = continuousActions.includes(trType.type) || isNotNewStatus;
84
+ return {
85
+ ...newPluginState,
86
+ totalActionCount: newTotalActionCount,
87
+ timeOfLastTextInput: shouldSetTimeOfLastTextInput ? now : undefined,
88
+ actionTypeCount: {
89
+ ...actionTypeCount,
90
+ textInputCount: newTextInputCount,
91
+ undoCount: newUndoCount,
92
+ nodeAttributeChangeCount: newNodeAttrCount,
93
+ contentMovedCount: contentMoved,
94
+ markChangeCount: newMarkChangeCount,
95
+ contentDeletedCount: newContentDeletedCount
96
+ },
97
+ previousTrType: trType,
98
+ repeatedActionCount: newRepeatedActionCount,
99
+ safeInsertCount: newSafeInsertCount
100
+ };
101
+ };
@@ -0,0 +1,28 @@
1
+ import { ReplaceStep } from '@atlaskit/editor-prosemirror/transform';
2
+ export const isSafeInsert = (tr, insertPos, trType) => {
3
+ var _$firstStepPos$node, _$insertPos$node;
4
+ // Exclude the cases where trType is defined, as it is a specific action
5
+ // that should not be considered for safe insert actions
6
+ if (trType) {
7
+ return false;
8
+ }
9
+ if (insertPos > tr.doc.content.size) {
10
+ return false;
11
+ }
12
+ const [firstStep] = tr.steps;
13
+ if (!(firstStep instanceof ReplaceStep)) {
14
+ return false;
15
+ }
16
+ const firstStepPos = firstStep.from;
17
+ if (firstStepPos === insertPos) {
18
+ return false;
19
+ }
20
+ const $firstStepPos = tr.doc.resolve(firstStepPos);
21
+ if ($firstStepPos.node().type.name === 'paragraph') {
22
+ return false;
23
+ }
24
+ const firstStepParentNodeType = (_$firstStepPos$node = $firstStepPos.node($firstStepPos.depth)) === null || _$firstStepPos$node === void 0 ? void 0 : _$firstStepPos$node.type.name;
25
+ const $insertPos = tr.doc.resolve(insertPos);
26
+ const parentNodeType = (_$insertPos$node = $insertPos.node($insertPos.depth - 1)) === null || _$insertPos$node === void 0 ? void 0 : _$insertPos$node.type.name;
27
+ return parentNodeType !== firstStepParentNodeType;
28
+ };
@@ -0,0 +1,38 @@
1
+ import { InsertTypeAheadStep, LinkMetaStep } from '@atlaskit/adf-schema/steps';
2
+ import { ReplaceStep } from '@atlaskit/editor-prosemirror/transform';
3
+ const isResolvingLink = tr => {
4
+ var _linkStep$getMetadata;
5
+ // When links are added, there are two transactions that are fired and we want to ignore the last one where the link is resolved
6
+ const linkStep = tr.steps.find(step => step instanceof LinkMetaStep);
7
+ const hasReplaceStep = tr.steps.some(step => step instanceof ReplaceStep);
8
+ return Boolean(hasReplaceStep && linkStep instanceof LinkMetaStep && ((_linkStep$getMetadata = linkStep.getMetadata()) === null || _linkStep$getMetadata === void 0 ? void 0 : _linkStep$getMetadata.cardAction) === 'RESOLVE');
9
+ };
10
+ const checkTypeAheadStepStage = tr => {
11
+ var _tr$getMeta;
12
+ // When nodes are inserted from typeahead, there are multiple transactions that are fired that changes the document
13
+ // We want to ignore all but the last transaction where the node is inserted
14
+ if (((_tr$getMeta = tr.getMeta('typeAheadPlugin$')) === null || _tr$getMeta === void 0 ? void 0 : _tr$getMeta.action) === 'INSERT_RAW_QUERY') {
15
+ return 'INSERT_RAW_QUERY';
16
+ }
17
+ if (!tr.getMeta('appendedTransaction')) {
18
+ return false;
19
+ }
20
+ const insertTypeAheadStep = tr.steps.find(step => step instanceof InsertTypeAheadStep);
21
+ const replaceStep = tr.steps.find(step => step instanceof ReplaceStep);
22
+ if (!insertTypeAheadStep || !replaceStep) {
23
+ return false;
24
+ }
25
+ return insertTypeAheadStep instanceof InsertTypeAheadStep && insertTypeAheadStep.stage;
26
+ };
27
+ export const shouldSkipTr = tr => {
28
+ if (isResolvingLink(tr)) {
29
+ return true;
30
+ }
31
+ const typeAheadStepStage = checkTypeAheadStepStage(tr);
32
+ if (typeAheadStepStage) {
33
+ return typeAheadStepStage !== 'INSERTING_ITEM';
34
+ } else {
35
+ // Ignore all appended transactions apart from when typeahead is inserting an item
36
+ return tr.getMeta('appendedTransaction');
37
+ }
38
+ };
@@ -18,9 +18,17 @@ export var metricsPlugin = function metricsPlugin(_ref) {
18
18
  }];
19
19
  },
20
20
  commands: {
21
- startActiveSessionTimer: function startActiveSessionTimer() {
21
+ setContentMoved: function setContentMoved() {
22
22
  return function (_ref2) {
23
23
  var tr = _ref2.tr;
24
+ return tr.setMeta(metricsKey, {
25
+ contentMoved: true
26
+ });
27
+ };
28
+ },
29
+ startActiveSessionTimer: function startActiveSessionTimer() {
30
+ return function (_ref3) {
31
+ var tr = _ref3.tr;
24
32
  var pluginState = api === null || api === void 0 ? void 0 : api.metrics.sharedState.currentState();
25
33
  if (!(pluginState !== null && pluginState !== void 0 && pluginState.intentToStartEditTime)) {
26
34
  return tr;
@@ -32,8 +40,8 @@ export var metricsPlugin = function metricsPlugin(_ref) {
32
40
  };
33
41
  },
34
42
  stopActiveSession: function stopActiveSession() {
35
- return function (_ref3) {
36
- var tr = _ref3.tr;
43
+ return function (_ref4) {
44
+ var tr = _ref4.tr;
37
45
  if (!api) {
38
46
  return tr;
39
47
  }
@@ -42,11 +50,12 @@ export var metricsPlugin = function metricsPlugin(_ref) {
42
50
  return tr;
43
51
  }
44
52
  if (pluginState && pluginState.totalActionCount > 0 && pluginState.activeSessionTime > 0) {
53
+ var _api$analytics;
45
54
  var payloadToSend = getAnalyticsPayload({
46
55
  currentContent: tr.doc.content,
47
56
  pluginState: pluginState
48
57
  });
49
- api === null || api === void 0 || api.analytics.actions.attachAnalyticsEvent(payloadToSend)(tr);
58
+ api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 || _api$analytics.actions.attachAnalyticsEvent(payloadToSend)(tr);
50
59
  }
51
60
  tr.setMeta(metricsKey, {
52
61
  stopActiveSession: true
@@ -54,13 +63,13 @@ export var metricsPlugin = function metricsPlugin(_ref) {
54
63
  return tr;
55
64
  };
56
65
  },
57
- handleIntentToStartEdit: function handleIntentToStartEdit(_ref4) {
58
- var newSelection = _ref4.newSelection,
59
- _ref4$shouldStartTime = _ref4.shouldStartTimer,
60
- shouldStartTimer = _ref4$shouldStartTime === void 0 ? true : _ref4$shouldStartTime,
61
- shouldPersistActiveSession = _ref4.shouldPersistActiveSession;
62
- return function (_ref5) {
63
- var tr = _ref5.tr;
66
+ handleIntentToStartEdit: function handleIntentToStartEdit(_ref5) {
67
+ var newSelection = _ref5.newSelection,
68
+ _ref5$shouldStartTime = _ref5.shouldStartTimer,
69
+ shouldStartTimer = _ref5$shouldStartTime === void 0 ? true : _ref5$shouldStartTime,
70
+ shouldPersistActiveSession = _ref5.shouldPersistActiveSession;
71
+ return function (_ref6) {
72
+ var tr = _ref6.tr;
64
73
  if (!api) {
65
74
  return tr;
66
75
  }