@atlaskit/editor-plugin-code-block 3.4.1 → 3.4.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,21 @@
1
1
  # @atlaskit/editor-plugin-code-block
2
2
 
3
+ ## 3.4.3
4
+
5
+ ### Patch Changes
6
+
7
+ - [#149087](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/149087)
8
+ [`8b2dcb618ccf8`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/8b2dcb618ccf8) -
9
+ ED-25141: Code block wrapping performance improvement. Only update the line number decorators on a
10
+ given code block when a line has been added or removed. Previously was updating line number
11
+ decorators on every update for all code blocks.
12
+
13
+ ## 3.4.2
14
+
15
+ ### Patch Changes
16
+
17
+ - Updated dependencies
18
+
3
19
  ## 3.4.1
4
20
 
5
21
  ### Patch Changes
@@ -4,7 +4,7 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
4
4
  Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
- exports.validateWordWrappedDecorators = exports.updateDecorationSetWithWordWrappedDecorator = exports.updateDecorationSetWithLineNumberDecorators = exports.updateCodeBlockDecorations = exports.getWordWrapDecoratorsFromNodePos = exports.generateLineAttributesFromNode = exports.generateInitialDecorations = exports.createLineNumbersDecorations = exports.createDecorationSetFromLineAttributes = exports.DECORATION_WRAPPED_BLOCK_NODE_TYPE = exports.DECORATION_WIDGET_TYPE = void 0;
7
+ exports.validateWordWrappedDecorators = exports.updateDecorationSetWithWordWrappedDecorator = exports.updateDecorationSetWithLineNumberDecorators = exports.updateCodeBlockDecorations = exports.getWordWrapDecoratorsFromNodePos = exports.generateLineAttributesFromNode = exports.generateInitialDecorations = exports.createDecorationSetFromLineAttributes = exports.DECORATION_WRAPPED_BLOCK_NODE_TYPE = exports.DECORATION_WIDGET_TYPE = void 0;
8
8
  var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
9
9
  var _codeBlock = require("@atlaskit/editor-common/code-block");
10
10
  var _view = require("@atlaskit/editor-prosemirror/view");
@@ -22,7 +22,7 @@ var DECORATION_WRAPPED_BLOCK_NODE_TYPE = exports.DECORATION_WRAPPED_BLOCK_NODE_T
22
22
  var generateInitialDecorations = exports.generateInitialDecorations = function generateInitialDecorations(state) {
23
23
  var codeBlockNodes = (0, _utils.getAllCodeBlockNodesInDoc)(state);
24
24
  return codeBlockNodes.flatMap(function (node) {
25
- return createLineNumbersDecorations(node);
25
+ return createDecorationSetFromLineAttributes(generateLineAttributesFromNode(node));
26
26
  });
27
27
  };
28
28
 
@@ -31,8 +31,7 @@ var generateInitialDecorations = exports.generateInitialDecorations = function g
31
31
  */
32
32
  var updateCodeBlockDecorations = exports.updateCodeBlockDecorations = function updateCodeBlockDecorations(tr, codeBlockNodes, decorationSet) {
33
33
  var updatedDecorationSet = decorationSet;
34
-
35
- // All the line numbers decorators are refreshed on doc change.
34
+ // Update line number decorators for changed code block nodes if new line added or line removed.
36
35
  updatedDecorationSet = updateDecorationSetWithLineNumberDecorators(tr, codeBlockNodes, updatedDecorationSet);
37
36
 
38
37
  // Check to make sure the word wrap decorators are still valid.
@@ -41,23 +40,36 @@ var updateCodeBlockDecorations = exports.updateCodeBlockDecorations = function u
41
40
  };
42
41
 
43
42
  /**
44
- * Update the decorations set with the line number decorators.
43
+ * Update the decorations set with the line number decorators. This will only happen for the code blocks passed to this function
44
+ * when there has been a new line added or removed. The line decorations will not update the code block node otherwise.
45
45
  */
46
46
  var updateDecorationSetWithLineNumberDecorators = exports.updateDecorationSetWithLineNumberDecorators = function updateDecorationSetWithLineNumberDecorators(tr, codeBlockNodes, decorationSet) {
47
47
  var updatedDecorationSet = decorationSet;
48
- // remove all the line number children from the decorations set. 'undefined, undefined' is used to find() the whole doc.
49
- var children = updatedDecorationSet.find(undefined, undefined, function (spec) {
50
- return spec.type === DECORATION_WIDGET_TYPE;
51
- });
52
- updatedDecorationSet = updatedDecorationSet.remove(children);
53
-
54
- // regenerate all the line number for the documents code blocks
48
+ if (!(0, _platformFeatureFlags.fg)('editor_code_wrapping_perf_improvement_ed-25141')) {
49
+ var children = updatedDecorationSet.find(undefined, undefined, function (spec) {
50
+ return spec.type === DECORATION_WIDGET_TYPE;
51
+ });
52
+ updatedDecorationSet = updatedDecorationSet.remove(children);
53
+ }
55
54
  var lineNumberDecorators = [];
56
55
  codeBlockNodes.forEach(function (node) {
57
- lineNumberDecorators.push.apply(lineNumberDecorators, (0, _toConsumableArray2.default)(createLineNumbersDecorations(node)));
56
+ if ((0, _platformFeatureFlags.fg)('editor_code_wrapping_perf_improvement_ed-25141')) {
57
+ var existingWidgetsOnNode = updatedDecorationSet.find(node.pos, node.pos + node.node.nodeSize, function (spec) {
58
+ return spec.type === DECORATION_WIDGET_TYPE;
59
+ });
60
+ var newLineAttributes = generateLineAttributesFromNode(node);
61
+
62
+ // There will be no widgets on initialisation. If the number of existing widgets does not equal the amount of lines, regenerate the widgets.
63
+ // There may be a case where the number of existing widgets and the number of lines are the same, that's why we track totalLineCount. This allows
64
+ // us to know how many lines there were when the widget was created. It avoids a break in line numbers, e.g. "1, 2, 3, 5, 6". Happens on line removal.
65
+ if (existingWidgetsOnNode.length === 0 || existingWidgetsOnNode.length !== newLineAttributes.length || existingWidgetsOnNode[0].spec.totalLineCount !== newLineAttributes.length) {
66
+ updatedDecorationSet = updatedDecorationSet.remove(existingWidgetsOnNode);
67
+ lineNumberDecorators.push.apply(lineNumberDecorators, (0, _toConsumableArray2.default)(createDecorationSetFromLineAttributes(newLineAttributes)));
68
+ }
69
+ } else {
70
+ lineNumberDecorators.push.apply(lineNumberDecorators, (0, _toConsumableArray2.default)(createDecorationSetFromLineAttributes(generateLineAttributesFromNode(node))));
71
+ }
58
72
  });
59
-
60
- // add the newly generated line numbers to the decorations set
61
73
  return updatedDecorationSet.add(tr.doc, [].concat(lineNumberDecorators));
62
74
  };
63
75
  var generateLineAttributesFromNode = exports.generateLineAttributesFromNode = function generateLineAttributesFromNode(node) {
@@ -110,16 +122,15 @@ var createDecorationSetFromLineAttributes = exports.createDecorationSetFromLineA
110
122
  };
111
123
 
112
124
  // side -1 is used so the line numbers are the first thing to the left of the lines of code.
125
+ // totalLineCount is used to know whether or not to update the line numbers when a new line is added or removed.
113
126
  return _view.Decoration.widget(lineStart, createLineNumberWidget, {
114
127
  type: DECORATION_WIDGET_TYPE,
115
- side: -1
128
+ side: -1,
129
+ totalLineCount: (0, _platformFeatureFlags.fg)('editor_code_wrapping_perf_improvement_ed-25141') ? lineAttributes.length : undefined
116
130
  });
117
131
  });
