@atlaskit/editor-plugin-selection-extension 3.0.1 → 3.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/dist/cjs/pm-plugins/actions.js +93 -0
- package/dist/cjs/pm-plugins/main.js +21 -0
- package/dist/cjs/pm-plugins/utils/getOffsetByPath.js +83 -0
- package/dist/cjs/pm-plugins/utils/index.js +23 -6
- package/dist/cjs/selectionExtensionPlugin.js +29 -2
- package/dist/cjs/types/index.js +2 -0
- package/dist/cjs/ui/extension/SelectionExtensionComponentWrapper.js +12 -6
- package/dist/es2019/pm-plugins/actions.js +93 -0
- package/dist/es2019/pm-plugins/main.js +22 -0
- package/dist/es2019/pm-plugins/utils/getOffsetByPath.js +76 -0
- package/dist/es2019/pm-plugins/utils/index.js +22 -5
- package/dist/es2019/selectionExtensionPlugin.js +31 -2
- package/dist/es2019/types/index.js +2 -0
- package/dist/es2019/ui/extension/SelectionExtensionComponentWrapper.js +11 -4
- package/dist/esm/pm-plugins/actions.js +87 -0
- package/dist/esm/pm-plugins/main.js +21 -0
- package/dist/esm/pm-plugins/utils/getOffsetByPath.js +78 -0
- package/dist/esm/pm-plugins/utils/index.js +21 -5
- package/dist/esm/selectionExtensionPlugin.js +29 -2
- package/dist/esm/types/index.js +2 -0
- package/dist/esm/ui/extension/SelectionExtensionComponentWrapper.js +13 -7
- package/dist/types/pm-plugins/actions.d.ts +8 -0
- package/dist/types/pm-plugins/main.d.ts +24 -0
- package/dist/types/pm-plugins/utils/getOffsetByPath.d.ts +14 -0
- package/dist/types/pm-plugins/utils/index.d.ts +12 -2
- package/dist/types/selectionExtensionPluginType.d.ts +8 -1
- package/dist/types/types/index.d.ts +17 -1
- package/dist/types-ts4.5/pm-plugins/actions.d.ts +8 -0
- package/dist/types-ts4.5/pm-plugins/main.d.ts +24 -0
- package/dist/types-ts4.5/pm-plugins/utils/getOffsetByPath.d.ts +14 -0
- package/dist/types-ts4.5/pm-plugins/utils/index.d.ts +12 -2
- package/dist/types-ts4.5/selectionExtensionPluginType.d.ts +8 -1
- package/dist/types-ts4.5/types/index.d.ts +17 -1
- package/package.json +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# @atlaskit/editor-plugin-selection-extension
|
|
2
2
|
|
|
3
|
+
## 3.1.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#183521](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/183521)
|
|
8
|
+
[`86379b9b3d99e`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/86379b9b3d99e) -
|
|
9
|
+
Insert links to page bottom as fallback when changes detect
|
|
10
|
+
- [#183158](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/183158)
|
|
11
|
+
[`d6096ec5c8ad9`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/d6096ec5c8ad9) -
|
|
12
|
+
Migrate to useSharedPluginStateWithSelector
|
|
13
|
+
- Updated dependencies
|
|
14
|
+
|
|
15
|
+
## 3.1.0
|
|
16
|
+
|
|
17
|
+
### Minor Changes
|
|
18
|
+
|
|
19
|
+
- [#181784](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/181784)
|
|
20
|
+
[`e3cd18b4fc263`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/e3cd18b4fc263) -
|
|
21
|
+
Create a new action insertSmartLinks to allow inserting multiple smart links in page
|
|
22
|
+
|
|
3
23
|
## 3.0.1
|
|
4
24
|
|
|
5
25
|
### Patch Changes
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.insertSmartLinks = void 0;
|
|
7
|
+
var _types = require("../types");
|
|
8
|
+
var _main = require("./main");
|
|
9
|
+
var _utils = require("./utils");
|
|
10
|
+
var _getOffsetByPath = require("./utils/getOffsetByPath");
|
|
11
|
+
var insertLinkTr = function insertLinkTr(tr, link, offset, schema) {
|
|
12
|
+
var newFromPos = tr.mapping.map(offset.from);
|
|
13
|
+
var newToPos = tr.mapping.map(offset.to || offset.from);
|
|
14
|
+
var smartLink = schema.nodes.inlineCard.createChecked({
|
|
15
|
+
url: link
|
|
16
|
+
});
|
|
17
|
+
return tr.replaceWith(newFromPos, newToPos, smartLink);
|
|
18
|
+
};
|
|
19
|
+
var insertSmartLinks = exports.insertSmartLinks = function insertSmartLinks(linkInsertionOption, selectedNodeAdf) {
|
|
20
|
+
return function (state, dispatch) {
|
|
21
|
+
var _selectionExtensionPl;
|
|
22
|
+
var tr = state.tr,
|
|
23
|
+
schema = state.schema;
|
|
24
|
+
if (!Array.isArray(linkInsertionOption)) {
|
|
25
|
+
linkInsertionOption = [linkInsertionOption];
|
|
26
|
+
}
|
|
27
|
+
if (linkInsertionOption.length === 0) {
|
|
28
|
+
return {
|
|
29
|
+
status: 'error',
|
|
30
|
+
message: 'No link insertion options provided'
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// we need to track if any changes were made since user click the toolbar button
|
|
35
|
+
// if there is change, we insert the links at the bottom of the page instead
|
|
36
|
+
var docChangedAfterClick = ((_selectionExtensionPl = _main.selectionExtensionPluginKey.getState(state)) === null || _selectionExtensionPl === void 0 ? void 0 : _selectionExtensionPl.docChangedAfterClick) || false;
|
|
37
|
+
if (docChangedAfterClick) {
|
|
38
|
+
var docEnd = state.doc.content.size;
|
|
39
|
+
linkInsertionOption.forEach(function (option) {
|
|
40
|
+
var link = option.link;
|
|
41
|
+
tr.insert(tr.mapping.map(docEnd), schema.nodes.inlineCard.createChecked({
|
|
42
|
+
url: link
|
|
43
|
+
}));
|
|
44
|
+
});
|
|
45
|
+
tr.setMeta(_main.selectionExtensionPluginKey, {
|
|
46
|
+
type: _types.SelectionExtensionActionTypes.START_TRACK_CHANGES,
|
|
47
|
+
startTrackChanges: false // Reset the flag when starting to track changes
|
|
48
|
+
});
|
|
49
|
+
dispatch(tr);
|
|
50
|
+
return {
|
|
51
|
+
status: 'success',
|
|
52
|
+
message: 'Links inserted to page bottom successfully'
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
var newTr = tr;
|
|
56
|
+
try {
|
|
57
|
+
var _selectionExtensionPl2, _selectionExtensionPl3;
|
|
58
|
+
var selectedNode = (_selectionExtensionPl2 = _main.selectionExtensionPluginKey.getState(state)) === null || _selectionExtensionPl2 === void 0 ? void 0 : _selectionExtensionPl2.selectedNode;
|
|
59
|
+
var nodePos = (_selectionExtensionPl3 = _main.selectionExtensionPluginKey.getState(state)) === null || _selectionExtensionPl3 === void 0 ? void 0 : _selectionExtensionPl3.nodePos;
|
|
60
|
+
if (!selectedNode || nodePos === undefined) {
|
|
61
|
+
throw new Error('No selected node or node position found');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Validate if the selectedNodeAdf matches the selected node we have in the state
|
|
65
|
+
if (!(0, _utils.validateSelectedNode)(selectedNodeAdf, selectedNode)) {
|
|
66
|
+
throw new Error('Selected node ADF does not match the previous stored node');
|
|
67
|
+
}
|
|
68
|
+
linkInsertionOption.forEach(function (option) {
|
|
69
|
+
var link = option.link,
|
|
70
|
+
insertPosition = option.insertPosition;
|
|
71
|
+
var pointer = insertPosition.pointer,
|
|
72
|
+
from = insertPosition.from,
|
|
73
|
+
to = insertPosition.to;
|
|
74
|
+
var offset = (0, _getOffsetByPath.getOffsetByPath)(selectedNode, nodePos, pointer, from, to);
|
|
75
|
+
newTr = insertLinkTr(tr, link, offset, schema);
|
|
76
|
+
});
|
|
77
|
+
} catch (error) {
|
|
78
|
+
return {
|
|
79
|
+
status: 'error',
|
|
80
|
+
message: error instanceof Error ? error.message : 'Unknown error'
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
newTr.setMeta(_main.selectionExtensionPluginKey, {
|
|
84
|
+
type: _types.SelectionExtensionActionTypes.START_TRACK_CHANGES,
|
|
85
|
+
startTrackChanges: false // Reset the flag when starting to track changes
|
|
86
|
+
});
|
|
87
|
+
dispatch(newTr);
|
|
88
|
+
return {
|
|
89
|
+
status: 'success',
|
|
90
|
+
message: 'Links inserted successfully'
|
|
91
|
+
};
|
|
92
|
+
};
|
|
93
|
+
};
|
|
@@ -8,6 +8,7 @@ exports.selectionExtensionPluginKey = exports.createPlugin = void 0;
|
|
|
8
8
|
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
9
9
|
var _safePlugin = require("@atlaskit/editor-common/safe-plugin");
|
|
10
10
|
var _state = require("@atlaskit/editor-prosemirror/state");
|
|
11
|
+
var _transform = require("@atlaskit/editor-prosemirror/transform");
|
|
11
12
|
var _types = require("../types");
|
|
12
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; }
|
|
13
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; }
|
|
@@ -32,6 +33,26 @@ var createPlugin = exports.createPlugin = function createPlugin() {
|
|
|
32
33
|
return _objectSpread(_objectSpread({}, pluginState), {}, {
|
|
33
34
|
activeExtension: undefined
|
|
34
35
|
});
|
|
36
|
+
case _types.SelectionExtensionActionTypes.SET_SELECTED_NODE:
|
|
37
|
+
return _objectSpread(_objectSpread({}, pluginState), {}, {
|
|
38
|
+
selectedNode: meta.selectedNode,
|
|
39
|
+
nodePos: meta.nodePos,
|
|
40
|
+
startTrackChanges: true,
|
|
41
|
+
docChangedAfterClick: false // Reset the flag when starting to track changes
|
|
42
|
+
});
|
|
43
|
+
case _types.SelectionExtensionActionTypes.START_TRACK_CHANGES:
|
|
44
|
+
return _objectSpread(_objectSpread({}, pluginState), {}, {
|
|
45
|
+
startTrackChanges: meta.startTrackChanges
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
var docChangedAfterClick = pluginState.startTrackChanges && tr.steps.some(function (step) {
|
|
49
|
+
return step instanceof _transform.ReplaceStep || step instanceof _transform.ReplaceAroundStep;
|
|
50
|
+
});
|
|
51
|
+
if (docChangedAfterClick) {
|
|
52
|
+
return _objectSpread(_objectSpread({}, pluginState), {}, {
|
|
53
|
+
docChangedAfterClick: true,
|
|
54
|
+
startTrackChanges: false // Reset the flag to stop tracking after the document has changed
|
|
55
|
+
});
|
|
35
56
|
}
|
|
36
57
|
return pluginState;
|
|
37
58
|
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.getOffsetByPath = getOffsetByPath;
|
|
7
|
+
var _model = require("@atlaskit/editor-prosemirror/model");
|
|
8
|
+
// TODO: ED-28434 - move this to a shared package
|
|
9
|
+
// mirror code from https://bitbucket.org/atlassian/pf-adf-service/src/master/src/lib/update/get-offset.ts
|
|
10
|
+
|
|
11
|
+
function getOffsetByPath(root, pos, pointer) {
|
|
12
|
+
var from = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
|
|
13
|
+
var to = arguments.length > 4 ? arguments[4] : undefined;
|
|
14
|
+
var parts = pointer.split('/');
|
|
15
|
+
var ref = root;
|
|
16
|
+
var len = parts.length;
|
|
17
|
+
// -1 to account for the root node (usually doc)
|
|
18
|
+
// The start of the document, right before the first content, is position 0.
|
|
19
|
+
var offset = pos; //-1;
|
|
20
|
+
|
|
21
|
+
for (var i = 1; i < len; i++) {
|
|
22
|
+
var key = parts[i];
|
|
23
|
+
if (ref instanceof _model.Fragment && /^[0-9]+$/.test(key)) {
|
|
24
|
+
var index = parseInt(key, 10);
|
|
25
|
+
if (index >= ref.childCount) {
|
|
26
|
+
throw new Error("JSON pointer \"".concat(pointer, "\" points to non-existing location."));
|
|
27
|
+
}
|
|
28
|
+
var nextRef = ref.child(index);
|
|
29
|
+
while (index--) {
|
|
30
|
+
offset += ref.child(index).nodeSize;
|
|
31
|
+
}
|
|
32
|
+
ref = nextRef;
|
|
33
|
+
} else if (ref instanceof _model.Node) {
|
|
34
|
+
/**
|
|
35
|
+
* Reference: https://prosemirror.net/docs/guide/#doc.data_structures
|
|
36
|
+
* +----------------------------------+
|
|
37
|
+
* | Node |
|
|
38
|
+
* | ^^^^ |
|
|
39
|
+
* | type: NodeType |
|
|
40
|
+
* | content: Fragment |
|
|
41
|
+
* | [ Node, Node, ...] |
|
|
42
|
+
* | attrs: Object |
|
|
43
|
+
* | marks: Mark |
|
|
44
|
+
* | [ |
|
|
45
|
+
* | type: MarkType |
|
|
46
|
+
* | attrs: Object |
|
|
47
|
+
* | ] |
|
|
48
|
+
* +----------------------------------+
|
|
49
|
+
*/
|
|
50
|
+
switch (key) {
|
|
51
|
+
case 'content':
|
|
52
|
+
// Entering or leaving a node that is not a leaf node (i.e. supports content) counts as one token.
|
|
53
|
+
offset++;
|
|
54
|
+
ref = ref.content;
|
|
55
|
+
break;
|
|
56
|
+
case 'attrs':
|
|
57
|
+
return {
|
|
58
|
+
type: 'attrs',
|
|
59
|
+
from: offset + from,
|
|
60
|
+
path: parts.slice(i + 1)
|
|
61
|
+
};
|
|
62
|
+
case 'text':
|
|
63
|
+
if (!ref.isText) {
|
|
64
|
+
throw new Error("\"".concat(parts.slice(0, i).join('/'), "\" doesn't have any \"text\" node!"));
|
|
65
|
+
}
|
|
66
|
+
continue;
|
|
67
|
+
default:
|
|
68
|
+
throw new Error("JSON pointer \"".concat(pointer, "\" points to an unsupported location."));
|
|
69
|
+
}
|
|
70
|
+
} else {
|
|
71
|
+
throw new Error("JSON pointer \"".concat(pointer, "\" points to an unsupported entity."));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (ref instanceof _model.Fragment) {
|
|
75
|
+
throw new Error("Expected a Node, but the JSON pointer \"".concat(pointer, "\" points to a Fragment."));
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
type: 'node',
|
|
79
|
+
from: offset + from,
|
|
80
|
+
to: offset + (to !== null && to !== void 0 ? to : ref.nodeSize),
|
|
81
|
+
matches: [to ? ref.textBetween(from, to) : ref.textContent]
|
|
82
|
+
};
|
|
83
|
+
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
3
4
|
Object.defineProperty(exports, "__esModule", {
|
|
4
5
|
value: true
|
|
5
6
|
});
|
|
6
|
-
exports.getSelectionInfo = void 0;
|
|
7
|
+
exports.validateSelectedNode = exports.getSelectionInfo = void 0;
|
|
8
|
+
var _isEqual = _interopRequireDefault(require("lodash/isEqual"));
|
|
7
9
|
var _editorJsonTransformer = require("@atlaskit/editor-json-transformer");
|
|
8
10
|
var _state = require("@atlaskit/editor-prosemirror/state");
|
|
9
11
|
var _editorTables = require("@atlaskit/editor-tables");
|
|
@@ -30,11 +32,13 @@ var getSelectionInfoFromSameNode = function getSelectionInfoFromSameNode(selecti
|
|
|
30
32
|
pointer: "/content/".concat($from.index(), "/text"),
|
|
31
33
|
position: $to.parentOffset - 1
|
|
32
34
|
}
|
|
33
|
-
}]
|
|
35
|
+
}],
|
|
36
|
+
nodePos: $from.before() // position before the selection
|
|
34
37
|
};
|
|
35
38
|
};
|
|
36
39
|
var getSelectionInfoFromCellSelection = function getSelectionInfoFromCellSelection(selection) {
|
|
37
40
|
var selectedNode = selection.$anchorCell.node(-1);
|
|
41
|
+
var nodePos = selection.$anchorCell.before(-1);
|
|
38
42
|
var selectionRanges = [];
|
|
39
43
|
var rect = getSelectedRect(selection);
|
|
40
44
|
for (var row = rect.top; row < rect.bottom; row++) {
|
|
@@ -49,14 +53,16 @@ var getSelectionInfoFromCellSelection = function getSelectionInfoFromCellSelecti
|
|
|
49
53
|
}
|
|
50
54
|
return {
|
|
51
55
|
selectedNode: selectedNode,
|
|
52
|
-
selectionRanges: selectionRanges
|
|
56
|
+
selectionRanges: selectionRanges,
|
|
57
|
+
nodePos: nodePos
|
|
53
58
|
};
|
|
54
59
|
};
|
|
55
60
|
var getSelectionInfo = exports.getSelectionInfo = function getSelectionInfo(state) {
|
|
56
61
|
var selection = state.selection;
|
|
57
62
|
var selectionInfo = {
|
|
58
63
|
selectedNode: selection.$from.node(),
|
|
59
|
-
selectionRanges: []
|
|
64
|
+
selectionRanges: [],
|
|
65
|
+
nodePos: selection.$from.before() // default to the position before the selection
|
|
60
66
|
};
|
|
61
67
|
if (selection instanceof _state.TextSelection) {
|
|
62
68
|
var $from = selection.$from,
|
|
@@ -70,9 +76,20 @@ var getSelectionInfo = exports.getSelectionInfo = function getSelectionInfo(stat
|
|
|
70
76
|
selectionInfo = getSelectionInfoFromCellSelection(selection);
|
|
71
77
|
}
|
|
72
78
|
var serializer = new _editorJsonTransformer.JSONTransformer();
|
|
73
|
-
var
|
|
79
|
+
var _selectionInfo = selectionInfo,
|
|
80
|
+
selectionRanges = _selectionInfo.selectionRanges,
|
|
81
|
+
selectedNode = _selectionInfo.selectedNode,
|
|
82
|
+
nodePos = _selectionInfo.nodePos;
|
|
83
|
+
var selectedNodeAdf = serializer.encodeNode(selectedNode);
|
|
74
84
|
return {
|
|
75
85
|
selectedNodeAdf: selectedNodeAdf,
|
|
76
|
-
selectionRanges:
|
|
86
|
+
selectionRanges: selectionRanges,
|
|
87
|
+
selectedNode: selectedNode,
|
|
88
|
+
nodePos: nodePos
|
|
77
89
|
};
|
|
90
|
+
};
|
|
91
|
+
var validateSelectedNode = exports.validateSelectedNode = function validateSelectedNode(selectedNodeAdf, selectedNode) {
|
|
92
|
+
var serializer = new _editorJsonTransformer.JSONTransformer();
|
|
93
|
+
var selectedNodeAdfFromState = serializer.encodeNode(selectedNode);
|
|
94
|
+
return (0, _isEqual.default)(selectedNodeAdf, selectedNodeAdfFromState);
|
|
78
95
|
};
|
|
@@ -10,8 +10,10 @@ var _react = _interopRequireDefault(require("react"));
|
|
|
10
10
|
var _messages = require("@atlaskit/editor-common/messages");
|
|
11
11
|
var _safePlugin = require("@atlaskit/editor-common/safe-plugin");
|
|
12
12
|
var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
|
|
13
|
+
var _actions = require("./pm-plugins/actions");
|
|
13
14
|
var _main = require("./pm-plugins/main");
|
|
14
15
|
var _utils = require("./pm-plugins/utils");
|
|
16
|
+
var _types = require("./types");
|
|
15
17
|
var _SelectionExtensionComponentWrapper = require("./ui/extension/SelectionExtensionComponentWrapper");
|
|
16
18
|
var _getBoundingBoxFromSelection = require("./ui/getBoundingBoxFromSelection");
|
|
17
19
|
var _selectionToolbar2 = require("./ui/selectionToolbar");
|
|
@@ -50,6 +52,20 @@ var selectionExtensionPlugin = exports.selectionExtensionPlugin = function selec
|
|
|
50
52
|
};
|
|
51
53
|
}
|
|
52
54
|
},
|
|
55
|
+
actions: {
|
|
56
|
+
insertSmartLinks: function insertSmartLinks(linkInsertionOptions, selectedNodeAdf) {
|
|
57
|
+
if (!editorViewRef.current) {
|
|
58
|
+
return {
|
|
59
|
+
status: 'error',
|
|
60
|
+
message: 'Editor view is not available'
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
var _editorViewRef$curren = editorViewRef.current,
|
|
64
|
+
state = _editorViewRef$curren.state,
|
|
65
|
+
dispatch = _editorViewRef$curren.dispatch;
|
|
66
|
+
return (0, _actions.insertSmartLinks)(linkInsertionOptions, selectedNodeAdf)(state, dispatch);
|
|
67
|
+
}
|
|
68
|
+
},
|
|
53
69
|
contentComponent: function contentComponent(_ref4) {
|
|
54
70
|
var _api$analytics;
|
|
55
71
|
var editorView = _ref4.editorView;
|
|
@@ -137,15 +153,26 @@ var selectionExtensionPlugin = exports.selectionExtensionPlugin = function selec
|
|
|
137
153
|
selection: selection
|
|
138
154
|
};
|
|
139
155
|
if ((0, _platformFeatureFlags.fg)('platform_editor_selection_extension_api_v2')) {
|
|
140
|
-
var _extension$onClick;
|
|
156
|
+
var _extension$onClick, _api$core;
|
|
141
157
|
var _getSelectionInfo = (0, _utils.getSelectionInfo)(view.state),
|
|
142
158
|
selectedNodeAdf = _getSelectionInfo.selectedNodeAdf,
|
|
143
|
-
selectionRanges = _getSelectionInfo.selectionRanges
|
|
159
|
+
selectionRanges = _getSelectionInfo.selectionRanges,
|
|
160
|
+
selectedNode = _getSelectionInfo.selectedNode,
|
|
161
|
+
nodePos = _getSelectionInfo.nodePos;
|
|
144
162
|
onClickCallbackOptions = {
|
|
145
163
|
selectedNodeAdf: selectedNodeAdf,
|
|
146
164
|
selectionRanges: selectionRanges
|
|
147
165
|
};
|
|
148
166
|
(_extension$onClick = extension.onClick) === null || _extension$onClick === void 0 || _extension$onClick.call(extension, onClickCallbackOptions);
|
|
167
|
+
api === null || api === void 0 || (_api$core = api.core) === null || _api$core === void 0 || _api$core.actions.execute(function (_ref5) {
|
|
168
|
+
var tr = _ref5.tr;
|
|
169
|
+
tr.setMeta(_main.selectionExtensionPluginKey, {
|
|
170
|
+
type: _types.SelectionExtensionActionTypes.SET_SELECTED_NODE,
|
|
171
|
+
selectedNode: selectedNode,
|
|
172
|
+
nodePos: nodePos
|
|
173
|
+
});
|
|
174
|
+
return tr;
|
|
175
|
+
});
|
|
149
176
|
} else {
|
|
150
177
|
if (extension.onClick) {
|
|
151
178
|
extension.onClick(onClickCallbackOptions);
|
package/dist/cjs/types/index.js
CHANGED
|
@@ -14,5 +14,7 @@ var SelectionExtensionActionTypes = exports.SelectionExtensionActionTypes = /*#_
|
|
|
14
14
|
SelectionExtensionActionTypes["SET_ACTIVE_EXTENSION"] = "set-active-extension";
|
|
15
15
|
SelectionExtensionActionTypes["UPDATE_ACTIVE_EXTENSION_COORDS"] = "update-active-extension-coords";
|
|
16
16
|
SelectionExtensionActionTypes["CLEAR_ACTIVE_EXTENSION"] = "clear-active-extension";
|
|
17
|
+
SelectionExtensionActionTypes["SET_SELECTED_NODE"] = "set-selected-node";
|
|
18
|
+
SelectionExtensionActionTypes["START_TRACK_CHANGES"] = "start-track-changes";
|
|
17
19
|
return SelectionExtensionActionTypes;
|
|
18
20
|
}({});
|
|
@@ -8,20 +8,26 @@ exports.SelectionExtensionComponentWrapper = void 0;
|
|
|
8
8
|
var _react = _interopRequireWildcard(require("react"));
|
|
9
9
|
var _analytics = require("@atlaskit/editor-common/analytics");
|
|
10
10
|
var _hooks = require("@atlaskit/editor-common/hooks");
|
|
11
|
-
var _useSharedPluginStateSelector = require("@atlaskit/editor-common/use-shared-plugin-state-selector");
|
|
12
11
|
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
|
|
13
12
|
var useSharedState = (0, _hooks.sharedPluginStateHookMigratorFactory)(function (api) {
|
|
14
|
-
var
|
|
15
|
-
|
|
13
|
+
var _useSharedPluginState = (0, _hooks.useSharedPluginStateWithSelector)(api, ['selectionExtension', 'editorViewMode'], function (states) {
|
|
14
|
+
var _states$selectionExte, _states$editorViewMod;
|
|
15
|
+
return {
|
|
16
|
+
activeExtension: (_states$selectionExte = states.selectionExtensionState) === null || _states$selectionExte === void 0 ? void 0 : _states$selectionExte.activeExtension,
|
|
17
|
+
mode: (_states$editorViewMod = states.editorViewModeState) === null || _states$editorViewMod === void 0 ? void 0 : _states$editorViewMod.mode
|
|
18
|
+
};
|
|
19
|
+
}),
|
|
20
|
+
activeExtension = _useSharedPluginState.activeExtension,
|
|
21
|
+
mode = _useSharedPluginState.mode;
|
|
16
22
|
return {
|
|
17
23
|
editorViewModeState: undefined,
|
|
18
24
|
mode: mode,
|
|
19
25
|
activeExtension: activeExtension
|
|
20
26
|
};
|
|
21
27
|
}, function (api) {
|
|
22
|
-
var
|
|
23
|
-
selectionExtensionState =
|
|
24
|
-
editorViewModeState =
|
|
28
|
+
var _useSharedPluginState2 = (0, _hooks.useSharedPluginState)(api, ['selectionExtension', 'editorViewMode']),
|
|
29
|
+
selectionExtensionState = _useSharedPluginState2.selectionExtensionState,
|
|
30
|
+
editorViewModeState = _useSharedPluginState2.editorViewModeState;
|
|
25
31
|
return {
|
|
26
32
|
editorViewModeState: editorViewModeState,
|
|
27
33
|
mode: editorViewModeState === null || editorViewModeState === void 0 ? void 0 : editorViewModeState.mode,
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { SelectionExtensionActionTypes } from '../types';
|
|
2
|
+
import { selectionExtensionPluginKey } from './main';
|
|
3
|
+
import { validateSelectedNode } from './utils';
|
|
4
|
+
import { getOffsetByPath } from './utils/getOffsetByPath';
|
|
5
|
+
const insertLinkTr = (tr, link, offset, schema) => {
|
|
6
|
+
const newFromPos = tr.mapping.map(offset.from);
|
|
7
|
+
const newToPos = tr.mapping.map(offset.to || offset.from);
|
|
8
|
+
const smartLink = schema.nodes.inlineCard.createChecked({
|
|
9
|
+
url: link
|
|
10
|
+
});
|
|
11
|
+
return tr.replaceWith(newFromPos, newToPos, smartLink);
|
|
12
|
+
};
|
|
13
|
+
export const insertSmartLinks = (linkInsertionOption, selectedNodeAdf) => (state, dispatch) => {
|
|
14
|
+
var _selectionExtensionPl;
|
|
15
|
+
const {
|
|
16
|
+
tr,
|
|
17
|
+
schema
|
|
18
|
+
} = state;
|
|
19
|
+
if (!Array.isArray(linkInsertionOption)) {
|
|
20
|
+
linkInsertionOption = [linkInsertionOption];
|
|
21
|
+
}
|
|
22
|
+
if (linkInsertionOption.length === 0) {
|
|
23
|
+
return {
|
|
24
|
+
status: 'error',
|
|
25
|
+
message: 'No link insertion options provided'
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// we need to track if any changes were made since user click the toolbar button
|
|
30
|
+
// if there is change, we insert the links at the bottom of the page instead
|
|
31
|
+
const docChangedAfterClick = ((_selectionExtensionPl = selectionExtensionPluginKey.getState(state)) === null || _selectionExtensionPl === void 0 ? void 0 : _selectionExtensionPl.docChangedAfterClick) || false;
|
|
32
|
+
if (docChangedAfterClick) {
|
|
33
|
+
const docEnd = state.doc.content.size;
|
|
34
|
+
linkInsertionOption.forEach(option => {
|
|
35
|
+
const {
|
|
36
|
+
link
|
|
37
|
+
} = option;
|
|
38
|
+
tr.insert(tr.mapping.map(docEnd), schema.nodes.inlineCard.createChecked({
|
|
39
|
+
url: link
|
|
40
|
+
}));
|
|
41
|
+
});
|
|
42
|
+
tr.setMeta(selectionExtensionPluginKey, {
|
|
43
|
+
type: SelectionExtensionActionTypes.START_TRACK_CHANGES,
|
|
44
|
+
startTrackChanges: false // Reset the flag when starting to track changes
|
|
45
|
+
});
|
|
46
|
+
dispatch(tr);
|
|
47
|
+
return {
|
|
48
|
+
status: 'success',
|
|
49
|
+
message: 'Links inserted to page bottom successfully'
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
let newTr = tr;
|
|
53
|
+
try {
|
|
54
|
+
var _selectionExtensionPl2, _selectionExtensionPl3;
|
|
55
|
+
const selectedNode = (_selectionExtensionPl2 = selectionExtensionPluginKey.getState(state)) === null || _selectionExtensionPl2 === void 0 ? void 0 : _selectionExtensionPl2.selectedNode;
|
|
56
|
+
const nodePos = (_selectionExtensionPl3 = selectionExtensionPluginKey.getState(state)) === null || _selectionExtensionPl3 === void 0 ? void 0 : _selectionExtensionPl3.nodePos;
|
|
57
|
+
if (!selectedNode || nodePos === undefined) {
|
|
58
|
+
throw new Error('No selected node or node position found');
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Validate if the selectedNodeAdf matches the selected node we have in the state
|
|
62
|
+
if (!validateSelectedNode(selectedNodeAdf, selectedNode)) {
|
|
63
|
+
throw new Error('Selected node ADF does not match the previous stored node');
|
|
64
|
+
}
|
|
65
|
+
linkInsertionOption.forEach(option => {
|
|
66
|
+
const {
|
|
67
|
+
link,
|
|
68
|
+
insertPosition
|
|
69
|
+
} = option;
|
|
70
|
+
const {
|
|
71
|
+
pointer,
|
|
72
|
+
from,
|
|
73
|
+
to
|
|
74
|
+
} = insertPosition;
|
|
75
|
+
const offset = getOffsetByPath(selectedNode, nodePos, pointer, from, to);
|
|
76
|
+
newTr = insertLinkTr(tr, link, offset, schema);
|
|
77
|
+
});
|
|
78
|
+
} catch (error) {
|
|
79
|
+
return {
|
|
80
|
+
status: 'error',
|
|
81
|
+
message: error instanceof Error ? error.message : 'Unknown error'
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
newTr.setMeta(selectionExtensionPluginKey, {
|
|
85
|
+
type: SelectionExtensionActionTypes.START_TRACK_CHANGES,
|
|
86
|
+
startTrackChanges: false // Reset the flag when starting to track changes
|
|
87
|
+
});
|
|
88
|
+
dispatch(newTr);
|
|
89
|
+
return {
|
|
90
|
+
status: 'success',
|
|
91
|
+
message: 'Links inserted successfully'
|
|
92
|
+
};
|
|
93
|
+
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
|
|
2
2
|
import { PluginKey } from '@atlaskit/editor-prosemirror/state';
|
|
3
|
+
import { ReplaceAroundStep, ReplaceStep } from '@atlaskit/editor-prosemirror/transform';
|
|
3
4
|
import { SelectionExtensionActionTypes } from '../types';
|
|
4
5
|
export const selectionExtensionPluginKey = new PluginKey('selectionExtensionPlugin');
|
|
5
6
|
export const createPlugin = () => {
|
|
@@ -24,6 +25,27 @@ export const createPlugin = () => {
|
|
|
24
25
|
...pluginState,
|
|
25
26
|
activeExtension: undefined
|
|
26
27
|
};
|
|
28
|
+
case SelectionExtensionActionTypes.SET_SELECTED_NODE:
|
|
29
|
+
return {
|
|
30
|
+
...pluginState,
|
|
31
|
+
selectedNode: meta.selectedNode,
|
|
32
|
+
nodePos: meta.nodePos,
|
|
33
|
+
startTrackChanges: true,
|
|
34
|
+
docChangedAfterClick: false // Reset the flag when starting to track changes
|
|
35
|
+
};
|
|
36
|
+
case SelectionExtensionActionTypes.START_TRACK_CHANGES:
|
|
37
|
+
return {
|
|
38
|
+
...pluginState,
|
|
39
|
+
startTrackChanges: meta.startTrackChanges
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
const docChangedAfterClick = pluginState.startTrackChanges && tr.steps.some(step => step instanceof ReplaceStep || step instanceof ReplaceAroundStep);
|
|
43
|
+
if (docChangedAfterClick) {
|
|
44
|
+
return {
|
|
45
|
+
...pluginState,
|
|
46
|
+
docChangedAfterClick: true,
|
|
47
|
+
startTrackChanges: false // Reset the flag to stop tracking after the document has changed
|
|
48
|
+
};
|
|
27
49
|
}
|
|
28
50
|
return pluginState;
|
|
29
51
|
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { Fragment, Node as PMNode } from '@atlaskit/editor-prosemirror/model';
|
|
2
|
+
|
|
3
|
+
// TODO: ED-28434 - move this to a shared package
|
|
4
|
+
// mirror code from https://bitbucket.org/atlassian/pf-adf-service/src/master/src/lib/update/get-offset.ts
|
|
5
|
+
|
|
6
|
+
export function getOffsetByPath(root, pos, pointer, from = 0, to) {
|
|
7
|
+
const parts = pointer.split('/');
|
|
8
|
+
let ref = root;
|
|
9
|
+
const len = parts.length;
|
|
10
|
+
// -1 to account for the root node (usually doc)
|
|
11
|
+
// The start of the document, right before the first content, is position 0.
|
|
12
|
+
let offset = pos; //-1;
|
|
13
|
+
|
|
14
|
+
for (let i = 1; i < len; i++) {
|
|
15
|
+
const key = parts[i];
|
|
16
|
+
if (ref instanceof Fragment && /^[0-9]+$/u.test(key)) {
|
|
17
|
+
let index = parseInt(key, 10);
|
|
18
|
+
if (index >= ref.childCount) {
|
|
19
|
+
throw new Error(`JSON pointer "${pointer}" points to non-existing location.`);
|
|
20
|
+
}
|
|
21
|
+
const nextRef = ref.child(index);
|
|
22
|
+
while (index--) {
|
|
23
|
+
offset += ref.child(index).nodeSize;
|
|
24
|
+
}
|
|
25
|
+
ref = nextRef;
|
|
26
|
+
} else if (ref instanceof PMNode) {
|
|
27
|
+
/**
|
|
28
|
+
* Reference: https://prosemirror.net/docs/guide/#doc.data_structures
|
|
29
|
+
* +----------------------------------+
|
|
30
|
+
* | Node |
|
|
31
|
+
* | ^^^^ |
|
|
32
|
+
* | type: NodeType |
|
|
33
|
+
* | content: Fragment |
|
|
34
|
+
* | [ Node, Node, ...] |
|
|
35
|
+
* | attrs: Object |
|
|
36
|
+
* | marks: Mark |
|
|
37
|
+
* | [ |
|
|
38
|
+
* | type: MarkType |
|
|
39
|
+
* | attrs: Object |
|
|
40
|
+
* | ] |
|
|
41
|
+
* +----------------------------------+
|
|
42
|
+
*/
|
|
43
|
+
switch (key) {
|
|
44
|
+
case 'content':
|
|
45
|
+
// Entering or leaving a node that is not a leaf node (i.e. supports content) counts as one token.
|
|
46
|
+
offset++;
|
|
47
|
+
ref = ref.content;
|
|
48
|
+
break;
|
|
49
|
+
case 'attrs':
|
|
50
|
+
return {
|
|
51
|
+
type: 'attrs',
|
|
52
|
+
from: offset + from,
|
|
53
|
+
path: parts.slice(i + 1)
|
|
54
|
+
};
|
|
55
|
+
case 'text':
|
|
56
|
+
if (!ref.isText) {
|
|
57
|
+
throw new Error(`"${parts.slice(0, i).join('/')}" doesn't have any "text" node!`);
|
|
58
|
+
}
|
|
59
|
+
continue;
|
|
60
|
+
default:
|
|
61
|
+
throw new Error(`JSON pointer "${pointer}" points to an unsupported location.`);
|
|
62
|
+
}
|
|
63
|
+
} else {
|
|
64
|
+
throw new Error(`JSON pointer "${pointer}" points to an unsupported entity.`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (ref instanceof Fragment) {
|
|
68
|
+
throw new Error(`Expected a Node, but the JSON pointer "${pointer}" points to a Fragment.`);
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
type: 'node',
|
|
72
|
+
from: offset + from,
|
|
73
|
+
to: offset + (to !== null && to !== void 0 ? to : ref.nodeSize),
|
|
74
|
+
matches: [to ? ref.textBetween(from, to) : ref.textContent]
|
|
75
|
+
};
|
|
76
|
+
}
|