@atlaskit/editor-plugin-paste 13.3.20 → 13.4.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 CHANGED
@@ -1,5 +1,21 @@
1
1
  # @atlaskit/editor-plugin-paste
2
2
 
3
+ ## 13.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`6e4030f86d5b6`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/6e4030f86d5b6) -
8
+ Fix copy/paste of partial text selected from inside a table nested in a panel (panel_c1)
9
+ re-wrapping the pasted text in a panel and table. The paste plugin now treats panel_c1 as a panel
10
+ variant everywhere it special-cases panels, so the existing panel paste handling strips the open
11
+ panel/table boundary. Gated behind platform_editor_nest_table_in_panel.
12
+
13
+ ### Patch Changes
14
+
15
+ - [`7d2c4ad5f91a2`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/7d2c4ad5f91a2) -
16
+ Clean up experiment `improve_3p_smart_link_resolve_rate`
17
+ - Updated dependencies
18
+
3
19
  ## 13.3.20
4
20
 
5
21
  ### Patch Changes
@@ -52,15 +52,16 @@ var isInsideBlockQuote = exports.isInsideBlockQuote = function isInsideBlockQuot
52
52
  return (0, _utils2.hasParentNodeOfType)(blockquote)(state.selection);
53
53
  };
54
54
  var enableNewDomainCheckToImproveSmartLinkResolveRate = function enableNewDomainCheckToImproveSmartLinkResolveRate(hostname) {
55
- return (0, _expValEquals.expValEquals)('improve_3p_smart_link_resolve_rate', 'isEnabled', true) && (
56
- // OneDrive Shortlinks
57
- hostname.endsWith('1drv.ms') ||
58
- // MS Teams links
59
- hostname.endsWith('teams.live.com') || hostname.endsWith('teams.cloud.microsoft') || hostname.endsWith('teams.microsoft.com') ||
60
- // MS Power BI
61
- hostname.endsWith('powerbi.com') ||
62
- // MS Azure devops
63
- hostname.endsWith('dev.azure.com') || hostname.endsWith('visualstudio.com'));
55
+ return (
56
+ // OneDrive Shortlinks
57
+ hostname.endsWith('1drv.ms') ||
58
+ // MS Teams links
59
+ hostname.endsWith('teams.live.com') || hostname.endsWith('teams.cloud.microsoft') || hostname.endsWith('teams.microsoft.com') ||
60
+ // MS Power BI
61
+ hostname.endsWith('powerbi.com') ||
62
+ // MS Azure devops
63
+ hostname.endsWith('dev.azure.com') || hostname.endsWith('visualstudio.com')
64
+ );
64
65
  };
65
66
  var PASTE = 'Editor Paste Plugin Paste Duration';