118
132
  return widgetDecorations;
119
133
  };
120
- var createLineNumbersDecorations = exports.createLineNumbersDecorations = function createLineNumbersDecorations(node) {
121
- return createDecorationSetFromLineAttributes(generateLineAttributesFromNode(node));
122
- };
123
134
 
124
135
  /**
125
136
  * There are edge cases like when a user drags and drops a code block node where the decorator breaks and no longer reflects
@@ -98,11 +98,13 @@ var createPlugin = exports.createPlugin = function createPlugin(_ref) {
98
98
  // specifically used for updating word wrap node decorators (does not cover drag & drop, validateWordWrappedDecorators does).
99
99
  var updatedDecorationSet = pluginState.decorations.map(tr.mapping, tr.doc);
100
100
  if ((0, _platformFeatureFlags.fg)('editor_support_code_block_wrapping')) {
101
- var codeBlockNodes = (0, _utils.getAllCodeBlockNodesInDoc)(newState);
102
- if ((0, _platformFeatureFlags.fg)('editor_code_block_wrapping_language_change_bug')) {
103
- (0, _codeBlock.updateCodeBlockWrappedStateNodeKeys)(codeBlockNodes, _oldState);
101
+ var codeBlockNodes = (0, _platformFeatureFlags.fg)('editor_code_wrapping_perf_improvement_ed-25141') ? (0, _utils.getAllChangedCodeBlocksInTransaction)(tr, newState) : (0, _utils.getAllCodeBlockNodesInDoc)(newState);
102
+ if (codeBlockNodes) {
103
+ if ((0, _platformFeatureFlags.fg)('editor_code_block_wrapping_language_change_bug')) {
104
+ (0, _codeBlock.updateCodeBlockWrappedStateNodeKeys)(codeBlockNodes, _oldState);
105
+ }
106
+ updatedDecorationSet = (0, _decorators.updateCodeBlockDecorations)(tr, codeBlockNodes, updatedDecorationSet);
104
107
  }
105
- updatedDecorationSet = (0, _decorators.updateCodeBlockDecorations)(tr, codeBlockNodes, updatedDecorationSet);
106
108
  }
107
109
  var newPluginState = _objectSpread(_objectSpread({}, pluginState), {}, {
108
110
  pos: _node ? _node.pos : null,
package/dist/cjs/utils.js CHANGED
@@ -9,6 +9,7 @@ Object.defineProperty(exports, "findCodeBlock", {
9
9
  return _transforms.findCodeBlock;
10
10
  }
11
11
  });
12
+ exports.getAllChangedCodeBlocksInTransaction = getAllChangedCodeBlocksInTransaction;
12
13
  exports.getAllCodeBlockNodesInDoc = getAllCodeBlockNodesInDoc;
13
14
  exports.getCursor = getCursor;
14
15
  Object.defineProperty(exports, "transformSingleLineCodeBlockToCodeMark", {
@@ -27,6 +28,8 @@ var _transforms = require("@atlaskit/editor-common/transforms");
27
28
  function getCursor(selection) {
28
29
  return selection.$cursor || undefined;
29
30
  }
31
+
32
+ // Replaced by getAllChangedCodeBlocksInTransaction with FG editor_code_wrapping_perf_improvement_ed-25141.
30
33
  function getAllCodeBlockNodesInDoc(state) {
31
34
  var codeBlockNodes = [];
32
35
  state.doc.descendants(function (node, pos) {
@@ -40,4 +43,28 @@ function getAllCodeBlockNodesInDoc(state) {
40
43
  return true;
41
44
  });
42
45
  return codeBlockNodes;
46
+ }
47
+ function getAllChangedCodeBlocksInTransaction(tr, state) {
48
+ var changedCodeBlocks = [];
49
+ var nodePositions = new Set();
50
+ tr.steps.forEach(function (step) {
51
+ var mapResult = step.getMap();
52
+ mapResult.forEach(function (oldStart, oldEnd, newStart, newEnd) {
53
+ state.doc.nodesBetween(newStart, newEnd, function (node, pos) {
54
+ if (node.type.name === 'codeBlock') {
55
+ if (!nodePositions.has(pos)) {
56
+ nodePositions.add(pos);
57
+ changedCodeBlocks.push({
58
+ node: node,
59
+ pos: pos
60
+ });
61
+ }
62
+ }
63
+ });
64
+ });
65
+ });
66
+ if (changedCodeBlocks.length < 1) {
67
+ return null;
68
+ }
69
+ return changedCodeBlocks;
43
70
  }
@@ -1,4 +1,5 @@
1
1
  /* eslint-disable @atlaskit/platform/ensure-feature-flag-prefix */
