@atlaskit/editor-plugin-selection-extension 7.1.1 → 7.1.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 +15 -0
- package/dist/cjs/pm-plugins/actions/replaceWithAdf.js +3 -2
- package/dist/cjs/pm-plugins/main.js +1 -2
- package/dist/cjs/pm-plugins/utils/index.js +17 -28
- package/dist/cjs/pm-plugins/utils/selection-helpers.js +168 -0
- package/dist/es2019/pm-plugins/actions/replaceWithAdf.js +3 -2
- package/dist/es2019/pm-plugins/main.js +1 -2
- package/dist/es2019/pm-plugins/utils/index.js +21 -34
- package/dist/es2019/pm-plugins/utils/selection-helpers.js +168 -0
- package/dist/esm/pm-plugins/actions/replaceWithAdf.js +3 -2
- package/dist/esm/pm-plugins/main.js +1 -2
- package/dist/esm/pm-plugins/utils/index.js +17 -28
- package/dist/esm/pm-plugins/utils/selection-helpers.js +162 -0
- package/dist/types/pm-plugins/utils/selection-helpers.d.ts +34 -0
- package/dist/types-ts4.5/pm-plugins/utils/selection-helpers.d.ts +34 -0
- package/package.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# @atlaskit/editor-plugin-selection-extension
|
|
2
2
|
|
|
3
|
+
## 7.1.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`096e1ff839aa4`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/096e1ff839aa4) -
|
|
8
|
+
Clean up `platform_editor_clear_active_extension_fix` feature gate
|
|
9
|
+
- Updated dependencies
|
|
10
|
+
|
|
11
|
+
## 7.1.2
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- [`0b0f96c20a852`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/0b0f96c20a852) -
|
|
16
|
+
Improve getSelectionAdf api to return expanded selection
|
|
17
|
+
|
|
3
18
|
## 7.1.1
|
|
4
19
|
|
|
5
20
|
### Patch Changes
|
|
@@ -5,6 +5,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.replaceWithAdf = void 0;
|
|
7
7
|
var _model = require("@atlaskit/editor-prosemirror/model");
|
|
8
|
+
var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
|
|
8
9
|
var _types = require("../../types");
|
|
9
10
|
var _main = require("../main");
|
|
10
11
|
var replaceWithAdf = exports.replaceWithAdf = function replaceWithAdf(nodeAdf, api) {
|
|
@@ -32,7 +33,7 @@ var replaceWithAdf = exports.replaceWithAdf = function replaceWithAdf(nodeAdf, a
|
|
|
32
33
|
if (!selectedNode || nodePos === undefined) {
|
|
33
34
|
throw new Error('No selected node or node position found');
|
|
34
35
|
}
|
|
35
|
-
var endPos = selectedNode.
|
|
36
|
+
var endPos = selectedNode.type.name === 'doc' && (0, _platformFeatureFlags.fg)('platform_editor_selection_extension_improvement') ? nodePos + selectedNode.content.size : nodePos + selectedNode.nodeSize;
|
|
36
37
|
var modifiedNode = _model.Node.fromJSON(schema, nodeAdf);
|
|
37
38
|
modifiedNode.check();
|
|
38
39
|
var updatedTr = tr.replaceWith(nodePos, endPos, modifiedNode).scrollIntoView();
|
|
@@ -41,7 +42,7 @@ var replaceWithAdf = exports.replaceWithAdf = function replaceWithAdf(nodeAdf, a
|
|
|
41
42
|
return {
|
|
42
43
|
status: 'success'
|
|
43
44
|
};
|
|
44
|
-
} catch (
|
|
45
|
+
} catch (_unused) {
|
|
45
46
|
dispatch(tr);
|
|
46
47
|
return {
|
|
47
48
|
status: 'failed-to-replace'
|
|
@@ -9,7 +9,6 @@ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/de
|
|
|
9
9
|
var _safePlugin = require("@atlaskit/editor-common/safe-plugin");
|
|
10
10
|
var _state = require("@atlaskit/editor-prosemirror/state");
|
|
11
11
|
var _transform = require("@atlaskit/editor-prosemirror/transform");
|
|
12
|
-
var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
|
|
13
12
|
var _types = require("../types");
|
|
14
13
|
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
15
14
|
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
@@ -56,7 +55,7 @@ var createPlugin = exports.createPlugin = function createPlugin() {
|
|
|
56
55
|
});
|
|
57
56
|
}
|
|
58
57
|
// clear activeExtension if the selection has changed and not empty
|
|
59
|
-
if (tr.selectionSet && !tr.selection.empty
|
|
58
|
+
if (tr.selectionSet && !tr.selection.empty) {
|
|
60
59
|
return _objectSpread(_objectSpread({}, pluginState), {}, {
|
|
61
60
|
activeExtension: undefined // Clear active extension on selection change
|
|
62
61
|
});
|
|
@@ -18,6 +18,7 @@ var _editorSharedStyles = require("@atlaskit/editor-shared-styles");
|
|
|
18
18
|
var _editorTables = require("@atlaskit/editor-tables");
|
|
19
19
|
var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
|
|
20
20
|
var _getBoundingBoxFromSelection = require("../../ui/getBoundingBoxFromSelection");
|
|
21
|
+
var _selectionHelpers = require("./selection-helpers");
|
|
21
22
|
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
22
23
|
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
23
24
|
var getSelectedRect = function getSelectedRect(selection) {
|
|
@@ -29,24 +30,6 @@ var getSelectedRect = function getSelectedRect(selection) {
|
|
|
29
30
|
var rect = map.rectBetween($anchorCell.pos - start, $headCell.pos - start);
|
|
30
31
|
return rect;
|
|
31
32
|
};
|
|
32
|
-
var getSelectionInfoFromSameNode = function getSelectionInfoFromSameNode(selection) {
|
|
33
|
-
var $from = selection.$from,
|
|
34
|
-
$to = selection.$to;
|
|
35
|
-
return {
|
|
36
|
-
selectedNode: $from.node(),
|
|
37
|
-
selectionRanges: [{
|
|
38
|
-
start: {
|
|
39
|
-
pointer: "/content/".concat($from.index(), "/text"),
|
|
40
|
-
position: $from.parentOffset
|
|
41
|
-
},
|
|
42
|
-
end: {
|
|
43
|
-
pointer: "/content/".concat($from.index(), "/text"),
|
|
44
|
-
position: $to.parentOffset
|
|
45
|
-
}
|
|
46
|
-
}],
|
|
47
|
-
nodePos: $from.before() // position before the selection
|
|
48
|
-
};
|
|
49
|
-
};
|
|
50
33
|
var getSelectionInfoFromCellSelection = function getSelectionInfoFromCellSelection(selection) {
|
|
51
34
|
var selectedNode = selection.$anchorCell.node(-1);
|
|
52
35
|
var nodePos = selection.$anchorCell.before(-1);
|
|
@@ -117,12 +100,15 @@ function getSelectionAdfInfo(state) {
|
|
|
117
100
|
nodePos: selection.$from.depth > 0 ? selection.$from.before() : selection.from
|
|
118
101
|
};
|
|
119
102
|
if (selection instanceof _state.TextSelection) {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
selectionInfo = getSelectionInfoFromSameNode(selection);
|
|
103
|
+
if ((0, _platformFeatureFlags.fg)('platform_editor_selection_extension_improvement')) {
|
|
104
|
+
// New implementation: unified handler for all text selections
|
|
105
|
+
selectionInfo = (0, _selectionHelpers.getSelectionInfo)(selection, state.schema);
|
|
124
106
|
} else {
|
|
125
|
-
|
|
107
|
+
var $from = selection.$from,
|
|
108
|
+
$to = selection.$to;
|
|
109
|
+
if ($from.parent === $to.parent) {
|
|
110
|
+
selectionInfo = (0, _selectionHelpers.getSelectionInfoFromSameNode)(selection);
|
|
111
|
+
}
|
|
126
112
|
}
|
|
127
113
|
} else if (selection instanceof _editorTables.CellSelection) {
|
|
128
114
|
selectionInfo = getSelectionInfoFromCellSelection(selection);
|
|
@@ -134,17 +120,20 @@ function getSelectionAdfInfo(state) {
|
|
|
134
120
|
});
|
|
135
121
|
}
|
|
136
122
|
function getSelectionAdfInfoNew(selection) {
|
|
123
|
+
var schema = selection.$from.doc.type.schema;
|
|
137
124
|
var selectionInfo = {
|
|
138
125
|
selectedNode: selection.$from.node(),
|
|
139
126
|
nodePos: selection.$from.depth > 0 ? selection.$from.before() : selection.from
|
|
140
127
|
};
|
|
141
128
|
if (selection instanceof _state.TextSelection) {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
if ($from.parent === $to.parent) {
|
|
145
|
-
selectionInfo = getSelectionInfoFromSameNode(selection);
|
|
129
|
+
if ((0, _platformFeatureFlags.fg)('platform_editor_selection_extension_improvement')) {
|
|
130
|
+
selectionInfo = (0, _selectionHelpers.getSelectionInfo)(selection, schema);
|
|
146
131
|
} else {
|
|
147
|
-
|
|
132
|
+
var $from = selection.$from,
|
|
133
|
+
$to = selection.$to;
|
|
134
|
+
if ($from.parent === $to.parent) {
|
|
135
|
+
selectionInfo = (0, _selectionHelpers.getSelectionInfoFromSameNode)(selection);
|
|
136
|
+
}
|
|
148
137
|
}
|
|
149
138
|
} else if (selection instanceof _editorTables.CellSelection) {
|
|
150
139
|
selectionInfo = getSelectionInfoFromCellSelection(selection);
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.wrapNodesInDoc = exports.getSelectionInfoFromSameNode = exports.getSelectionInfo = exports.getCommonParentContainer = void 0;
|
|
7
|
+
var _monitoring = require("@atlaskit/editor-common/monitoring");
|
|
8
|
+
var _model = require("@atlaskit/editor-prosemirror/model");
|
|
9
|
+
var LIST_ITEM_TYPES = new Set(['taskItem', 'decisionItem', 'listItem']);
|
|
10
|
+
var LIST_NODE_TYPES = new Set(['taskList', 'bulletList', 'orderedList', 'decisionList']);
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Find the depth of the deepest common ancestor node.
|
|
14
|
+
*/
|
|
15
|
+
var getCommonAncestorDepth = function getCommonAncestorDepth($from, $to) {
|
|
16
|
+
var minDepth = Math.min($from.depth, $to.depth);
|
|
17
|
+
for (var d = 0; d <= minDepth; d++) {
|
|
18
|
+
if ($from.node(d) !== $to.node(d)) {
|
|
19
|
+
return d - 1;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return minDepth;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Find the closest parent container node that contains the selection.
|
|
27
|
+
* - For lists: returns the topmost list (to handle nested lists)
|
|
28
|
+
* - For other containers returns the closest one
|
|
29
|
+
* Returns the parent and its position.
|
|
30
|
+
*/
|
|
31
|
+
var getCommonParentContainer = exports.getCommonParentContainer = function getCommonParentContainer($from, $to) {
|
|
32
|
+
var commonDepth = getCommonAncestorDepth($from, $to);
|
|
33
|
+
|
|
34
|
+
// Single pass: look for topmost list OR first non-list parent
|
|
35
|
+
var topMostList = null;
|
|
36
|
+
var topMostListPos = -1;
|
|
37
|
+
var firstNonListParent = null;
|
|
38
|
+
var firstNonListParentPos = -1;
|
|
39
|
+
for (var depth = commonDepth; depth > 0; depth--) {
|
|
40
|
+
var node = $from.node(depth);
|
|
41
|
+
if (LIST_NODE_TYPES.has(node.type.name)) {
|
|
42
|
+
// Keep updating to find the topmost list (last one found going upward)
|
|
43
|
+
topMostList = node;
|
|
44
|
+
topMostListPos = $from.before(depth);
|
|
45
|
+
} else if (!firstNonListParent && node.type.name !== 'doc') {
|
|
46
|
+
// Only capture the first (innermost) non-list parent
|
|
47
|
+
firstNonListParent = node;
|
|
48
|
+
firstNonListParentPos = $from.before(depth);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Return topmost list if found, else first non-list parent
|
|
53
|
+
if (topMostList) {
|
|
54
|
+
return {
|
|
55
|
+
node: topMostList,
|
|
56
|
+
pos: topMostListPos
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
node: firstNonListParent,
|
|
61
|
+
pos: firstNonListParentPos
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Wraps nodes in a doc fragment if there are multiple nodes
|
|
67
|
+
*/
|
|
68
|
+
var wrapNodesInDoc = exports.wrapNodesInDoc = function wrapNodesInDoc(schema, nodes) {
|
|
69
|
+
if (nodes.length === 0) {
|
|
70
|
+
return schema.nodes.doc.createChecked({}, _model.Fragment.empty);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Single node: return unwrapped
|
|
74
|
+
if (nodes.length === 1) {
|
|
75
|
+
return nodes[0];
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// For multiple nodes, wrap in doc
|
|
79
|
+
try {
|
|
80
|
+
return schema.node('doc', null, _model.Fragment.from(nodes));
|
|
81
|
+
} catch (error) {
|
|
82
|
+
(0, _monitoring.logException)(error, {
|
|
83
|
+
location: 'editor-plugin-selection-extension'
|
|
84
|
+
});
|
|
85
|
+
return schema.nodes.doc.createChecked({}, _model.Fragment.empty);
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
var getSelectionInfoFromSameNode = exports.getSelectionInfoFromSameNode = function getSelectionInfoFromSameNode(selection) {
|
|
89
|
+
var $from = selection.$from,
|
|
90
|
+
$to = selection.$to;
|
|
91
|
+
return {
|
|
92
|
+
selectedNode: $from.node(),
|
|
93
|
+
selectionRanges: [{
|
|
94
|
+
start: {
|
|
95
|
+
pointer: "/content/".concat($from.index(), "/text"),
|
|
96
|
+
position: $from.parentOffset
|
|
97
|
+
},
|
|
98
|
+
end: {
|
|
99
|
+
pointer: "/content/".concat($from.index(), "/text"),
|
|
100
|
+
position: $to.parentOffset
|
|
101
|
+
}
|
|
102
|
+
}],
|
|
103
|
+
nodePos: $from.before()
|
|
104
|
+
};
|
|
105
|
+
};
|
|
106
|
+
var getSelectionInfo = exports.getSelectionInfo = function getSelectionInfo(selection, schema) {
|
|
107
|
+
var $from = selection.$from,
|
|
108
|
+
$to = selection.$to;
|
|
109
|
+
|
|
110
|
+
// For same parent selections, check for parent container
|
|
111
|
+
if ($from.parent === $to.parent) {
|
|
112
|
+
var _getCommonParentConta = getCommonParentContainer($from, $to),
|
|
113
|
+
parentNode = _getCommonParentConta.node,
|
|
114
|
+
parentNodePos = _getCommonParentConta.pos;
|
|
115
|
+
if (parentNode) {
|
|
116
|
+
return {
|
|
117
|
+
selectedNode: parentNode,
|
|
118
|
+
nodePos: parentNodePos
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
var nodePos = $from.before();
|
|
122
|
+
return {
|
|
123
|
+
selectedNode: $from.node(),
|
|
124
|
+
nodePos: nodePos
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// find the common ancestor
|
|
129
|
+
var range = $from.blockRange($to);
|
|
130
|
+
if (!range) {
|
|
131
|
+
return {
|
|
132
|
+
selectedNode: $from.node(),
|
|
133
|
+
nodePos: $from.depth > 0 ? $from.before() : $from.pos
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
if (range.parent.type.name !== 'doc') {
|
|
137
|
+
// If it's a list OR list item, check for topmost list parent
|
|
138
|
+
if (LIST_NODE_TYPES.has(range.parent.type.name) || LIST_ITEM_TYPES.has(range.parent.type.name)) {
|
|
139
|
+
var _getCommonParentConta2 = getCommonParentContainer($from, $to),
|
|
140
|
+
topList = _getCommonParentConta2.node,
|
|
141
|
+
topListPos = _getCommonParentConta2.pos;
|
|
142
|
+
if (topList) {
|
|
143
|
+
return {
|
|
144
|
+
selectedNode: topList,
|
|
145
|
+
nodePos: topListPos
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// For non-list containers (panel, expand, etc.), return the immediate parent
|
|
151
|
+
var _nodePos = range.depth > 0 ? $from.before(range.depth) : 0;
|
|
152
|
+
return {
|
|
153
|
+
selectedNode: range.parent,
|
|
154
|
+
nodePos: _nodePos
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Extract complete nodes within the block range
|
|
159
|
+
var nodes = [];
|
|
160
|
+
for (var i = range.startIndex; i < range.endIndex; i++) {
|
|
161
|
+
nodes.push(range.parent.child(i));
|
|
162
|
+
}
|
|
163
|
+
var selectedNode = wrapNodesInDoc(schema, nodes);
|
|
164
|
+
return {
|
|
165
|
+
selectedNode: selectedNode,
|
|
166
|
+
nodePos: range.start
|
|
167
|
+
};
|
|
168
|
+
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Node } from '@atlaskit/editor-prosemirror/model';
|
|
2
|
+
import { fg } from '@atlaskit/platform-feature-flags';
|
|
2
3
|
import { SelectionExtensionActionTypes } from '../../types';
|
|
3
4
|
import { selectionExtensionPluginKey } from '../main';
|
|
4
5
|
export const replaceWithAdf = (nodeAdf, api) => (state, dispatch) => {
|
|
@@ -27,7 +28,7 @@ export const replaceWithAdf = (nodeAdf, api) => (state, dispatch) => {
|
|
|
27
28
|
if (!selectedNode || nodePos === undefined) {
|
|
28
29
|
throw new Error('No selected node or node position found');
|
|
29
30
|
}
|
|
30
|
-
const endPos = selectedNode.
|
|
31
|
+
const endPos = selectedNode.type.name === 'doc' && fg('platform_editor_selection_extension_improvement') ? nodePos + selectedNode.content.size : nodePos + selectedNode.nodeSize;
|
|
31
32
|
const modifiedNode = Node.fromJSON(schema, nodeAdf);
|
|
32
33
|
modifiedNode.check();
|
|
33
34
|
const updatedTr = tr.replaceWith(nodePos, endPos, modifiedNode).scrollIntoView();
|
|
@@ -36,7 +37,7 @@ export const replaceWithAdf = (nodeAdf, api) => (state, dispatch) => {
|
|
|
36
37
|
return {
|
|
37
38
|
status: 'success'
|
|
38
39
|
};
|
|
39
|
-
} catch
|
|
40
|
+
} catch {
|
|
40
41
|
dispatch(tr);
|
|
41
42
|
return {
|
|
42
43
|
status: 'failed-to-replace'
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
|
|
2
2
|
import { PluginKey } from '@atlaskit/editor-prosemirror/state';
|
|
3
3
|
import { ReplaceAroundStep, ReplaceStep } from '@atlaskit/editor-prosemirror/transform';
|
|
4
|
-
import { fg } from '@atlaskit/platform-feature-flags';
|
|
5
4
|
import { SelectionExtensionActionTypes } from '../types';
|
|
6
5
|
export const selectionExtensionPluginKey = new PluginKey('selectionExtensionPlugin');
|
|
7
6
|
export const createPlugin = () => {
|
|
@@ -49,7 +48,7 @@ export const createPlugin = () => {
|
|
|
49
48
|
};
|
|
50
49
|
}
|
|
51
50
|
// clear activeExtension if the selection has changed and not empty
|
|
52
|
-
if (tr.selectionSet && !tr.selection.empty
|
|
51
|
+
if (tr.selectionSet && !tr.selection.empty) {
|
|
53
52
|
return {
|
|
54
53
|
...pluginState,
|
|
55
54
|
activeExtension: undefined // Clear active extension on selection change
|
|
@@ -7,6 +7,7 @@ import { akEditorFullPageToolbarHeight } from '@atlaskit/editor-shared-styles';
|
|
|
7
7
|
import { CellSelection, TableMap } from '@atlaskit/editor-tables';
|
|
8
8
|
import { fg } from '@atlaskit/platform-feature-flags';
|
|
9
9
|
import { getBoundingBoxFromSelection } from '../../ui/getBoundingBoxFromSelection';
|
|
10
|
+
import { getSelectionInfo, getSelectionInfoFromSameNode } from './selection-helpers';
|
|
10
11
|
const getSelectedRect = selection => {
|
|
11
12
|
const {
|
|
12
13
|
$anchorCell,
|
|
@@ -18,26 +19,6 @@ const getSelectedRect = selection => {
|
|
|
18
19
|
const rect = map.rectBetween($anchorCell.pos - start, $headCell.pos - start);
|
|
19
20
|
return rect;
|
|
20
21
|
};
|
|
21
|
-
const getSelectionInfoFromSameNode = selection => {
|
|
22
|
-
const {
|
|
23
|
-
$from,
|
|
24
|
-
$to
|
|
25
|
-
} = selection;
|
|
26
|
-
return {
|
|
27
|
-
selectedNode: $from.node(),
|
|
28
|
-
selectionRanges: [{
|
|
29
|
-
start: {
|
|
30
|
-
pointer: `/content/${$from.index()}/text`,
|
|
31
|
-
position: $from.parentOffset
|
|
32
|
-
},
|
|
33
|
-
end: {
|
|
34
|
-
pointer: `/content/${$from.index()}/text`,
|
|
35
|
-
position: $to.parentOffset
|
|
36
|
-
}
|
|
37
|
-
}],
|
|
38
|
-
nodePos: $from.before() // position before the selection
|
|
39
|
-
};
|
|
40
|
-
};
|
|
41
22
|
const getSelectionInfoFromCellSelection = selection => {
|
|
42
23
|
const selectedNode = selection.$anchorCell.node(-1);
|
|
43
24
|
const nodePos = selection.$anchorCell.before(-1);
|
|
@@ -116,14 +97,17 @@ export function getSelectionAdfInfo(state) {
|
|
|
116
97
|
nodePos: selection.$from.depth > 0 ? selection.$from.before() : selection.from
|
|
117
98
|
};
|
|
118
99
|
if (selection instanceof TextSelection) {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
} = selection;
|
|
123
|
-
if ($from.parent === $to.parent) {
|
|
124
|
-
selectionInfo = getSelectionInfoFromSameNode(selection);
|
|
100
|
+
if (fg('platform_editor_selection_extension_improvement')) {
|
|
101
|
+
// New implementation: unified handler for all text selections
|
|
102
|
+
selectionInfo = getSelectionInfo(selection, state.schema);
|
|
125
103
|
} else {
|
|
126
|
-
|
|
104
|
+
const {
|
|
105
|
+
$from,
|
|
106
|
+
$to
|
|
107
|
+
} = selection;
|
|
108
|
+
if ($from.parent === $to.parent) {
|
|
109
|
+
selectionInfo = getSelectionInfoFromSameNode(selection);
|
|
110
|
+
}
|
|
127
111
|
}
|
|
128
112
|
} else if (selection instanceof CellSelection) {
|
|
129
113
|
selectionInfo = getSelectionInfoFromCellSelection(selection);
|
|
@@ -136,19 +120,22 @@ export function getSelectionAdfInfo(state) {
|
|
|
136
120
|
};
|
|
137
121
|
}
|
|
138
122
|
export function getSelectionAdfInfoNew(selection) {
|
|
123
|
+
const schema = selection.$from.doc.type.schema;
|
|
139
124
|
let selectionInfo = {
|
|
140
125
|
selectedNode: selection.$from.node(),
|
|
141
126
|
nodePos: selection.$from.depth > 0 ? selection.$from.before() : selection.from
|
|
142
127
|
};
|
|
143
128
|
if (selection instanceof TextSelection) {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
$to
|
|
147
|
-
} = selection;
|
|
148
|
-
if ($from.parent === $to.parent) {
|
|
149
|
-
selectionInfo = getSelectionInfoFromSameNode(selection);
|
|
129
|
+
if (fg('platform_editor_selection_extension_improvement')) {
|
|
130
|
+
selectionInfo = getSelectionInfo(selection, schema);
|
|
150
131
|
} else {
|
|
151
|
-
|
|
132
|
+
const {
|
|
133
|
+
$from,
|
|
134
|
+
$to
|
|
135
|
+
} = selection;
|
|
136
|
+
if ($from.parent === $to.parent) {
|
|
137
|
+
selectionInfo = getSelectionInfoFromSameNode(selection);
|
|
138
|
+
}
|
|
152
139
|
}
|
|
153
140
|
} else if (selection instanceof CellSelection) {
|
|
154
141
|
selectionInfo = getSelectionInfoFromCellSelection(selection);
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { logException } from '@atlaskit/editor-common/monitoring';
|
|
2
|
+
import { Fragment } from '@atlaskit/editor-prosemirror/model';
|
|
3
|
+
const LIST_ITEM_TYPES = new Set(['taskItem', 'decisionItem', 'listItem']);
|
|
4
|
+
const LIST_NODE_TYPES = new Set(['taskList', 'bulletList', 'orderedList', 'decisionList']);
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Find the depth of the deepest common ancestor node.
|
|
8
|
+
*/
|
|
9
|
+
const getCommonAncestorDepth = ($from, $to) => {
|
|
10
|
+
const minDepth = Math.min($from.depth, $to.depth);
|
|
11
|
+
for (let d = 0; d <= minDepth; d++) {
|
|
12
|
+
if ($from.node(d) !== $to.node(d)) {
|
|
13
|
+
return d - 1;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return minDepth;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Find the closest parent container node that contains the selection.
|
|
21
|
+
* - For lists: returns the topmost list (to handle nested lists)
|
|
22
|
+
* - For other containers returns the closest one
|
|
23
|
+
* Returns the parent and its position.
|
|
24
|
+
*/
|
|
25
|
+
export const getCommonParentContainer = ($from, $to) => {
|
|
26
|
+
const commonDepth = getCommonAncestorDepth($from, $to);
|
|
27
|
+
|
|
28
|
+
// Single pass: look for topmost list OR first non-list parent
|
|
29
|
+
let topMostList = null;
|
|
30
|
+
let topMostListPos = -1;
|
|
31
|
+
let firstNonListParent = null;
|
|
32
|
+
let firstNonListParentPos = -1;
|
|
33
|
+
for (let depth = commonDepth; depth > 0; depth--) {
|
|
34
|
+
const node = $from.node(depth);
|
|
35
|
+
if (LIST_NODE_TYPES.has(node.type.name)) {
|
|
36
|
+
// Keep updating to find the topmost list (last one found going upward)
|
|
37
|
+
topMostList = node;
|
|
38
|
+
topMostListPos = $from.before(depth);
|
|
39
|
+
} else if (!firstNonListParent && node.type.name !== 'doc') {
|
|
40
|
+
// Only capture the first (innermost) non-list parent
|
|
41
|
+
firstNonListParent = node;
|
|
42
|
+
firstNonListParentPos = $from.before(depth);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Return topmost list if found, else first non-list parent
|
|
47
|
+
if (topMostList) {
|
|
48
|
+
return {
|
|
49
|
+
node: topMostList,
|
|
50
|
+
pos: topMostListPos
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
node: firstNonListParent,
|
|
55
|
+
pos: firstNonListParentPos
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Wraps nodes in a doc fragment if there are multiple nodes
|
|
61
|
+
*/
|
|
62
|
+
export const wrapNodesInDoc = (schema, nodes) => {
|
|
63
|
+
if (nodes.length === 0) {
|
|
64
|
+
return schema.nodes.doc.createChecked({}, Fragment.empty);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Single node: return unwrapped
|
|
68
|
+
if (nodes.length === 1) {
|
|
69
|
+
return nodes[0];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// For multiple nodes, wrap in doc
|
|
73
|
+
try {
|
|
74
|
+
return schema.node('doc', null, Fragment.from(nodes));
|
|
75
|
+
} catch (error) {
|
|
76
|
+
logException(error, {
|
|
77
|
+
location: 'editor-plugin-selection-extension'
|
|
78
|
+
});
|
|
79
|
+
return schema.nodes.doc.createChecked({}, Fragment.empty);
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
export const getSelectionInfoFromSameNode = selection => {
|
|
83
|
+
const {
|
|
84
|
+
$from,
|
|
85
|
+
$to
|
|
86
|
+
} = selection;
|
|
87
|
+
return {
|
|
88
|
+
selectedNode: $from.node(),
|
|
89
|
+
selectionRanges: [{
|
|
90
|
+
start: {
|
|
91
|
+
pointer: `/content/${$from.index()}/text`,
|
|
92
|
+
position: $from.parentOffset
|
|
93
|
+
},
|
|
94
|
+
end: {
|
|
95
|
+
pointer: `/content/${$from.index()}/text`,
|
|
96
|
+
position: $to.parentOffset
|
|
97
|
+
}
|
|
98
|
+
}],
|
|
99
|
+
nodePos: $from.before()
|
|
100
|
+
};
|
|
101
|
+
};
|
|
102
|
+
export const getSelectionInfo = (selection, schema) => {
|
|
103
|
+
const {
|
|
104
|
+
$from,
|
|
105
|
+
$to
|
|
106
|
+
} = selection;
|
|
107
|
+
|
|
108
|
+
// For same parent selections, check for parent container
|
|
109
|
+
if ($from.parent === $to.parent) {
|
|
110
|
+
const {
|
|
111
|
+
node: parentNode,
|
|
112
|
+
pos: parentNodePos
|
|
113
|
+
} = getCommonParentContainer($from, $to);
|
|
114
|
+
if (parentNode) {
|
|
115
|
+
return {
|
|
116
|
+
selectedNode: parentNode,
|
|
117
|
+
nodePos: parentNodePos
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
const nodePos = $from.before();
|
|
121
|
+
return {
|
|
122
|
+
selectedNode: $from.node(),
|
|
123
|
+
nodePos
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// find the common ancestor
|
|
128
|
+
const range = $from.blockRange($to);
|
|
129
|
+
if (!range) {
|
|
130
|
+
return {
|
|
131
|
+
selectedNode: $from.node(),
|
|
132
|
+
nodePos: $from.depth > 0 ? $from.before() : $from.pos
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
if (range.parent.type.name !== 'doc') {
|
|
136
|
+
// If it's a list OR list item, check for topmost list parent
|
|
137
|
+
if (LIST_NODE_TYPES.has(range.parent.type.name) || LIST_ITEM_TYPES.has(range.parent.type.name)) {
|
|
138
|
+
const {
|
|
139
|
+
node: topList,
|
|
140
|
+
pos: topListPos
|
|
141
|
+
} = getCommonParentContainer($from, $to);
|
|
142
|
+
if (topList) {
|
|
143
|
+
return {
|
|
144
|
+
selectedNode: topList,
|
|
145
|
+
nodePos: topListPos
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// For non-list containers (panel, expand, etc.), return the immediate parent
|
|
151
|
+
const nodePos = range.depth > 0 ? $from.before(range.depth) : 0;
|
|
152
|
+
return {
|
|
153
|
+
selectedNode: range.parent,
|
|
154
|
+
nodePos
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Extract complete nodes within the block range
|
|
159
|
+
const nodes = [];
|
|
160
|
+
for (let i = range.startIndex; i < range.endIndex; i++) {
|
|
161
|
+
nodes.push(range.parent.child(i));
|
|
162
|
+
}
|
|
163
|
+
const selectedNode = wrapNodesInDoc(schema, nodes);
|
|
164
|
+
return {
|
|
165
|
+
selectedNode,
|
|
166
|
+
nodePos: range.start
|
|
167
|
+
};
|
|
168
|
+
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Node } from '@atlaskit/editor-prosemirror/model';
|
|
2
|
+
import { fg } from '@atlaskit/platform-feature-flags';
|
|
2
3
|
import { SelectionExtensionActionTypes } from '../../types';
|
|
3
4
|
import { selectionExtensionPluginKey } from '../main';
|
|
4
5
|
export var replaceWithAdf = function replaceWithAdf(nodeAdf, api) {
|
|
@@ -26,7 +27,7 @@ export var replaceWithAdf = function replaceWithAdf(nodeAdf, api) {
|
|
|
26
27
|
if (!selectedNode || nodePos === undefined) {
|
|
27
28
|
throw new Error('No selected node or node position found');
|
|
28
29
|
}
|
|
29
|
-
var endPos = selectedNode.
|
|
30
|
+
var endPos = selectedNode.type.name === 'doc' && fg('platform_editor_selection_extension_improvement') ? nodePos + selectedNode.content.size : nodePos + selectedNode.nodeSize;
|
|
30
31
|
var modifiedNode = Node.fromJSON(schema, nodeAdf);
|
|
31
32
|
modifiedNode.check();
|
|
32
33
|
var updatedTr = tr.replaceWith(nodePos, endPos, modifiedNode).scrollIntoView();
|
|
@@ -35,7 +36,7 @@ export var replaceWithAdf = function replaceWithAdf(nodeAdf, api) {
|
|
|
35
36
|
return {
|
|
36
37
|
status: 'success'
|
|
37
38
|
};
|
|
38
|
-
} catch (
|
|
39
|
+
} catch (_unused) {
|
|
39
40
|
dispatch(tr);
|
|
40
41
|
return {
|
|
41
42
|
status: 'failed-to-replace'
|
|
@@ -4,7 +4,6 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
|
|
|
4
4
|
import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
|
|
5
5
|
import { PluginKey } from '@atlaskit/editor-prosemirror/state';
|
|
6
6
|
import { ReplaceAroundStep, ReplaceStep } from '@atlaskit/editor-prosemirror/transform';
|
|
7
|
-
import { fg } from '@atlaskit/platform-feature-flags';
|
|
8
7
|
import { SelectionExtensionActionTypes } from '../types';
|
|
9
8
|
export var selectionExtensionPluginKey = new PluginKey('selectionExtensionPlugin');
|
|
10
9
|
export var createPlugin = function createPlugin() {
|
|
@@ -49,7 +48,7 @@ export var createPlugin = function createPlugin() {
|
|
|
49
48
|
});
|
|
50
49
|
}
|
|
51
50
|
// clear activeExtension if the selection has changed and not empty
|
|
52
|
-
if (tr.selectionSet && !tr.selection.empty
|
|
51
|
+
if (tr.selectionSet && !tr.selection.empty) {
|
|
53
52
|
return _objectSpread(_objectSpread({}, pluginState), {}, {
|
|
54
53
|
activeExtension: undefined // Clear active extension on selection change
|
|
55
54
|
});
|
|
@@ -10,6 +10,7 @@ import { akEditorFullPageToolbarHeight } from '@atlaskit/editor-shared-styles';
|
|
|
10
10
|
import { CellSelection, TableMap } from '@atlaskit/editor-tables';
|
|
11
11
|
import { fg } from '@atlaskit/platform-feature-flags';
|
|
12
12
|
import { getBoundingBoxFromSelection } from '../../ui/getBoundingBoxFromSelection';
|
|
13
|
+
import { getSelectionInfo, getSelectionInfoFromSameNode } from './selection-helpers';
|
|
13
14
|
var getSelectedRect = function getSelectedRect(selection) {
|
|
14
15
|
var $anchorCell = selection.$anchorCell,
|
|
15
16
|
$headCell = selection.$headCell;
|
|
@@ -19,24 +20,6 @@ var getSelectedRect = function getSelectedRect(selection) {
|
|
|
19
20
|
var rect = map.rectBetween($anchorCell.pos - start, $headCell.pos - start);
|
|
20
21
|
return rect;
|
|
21
22
|
};
|
|
22
|
-
var getSelectionInfoFromSameNode = function getSelectionInfoFromSameNode(selection) {
|
|
23
|
-
var $from = selection.$from,
|
|
24
|
-
$to = selection.$to;
|
|
25
|
-
return {
|
|
26
|
-
selectedNode: $from.node(),
|
|
27
|
-
selectionRanges: [{
|
|
28
|
-
start: {
|
|
29
|
-
pointer: "/content/".concat($from.index(), "/text"),
|
|
30
|
-
position: $from.parentOffset
|
|
31
|
-
},
|
|
32
|
-
end: {
|
|
33
|
-
pointer: "/content/".concat($from.index(), "/text"),
|
|
34
|
-
position: $to.parentOffset
|
|
35
|
-
}
|
|
36
|
-
}],
|
|
37
|
-
nodePos: $from.before() // position before the selection
|
|
38
|
-
};
|
|
39
|
-
};
|
|
40
23
|
var getSelectionInfoFromCellSelection = function getSelectionInfoFromCellSelection(selection) {
|
|
41
24
|
var selectedNode = selection.$anchorCell.node(-1);
|
|
42
25
|
var nodePos = selection.$anchorCell.before(-1);
|
|
@@ -107,12 +90,15 @@ export function getSelectionAdfInfo(state) {
|
|
|
107
90
|
nodePos: selection.$from.depth > 0 ? selection.$from.before() : selection.from
|
|
108
91
|
};
|
|
109
92
|
if (selection instanceof TextSelection) {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
selectionInfo = getSelectionInfoFromSameNode(selection);
|
|
93
|
+
if (fg('platform_editor_selection_extension_improvement')) {
|
|
94
|
+
// New implementation: unified handler for all text selections
|
|
95
|
+
selectionInfo = getSelectionInfo(selection, state.schema);
|
|
114
96
|
} else {
|
|
115
|
-
|
|
97
|
+
var $from = selection.$from,
|
|
98
|
+
$to = selection.$to;
|
|
99
|
+
if ($from.parent === $to.parent) {
|
|
100
|
+
selectionInfo = getSelectionInfoFromSameNode(selection);
|
|
101
|
+
}
|
|
116
102
|
}
|
|
117
103
|
} else if (selection instanceof CellSelection) {
|
|
118
104
|
selectionInfo = getSelectionInfoFromCellSelection(selection);
|
|
@@ -124,17 +110,20 @@ export function getSelectionAdfInfo(state) {
|
|
|
124
110
|
});
|
|
125
111
|
}
|
|
126
112
|
export function getSelectionAdfInfoNew(selection) {
|
|
113
|
+
var schema = selection.$from.doc.type.schema;
|
|
127
114
|
var selectionInfo = {
|
|
128
115
|
selectedNode: selection.$from.node(),
|
|
129
116
|
nodePos: selection.$from.depth > 0 ? selection.$from.before() : selection.from
|
|
130
117
|
};
|
|
131
118
|
if (selection instanceof TextSelection) {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
if ($from.parent === $to.parent) {
|
|
135
|
-
selectionInfo = getSelectionInfoFromSameNode(selection);
|
|
119
|
+
if (fg('platform_editor_selection_extension_improvement')) {
|
|
120
|
+
selectionInfo = getSelectionInfo(selection, schema);
|
|
136
121
|
} else {
|
|
137
|
-
|
|
122
|
+
var $from = selection.$from,
|
|
123
|
+
$to = selection.$to;
|
|
124
|
+
if ($from.parent === $to.parent) {
|
|
125
|
+
selectionInfo = getSelectionInfoFromSameNode(selection);
|
|
126
|
+
}
|
|
138
127
|
}
|
|
139
128
|
} else if (selection instanceof CellSelection) {
|
|
140
129
|
selectionInfo = getSelectionInfoFromCellSelection(selection);
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { logException } from '@atlaskit/editor-common/monitoring';
|
|
2
|
+
import { Fragment } from '@atlaskit/editor-prosemirror/model';
|
|
3
|
+
var LIST_ITEM_TYPES = new Set(['taskItem', 'decisionItem', 'listItem']);
|
|
4
|
+
var LIST_NODE_TYPES = new Set(['taskList', 'bulletList', 'orderedList', 'decisionList']);
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Find the depth of the deepest common ancestor node.
|
|
8
|
+
*/
|
|
9
|
+
var getCommonAncestorDepth = function getCommonAncestorDepth($from, $to) {
|
|
10
|
+
var minDepth = Math.min($from.depth, $to.depth);
|
|
11
|
+
for (var d = 0; d <= minDepth; d++) {
|
|
12
|
+
if ($from.node(d) !== $to.node(d)) {
|
|
13
|
+
return d - 1;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return minDepth;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Find the closest parent container node that contains the selection.
|
|
21
|
+
* - For lists: returns the topmost list (to handle nested lists)
|
|
22
|
+
* - For other containers returns the closest one
|
|
23
|
+
* Returns the parent and its position.
|
|
24
|
+
*/
|
|
25
|
+
export var getCommonParentContainer = function getCommonParentContainer($from, $to) {
|
|
26
|
+
var commonDepth = getCommonAncestorDepth($from, $to);
|
|
27
|
+
|
|
28
|
+
// Single pass: look for topmost list OR first non-list parent
|
|
29
|
+
var topMostList = null;
|
|
30
|
+
var topMostListPos = -1;
|
|
31
|
+
var firstNonListParent = null;
|
|
32
|
+
var firstNonListParentPos = -1;
|
|
33
|
+
for (var depth = commonDepth; depth > 0; depth--) {
|
|
34
|
+
var node = $from.node(depth);
|
|
35
|
+
if (LIST_NODE_TYPES.has(node.type.name)) {
|
|
36
|
+
// Keep updating to find the topmost list (last one found going upward)
|
|
37
|
+
topMostList = node;
|
|
38
|
+
topMostListPos = $from.before(depth);
|
|
39
|
+
} else if (!firstNonListParent && node.type.name !== 'doc') {
|
|
40
|
+
// Only capture the first (innermost) non-list parent
|
|
41
|
+
firstNonListParent = node;
|
|
42
|
+
firstNonListParentPos = $from.before(depth);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Return topmost list if found, else first non-list parent
|
|
47
|
+
if (topMostList) {
|
|
48
|
+
return {
|
|
49
|
+
node: topMostList,
|
|
50
|
+
pos: topMostListPos
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
node: firstNonListParent,
|
|
55
|
+
pos: firstNonListParentPos
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Wraps nodes in a doc fragment if there are multiple nodes
|
|
61
|
+
*/
|
|
62
|
+
export var wrapNodesInDoc = function wrapNodesInDoc(schema, nodes) {
|
|
63
|
+
if (nodes.length === 0) {
|
|
64
|
+
return schema.nodes.doc.createChecked({}, Fragment.empty);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Single node: return unwrapped
|
|
68
|
+
if (nodes.length === 1) {
|
|
69
|
+
return nodes[0];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// For multiple nodes, wrap in doc
|
|
73
|
+
try {
|
|
74
|
+
return schema.node('doc', null, Fragment.from(nodes));
|
|
75
|
+
} catch (error) {
|
|
76
|
+
logException(error, {
|
|
77
|
+
location: 'editor-plugin-selection-extension'
|
|
78
|
+
});
|
|
79
|
+
return schema.nodes.doc.createChecked({}, Fragment.empty);
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
export var getSelectionInfoFromSameNode = function getSelectionInfoFromSameNode(selection) {
|
|
83
|
+
var $from = selection.$from,
|
|
84
|
+
$to = selection.$to;
|
|
85
|
+
return {
|
|
86
|
+
selectedNode: $from.node(),
|
|
87
|
+
selectionRanges: [{
|
|
88
|
+
start: {
|
|
89
|
+
pointer: "/content/".concat($from.index(), "/text"),
|
|
90
|
+
position: $from.parentOffset
|
|
91
|
+
},
|
|
92
|
+
end: {
|
|
93
|
+
pointer: "/content/".concat($from.index(), "/text"),
|
|
94
|
+
position: $to.parentOffset
|
|
95
|
+
}
|
|
96
|
+
}],
|
|
97
|
+
nodePos: $from.before()
|
|
98
|
+
};
|
|
99
|
+
};
|
|
100
|
+
export var getSelectionInfo = function getSelectionInfo(selection, schema) {
|
|
101
|
+
var $from = selection.$from,
|
|
102
|
+
$to = selection.$to;
|
|
103
|
+
|
|
104
|
+
// For same parent selections, check for parent container
|
|
105
|
+
if ($from.parent === $to.parent) {
|
|
106
|
+
var _getCommonParentConta = getCommonParentContainer($from, $to),
|
|
107
|
+
parentNode = _getCommonParentConta.node,
|
|
108
|
+
parentNodePos = _getCommonParentConta.pos;
|
|
109
|
+
if (parentNode) {
|
|
110
|
+
return {
|
|
111
|
+
selectedNode: parentNode,
|
|
112
|
+
nodePos: parentNodePos
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
var nodePos = $from.before();
|
|
116
|
+
return {
|
|
117
|
+
selectedNode: $from.node(),
|
|
118
|
+
nodePos: nodePos
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// find the common ancestor
|
|
123
|
+
var range = $from.blockRange($to);
|
|
124
|
+
if (!range) {
|
|
125
|
+
return {
|
|
126
|
+
selectedNode: $from.node(),
|
|
127
|
+
nodePos: $from.depth > 0 ? $from.before() : $from.pos
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
if (range.parent.type.name !== 'doc') {
|
|
131
|
+
// If it's a list OR list item, check for topmost list parent
|
|
132
|
+
if (LIST_NODE_TYPES.has(range.parent.type.name) || LIST_ITEM_TYPES.has(range.parent.type.name)) {
|
|
133
|
+
var _getCommonParentConta2 = getCommonParentContainer($from, $to),
|
|
134
|
+
topList = _getCommonParentConta2.node,
|
|
135
|
+
topListPos = _getCommonParentConta2.pos;
|
|
136
|
+
if (topList) {
|
|
137
|
+
return {
|
|
138
|
+
selectedNode: topList,
|
|
139
|
+
nodePos: topListPos
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// For non-list containers (panel, expand, etc.), return the immediate parent
|
|
145
|
+
var _nodePos = range.depth > 0 ? $from.before(range.depth) : 0;
|
|
146
|
+
return {
|
|
147
|
+
selectedNode: range.parent,
|
|
148
|
+
nodePos: _nodePos
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Extract complete nodes within the block range
|
|
153
|
+
var nodes = [];
|
|
154
|
+
for (var i = range.startIndex; i < range.endIndex; i++) {
|
|
155
|
+
nodes.push(range.parent.child(i));
|
|
156
|
+
}
|
|
157
|
+
var selectedNode = wrapNodesInDoc(schema, nodes);
|
|
158
|
+
return {
|
|
159
|
+
selectedNode: selectedNode,
|
|
160
|
+
nodePos: range.start
|
|
161
|
+
};
|
|
162
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { type Node as PMNode, type ResolvedPos, type Schema } from '@atlaskit/editor-prosemirror/model';
|
|
2
|
+
import type { TextSelection } from '@atlaskit/editor-prosemirror/state';
|
|
3
|
+
/**
|
|
4
|
+
* Find the closest parent container node that contains the selection.
|
|
5
|
+
* - For lists: returns the topmost list (to handle nested lists)
|
|
6
|
+
* - For other containers returns the closest one
|
|
7
|
+
* Returns the parent and its position.
|
|
8
|
+
*/
|
|
9
|
+
export declare const getCommonParentContainer: ($from: ResolvedPos, $to: ResolvedPos) => {
|
|
10
|
+
node: PMNode | null;
|
|
11
|
+
pos: number;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Wraps nodes in a doc fragment if there are multiple nodes
|
|
15
|
+
*/
|
|
16
|
+
export declare const wrapNodesInDoc: (schema: Schema, nodes: PMNode[]) => PMNode;
|
|
17
|
+
export declare const getSelectionInfoFromSameNode: (selection: TextSelection) => {
|
|
18
|
+
selectedNode: PMNode;
|
|
19
|
+
selectionRanges: {
|
|
20
|
+
start: {
|
|
21
|
+
pointer: string;
|
|
22
|
+
position: number;
|
|
23
|
+
};
|
|
24
|
+
end: {
|
|
25
|
+
pointer: string;
|
|
26
|
+
position: number;
|
|
27
|
+
};
|
|
28
|
+
}[];
|
|
29
|
+
nodePos: number;
|
|
30
|
+
};
|
|
31
|
+
export declare const getSelectionInfo: (selection: TextSelection, schema: Schema) => {
|
|
32
|
+
selectedNode: PMNode;
|
|
33
|
+
nodePos: number;
|
|
34
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { type Node as PMNode, type ResolvedPos, type Schema } from '@atlaskit/editor-prosemirror/model';
|
|
2
|
+
import type { TextSelection } from '@atlaskit/editor-prosemirror/state';
|
|
3
|
+
/**
|
|
4
|
+
* Find the closest parent container node that contains the selection.
|
|
5
|
+
* - For lists: returns the topmost list (to handle nested lists)
|
|
6
|
+
* - For other containers returns the closest one
|
|
7
|
+
* Returns the parent and its position.
|
|
8
|
+
*/
|
|
9
|
+
export declare const getCommonParentContainer: ($from: ResolvedPos, $to: ResolvedPos) => {
|
|
10
|
+
node: PMNode | null;
|
|
11
|
+
pos: number;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Wraps nodes in a doc fragment if there are multiple nodes
|
|
15
|
+
*/
|
|
16
|
+
export declare const wrapNodesInDoc: (schema: Schema, nodes: PMNode[]) => PMNode;
|
|
17
|
+
export declare const getSelectionInfoFromSameNode: (selection: TextSelection) => {
|
|
18
|
+
selectedNode: PMNode;
|
|
19
|
+
selectionRanges: {
|
|
20
|
+
start: {
|
|
21
|
+
pointer: string;
|
|
22
|
+
position: number;
|
|
23
|
+
};
|
|
24
|
+
end: {
|
|
25
|
+
pointer: string;
|
|
26
|
+
position: number;
|
|
27
|
+
};
|
|
28
|
+
}[];
|
|
29
|
+
nodePos: number;
|
|
30
|
+
};
|
|
31
|
+
export declare const getSelectionInfo: (selection: TextSelection, schema: Schema) => {
|
|
32
|
+
selectedNode: PMNode;
|
|
33
|
+
nodePos: number;
|
|
34
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/editor-plugin-selection-extension",
|
|
3
|
-
"version": "7.1.
|
|
3
|
+
"version": "7.1.3",
|
|
4
4
|
"description": "editor-plugin-selection-extension plugin for @atlaskit/editor-core",
|
|
5
5
|
"author": "Atlassian Pty Ltd",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"@atlaskit/adf-utils": "^19.26.0",
|
|
36
36
|
"@atlaskit/editor-json-transformer": "^8.31.0",
|
|
37
37
|
"@atlaskit/editor-plugin-analytics": "^6.2.0",
|
|
38
|
-
"@atlaskit/editor-plugin-block-menu": "^5.
|
|
38
|
+
"@atlaskit/editor-plugin-block-menu": "^5.1.0",
|
|
39
39
|
"@atlaskit/editor-plugin-editor-viewmode": "^8.0.0",
|
|
40
40
|
"@atlaskit/editor-plugin-editor-viewmode-effects": "^6.1.0",
|
|
41
41
|
"@atlaskit/editor-plugin-primary-toolbar": "^7.0.0",
|
|
@@ -49,14 +49,14 @@
|
|
|
49
49
|
"@atlaskit/icon": "^29.0.0",
|
|
50
50
|
"@atlaskit/platform-feature-flags": "^1.1.0",
|
|
51
51
|
"@atlaskit/platform-feature-flags-react": "^0.4.0",
|
|
52
|
-
"@atlaskit/tmp-editor-statsig": "^14.
|
|
52
|
+
"@atlaskit/tmp-editor-statsig": "^14.5.0",
|
|
53
53
|
"@babel/runtime": "^7.0.0",
|
|
54
54
|
"lodash": "^4.17.21",
|
|
55
55
|
"react-intl-next": "npm:react-intl@^5.18.1",
|
|
56
56
|
"uuid": "^3.1.0"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
|
-
"@atlaskit/editor-common": "^110.
|
|
59
|
+
"@atlaskit/editor-common": "^110.38.0",
|
|
60
60
|
"react": "^18.2.0"
|
|
61
61
|
},
|
|
62
62
|
"devDependencies": {
|
|
@@ -103,10 +103,10 @@
|
|
|
103
103
|
}
|
|
104
104
|
},
|
|
105
105
|
"platform-feature-flags": {
|
|
106
|
-
"
|
|
106
|
+
"platform_editor_use_preferences_plugin": {
|
|
107
107
|
"type": "boolean"
|
|
108
108
|
},
|
|
109
|
-
"
|
|
109
|
+
"platform_editor_selection_extension_improvement": {
|
|
110
110
|
"type": "boolean"
|
|
111
111
|
}
|
|
112
112
|
}
|