66
67
  function isSharePointUrl(url) {
@@ -160,7 +161,7 @@ function createPlugin(schema, dispatchAnalyticsEvent, dispatch, featureFlags, pl
160
161
  },
161
162
  // note
162
163
  handlePaste: function handlePaste(view, rawEvent, slice) {
163
- var _text, _schema$nodes, _schema$nodes2, _schema$nodes3, _pluginInjectionApi$m, _schema$nodes$table;
164
+ var _text, _schema$nodes, _schema$nodes2, _schema$nodes3, _schema$nodes4, _schema$nodes5, _schema$nodes6, _schema$nodes7, _pluginInjectionApi$m, _schema$nodes$table;
164
165
  var event = rawEvent;
165
166
  if (!event.clipboardData) {
166
167
  return false;
@@ -432,7 +433,9 @@ function createPlugin(schema, dispatchAnalyticsEvent, dispatch, featureFlags, pl
432
433
  var selectionDepth = state.selection.$head.depth;
433
434
  var selectionParentNode = state.selection.$head.node(selectionDepth - 1);
434
435
  var selectionParentType = selectionParentNode === null || selectionParentNode === void 0 ? void 0 : selectionParentNode.type;
435
- var edgeCaseNodeTypes = [(_schema$nodes = schema.nodes) === null || _schema$nodes === void 0 ? void 0 : _schema$nodes.panel, (_schema$nodes2 = schema.nodes) === null || _schema$nodes2 === void 0 ? void 0 : _schema$nodes2.taskList, (_schema$nodes3 = schema.nodes) === null || _schema$nodes3 === void 0 ? void 0 : _schema$nodes3.decisionList];
436
+ // panel_c1 is a schema variant of panel (table-in-panel); when the experiment is on,
437
+ // handle it the same way as a panel.
438
+ var edgeCaseNodeTypes = (0, _expValEquals.expValEquals)('platform_editor_nest_table_in_panel', 'isEnabled', true) ? [(_schema$nodes = schema.nodes) === null || _schema$nodes === void 0 ? void 0 : _schema$nodes.panel, (_schema$nodes2 = schema.nodes) === null || _schema$nodes2 === void 0 ? void 0 : _schema$nodes2.panel_c1, (_schema$nodes3 = schema.nodes) === null || _schema$nodes3 === void 0 ? void 0 : _schema$nodes3.taskList, (_schema$nodes4 = schema.nodes) === null || _schema$nodes4 === void 0 ? void 0 : _schema$nodes4.decisionList] : [(_schema$nodes5 = schema.nodes) === null || _schema$nodes5 === void 0 ? void 0 : _schema$nodes5.panel, (_schema$nodes6 = schema.nodes) === null || _schema$nodes6 === void 0 ? void 0 : _schema$nodes6.taskList, (_schema$nodes7 = schema.nodes) === null || _schema$nodes7 === void 0 ? void 0 : _schema$nodes7.decisionList];
436
439
  if (slice.openStart === 0 && slice.openEnd !== 1 && selectionParentNode && edgeCaseNodeTypes.includes(selectionParentType)) {
437
440
  // @ts-ignore - [unblock prosemirror bump] assigning to readonly prop
438
441
  slice.openStart = 1;
@@ -42,6 +42,7 @@ var _mark = require("@atlaskit/editor-common/mark");
42
42
  var _nesting = require("@atlaskit/editor-common/nesting");
43
43
  var _selection = require("@atlaskit/editor-common/selection");
44
44
  var _utils = require("@atlaskit/editor-common/utils");
45
+ var _nodeTypeUtils = require("@atlaskit/editor-common/utils/node-type-utils");
45
46
  var _model = require("@atlaskit/editor-prosemirror/model");
46
47
  var _state = require("@atlaskit/editor-prosemirror/state");
47
48
  var _utils2 = require("@atlaskit/editor-prosemirror/utils");
@@ -107,7 +108,7 @@ function handleMention(slice, schema) {
107
108
  }
108
109
  function handlePasteIntoTaskOrDecisionOrPanel(slice, queueCardsFromChangedTr) {
109
110
  return function (state, dispatch) {
110
- var _slice$content$firstC, _slice$content$firstC2, _slice$content$firstC3, _transformedSlice$con, _transformedSlice$con2;
111
+ var _slice$content$firstC, _slice$content$firstC2, _panelNode$type, _transformedSlice$con, _transformedSlice$con2;
111
112
  var schema = state.schema,
112
113
  selection = state.tr.selection;
113
114
  var codeMark = schema.marks.code,
@@ -120,6 +121,7 @@ function handlePasteIntoTaskOrDecisionOrPanel(slice, queueCardsFromChangedTr) {
120
121
  taskItem = _schema$nodes.taskItem,
121
122
  text = _schema$nodes.text,
122
123
  panel = _schema$nodes.panel,
124
+ panel_c1 = _schema$nodes.panel_c1,
123
125
  bulletList = _schema$nodes.bulletList,
124
126
  orderedList = _schema$nodes.orderedList,
125
127
  taskList = _schema$nodes.taskList,
@@ -128,12 +130,17 @@ function handlePasteIntoTaskOrDecisionOrPanel(slice, queueCardsFromChangedTr) {
128
130
  heading = _schema$nodes.heading,
129
131
  codeBlock = _schema$nodes.codeBlock;
130
132
  var selectionIsValidNode = state.selection instanceof _state.NodeSelection && ['decisionList', 'decisionItem', 'taskList', 'taskItem'].includes(state.selection.node.type.name);
131
- var selectionHasValidParentNode = (0, _utils2.hasParentNodeOfType)([decisionItem, taskItem, panel])(state.selection);
133
+ // panel_c1 is a schema variant of panel (used when a table is nested inside a panel). When the
134
+ // experiment is on we must handle it anywhere we special-case a panel, otherwise partial
135
+ // selections copied from inside a table-in-panel are treated as a foreign container and
136
+ // re-wrapped on paste.
137
+ var selectionHasValidParentNode = (0, _expValEquals.expValEquals)('platform_editor_nest_table_in_panel', 'isEnabled', true) ? (0, _utils2.hasParentNodeOfType)([decisionItem, taskItem, panel, panel_c1].filter(Boolean))(state.selection) : (0, _utils2.hasParentNodeOfType)([decisionItem, taskItem, panel])(state.selection);
132
138
  var selectionIsCodeBlock = (0, _utils2.hasParentNodeOfType)([codeBlock])(state.selection);
133
139
  var selectionIsListItem = (0, _utils2.hasParentNodeOfType)([listItem])(state.selection);
134
140
  var panelNode = (0, _index.isSelectionInsidePanel)(selection);
135
141
  var selectionIsPanel = Boolean(panelNode);
136
- var isSliceWholePanel = ((_slice$content$firstC = slice.content.firstChild) === null || _slice$content$firstC === void 0 ? void 0 : _slice$content$firstC.type) === panel && slice.openStart === 0 && slice.openEnd === 0;
142
+ var sliceFirstChildIsPanel = (0, _expValEquals.expValEquals)('platform_editor_nest_table_in_panel', 'isEnabled', true) ? !!slice.content.firstChild && (0, _nodeTypeUtils.getBaseNodeTypeName)(slice.content.firstChild.type) === 'panel' : ((_slice$content$firstC = slice.content.firstChild) === null || _slice$content$firstC === void 0 ? void 0 : _slice$content$firstC.type) === panel;
143
+ var isSliceWholePanel = sliceFirstChildIsPanel && slice.openStart === 0 && slice.openEnd === 0;
137
144
 
138
145
  // we avoid handling codeBlock-in-panel use case in this function
139
146
  // returning false will allow code to flow into `handleCodeBlock` function
@@ -175,18 +182,21 @@ function handlePasteIntoTaskOrDecisionOrPanel(slice, queueCardsFromChangedTr) {
175
182
  var transformedSlice = compose.apply(null, filters)(slice);
176
183
  var isFirstChildTaskNode = transformedSlice.content.firstChild.type === taskList || transformedSlice.content.firstChild.type === taskItem;
177
184
  var tr = (0, _prosemirrorHistory.closeHistory)(state.tr);
178
- if (panelNode && sliceHasTask && ((_slice$content$firstC3 = slice.content.firstChild) === null || _slice$content$firstC3 === void 0 ? void 0 : _slice$content$firstC3.type) === panel && (0, _index.isEmptyNode)(panelNode) && selection.$from.node() === selection.$to.node()) {
185
+ if (panelNode && sliceHasTask && sliceFirstChildIsPanel && (0, _index.isEmptyNode)(panelNode) && selection.$from.node() === selection.$to.node()) {
179
186
  return Boolean((0, _lists2.insertSliceInsideOfPanelNodeSelected)(panelNode)({
180
187
  tr: tr,
181
188
  slice: slice
182
189
  }));
183
190
  }
184
- var transformedSliceIsValidNode = (transformedSlice.content.firstChild.type.inlineContent || ['decisionList', 'decisionItem', 'taskItem', 'taskList', 'panel'].includes(transformedSlice.content.firstChild.type.name)) && (!(0, _utils.isInListItem)(state) || (0, _utils.isInListItem)(state) && isFirstChildTaskNode);
191
+ var transformedSliceIsValidNode = (0, _expValEquals.expValEquals)('platform_editor_nest_table_in_panel', 'isEnabled', true) ? (transformedSlice.content.firstChild.type.inlineContent || ['decisionList', 'decisionItem', 'taskItem', 'taskList', 'panel'].includes((0, _nodeTypeUtils.getBaseNodeTypeName)(transformedSlice.content.firstChild.type))) && (!(0, _utils.isInListItem)(state) || (0, _utils.isInListItem)(state) && isFirstChildTaskNode) : (transformedSlice.content.firstChild.type.inlineContent || ['decisionList', 'decisionItem', 'taskItem', 'taskList', 'panel'].includes(transformedSlice.content.firstChild.type.name)) && (!(0, _utils.isInListItem)(state) || (0, _utils.isInListItem)(state) && isFirstChildTaskNode);
185
192
  // If the slice or the selection are valid nodes to handle,
186
193
  // and the slice is not a whole node (i.e. openStart is 1 and openEnd is 0)
187
194
  // or the slice's first node is a paragraph,
188
195
  // then we can replace the selection with our slice.
189
- var pastingIntoExtendedPanel = selectionIsPanel && panel.validContent(transformedSlice.content);
196
+ // When the experiment is on, validate against the actual destination panel variant (panel or
197
+ // panel_c1) since their content expressions differ (panel_c1 additionally allows a nested
198
+ // table).
199
+ var pastingIntoExtendedPanel = (0, _expValEquals.expValEquals)('platform_editor_nest_table_in_panel', 'isEnabled', true) ? selectionIsPanel && ((_panelNode$type = panelNode === null || panelNode === void 0 ? void 0 : panelNode.type) !== null && _panelNode$type !== void 0 ? _panelNode$type : panel).validContent(transformedSlice.content) : selectionIsPanel && panel.validContent(transformedSlice.content);
190
200
 
191
201
  // A task slice carrying its own open taskList wrapper would, on a plain replaceSelection,
192
202
  // nest that wrapper inside the current item and add an extra taskList level. Unwrapping one
@@ -210,7 +220,7 @@ function handlePasteIntoTaskOrDecisionOrPanel(slice, queueCardsFromChangedTr) {
210
220
  //tr.replaceSelection(transformedSlice).scrollIntoView();
211
221
  tr.replaceSelection(new _model.Slice(transformedSlice.content, 0, transformedSlice.openEnd)).scrollIntoView();
212
222
  } else if (['mediaSingle'].includes(transformedSlice.content.firstChild.type.name) && selectionIsPanel) {
213
- var parentNode = (0, _utils2.findParentNodeOfType)(panel)(selection);
223
+ var parentNode = (0, _expValEquals.expValEquals)('platform_editor_nest_table_in_panel', 'isEnabled', true) ? (0, _utils2.findParentNodeOfType)([panel, panel_c1].filter(Boolean))(selection) : (0, _utils2.findParentNodeOfType)(panel)(selection);
214
224
  if (selectionIsPanel && parentNode && (0, _utils.isNodeEmpty)(parentNode.node)) {
215
225
  tr.insert(selection.$from.pos, transformedSlice.content).scrollIntoView();
216
226
  // Place the cursor at the the end of the insersertion
@@ -247,7 +257,7 @@ function handlePasteIntoTaskOrDecisionOrPanel(slice, queueCardsFromChangedTr) {
247
257
  }
248
258
  function handlePasteNonNestableBlockNodesIntoList(slice) {
249
259
  return function (state, dispatch) {
250
- var _tr$doc$nodeAt, _slice$content$firstC4, _sliceContent$firstCh, _findParentNodeOfType;
260
+ var _tr$doc$nodeAt, _slice$content$firstC3, _sliceContent$firstCh, _findParentNodeOfType;
251
261
  var tr = state.tr;
252
262
  var selection = tr.selection;
253
263
  var $from = selection.$from,
@@ -314,7 +324,7 @@ function handlePasteNonNestableBlockNodesIntoList(slice) {
314
324
  }
315
325
 
316
326
  // handle the insertion of the slice
317
- if (((_slice$content$firstC4 = slice.content.firstChild) === null || _slice$content$firstC4 === void 0 ? void 0 : _slice$content$firstC4.type.name) === 'blockquote' && (0, _utils2.contains)(slice.content.firstChild, state.schema.nodes.listItem)) {
327
+ if (((_slice$content$firstC3 = slice.content.firstChild) === null || _slice$content$firstC3 === void 0 ? void 0 : _slice$content$firstC3.type.name) === 'blockquote' && (0, _utils2.contains)(slice.content.firstChild, state.schema.nodes.listItem)) {
318
328
  (0, _edgeCases.insertSliceInsideBlockquote)({
319
329
  tr: tr,
320
330
  slice: slice
@@ -380,6 +390,7 @@ var doesSelectionWhichStartsOrEndsInListContainEntireList = exports.doesSelectio
380
390
  };
381
391
  function handlePastePanelOrDecisionContentIntoList(slice, findRootParentListNode) {
382
392
  return function (state, dispatch) {
393
+ var _blockNode$type$name;
383
394
  var schema = state.schema,
384
395
  tr = state.tr;
385
396
  var selection = tr.selection;
@@ -388,7 +399,10 @@ function handlePastePanelOrDecisionContentIntoList(slice, findRootParentListNode
388
399
  var isSliceWholeNode = slice.openStart === 0 && slice.openEnd === 0;
389
400
  var selectionParentListItemNode = selection.$to.node(selection.$to.depth - 1);
390
401
  var sliceIsWholeNodeButShouldNotReplaceSelection = isSliceWholeNode && !doesSelectionWhichStartsOrEndsInListContainEntireList(selection, findRootParentListNode);
391
- if (!selectionParentListItemNode || (selectionParentListItemNode === null || selectionParentListItemNode === void 0 ? void 0 : selectionParentListItemNode.type) !== schema.nodes.listItem || !blockNode || !['panel', 'decisionList'].includes(blockNode === null || blockNode === void 0 ? void 0 : blockNode.type.name) || slice.content.childCount > 1 || (blockNode === null || blockNode === void 0 ? void 0 : blockNode.content.firstChild) === undefined || sliceIsWholeNodeButShouldNotReplaceSelection) {
402
+
403
+ // When the experiment is on, treat panel_c1 (table-in-panel variant) like a panel.
404
+ var blockNodeIsPanelOrDecision = (0, _expValEquals.expValEquals)('platform_editor_nest_table_in_panel', 'isEnabled', true) ? ['panel', 'decisionList'].includes(blockNode ? (0, _nodeTypeUtils.getBaseNodeTypeName)(blockNode.type) : '') : ['panel', 'decisionList'].includes((_blockNode$type$name = blockNode === null || blockNode === void 0 ? void 0 : blockNode.type.name) !== null && _blockNode$type$name !== void 0 ? _blockNode$type$name : '');
405
+ if (!selectionParentListItemNode || (selectionParentListItemNode === null || selectionParentListItemNode === void 0 ? void 0 : selectionParentListItemNode.type) !== schema.nodes.listItem || !blockNode || !blockNodeIsPanelOrDecision || slice.content.childCount > 1 || (blockNode === null || blockNode === void 0 ? void 0 : blockNode.content.firstChild) === undefined || sliceIsWholeNodeButShouldNotReplaceSelection) {
392
406
  return false;
393
407
  }
394
408
 
@@ -1152,6 +1166,7 @@ function handleRichText(slice, queueCardsFromChangedTr) {
1152
1166
  heading = _state$schema$nodes4.heading,
1153
1167
  paragraph = _state$schema$nodes4.paragraph,
1154
1168
  panel = _state$schema$nodes4.panel,
1169
+ panel_c1 = _state$schema$nodes4.panel_c1,
1155
1170
  bulletList = _state$schema$nodes4.bulletList,
1156
1171
  orderedList = _state$schema$nodes4.orderedList;
1157
1172
  var fontSize = state.schema.marks.fontSize;
@@ -1199,7 +1214,8 @@ function handleRichText(slice, queueCardsFromChangedTr) {
1199
1214
  var textNodes = [heading, paragraph];
1200
1215
  var selectionParent = selection.$to.node(selection.$to.depth - 1);
1201
1216
  var noNeedForSafeInsert = selection.$to.node().type.validContent(slice.content) || textNodes.includes(selection.$to.node().type) && selectionParent.type.validContent(slice.content);
1202
- var panelParentOverCurrentSelection = (0, _utils2.findParentNodeOfType)(panel)(tr.selection);
1217
+ // panel_c1 is a schema variant of panel; when the experiment is on, treat both together.
1218
+ var panelParentOverCurrentSelection = (0, _expValEquals.expValEquals)('platform_editor_nest_table_in_panel', 'isEnabled', true) ? (0, _utils2.findParentNodeOfType)([panel, panel_c1].filter(Boolean))(tr.selection) : (0, _utils2.findParentNodeOfType)(panel)(tr.selection);
1203
1219
  var isTargetPanelEmpty = panelParentOverCurrentSelection && ((_panelParentOverCurre = panelParentOverCurrentSelection.node) === null || _panelParentOverCurre === void 0 ? void 0 : _panelParentOverCurre.content.size) === 2;
1204
1220
  if (!isSliceContentTaskListNodes && (isSliceContentListNodes || isTargetPanelEmpty)) {
1205
1221
  (0, _edgeCases.insertSliceForLists)({
@@ -1221,7 +1237,7 @@ function handleRichText(slice, queueCardsFromChangedTr) {
1221
1237
  // when cursor is inside a table cell, and slice.content.lastChild is a panel, expand, or decisionList
1222
1238
  // need to make sure the cursor position is is right after the panel, expand, or decisionList
1223
1239
  // still in the same table cell, see issue: https://product-fabric.atlassian.net/browse/ED-17862
1224
- var shouldUpdateCursorPosAfterPaste = ['panel', 'nestedExpand', 'decisionList', 'codeBlock'].includes(((_slice$content$lastCh = slice.content.lastChild) === null || _slice$content$lastCh === void 0 || (_slice$content$lastCh = _slice$content$lastCh.type) === null || _slice$content$lastCh === void 0 ? void 0 : _slice$content$lastCh.name) || '');
1240
+ var shouldUpdateCursorPosAfterPaste = (0, _expValEquals.expValEquals)('platform_editor_nest_table_in_panel', 'isEnabled', true) ? ['panel', 'nestedExpand', 'decisionList', 'codeBlock'].includes(slice.content.lastChild ? (0, _nodeTypeUtils.getBaseNodeTypeName)(slice.content.lastChild.type) : '') : ['panel', 'nestedExpand', 'decisionList', 'codeBlock'].includes(((_slice$content$lastCh = slice.content.lastChild) === null || _slice$content$lastCh === void 0 || (_slice$content$lastCh = _slice$content$lastCh.type) === null || _slice$content$lastCh === void 0 ? void 0 : _slice$content$lastCh.name) || '');
1225
1241
  var lastChild = slice.content.lastChild;
1226
1242
  var $nextPos = tr.doc.resolve(tr.mapping.map(selection.from));
1227
1243
  var nextSelection = lastChild !== null && lastChild !== void 0 && lastChild.type.isTextblock ? _state.TextSelection.findFrom($nextPos, -1, true) : new _selection.GapCursorSelection($nextPos, _selection.Side.RIGHT);
@@ -1377,8 +1393,8 @@ var handleSelectedTable = exports.handleSelectedTable = function handleSelectedT
1377
1393
  };
1378
1394
  };
1379
1395
  function checkTaskListInList(state, slice) {
1380
- var _slice$content$firstC5;
1381
- return Boolean((0, _utils.isInListItem)(state) && ['taskList', 'taskItem'].includes(((_slice$content$firstC5 = slice.content.firstChild) === null || _slice$content$firstC5 === void 0 || (_slice$content$firstC5 = _slice$content$firstC5.type) === null || _slice$content$firstC5 === void 0 ? void 0 : _slice$content$firstC5.name) || ''));
1396
+ var _slice$content$firstC4;
1397
+ return Boolean((0, _utils.isInListItem)(state) && ['taskList', 'taskItem'].includes(((_slice$content$firstC4 = slice.content.firstChild) === null || _slice$content$firstC4 === void 0 || (_slice$content$firstC4 = _slice$content$firstC4.type) === null || _slice$content$firstC4 === void 0 ? void 0 : _slice$content$firstC4.name) || ''));
1382
1398
  }
1383
1399
  function checkIfSelectionInNestedList(state) {
1384
1400
  var selection = state.selection,
@@ -23,12 +23,14 @@ var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers
23
23
  var _analytics = require("@atlaskit/editor-common/analytics");
24
24
  var _legacyRankPlugins = require("@atlaskit/editor-common/legacy-rank-plugins");
25
25
  var _utils = require("@atlaskit/editor-common/utils");
26
+ var _nodeTypeUtils = require("@atlaskit/editor-common/utils/node-type-utils");
26
27
  var _model = require("@atlaskit/editor-prosemirror/model");
27
28
  var _state = require("@atlaskit/editor-prosemirror/state");
28
29
  var _utils2 = require("@atlaskit/editor-prosemirror/utils");
29
30
  var _utils3 = require("@atlaskit/editor-tables/utils");
30
31
  var _mediaClient = require("@atlaskit/media-client");
31
32
  var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
33
+ var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals");
32
34
  // Ignored via go/ees005
33
35
  // eslint-disable-next-line require-unicode-regexp
34
36
  var HTML_CONTAINS_SINGLE_FILE_REGEX = /<img .*>/;
@@ -224,14 +226,23 @@ function isCursorSelectionAtTextStartOrEnd(selection) {
224
226
  return selection instanceof _state.TextSelection && selection.empty && selection.$cursor && (!selection.$cursor.nodeBefore || !selection.$cursor.nodeAfter);
225
227
  }
226
228
  function isPanelNode(node) {
229
+ // panel_c1 is a schema variant of panel (used when a table is nested inside a panel). When the
230
+ // experiment is on, treat it as a panel too.
231
+ if ((0, _expValEquals.expValEquals)('platform_editor_nest_table_in_panel', 'isEnabled', true)) {
232
+ return Boolean(node && (0, _nodeTypeUtils.getBaseNodeTypeName)(node.type) === 'panel');
233
+ }
227
234
  return Boolean(node && node.type.name === 'panel');
228
235
  }
229
236
  function isSelectionInsidePanel(selection) {
230
237
  if (selection instanceof _state.NodeSelection && isPanelNode(selection.node)) {
231
238
  return selection.node;
232
239
  }
233
- var panel = selection.$from.doc.type.schema.nodes.panel;
234
- var panelPosition = (0, _utils2.findParentNodeOfType)(panel)(selection);
240
+ var _selection$$from$doc$ = selection.$from.doc.type.schema.nodes,
241
+ panel = _selection$$from$doc$.panel,
242
+ panel_c1 = _selection$$from$doc$.panel_c1;
243
+
244
+ // When the experiment is on, also match panel_c1 (table-in-panel variant).
245
+ var panelPosition = (0, _expValEquals.expValEquals)('platform_editor_nest_table_in_panel', 'isEnabled', true) ? (0, _utils2.findParentNodeOfType)([panel, panel_c1].filter(Boolean))(selection) : (0, _utils2.findParentNodeOfType)(panel)(selection);
235
246
  if (panelPosition) {
236
247
  return panelPosition.node;
237
248
  }
@@ -41,15 +41,16 @@ export const isInsideBlockQuote = state => {
41
41
  return hasParentNodeOfType(blockquote)(state.selection);
42
42
  };
43
43
  const enableNewDomainCheckToImproveSmartLinkResolveRate = hostname => {
44
- return expValEquals('improve_3p_smart_link_resolve_rate', 'isEnabled', true) && (
45
- // OneDrive Shortlinks
46
- hostname.endsWith('1drv.ms') ||
47
- // MS Teams links
48
- hostname.endsWith('teams.live.com') || hostname.endsWith('teams.cloud.microsoft') || hostname.endsWith('teams.microsoft.com') ||
49
- // MS Power BI
50
- hostname.endsWith('powerbi.com') ||
51
- // MS Azure devops
52
- hostname.endsWith('dev.azure.com') || hostname.endsWith('visualstudio.com'));
44
+ return (
45
+ // OneDrive Shortlinks
46
+ hostname.endsWith('1drv.ms') ||
47
+ // MS Teams links
48
+ hostname.endsWith('teams.live.com') || hostname.endsWith('teams.cloud.microsoft') || hostname.endsWith('teams.microsoft.com') ||
49
+ // MS Power BI
50
+ hostname.endsWith('powerbi.com') ||
51
+ // MS Azure devops
52
+ hostname.endsWith('dev.azure.com') || hostname.endsWith('visualstudio.com')
53
+ );
53
54
  };
54
55
  const PASTE = 'Editor Paste Plugin Paste Duration';
55
56
  export function isSharePointUrl(url) {
@@ -125,7 +126,7 @@ export function createPlugin(schema, dispatchAnalyticsEvent, dispatch, featureFl
125
126
  },
126
127
  // note
127
128
  handlePaste(view, rawEvent, slice) {
128
- var _text, _schema$nodes, _schema$nodes2, _schema$nodes3, _pluginInjectionApi$m, _schema$nodes$table;
129
+ var _text, _schema$nodes, _schema$nodes2, _schema$nodes3, _schema$nodes4, _schema$nodes5, _schema$nodes6, _schema$nodes7, _pluginInjectionApi$m, _schema$nodes$table;
129
130
  const event = rawEvent;
130
131
  if (!event.clipboardData) {
131
132
  return false;
@@ -391,7 +392,9 @@ export function createPlugin(schema, dispatchAnalyticsEvent, dispatch, featureFl
391
392
  const selectionDepth = state.selection.$head.depth;
392
393
  const selectionParentNode = state.selection.$head.node(selectionDepth - 1);
393
394
  const selectionParentType = selectionParentNode === null || selectionParentNode === void 0 ? void 0 : selectionParentNode.type;
394
- const edgeCaseNodeTypes = [(_schema$nodes = schema.nodes) === null || _schema$nodes === void 0 ? void 0 : _schema$nodes.panel, (_schema$nodes2 = schema.nodes) === null || _schema$nodes2 === void 0 ? void 0 : _schema$nodes2.taskList, (_schema$nodes3 = schema.nodes) === null || _schema$nodes3 === void 0 ? void 0 : _schema$nodes3.decisionList];
395
+ // panel_c1 is a schema variant of panel (table-in-panel); when the experiment is on,
396
+ // handle it the same way as a panel.
397
+ const edgeCaseNodeTypes = expValEquals('platform_editor_nest_table_in_panel', 'isEnabled', true) ? [(_schema$nodes = schema.nodes) === null || _schema$nodes === void 0 ? void 0 : _schema$nodes.panel, (_schema$nodes2 = schema.nodes) === null || _schema$nodes2 === void 0 ? void 0 : _schema$nodes2.panel_c1, (_schema$nodes3 = schema.nodes) === null || _schema$nodes3 === void 0 ? void 0 : _schema$nodes3.taskList, (_schema$nodes4 = schema.nodes) === null || _schema$nodes4 === void 0 ? void 0 : _schema$nodes4.decisionList] : [(_schema$nodes5 = schema.nodes) === null || _schema$nodes5 === void 0 ? void 0 : _schema$nodes5.panel, (_schema$nodes6 = schema.nodes) === null || _schema$nodes6 === void 0 ? void 0 : _schema$nodes6.taskList, (_schema$nodes7 = schema.nodes) === null || _schema$nodes7 === void 0 ? void 0 : _schema$nodes7.decisionList];
395
398
  if (slice.openStart === 0 && slice.openEnd !== 1 && selectionParentNode && edgeCaseNodeTypes.includes(selectionParentType)) {
396
399
  // @ts-ignore - [unblock prosemirror bump] assigning to readonly prop
397
400
  slice.openStart = 1;
@@ -9,6 +9,7 @@ import { anyMarkActive } from '@atlaskit/editor-common/mark';
9
9
  import { getParentOfTypeCount, getPositionAfterTopParentNodeOfType } from '@atlaskit/editor-common/nesting';
10
10
  import { GapCursorSelection, Side } from '@atlaskit/editor-common/selection';
11
11
  import { canLinkBeCreatedInRange, insideTableCell, isInListItem, isLinkMark, isListItemNode, isListNode, isNodeEmpty, isParagraph, isText, linkifyContent, mapSlice } from '@atlaskit/editor-common/utils';
12
+ import { getBaseNodeTypeName } from '@atlaskit/editor-common/utils/node-type-utils';
12
13
  import { Fragment, Node as PMNode, Slice } from '@atlaskit/editor-prosemirror/model';
13
14
  import { AllSelection, NodeSelection, TextSelection } from '@atlaskit/editor-prosemirror/state';
14
15
  import { canInsert, contains, findParentNodeOfType, findParentNodeOfTypeClosestToPos, hasParentNode, hasParentNodeOfType, safeInsert } from '@atlaskit/editor-prosemirror/utils';
@@ -67,7 +68,7 @@ export function handleMention(slice, schema) {
67
68
  }
68
69
  export function handlePasteIntoTaskOrDecisionOrPanel(slice, queueCardsFromChangedTr) {
69
70
  return (state, dispatch) => {
70
- var _slice$content$firstC, _slice$content$firstC2, _slice$content$firstC3, _transformedSlice$con, _transformedSlice$con2;
71
+ var _slice$content$firstC, _slice$content$firstC2, _panelNode$type, _transformedSlice$con, _transformedSlice$con2;
71
72
  const {
72
73
  schema,
73
74
  tr: {
@@ -87,6 +88,7 @@ export function handlePasteIntoTaskOrDecisionOrPanel(slice, queueCardsFromChange
87
88
  taskItem,
88
89
  text,
89
90
  panel,
91
+ panel_c1,
90
92
  bulletList,
91
93
  orderedList,
92
94
  taskList,
@@ -97,12 +99,17 @@ export function handlePasteIntoTaskOrDecisionOrPanel(slice, queueCardsFromChange
97
99
  }
98
100
  } = schema;
99
101
  const selectionIsValidNode = state.selection instanceof NodeSelection && ['decisionList', 'decisionItem', 'taskList', 'taskItem'].includes(state.selection.node.type.name);
100
- const selectionHasValidParentNode = hasParentNodeOfType([decisionItem, taskItem, panel])(state.selection);
102
+ // panel_c1 is a schema variant of panel (used when a table is nested inside a panel). When the
103
+ // experiment is on we must handle it anywhere we special-case a panel, otherwise partial
104
+ // selections copied from inside a table-in-panel are treated as a foreign container and
105
+ // re-wrapped on paste.
106
+ const selectionHasValidParentNode = expValEquals('platform_editor_nest_table_in_panel', 'isEnabled', true) ? hasParentNodeOfType([decisionItem, taskItem, panel, panel_c1].filter(Boolean))(state.selection) : hasParentNodeOfType([decisionItem, taskItem, panel])(state.selection);
101
107
  const selectionIsCodeBlock = hasParentNodeOfType([codeBlock])(state.selection);
102
108
  const selectionIsListItem = hasParentNodeOfType([listItem])(state.selection);
103
109
  const panelNode = isSelectionInsidePanel(selection);
104
110
  const selectionIsPanel = Boolean(panelNode);
105
- const isSliceWholePanel = ((_slice$content$firstC = slice.content.firstChild) === null || _slice$content$firstC === void 0 ? void 0 : _slice$content$firstC.type) === panel && slice.openStart === 0 && slice.openEnd === 0;
111
+ const sliceFirstChildIsPanel = expValEquals('platform_editor_nest_table_in_panel', 'isEnabled', true) ? !!slice.content.firstChild && getBaseNodeTypeName(slice.content.firstChild.type) === 'panel' : ((_slice$content$firstC = slice.content.firstChild) === null || _slice$content$firstC === void 0 ? void 0 : _slice$content$firstC.type) === panel;
112
+ const isSliceWholePanel = sliceFirstChildIsPanel && slice.openStart === 0 && slice.openEnd === 0;
106
113
 
107
114
  // we avoid handling codeBlock-in-panel use case in this function
108
115
  // returning false will allow code to flow into `handleCodeBlock` function
@@ -142,18 +149,21 @@ export function handlePasteIntoTaskOrDecisionOrPanel(slice, queueCardsFromChange
142
149
  const transformedSlice = compose.apply(null, filters)(slice);
143
150
  const isFirstChildTaskNode = transformedSlice.content.firstChild.type === taskList || transformedSlice.content.firstChild.type === taskItem;
144
151
  const tr = closeHistory(state.tr);
145
- if (panelNode && sliceHasTask && ((_slice$content$firstC3 = slice.content.firstChild) === null || _slice$content$firstC3 === void 0 ? void 0 : _slice$content$firstC3.type) === panel && isEmptyNode(panelNode) && selection.$from.node() === selection.$to.node()) {
152
+ if (panelNode && sliceHasTask && sliceFirstChildIsPanel && isEmptyNode(panelNode) && selection.$from.node() === selection.$to.node()) {
146
153
  return Boolean(insertSliceInsideOfPanelNodeSelected(panelNode)({
147
154
  tr,
148
155
  slice
149
156
  }));
150
157
  }
151
- const transformedSliceIsValidNode = (transformedSlice.content.firstChild.type.inlineContent || ['decisionList', 'decisionItem', 'taskItem', 'taskList', 'panel'].includes(transformedSlice.content.firstChild.type.name)) && (!isInListItem(state) || isInListItem(state) && isFirstChildTaskNode);
158
+ const transformedSliceIsValidNode = expValEquals('platform_editor_nest_table_in_panel', 'isEnabled', true) ? (transformedSlice.content.firstChild.type.inlineContent || ['decisionList', 'decisionItem', 'taskItem', 'taskList', 'panel'].includes(getBaseNodeTypeName(transformedSlice.content.firstChild.type))) && (!isInListItem(state) || isInListItem(state) && isFirstChildTaskNode) : (transformedSlice.content.firstChild.type.inlineContent || ['decisionList', 'decisionItem', 'taskItem', 'taskList', 'panel'].includes(transformedSlice.content.firstChild.type.name)) && (!isInListItem(state) || isInListItem(state) && isFirstChildTaskNode);
152
159
  // If the slice or the selection are valid nodes to handle,
153
160
  // and the slice is not a whole node (i.e. openStart is 1 and openEnd is 0)
154
161
  // or the slice's first node is a paragraph,
155
162
  // then we can replace the selection with our slice.
156
- const pastingIntoExtendedPanel = selectionIsPanel && panel.validContent(transformedSlice.content);
163
+ // When the experiment is on, validate against the actual destination panel variant (panel or
164
+ // panel_c1) since their content expressions differ (panel_c1 additionally allows a nested
165
+ // table).
166
+ const pastingIntoExtendedPanel = expValEquals('platform_editor_nest_table_in_panel', 'isEnabled', true) ? selectionIsPanel && ((_panelNode$type = panelNode === null || panelNode === void 0 ? void 0 : panelNode.type) !== null && _panelNode$type !== void 0 ? _panelNode$type : panel).validContent(transformedSlice.content) : selectionIsPanel && panel.validContent(transformedSlice.content);
157
167
 
158
168
  // A task slice carrying its own open taskList wrapper would, on a plain replaceSelection,
159
169
  // nest that wrapper inside the current item and add an extra taskList level. Unwrapping one
@@ -177,7 +187,7 @@ export function handlePasteIntoTaskOrDecisionOrPanel(slice, queueCardsFromChange
177
187
  //tr.replaceSelection(transformedSlice).scrollIntoView();
178
188
  tr.replaceSelection(new Slice(transformedSlice.content, 0, transformedSlice.openEnd)).scrollIntoView();
179
189
  } else if (['mediaSingle'].includes(transformedSlice.content.firstChild.type.name) && selectionIsPanel) {
180
- const parentNode = findParentNodeOfType(panel)(selection);
190
+ const parentNode = expValEquals('platform_editor_nest_table_in_panel', 'isEnabled', true) ? findParentNodeOfType([panel, panel_c1].filter(Boolean))(selection) : findParentNodeOfType(panel)(selection);
181
191
  if (selectionIsPanel && parentNode && isNodeEmpty(parentNode.node)) {
182
192
  tr.insert(selection.$from.pos, transformedSlice.content).scrollIntoView();
183
193
  // Place the cursor at the the end of the insersertion
@@ -214,7 +224,7 @@ export function handlePasteIntoTaskOrDecisionOrPanel(slice, queueCardsFromChange
214
224
  }
215
225
  export function handlePasteNonNestableBlockNodesIntoList(slice) {
216
226
  return (state, dispatch) => {
217
- var _tr$doc$nodeAt, _slice$content$firstC4, _sliceContent$firstCh, _findParentNodeOfType;
227
+ var _tr$doc$nodeAt, _slice$content$firstC3, _sliceContent$firstCh, _findParentNodeOfType;
218
228
  const {
219
229
  tr
220
230
  } = state;
@@ -288,7 +298,7 @@ export function handlePasteNonNestableBlockNodesIntoList(slice) {
288
298
  }
289
299
 
290
300
  // handle the insertion of the slice
291
- if (((_slice$content$firstC4 = slice.content.firstChild) === null || _slice$content$firstC4 === void 0 ? void 0 : _slice$content$firstC4.type.name) === 'blockquote' && contains(slice.content.firstChild, state.schema.nodes.listItem)) {
301
+ if (((_slice$content$firstC3 = slice.content.firstChild) === null || _slice$content$firstC3 === void 0 ? void 0 : _slice$content$firstC3.type.name) === 'blockquote' && contains(slice.content.firstChild, state.schema.nodes.listItem)) {
292
302
  insertSliceInsideBlockquote({
293
303
  tr,
294
304
  slice
@@ -357,6 +367,7 @@ export const doesSelectionWhichStartsOrEndsInListContainEntireList = (selection,
357
367
  };
358
368
  export function handlePastePanelOrDecisionContentIntoList(slice, findRootParentListNode) {
359
369
  return (state, dispatch) => {
370
+ var _blockNode$type$name;
360
371
  const {
361
372
  schema,
362
373
  tr
@@ -369,7 +380,10 @@ export function handlePastePanelOrDecisionContentIntoList(slice, findRootParentL
369
380
  const isSliceWholeNode = slice.openStart === 0 && slice.openEnd === 0;
370
381
  const selectionParentListItemNode = selection.$to.node(selection.$to.depth - 1);
371
382
  const sliceIsWholeNodeButShouldNotReplaceSelection = isSliceWholeNode && !doesSelectionWhichStartsOrEndsInListContainEntireList(selection, findRootParentListNode);
372
- if (!selectionParentListItemNode || (selectionParentListItemNode === null || selectionParentListItemNode === void 0 ? void 0 : selectionParentListItemNode.type) !== schema.nodes.listItem || !blockNode || !['panel', 'decisionList'].includes(blockNode === null || blockNode === void 0 ? void 0 : blockNode.type.name) || slice.content.childCount > 1 || (blockNode === null || blockNode === void 0 ? void 0 : blockNode.content.firstChild) === undefined || sliceIsWholeNodeButShouldNotReplaceSelection) {
383
+
384
+ // When the experiment is on, treat panel_c1 (table-in-panel variant) like a panel.
385
+ const blockNodeIsPanelOrDecision = expValEquals('platform_editor_nest_table_in_panel', 'isEnabled', true) ? ['panel', 'decisionList'].includes(blockNode ? getBaseNodeTypeName(blockNode.type) : '') : ['panel', 'decisionList'].includes((_blockNode$type$name = blockNode === null || blockNode === void 0 ? void 0 : blockNode.type.name) !== null && _blockNode$type$name !== void 0 ? _blockNode$type$name : '');
386
+ if (!selectionParentListItemNode || (selectionParentListItemNode === null || selectionParentListItemNode === void 0 ? void 0 : selectionParentListItemNode.type) !== schema.nodes.listItem || !blockNode || !blockNodeIsPanelOrDecision || slice.content.childCount > 1 || (blockNode === null || blockNode === void 0 ? void 0 : blockNode.content.firstChild) === undefined || sliceIsWholeNodeButShouldNotReplaceSelection) {
373
387
  return false;
374
388
  }
375
389
 
@@ -1124,6 +1138,7 @@ export function handleRichText(slice, queueCardsFromChangedTr) {
1124
1138
  heading,
1125
1139
  paragraph,
1126
1140
  panel,
1141
+ panel_c1,
1127
1142
  bulletList,
1128
1143
  orderedList
1129
1144
  } = state.schema.nodes;
@@ -1174,7 +1189,8 @@ export function handleRichText(slice, queueCardsFromChangedTr) {
1174
1189
  const textNodes = [heading, paragraph];
1175
1190
  const selectionParent = selection.$to.node(selection.$to.depth - 1);
1176
1191
  const noNeedForSafeInsert = selection.$to.node().type.validContent(slice.content) || textNodes.includes(selection.$to.node().type) && selectionParent.type.validContent(slice.content);
1177
- const panelParentOverCurrentSelection = findParentNodeOfType(panel)(tr.selection);
1192
+ // panel_c1 is a schema variant of panel; when the experiment is on, treat both together.
1193
+ const panelParentOverCurrentSelection = expValEquals('platform_editor_nest_table_in_panel', 'isEnabled', true) ? findParentNodeOfType([panel, panel_c1].filter(Boolean))(tr.selection) : findParentNodeOfType(panel)(tr.selection);
1178
1194
  const isTargetPanelEmpty = panelParentOverCurrentSelection && ((_panelParentOverCurre = panelParentOverCurrentSelection.node) === null || _panelParentOverCurre === void 0 ? void 0 : _panelParentOverCurre.content.size) === 2;
1179
1195
  if (!isSliceContentTaskListNodes && (isSliceContentListNodes || isTargetPanelEmpty)) {
1180
1196
  insertSliceForLists({
@@ -1196,7 +1212,7 @@ export function handleRichText(slice, queueCardsFromChangedTr) {
1196
1212
  // when cursor is inside a table cell, and slice.content.lastChild is a panel, expand, or decisionList
1197
1213
  // need to make sure the cursor position is is right after the panel, expand, or decisionList
1198
1214
  // still in the same table cell, see issue: https://product-fabric.atlassian.net/browse/ED-17862
1199
- const shouldUpdateCursorPosAfterPaste = ['panel', 'nestedExpand', 'decisionList', 'codeBlock'].includes(((_slice$content$lastCh = slice.content.lastChild) === null || _slice$content$lastCh === void 0 ? void 0 : (_slice$content$lastCh2 = _slice$content$lastCh.type) === null || _slice$content$lastCh2 === void 0 ? void 0 : _slice$content$lastCh2.name) || '');
1215
+ const shouldUpdateCursorPosAfterPaste = expValEquals('platform_editor_nest_table_in_panel', 'isEnabled', true) ? ['panel', 'nestedExpand', 'decisionList', 'codeBlock'].includes(slice.content.lastChild ? getBaseNodeTypeName(slice.content.lastChild.type) : '') : ['panel', 'nestedExpand', 'decisionList', 'codeBlock'].includes(((_slice$content$lastCh = slice.content.lastChild) === null || _slice$content$lastCh === void 0 ? void 0 : (_slice$content$lastCh2 = _slice$content$lastCh.type) === null || _slice$content$lastCh2 === void 0 ? void 0 : _slice$content$lastCh2.name) || '');
1200
1216
  const lastChild = slice.content.lastChild;
1201
1217
  const $nextPos = tr.doc.resolve(tr.mapping.map(selection.from));
1202
1218
  const nextSelection = lastChild !== null && lastChild !== void 0 && lastChild.type.isTextblock ? TextSelection.findFrom($nextPos, -1, true) : new GapCursorSelection($nextPos, Side.RIGHT);
@@ -1339,8 +1355,8 @@ export const handleSelectedTable = editorAnalyticsAPI => slice => (state, dispat
1339
1355
  return false;
1340
1356
  };
1341
1357
  export function checkTaskListInList(state, slice) {
1342
- var _slice$content$firstC5, _slice$content$firstC6;
1343
- return Boolean(isInListItem(state) && ['taskList', 'taskItem'].includes(((_slice$content$firstC5 = slice.content.firstChild) === null || _slice$content$firstC5 === void 0 ? void 0 : (_slice$content$firstC6 = _slice$content$firstC5.type) === null || _slice$content$firstC6 === void 0 ? void 0 : _slice$content$firstC6.name) || ''));
1358
+ var _slice$content$firstC4, _slice$content$firstC5;
1359
+ return Boolean(isInListItem(state) && ['taskList', 'taskItem'].includes(((_slice$content$firstC4 = slice.content.firstChild) === null || _slice$content$firstC4 === void 0 ? void 0 : (_slice$content$firstC5 = _slice$content$firstC4.type) === null || _slice$content$firstC5 === void 0 ? void 0 : _slice$content$firstC5.name) || ''));
1344
1360
  }
1345
1361
  export function checkIfSelectionInNestedList(state) {
1346
1362
  const {
@@ -1,12 +1,14 @@
1
1
  import { ACTION_SUBJECT, EVENT_TYPE, INPUT_METHOD, TABLE_ACTION } from '@atlaskit/editor-common/analytics';
2
2
  import { sortByOrderWithTypeName } from '@atlaskit/editor-common/legacy-rank-plugins';
3
3
  import { isSupportedInParent, mapChildren } from '@atlaskit/editor-common/utils';
4
+ import { getBaseNodeTypeName } from '@atlaskit/editor-common/utils/node-type-utils';
4
5
  import { Fragment, Mark, Slice } from '@atlaskit/editor-prosemirror/model';
5
6
  import { NodeSelection, TextSelection } from '@atlaskit/editor-prosemirror/state';
6
7
  import { findParentNodeOfType } from '@atlaskit/editor-prosemirror/utils';
7
8
  import { getSelectedTableInfo, isTableSelected } from '@atlaskit/editor-tables/utils';
8
9
  import { isMediaBlobUrl } from '@atlaskit/media-client';
9
10
  import { fg } from '@atlaskit/platform-feature-flags';
11
+ import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
10
12
 
11
13
  // Ignored via go/ees005
12
14
  // eslint-disable-next-line require-unicode-regexp
@@ -205,6 +207,11 @@ export function isCursorSelectionAtTextStartOrEnd(selection) {
205
207
  return selection instanceof TextSelection && selection.empty && selection.$cursor && (!selection.$cursor.nodeBefore || !selection.$cursor.nodeAfter);
206
208
  }
207
209
  export function isPanelNode(node) {
210
+ // panel_c1 is a schema variant of panel (used when a table is nested inside a panel). When the
211
+ // experiment is on, treat it as a panel too.
212
+ if (expValEquals('platform_editor_nest_table_in_panel', 'isEnabled', true)) {
213
+ return Boolean(node && getBaseNodeTypeName(node.type) === 'panel');
214
+ }
208
215
  return Boolean(node && node.type.name === 'panel');
209
216
  }
210
217
  export function isSelectionInsidePanel(selection) {
@@ -216,13 +223,16 @@ export function isSelectionInsidePanel(selection) {
216
223
  type: {
217
224
  schema: {
218
225
  nodes: {
219
- panel
226
+ panel,
227
+ panel_c1
220
228
  }
221
229
  }
222
230
  }
223
231
  }
224
232
  } = selection.$from;
225
- const panelPosition = findParentNodeOfType(panel)(selection);
233
+
234
+ // When the experiment is on, also match panel_c1 (table-in-panel variant).
235
+ const panelPosition = expValEquals('platform_editor_nest_table_in_panel', 'isEnabled', true) ? findParentNodeOfType([panel, panel_c1].filter(Boolean))(selection) : findParentNodeOfType(panel)(selection);
226
236
  if (panelPosition) {
227
237
  return panelPosition.node;
228
238
  }
@@ -44,15 +44,16 @@ export var isInsideBlockQuote = function isInsideBlockQuote(state) {
44
44
  return hasParentNodeOfType(blockquote)(state.selection);
45
45
  };
46
46
  var enableNewDomainCheckToImproveSmartLinkResolveRate = function enableNewDomainCheckToImproveSmartLinkResolveRate(hostname) {
47
- return expValEquals('improve_3p_smart_link_resolve_rate', 'isEnabled', true) && (
48
- // OneDrive Shortlinks
49
- hostname.endsWith('1drv.ms') ||
50
- // MS Teams links
51
- hostname.endsWith('teams.live.com') || hostname.endsWith('teams.cloud.microsoft') || hostname.endsWith('teams.microsoft.com') ||
52
- // MS Power BI
53
- hostname.endsWith('powerbi.com') ||
54
- // MS Azure devops
55
- hostname.endsWith('dev.azure.com') || hostname.endsWith('visualstudio.com'));
47
+ return (
48
+ // OneDrive Shortlinks
49
+ hostname.endsWith('1drv.ms') ||
50
+ // MS Teams links
51
+ hostname.endsWith('teams.live.com') || hostname.endsWith('teams.cloud.microsoft') || hostname.endsWith('teams.microsoft.com') ||
52
+ // MS Power BI
53
+ hostname.endsWith('powerbi.com') ||
54
+ // MS Azure devops
55
+ hostname.endsWith('dev.azure.com') || hostname.endsWith('visualstudio.com')
56
+ );
56
57
  };
57
58
  var PASTE = 'Editor Paste Plugin Paste Duration';
58
59
  export function isSharePointUrl(url) {
@@ -152,7 +153,7 @@ export function createPlugin(schema, dispatchAnalyticsEvent, dispatch, featureFl
152
153
  },
153
154
  // note
154
155
  handlePaste: function handlePaste(view, rawEvent, slice) {
155
- var _text, _schema$nodes, _schema$nodes2, _schema$nodes3, _pluginInjectionApi$m, _schema$nodes$table;
156
+ var _text, _schema$nodes, _schema$nodes2, _schema$nodes3, _schema$nodes4, _schema$nodes5, _schema$nodes6, _schema$nodes7, _pluginInjectionApi$m, _schema$nodes$table;
156
157
  var event = rawEvent;
157
158
  if (!event.clipboardData) {
158
159
  return false;
@@ -424,7 +425,9 @@ export function createPlugin(schema, dispatchAnalyticsEvent, dispatch, featureFl
424
425
  var selectionDepth = state.selection.$head.depth;
425
426
  var selectionParentNode = state.selection.$head.node(selectionDepth - 1);
426
427
  var selectionParentType = selectionParentNode === null || selectionParentNode === void 0 ? void 0 : selectionParentNode.type;
427
- var edgeCaseNodeTypes = [(_schema$nodes = schema.nodes) === null || _schema$nodes === void 0 ? void 0 : _schema$nodes.panel, (_schema$nodes2 = schema.nodes) === null || _schema$nodes2 === void 0 ? void 0 : _schema$nodes2.taskList, (_schema$nodes3 = schema.nodes) === null || _schema$nodes3 === void 0 ? void 0 : _schema$nodes3.decisionList];
428
+ // panel_c1 is a schema variant of panel (table-in-panel); when the experiment is on,
429
+ // handle it the same way as a panel.
430
+ var edgeCaseNodeTypes = expValEquals('platform_editor_nest_table_in_panel', 'isEnabled', true) ? [(_schema$nodes = schema.nodes) === null || _schema$nodes === void 0 ? void 0 : _schema$nodes.panel, (_schema$nodes2 = schema.nodes) === null || _schema$nodes2 === void 0 ? void 0 : _schema$nodes2.panel_c1, (_schema$nodes3 = schema.nodes) === null || _schema$nodes3 === void 0 ? void 0 : _schema$nodes3.taskList, (_schema$nodes4 = schema.nodes) === null || _schema$nodes4 === void 0 ? void 0 : _schema$nodes4.decisionList] : [(_schema$nodes5 = schema.nodes) === null || _schema$nodes5 === void 0 ? void 0 : _schema$nodes5.panel, (_schema$nodes6 = schema.nodes) === null || _schema$nodes6 === void 0 ? void 0 : _schema$nodes6.taskList, (_schema$nodes7 = schema.nodes) === null || _schema$nodes7 === void 0 ? void 0 : _schema$nodes7.decisionList];
428
431
  if (slice.openStart === 0 && slice.openEnd !== 1 && selectionParentNode && edgeCaseNodeTypes.includes(selectionParentType)) {
429
432
  // @ts-ignore - [unblock prosemirror bump] assigning to readonly prop
430
433
  slice.openStart = 1;
@@ -17,6 +17,7 @@ import { anyMarkActive } from '@atlaskit/editor-common/mark';
17
17
  import { getParentOfTypeCount, getPositionAfterTopParentNodeOfType } from '@atlaskit/editor-common/nesting';
18
18
  import { GapCursorSelection, Side } from '@atlaskit/editor-common/selection';
19
19
  import { canLinkBeCreatedInRange, insideTableCell, isInListItem, isLinkMark, isListItemNode, isListNode, isNodeEmpty, isParagraph, isText, linkifyContent, mapSlice } from '@atlaskit/editor-common/utils';
20
+ import { getBaseNodeTypeName } from '@atlaskit/editor-common/utils/node-type-utils';
20
21
  import { Fragment, Node as PMNode, Slice } from '@atlaskit/editor-prosemirror/model';
21
22
  import { AllSelection, NodeSelection, TextSelection } from '@atlaskit/editor-prosemirror/state';
22
23
  import { canInsert, contains, findParentNodeOfType, findParentNodeOfTypeClosestToPos, hasParentNode, hasParentNodeOfType, safeInsert } from '@atlaskit/editor-prosemirror/utils';
@@ -78,7 +79,7 @@ export function handleMention(slice, schema) {
78
79
  }
79
80
  export function handlePasteIntoTaskOrDecisionOrPanel(slice, queueCardsFromChangedTr) {
80
81
  return function (state, dispatch) {
81
- var _slice$content$firstC, _slice$content$firstC2, _slice$content$firstC3, _transformedSlice$con, _transformedSlice$con2;
82
+ var _slice$content$firstC, _slice$content$firstC2, _panelNode$type, _transformedSlice$con, _transformedSlice$con2;
82
83
  var schema = state.schema,
83
84
  selection = state.tr.selection;
84
85
  var codeMark = schema.marks.code,
@@ -91,6 +92,7 @@ export function handlePasteIntoTaskOrDecisionOrPanel(slice, queueCardsFromChange
91
92
  taskItem = _schema$nodes.taskItem,
92
93
  text = _schema$nodes.text,
93
94
  panel = _schema$nodes.panel,
95
+ panel_c1 = _schema$nodes.panel_c1,
94
96
  bulletList = _schema$nodes.bulletList,
95
97
  orderedList = _schema$nodes.orderedList,
96
98
  taskList = _schema$nodes.taskList,
@@ -99,12 +101,17 @@ export function handlePasteIntoTaskOrDecisionOrPanel(slice, queueCardsFromChange
99
101
  heading = _schema$nodes.heading,
100
102
  codeBlock = _schema$nodes.codeBlock;
101
103
  var selectionIsValidNode = state.selection instanceof NodeSelection && ['decisionList', 'decisionItem', 'taskList', 'taskItem'].includes(state.selection.node.type.name);
102
- var selectionHasValidParentNode = hasParentNodeOfType([decisionItem, taskItem, panel])(state.selection);
104
+ // panel_c1 is a schema variant of panel (used when a table is nested inside a panel). When the
105
+ // experiment is on we must handle it anywhere we special-case a panel, otherwise partial
106
+ // selections copied from inside a table-in-panel are treated as a foreign container and
107
+ // re-wrapped on paste.
108
+ var selectionHasValidParentNode = expValEquals('platform_editor_nest_table_in_panel', 'isEnabled', true) ? hasParentNodeOfType([decisionItem, taskItem, panel, panel_c1].filter(Boolean))(state.selection) : hasParentNodeOfType([decisionItem, taskItem, panel])(state.selection);
103
109
  var selectionIsCodeBlock = hasParentNodeOfType([codeBlock])(state.selection);
104
110
  var selectionIsListItem = hasParentNodeOfType([listItem])(state.selection);
105
111
  var panelNode = isSelectionInsidePanel(selection);
106
112
  var selectionIsPanel = Boolean(panelNode);
107
- var isSliceWholePanel = ((_slice$content$firstC = slice.content.firstChild) === null || _slice$content$firstC === void 0 ? void 0 : _slice$content$firstC.type) === panel && slice.openStart === 0 && slice.openEnd === 0;
113
+ var sliceFirstChildIsPanel = expValEquals('platform_editor_nest_table_in_panel', 'isEnabled', true) ? !!slice.content.firstChild && getBaseNodeTypeName(slice.content.firstChild.type) === 'panel' : ((_slice$content$firstC = slice.content.firstChild) === null || _slice$content$firstC === void 0 ? void 0 : _slice$content$firstC.type) === panel;
114
+ var isSliceWholePanel = sliceFirstChildIsPanel && slice.openStart === 0 && slice.openEnd === 0;
108
115
 
109
116
  // we avoid handling codeBlock-in-panel use case in this function
110
117
  // returning false will allow code to flow into `handleCodeBlock` function
@@ -146,18 +153,21 @@ export function handlePasteIntoTaskOrDecisionOrPanel(slice, queueCardsFromChange
146
153
  var transformedSlice = compose.apply(null, filters)(slice);
147
154
  var isFirstChildTaskNode = transformedSlice.content.firstChild.type === taskList || transformedSlice.content.firstChild.type === taskItem;
148
155
  var tr = closeHistory(state.tr);
149
- if (panelNode && sliceHasTask && ((_slice$content$firstC3 = slice.content.firstChild) === null || _slice$content$firstC3 === void 0 ? void 0 : _slice$content$firstC3.type) === panel && isEmptyNode(panelNode) && selection.$from.node() === selection.$to.node()) {
156
+ if (panelNode && sliceHasTask && sliceFirstChildIsPanel && isEmptyNode(panelNode) && selection.$from.node() === selection.$to.node()) {
150
157
  return Boolean(insertSliceInsideOfPanelNodeSelected(panelNode)({
151
158
  tr: tr,
152
159
  slice: slice
153
160
  }));
154
161
  }
155
- var transformedSliceIsValidNode = (transformedSlice.content.firstChild.type.inlineContent || ['decisionList', 'decisionItem', 'taskItem', 'taskList', 'panel'].includes(transformedSlice.content.firstChild.type.name)) && (!isInListItem(state) || isInListItem(state) && isFirstChildTaskNode);
162
+ var transformedSliceIsValidNode = expValEquals('platform_editor_nest_table_in_panel', 'isEnabled', true) ? (transformedSlice.content.firstChild.type.inlineContent || ['decisionList', 'decisionItem', 'taskItem', 'taskList', 'panel'].includes(getBaseNodeTypeName(transformedSlice.content.firstChild.type))) && (!isInListItem(state) || isInListItem(state) && isFirstChildTaskNode) : (transformedSlice.content.firstChild.type.inlineContent || ['decisionList', 'decisionItem', 'taskItem', 'taskList', 'panel'].includes(transformedSlice.content.firstChild.type.name)) && (!isInListItem(state) || isInListItem(state) && isFirstChildTaskNode);
156
163
  // If the slice or the selection are valid nodes to handle,
157
164
  // and the slice is not a whole node (i.e. openStart is 1 and openEnd is 0)
158
165
  // or the slice's first node is a paragraph,
159
166
  // then we can replace the selection with our slice.
160
- var pastingIntoExtendedPanel = selectionIsPanel && panel.validContent(transformedSlice.content);
167
+ // When the experiment is on, validate against the actual destination panel variant (panel or
168
+ // panel_c1) since their content expressions differ (panel_c1 additionally allows a nested
169
+ // table).
170
+ var pastingIntoExtendedPanel = expValEquals('platform_editor_nest_table_in_panel', 'isEnabled', true) ? selectionIsPanel && ((_panelNode$type = panelNode === null || panelNode === void 0 ? void 0 : panelNode.type) !== null && _panelNode$type !== void 0 ? _panelNode$type : panel).validContent(transformedSlice.content) : selectionIsPanel && panel.validContent(transformedSlice.content);
161
171
 
162
172
  // A task slice carrying its own open taskList wrapper would, on a plain replaceSelection,
163
173
  // nest that wrapper inside the current item and add an extra taskList level. Unwrapping one
@@ -181,7 +191,7 @@ export function handlePasteIntoTaskOrDecisionOrPanel(slice, queueCardsFromChange
181
191
  //tr.replaceSelection(transformedSlice).scrollIntoView();
182
192
  tr.replaceSelection(new Slice(transformedSlice.content, 0, transformedSlice.openEnd)).scrollIntoView();
183
193
  } else if (['mediaSingle'].includes(transformedSlice.content.firstChild.type.name) && selectionIsPanel) {
184
- var parentNode = findParentNodeOfType(panel)(selection);
194
+ var parentNode = expValEquals('platform_editor_nest_table_in_panel', 'isEnabled', true) ? findParentNodeOfType([panel, panel_c1].filter(Boolean))(selection) : findParentNodeOfType(panel)(selection);
185
195
  if (selectionIsPanel && parentNode && isNodeEmpty(parentNode.node)) {
186
196
  tr.insert(selection.$from.pos, transformedSlice.content).scrollIntoView();
187
197
  // Place the cursor at the the end of the insersertion
@@ -218,7 +228,7 @@ export function handlePasteIntoTaskOrDecisionOrPanel(slice, queueCardsFromChange
218
228
  }
219
229
  export function handlePasteNonNestableBlockNodesIntoList(slice) {
220
230
  return function (state, dispatch) {
221
- var _tr$doc$nodeAt, _slice$content$firstC4, _sliceContent$firstCh, _findParentNodeOfType;
231
+ var _tr$doc$nodeAt, _slice$content$firstC3, _sliceContent$firstCh, _findParentNodeOfType;
222
232
  var tr = state.tr;
223
233
  var selection = tr.selection;
224
234
  var $from = selection.$from,
@@ -285,7 +295,7 @@ export function handlePasteNonNestableBlockNodesIntoList(slice) {
285
295
  }
286
296
 
287
297
  // handle the insertion of the slice
288
- if (((_slice$content$firstC4 = slice.content.firstChild) === null || _slice$content$firstC4 === void 0 ? void 0 : _slice$content$firstC4.type.name) === 'blockquote' && contains(slice.content.firstChild, state.schema.nodes.listItem)) {
298
+ if (((_slice$content$firstC3 = slice.content.firstChild) === null || _slice$content$firstC3 === void 0 ? void 0 : _slice$content$firstC3.type.name) === 'blockquote' && contains(slice.content.firstChild, state.schema.nodes.listItem)) {
289
299
  insertSliceInsideBlockquote({
290
300
  tr: tr,
291
301
  slice: slice
@@ -351,6 +361,7 @@ export var doesSelectionWhichStartsOrEndsInListContainEntireList = function does
351
361
  };
352
362
  export function handlePastePanelOrDecisionContentIntoList(slice, findRootParentListNode) {
353
363
  return function (state, dispatch) {
364
+ var _blockNode$type$name;
354
365
  var schema = state.schema,
355
366
  tr = state.tr;
356
367
  var selection = tr.selection;
@@ -359,7 +370,10 @@ export function handlePastePanelOrDecisionContentIntoList(slice, findRootParentL
359
370
  var isSliceWholeNode = slice.openStart === 0 && slice.openEnd === 0;
360
371
  var selectionParentListItemNode = selection.$to.node(selection.$to.depth - 1);
361
372
  var sliceIsWholeNodeButShouldNotReplaceSelection = isSliceWholeNode && !doesSelectionWhichStartsOrEndsInListContainEntireList(selection, findRootParentListNode);
362
- if (!selectionParentListItemNode || (selectionParentListItemNode === null || selectionParentListItemNode === void 0 ? void 0 : selectionParentListItemNode.type) !== schema.nodes.listItem || !blockNode || !['panel', 'decisionList'].includes(blockNode === null || blockNode === void 0 ? void 0 : blockNode.type.name) || slice.content.childCount > 1 || (blockNode === null || blockNode === void 0 ? void 0 : blockNode.content.firstChild) === undefined || sliceIsWholeNodeButShouldNotReplaceSelection) {
373
+
374
+ // When the experiment is on, treat panel_c1 (table-in-panel variant) like a panel.
375
+ var blockNodeIsPanelOrDecision = expValEquals('platform_editor_nest_table_in_panel', 'isEnabled', true) ? ['panel', 'decisionList'].includes(blockNode ? getBaseNodeTypeName(blockNode.type) : '') : ['panel', 'decisionList'].includes((_blockNode$type$name = blockNode === null || blockNode === void 0 ? void 0 : blockNode.type.name) !== null && _blockNode$type$name !== void 0 ? _blockNode$type$name : '');
376
+ if (!selectionParentListItemNode || (selectionParentListItemNode === null || selectionParentListItemNode === void 0 ? void 0 : selectionParentListItemNode.type) !== schema.nodes.listItem || !blockNode || !blockNodeIsPanelOrDecision || slice.content.childCount > 1 || (blockNode === null || blockNode === void 0 ? void 0 : blockNode.content.firstChild) === undefined || sliceIsWholeNodeButShouldNotReplaceSelection) {
363
377
  return false;
364
378
  }
365
379
 
@@ -1123,6 +1137,7 @@ export function handleRichText(slice, queueCardsFromChangedTr) {
1123
1137
  heading = _state$schema$nodes4.heading,
1124
1138
  paragraph = _state$schema$nodes4.paragraph,
1125
1139
  panel = _state$schema$nodes4.panel,
1140
+ panel_c1 = _state$schema$nodes4.panel_c1,
1126
1141
  bulletList = _state$schema$nodes4.bulletList,
1127
1142
  orderedList = _state$schema$nodes4.orderedList;
1128
1143
  var fontSize = state.schema.marks.fontSize;
@@ -1170,7 +1185,8 @@ export function handleRichText(slice, queueCardsFromChangedTr) {
1170
1185
  var textNodes = [heading, paragraph];
1171
1186
  var selectionParent = selection.$to.node(selection.$to.depth - 1);
1172
1187
  var noNeedForSafeInsert = selection.$to.node().type.validContent(slice.content) || textNodes.includes(selection.$to.node().type) && selectionParent.type.validContent(slice.content);
1173
- var panelParentOverCurrentSelection = findParentNodeOfType(panel)(tr.selection);
1188
+ // panel_c1 is a schema variant of panel; when the experiment is on, treat both together.
1189
+ var panelParentOverCurrentSelection = expValEquals('platform_editor_nest_table_in_panel', 'isEnabled', true) ? findParentNodeOfType([panel, panel_c1].filter(Boolean))(tr.selection) : findParentNodeOfType(panel)(tr.selection);
1174
1190
  var isTargetPanelEmpty = panelParentOverCurrentSelection && ((_panelParentOverCurre = panelParentOverCurrentSelection.node) === null || _panelParentOverCurre === void 0 ? void 0 : _panelParentOverCurre.content.size) === 2;
1175
1191
  if (!isSliceContentTaskListNodes && (isSliceContentListNodes || isTargetPanelEmpty)) {
1176
1192
  insertSliceForLists({
@@ -1192,7 +1208,7 @@ export function handleRichText(slice, queueCardsFromChangedTr) {
1192
1208
  // when cursor is inside a table cell, and slice.content.lastChild is a panel, expand, or decisionList
1193
1209
  // need to make sure the cursor position is is right after the panel, expand, or decisionList
1194
1210
  // still in the same table cell, see issue: https://product-fabric.atlassian.net/browse/ED-17862
1195
- var shouldUpdateCursorPosAfterPaste = ['panel', 'nestedExpand', 'decisionList', 'codeBlock'].includes(((_slice$content$lastCh = slice.content.lastChild) === null || _slice$content$lastCh === void 0 || (_slice$content$lastCh = _slice$content$lastCh.type) === null || _slice$content$lastCh === void 0 ? void 0 : _slice$content$lastCh.name) || '');
1211
+ var shouldUpdateCursorPosAfterPaste = expValEquals('platform_editor_nest_table_in_panel', 'isEnabled', true) ? ['panel', 'nestedExpand', 'decisionList', 'codeBlock'].includes(slice.content.lastChild ? getBaseNodeTypeName(slice.content.lastChild.type) : '') : ['panel', 'nestedExpand', 'decisionList', 'codeBlock'].includes(((_slice$content$lastCh = slice.content.lastChild) === null || _slice$content$lastCh === void 0 || (_slice$content$lastCh = _slice$content$lastCh.type) === null || _slice$content$lastCh === void 0 ? void 0 : _slice$content$lastCh.name) || '');
1196
1212
  var lastChild = slice.content.lastChild;
1197
1213
  var $nextPos = tr.doc.resolve(tr.mapping.map(selection.from));
1198
1214
  var nextSelection = lastChild !== null && lastChild !== void 0 && lastChild.type.isTextblock ? TextSelection.findFrom($nextPos, -1, true) : new GapCursorSelection($nextPos, Side.RIGHT);
@@ -1348,8 +1364,8 @@ export var handleSelectedTable = function handleSelectedTable(editorAnalyticsAPI
1348
1364
  };
1349
1365
  };
1350
1366
  export function checkTaskListInList(state, slice) {
1351
- var _slice$content$firstC5;
1352
- return Boolean(isInListItem(state) && ['taskList', 'taskItem'].includes(((_slice$content$firstC5 = slice.content.firstChild) === null || _slice$content$firstC5 === void 0 || (_slice$content$firstC5 = _slice$content$firstC5.type) === null || _slice$content$firstC5 === void 0 ? void 0 : _slice$content$firstC5.name) || ''));
1367
+ var _slice$content$firstC4;
1368
+ return Boolean(isInListItem(state) && ['taskList', 'taskItem'].includes(((_slice$content$firstC4 = slice.content.firstChild) === null || _slice$content$firstC4 === void 0 || (_slice$content$firstC4 = _slice$content$firstC4.type) === null || _slice$content$firstC4 === void 0 ? void 0 : _slice$content$firstC4.name) || ''));
1353
1369
  }
1354
1370
  export function checkIfSelectionInNestedList(state) {
1355
1371
  var selection = state.selection,
@@ -2,12 +2,14 @@ import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
2
2
  import { ACTION_SUBJECT, EVENT_TYPE, INPUT_METHOD, TABLE_ACTION } from '@atlaskit/editor-common/analytics';
3
3
  import { sortByOrderWithTypeName } from '@atlaskit/editor-common/legacy-rank-plugins';
4
4
  import { isSupportedInParent, mapChildren } from '@atlaskit/editor-common/utils';
5
+ import { getBaseNodeTypeName } from '@atlaskit/editor-common/utils/node-type-utils';
5
6
  import { Fragment, Mark, Slice } from '@atlaskit/editor-prosemirror/model';
6
7
  import { NodeSelection, TextSelection } from '@atlaskit/editor-prosemirror/state';
7
8
  import { findParentNodeOfType } from '@atlaskit/editor-prosemirror/utils';
8
9
  import { getSelectedTableInfo, isTableSelected } from '@atlaskit/editor-tables/utils';
9
10
  import { isMediaBlobUrl } from '@atlaskit/media-client';
10
11
  import { fg } from '@atlaskit/platform-feature-flags';
12
+ import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
11
13
 
12
14
  // Ignored via go/ees005
13
15
  // eslint-disable-next-line require-unicode-regexp
@@ -204,14 +206,23 @@ export function isCursorSelectionAtTextStartOrEnd(selection) {
204
206
  return selection instanceof TextSelection && selection.empty && selection.$cursor && (!selection.$cursor.nodeBefore || !selection.$cursor.nodeAfter);
205
207
  }
206
208
  export function isPanelNode(node) {
209
+ // panel_c1 is a schema variant of panel (used when a table is nested inside a panel). When the
210
+ // experiment is on, treat it as a panel too.
211
+ if (expValEquals('platform_editor_nest_table_in_panel', 'isEnabled', true)) {
212
+ return Boolean(node && getBaseNodeTypeName(node.type) === 'panel');
213
+ }
207
214
  return Boolean(node && node.type.name === 'panel');
208
215
  }
209
216
  export function isSelectionInsidePanel(selection) {
210
217
  if (selection instanceof NodeSelection && isPanelNode(selection.node)) {
211
218
  return selection.node;
212
219
  }
213
- var panel = selection.$from.doc.type.schema.nodes.panel;
214
- var panelPosition = findParentNodeOfType(panel)(selection);
220
+ var _selection$$from$doc$ = selection.$from.doc.type.schema.nodes,
221
+ panel = _selection$$from$doc$.panel,
222
+ panel_c1 = _selection$$from$doc$.panel_c1;
223
+
224
+ // When the experiment is on, also match panel_c1 (table-in-panel variant).
225
+ var panelPosition = expValEquals('platform_editor_nest_table_in_panel', 'isEnabled', true) ? findParentNodeOfType([panel, panel_c1].filter(Boolean))(selection) : findParentNodeOfType(panel)(selection);
215
226
  if (panelPosition) {
216
227
  return panelPosition.node;
217
228
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-paste",
3
- "version": "13.3.20",
3
+ "version": "13.4.0",
4
4
  "description": "Paste plugin for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -39,16 +39,16 @@
39
39
  "@atlaskit/insm": "^1.0.0",
40
40
  "@atlaskit/media-client": "^37.2.0",
41
41
  "@atlaskit/media-common": "^14.3.0",
42
- "@atlaskit/platform-feature-flags": "^2.0.0",
42
+ "@atlaskit/platform-feature-flags": "^2.1.0",
43
43
  "@atlaskit/prosemirror-history": "^1.0.0",
44
- "@atlaskit/tmp-editor-statsig": "^130.0.0",
45
- "@atlaskit/tokens": "^16.1.0",
44
+ "@atlaskit/tmp-editor-statsig": "^131.0.0",
45
+ "@atlaskit/tokens": "^16.2.0",
46
46
  "@babel/runtime": "^7.0.0",
47
47
  "lodash": "^4.17.21",
48
48
  "uuid": "^3.1.0"
49
49
  },
50
50
  "peerDependencies": {
51
- "@atlaskit/editor-common": "^116.33.0",
51
+ "@atlaskit/editor-common": "^116.35.0",
52
52
  "react": "^18.2.0",
53
53
  "react-dom": "^18.2.0",
54
54
  "react-intl": "^5.25.1 || ^6.0.0 || ^7.0.0"