2
+
2
3
  import { isCodeBlockWordWrapEnabled } from '@atlaskit/editor-common/code-block';
3
4
  import { Decoration } from '@atlaskit/editor-prosemirror/view';
4
5
  import { fg } from '@atlaskit/platform-feature-flags';
@@ -12,7 +13,7 @@ export const DECORATION_WRAPPED_BLOCK_NODE_TYPE = 'decorationNodeType';
12
13
  */
13
14
  export const generateInitialDecorations = state => {
14
15
  const codeBlockNodes = getAllCodeBlockNodesInDoc(state);
15
- return codeBlockNodes.flatMap(node => createLineNumbersDecorations(node));
16
+ return codeBlockNodes.flatMap(node => createDecorationSetFromLineAttributes(generateLineAttributesFromNode(node)));
16
17
  };
17
18
 
18
19
  /**
@@ -20,8 +21,7 @@ export const generateInitialDecorations = state => {
20
21
  */
21
22
  export const updateCodeBlockDecorations = (tr, codeBlockNodes, decorationSet) => {
22
23
  let updatedDecorationSet = decorationSet;
23
-
24
- // All the line numbers decorators are refreshed on doc change.
24
+ // Update line number decorators for changed code block nodes if new line added or line removed.
25
25
  updatedDecorationSet = updateDecorationSetWithLineNumberDecorators(tr, codeBlockNodes, updatedDecorationSet);
26
26
 
27
27
  // Check to make sure the word wrap decorators are still valid.
@@ -30,21 +30,32 @@ export const updateCodeBlockDecorations = (tr, codeBlockNodes, decorationSet) =>
30
30
  };
31
31
 
32
32
  /**
33
- * Update the decorations set with the line number decorators.
33
+ * Update the decorations set with the line number decorators. This will only happen for the code blocks passed to this function
34
+ * when there has been a new line added or removed. The line decorations will not update the code block node otherwise.
34
35
  */
