@atlaskit/editor-plugin-paste 31.1.7 → 31.2.0
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/main.js +3 -0
- package/dist/cjs/pm-plugins/util/handlers.js +86 -81
- package/dist/es2019/pm-plugins/main.js +4 -1
- package/dist/es2019/pm-plugins/util/handlers.js +81 -82
- package/dist/esm/pm-plugins/main.js +4 -1
- package/dist/esm/pm-plugins/util/handlers.js +85 -81
- package/dist/types/pm-plugins/util/handlers.d.ts +13 -1
- package/package.json +5 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# @atlaskit/editor-plugin-paste
|
|
2
2
|
|
|
3
|
+
## 31.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [`960570244e4c8`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/960570244e4c8) -
|
|
8
|
+
Keep the text of a partially copied panel in the destination table cell, table header or expand
|
|
9
|
+
instead of inserting a new panel after it, behind platform_editor_paste_panel_c1_into_container
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- [`4f6171751461e`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/4f6171751461e) -
|
|
14
|
+
Clean up experiment `platform_editor_paste_autoconvert_robustness`
|
|
15
|
+
- Updated dependencies
|
|
16
|
+
|
|
17
|
+
## 31.1.8
|
|
18
|
+
|
|
19
|
+
### Patch Changes
|
|
20
|
+
|
|
21
|
+
- Updated dependencies
|
|
22
|
+
|
|
3
23
|
## 31.1.7
|
|
4
24
|
|
|
5
25
|
### Patch Changes
|
|
@@ -381,6 +381,9 @@ function createPlugin(schema, dispatchAnalyticsEvent, dispatch, featureFlags, pl
|
|
|
381
381
|
var _view$state$selection, _view$state$selection2;
|
|
382
382
|
var destinationParentType = (_view$state$selection = (_view$state$selection2 = view.state.selection.$from.node(-1)) === null || _view$state$selection2 === void 0 ? void 0 : _view$state$selection2.type.name) !== null && _view$state$selection !== void 0 ? _view$state$selection : view.state.doc.type.name;
|
|
383
383
|
slice = (0, _handlers.applyContainerNodeTransformToSlice)(slice, schema, destinationParentType);
|
|
384
|
+
if ((0, _fg.fg)('platform_editor_paste_panel_c1_into_container')) {
|
|
385
|
+
slice = (0, _handlers.downgradePanelC1ForDestination)(slice, schema, view.state.selection.$from);
|
|
386
|
+
}
|
|
384
387
|
}
|
|
385
388
|
slice = (0, _handleVSCodeBlock.handleVSCodeBlock)({
|
|
386
389
|
state: state,
|
|
@@ -8,6 +8,7 @@ exports.applyContainerNodeTransformToSlice = applyContainerNodeTransformToSlice;
|
|
|
8
8
|
exports.checkIfSelectionInNestedList = checkIfSelectionInNestedList;
|
|
9
9
|
exports.checkTaskListInList = checkTaskListInList;
|
|
10
10
|
exports.doesSelectionWhichStartsOrEndsInListContainEntireList = void 0;
|
|
11
|
+
exports.downgradePanelC1ForDestination = downgradePanelC1ForDestination;
|
|
11
12
|
exports.flattenNestedListInSlice = flattenNestedListInSlice;
|
|
12
13
|
exports.handleCodeBlock = handleCodeBlock;
|
|
13
14
|
exports.handleExpandPaste = handleExpandPaste;
|
|
@@ -52,7 +53,6 @@ var _model = require("@atlaskit/editor-prosemirror/model");
|
|
|
52
53
|
var _state = require("@atlaskit/editor-prosemirror/state");
|
|
53
54
|
var _utils2 = require("@atlaskit/editor-prosemirror/utils");
|
|
54
55
|
var _replaceTable = require("@atlaskit/editor-tables/utils/replace-table");
|
|
55
|
-
var _isExperimentEnabled = require("@atlaskit/platform-feature-experiments/is-experiment-enabled");
|
|
56
56
|
var _fg = require("@atlaskit/platform-feature-flags/fg");
|
|
57
57
|
var _closeHistory = require("@atlaskit/prosemirror-history/closeHistory");
|
|
58
58
|
var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals");
|
|
@@ -618,6 +618,15 @@ function handlePastePreservingMarks(slice, queueCardsFromChangedTr) {
|
|
|
618
618
|
function getSmartLinkAdf(_x, _x2, _x3) {
|
|
619
619
|
return _getSmartLinkAdf.apply(this, arguments);
|
|
620
620
|
}
|
|
621
|
+
/**
|
|
622
|
+
* Inserts the pasted content and then replaces it with `macro` as a separate transaction.
|
|
623
|
+
*
|
|
624
|
+
* The range the macro replaces is derived from the steps that were actually applied
|
|
625
|
+
* rather than from `slice.size`. `slice.size` is the slice's own measure and does not
|
|
626
|
+
* account for ProseMirror's fitting behaviour in `replaceRange`/`replaceSelection`, so
|
|
627
|
+
* the two can disagree — and when they do the macro would be inserted without removing
|
|
628
|
+
* the text it should replace, leaving both the pasted text and the macro in the document.
|
|
629
|
+
*/
|
|
621
630
|
function _getSmartLinkAdf() {
|
|
622
631
|
_getSmartLinkAdf = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(text, type, cardOptions) {
|
|
623
632
|
var provider;
|
|
@@ -646,46 +655,7 @@ function _getSmartLinkAdf() {
|
|
|
646
655
|
}));
|
|
647
656
|
return _getSmartLinkAdf.apply(this, arguments);
|
|
648
657
|
}
|
|
649
|
-
function
|
|
650
|
-
if (view) {
|
|
651
|
-
// insert the text or linkified/md-converted clipboard data
|
|
652
|
-
var selection = view.state.tr.selection;
|
|
653
|
-
var tr;
|
|
654
|
-
var before;
|
|
655
|
-
if (typeof from === 'number' && typeof to === 'number') {
|
|
656
|
-
tr = view.state.tr.replaceRange(from, to, slice);
|
|
657
|
-
before = tr.mapping.map(from, -1);
|
|
658
|
-
} else {
|
|
659
|
-
tr = view.state.tr.replaceSelection(slice);
|
|
660
|
-
before = tr.mapping.map(selection.from, -1);
|
|
661
|
-
}
|
|
662
|
-
view.dispatch(tr);
|
|
663
|
-
|
|
664
|
-
// replace the text with the macro as a separate transaction
|
|
665
|
-
// so the autoconversion generates 2 undo steps
|
|
666
|
-
var macroTr = (0, _closeHistory.closeHistory)(view.state.tr).replaceRangeWith(before, before + slice.size, macro).scrollIntoView();
|
|
667
|
-
(0, _card.addLinkMetadata)(view.state.selection, macroTr, {
|
|
668
|
-
inputMethod: _enums.INPUT_METHOD.CLIPBOARD,
|
|
669
|
-
cardAction: 'AUTO_CONVERT'
|
|
670
|
-
});
|
|
671
|
-
view.dispatch(macroTr);
|
|
672
|
-
return true;
|
|
673
|
-
}
|
|
674
|
-
return false;
|
|
675
|
-
}
|
|
676
|
-
|
|
677
|
-
/**
|
|
678
|
-
* Replacement for `insertAutoMacroOld` behind
|
|
679
|
-
* `platform_editor_paste_autoconvert_robustness`.
|
|
680
|
-
*
|
|
681
|
-
* Identical in shape, except that the range the macro replaces is derived from the steps
|
|
682
|
-
* that were actually applied rather than from `slice.size`. `slice.size` is the slice's
|
|
683
|
-
* own measure and does not account for ProseMirror's fitting behaviour in
|
|
684
|
-
* `replaceRange`/`replaceSelection`, so the two can disagree — and when they do the macro
|
|
685
|
-
* is inserted without removing the text it should replace, leaving both the pasted text
|
|
686
|
-
* and the macro in the document.
|
|
687
|
-
*/
|
|
688
|
-
function insertAutoMacroNew(slice, macro, view, from, to) {
|
|
658
|
+
function insertAutoMacro(slice, macro, view, from, to) {
|
|
689
659
|
if (!view) {
|
|
690
660
|
return false;
|
|
691
661
|
}
|
|
@@ -715,9 +685,6 @@ function insertAutoMacroNew(slice, macro, view, from, to) {
|
|
|
715
685
|
view.dispatch(macroTr);
|
|
716
686
|
return true;
|
|
717
687
|
}
|
|
718
|
-
function insertAutoMacro(slice, macro, view, from, to) {
|
|
719
|
-
return (0, _isExperimentEnabled.isExperimentEnabled)('platform_editor_paste_autoconvert_robustness') ? insertAutoMacroNew(slice, macro, view, from, to) : insertAutoMacroOld(slice, macro, view, from, to);
|
|
720
|
-
}
|
|
721
688
|
|
|
722
689
|
/**
|
|
723
690
|
* Locates the range currently occupied by a link that we pasted earlier.
|
|
@@ -868,45 +835,27 @@ function handleMacroAutoConvert(text, slice, queueCardsFromChangedTr, runMacroAu
|
|
|
868
835
|
var trackingId = (0, _uuid.v4)();
|
|
869
836
|
var trackingFrom = "handleMacroAutoConvert-from-".concat(trackingId);
|
|
870
837
|
var trackingTo = "handleMacroAutoConvert-to-".concat(trackingId);
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
return true;
|
|
883
|
-
}
|
|
884
|
-
(0, _commands.startTrackingPastedMacroPositions)((0, _defineProperty2.default)((0, _defineProperty2.default)({}, trackingFrom, insertedRange.from), trackingTo, insertedRange.to))(view.state, dispatch);
|
|
885
|
-
getSmartLinkAdf(text, 'inline', cardsOptions).catch(function () {
|
|
886
|
-
// Smart links could not resolve the URL, so fall back to the macro.
|
|
887
|
-
// we use view.state rather than state because state becomes a stale
|
|
888
|
-
// state reference after getSmartLinkAdf's async work
|
|
889
|
-
var _getPastePluginState = (0, _pluginFactory.getPluginState)(view.state),
|
|
890
|
-
pastedMacroPositions = _getPastePluginState.pastedMacroPositions;
|
|
891
|
-
replacePastedLinkWithMacro(view, autoConvertMacro, text, pastedMacroPositions[trackingFrom], pastedMacroPositions[trackingTo], editorAnalyticsAPI);
|
|
892
|
-
}).finally(function () {
|
|
893
|
-
(0, _commands.stopTrackingPastedMacroPositions)([trackingFrom, trackingTo])(view.state, dispatch);
|
|
894
|
-
});
|
|
838
|
+
|
|
839
|
+
// Insert the pasted content straight away. The smart link provider is only
|
|
840
|
+
// consulted to decide whether the inserted link should later be swapped for
|
|
841
|
+
// a macro, so it does not need to gate the insert — otherwise every
|
|
842
|
+
// autoconvertible paste appears to do nothing until a network round trip
|
|
843
|
+
// completes.
|
|
844
|
+
var insertedRange;
|
|
845
|
+
handleMarkdownWithInsertedRange(slice, queueCardsFromChangedTr, function (range) {
|
|
846
|
+
insertedRange = range;
|
|
847
|
+
})(state, dispatch);
|
|
848
|
+
if (!insertedRange) {
|
|
895
849
|
return true;
|
|
896
850
|
}
|
|
897
|
-
(0, _commands.startTrackingPastedMacroPositions)((0, _defineProperty2.default)((0, _defineProperty2.default)({}, trackingFrom,
|
|
898
|
-
getSmartLinkAdf(text, 'inline', cardsOptions).
|
|
851
|
+
(0, _commands.startTrackingPastedMacroPositions)((0, _defineProperty2.default)((0, _defineProperty2.default)({}, trackingFrom, insertedRange.from), trackingTo, insertedRange.to))(view.state, dispatch);
|
|
852
|
+
getSmartLinkAdf(text, 'inline', cardsOptions).catch(function () {
|
|
853
|
+
// Smart links could not resolve the URL, so fall back to the macro.
|
|
899
854
|
// we use view.state rather than state because state becomes a stale
|
|
900
855
|
// state reference after getSmartLinkAdf's async work
|
|
901
|
-
var
|
|
902
|
-
pastedMacroPositions =
|
|
903
|
-
|
|
904
|
-
handleMarkdown(slice, queueCardsFromChangedTr, pastedMacroPositions[trackingFrom], pastedMacroPositions[trackingTo])(view.state, dispatch);
|
|
905
|
-
}
|
|
906
|
-
}).catch(function () {
|
|
907
|
-
var _getPastePluginState3 = (0, _pluginFactory.getPluginState)(view.state),
|
|
908
|
-
pastedMacroPositions = _getPastePluginState3.pastedMacroPositions;
|
|
909
|
-
insertAutoMacro(slice, macro, view, pastedMacroPositions[trackingFrom], pastedMacroPositions[trackingTo]);
|
|
856
|
+
var _getPastePluginState = (0, _pluginFactory.getPluginState)(view.state),
|
|
857
|
+
pastedMacroPositions = _getPastePluginState.pastedMacroPositions;
|
|
858
|
+
replacePastedLinkWithMacro(view, autoConvertMacro, text, pastedMacroPositions[trackingFrom], pastedMacroPositions[trackingTo], editorAnalyticsAPI);
|
|
910
859
|
}).finally(function () {
|
|
911
860
|
(0, _commands.stopTrackingPastedMacroPositions)([trackingFrom, trackingTo])(view.state, dispatch);
|
|
912
861
|
});
|
|
@@ -1212,8 +1161,7 @@ function resolveParagraphMarks(marks, destinationBlockMarkAttrs, shouldNormalize
|
|
|
1212
1161
|
}
|
|
1213
1162
|
|
|
1214
1163
|
/**
|
|
1215
|
-
* Variant of `handleMarkdown` used by macro auto-conversion
|
|
1216
|
-
* `platform_editor_paste_autoconvert_robustness`.
|
|
1164
|
+
* Variant of `handleMarkdown` used by macro auto-conversion.
|
|
1217
1165
|
*
|
|
1218
1166
|
* Differs in two ways: the inserted range is derived from the steps that were applied
|
|
1219
1167
|
* rather than from `markdownSlice.size`, which does not account for ProseMirror's fitting
|
|
@@ -1694,6 +1642,63 @@ function applyContainerNodeTransformToSlice(slice, schema, destinationParentType
|
|
|
1694
1642
|
}
|
|
1695
1643
|
}
|
|
1696
1644
|
|
|
1645
|
+
/**
|
|
1646
|
+
* Finds the type of the nearest ancestor of the paste position that can hold the panel in either
|
|
1647
|
+
* of its forms. That is the node a block-level panel would be placed into, which is not always the
|
|
1648
|
+
* direct parent of the cursor's textblock (e.g. a blockquote inside a table cell).
|
|
1649
|
+
*/
|
|
1650
|
+
function findNearestPanelHolderType($from, panelAsC1, panelAsPlain) {
|
|
1651
|
+
var panelAsC1Content = _model.Fragment.from(panelAsC1);
|
|
1652
|
+
var panelAsPlainContent = _model.Fragment.from(panelAsPlain);
|
|
1653
|
+
for (var depth = $from.depth; depth >= 0; depth--) {
|
|
1654
|
+
var ancestorType = $from.node(depth).type;
|
|
1655
|
+
if (ancestorType.validContent(panelAsC1Content) || ancestorType.validContent(panelAsPlainContent)) {
|
|
1656
|
+
return ancestorType;
|
|
1657
|
+
}
|
|
1658
|
+
}
|
|
1659
|
+
return undefined;
|
|
1660
|
+
}
|
|
1661
|
+
|
|
1662
|
+
/**
|
|
1663
|
+
* Turns top-level `panel_c1` children of the slice back into `panel` when the nearest ancestor of
|
|
1664
|
+
* the paste position that can hold a panel accepts `panel` but not `panel_c1`. Only panels whose
|
|
1665
|
+
* content is valid for a plain `panel` are changed, that is content without the containers only
|
|
1666
|
+
* `panel_c1` allows: tables (`platform_editor_nest_table_in_panel`), and expands, nested panels and
|
|
1667
|
+
* other containers when `platform_editor_nest_container_in_panel` is on.
|
|
1668
|
+
*
|
|
1669
|
+
* A partial copy from a top-level panel is re-wrapped as `panel_c1` from the clipboard context, and
|
|
1670
|
+
* a wrapper the destination cannot hold makes the paste insert the panel after the container (e.g.
|
|
1671
|
+
* below a table) instead of pasting the text where the cursor is.
|
|
1672
|
+
*/
|
|
1673
|
+
function downgradePanelC1ForDestination(slice, schema, $from) {
|
|
1674
|
+
var _schema$nodes4 = schema.nodes,
|
|
1675
|
+
panel = _schema$nodes4.panel,
|
|
1676
|
+
panel_c1 = _schema$nodes4.panel_c1;
|
|
1677
|
+
if (!panel || !panel_c1) {
|
|
1678
|
+
return slice;
|
|
1679
|
+
}
|
|
1680
|
+
var isDowngraded = false;
|
|
1681
|
+
var children = [];
|
|
1682
|
+
slice.content.forEach(function (child) {
|
|
1683
|
+
if (child.type !== panel_c1 || !panel.validContent(child.content)) {
|
|
1684
|
+
children.push(child);
|
|
1685
|
+
return;
|
|
1686
|
+
}
|
|
1687
|
+
var plainPanel = panel.create(child.attrs, child.content, child.marks.filter(function (mark) {
|
|
1688
|
+
return panel.allowsMarkType(mark.type);
|
|
1689
|
+
}));
|
|
1690
|
+
var holderType = findNearestPanelHolderType($from, child, plainPanel);
|
|
1691
|
+
var holderOnlyAcceptsPlainPanel = !!holderType && !holderType.validContent(_model.Fragment.from(child)) && holderType.validContent(_model.Fragment.from(plainPanel));
|
|
1692
|
+
if (holderOnlyAcceptsPlainPanel) {
|
|
1693
|
+
isDowngraded = true;
|
|
1694
|
+
children.push(plainPanel);
|
|
1695
|
+
return;
|
|
1696
|
+
}
|
|
1697
|
+
children.push(child);
|
|
1698
|
+
});
|
|
1699
|
+
return isDowngraded ? new _model.Slice(_model.Fragment.fromArray(children), slice.openStart, slice.openEnd) : slice;
|
|
1700
|
+
}
|
|
1701
|
+
|
|
1697
1702
|
/*
|
|
1698
1703
|
* When platform_editor_nest_table_in_panel is OFF, move table elements out of panel divs in the
|
|
1699
1704
|
* clipboard HTML before ProseMirror parses it. This prevents the panel schema from
|
|
@@ -41,7 +41,7 @@ import { createPluginState, pluginKey as stateKey } from './plugin-factory';
|
|
|
41
41
|
import { escapeBackslashAndLinksExceptCodeBlock, getPasteSource, htmlContainsSingleFile, htmlHasInvalidLinkTags, isPastedFromExcel, isPastedFromWord, removeDuplicateInvalidLinks, transformUnsupportedBlockCardToInline } from './util';
|
|
42
42
|
import { handleVSCodeBlock } from './util/edge-cases/handleVSCodeBlock';
|
|
43
43
|
import { getMarkdownSliceViaGfm } from './util/get-markdown-slice';
|
|
44
|
-
import { applyContainerNodeTransformToSlice, splitTablesOutOfPanelHtml, handleMacroAutoConvert, handleMention, handleParagraphBlockMarks, handlePasteExpand, handleTableContentPasteInBodiedExtension } from './util/handlers';
|
|
44
|
+
import { applyContainerNodeTransformToSlice, downgradePanelC1ForDestination, splitTablesOutOfPanelHtml, handleMacroAutoConvert, handleMention, handleParagraphBlockMarks, handlePasteExpand, handleTableContentPasteInBodiedExtension } from './util/handlers';
|
|
45
45
|
import { normalizePastedCodeBlockAttrs } from './util/normalize-pasted-code-block-attrs';
|
|
46
46
|
import { handleSyncBlocksPaste } from './util/sync-block';
|
|
47
47
|
import { htmlHasIncompleteTable, isPastedFromTinyMCEConfluence, tryRebuildCompleteTableHtml } from './util/tinyMCE';
|
|
@@ -340,6 +340,9 @@ export function createPlugin(schema, dispatchAnalyticsEvent, dispatch, featureFl
|
|
|
340
340
|
var _view$state$selection, _view$state$selection2;
|
|
341
341
|
const destinationParentType = (_view$state$selection = (_view$state$selection2 = view.state.selection.$from.node(-1)) === null || _view$state$selection2 === void 0 ? void 0 : _view$state$selection2.type.name) !== null && _view$state$selection !== void 0 ? _view$state$selection : view.state.doc.type.name;
|
|
342
342
|
slice = applyContainerNodeTransformToSlice(slice, schema, destinationParentType);
|
|
343
|
+
if (fg('platform_editor_paste_panel_c1_into_container')) {
|
|
344
|
+
slice = downgradePanelC1ForDestination(slice, schema, view.state.selection.$from);
|
|
345
|
+
}
|
|
343
346
|
}
|
|
344
347
|
slice = handleVSCodeBlock({
|
|
345
348
|
state,
|
|
@@ -18,7 +18,6 @@ import { Fragment, Node as PMNode, Slice } from '@atlaskit/editor-prosemirror/mo
|
|
|
18
18
|
import { AllSelection, NodeSelection, TextSelection } from '@atlaskit/editor-prosemirror/state';
|
|
19
19
|
import { canInsert, contains, findParentNodeOfType, findParentNodeOfTypeClosestToPos, hasParentNode, hasParentNodeOfType, safeInsert } from '@atlaskit/editor-prosemirror/utils';
|
|
20
20
|
import { replaceSelectedTable } from '@atlaskit/editor-tables/utils/replace-table';
|
|
21
|
-
import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
|
|
22
21
|
import { fg } from '@atlaskit/platform-feature-flags/fg';
|
|
23
22
|
import { closeHistory } from '@atlaskit/prosemirror-history/closeHistory';
|
|
24
23
|
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
|
|
@@ -612,46 +611,17 @@ async function getSmartLinkAdf(text, type, cardOptions) {
|
|
|
612
611
|
const provider = await cardOptions.provider;
|
|
613
612
|
return await provider.resolve(text, type);
|
|
614
613
|
}
|
|
615
|
-
function insertAutoMacroOld(slice, macro, view, from, to) {
|
|
616
|
-
if (view) {
|
|
617
|
-
// insert the text or linkified/md-converted clipboard data
|
|
618
|
-
const selection = view.state.tr.selection;
|
|
619
|
-
let tr;
|
|
620
|
-
let before;
|
|
621
|
-
if (typeof from === 'number' && typeof to === 'number') {
|
|
622
|
-
tr = view.state.tr.replaceRange(from, to, slice);
|
|
623
|
-
before = tr.mapping.map(from, -1);
|
|
624
|
-
} else {
|
|
625
|
-
tr = view.state.tr.replaceSelection(slice);
|
|
626
|
-
before = tr.mapping.map(selection.from, -1);
|
|
627
|
-
}
|
|
628
|
-
view.dispatch(tr);
|
|
629
|
-
|
|
630
|
-
// replace the text with the macro as a separate transaction
|
|
631
|
-
// so the autoconversion generates 2 undo steps
|
|
632
|
-
const macroTr = closeHistory(view.state.tr).replaceRangeWith(before, before + slice.size, macro).scrollIntoView();
|
|
633
|
-
addLinkMetadata(view.state.selection, macroTr, {
|
|
634
|
-
inputMethod: INPUT_METHOD.CLIPBOARD,
|
|
635
|
-
cardAction: 'AUTO_CONVERT'
|
|
636
|
-
});
|
|
637
|
-
view.dispatch(macroTr);
|
|
638
|
-
return true;
|
|
639
|
-
}
|
|
640
|
-
return false;
|
|
641
|
-
}
|
|
642
614
|
|
|
643
615
|
/**
|
|
644
|
-
*
|
|
645
|
-
* `platform_editor_paste_autoconvert_robustness`.
|
|
616
|
+
* Inserts the pasted content and then replaces it with `macro` as a separate transaction.
|
|
646
617
|
*
|
|
647
|
-
*
|
|
648
|
-
*
|
|
649
|
-
*
|
|
650
|
-
*
|
|
651
|
-
*
|
|
652
|
-
* and the macro in the document.
|
|
618
|
+
* The range the macro replaces is derived from the steps that were actually applied
|
|
619
|
+
* rather than from `slice.size`. `slice.size` is the slice's own measure and does not
|
|
620
|
+
* account for ProseMirror's fitting behaviour in `replaceRange`/`replaceSelection`, so
|
|
621
|
+
* the two can disagree — and when they do the macro would be inserted without removing
|
|
622
|
+
* the text it should replace, leaving both the pasted text and the macro in the document.
|
|
653
623
|
*/
|
|
654
|
-
function
|
|
624
|
+
function insertAutoMacro(slice, macro, view, from, to) {
|
|
655
625
|
if (!view) {
|
|
656
626
|
return false;
|
|
657
627
|
}
|
|
@@ -683,9 +653,6 @@ function insertAutoMacroNew(slice, macro, view, from, to) {
|
|
|
683
653
|
view.dispatch(macroTr);
|
|
684
654
|
return true;
|
|
685
655
|
}
|
|
686
|
-
function insertAutoMacro(slice, macro, view, from, to) {
|
|
687
|
-
return isExperimentEnabled('platform_editor_paste_autoconvert_robustness') ? insertAutoMacroNew(slice, macro, view, from, to) : insertAutoMacroOld(slice, macro, view, from, to);
|
|
688
|
-
}
|
|
689
656
|
|
|
690
657
|
/**
|
|
691
658
|
* Locates the range currently occupied by a link that we pasted earlier.
|
|
@@ -838,54 +805,31 @@ export function handleMacroAutoConvert(text, slice, queueCardsFromChangedTr, run
|
|
|
838
805
|
const trackingId = uuid();
|
|
839
806
|
const trackingFrom = `handleMacroAutoConvert-from-${trackingId}`;
|
|
840
807
|
const trackingTo = `handleMacroAutoConvert-to-${trackingId}`;
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
return true;
|
|
853
|
-
}
|
|
854
|
-
startTrackingPastedMacroPositions({
|
|
855
|
-
[trackingFrom]: insertedRange.from,
|
|
856
|
-
[trackingTo]: insertedRange.to
|
|
857
|
-
})(view.state, dispatch);
|
|
858
|
-
getSmartLinkAdf(text, 'inline', cardsOptions).catch(() => {
|
|
859
|
-
// Smart links could not resolve the URL, so fall back to the macro.
|
|
860
|
-
// we use view.state rather than state because state becomes a stale
|
|
861
|
-
// state reference after getSmartLinkAdf's async work
|
|
862
|
-
const {
|
|
863
|
-
pastedMacroPositions
|
|
864
|
-
} = getPastePluginState(view.state);
|
|
865
|
-
replacePastedLinkWithMacro(view, autoConvertMacro, text, pastedMacroPositions[trackingFrom], pastedMacroPositions[trackingTo], editorAnalyticsAPI);
|
|
866
|
-
}).finally(() => {
|
|
867
|
-
stopTrackingPastedMacroPositions([trackingFrom, trackingTo])(view.state, dispatch);
|
|
868
|
-
});
|
|
808
|
+
|
|
809
|
+
// Insert the pasted content straight away. The smart link provider is only
|
|
810
|
+
// consulted to decide whether the inserted link should later be swapped for
|
|
811
|
+
// a macro, so it does not need to gate the insert — otherwise every
|
|
812
|
+
// autoconvertible paste appears to do nothing until a network round trip
|
|
813
|
+
// completes.
|
|
814
|
+
let insertedRange;
|
|
815
|
+
handleMarkdownWithInsertedRange(slice, queueCardsFromChangedTr, range => {
|
|
816
|
+
insertedRange = range;
|
|
817
|
+
})(state, dispatch);
|
|
818
|
+
if (!insertedRange) {
|
|
869
819
|
return true;
|
|
870
820
|
}
|
|
871
821
|
startTrackingPastedMacroPositions({
|
|
872
|
-
[trackingFrom]:
|
|
873
|
-
[trackingTo]:
|
|
874
|
-
})(state, dispatch);
|
|
875
|
-
getSmartLinkAdf(text, 'inline', cardsOptions).
|
|
822
|
+
[trackingFrom]: insertedRange.from,
|
|
823
|
+
[trackingTo]: insertedRange.to
|
|
824
|
+
})(view.state, dispatch);
|
|
825
|
+
getSmartLinkAdf(text, 'inline', cardsOptions).catch(() => {
|
|
826
|
+
// Smart links could not resolve the URL, so fall back to the macro.
|
|
876
827
|
// we use view.state rather than state because state becomes a stale
|
|
877
828
|
// state reference after getSmartLinkAdf's async work
|
|
878
829
|
const {
|
|
879
830
|
pastedMacroPositions
|
|
880
831
|
} = getPastePluginState(view.state);
|
|
881
|
-
|
|
882
|
-
handleMarkdown(slice, queueCardsFromChangedTr, pastedMacroPositions[trackingFrom], pastedMacroPositions[trackingTo])(view.state, dispatch);
|
|
883
|
-
}
|
|
884
|
-
}).catch(() => {
|
|
885
|
-
const {
|
|
886
|
-
pastedMacroPositions
|
|
887
|
-
} = getPastePluginState(view.state);
|
|
888
|
-
insertAutoMacro(slice, macro, view, pastedMacroPositions[trackingFrom], pastedMacroPositions[trackingTo]);
|
|
832
|
+
replacePastedLinkWithMacro(view, autoConvertMacro, text, pastedMacroPositions[trackingFrom], pastedMacroPositions[trackingTo], editorAnalyticsAPI);
|
|
889
833
|
}).finally(() => {
|
|
890
834
|
stopTrackingPastedMacroPositions([trackingFrom, trackingTo])(view.state, dispatch);
|
|
891
835
|
});
|
|
@@ -1195,8 +1139,7 @@ function resolveParagraphMarks(marks, destinationBlockMarkAttrs, shouldNormalize
|
|
|
1195
1139
|
}
|
|
1196
1140
|
|
|
1197
1141
|
/**
|
|
1198
|
-
* Variant of `handleMarkdown` used by macro auto-conversion
|
|
1199
|
-
* `platform_editor_paste_autoconvert_robustness`.
|
|
1142
|
+
* Variant of `handleMarkdown` used by macro auto-conversion.
|
|
1200
1143
|
*
|
|
1201
1144
|
* Differs in two ways: the inserted range is derived from the steps that were applied
|
|
1202
1145
|
* rather than from `markdownSlice.size`, which does not account for ProseMirror's fitting
|
|
@@ -1664,6 +1607,62 @@ export function applyContainerNodeTransformToSlice(slice, schema, destinationPar
|
|
|
1664
1607
|
}
|
|
1665
1608
|
}
|
|
1666
1609
|
|
|
1610
|
+
/**
|
|
1611
|
+
* Finds the type of the nearest ancestor of the paste position that can hold the panel in either
|
|
1612
|
+
* of its forms. That is the node a block-level panel would be placed into, which is not always the
|
|
1613
|
+
* direct parent of the cursor's textblock (e.g. a blockquote inside a table cell).
|
|
1614
|
+
*/
|
|
1615
|
+
function findNearestPanelHolderType($from, panelAsC1, panelAsPlain) {
|
|
1616
|
+
const panelAsC1Content = Fragment.from(panelAsC1);
|
|
1617
|
+
const panelAsPlainContent = Fragment.from(panelAsPlain);
|
|
1618
|
+
for (let depth = $from.depth; depth >= 0; depth--) {
|
|
1619
|
+
const ancestorType = $from.node(depth).type;
|
|
1620
|
+
if (ancestorType.validContent(panelAsC1Content) || ancestorType.validContent(panelAsPlainContent)) {
|
|
1621
|
+
return ancestorType;
|
|
1622
|
+
}
|
|
1623
|
+
}
|
|
1624
|
+
return undefined;
|
|
1625
|
+
}
|
|
1626
|
+
|
|
1627
|
+
/**
|
|
1628
|
+
* Turns top-level `panel_c1` children of the slice back into `panel` when the nearest ancestor of
|
|
1629
|
+
* the paste position that can hold a panel accepts `panel` but not `panel_c1`. Only panels whose
|
|
1630
|
+
* content is valid for a plain `panel` are changed, that is content without the containers only
|
|
1631
|
+
* `panel_c1` allows: tables (`platform_editor_nest_table_in_panel`), and expands, nested panels and
|
|
1632
|
+
* other containers when `platform_editor_nest_container_in_panel` is on.
|
|
1633
|
+
*
|
|
1634
|
+
* A partial copy from a top-level panel is re-wrapped as `panel_c1` from the clipboard context, and
|
|
1635
|
+
* a wrapper the destination cannot hold makes the paste insert the panel after the container (e.g.
|
|
1636
|
+
* below a table) instead of pasting the text where the cursor is.
|
|
1637
|
+
*/
|
|
1638
|
+
export function downgradePanelC1ForDestination(slice, schema, $from) {
|
|
1639
|
+
const {
|
|
1640
|
+
panel,
|
|
1641
|
+
panel_c1
|
|
1642
|
+
} = schema.nodes;
|
|
1643
|
+
if (!panel || !panel_c1) {
|
|
1644
|
+
return slice;
|
|
1645
|
+
}
|
|
1646
|
+
let isDowngraded = false;
|
|
1647
|
+
const children = [];
|
|
1648
|
+
slice.content.forEach(child => {
|
|
1649
|
+
if (child.type !== panel_c1 || !panel.validContent(child.content)) {
|
|
1650
|
+
children.push(child);
|
|
1651
|
+
return;
|
|
1652
|
+
}
|
|
1653
|
+
const plainPanel = panel.create(child.attrs, child.content, child.marks.filter(mark => panel.allowsMarkType(mark.type)));
|
|
1654
|
+
const holderType = findNearestPanelHolderType($from, child, plainPanel);
|
|
1655
|
+
const holderOnlyAcceptsPlainPanel = !!holderType && !holderType.validContent(Fragment.from(child)) && holderType.validContent(Fragment.from(plainPanel));
|
|
1656
|
+
if (holderOnlyAcceptsPlainPanel) {
|
|
1657
|
+
isDowngraded = true;
|
|
1658
|
+
children.push(plainPanel);
|
|
1659
|
+
return;
|
|
1660
|
+
}
|
|
1661
|
+
children.push(child);
|
|
1662
|
+
});
|
|
1663
|
+
return isDowngraded ? new Slice(Fragment.fromArray(children), slice.openStart, slice.openEnd) : slice;
|
|
1664
|
+
}
|
|
1665
|
+
|
|
1667
1666
|
/*
|
|
1668
1667
|
* When platform_editor_nest_table_in_panel is OFF, move table elements out of panel divs in the
|
|
1669
1668
|
* clipboard HTML before ProseMirror parses it. This prevents the panel schema from
|
|
@@ -46,7 +46,7 @@ import { createPluginState, pluginKey as stateKey } from './plugin-factory';
|
|
|
46
46
|
import { escapeBackslashAndLinksExceptCodeBlock, getPasteSource, htmlContainsSingleFile, htmlHasInvalidLinkTags, isPastedFromExcel, isPastedFromWord, removeDuplicateInvalidLinks, transformUnsupportedBlockCardToInline } from './util';
|
|
47
47
|
import { handleVSCodeBlock } from './util/edge-cases/handleVSCodeBlock';
|
|
48
48
|
import { getMarkdownSliceViaGfm } from './util/get-markdown-slice';
|
|
49
|
-
import { applyContainerNodeTransformToSlice, splitTablesOutOfPanelHtml, handleMacroAutoConvert, handleMention, handleParagraphBlockMarks, handlePasteExpand, handleTableContentPasteInBodiedExtension } from './util/handlers';
|
|
49
|
+
import { applyContainerNodeTransformToSlice, downgradePanelC1ForDestination, splitTablesOutOfPanelHtml, handleMacroAutoConvert, handleMention, handleParagraphBlockMarks, handlePasteExpand, handleTableContentPasteInBodiedExtension } from './util/handlers';
|
|
50
50
|
import { normalizePastedCodeBlockAttrs } from './util/normalize-pasted-code-block-attrs';
|
|
51
51
|
import { handleSyncBlocksPaste } from './util/sync-block';
|
|
52
52
|
import { htmlHasIncompleteTable, isPastedFromTinyMCEConfluence, tryRebuildCompleteTableHtml } from './util/tinyMCE';
|
|
@@ -373,6 +373,9 @@ export function createPlugin(schema, dispatchAnalyticsEvent, dispatch, featureFl
|
|
|
373
373
|
var _view$state$selection, _view$state$selection2;
|
|
374
374
|
var destinationParentType = (_view$state$selection = (_view$state$selection2 = view.state.selection.$from.node(-1)) === null || _view$state$selection2 === void 0 ? void 0 : _view$state$selection2.type.name) !== null && _view$state$selection !== void 0 ? _view$state$selection : view.state.doc.type.name;
|
|
375
375
|
slice = applyContainerNodeTransformToSlice(slice, schema, destinationParentType);
|
|
376
|
+
if (fg('platform_editor_paste_panel_c1_into_container')) {
|
|
377
|
+
slice = downgradePanelC1ForDestination(slice, schema, view.state.selection.$from);
|
|
378
|
+
}
|
|
376
379
|
}
|
|
377
380
|
slice = handleVSCodeBlock({
|
|
378
381
|
state: state,
|
|
@@ -27,7 +27,6 @@ import { Fragment, Node as PMNode, Slice } from '@atlaskit/editor-prosemirror/mo
|
|
|
27
27
|
import { AllSelection, NodeSelection, TextSelection } from '@atlaskit/editor-prosemirror/state';
|
|
28
28
|
import { canInsert, contains, findParentNodeOfType, findParentNodeOfTypeClosestToPos, hasParentNode, hasParentNodeOfType, safeInsert } from '@atlaskit/editor-prosemirror/utils';
|
|
29
29
|
import { replaceSelectedTable } from '@atlaskit/editor-tables/utils/replace-table';
|
|
30
|
-
import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
|
|
31
30
|
import { fg } from '@atlaskit/platform-feature-flags/fg';
|
|
32
31
|
import { closeHistory } from '@atlaskit/prosemirror-history/closeHistory';
|
|
33
32
|
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
|
|
@@ -589,6 +588,15 @@ export function handlePastePreservingMarks(slice, queueCardsFromChangedTr) {
|
|
|
589
588
|
function getSmartLinkAdf(_x, _x2, _x3) {
|
|
590
589
|
return _getSmartLinkAdf.apply(this, arguments);
|
|
591
590
|
}
|
|
591
|
+
/**
|
|
592
|
+
* Inserts the pasted content and then replaces it with `macro` as a separate transaction.
|
|
593
|
+
*
|
|
594
|
+
* The range the macro replaces is derived from the steps that were actually applied
|
|
595
|
+
* rather than from `slice.size`. `slice.size` is the slice's own measure and does not
|
|
596
|
+
* account for ProseMirror's fitting behaviour in `replaceRange`/`replaceSelection`, so
|
|
597
|
+
* the two can disagree — and when they do the macro would be inserted without removing
|
|
598
|
+
* the text it should replace, leaving both the pasted text and the macro in the document.
|
|
599
|
+
*/
|
|
592
600
|
function _getSmartLinkAdf() {
|
|
593
601
|
_getSmartLinkAdf = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(text, type, cardOptions) {
|
|
594
602
|
var provider;
|
|
@@ -617,46 +625,7 @@ function _getSmartLinkAdf() {
|
|
|
617
625
|
}));
|
|
618
626
|
return _getSmartLinkAdf.apply(this, arguments);
|
|
619
627
|
}
|
|
620
|
-
function
|
|
621
|
-
if (view) {
|
|
622
|
-
// insert the text or linkified/md-converted clipboard data
|
|
623
|
-
var selection = view.state.tr.selection;
|
|
624
|
-
var tr;
|
|
625
|
-
var before;
|
|
626
|
-
if (typeof from === 'number' && typeof to === 'number') {
|
|
627
|
-
tr = view.state.tr.replaceRange(from, to, slice);
|
|
628
|
-
before = tr.mapping.map(from, -1);
|
|
629
|
-
} else {
|
|
630
|
-
tr = view.state.tr.replaceSelection(slice);
|
|
631
|
-
before = tr.mapping.map(selection.from, -1);
|
|
632
|
-
}
|
|
633
|
-
view.dispatch(tr);
|
|
634
|
-
|
|
635
|
-
// replace the text with the macro as a separate transaction
|
|
636
|
-
// so the autoconversion generates 2 undo steps
|
|
637
|
-
var macroTr = closeHistory(view.state.tr).replaceRangeWith(before, before + slice.size, macro).scrollIntoView();
|
|
638
|
-
addLinkMetadata(view.state.selection, macroTr, {
|
|
639
|
-
inputMethod: INPUT_METHOD.CLIPBOARD,
|
|
640
|
-
cardAction: 'AUTO_CONVERT'
|
|
641
|
-
});
|
|
642
|
-
view.dispatch(macroTr);
|
|
643
|
-
return true;
|
|
644
|
-
}
|
|
645
|
-
return false;
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
/**
|
|
649
|
-
* Replacement for `insertAutoMacroOld` behind
|
|
650
|
-
* `platform_editor_paste_autoconvert_robustness`.
|
|
651
|
-
*
|
|
652
|
-
* Identical in shape, except that the range the macro replaces is derived from the steps
|
|
653
|
-
* that were actually applied rather than from `slice.size`. `slice.size` is the slice's
|
|
654
|
-
* own measure and does not account for ProseMirror's fitting behaviour in
|
|
655
|
-
* `replaceRange`/`replaceSelection`, so the two can disagree — and when they do the macro
|
|
656
|
-
* is inserted without removing the text it should replace, leaving both the pasted text
|
|
657
|
-
* and the macro in the document.
|
|
658
|
-
*/
|
|
659
|
-
function insertAutoMacroNew(slice, macro, view, from, to) {
|
|
628
|
+
function insertAutoMacro(slice, macro, view, from, to) {
|
|
660
629
|
if (!view) {
|
|
661
630
|
return false;
|
|
662
631
|
}
|
|
@@ -686,9 +655,6 @@ function insertAutoMacroNew(slice, macro, view, from, to) {
|
|
|
686
655
|
view.dispatch(macroTr);
|
|
687
656
|
return true;
|
|
688
657
|
}
|
|
689
|
-
function insertAutoMacro(slice, macro, view, from, to) {
|
|
690
|
-
return isExperimentEnabled('platform_editor_paste_autoconvert_robustness') ? insertAutoMacroNew(slice, macro, view, from, to) : insertAutoMacroOld(slice, macro, view, from, to);
|
|
691
|
-
}
|
|
692
658
|
|
|
693
659
|
/**
|
|
694
660
|
* Locates the range currently occupied by a link that we pasted earlier.
|
|
@@ -839,45 +805,27 @@ export function handleMacroAutoConvert(text, slice, queueCardsFromChangedTr, run
|
|
|
839
805
|
var trackingId = uuid();
|
|
840
806
|
var trackingFrom = "handleMacroAutoConvert-from-".concat(trackingId);
|
|
841
807
|
var trackingTo = "handleMacroAutoConvert-to-".concat(trackingId);
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
return true;
|
|
854
|
-
}
|
|
855
|
-
startTrackingPastedMacroPositions(_defineProperty(_defineProperty({}, trackingFrom, insertedRange.from), trackingTo, insertedRange.to))(view.state, dispatch);
|
|
856
|
-
getSmartLinkAdf(text, 'inline', cardsOptions).catch(function () {
|
|
857
|
-
// Smart links could not resolve the URL, so fall back to the macro.
|
|
858
|
-
// we use view.state rather than state because state becomes a stale
|
|
859
|
-
// state reference after getSmartLinkAdf's async work
|
|
860
|
-
var _getPastePluginState = getPastePluginState(view.state),
|
|
861
|
-
pastedMacroPositions = _getPastePluginState.pastedMacroPositions;
|
|
862
|
-
replacePastedLinkWithMacro(view, autoConvertMacro, text, pastedMacroPositions[trackingFrom], pastedMacroPositions[trackingTo], editorAnalyticsAPI);
|
|
863
|
-
}).finally(function () {
|
|
864
|
-
stopTrackingPastedMacroPositions([trackingFrom, trackingTo])(view.state, dispatch);
|
|
865
|
-
});
|
|
808
|
+
|
|
809
|
+
// Insert the pasted content straight away. The smart link provider is only
|
|
810
|
+
// consulted to decide whether the inserted link should later be swapped for
|
|
811
|
+
// a macro, so it does not need to gate the insert — otherwise every
|
|
812
|
+
// autoconvertible paste appears to do nothing until a network round trip
|
|
813
|
+
// completes.
|
|
814
|
+
var insertedRange;
|
|
815
|
+
handleMarkdownWithInsertedRange(slice, queueCardsFromChangedTr, function (range) {
|
|
816
|
+
insertedRange = range;
|
|
817
|
+
})(state, dispatch);
|
|
818
|
+
if (!insertedRange) {
|
|
866
819
|
return true;
|
|
867
820
|
}
|
|
868
|
-
startTrackingPastedMacroPositions(_defineProperty(_defineProperty({}, trackingFrom,
|
|
869
|
-
getSmartLinkAdf(text, 'inline', cardsOptions).
|
|
821
|
+
startTrackingPastedMacroPositions(_defineProperty(_defineProperty({}, trackingFrom, insertedRange.from), trackingTo, insertedRange.to))(view.state, dispatch);
|
|
822
|
+
getSmartLinkAdf(text, 'inline', cardsOptions).catch(function () {
|
|
823
|
+
// Smart links could not resolve the URL, so fall back to the macro.
|
|
870
824
|
// we use view.state rather than state because state becomes a stale
|
|
871
825
|
// state reference after getSmartLinkAdf's async work
|
|
872
|
-
var
|
|
873
|
-
pastedMacroPositions =
|
|
874
|
-
|
|
875
|
-
handleMarkdown(slice, queueCardsFromChangedTr, pastedMacroPositions[trackingFrom], pastedMacroPositions[trackingTo])(view.state, dispatch);
|
|
876
|
-
}
|
|
877
|
-
}).catch(function () {
|
|
878
|
-
var _getPastePluginState3 = getPastePluginState(view.state),
|
|
879
|
-
pastedMacroPositions = _getPastePluginState3.pastedMacroPositions;
|
|
880
|
-
insertAutoMacro(slice, macro, view, pastedMacroPositions[trackingFrom], pastedMacroPositions[trackingTo]);
|
|
826
|
+
var _getPastePluginState = getPastePluginState(view.state),
|
|
827
|
+
pastedMacroPositions = _getPastePluginState.pastedMacroPositions;
|
|
828
|
+
replacePastedLinkWithMacro(view, autoConvertMacro, text, pastedMacroPositions[trackingFrom], pastedMacroPositions[trackingTo], editorAnalyticsAPI);
|
|
881
829
|
}).finally(function () {
|
|
882
830
|
stopTrackingPastedMacroPositions([trackingFrom, trackingTo])(view.state, dispatch);
|
|
883
831
|
});
|
|
@@ -1183,8 +1131,7 @@ function resolveParagraphMarks(marks, destinationBlockMarkAttrs, shouldNormalize
|
|
|
1183
1131
|
}
|
|
1184
1132
|
|
|
1185
1133
|
/**
|
|
1186
|
-
* Variant of `handleMarkdown` used by macro auto-conversion
|
|
1187
|
-
* `platform_editor_paste_autoconvert_robustness`.
|
|
1134
|
+
* Variant of `handleMarkdown` used by macro auto-conversion.
|
|
1188
1135
|
*
|
|
1189
1136
|
* Differs in two ways: the inserted range is derived from the steps that were applied
|
|
1190
1137
|
* rather than from `markdownSlice.size`, which does not account for ProseMirror's fitting
|
|
@@ -1665,6 +1612,63 @@ export function applyContainerNodeTransformToSlice(slice, schema, destinationPar
|
|
|
1665
1612
|
}
|
|
1666
1613
|
}
|
|
1667
1614
|
|
|
1615
|
+
/**
|
|
1616
|
+
* Finds the type of the nearest ancestor of the paste position that can hold the panel in either
|
|
1617
|
+
* of its forms. That is the node a block-level panel would be placed into, which is not always the
|
|
1618
|
+
* direct parent of the cursor's textblock (e.g. a blockquote inside a table cell).
|
|
1619
|
+
*/
|
|
1620
|
+
function findNearestPanelHolderType($from, panelAsC1, panelAsPlain) {
|
|
1621
|
+
var panelAsC1Content = Fragment.from(panelAsC1);
|
|
1622
|
+
var panelAsPlainContent = Fragment.from(panelAsPlain);
|
|
1623
|
+
for (var depth = $from.depth; depth >= 0; depth--) {
|
|
1624
|
+
var ancestorType = $from.node(depth).type;
|
|
1625
|
+
if (ancestorType.validContent(panelAsC1Content) || ancestorType.validContent(panelAsPlainContent)) {
|
|
1626
|
+
return ancestorType;
|
|
1627
|
+
}
|
|
1628
|
+
}
|
|
1629
|
+
return undefined;
|
|
1630
|
+
}
|
|
1631
|
+
|
|
1632
|
+
/**
|
|
1633
|
+
* Turns top-level `panel_c1` children of the slice back into `panel` when the nearest ancestor of
|
|
1634
|
+
* the paste position that can hold a panel accepts `panel` but not `panel_c1`. Only panels whose
|
|
1635
|
+
* content is valid for a plain `panel` are changed, that is content without the containers only
|
|
1636
|
+
* `panel_c1` allows: tables (`platform_editor_nest_table_in_panel`), and expands, nested panels and
|
|
1637
|
+
* other containers when `platform_editor_nest_container_in_panel` is on.
|
|
1638
|
+
*
|
|
1639
|
+
* A partial copy from a top-level panel is re-wrapped as `panel_c1` from the clipboard context, and
|
|
1640
|
+
* a wrapper the destination cannot hold makes the paste insert the panel after the container (e.g.
|
|
1641
|
+
* below a table) instead of pasting the text where the cursor is.
|
|
1642
|
+
*/
|
|
1643
|
+
export function downgradePanelC1ForDestination(slice, schema, $from) {
|
|
1644
|
+
var _schema$nodes4 = schema.nodes,
|
|
1645
|
+
panel = _schema$nodes4.panel,
|
|
1646
|
+
panel_c1 = _schema$nodes4.panel_c1;
|
|
1647
|
+
if (!panel || !panel_c1) {
|
|
1648
|
+
return slice;
|
|
1649
|
+
}
|
|
1650
|
+
var isDowngraded = false;
|
|
1651
|
+
var children = [];
|
|
1652
|
+
slice.content.forEach(function (child) {
|
|
1653
|
+
if (child.type !== panel_c1 || !panel.validContent(child.content)) {
|
|
1654
|
+
children.push(child);
|
|
1655
|
+
return;
|
|
1656
|
+
}
|
|
1657
|
+
var plainPanel = panel.create(child.attrs, child.content, child.marks.filter(function (mark) {
|
|
1658
|
+
return panel.allowsMarkType(mark.type);
|
|
1659
|
+
}));
|
|
1660
|
+
var holderType = findNearestPanelHolderType($from, child, plainPanel);
|
|
1661
|
+
var holderOnlyAcceptsPlainPanel = !!holderType && !holderType.validContent(Fragment.from(child)) && holderType.validContent(Fragment.from(plainPanel));
|
|
1662
|
+
if (holderOnlyAcceptsPlainPanel) {
|
|
1663
|
+
isDowngraded = true;
|
|
1664
|
+
children.push(plainPanel);
|
|
1665
|
+
return;
|
|
1666
|
+
}
|
|
1667
|
+
children.push(child);
|
|
1668
|
+
});
|
|
1669
|
+
return isDowngraded ? new Slice(Fragment.fromArray(children), slice.openStart, slice.openEnd) : slice;
|
|
1670
|
+
}
|
|
1671
|
+
|
|
1668
1672
|
/*
|
|
1669
1673
|
* When platform_editor_nest_table_in_panel is OFF, move table elements out of panel divs in the
|
|
1670
1674
|
* clipboard HTML before ProseMirror parses it. This prevents the panel schema from
|
|
@@ -7,7 +7,7 @@ import type { Command } from '@atlaskit/editor-common/types/command';
|
|
|
7
7
|
import type { RunMacroAutoConvert } from '@atlaskit/editor-plugin-extension/extensionPluginType';
|
|
8
8
|
import type { FindRootParentListNode } from '@atlaskit/editor-plugin-list/types';
|
|
9
9
|
import type { InsertMediaAsMediaSingle } from '@atlaskit/editor-plugin-media/types';
|
|
10
|
-
import type { Schema } from '@atlaskit/editor-prosemirror/model';
|
|
10
|
+
import type { ResolvedPos, Schema } from '@atlaskit/editor-prosemirror/model';
|
|
11
11
|
import { Slice } from '@atlaskit/editor-prosemirror/model';
|
|
12
12
|
import type { EditorState, Selection } from '@atlaskit/editor-prosemirror/state';
|
|
13
13
|
export declare function handleMention(slice: Slice, schema: Schema): Slice;
|
|
@@ -61,4 +61,16 @@ export declare function checkTaskListInList(state: EditorState, slice: Slice): b
|
|
|
61
61
|
export declare function checkIfSelectionInNestedList(state: EditorState): boolean;
|
|
62
62
|
export declare function handlePasteExpand(slice: Slice): Slice;
|
|
63
63
|
export declare function applyContainerNodeTransformToSlice(slice: Slice, schema: Schema, destinationParentType: string): Slice;
|
|
64
|
+
/**
|
|
65
|
+
* Turns top-level `panel_c1` children of the slice back into `panel` when the nearest ancestor of
|
|
66
|
+
* the paste position that can hold a panel accepts `panel` but not `panel_c1`. Only panels whose
|
|
67
|
+
* content is valid for a plain `panel` are changed, that is content without the containers only
|
|
68
|
+
* `panel_c1` allows: tables (`platform_editor_nest_table_in_panel`), and expands, nested panels and
|
|
69
|
+
* other containers when `platform_editor_nest_container_in_panel` is on.
|
|
70
|
+
*
|
|
71
|
+
* A partial copy from a top-level panel is re-wrapped as `panel_c1` from the clipboard context, and
|
|
72
|
+
* a wrapper the destination cannot hold makes the paste insert the panel after the container (e.g.
|
|
73
|
+
* below a table) instead of pasting the text where the cursor is.
|
|
74
|
+
*/
|
|
75
|
+
export declare function downgradePanelC1ForDestination(slice: Slice, schema: Schema, $from: ResolvedPos): Slice;
|
|
64
76
|
export declare function splitTablesOutOfPanelHtml(html: string): string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/editor-plugin-paste",
|
|
3
|
-
"version": "31.
|
|
3
|
+
"version": "31.2.0",
|
|
4
4
|
"description": "Paste plugin for @atlaskit/editor-core",
|
|
5
5
|
"author": "Atlassian Pty Ltd",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"@atlaskit/platform-feature-experiments": "^0.3.0",
|
|
45
45
|
"@atlaskit/platform-feature-flags": "^2.2.0",
|
|
46
46
|
"@atlaskit/prosemirror-history": "^1.3.0",
|
|
47
|
-
"@atlaskit/tmp-editor-statsig": "^
|
|
47
|
+
"@atlaskit/tmp-editor-statsig": "^258.0.0",
|
|
48
48
|
"@atlaskit/tokens": "^20.9.0",
|
|
49
49
|
"@babel/runtime": "^7.0.0",
|
|
50
50
|
"lodash": "^4.17.21",
|
|
@@ -77,12 +77,9 @@
|
|
|
77
77
|
},
|
|
78
78
|
"platform_editor_paste_strip_invalid_block_marks": {
|
|
79
79
|
"type": "boolean"
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
"platform_editor_paste_autoconvert_robustness": {
|
|
84
|
-
"param": "isEnabled",
|
|
85
|
-
"defaultValue": false
|
|
80
|
+
},
|
|
81
|
+
"platform_editor_paste_panel_c1_into_container": {
|
|
82
|
+
"type": "boolean"
|
|
86
83
|
}
|
|
87
84
|
}
|
|
88
85
|
}
|