@atlaskit/editor-plugin-extension 10.0.15 → 10.1.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,25 @@
1
1
  # @atlaskit/editor-plugin-extension
2
2
 
3
+ ## 10.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`71321772bd9a7`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/71321772bd9a7) -
8
+ [ux] EDITOR-4932 - Copy extension text content when clicking copy button for unsupported content
9
+ extension.
10
+
11
+ ### Patch Changes
12
+
13
+ - Updated dependencies
14
+
15
+ ## 10.0.16
16
+
17
+ ### Patch Changes
18
+
19
+ - [`584ac5ca3f498`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/584ac5ca3f498) -
20
+ [ux] EDITOR-5269 Disables the copy button for legacy content macro nodes
21
+ - Updated dependencies
22
+
3
23
  ## 10.0.15
4
24
 
5
25
  ### Patch Changes
@@ -182,7 +182,8 @@ var extensionPlugin = exports.extensionPlugin = function extensionPlugin(_ref) {
182
182
  pluginsOptions: {
183
183
  floatingToolbar: (0, _toolbar.getToolbarConfig)({
184
184
  breakoutEnabled: options.breakoutEnabled,
185
- extensionApi: _api
185
+ extensionApi: _api,
186
+ getUnsupportedContent: options.getUnsupportedContent
186
187
  }),
187
188
  contextPanel:
188
189
  // if showContextPanel action is not available, or platform_editor_ai_object_sidebar_injection feature flag is off
@@ -4,7 +4,8 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
4
4
  Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
- exports.getToolbarConfig = void 0;
7
+ exports.getToolbarConfig = exports.createOnClickCopyButton = void 0;
8
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
8
9
  var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
9
10
  var _react = _interopRequireDefault(require("react"));
10
11
  var _analytics = require("@atlaskit/editor-common/analytics");
@@ -27,6 +28,8 @@ var _commands = require("../editor-commands/commands");
27
28
  var _pluginKey = require("./macro/plugin-key");
28
29
  var _pluginFactory = require("./plugin-factory");
29
30
  var _utils3 = require("./utils");
31
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
32
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
30
33
  // non-bodied extensions nested inside panels, blockquotes and lists do not support layouts
31
34
  var isNestedNBM = function isNestedNBM(state, selectedExtNode) {
32
35
  var _state$schema$nodes = state.schema.nodes,
@@ -259,14 +262,67 @@ var calculateToolbarPosition = function calculateToolbarPosition(editorView, nex
259
262
  left: nextPos.left
260
263
  };
261
264
  };
262
- var getToolbarConfig = exports.getToolbarConfig = function getToolbarConfig(_ref) {
263
- var _ref$breakoutEnabled = _ref.breakoutEnabled,
264
- breakoutEnabled = _ref$breakoutEnabled === void 0 ? true : _ref$breakoutEnabled,
265
- extensionApi = _ref.extensionApi;
265
+
266
+ /**
267
+ * Creates a function that copies the text content of the unsupported content extension to the clipboard
268
+ * if the current selected extension is an unsupported content extension.
269
+ */
270
+ var createOnClickCopyButton = exports.createOnClickCopyButton = function createOnClickCopyButton(_ref) {
271
+ var extensionApi = _ref.extensionApi,
272
+ extensionProvider = _ref.extensionProvider,
273
+ getUnsupportedContent = _ref.getUnsupportedContent,
274
+ state = _ref.state;
275
+ if (!extensionProvider) {
276
+ return;
277
+ }
278
+ var nodeWithPos = (0, _utils3.getSelectedExtension)(state, true);
279
+ if (!nodeWithPos) {
280
+ return;
281
+ }
282
+ var node = nodeWithPos.node;
283
+ var _node$attrs = node.attrs,
284
+ extensionType = _node$attrs.extensionType,
285
+ extensionKey = _node$attrs.extensionKey;
286
+ var extensionParams = {
287
+ type: node.type.name,
288
+ extensionKey: extensionKey,
289
+ extensionType: extensionType,
290
+ parameters: node.attrs.parameters,
291
+ content: node.content,
292
+ localId: node.attrs.localId
293
+ };
294
+ var adf = getUnsupportedContent === null || getUnsupportedContent === void 0 ? void 0 : getUnsupportedContent(extensionParams);
295
+ if (!adf) {
296
+ return;
297
+ }
298
+
299
+ // this command copies the text content of the unsupported content extension to the clipboard
300
+ return function (editorState) {
301
+ var error = (0, _utils3.copyUnsupportedContentToClipboard)({
302
+ unsupportedContent: adf,
303
+ schema: state.schema
304
+ });
305
+ if (error) {
306
+ (0, _utils3.onCopyFailed)({
307
+ error: error,
308
+ extensionApi: extensionApi,
309
+ state: editorState
310
+ });
311
+ return false;
312
+ }
313
+ return true;
314
+ };
315
+ };
316
+ var getToolbarConfig = exports.getToolbarConfig = function getToolbarConfig(_ref2) {
317
+ var _ref2$breakoutEnabled = _ref2.breakoutEnabled,
318
+ breakoutEnabled = _ref2$breakoutEnabled === void 0 ? true : _ref2$breakoutEnabled,
319
+ extensionApi = _ref2.extensionApi,
320
+ getUnsupportedContent = _ref2.getUnsupportedContent;
266
321
  return function (state, intl) {
267
322
  var _extensionApi$decorat, _extensionApi$context, _extensionApi$analyti, _extensionApi$connect;
268
323
  var formatMessage = intl.formatMessage;
269
324
  var extensionState = (0, _pluginFactory.getPluginState)(state);
325
+ var extensionProvider = extensionState.extensionProvider;
270
326
  var hoverDecoration = extensionApi === null || extensionApi === void 0 || (_extensionApi$decorat = extensionApi.decorations) === null || _extensionApi$decorat === void 0 ? void 0 : _extensionApi$decorat.actions.hoverDecoration;
271
327
  var applyChangeToContextPanel = extensionApi === null || extensionApi === void 0 || (_extensionApi$context = extensionApi.contextPanel) === null || _extensionApi$context === void 0 ? void 0 : _extensionApi$context.actions.applyChange;
272
328
  var editorAnalyticsAPI = extensionApi === null || extensionApi === void 0 || (_extensionApi$analyti = extensionApi.analytics) === null || _extensionApi$analyti === void 0 ? void 0 : _extensionApi$analyti.actions;
@@ -301,6 +357,10 @@ var getToolbarConfig = exports.getToolbarConfig = function getToolbarConfig(_ref
301
357
  };
302
358
  };
303
359
  }
360
+
361
+ // disable copy button for legacy content macro
362
+ var isLegacyContentMacro = (extensionObj === null || extensionObj === void 0 ? void 0 : extensionObj.node.attrs.extensionType) === 'com.atlassian.confluence.migration' && (extensionObj === null || extensionObj === void 0 ? void 0 : extensionObj.node.attrs.extensionKey) === 'legacy-content';
363
+ var shouldHideCopyButton = isLegacyContentMacro && (0, _expValEquals.expValEquals)('platform_editor_disable_lcm_copy_button', 'isEnabled', true);
304
364
  return {
305
365
  title: 'Extension floating controls',
306
366
  // Ignored via go/ees005
@@ -318,14 +378,22 @@ var getToolbarConfig = exports.getToolbarConfig = function getToolbarConfig(_ref
318
378
  }, {
319
379
  type: 'extensions-placeholder',
320
380
  separator: 'end'
321
- }, {
381
+ }, _objectSpread({
322
382
  type: 'copy-button',
323
383
  items: [{
324
384
  state: state,
325
385
  formatMessage: intl.formatMessage,
326
- nodeType: nodeType
386
+ nodeType: nodeType,
387
+ onClick: (0, _expValEquals.expValEquals)('platform_editor_ai_edit_unsupported_content', 'isEnabled', true) ? createOnClickCopyButton({
388
+ extensionApi: extensionApi,
389
+ extensionProvider: extensionProvider,
390
+ getUnsupportedContent: getUnsupportedContent,
391
+ state: state
392
+ }) : undefined
327
393
  }]
328
- }, {
394
+ }, shouldHideCopyButton && {
395
+ hidden: shouldHideCopyButton
396
+ }), {
329
397
  type: 'separator'
330
398
  }, {
331
399
  id: 'editor.extension.delete',
@@ -3,8 +3,11 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.getSelectedExtension = exports.getSelectedDomElement = exports.getNodeTypesReferenced = exports.getDataConsumerMark = exports.findNodePosWithLocalId = exports.findExtensionWithLocalId = void 0;
6
+ exports.onCopyFailed = exports.getSelectedExtension = exports.getSelectedDomElement = exports.getNodeTypesReferenced = exports.getDataConsumerMark = exports.findNodePosWithLocalId = exports.findExtensionWithLocalId = exports.copyUnsupportedContentToClipboard = void 0;
7
+ var _analytics = require("@atlaskit/editor-common/analytics");
8
+ var _clipboard = require("@atlaskit/editor-common/clipboard");
7
9
  var _utils = require("@atlaskit/editor-common/utils");
10
+ var _editorJsonTransformer = require("@atlaskit/editor-json-transformer");
8
11
  var _utils2 = require("@atlaskit/editor-prosemirror/utils");
9
12
  var getSelectedExtension = exports.getSelectedExtension = function getSelectedExtension(state) {
10
13
  var searchParent = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
@@ -70,4 +73,55 @@ var getNodeTypesReferenced = exports.getNodeTypesReferenced = function getNodeTy
70
73
  var findNodePosWithLocalId = exports.findNodePosWithLocalId = function findNodePosWithLocalId(state, localId) {
71
74
  var nodes = (0, _utils.findNodePosByLocalIds)(state, [localId]);
72
75
  return nodes.length >= 1 ? nodes[0] : undefined;
76
+ };
77
+ /**
78
+ * copying ADF from the unsupported content extension as text to clipboard
79
+ */
80
+ var copyUnsupportedContentToClipboard = exports.copyUnsupportedContentToClipboard = function copyUnsupportedContentToClipboard(_ref2) {
81
+ var schema = _ref2.schema,
82
+ unsupportedContent = _ref2.unsupportedContent;
83
+ try {
84
+ if (!unsupportedContent) {
85
+ return new Error('No nested content found');
86
+ }
87
+ if (unsupportedContent.type !== 'doc') {
88
+ unsupportedContent = {
89
+ version: 1,
90
+ type: 'doc',
91
+ content: [unsupportedContent]
92
+ };
93
+ }
94
+ var transformer = new _editorJsonTransformer.JSONTransformer(schema);
95
+ var pmNode = transformer.parse(unsupportedContent);
96
+ var text = pmNode.textBetween(0, pmNode.content.size, '\n\n');
97
+ (0, _clipboard.copyToClipboard)(text);
98
+ } catch (error) {
99
+ return error instanceof Error ? error : new Error('Failed to copy content');
100
+ }
101
+ };
102
+ var onCopyFailed = exports.onCopyFailed = function onCopyFailed(_ref3) {
103
+ var _extensionApi$analyti;
104
+ var error = _ref3.error,
105
+ extensionApi = _ref3.extensionApi,
106
+ state = _ref3.state;
107
+ var nodeWithPos = getSelectedExtension(state, true);
108
+ if (!nodeWithPos) {
109
+ return;
110
+ }
111
+ var node = nodeWithPos.node;
112
+ var _node$attrs = node.attrs,
113
+ extensionType = _node$attrs.extensionType,
114
+ extensionKey = _node$attrs.extensionKey;
115
+ extensionApi === null || extensionApi === void 0 || (_extensionApi$analyti = extensionApi.analytics) === null || _extensionApi$analyti === void 0 || _extensionApi$analyti.actions.fireAnalyticsEvent({
116
+ eventType: _analytics.EVENT_TYPE.OPERATIONAL,
117
+ action: _analytics.ACTION.COPY_FAILED,
118
+ actionSubject: _analytics.ACTION_SUBJECT.EXTENSION,
119
+ actionSubjectId: node.type.name,
120
+ attributes: {
121
+ extensionKey: extensionKey,
122
+ extensionType: extensionType,
123
+ errorMessage: error.message,
124
+ errorStack: error.stack
125
+ }
126
+ });
73
127
  };
@@ -169,7 +169,8 @@ export const extensionPlugin = ({
169
169
  pluginsOptions: {
170
170
  floatingToolbar: getToolbarConfig({
171
171
  breakoutEnabled: options.breakoutEnabled,
172
- extensionApi: api
172
+ extensionApi: api,
173
+ getUnsupportedContent: options.getUnsupportedContent
173
174
  }),
174
175
  contextPanel:
175
176
  // if showContextPanel action is not available, or platform_editor_ai_object_sidebar_injection feature flag is off
@@ -18,7 +18,7 @@ import { editExtension } from '../editor-actions/actions';
18
18
  import { removeDescendantNodes, removeExtension, updateExtensionLayout } from '../editor-commands/commands';
19
19
  import { pluginKey as macroPluginKey } from './macro/plugin-key';
20
20
  import { getPluginState } from './plugin-factory';
21
- import { getSelectedExtension } from './utils';
21
+ import { copyUnsupportedContentToClipboard, getSelectedExtension, onCopyFailed } from './utils';
22
22
 
23
23
  // non-bodied extensions nested inside panels, blockquotes and lists do not support layouts
24
24
  const isNestedNBM = (state, selectedExtNode) => {
@@ -260,15 +260,74 @@ const calculateToolbarPosition = (editorView, nextPos, state, extensionNode) =>
260
260
  left: nextPos.left
261
261
  };
262
262
  };
263
+
264
+ /**
265
+ * Creates a function that copies the text content of the unsupported content extension to the clipboard
266
+ * if the current selected extension is an unsupported content extension.
267
+ */
268
+ export const createOnClickCopyButton = ({
269
+ extensionApi,
270
+ extensionProvider,
271
+ getUnsupportedContent,
272
+ state
273
+ }) => {
274
+ if (!extensionProvider) {
275
+ return;
276
+ }
277
+ const nodeWithPos = getSelectedExtension(state, true);
278
+ if (!nodeWithPos) {
279
+ return;
280
+ }
281
+ const {
282
+ node
283
+ } = nodeWithPos;
284
+ const {
285
+ extensionType,
286
+ extensionKey
287
+ } = node.attrs;
288
+ const extensionParams = {
289
+ type: node.type.name,
290
+ extensionKey,
291
+ extensionType,
292
+ parameters: node.attrs.parameters,
293
+ content: node.content,
294
+ localId: node.attrs.localId
295
+ };
296
+ const adf = getUnsupportedContent === null || getUnsupportedContent === void 0 ? void 0 : getUnsupportedContent(extensionParams);
297
+ if (!adf) {
298
+ return;
299
+ }
300
+
301
+ // this command copies the text content of the unsupported content extension to the clipboard
302
+ return editorState => {
303
+ const error = copyUnsupportedContentToClipboard({
304
+ unsupportedContent: adf,
305
+ schema: state.schema
306
+ });
307
+ if (error) {
308
+ onCopyFailed({
309
+ error,
310
+ extensionApi,
311
+ state: editorState
312
+ });
313
+ return false;
314
+ }
315
+ return true;
316
+ };
317
+ };
263
318
  export const getToolbarConfig = ({
264
319
  breakoutEnabled = true,
265
- extensionApi
320
+ extensionApi,
321
+ getUnsupportedContent
266
322
  }) => (state, intl) => {
267
323
  var _extensionApi$decorat, _extensionApi$context, _extensionApi$analyti, _extensionApi$connect, _extensionApi$connect2, _extensionApi$connect3;
268
324
  const {
269
325
  formatMessage
270
326
  } = intl;
271
327
  const extensionState = getPluginState(state);
328
+ const {
329
+ extensionProvider
330
+ } = extensionState;
272
331
  const hoverDecoration = extensionApi === null || extensionApi === void 0 ? void 0 : (_extensionApi$decorat = extensionApi.decorations) === null || _extensionApi$decorat === void 0 ? void 0 : _extensionApi$decorat.actions.hoverDecoration;
273
332
  const applyChangeToContextPanel = extensionApi === null || extensionApi === void 0 ? void 0 : (_extensionApi$context = extensionApi.contextPanel) === null || _extensionApi$context === void 0 ? void 0 : _extensionApi$context.actions.applyChange;
274
333
  const editorAnalyticsAPI = extensionApi === null || extensionApi === void 0 ? void 0 : (_extensionApi$analyti = extensionApi.analytics) === null || _extensionApi$analyti === void 0 ? void 0 : _extensionApi$analyti.actions;
@@ -298,6 +357,10 @@ export const getToolbarConfig = ({
298
357
  };
299
358
  };
300
359
  }
360
+
361
+ // disable copy button for legacy content macro
362
+ const isLegacyContentMacro = (extensionObj === null || extensionObj === void 0 ? void 0 : extensionObj.node.attrs.extensionType) === 'com.atlassian.confluence.migration' && (extensionObj === null || extensionObj === void 0 ? void 0 : extensionObj.node.attrs.extensionKey) === 'legacy-content';
363
+ const shouldHideCopyButton = isLegacyContentMacro && expValEquals('platform_editor_disable_lcm_copy_button', 'isEnabled', true);
301
364
  return {
302
365
  title: 'Extension floating controls',
303
366
  // Ignored via go/ees005
@@ -316,8 +379,17 @@ export const getToolbarConfig = ({
316
379
  items: [{
317
380
  state,
318
381
  formatMessage: intl.formatMessage,
319
- nodeType
320
- }]
382
+ nodeType,
383
+ onClick: expValEquals('platform_editor_ai_edit_unsupported_content', 'isEnabled', true) ? createOnClickCopyButton({
384
+ extensionApi,
385
+ extensionProvider,
386
+ getUnsupportedContent,
387
+ state
388
+ }) : undefined
389
+ }],
390
+ ...(shouldHideCopyButton && {
391
+ hidden: shouldHideCopyButton
392
+ })
321
393
  }, {
322
394
  type: 'separator'
323
395
  }, {
@@ -1,4 +1,7 @@
1
+ import { ACTION, ACTION_SUBJECT, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
2
+ import { copyToClipboard } from '@atlaskit/editor-common/clipboard';
1
3
  import { closestElement, findNodePosByLocalIds } from '@atlaskit/editor-common/utils';
4
+ import { JSONTransformer } from '@atlaskit/editor-json-transformer';
2
5
  import { findDomRefAtPos, findParentNodeOfType, findSelectedNodeOfType } from '@atlaskit/editor-prosemirror/utils';
3
6
  export const getSelectedExtension = (state, searchParent = false) => {
4
7
  const {
@@ -62,4 +65,60 @@ export const getNodeTypesReferenced = (ids, state) => {
62
65
  export const findNodePosWithLocalId = (state, localId) => {
63
66
  const nodes = findNodePosByLocalIds(state, [localId]);
64
67
  return nodes.length >= 1 ? nodes[0] : undefined;
68
+ };
69
+ /**
70
+ * copying ADF from the unsupported content extension as text to clipboard
71
+ */
72
+ export const copyUnsupportedContentToClipboard = ({
73
+ schema,
74
+ unsupportedContent
75
+ }) => {
76
+ try {
77
+ if (!unsupportedContent) {
78
+ return new Error('No nested content found');
79
+ }
80
+ if (unsupportedContent.type !== 'doc') {
81
+ unsupportedContent = {
82
+ version: 1,
83
+ type: 'doc',
84
+ content: [unsupportedContent]
85
+ };
86
+ }
87
+ const transformer = new JSONTransformer(schema);
88
+ const pmNode = transformer.parse(unsupportedContent);
89
+ const text = pmNode.textBetween(0, pmNode.content.size, '\n\n');
90
+ copyToClipboard(text);
91
+ } catch (error) {
92
+ return error instanceof Error ? error : new Error('Failed to copy content');
93
+ }
94
+ };
95
+ export const onCopyFailed = ({
96
+ error,
97
+ extensionApi,
98
+ state
99
+ }) => {
100
+ var _extensionApi$analyti;
101
+ const nodeWithPos = getSelectedExtension(state, true);
102
+ if (!nodeWithPos) {
103
+ return;
104
+ }
105
+ const {
106
+ node
107
+ } = nodeWithPos;
108
+ const {
109
+ extensionType,
110
+ extensionKey
111
+ } = node.attrs;
112
+ extensionApi === null || extensionApi === void 0 ? void 0 : (_extensionApi$analyti = extensionApi.analytics) === null || _extensionApi$analyti === void 0 ? void 0 : _extensionApi$analyti.actions.fireAnalyticsEvent({
113
+ eventType: EVENT_TYPE.OPERATIONAL,
114
+ action: ACTION.COPY_FAILED,
115
+ actionSubject: ACTION_SUBJECT.EXTENSION,
116
+ actionSubjectId: node.type.name,
117
+ attributes: {
118
+ extensionKey,
119
+ extensionType,
120
+ errorMessage: error.message,
121
+ errorStack: error.stack
122
+ }
123
+ });
65
124
  };
@@ -173,7 +173,8 @@ export var extensionPlugin = function extensionPlugin(_ref) {
173
173
  pluginsOptions: {
174
174
  floatingToolbar: getToolbarConfig({
175
175
  breakoutEnabled: options.breakoutEnabled,
176
- extensionApi: _api
176
+ extensionApi: _api,
177
+ getUnsupportedContent: options.getUnsupportedContent
177
178
  }),
178
179
  contextPanel:
179
180
  // if showContextPanel action is not available, or platform_editor_ai_object_sidebar_injection feature flag is off
@@ -1,4 +1,7 @@
1
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
1
2
  import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
3
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
4
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
2
5
  import React from 'react';
3
6
  import { INPUT_METHOD } from '@atlaskit/editor-common/analytics';
4
7
  import { messages } from '@atlaskit/editor-common/extensions';
@@ -19,7 +22,7 @@ import { editExtension } from '../editor-actions/actions';
19
22
  import { removeDescendantNodes, removeExtension, updateExtensionLayout } from '../editor-commands/commands';
20
23
  import { pluginKey as macroPluginKey } from './macro/plugin-key';
21
24
  import { getPluginState } from './plugin-factory';
22
- import { getSelectedExtension } from './utils';
25
+ import { copyUnsupportedContentToClipboard, getSelectedExtension, onCopyFailed } from './utils';
23
26
 
24
27
  // non-bodied extensions nested inside panels, blockquotes and lists do not support layouts
25
28
  var isNestedNBM = function isNestedNBM(state, selectedExtNode) {
@@ -253,14 +256,67 @@ var calculateToolbarPosition = function calculateToolbarPosition(editorView, nex
253
256
  left: nextPos.left
254
257
  };
255
258
  };
256
- export var getToolbarConfig = function getToolbarConfig(_ref) {
257
- var _ref$breakoutEnabled = _ref.breakoutEnabled,
258
- breakoutEnabled = _ref$breakoutEnabled === void 0 ? true : _ref$breakoutEnabled,
259
- extensionApi = _ref.extensionApi;
259
+
260
+ /**
261
+ * Creates a function that copies the text content of the unsupported content extension to the clipboard
262
+ * if the current selected extension is an unsupported content extension.
263
+ */
264
+ export var createOnClickCopyButton = function createOnClickCopyButton(_ref) {
265
+ var extensionApi = _ref.extensionApi,
266
+ extensionProvider = _ref.extensionProvider,
267
+ getUnsupportedContent = _ref.getUnsupportedContent,
268
+ state = _ref.state;
269
+ if (!extensionProvider) {
270
+ return;
271
+ }
272
+ var nodeWithPos = getSelectedExtension(state, true);
273
+ if (!nodeWithPos) {
274
+ return;
275
+ }
276
+ var node = nodeWithPos.node;
277
+ var _node$attrs = node.attrs,
278
+ extensionType = _node$attrs.extensionType,
279
+ extensionKey = _node$attrs.extensionKey;
280
+ var extensionParams = {
281
+ type: node.type.name,
282
+ extensionKey: extensionKey,
283
+ extensionType: extensionType,
284
+ parameters: node.attrs.parameters,
285
+ content: node.content,
286
+ localId: node.attrs.localId
287
+ };
288
+ var adf = getUnsupportedContent === null || getUnsupportedContent === void 0 ? void 0 : getUnsupportedContent(extensionParams);
289
+ if (!adf) {
290
+ return;
291
+ }
292
+
293
+ // this command copies the text content of the unsupported content extension to the clipboard
294
+ return function (editorState) {
295
+ var error = copyUnsupportedContentToClipboard({
296
+ unsupportedContent: adf,
297
+ schema: state.schema
298
+ });
299
+ if (error) {
300
+ onCopyFailed({
301
+ error: error,
302
+ extensionApi: extensionApi,
303
+ state: editorState
304
+ });
305
+ return false;
306
+ }
307
+ return true;
308
+ };
309
+ };
310
+ export var getToolbarConfig = function getToolbarConfig(_ref2) {
311
+ var _ref2$breakoutEnabled = _ref2.breakoutEnabled,
312
+ breakoutEnabled = _ref2$breakoutEnabled === void 0 ? true : _ref2$breakoutEnabled,
313
+ extensionApi = _ref2.extensionApi,
314
+ getUnsupportedContent = _ref2.getUnsupportedContent;
260
315
  return function (state, intl) {
261
316
  var _extensionApi$decorat, _extensionApi$context, _extensionApi$analyti, _extensionApi$connect;
262
317
  var formatMessage = intl.formatMessage;
263
318
  var extensionState = getPluginState(state);
319
+ var extensionProvider = extensionState.extensionProvider;
264
320
  var hoverDecoration = extensionApi === null || extensionApi === void 0 || (_extensionApi$decorat = extensionApi.decorations) === null || _extensionApi$decorat === void 0 ? void 0 : _extensionApi$decorat.actions.hoverDecoration;
265
321
  var applyChangeToContextPanel = extensionApi === null || extensionApi === void 0 || (_extensionApi$context = extensionApi.contextPanel) === null || _extensionApi$context === void 0 ? void 0 : _extensionApi$context.actions.applyChange;
266
322
  var editorAnalyticsAPI = extensionApi === null || extensionApi === void 0 || (_extensionApi$analyti = extensionApi.analytics) === null || _extensionApi$analyti === void 0 ? void 0 : _extensionApi$analyti.actions;
@@ -295,6 +351,10 @@ export var getToolbarConfig = function getToolbarConfig(_ref) {
295
351
  };
296
352
  };
297
353
  }
354
+
355
+ // disable copy button for legacy content macro
356
+ var isLegacyContentMacro = (extensionObj === null || extensionObj === void 0 ? void 0 : extensionObj.node.attrs.extensionType) === 'com.atlassian.confluence.migration' && (extensionObj === null || extensionObj === void 0 ? void 0 : extensionObj.node.attrs.extensionKey) === 'legacy-content';
357
+ var shouldHideCopyButton = isLegacyContentMacro && expValEquals('platform_editor_disable_lcm_copy_button', 'isEnabled', true);
298
358
  return {
299
359
  title: 'Extension floating controls',
300
360
  // Ignored via go/ees005
@@ -312,14 +372,22 @@ export var getToolbarConfig = function getToolbarConfig(_ref) {
312
372
  }, {
313
373
  type: 'extensions-placeholder',
314
374
  separator: 'end'
315
- }, {
375
+ }, _objectSpread({
316
376
  type: 'copy-button',
317
377
  items: [{
318
378
  state: state,
319
379
  formatMessage: intl.formatMessage,
320
- nodeType: nodeType
380
+ nodeType: nodeType,
381
+ onClick: expValEquals('platform_editor_ai_edit_unsupported_content', 'isEnabled', true) ? createOnClickCopyButton({
382
+ extensionApi: extensionApi,
383
+ extensionProvider: extensionProvider,
384
+ getUnsupportedContent: getUnsupportedContent,
385
+ state: state
386
+ }) : undefined
321
387
  }]
322
- }, {
388
+ }, shouldHideCopyButton && {
389
+ hidden: shouldHideCopyButton
390
+ }), {
323
391
  type: 'separator'
324
392
  }, {
325
393
  id: 'editor.extension.delete',
@@ -1,4 +1,7 @@
1
+ import { ACTION, ACTION_SUBJECT, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
2
+ import { copyToClipboard } from '@atlaskit/editor-common/clipboard';
1
3
  import { closestElement, findNodePosByLocalIds } from '@atlaskit/editor-common/utils';
4
+ import { JSONTransformer } from '@atlaskit/editor-json-transformer';
2
5
  import { findDomRefAtPos, findParentNodeOfType, findSelectedNodeOfType } from '@atlaskit/editor-prosemirror/utils';
3
6
  export var getSelectedExtension = function getSelectedExtension(state) {
4
7
  var searchParent = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
@@ -64,4 +67,55 @@ export var getNodeTypesReferenced = function getNodeTypesReferenced(ids, state)
64
67
  export var findNodePosWithLocalId = function findNodePosWithLocalId(state, localId) {
65
68
  var nodes = findNodePosByLocalIds(state, [localId]);
66
69
  return nodes.length >= 1 ? nodes[0] : undefined;
70
+ };
71
+ /**
72
+ * copying ADF from the unsupported content extension as text to clipboard
73
+ */
74
+ export var copyUnsupportedContentToClipboard = function copyUnsupportedContentToClipboard(_ref2) {
75
+ var schema = _ref2.schema,
76
+ unsupportedContent = _ref2.unsupportedContent;
77
+ try {
78
+ if (!unsupportedContent) {
79
+ return new Error('No nested content found');
80
+ }
81
+ if (unsupportedContent.type !== 'doc') {
82
+ unsupportedContent = {
83
+ version: 1,
84
+ type: 'doc',
85
+ content: [unsupportedContent]
86
+ };
87
+ }
88
+ var transformer = new JSONTransformer(schema);
89
+ var pmNode = transformer.parse(unsupportedContent);
90
+ var text = pmNode.textBetween(0, pmNode.content.size, '\n\n');
91
+ copyToClipboard(text);
92
+ } catch (error) {
93
+ return error instanceof Error ? error : new Error('Failed to copy content');
94
+ }
95
+ };
96
+ export var onCopyFailed = function onCopyFailed(_ref3) {
97
+ var _extensionApi$analyti;
98
+ var error = _ref3.error,
99
+ extensionApi = _ref3.extensionApi,
100
+ state = _ref3.state;
101
+ var nodeWithPos = getSelectedExtension(state, true);
102
+ if (!nodeWithPos) {
103
+ return;
104
+ }
105
+ var node = nodeWithPos.node;
106
+ var _node$attrs = node.attrs,
107
+ extensionType = _node$attrs.extensionType,
108
+ extensionKey = _node$attrs.extensionKey;
109
+ extensionApi === null || extensionApi === void 0 || (_extensionApi$analyti = extensionApi.analytics) === null || _extensionApi$analyti === void 0 || _extensionApi$analyti.actions.fireAnalyticsEvent({
110
+ eventType: EVENT_TYPE.OPERATIONAL,
111
+ action: ACTION.COPY_FAILED,
112
+ actionSubject: ACTION_SUBJECT.EXTENSION,
113
+ actionSubjectId: node.type.name,
114
+ attributes: {
115
+ extensionKey: extensionKey,
116
+ extensionType: extensionType,
117
+ errorMessage: error.message,
118
+ errorStack: error.stack
119
+ }
120
+ });
67
121
  };
@@ -1,9 +1,10 @@
1
1
  import type { ADFEntity } from '@atlaskit/adf-utils/types';
2
2
  import type { EditorAnalyticsAPI } from '@atlaskit/editor-common/analytics';
3
3
  import type { GetPMNodeHeight } from '@atlaskit/editor-common/extensibility';
4
- import type { ExtensionAPI, ExtensionHandlers, ExtensionProvider, Parameters, TransformAfter, TransformBefore, UpdateExtension } from '@atlaskit/editor-common/extensions';
4
+ import type { ExtensionAPI, ExtensionHandlers, ExtensionParams, ExtensionProvider, Parameters, TransformAfter, TransformBefore, UpdateExtension } from '@atlaskit/editor-common/extensions';
5
5
  import type { MacroProvider } from '@atlaskit/editor-common/provider-factory';
6
6
  import type { EditorAppearance, LongPressSelectionPluginOptions, NextEditorPlugin, OptionalPlugin } from '@atlaskit/editor-common/types';
7
+ import type { JSONDocNode } from '@atlaskit/editor-json-transformer';
7
8
  import type { AnalyticsPlugin } from '@atlaskit/editor-plugin-analytics';
8
9
  import type { ConnectivityPlugin } from '@atlaskit/editor-plugin-connectivity';
9
10
  import type { ContextIdentifierPlugin } from '@atlaskit/editor-plugin-context-identifier';
@@ -54,6 +55,11 @@ export interface ExtensionPluginOptions extends LongPressSelectionPluginOptions
54
55
  * Helps optimize layout shift while rendering by setting minimum heights before the extension content loads.
55
56
  */
56
57
  getExtensionHeight?: GetPMNodeHeight;
58
+ /**
59
+ * Returns the ADF content of the unsupported content extension.
60
+ * Which will be copied to the clipboard when the copy button is clicked.
61
+ */
62
+ getUnsupportedContent?: (node: ExtensionParams<Parameters>) => JSONDocNode | undefined;
57
63
  }
58
64
  type InsertMacroFromMacroBrowser = (macroProvider: MacroProvider, macroNode?: PmNode, isEditing?: boolean) => (view: EditorView) => Promise<boolean>;
59
65
  export type RunMacroAutoConvert = (state: EditorState, text: string) => PmNode | null;
@@ -1,11 +1,25 @@
1
- import type { FloatingToolbarHandler, PublicPluginAPI } from '@atlaskit/editor-common/types';
1
+ import { type ExtensionProvider } from '@atlaskit/editor-common/extensions';
2
+ import type { Command, FloatingToolbarHandler, PublicPluginAPI } from '@atlaskit/editor-common/types';
2
3
  import type { AnalyticsPlugin } from '@atlaskit/editor-plugin-analytics';
3
4
  import type { ConnectivityPlugin } from '@atlaskit/editor-plugin-connectivity';
4
5
  import type { ContextPanelPlugin } from '@atlaskit/editor-plugin-context-panel';
5
6
  import type { DecorationsPlugin } from '@atlaskit/editor-plugin-decorations';
7
+ import type { EditorState } from '@atlaskit/editor-prosemirror/state';
8
+ import type { ExtensionPluginOptions } from '../extensionPluginType';
9
+ /**
10
+ * Creates a function that copies the text content of the unsupported content extension to the clipboard
11
+ * if the current selected extension is an unsupported content extension.
12
+ */
13
+ export declare const createOnClickCopyButton: ({ extensionApi, extensionProvider, getUnsupportedContent, state, }: {
14
+ extensionApi: GetToolbarConfigProps["extensionApi"];
15
+ extensionProvider?: ExtensionProvider;
16
+ getUnsupportedContent?: ExtensionPluginOptions["getUnsupportedContent"];
17
+ state: EditorState;
18
+ }) => Command | undefined;
6
19
  interface GetToolbarConfigProps {
7
20
  breakoutEnabled: boolean | undefined;
8
21
  extensionApi?: PublicPluginAPI<[ContextPanelPlugin, AnalyticsPlugin, DecorationsPlugin, ConnectivityPlugin]> | undefined;
22
+ getUnsupportedContent?: ExtensionPluginOptions['getUnsupportedContent'];
9
23
  }
10
- export declare const getToolbarConfig: ({ breakoutEnabled, extensionApi }: GetToolbarConfigProps) => FloatingToolbarHandler;
24
+ export declare const getToolbarConfig: ({ breakoutEnabled, extensionApi, getUnsupportedContent, }: GetToolbarConfigProps) => FloatingToolbarHandler;
11
25
  export {};
@@ -1,3 +1,6 @@
1
+ import type { PublicPluginAPI } from '@atlaskit/editor-common/types';
2
+ import { type JSONDocNode } from '@atlaskit/editor-json-transformer';
3
+ import type { AnalyticsPlugin } from '@atlaskit/editor-plugin-analytics';
1
4
  import type { Mark, Node as PMNode, Schema } from '@atlaskit/editor-prosemirror/model';
2
5
  import type { EditorState } from '@atlaskit/editor-prosemirror/state';
3
6
  import type { DomAtPos, NodeWithPos } from '@atlaskit/editor-prosemirror/utils';
@@ -13,3 +16,15 @@ export interface Position {
13
16
  right?: number;
14
17
  top?: number;
15
18
  }
19
+ /**
20
+ * copying ADF from the unsupported content extension as text to clipboard
21
+ */
22
+ export declare const copyUnsupportedContentToClipboard: ({ schema, unsupportedContent, }: {
23
+ schema: Schema;
24
+ unsupportedContent?: JSONDocNode;
25
+ }) => Error | undefined;
26
+ export declare const onCopyFailed: ({ error, extensionApi, state, }: {
27
+ error: Error;
28
+ extensionApi?: PublicPluginAPI<[AnalyticsPlugin]>;
29
+ state: EditorState;
30
+ }) => void;
@@ -1,9 +1,10 @@
1
1
  import type { ADFEntity } from '@atlaskit/adf-utils/types';
2
2
  import type { EditorAnalyticsAPI } from '@atlaskit/editor-common/analytics';
3
3
  import type { GetPMNodeHeight } from '@atlaskit/editor-common/extensibility';
4
- import type { ExtensionAPI, ExtensionHandlers, ExtensionProvider, Parameters, TransformAfter, TransformBefore, UpdateExtension } from '@atlaskit/editor-common/extensions';
4
+ import type { ExtensionAPI, ExtensionHandlers, ExtensionParams, ExtensionProvider, Parameters, TransformAfter, TransformBefore, UpdateExtension } from '@atlaskit/editor-common/extensions';
5
5
  import type { MacroProvider } from '@atlaskit/editor-common/provider-factory';
6
6
  import type { EditorAppearance, LongPressSelectionPluginOptions, NextEditorPlugin, OptionalPlugin } from '@atlaskit/editor-common/types';
7
+ import type { JSONDocNode } from '@atlaskit/editor-json-transformer';
7
8
  import type { AnalyticsPlugin } from '@atlaskit/editor-plugin-analytics';
8
9
  import type { ConnectivityPlugin } from '@atlaskit/editor-plugin-connectivity';
9
10
  import type { ContextIdentifierPlugin } from '@atlaskit/editor-plugin-context-identifier';
@@ -54,6 +55,11 @@ export interface ExtensionPluginOptions extends LongPressSelectionPluginOptions
54
55
  * Helps optimize layout shift while rendering by setting minimum heights before the extension content loads.
55
56
  */
56
57
  getExtensionHeight?: GetPMNodeHeight;
58
+ /**
59
+ * Returns the ADF content of the unsupported content extension.
60
+ * Which will be copied to the clipboard when the copy button is clicked.
61
+ */
62
+ getUnsupportedContent?: (node: ExtensionParams<Parameters>) => JSONDocNode | undefined;
57
63
  }
58
64
  type InsertMacroFromMacroBrowser = (macroProvider: MacroProvider, macroNode?: PmNode, isEditing?: boolean) => (view: EditorView) => Promise<boolean>;
59
65
  export type RunMacroAutoConvert = (state: EditorState, text: string) => PmNode | null;
@@ -1,8 +1,21 @@
1
- import type { FloatingToolbarHandler, PublicPluginAPI } from '@atlaskit/editor-common/types';
1
+ import { type ExtensionProvider } from '@atlaskit/editor-common/extensions';
2
+ import type { Command, FloatingToolbarHandler, PublicPluginAPI } from '@atlaskit/editor-common/types';
2
3
  import type { AnalyticsPlugin } from '@atlaskit/editor-plugin-analytics';
3
4
  import type { ConnectivityPlugin } from '@atlaskit/editor-plugin-connectivity';
4
5
  import type { ContextPanelPlugin } from '@atlaskit/editor-plugin-context-panel';
5
6
  import type { DecorationsPlugin } from '@atlaskit/editor-plugin-decorations';
7
+ import type { EditorState } from '@atlaskit/editor-prosemirror/state';
8
+ import type { ExtensionPluginOptions } from '../extensionPluginType';
9
+ /**
10
+ * Creates a function that copies the text content of the unsupported content extension to the clipboard
11
+ * if the current selected extension is an unsupported content extension.
12
+ */
13
+ export declare const createOnClickCopyButton: ({ extensionApi, extensionProvider, getUnsupportedContent, state, }: {
14
+ extensionApi: GetToolbarConfigProps["extensionApi"];
15
+ extensionProvider?: ExtensionProvider;
16
+ getUnsupportedContent?: ExtensionPluginOptions["getUnsupportedContent"];
17
+ state: EditorState;
18
+ }) => Command | undefined;
6
19
  interface GetToolbarConfigProps {
7
20
  breakoutEnabled: boolean | undefined;
8
21
  extensionApi?: PublicPluginAPI<[
@@ -11,6 +24,7 @@ interface GetToolbarConfigProps {
11
24
  DecorationsPlugin,
12
25
  ConnectivityPlugin
13
26
  ]> | undefined;
27
+ getUnsupportedContent?: ExtensionPluginOptions['getUnsupportedContent'];
14
28
  }
15
- export declare const getToolbarConfig: ({ breakoutEnabled, extensionApi }: GetToolbarConfigProps) => FloatingToolbarHandler;
29
+ export declare const getToolbarConfig: ({ breakoutEnabled, extensionApi, getUnsupportedContent, }: GetToolbarConfigProps) => FloatingToolbarHandler;
16
30
  export {};
@@ -1,3 +1,6 @@
1
+ import type { PublicPluginAPI } from '@atlaskit/editor-common/types';
2
+ import { type JSONDocNode } from '@atlaskit/editor-json-transformer';
3
+ import type { AnalyticsPlugin } from '@atlaskit/editor-plugin-analytics';
1
4
  import type { Mark, Node as PMNode, Schema } from '@atlaskit/editor-prosemirror/model';
2
5
  import type { EditorState } from '@atlaskit/editor-prosemirror/state';
3
6
  import type { DomAtPos, NodeWithPos } from '@atlaskit/editor-prosemirror/utils';
@@ -13,3 +16,17 @@ export interface Position {
13
16
  right?: number;
14
17
  top?: number;
15
18
  }
19
+ /**
20
+ * copying ADF from the unsupported content extension as text to clipboard
21
+ */
22
+ export declare const copyUnsupportedContentToClipboard: ({ schema, unsupportedContent, }: {
23
+ schema: Schema;
24
+ unsupportedContent?: JSONDocNode;
25
+ }) => Error | undefined;
26
+ export declare const onCopyFailed: ({ error, extensionApi, state, }: {
27
+ error: Error;
28
+ extensionApi?: PublicPluginAPI<[
29
+ AnalyticsPlugin
30
+ ]>;
31
+ state: EditorState;
32
+ }) => void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-extension",
3
- "version": "10.0.15",
3
+ "version": "10.1.0",
4
4
  "description": "editor-plugin-extension plugin for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -56,7 +56,7 @@
56
56
  "@atlaskit/textarea": "^8.2.0",
57
57
  "@atlaskit/textfield": "^8.2.0",
58
58
  "@atlaskit/theme": "^21.0.0",
59
- "@atlaskit/tmp-editor-statsig": "^25.0.0",
59
+ "@atlaskit/tmp-editor-statsig": "^25.2.0",
60
60
  "@atlaskit/toggle": "^15.2.0",
61
61
  "@atlaskit/tokens": "^11.0.0",
62
62
  "@atlaskit/tooltip": "^20.14.0",
@@ -70,7 +70,7 @@
70
70
  "uuid": "^3.1.0"
71
71
  },
72
72
  "peerDependencies": {
73
- "@atlaskit/editor-common": "^111.12.0",
73
+ "@atlaskit/editor-common": "^111.13.0",
74
74
  "react": "^18.2.0",
75
75
  "react-intl-next": "npm:react-intl@^5.18.1"
76
76
  },