35
36
  export const updateDecorationSetWithLineNumberDecorators = (tr, codeBlockNodes, decorationSet) => {
36
37
  let updatedDecorationSet = decorationSet;
37
- // remove all the line number children from the decorations set. 'undefined, undefined' is used to find() the whole doc.
38
- const children = updatedDecorationSet.find(undefined, undefined, spec => spec.type === DECORATION_WIDGET_TYPE);
39
- updatedDecorationSet = updatedDecorationSet.remove(children);
40
-
41
- // regenerate all the line number for the documents code blocks
38
+ if (!fg('editor_code_wrapping_perf_improvement_ed-25141')) {
39
+ const children = updatedDecorationSet.find(undefined, undefined, spec => spec.type === DECORATION_WIDGET_TYPE);
40
+ updatedDecorationSet = updatedDecorationSet.remove(children);
41
+ }
42
42
  const lineNumberDecorators = [];
43
43
  codeBlockNodes.forEach(node => {
44
- lineNumberDecorators.push(...createLineNumbersDecorations(node));
45
- });
44
+ if (fg('editor_code_wrapping_perf_improvement_ed-25141')) {
45
+ const existingWidgetsOnNode = updatedDecorationSet.find(node.pos, node.pos + node.node.nodeSize, spec => spec.type === DECORATION_WIDGET_TYPE);
46
+ const newLineAttributes = generateLineAttributesFromNode(node);
46
47
 
47
- // add the newly generated line numbers to the decorations set
48
+ // There will be no widgets on initialisation. If the number of existing widgets does not equal the amount of lines, regenerate the widgets.
49
+ // There may be a case where the number of existing widgets and the number of lines are the same, that's why we track totalLineCount. This allows
50
+ // us to know how many lines there were when the widget was created. It avoids a break in line numbers, e.g. "1, 2, 3, 5, 6". Happens on line removal.
51
+ if (existingWidgetsOnNode.length === 0 || existingWidgetsOnNode.length !== newLineAttributes.length || existingWidgetsOnNode[0].spec.totalLineCount !== newLineAttributes.length) {
52
+ updatedDecorationSet = updatedDecorationSet.remove(existingWidgetsOnNode);
53
+ lineNumberDecorators.push(...createDecorationSetFromLineAttributes(newLineAttributes));
54
+ }
55
+ } else {
56
+ lineNumberDecorators.push(...createDecorationSetFromLineAttributes(generateLineAttributesFromNode(node)));
57
+ }
58
+ });
48
59
  return updatedDecorationSet.add(tr.doc, [...lineNumberDecorators]);
49
60
  };
50
61
  export const generateLineAttributesFromNode = node => {
@@ -101,14 +112,15 @@ export const createDecorationSetFromLineAttributes = lineAttributes => {
101
112
  };
102
113
 
103
114
  // side -1 is used so the line numbers are the first thing to the left of the lines of code.
115
+ // totalLineCount is used to know whether or not to update the line numbers when a new line is added or removed.
104
116
  return Decoration.widget(lineStart, createLineNumberWidget, {
105
117
  type: DECORATION_WIDGET_TYPE,
106
- side: -1
118
+ side: -1,
119
+ totalLineCount: fg('editor_code_wrapping_perf_improvement_ed-25141') ? lineAttributes.length : undefined
107
120
  });
108
121
  });
109
122
  return widgetDecorations;
110
123
  };
111
- export const createLineNumbersDecorations = node => createDecorationSetFromLineAttributes(generateLineAttributesFromNode(node));
112
124
 
