@atlaskit/editor-plugin-limited-mode 4.0.4 → 4.0.6
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 +15 -0
- package/dist/cjs/pm-plugins/main.js +85 -45
- package/dist/es2019/pm-plugins/main.js +85 -45
- package/dist/esm/pm-plugins/main.js +85 -45
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# @atlaskit/editor-plugin-limited-mode
|
|
2
2
|
|
|
3
|
+
## 4.0.6
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`49dad8567c387`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/49dad8567c387) -
|
|
8
|
+
EDITOR-4948 - Change performance mode threshold condition to include doc size, node count, and LCM
|
|
9
|
+
check.
|
|
10
|
+
- Updated dependencies
|
|
11
|
+
|
|
12
|
+
## 4.0.5
|
|
13
|
+
|
|
14
|
+
### Patch Changes
|
|
15
|
+
|
|
16
|
+
- Updated dependencies
|
|
17
|
+
|
|
3
18
|
## 4.0.4
|
|
4
19
|
|
|
5
20
|
### Patch Changes
|
|
@@ -10,36 +10,98 @@ var _expVal = require("@atlaskit/tmp-editor-statsig/expVal");
|
|
|
10
10
|
var limitedModePluginKey = exports.limitedModePluginKey = new _state.PluginKey('limitedModePlugin');
|
|
11
11
|
var LIMITED_MODE_NODE_SIZE_THRESHOLD = 40000;
|
|
12
12
|
/**
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* Note: legacy-content macros add a damped contribution based on ADF length to avoid
|
|
16
|
-
* parsing nested ADF on every check, which is inefficient.
|
|
13
|
+
* Gets a numeric experiment param, returning undefined if the value is not a valid number.
|
|
14
|
+
* This guards against test overrides returning booleans or strings for numeric params.
|
|
17
15
|
*/
|
|
18
|
-
var
|
|
19
|
-
var
|
|
16
|
+
var getNumericExperimentParam = function getNumericExperimentParam(paramName, fallbackValue) {
|
|
17
|
+
var rawValue = (0, _expVal.expVal)('cc_editor_limited_mode_expanded', paramName, fallbackValue);
|
|
18
|
+
if (typeof rawValue === 'number') {
|
|
19
|
+
return rawValue;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Handle string values from test overrides
|
|
23
|
+
if (typeof rawValue === 'string') {
|
|
24
|
+
var parsed = parseInt(rawValue, 10);
|
|
25
|
+
if (!isNaN(parsed)) {
|
|
26
|
+
return parsed;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return undefined;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Calculates custom document size including LCM ADF lengths (for non-expanded path).
|
|
34
|
+
* This function can be removed when cc_editor_limited_mode_expanded is cleaned up.
|
|
35
|
+
*/
|
|
36
|
+
var getCustomDocSize = function getCustomDocSize(doc) {
|
|
37
|
+
var lcmAdfLength = 0;
|
|
20
38
|
doc.descendants(function (node) {
|
|
21
39
|
var _node$attrs;
|
|
22
|
-
nodeCount += 1;
|
|
23
40
|
if (((_node$attrs = node.attrs) === null || _node$attrs === void 0 ? void 0 : _node$attrs.extensionKey) === 'legacy-content') {
|
|
24
|
-
var _node$attrs2;
|
|
25
|
-
|
|
26
|
-
if (typeof adfLength === 'number' && lcmDampingFactor > 0) {
|
|
27
|
-
nodeCount += Math.ceil(adfLength / lcmDampingFactor);
|
|
28
|
-
}
|
|
41
|
+
var _node$attrs$parameter, _node$attrs2;
|
|
42
|
+
lcmAdfLength += (_node$attrs$parameter = (_node$attrs2 = node.attrs) === null || _node$attrs2 === void 0 || (_node$attrs2 = _node$attrs2.parameters) === null || _node$attrs2 === void 0 || (_node$attrs2 = _node$attrs2.adf) === null || _node$attrs2 === void 0 ? void 0 : _node$attrs2.length) !== null && _node$attrs$parameter !== void 0 ? _node$attrs$parameter : 0;
|
|
29
43
|
}
|
|
30
44
|
});
|
|
31
|
-
return
|
|
45
|
+
return doc.nodeSize + lcmAdfLength;
|
|
32
46
|
};
|
|
33
47
|
|
|
34
48
|
/**
|
|
35
|
-
*
|
|
49
|
+
* Determines whether limited mode should be enabled under the expanded gate.
|
|
50
|
+
* If this logic changes, update the duplicate in `editor-common/src/node-anchor/node-anchor-provider.ts` to avoid drift.
|
|
51
|
+
*
|
|
52
|
+
* Limited mode is activated when ANY of the following conditions are met:
|
|
53
|
+
* 1. Document size exceeds `docSizeThreshold` (if defined)
|
|
54
|
+
* 2. Node count exceeds `nodeCountThreshold` (if defined)
|
|
55
|
+
* 3. Document contains a legacy-content macro (LCM) (if `includeLcmInThreshold` is true)
|
|
56
|
+
*
|
|
57
|
+
* Performance optimisations:
|
|
58
|
+
* - Doc size is checked first (O(1)) - if it exceeds threshold, we skip traversal entirely.
|
|
59
|
+
* - If `includeLcmInThreshold` is enabled and we find an LCM, we exit traversal early
|
|
60
|
+
* since we already know limited mode will be enabled.
|
|
61
|
+
* - If neither node count nor LCM conditions are configured, we skip traversal entirely.
|
|
36
62
|
*/
|
|
37
|
-
var
|
|
38
|
-
var
|
|
39
|
-
|
|
40
|
-
|
|
63
|
+
var shouldEnableLimitedModeExpanded = function shouldEnableLimitedModeExpanded(doc) {
|
|
64
|
+
var nodeCountThreshold = getNumericExperimentParam('nodeCountThreshold', 5000);
|
|
65
|
+
var docSizeThreshold = getNumericExperimentParam('docSizeThreshold', 30000);
|
|
66
|
+
var includeLcmInThreshold = Boolean((0, _expVal.expVal)('cc_editor_limited_mode_expanded', 'includeLcmInThreshold', false));
|
|
67
|
+
|
|
68
|
+
// Early exit: doc size exceeds threshold - O(1), no traversal needed
|
|
69
|
+
if (docSizeThreshold !== undefined && doc.nodeSize > docSizeThreshold) {
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Early exit: no traversal needed if neither condition is configured
|
|
74
|
+
var needNodeCount = nodeCountThreshold !== undefined;
|
|
75
|
+
if (!needNodeCount && !includeLcmInThreshold) {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Single traversal for node count and/or LCM detection
|
|
80
|
+
var nodeCount = 0;
|
|
81
|
+
var hasLcm = false;
|
|
82
|
+
doc.descendants(function (node) {
|
|
83
|
+
var _node$attrs3;
|
|
84
|
+
nodeCount += 1;
|
|
85
|
+
if (((_node$attrs3 = node.attrs) === null || _node$attrs3 === void 0 ? void 0 : _node$attrs3.extensionKey) === 'legacy-content') {
|
|
86
|
+
hasLcm = true;
|
|
87
|
+
|
|
88
|
+
// Early exit: LCM found and condition is enabled - no need to continue counting
|
|
89
|
+
if (includeLcmInThreshold) {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// LCM condition takes precedence (if we early exited traversal, this is why)
|
|
96
|
+
if (includeLcmInThreshold && hasLcm) {
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Check node count threshold
|
|
101
|
+
if (needNodeCount && nodeCount > nodeCountThreshold) {
|
|
102
|
+
return true;
|
|
41
103
|
}
|
|
42
|
-
return
|
|
104
|
+
return false;
|
|
43
105
|
};
|
|
44
106
|
var createPlugin = exports.createPlugin = function createPlugin() {
|
|
45
107
|
return new _safePlugin.SafePlugin({
|
|
@@ -50,24 +112,13 @@ var createPlugin = exports.createPlugin = function createPlugin() {
|
|
|
50
112
|
state: {
|
|
51
113
|
init: function init(config, editorState) {
|
|
52
114
|
if ((0, _expVal.expVal)('cc_editor_limited_mode_expanded', 'isEnabled', false)) {
|
|
53
|
-
var lcmNodeCountDampingFactor = getNumericExperimentParam('cc_editor_limited_mode_expanded', 'lcmNodeCountDampingFactor', 10);
|
|
54
|
-
var nodeCountThreshold = getNumericExperimentParam('cc_editor_limited_mode_expanded', 'nodeCountThreshold', 1000);
|
|
55
|
-
var nodeCount = countNodesInDoc(editorState.doc, lcmNodeCountDampingFactor);
|
|
56
115
|
return {
|
|
57
|
-
documentSizeBreachesThreshold:
|
|
116
|
+
documentSizeBreachesThreshold: shouldEnableLimitedModeExpanded(editorState.doc)
|
|
58
117
|
};
|
|
59
118
|
} else {
|
|
60
119
|
// calculates the size of the doc, where when there are legacy content macros, the content
|
|
61
120
|
// is stored in the attrs.
|
|
62
|
-
|
|
63
|
-
var customDocSize = editorState.doc.nodeSize;
|
|
64
|
-
editorState.doc.descendants(function (node) {
|
|
65
|
-
var _node$attrs3;
|
|
66
|
-
if (((_node$attrs3 = node.attrs) === null || _node$attrs3 === void 0 ? void 0 : _node$attrs3.extensionKey) === 'legacy-content') {
|
|
67
|
-
var _node$attrs$parameter, _node$attrs4;
|
|
68
|
-
customDocSize += (_node$attrs$parameter = (_node$attrs4 = node.attrs) === null || _node$attrs4 === void 0 || (_node$attrs4 = _node$attrs4.parameters) === null || _node$attrs4 === void 0 || (_node$attrs4 = _node$attrs4.adf) === null || _node$attrs4 === void 0 ? void 0 : _node$attrs4.length) !== null && _node$attrs$parameter !== void 0 ? _node$attrs$parameter : 0;
|
|
69
|
-
}
|
|
70
|
-
});
|
|
121
|
+
var customDocSize = getCustomDocSize(editorState.doc);
|
|
71
122
|
return {
|
|
72
123
|
documentSizeBreachesThreshold: customDocSize > LIMITED_MODE_NODE_SIZE_THRESHOLD
|
|
73
124
|
};
|
|
@@ -81,24 +132,13 @@ var createPlugin = exports.createPlugin = function createPlugin() {
|
|
|
81
132
|
return currentPluginState;
|
|
82
133
|
}
|
|
83
134
|
if ((0, _expVal.expVal)('cc_editor_limited_mode_expanded', 'isEnabled', false)) {
|
|
84
|
-
var lcmNodeCountDampingFactor = getNumericExperimentParam('cc_editor_limited_mode_expanded', 'lcmNodeCountDampingFactor', 10);
|
|
85
|
-
var nodeCountThreshold = getNumericExperimentParam('cc_editor_limited_mode_expanded', 'nodeCountThreshold', 1000);
|
|
86
|
-
var nodeCount = countNodesInDoc(tr.doc, lcmNodeCountDampingFactor);
|
|
87
135
|
return {
|
|
88
|
-
documentSizeBreachesThreshold:
|
|
136
|
+
documentSizeBreachesThreshold: shouldEnableLimitedModeExpanded(tr.doc)
|
|
89
137
|
};
|
|
90
138
|
} else {
|
|
91
139
|
// calculates the size of the doc, where when there are legacy content macros, the content
|
|
92
140
|
// is stored in the attrs.
|
|
93
|
-
|
|
94
|
-
var customDocSize = tr.doc.nodeSize;
|
|
95
|
-
tr.doc.descendants(function (node) {
|
|
96
|
-
var _node$attrs5;
|
|
97
|
-
if (((_node$attrs5 = node.attrs) === null || _node$attrs5 === void 0 ? void 0 : _node$attrs5.extensionKey) === 'legacy-content') {
|
|
98
|
-
var _node$attrs$parameter2, _node$attrs6;
|
|
99
|
-
customDocSize += (_node$attrs$parameter2 = (_node$attrs6 = node.attrs) === null || _node$attrs6 === void 0 || (_node$attrs6 = _node$attrs6.parameters) === null || _node$attrs6 === void 0 || (_node$attrs6 = _node$attrs6.adf) === null || _node$attrs6 === void 0 ? void 0 : _node$attrs6.length) !== null && _node$attrs$parameter2 !== void 0 ? _node$attrs$parameter2 : 0;
|
|
100
|
-
}
|
|
101
|
-
});
|
|
141
|
+
var customDocSize = getCustomDocSize(tr.doc);
|
|
102
142
|
return {
|
|
103
143
|
documentSizeBreachesThreshold: customDocSize > LIMITED_MODE_NODE_SIZE_THRESHOLD
|
|
104
144
|
};
|
|
@@ -4,36 +4,98 @@ import { expVal } from '@atlaskit/tmp-editor-statsig/expVal';
|
|
|
4
4
|
export const limitedModePluginKey = new PluginKey('limitedModePlugin');
|
|
5
5
|
const LIMITED_MODE_NODE_SIZE_THRESHOLD = 40000;
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* Note: legacy-content macros add a damped contribution based on ADF length to avoid
|
|
10
|
-
* parsing nested ADF on every check, which is inefficient.
|
|
7
|
+
* Gets a numeric experiment param, returning undefined if the value is not a valid number.
|
|
8
|
+
* This guards against test overrides returning booleans or strings for numeric params.
|
|
11
9
|
*/
|
|
12
|
-
const
|
|
13
|
-
|
|
10
|
+
const getNumericExperimentParam = (paramName, fallbackValue) => {
|
|
11
|
+
const rawValue = expVal('cc_editor_limited_mode_expanded', paramName, fallbackValue);
|
|
12
|
+
if (typeof rawValue === 'number') {
|
|
13
|
+
return rawValue;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Handle string values from test overrides
|
|
17
|
+
if (typeof rawValue === 'string') {
|
|
18
|
+
const parsed = parseInt(rawValue, 10);
|
|
19
|
+
if (!isNaN(parsed)) {
|
|
20
|
+
return parsed;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return undefined;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Calculates custom document size including LCM ADF lengths (for non-expanded path).
|
|
28
|
+
* This function can be removed when cc_editor_limited_mode_expanded is cleaned up.
|
|
29
|
+
*/
|
|
30
|
+
const getCustomDocSize = doc => {
|
|
31
|
+
let lcmAdfLength = 0;
|
|
14
32
|
doc.descendants(node => {
|
|
15
33
|
var _node$attrs;
|
|
16
|
-
nodeCount += 1;
|
|
17
34
|
if (((_node$attrs = node.attrs) === null || _node$attrs === void 0 ? void 0 : _node$attrs.extensionKey) === 'legacy-content') {
|
|
18
|
-
var _node$attrs2, _node$attrs2$paramete, _node$attrs2$paramete2;
|
|
19
|
-
|
|
20
|
-
if (typeof adfLength === 'number' && lcmDampingFactor > 0) {
|
|
21
|
-
nodeCount += Math.ceil(adfLength / lcmDampingFactor);
|
|
22
|
-
}
|
|
35
|
+
var _node$attrs$parameter, _node$attrs2, _node$attrs2$paramete, _node$attrs2$paramete2;
|
|
36
|
+
lcmAdfLength += (_node$attrs$parameter = (_node$attrs2 = node.attrs) === null || _node$attrs2 === void 0 ? void 0 : (_node$attrs2$paramete = _node$attrs2.parameters) === null || _node$attrs2$paramete === void 0 ? void 0 : (_node$attrs2$paramete2 = _node$attrs2$paramete.adf) === null || _node$attrs2$paramete2 === void 0 ? void 0 : _node$attrs2$paramete2.length) !== null && _node$attrs$parameter !== void 0 ? _node$attrs$parameter : 0;
|
|
23
37
|
}
|
|
24
38
|
});
|
|
25
|
-
return
|
|
39
|
+
return doc.nodeSize + lcmAdfLength;
|
|
26
40
|
};
|
|
27
41
|
|
|
28
42
|
/**
|
|
29
|
-
*
|
|
43
|
+
* Determines whether limited mode should be enabled under the expanded gate.
|
|
44
|
+
* If this logic changes, update the duplicate in `editor-common/src/node-anchor/node-anchor-provider.ts` to avoid drift.
|
|
45
|
+
*
|
|
46
|
+
* Limited mode is activated when ANY of the following conditions are met:
|
|
47
|
+
* 1. Document size exceeds `docSizeThreshold` (if defined)
|
|
48
|
+
* 2. Node count exceeds `nodeCountThreshold` (if defined)
|
|
49
|
+
* 3. Document contains a legacy-content macro (LCM) (if `includeLcmInThreshold` is true)
|
|
50
|
+
*
|
|
51
|
+
* Performance optimisations:
|
|
52
|
+
* - Doc size is checked first (O(1)) - if it exceeds threshold, we skip traversal entirely.
|
|
53
|
+
* - If `includeLcmInThreshold` is enabled and we find an LCM, we exit traversal early
|
|
54
|
+
* since we already know limited mode will be enabled.
|
|
55
|
+
* - If neither node count nor LCM conditions are configured, we skip traversal entirely.
|
|
30
56
|
*/
|
|
31
|
-
const
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
57
|
+
const shouldEnableLimitedModeExpanded = doc => {
|
|
58
|
+
const nodeCountThreshold = getNumericExperimentParam('nodeCountThreshold', 5000);
|
|
59
|
+
const docSizeThreshold = getNumericExperimentParam('docSizeThreshold', 30000);
|
|
60
|
+
const includeLcmInThreshold = Boolean(expVal('cc_editor_limited_mode_expanded', 'includeLcmInThreshold', false));
|
|
61
|
+
|
|
62
|
+
// Early exit: doc size exceeds threshold - O(1), no traversal needed
|
|
63
|
+
if (docSizeThreshold !== undefined && doc.nodeSize > docSizeThreshold) {
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Early exit: no traversal needed if neither condition is configured
|
|
68
|
+
const needNodeCount = nodeCountThreshold !== undefined;
|
|
69
|
+
if (!needNodeCount && !includeLcmInThreshold) {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Single traversal for node count and/or LCM detection
|
|
74
|
+
let nodeCount = 0;
|
|
75
|
+
let hasLcm = false;
|
|
76
|
+
doc.descendants(node => {
|
|
77
|
+
var _node$attrs3;
|
|
78
|
+
nodeCount += 1;
|
|
79
|
+
if (((_node$attrs3 = node.attrs) === null || _node$attrs3 === void 0 ? void 0 : _node$attrs3.extensionKey) === 'legacy-content') {
|
|
80
|
+
hasLcm = true;
|
|
81
|
+
|
|
82
|
+
// Early exit: LCM found and condition is enabled - no need to continue counting
|
|
83
|
+
if (includeLcmInThreshold) {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
// LCM condition takes precedence (if we early exited traversal, this is why)
|
|
90
|
+
if (includeLcmInThreshold && hasLcm) {
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Check node count threshold
|
|
95
|
+
if (needNodeCount && nodeCount > nodeCountThreshold) {
|
|
96
|
+
return true;
|
|
35
97
|
}
|
|
36
|
-
return
|
|
98
|
+
return false;
|
|
37
99
|
};
|
|
38
100
|
export const createPlugin = () => {
|
|
39
101
|
return new SafePlugin({
|
|
@@ -44,24 +106,13 @@ export const createPlugin = () => {
|
|
|
44
106
|
state: {
|
|
45
107
|
init(config, editorState) {
|
|
46
108
|
if (expVal('cc_editor_limited_mode_expanded', 'isEnabled', false)) {
|
|
47
|
-
const lcmNodeCountDampingFactor = getNumericExperimentParam('cc_editor_limited_mode_expanded', 'lcmNodeCountDampingFactor', 10);
|
|
48
|
-
const nodeCountThreshold = getNumericExperimentParam('cc_editor_limited_mode_expanded', 'nodeCountThreshold', 1000);
|
|
49
|
-
const nodeCount = countNodesInDoc(editorState.doc, lcmNodeCountDampingFactor);
|
|
50
109
|
return {
|
|
51
|
-
documentSizeBreachesThreshold:
|
|
110
|
+
documentSizeBreachesThreshold: shouldEnableLimitedModeExpanded(editorState.doc)
|
|
52
111
|
};
|
|
53
112
|
} else {
|
|
54
113
|
// calculates the size of the doc, where when there are legacy content macros, the content
|
|
55
114
|
// is stored in the attrs.
|
|
56
|
-
|
|
57
|
-
let customDocSize = editorState.doc.nodeSize;
|
|
58
|
-
editorState.doc.descendants(node => {
|
|
59
|
-
var _node$attrs3;
|
|
60
|
-
if (((_node$attrs3 = node.attrs) === null || _node$attrs3 === void 0 ? void 0 : _node$attrs3.extensionKey) === 'legacy-content') {
|
|
61
|
-
var _node$attrs$parameter, _node$attrs4, _node$attrs4$paramete, _node$attrs4$paramete2;
|
|
62
|
-
customDocSize += (_node$attrs$parameter = (_node$attrs4 = node.attrs) === null || _node$attrs4 === void 0 ? void 0 : (_node$attrs4$paramete = _node$attrs4.parameters) === null || _node$attrs4$paramete === void 0 ? void 0 : (_node$attrs4$paramete2 = _node$attrs4$paramete.adf) === null || _node$attrs4$paramete2 === void 0 ? void 0 : _node$attrs4$paramete2.length) !== null && _node$attrs$parameter !== void 0 ? _node$attrs$parameter : 0;
|
|
63
|
-
}
|
|
64
|
-
});
|
|
115
|
+
const customDocSize = getCustomDocSize(editorState.doc);
|
|
65
116
|
return {
|
|
66
117
|
documentSizeBreachesThreshold: customDocSize > LIMITED_MODE_NODE_SIZE_THRESHOLD
|
|
67
118
|
};
|
|
@@ -75,24 +126,13 @@ export const createPlugin = () => {
|
|
|
75
126
|
return currentPluginState;
|
|
76
127
|
}
|
|
77
128
|
if (expVal('cc_editor_limited_mode_expanded', 'isEnabled', false)) {
|
|
78
|
-
const lcmNodeCountDampingFactor = getNumericExperimentParam('cc_editor_limited_mode_expanded', 'lcmNodeCountDampingFactor', 10);
|
|
79
|
-
const nodeCountThreshold = getNumericExperimentParam('cc_editor_limited_mode_expanded', 'nodeCountThreshold', 1000);
|
|
80
|
-
const nodeCount = countNodesInDoc(tr.doc, lcmNodeCountDampingFactor);
|
|
81
129
|
return {
|
|
82
|
-
documentSizeBreachesThreshold:
|
|
130
|
+
documentSizeBreachesThreshold: shouldEnableLimitedModeExpanded(tr.doc)
|
|
83
131
|
};
|
|
84
132
|
} else {
|
|
85
133
|
// calculates the size of the doc, where when there are legacy content macros, the content
|
|
86
134
|
// is stored in the attrs.
|
|
87
|
-
|
|
88
|
-
let customDocSize = tr.doc.nodeSize;
|
|
89
|
-
tr.doc.descendants(node => {
|
|
90
|
-
var _node$attrs5;
|
|
91
|
-
if (((_node$attrs5 = node.attrs) === null || _node$attrs5 === void 0 ? void 0 : _node$attrs5.extensionKey) === 'legacy-content') {
|
|
92
|
-
var _node$attrs$parameter2, _node$attrs6, _node$attrs6$paramete, _node$attrs6$paramete2;
|
|
93
|
-
customDocSize += (_node$attrs$parameter2 = (_node$attrs6 = node.attrs) === null || _node$attrs6 === void 0 ? void 0 : (_node$attrs6$paramete = _node$attrs6.parameters) === null || _node$attrs6$paramete === void 0 ? void 0 : (_node$attrs6$paramete2 = _node$attrs6$paramete.adf) === null || _node$attrs6$paramete2 === void 0 ? void 0 : _node$attrs6$paramete2.length) !== null && _node$attrs$parameter2 !== void 0 ? _node$attrs$parameter2 : 0;
|
|
94
|
-
}
|
|
95
|
-
});
|
|
135
|
+
const customDocSize = getCustomDocSize(tr.doc);
|
|
96
136
|
return {
|
|
97
137
|
documentSizeBreachesThreshold: customDocSize > LIMITED_MODE_NODE_SIZE_THRESHOLD
|
|
98
138
|
};
|
|
@@ -4,36 +4,98 @@ import { expVal } from '@atlaskit/tmp-editor-statsig/expVal';
|
|
|
4
4
|
export var limitedModePluginKey = new PluginKey('limitedModePlugin');
|
|
5
5
|
var LIMITED_MODE_NODE_SIZE_THRESHOLD = 40000;
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* Note: legacy-content macros add a damped contribution based on ADF length to avoid
|
|
10
|
-
* parsing nested ADF on every check, which is inefficient.
|
|
7
|
+
* Gets a numeric experiment param, returning undefined if the value is not a valid number.
|
|
8
|
+
* This guards against test overrides returning booleans or strings for numeric params.
|
|
11
9
|
*/
|
|
12
|
-
var
|
|
13
|
-
var
|
|
10
|
+
var getNumericExperimentParam = function getNumericExperimentParam(paramName, fallbackValue) {
|
|
11
|
+
var rawValue = expVal('cc_editor_limited_mode_expanded', paramName, fallbackValue);
|
|
12
|
+
if (typeof rawValue === 'number') {
|
|
13
|
+
return rawValue;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Handle string values from test overrides
|
|
17
|
+
if (typeof rawValue === 'string') {
|
|
18
|
+
var parsed = parseInt(rawValue, 10);
|
|
19
|
+
if (!isNaN(parsed)) {
|
|
20
|
+
return parsed;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return undefined;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Calculates custom document size including LCM ADF lengths (for non-expanded path).
|
|
28
|
+
* This function can be removed when cc_editor_limited_mode_expanded is cleaned up.
|
|
29
|
+
*/
|
|
30
|
+
var getCustomDocSize = function getCustomDocSize(doc) {
|
|
31
|
+
var lcmAdfLength = 0;
|
|
14
32
|
doc.descendants(function (node) {
|
|
15
33
|
var _node$attrs;
|
|
16
|
-
nodeCount += 1;
|
|
17
34
|
if (((_node$attrs = node.attrs) === null || _node$attrs === void 0 ? void 0 : _node$attrs.extensionKey) === 'legacy-content') {
|
|
18
|
-
var _node$attrs2;
|
|
19
|
-
|
|
20
|
-
if (typeof adfLength === 'number' && lcmDampingFactor > 0) {
|
|
21
|
-
nodeCount += Math.ceil(adfLength / lcmDampingFactor);
|
|
22
|
-
}
|
|
35
|
+
var _node$attrs$parameter, _node$attrs2;
|
|
36
|
+
lcmAdfLength += (_node$attrs$parameter = (_node$attrs2 = node.attrs) === null || _node$attrs2 === void 0 || (_node$attrs2 = _node$attrs2.parameters) === null || _node$attrs2 === void 0 || (_node$attrs2 = _node$attrs2.adf) === null || _node$attrs2 === void 0 ? void 0 : _node$attrs2.length) !== null && _node$attrs$parameter !== void 0 ? _node$attrs$parameter : 0;
|
|
23
37
|
}
|
|
24
38
|
});
|
|
25
|
-
return
|
|
39
|
+
return doc.nodeSize + lcmAdfLength;
|
|
26
40
|
};
|
|
27
41
|
|
|
28
42
|
/**
|
|
29
|
-
*
|
|
43
|
+
* Determines whether limited mode should be enabled under the expanded gate.
|
|
44
|
+
* If this logic changes, update the duplicate in `editor-common/src/node-anchor/node-anchor-provider.ts` to avoid drift.
|
|
45
|
+
*
|
|
46
|
+
* Limited mode is activated when ANY of the following conditions are met:
|
|
47
|
+
* 1. Document size exceeds `docSizeThreshold` (if defined)
|
|
48
|
+
* 2. Node count exceeds `nodeCountThreshold` (if defined)
|
|
49
|
+
* 3. Document contains a legacy-content macro (LCM) (if `includeLcmInThreshold` is true)
|
|
50
|
+
*
|
|
51
|
+
* Performance optimisations:
|
|
52
|
+
* - Doc size is checked first (O(1)) - if it exceeds threshold, we skip traversal entirely.
|
|
53
|
+
* - If `includeLcmInThreshold` is enabled and we find an LCM, we exit traversal early
|
|
54
|
+
* since we already know limited mode will be enabled.
|
|
55
|
+
* - If neither node count nor LCM conditions are configured, we skip traversal entirely.
|
|
30
56
|
*/
|
|
31
|
-
var
|
|
32
|
-
var
|
|
33
|
-
|
|
34
|
-
|
|
57
|
+
var shouldEnableLimitedModeExpanded = function shouldEnableLimitedModeExpanded(doc) {
|
|
58
|
+
var nodeCountThreshold = getNumericExperimentParam('nodeCountThreshold', 5000);
|
|
59
|
+
var docSizeThreshold = getNumericExperimentParam('docSizeThreshold', 30000);
|
|
60
|
+
var includeLcmInThreshold = Boolean(expVal('cc_editor_limited_mode_expanded', 'includeLcmInThreshold', false));
|
|
61
|
+
|
|
62
|
+
// Early exit: doc size exceeds threshold - O(1), no traversal needed
|
|
63
|
+
if (docSizeThreshold !== undefined && doc.nodeSize > docSizeThreshold) {
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Early exit: no traversal needed if neither condition is configured
|
|
68
|
+
var needNodeCount = nodeCountThreshold !== undefined;
|
|
69
|
+
if (!needNodeCount && !includeLcmInThreshold) {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Single traversal for node count and/or LCM detection
|
|
74
|
+
var nodeCount = 0;
|
|
75
|
+
var hasLcm = false;
|
|
76
|
+
doc.descendants(function (node) {
|
|
77
|
+
var _node$attrs3;
|
|
78
|
+
nodeCount += 1;
|
|
79
|
+
if (((_node$attrs3 = node.attrs) === null || _node$attrs3 === void 0 ? void 0 : _node$attrs3.extensionKey) === 'legacy-content') {
|
|
80
|
+
hasLcm = true;
|
|
81
|
+
|
|
82
|
+
// Early exit: LCM found and condition is enabled - no need to continue counting
|
|
83
|
+
if (includeLcmInThreshold) {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
// LCM condition takes precedence (if we early exited traversal, this is why)
|
|
90
|
+
if (includeLcmInThreshold && hasLcm) {
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Check node count threshold
|
|
95
|
+
if (needNodeCount && nodeCount > nodeCountThreshold) {
|
|
96
|
+
return true;
|
|
35
97
|
}
|
|
36
|
-
return
|
|
98
|
+
return false;
|
|
37
99
|
};
|
|
38
100
|
export var createPlugin = function createPlugin() {
|
|
39
101
|
return new SafePlugin({
|
|
@@ -44,24 +106,13 @@ export var createPlugin = function createPlugin() {
|
|
|
44
106
|
state: {
|
|
45
107
|
init: function init(config, editorState) {
|
|
46
108
|
if (expVal('cc_editor_limited_mode_expanded', 'isEnabled', false)) {
|
|
47
|
-
var lcmNodeCountDampingFactor = getNumericExperimentParam('cc_editor_limited_mode_expanded', 'lcmNodeCountDampingFactor', 10);
|
|
48
|
-
var nodeCountThreshold = getNumericExperimentParam('cc_editor_limited_mode_expanded', 'nodeCountThreshold', 1000);
|
|
49
|
-
var nodeCount = countNodesInDoc(editorState.doc, lcmNodeCountDampingFactor);
|
|
50
109
|
return {
|
|
51
|
-
documentSizeBreachesThreshold:
|
|
110
|
+
documentSizeBreachesThreshold: shouldEnableLimitedModeExpanded(editorState.doc)
|
|
52
111
|
};
|
|
53
112
|
} else {
|
|
54
113
|
// calculates the size of the doc, where when there are legacy content macros, the content
|
|
55
114
|
// is stored in the attrs.
|
|
56
|
-
|
|
57
|
-
var customDocSize = editorState.doc.nodeSize;
|
|
58
|
-
editorState.doc.descendants(function (node) {
|
|
59
|
-
var _node$attrs3;
|
|
60
|
-
if (((_node$attrs3 = node.attrs) === null || _node$attrs3 === void 0 ? void 0 : _node$attrs3.extensionKey) === 'legacy-content') {
|
|
61
|
-
var _node$attrs$parameter, _node$attrs4;
|
|
62
|
-
customDocSize += (_node$attrs$parameter = (_node$attrs4 = node.attrs) === null || _node$attrs4 === void 0 || (_node$attrs4 = _node$attrs4.parameters) === null || _node$attrs4 === void 0 || (_node$attrs4 = _node$attrs4.adf) === null || _node$attrs4 === void 0 ? void 0 : _node$attrs4.length) !== null && _node$attrs$parameter !== void 0 ? _node$attrs$parameter : 0;
|
|
63
|
-
}
|
|
64
|
-
});
|
|
115
|
+
var customDocSize = getCustomDocSize(editorState.doc);
|
|
65
116
|
return {
|
|
66
117
|
documentSizeBreachesThreshold: customDocSize > LIMITED_MODE_NODE_SIZE_THRESHOLD
|
|
67
118
|
};
|
|
@@ -75,24 +126,13 @@ export var createPlugin = function createPlugin() {
|
|
|
75
126
|
return currentPluginState;
|
|
76
127
|
}
|
|
77
128
|
if (expVal('cc_editor_limited_mode_expanded', 'isEnabled', false)) {
|
|
78
|
-
var lcmNodeCountDampingFactor = getNumericExperimentParam('cc_editor_limited_mode_expanded', 'lcmNodeCountDampingFactor', 10);
|
|
79
|
-
var nodeCountThreshold = getNumericExperimentParam('cc_editor_limited_mode_expanded', 'nodeCountThreshold', 1000);
|
|
80
|
-
var nodeCount = countNodesInDoc(tr.doc, lcmNodeCountDampingFactor);
|
|
81
129
|
return {
|
|
82
|
-
documentSizeBreachesThreshold:
|
|
130
|
+
documentSizeBreachesThreshold: shouldEnableLimitedModeExpanded(tr.doc)
|
|
83
131
|
};
|
|
84
132
|
} else {
|
|
85
133
|
// calculates the size of the doc, where when there are legacy content macros, the content
|
|
86
134
|
// is stored in the attrs.
|
|
87
|
-
|
|
88
|
-
var customDocSize = tr.doc.nodeSize;
|
|
89
|
-
tr.doc.descendants(function (node) {
|
|
90
|
-
var _node$attrs5;
|
|
91
|
-
if (((_node$attrs5 = node.attrs) === null || _node$attrs5 === void 0 ? void 0 : _node$attrs5.extensionKey) === 'legacy-content') {
|
|
92
|
-
var _node$attrs$parameter2, _node$attrs6;
|
|
93
|
-
customDocSize += (_node$attrs$parameter2 = (_node$attrs6 = node.attrs) === null || _node$attrs6 === void 0 || (_node$attrs6 = _node$attrs6.parameters) === null || _node$attrs6 === void 0 || (_node$attrs6 = _node$attrs6.adf) === null || _node$attrs6 === void 0 ? void 0 : _node$attrs6.length) !== null && _node$attrs$parameter2 !== void 0 ? _node$attrs$parameter2 : 0;
|
|
94
|
-
}
|
|
95
|
-
});
|
|
135
|
+
var customDocSize = getCustomDocSize(tr.doc);
|
|
96
136
|
return {
|
|
97
137
|
documentSizeBreachesThreshold: customDocSize > LIMITED_MODE_NODE_SIZE_THRESHOLD
|
|
98
138
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/editor-plugin-limited-mode",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.6",
|
|
4
4
|
"description": "LimitedMode plugin for @atlaskit/editor-core",
|
|
5
5
|
"author": "Atlassian Pty Ltd",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"@atlaskit/editor-prosemirror": "^7.3.0",
|
|
32
32
|
"@atlaskit/platform-feature-flags": "^1.1.0",
|
|
33
|
-
"@atlaskit/tmp-editor-statsig": "^
|
|
33
|
+
"@atlaskit/tmp-editor-statsig": "^20.0.0",
|
|
34
34
|
"@babel/runtime": "^7.0.0",
|
|
35
35
|
"bind-event-listener": "^3.0.0",
|
|
36
36
|
"react-intl-next": "npm:react-intl@^5.18.1"
|