113
125
  /**
114
126
  * There are edge cases like when a user drags and drops a code block node where the decorator breaks and no longer reflects
@@ -12,7 +12,7 @@ import { ignoreFollowingMutations, resetShouldIgnoreFollowingMutations } from '.
12
12
  import { codeBlockNodeView } from '../nodeviews/code-block';
13
13
  import { pluginKey } from '../plugin-key';
14
14
  import { codeBlockClassNames } from '../ui/class-names';
15
- import { findCodeBlock, getAllCodeBlockNodesInDoc } from '../utils';
15
+ import { findCodeBlock, getAllChangedCodeBlocksInTransaction, getAllCodeBlockNodesInDoc } from '../utils';
16
16
  import { ACTIONS } from './actions';
17
17
  import { generateInitialDecorations, updateCodeBlockDecorations, updateDecorationSetWithWordWrappedDecorator } from './decorators';
18
18
  export const createPlugin = ({
@@ -88,11 +88,13 @@ export const createPlugin = ({
88
88
  // specifically used for updating word wrap node decorators (does not cover drag & drop, validateWordWrappedDecorators does).
89
89
  let updatedDecorationSet = pluginState.decorations.map(tr.mapping, tr.doc);
90
90
  if (fg('editor_support_code_block_wrapping')) {
91
- const codeBlockNodes = getAllCodeBlockNodesInDoc(newState);
92
- if (fg('editor_code_block_wrapping_language_change_bug')) {
93
- updateCodeBlockWrappedStateNodeKeys(codeBlockNodes, _oldState);
91
+ const codeBlockNodes = fg('editor_code_wrapping_perf_improvement_ed-25141') ? getAllChangedCodeBlocksInTransaction(tr, newState) : getAllCodeBlockNodesInDoc(newState);
92
+ if (codeBlockNodes) {
93
+ if (fg('editor_code_block_wrapping_language_change_bug')) {
94
+ updateCodeBlockWrappedStateNodeKeys(codeBlockNodes, _oldState);
95
+ }
96
+ updatedDecorationSet = updateCodeBlockDecorations(tr, codeBlockNodes, updatedDecorationSet);
94
97
  }
95
- updatedDecorationSet = updateCodeBlockDecorations(tr, codeBlockNodes, updatedDecorationSet);
96
98
  }
97
99
  const newPluginState = {
98
100
  ...pluginState,
@@ -2,6 +2,8 @@ export { findCodeBlock, transformSliceToJoinAdjacentCodeBlocks, transformSingleL
2
2
  export function getCursor(selection) {
3
3
  return selection.$cursor || undefined;
4
4
  }
5
+
6
+ // Replaced by getAllChangedCodeBlocksInTransaction with FG editor_code_wrapping_perf_improvement_ed-25141.
5
7
  export function getAllCodeBlockNodesInDoc(state) {
6
8
  const codeBlockNodes = [];
7
9
  state.doc.descendants((node, pos) => {
@@ -15,4 +17,28 @@ export function getAllCodeBlockNodesInDoc(state) {
15
17
  return true;
16
18
  });
17
19
  return codeBlockNodes;
20
+ }
21
+ export function getAllChangedCodeBlocksInTransaction(tr, state) {
22
+ const changedCodeBlocks = [];
23
+ const nodePositions = new Set();
24
+ tr.steps.forEach(step => {
25
+ const mapResult = step.getMap();
26
+ mapResult.forEach((oldStart, oldEnd, newStart, newEnd) => {
27
+ state.doc.nodesBetween(newStart, newEnd, (node, pos) => {
28
+ if (node.type.name === 'codeBlock') {
29
+ if (!nodePositions.has(pos)) {
30
+ nodePositions.add(pos);
31
+ changedCodeBlocks.push({
32
+ node,
33
+ pos
34
+ });
35
+ }
36
+ }
37
+ });
38
+ });
39
+ });
40
+ if (changedCodeBlocks.length < 1) {
41
+ return null;
42
+ }
43
+ return changedCodeBlocks;
18
44
  }
@@ -1,5 +1,6 @@
1
1
  import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
2
2
  /* eslint-disable @atlaskit/platform/ensure-feature-flag-prefix */
3
+
3
4
  import { isCodeBlockWordWrapEnabled } from '@atlaskit/editor-common/code-block';
4
5
  import { Decoration } from '@atlaskit/editor-prosemirror/view';
5
6
  import { fg } from '@atlaskit/platform-feature-flags';
@@ -14,7 +15,7 @@ export var DECORATION_WRAPPED_BLOCK_NODE_TYPE = 'decorationNodeType';
14
15
  export var generateInitialDecorations = function generateInitialDecorations(state) {
15
16
  var codeBlockNodes = getAllCodeBlockNodesInDoc(state);
16
17
  return codeBlockNodes.flatMap(function (node) {
17
- return createLineNumbersDecorations(node);
18
+ return createDecorationSetFromLineAttributes(generateLineAttributesFromNode(node));
18
19
  });
19
20
  };
20
21
 
@@ -23,8 +24,7 @@ export var generateInitialDecorations = function generateInitialDecorations(stat
23
24
  */
24
25
  export var updateCodeBlockDecorations = function updateCodeBlockDecorations(tr, codeBlockNodes, decorationSet) {
25
26
  var updatedDecorationSet = decorationSet;
26
-
27
- // All the line numbers decorators are refreshed on doc change.
27
+ // Update line number decorators for changed code block nodes if new line added or line removed.
28
28
  updatedDecorationSet = updateDecorationSetWithLineNumberDecorators(tr, codeBlockNodes, updatedDecorationSet);
29
29
 
30
30
  // Check to make sure the word wrap decorators are still valid.
@@ -33,23 +33,36 @@ export var updateCodeBlockDecorations = function updateCodeBlockDecorations(tr,
33
33
  };
34
34
 
35
35
  /**
36
- * Update the decorations set with the line number decorators.
36
+ * Update the decorations set with the line number decorators. This will only happen for the code blocks passed to this function
37
+ * when there has been a new line added or removed. The line decorations will not update the code block node otherwise.
37
38
  */
38
39
  export var updateDecorationSetWithLineNumberDecorators = function updateDecorationSetWithLineNumberDecorators(tr, codeBlockNodes, decorationSet) {
39
40
  var updatedDecorationSet = decorationSet;
40
- // remove all the line number children from the decorations set. 'undefined, undefined' is used to find() the whole doc.
41
- var children = updatedDecorationSet.find(undefined, undefined, function (spec) {
42
- return spec.type === DECORATION_WIDGET_TYPE;
43
- });
44
- updatedDecorationSet = updatedDecorationSet.remove(children);
45
-
46
- // regenerate all the line number for the documents code blocks
41
+ if (!fg('editor_code_wrapping_perf_improvement_ed-25141')) {
42
+ var children = updatedDecorationSet.find(undefined, undefined, function (spec) {
43
+ return spec.type === DECORATION_WIDGET_TYPE;
44
+ });
45
+ updatedDecorationSet = updatedDecorationSet.remove(children);
46
+ }
47
47
  var lineNumberDecorators = [];
48
48
  codeBlockNodes.forEach(function (node) {
49
- lineNumberDecorators.push.apply(lineNumberDecorators, _toConsumableArray(createLineNumbersDecorations(node)));
50
- });
49
+ if (fg('editor_code_wrapping_perf_improvement_ed-25141')) {
50
+ var existingWidgetsOnNode = updatedDecorationSet.find(node.pos, node.pos + node.node.nodeSize, function (spec) {
51
+ return spec.type === DECORATION_WIDGET_TYPE;
52
+ });
53
+ var newLineAttributes = generateLineAttributesFromNode(node);
51
54
 
52
- // add the newly generated line numbers to the decorations set
55
+ // There will be no widgets on initialisation. If the number of existing widgets does not equal the amount of lines, regenerate the widgets.
56
+ // There may be a case where the number of existing widgets and the number of lines are the same, that's why we track totalLineCount. This allows
57
+ // us to know how many lines there were when the widget was created. It avoids a break in line numbers, e.g. "1, 2, 3, 5, 6". Happens on line removal.
58
+ if (existingWidgetsOnNode.length === 0 || existingWidgetsOnNode.length !== newLineAttributes.length || existingWidgetsOnNode[0].spec.totalLineCount !== newLineAttributes.length) {
59
+ updatedDecorationSet = updatedDecorationSet.remove(existingWidgetsOnNode);
60
+ lineNumberDecorators.push.apply(lineNumberDecorators, _toConsumableArray(createDecorationSetFromLineAttributes(newLineAttributes)));
61
+ }
62
+ } else {
63
+ lineNumberDecorators.push.apply(lineNumberDecorators, _toConsumableArray(createDecorationSetFromLineAttributes(generateLineAttributesFromNode(node))));
64
+ }
65
+ });
53
66
  return updatedDecorationSet.add(tr.doc, [].concat(lineNumberDecorators));
54
67
  };
55
68
  export var generateLineAttributesFromNode = function generateLineAttributesFromNode(node) {
@@ -102,16 +115,15 @@ export var createDecorationSetFromLineAttributes = function createDecorationSetF
102
115
  };
103
116
 
104
117
  // side -1 is used so the line numbers are the first thing to the left of the lines of code.
118
+ // totalLineCount is used to know whether or not to update the line numbers when a new line is added or removed.
105
119
  return Decoration.widget(lineStart, createLineNumberWidget, {
106
120
  type: DECORATION_WIDGET_TYPE,
107
- side: -1
121
+ side: -1,
122
+ totalLineCount: fg('editor_code_wrapping_perf_improvement_ed-25141') ? lineAttributes.length : undefined
108
123
  });
109
124
  });
110
125
  return widgetDecorations;
111
126
  };
112
- export var createLineNumbersDecorations = function createLineNumbersDecorations(node) {
113
- return createDecorationSetFromLineAttributes(generateLineAttributesFromNode(node));
114
- };
115
127
 
116
128
  /**
117
129
  * There are edge cases like when a user drags and drops a code block node where the decorator breaks and no longer reflects
@@ -15,7 +15,7 @@ import { ignoreFollowingMutations, resetShouldIgnoreFollowingMutations } from '.
15
15
  import { codeBlockNodeView } from '../nodeviews/code-block';
16
16
  import { pluginKey } from '../plugin-key';
17
17
  import { codeBlockClassNames } from '../ui/class-names';
18
- import { findCodeBlock, getAllCodeBlockNodesInDoc } from '../utils';
18
+ import { findCodeBlock, getAllChangedCodeBlocksInTransaction, getAllCodeBlockNodesInDoc } from '../utils';
19
19
  import { ACTIONS } from './actions';
20
20
  import { generateInitialDecorations, updateCodeBlockDecorations, updateDecorationSetWithWordWrappedDecorator } from './decorators';
21
21
  export var createPlugin = function createPlugin(_ref) {
@@ -93,11 +93,13 @@ export var createPlugin = function createPlugin(_ref) {
93
93
  // specifically used for updating word wrap node decorators (does not cover drag & drop, validateWordWrappedDecorators does).
94
94
  var updatedDecorationSet = pluginState.decorations.map(tr.mapping, tr.doc);
95
95
  if (fg('editor_support_code_block_wrapping')) {
96
- var codeBlockNodes = getAllCodeBlockNodesInDoc(newState);
97
- if (fg('editor_code_block_wrapping_language_change_bug')) {
98
- updateCodeBlockWrappedStateNodeKeys(codeBlockNodes, _oldState);
96
+ var codeBlockNodes = fg('editor_code_wrapping_perf_improvement_ed-25141') ? getAllChangedCodeBlocksInTransaction(tr, newState) : getAllCodeBlockNodesInDoc(newState);
97
+ if (codeBlockNodes) {
98
+ if (fg('editor_code_block_wrapping_language_change_bug')) {
99
+ updateCodeBlockWrappedStateNodeKeys(codeBlockNodes, _oldState);
100
+ }
101
+ updatedDecorationSet = updateCodeBlockDecorations(tr, codeBlockNodes, updatedDecorationSet);
99
102
  }
100
- updatedDecorationSet = updateCodeBlockDecorations(tr, codeBlockNodes, updatedDecorationSet);
101
103
  }
102
104
  var newPluginState = _objectSpread(_objectSpread({}, pluginState), {}, {
103
105
  pos: _node ? _node.pos : null,
package/dist/esm/utils.js CHANGED
@@ -2,6 +2,8 @@ export { findCodeBlock, transformSliceToJoinAdjacentCodeBlocks, transformSingleL
2
2
  export function getCursor(selection) {
3
3
  return selection.$cursor || undefined;
4
4
  }
5
+
6
+ // Replaced by getAllChangedCodeBlocksInTransaction with FG editor_code_wrapping_perf_improvement_ed-25141.
5
7
  export function getAllCodeBlockNodesInDoc(state) {
6
8
  var codeBlockNodes = [];
7
9
  state.doc.descendants(function (node, pos) {
@@ -15,4 +17,28 @@ export function getAllCodeBlockNodesInDoc(state) {
15
17
  return true;
16
18
  });
17
19
  return codeBlockNodes;
20
+ }
21
+ export function getAllChangedCodeBlocksInTransaction(tr, state) {
22
+ var changedCodeBlocks = [];
23
+ var nodePositions = new Set();
24
+ tr.steps.forEach(function (step) {
25
+ var mapResult = step.getMap();
26
+ mapResult.forEach(function (oldStart, oldEnd, newStart, newEnd) {
27
+ state.doc.nodesBetween(newStart, newEnd, function (node, pos) {
28
+ if (node.type.name === 'codeBlock') {
29
+ if (!nodePositions.has(pos)) {
30
+ nodePositions.add(pos);
31
+ changedCodeBlocks.push({
32
+ node: node,
33
+ pos: pos
34
+ });
35
+ }
36
+ }
37
+ });
38
+ });
39
+ });
40
+ if (changedCodeBlocks.length < 1) {
41
+ return null;
42
+ }
43
+ return changedCodeBlocks;
18
44
  }
@@ -13,12 +13,12 @@ export declare const generateInitialDecorations: (state: EditorState) => Decorat
13
13
  */
14
14
  export declare const updateCodeBlockDecorations: (tr: ReadonlyTransaction, codeBlockNodes: NodeWithPos[], decorationSet: DecorationSet) => DecorationSet;
15
15
  /**
16
- * Update the decorations set with the line number decorators.
16
+ * Update the decorations set with the line number decorators. This will only happen for the code blocks passed to this function
17
+ * when there has been a new line added or removed. The line decorations will not update the code block node otherwise.
17
18
  */
18
19
  export declare const updateDecorationSetWithLineNumberDecorators: (tr: ReadonlyTransaction, codeBlockNodes: NodeWithPos[], decorationSet: DecorationSet) => DecorationSet;
19
20
  export declare const generateLineAttributesFromNode: (node: NodeWithPos) => CodeBlockLineAttributes[];
20
21
  export declare const createDecorationSetFromLineAttributes: (lineAttributes: CodeBlockLineAttributes[]) => Decoration[];
21
- export declare const createLineNumbersDecorations: (node: NodeWithPos) => Decoration[];
22
22
  /**
23
23
  * There are edge cases like when a user drags and drops a code block node where the decorator breaks and no longer reflects
24
24
  * the correct word wrap state. This function validates that the decorator and the state are in line, otherwise it will
@@ -1,6 +1,7 @@
1
1
  export { findCodeBlock, transformSliceToJoinAdjacentCodeBlocks, transformSingleLineCodeBlockToCodeMark, } from '@atlaskit/editor-common/transforms';
2
2
  import type { ResolvedPos } from '@atlaskit/editor-prosemirror/model';
3
- import type { EditorState, Selection } from '@atlaskit/editor-prosemirror/state';
3
+ import type { EditorState, ReadonlyTransaction, Selection } from '@atlaskit/editor-prosemirror/state';
4
4
  import type { NodeWithPos } from '@atlaskit/editor-prosemirror/utils';
5
5
  export declare function getCursor(selection: Selection): ResolvedPos | undefined;
6
6
  export declare function getAllCodeBlockNodesInDoc(state: EditorState): NodeWithPos[];
7
+ export declare function getAllChangedCodeBlocksInTransaction(tr: ReadonlyTransaction, state: EditorState): NodeWithPos[] | null;
@@ -13,12 +13,12 @@ export declare const generateInitialDecorations: (state: EditorState) => Decorat
13
13
  */
14
14
  export declare const updateCodeBlockDecorations: (tr: ReadonlyTransaction, codeBlockNodes: NodeWithPos[], decorationSet: DecorationSet) => DecorationSet;
15
15
  /**
16
- * Update the decorations set with the line number decorators.
16
+ * Update the decorations set with the line number decorators. This will only happen for the code blocks passed to this function
17
+ * when there has been a new line added or removed. The line decorations will not update the code block node otherwise.
17
18
  */
18
19
  export declare const updateDecorationSetWithLineNumberDecorators: (tr: ReadonlyTransaction, codeBlockNodes: NodeWithPos[], decorationSet: DecorationSet) => DecorationSet;
19
20
  export declare const generateLineAttributesFromNode: (node: NodeWithPos) => CodeBlockLineAttributes[];
20
21
  export declare const createDecorationSetFromLineAttributes: (lineAttributes: CodeBlockLineAttributes[]) => Decoration[];
21
- export declare const createLineNumbersDecorations: (node: NodeWithPos) => Decoration[];
22
22
  /**
23
23
  * There are edge cases like when a user drags and drops a code block node where the decorator breaks and no longer reflects
24
24
  * the correct word wrap state. This function validates that the decorator and the state are in line, otherwise it will
@@ -1,6 +1,7 @@
1
1
  export { findCodeBlock, transformSliceToJoinAdjacentCodeBlocks, transformSingleLineCodeBlockToCodeMark, } from '@atlaskit/editor-common/transforms';
2
2
  import type { ResolvedPos } from '@atlaskit/editor-prosemirror/model';
3
- import type { EditorState, Selection } from '@atlaskit/editor-prosemirror/state';
3
+ import type { EditorState, ReadonlyTransaction, Selection } from '@atlaskit/editor-prosemirror/state';
4
4
  import type { NodeWithPos } from '@atlaskit/editor-prosemirror/utils';
5
5
  export declare function getCursor(selection: Selection): ResolvedPos | undefined;
6
6
  export declare function getAllCodeBlockNodesInDoc(state: EditorState): NodeWithPos[];
7
+ export declare function getAllChangedCodeBlocksInTransaction(tr: ReadonlyTransaction, state: EditorState): NodeWithPos[] | null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-code-block",
3
- "version": "3.4.1",
3
+ "version": "3.4.3",
4
4
  "description": "Code block plugin for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -33,13 +33,13 @@
33
33
  "dependencies": {
34
34
  "@atlaskit/adf-schema": "^40.9.0",
35
35
  "@atlaskit/code": "^15.6.0",
36
- "@atlaskit/editor-common": "^92.0.0",
36
+ "@atlaskit/editor-common": "^93.1.0",
37
37
  "@atlaskit/editor-plugin-analytics": "^1.8.0",
38
38
  "@atlaskit/editor-plugin-composition": "^1.2.0",
39
39
  "@atlaskit/editor-plugin-decorations": "^1.3.0",
40
40
  "@atlaskit/editor-plugin-editor-disabled": "^1.3.0",
41
41
  "@atlaskit/editor-prosemirror": "6.0.0",
42
- "@atlaskit/icon": "^22.19.0",
42
+ "@atlaskit/icon": "^22.20.0",
43
43
  "@atlaskit/platform-feature-flags": "^0.3.0",
44
44
  "@atlaskit/prosemirror-input-rules": "^3.2.0",
45
45
  "@babel/runtime": "^7.0.0",
@@ -102,6 +102,9 @@
102
102
  },
103
103
  "editor_nest_media_and_codeblock_in_quotes_jira": {
104
104
  "type": "boolean"
105
+ },
106
+ "editor_code_wrapping_perf_improvement_ed-25141": {
107
+ "type": "boolean"
105
108
  }
106
109
  }
107
110
  }