@atlaskit/editor-plugin-copy-button 0.1.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/dist/cjs/commands.js +172 -0
- package/dist/cjs/index.js +8 -1
- package/dist/cjs/plugin.js +28 -0
- package/dist/cjs/pm-plugins/main.js +104 -0
- package/dist/cjs/pm-plugins/plugin-key.js +9 -0
- package/dist/cjs/toolbar.js +103 -0
- package/dist/cjs/types.js +3 -3
- package/dist/cjs/utils.js +22 -0
- package/dist/es2019/commands.js +158 -0
- package/dist/es2019/index.js +1 -1
- package/dist/es2019/plugin.js +19 -0
- package/dist/es2019/pm-plugins/main.js +97 -0
- package/dist/es2019/pm-plugins/plugin-key.js +2 -0
- package/dist/es2019/toolbar.js +85 -0
- package/dist/es2019/types.js +3 -1
- package/dist/es2019/utils.js +15 -0
- package/dist/esm/commands.js +160 -0
- package/dist/esm/index.js +1 -1
- package/dist/esm/plugin.js +20 -0
- package/dist/esm/pm-plugins/main.js +96 -0
- package/dist/esm/pm-plugins/plugin-key.js +2 -0
- package/dist/esm/toolbar.js +94 -0
- package/dist/esm/types.js +3 -1
- package/dist/esm/utils.js +14 -0
- package/dist/types/commands.d.ts +10 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/plugin.d.ts +2 -0
- package/dist/types/pm-plugins/main.d.ts +4 -0
- package/dist/types/pm-plugins/plugin-key.d.ts +2 -0
- package/dist/types/toolbar.d.ts +13 -0
- package/dist/types/types.d.ts +10 -2
- package/dist/types/utils.d.ts +7 -0
- package/dist/types-ts4.5/commands.d.ts +10 -0
- package/dist/types-ts4.5/index.d.ts +1 -0
- package/dist/types-ts4.5/plugin.d.ts +2 -0
- package/dist/types-ts4.5/pm-plugins/main.d.ts +4 -0
- package/dist/types-ts4.5/pm-plugins/plugin-key.d.ts +2 -0
- package/dist/types-ts4.5/toolbar.d.ts +13 -0
- package/dist/types-ts4.5/types.d.ts +12 -2
- package/dist/types-ts4.5/utils.d.ts +7 -0
- package/package.json +9 -3
- package/report.api.md +32 -1
- package/tmp/api-report-tmp.d.ts +18 -1
- package/toolbar/package.json +15 -0
- package/utils/package.json +15 -0
package/CHANGELOG.md
CHANGED
|
@@ -1 +1,17 @@
|
|
|
1
1
|
# @atlaskit/editor-plugin-copy-button
|
|
2
|
+
|
|
3
|
+
## 0.2.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies
|
|
8
|
+
|
|
9
|
+
## 0.2.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- [`9f2365fabcc`](https://bitbucket.org/atlassian/atlassian-frontend/commits/9f2365fabcc) - ED-19617 - Initial creation of editor-plugin-copy-button package
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- Updated dependencies
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.createToolbarCopyCommandForMark = createToolbarCopyCommandForMark;
|
|
7
|
+
exports.createToolbarCopyCommandForNode = void 0;
|
|
8
|
+
exports.getProvideMarkVisualFeedbackForCopyButtonCommand = getProvideMarkVisualFeedbackForCopyButtonCommand;
|
|
9
|
+
exports.removeMarkVisualFeedbackForCopyButtonCommand = removeMarkVisualFeedbackForCopyButtonCommand;
|
|
10
|
+
exports.resetCopiedState = void 0;
|
|
11
|
+
var _analytics = require("@atlaskit/editor-common/analytics");
|
|
12
|
+
var _clipboard = require("@atlaskit/editor-common/clipboard");
|
|
13
|
+
var _utils = require("@atlaskit/editor-common/utils");
|
|
14
|
+
var _state = require("@atlaskit/editor-prosemirror/state");
|
|
15
|
+
var _pluginKey = require("./pm-plugins/plugin-key");
|
|
16
|
+
var _utils2 = require("./utils");
|
|
17
|
+
function createToolbarCopyCommandForMark(markType, editorAnalyticsApi) {
|
|
18
|
+
function command(state, dispatch) {
|
|
19
|
+
var textNode = state.tr.selection.$head.parent.maybeChild(state.tr.selection.$head.index());
|
|
20
|
+
if (!textNode) {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
if (dispatch) {
|
|
24
|
+
// As calling copyHTMLToClipboard causes side effects -- we only run this when
|
|
25
|
+
// dispatch is provided -- as otherwise the consumer is only testing to see if
|
|
26
|
+
// the action is availble.
|
|
27
|
+
var domNode = (0, _utils2.toDOM)(textNode, state.schema);
|
|
28
|
+
if (domNode) {
|
|
29
|
+
var div = document.createElement('div');
|
|
30
|
+
var p = document.createElement('p');
|
|
31
|
+
div.appendChild(p);
|
|
32
|
+
p.appendChild(domNode);
|
|
33
|
+
// The "1 1" refers to the start and end depth of the slice
|
|
34
|
+
// since we're copying the text inside a paragraph, it will always be 1 1
|
|
35
|
+
// https://github.com/ProseMirror/prosemirror-view/blob/master/src/clipboard.ts#L32
|
|
36
|
+
div.firstChild.setAttribute('data-pm-slice', '1 1 []');
|
|
37
|
+
|
|
38
|
+
// If we're copying a hyperlink, we'd copy the url as the fallback plain text
|
|
39
|
+
var linkUrl = domNode.getAttribute('href');
|
|
40
|
+
(0, _clipboard.copyHTMLToClipboard)(div, markType.name === 'link' && linkUrl ? linkUrl : undefined);
|
|
41
|
+
}
|
|
42
|
+
var copyToClipboardTr = state.tr;
|
|
43
|
+
copyToClipboardTr.setMeta(_pluginKey.copyButtonPluginKey, {
|
|
44
|
+
copied: true
|
|
45
|
+
});
|
|
46
|
+
var analyticsPayload = (0, _clipboard.getAnalyticsPayload)(state, _analytics.ACTION.COPIED);
|
|
47
|
+
if (analyticsPayload && editorAnalyticsApi) {
|
|
48
|
+
var _editorAnalyticsApi$a;
|
|
49
|
+
analyticsPayload.attributes.inputMethod = _analytics.INPUT_METHOD.FLOATING_TB;
|
|
50
|
+
analyticsPayload.attributes.markType = markType.name;
|
|
51
|
+
editorAnalyticsApi === null || editorAnalyticsApi === void 0 ? void 0 : (_editorAnalyticsApi$a = editorAnalyticsApi.attachAnalyticsEvent) === null || _editorAnalyticsApi$a === void 0 ? void 0 : _editorAnalyticsApi$a.call(editorAnalyticsApi, analyticsPayload)(copyToClipboardTr);
|
|
52
|
+
}
|
|
53
|
+
dispatch(copyToClipboardTr);
|
|
54
|
+
}
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
return command;
|
|
58
|
+
}
|
|
59
|
+
function getProvideMarkVisualFeedbackForCopyButtonCommand(markType) {
|
|
60
|
+
function provideMarkVisualFeedbackForCopyButtonCommand(state, dispatch) {
|
|
61
|
+
var tr = state.tr;
|
|
62
|
+
tr.setMeta(_pluginKey.copyButtonPluginKey, {
|
|
63
|
+
showSelection: true,
|
|
64
|
+
markType: markType
|
|
65
|
+
});
|
|
66
|
+
if (dispatch) {
|
|
67
|
+
dispatch(tr);
|
|
68
|
+
}
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
return provideMarkVisualFeedbackForCopyButtonCommand;
|
|
72
|
+
}
|
|
73
|
+
function removeMarkVisualFeedbackForCopyButtonCommand(state, dispatch) {
|
|
74
|
+
var tr = state.tr;
|
|
75
|
+
tr.setMeta(_pluginKey.copyButtonPluginKey, {
|
|
76
|
+
removeSelection: true
|
|
77
|
+
});
|
|
78
|
+
var copyButtonState = _pluginKey.copyButtonPluginKey.getState(state);
|
|
79
|
+
if (copyButtonState !== null && copyButtonState !== void 0 && copyButtonState.copied) {
|
|
80
|
+
tr.setMeta(_pluginKey.copyButtonPluginKey, {
|
|
81
|
+
copied: false
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
if (dispatch) {
|
|
85
|
+
dispatch(tr);
|
|
86
|
+
}
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
var createToolbarCopyCommandForNode = function createToolbarCopyCommandForNode(nodeType, editorAnalyticsApi) {
|
|
90
|
+
return function (state, dispatch) {
|
|
91
|
+
var tr = state.tr,
|
|
92
|
+
schema = state.schema;
|
|
93
|
+
|
|
94
|
+
// This command should only be triggered by the Copy button in the floating toolbar
|
|
95
|
+
// which is only visible when selection is inside the target node
|
|
96
|
+
var contentNodeWithPos = (0, _utils2.getSelectedNodeOrNodeParentByNodeType)({
|
|
97
|
+
nodeType: nodeType,
|
|
98
|
+
selection: tr.selection
|
|
99
|
+
});
|
|
100
|
+
if (!contentNodeWithPos) {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
var copyToClipboardTr = tr;
|
|
104
|
+
copyToClipboardTr.setMeta(_pluginKey.copyButtonPluginKey, {
|
|
105
|
+
copied: true
|
|
106
|
+
});
|
|
107
|
+
var analyticsPayload = (0, _clipboard.getAnalyticsPayload)(state, _analytics.ACTION.COPIED);
|
|
108
|
+
if (analyticsPayload && editorAnalyticsApi) {
|
|
109
|
+
var _editorAnalyticsApi$a2;
|
|
110
|
+
analyticsPayload.attributes.inputMethod = _analytics.INPUT_METHOD.FLOATING_TB;
|
|
111
|
+
analyticsPayload.attributes.nodeType = contentNodeWithPos.node.type.name;
|
|
112
|
+
editorAnalyticsApi === null || editorAnalyticsApi === void 0 ? void 0 : (_editorAnalyticsApi$a2 = editorAnalyticsApi.attachAnalyticsEvent) === null || _editorAnalyticsApi$a2 === void 0 ? void 0 : _editorAnalyticsApi$a2.call(editorAnalyticsApi, analyticsPayload)(copyToClipboardTr);
|
|
113
|
+
}
|
|
114
|
+
if (dispatch) {
|
|
115
|
+
// As calling copyHTMLToClipboard causes side effects -- we only run this when
|
|
116
|
+
// dispatch is provided -- as otherwise the consumer is only testing to see if
|
|
117
|
+
// the action is availble.
|
|
118
|
+
var domNode = (0, _utils2.toDOM)(contentNodeWithPos.node, schema);
|
|
119
|
+
if (domNode) {
|
|
120
|
+
var div = document.createElement('div');
|
|
121
|
+
div.appendChild(domNode);
|
|
122
|
+
|
|
123
|
+
// if copying inline content
|
|
124
|
+
if (contentNodeWithPos.node.type.inlineContent) {
|
|
125
|
+
// The "1 1" refers to the start and end depth of the slice
|
|
126
|
+
// since we're copying the text inside a paragraph, it will always be 1 1
|
|
127
|
+
// https://github.com/ProseMirror/prosemirror-view/blob/master/src/clipboard.ts#L32
|
|
128
|
+
div.firstChild.setAttribute('data-pm-slice', '1 1 []');
|
|
129
|
+
} else {
|
|
130
|
+
// The "0 0" refers to the start and end depth of the slice
|
|
131
|
+
// since we're copying the block node only, it will always be 0 0
|
|
132
|
+
// https://github.com/ProseMirror/prosemirror-view/blob/master/src/clipboard.ts#L32
|
|
133
|
+
div.firstChild.setAttribute('data-pm-slice', '0 0 []');
|
|
134
|
+
}
|
|
135
|
+
// ED-17083 safari seems have bugs for extension copy because exntension do not have a child text(innerText) and it will not recognized as html in clipboard, this could be merge into one if this extension fixed children issue or safari fix the copy bug
|
|
136
|
+
// MEX-2528 safari has a bug related to the mediaSingle node with border or link. The image tag within the clipboard is not recognized as HTML when using the ClipboardItem API. To address this, we have to switch to ClipboardPolyfill
|
|
137
|
+
if (_utils.browser.safari && state.selection instanceof _state.NodeSelection && (state.selection.node.type === state.schema.nodes.extension || state.selection.node.type === state.schema.nodes.mediaSingle)) {
|
|
138
|
+
(0, _clipboard.copyHTMLToClipboardPolyfill)(div);
|
|
139
|
+
} else {
|
|
140
|
+
(0, _clipboard.copyHTMLToClipboard)(div);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
copyToClipboardTr.setMeta('scrollIntoView', false);
|
|
144
|
+
dispatch(copyToClipboardTr);
|
|
145
|
+
}
|
|
146
|
+
return true;
|
|
147
|
+
};
|
|
148
|
+
};
|
|
149
|
+
exports.createToolbarCopyCommandForNode = createToolbarCopyCommandForNode;
|
|
150
|
+
var resetCopiedState = function resetCopiedState(nodeType, hoverDecoration, onMouseLeave) {
|
|
151
|
+
return function (state, dispatch) {
|
|
152
|
+
var customTr = state.tr;
|
|
153
|
+
|
|
154
|
+
// Avoid multipe dispatch
|
|
155
|
+
// https://product-fabric.atlassian.net/wiki/spaces/E/pages/2241659456/All+about+dispatch+and+why+there+shouldn+t+be+multiple#How-do-I-avoid-them%3F
|
|
156
|
+
var customDispatch = function customDispatch(tr) {
|
|
157
|
+
customTr = tr;
|
|
158
|
+
};
|
|
159
|
+
onMouseLeave ? onMouseLeave(state, customDispatch) : hoverDecoration === null || hoverDecoration === void 0 ? void 0 : hoverDecoration(nodeType, false)(state, customDispatch);
|
|
160
|
+
var copyButtonState = _pluginKey.copyButtonPluginKey.getState(state);
|
|
161
|
+
if (copyButtonState !== null && copyButtonState !== void 0 && copyButtonState.copied) {
|
|
162
|
+
customTr.setMeta(_pluginKey.copyButtonPluginKey, {
|
|
163
|
+
copied: false
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
if (dispatch) {
|
|
167
|
+
dispatch(customTr);
|
|
168
|
+
}
|
|
169
|
+
return true;
|
|
170
|
+
};
|
|
171
|
+
};
|
|
172
|
+
exports.resetCopiedState = resetCopiedState;
|
package/dist/cjs/index.js
CHANGED
|
@@ -2,4 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
|
-
});
|
|
5
|
+
});
|
|
6
|
+
Object.defineProperty(exports, "copyButtonPlugin", {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: function get() {
|
|
9
|
+
return _plugin.copyButtonPlugin;
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
var _plugin = require("./plugin");
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.copyButtonPlugin = void 0;
|
|
8
|
+
var _main = _interopRequireDefault(require("./pm-plugins/main"));
|
|
9
|
+
var _toolbar = require("./toolbar");
|
|
10
|
+
var copyButtonPlugin = function copyButtonPlugin(_ref) {
|
|
11
|
+
var _api$analytics;
|
|
12
|
+
var api = _ref.api;
|
|
13
|
+
return {
|
|
14
|
+
name: 'copyButton',
|
|
15
|
+
pmPlugins: function pmPlugins() {
|
|
16
|
+
return [{
|
|
17
|
+
name: 'copyButton',
|
|
18
|
+
plugin: function plugin() {
|
|
19
|
+
return (0, _main.default)();
|
|
20
|
+
}
|
|
21
|
+
}];
|
|
22
|
+
},
|
|
23
|
+
actions: {
|
|
24
|
+
processCopyButtonItems: (0, _toolbar.processCopyButtonItems)(api === null || api === void 0 ? void 0 : (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions)
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
exports.copyButtonPlugin = copyButtonPlugin;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.copyButtonPlugin = copyButtonPlugin;
|
|
7
|
+
exports.default = void 0;
|
|
8
|
+
var _safePlugin = require("@atlaskit/editor-common/safe-plugin");
|
|
9
|
+
var _view = require("@atlaskit/editor-prosemirror/view");
|
|
10
|
+
var _pluginKey = require("./plugin-key");
|
|
11
|
+
function getMarkSelectionDecorationStartAndEnd(_ref) {
|
|
12
|
+
var markType = _ref.markType,
|
|
13
|
+
transaction = _ref.transaction;
|
|
14
|
+
var headResolvedPos = transaction.selection.$head;
|
|
15
|
+
var textNodeIndex = transaction.selection.$head.index();
|
|
16
|
+
var textNode = headResolvedPos.parent.maybeChild(textNodeIndex);
|
|
17
|
+
var textNodeOffset = 0;
|
|
18
|
+
headResolvedPos.parent.forEach(function (_node, nodeOffset, index) {
|
|
19
|
+
if (index === textNodeIndex) {
|
|
20
|
+
textNodeOffset = nodeOffset;
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
var start = headResolvedPos.start(headResolvedPos.depth) + textNodeOffset;
|
|
24
|
+
var end = start + textNode.text.length;
|
|
25
|
+
return {
|
|
26
|
+
start: start,
|
|
27
|
+
end: end,
|
|
28
|
+
markType: markType
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
function copyButtonPlugin() {
|
|
32
|
+
return new _safePlugin.SafePlugin({
|
|
33
|
+
key: _pluginKey.copyButtonPluginKey,
|
|
34
|
+
state: {
|
|
35
|
+
init: function init() {
|
|
36
|
+
return {
|
|
37
|
+
copied: false,
|
|
38
|
+
markSelection: undefined
|
|
39
|
+
};
|
|
40
|
+
},
|
|
41
|
+
apply: function apply(tr, currentPluginState) {
|
|
42
|
+
var meta = tr.getMeta(_pluginKey.copyButtonPluginKey);
|
|
43
|
+
if ((meta === null || meta === void 0 ? void 0 : meta.copied) !== undefined) {
|
|
44
|
+
return {
|
|
45
|
+
copied: meta.copied,
|
|
46
|
+
markSelection: undefined
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
if (meta !== null && meta !== void 0 && meta.showSelection) {
|
|
50
|
+
return {
|
|
51
|
+
copied: currentPluginState.copied,
|
|
52
|
+
markSelection: getMarkSelectionDecorationStartAndEnd({
|
|
53
|
+
markType: meta.markType,
|
|
54
|
+
transaction: tr
|
|
55
|
+
})
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
if (meta !== null && meta !== void 0 && meta.removeSelection) {
|
|
59
|
+
return {
|
|
60
|
+
copied: currentPluginState.copied,
|
|
61
|
+
markSelection: undefined
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
if (currentPluginState.markSelection) {
|
|
65
|
+
return {
|
|
66
|
+
copied: currentPluginState.copied,
|
|
67
|
+
markSelection: getMarkSelectionDecorationStartAndEnd({
|
|
68
|
+
markType: currentPluginState.markSelection.markType,
|
|
69
|
+
transaction: tr
|
|
70
|
+
})
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
return currentPluginState;
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
props: {
|
|
77
|
+
decorations: function decorations(_state) {
|
|
78
|
+
// Showing visual hints for the hyperlink copy button has been disabled
|
|
79
|
+
// due to an issue where invalid hyperlink marks cause the floating toolbar
|
|
80
|
+
// to jump around when the copy button is hovered.
|
|
81
|
+
// See the following bug for details -- once that is resolved -- the visual
|
|
82
|
+
// hints can be re enabled.
|
|
83
|
+
// https://product-fabric.atlassian.net/browse/DTR-722
|
|
84
|
+
|
|
85
|
+
// const copyButtonPluginState = copyButtonPluginKey.getState(
|
|
86
|
+
// state,
|
|
87
|
+
// ) as CopyButtonPluginState;
|
|
88
|
+
// if (copyButtonPluginState.markSelection) {
|
|
89
|
+
// const { start, end } = copyButtonPluginState.markSelection;
|
|
90
|
+
|
|
91
|
+
// return DecorationSet.create(state.doc, [
|
|
92
|
+
// Decoration.inline(start, end, {
|
|
93
|
+
// class: 'ProseMirror-fake-text-selection',
|
|
94
|
+
// }),
|
|
95
|
+
// ]);
|
|
96
|
+
// }
|
|
97
|
+
|
|
98
|
+
return _view.DecorationSet.empty;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
var _default = copyButtonPlugin;
|
|
104
|
+
exports.default = _default;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.copyButtonPluginKey = void 0;
|
|
7
|
+
var _state = require("@atlaskit/editor-prosemirror/state");
|
|
8
|
+
var copyButtonPluginKey = new _state.PluginKey('copyButtonPlugin');
|
|
9
|
+
exports.copyButtonPluginKey = copyButtonPluginKey;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.getCopyButtonConfig = getCopyButtonConfig;
|
|
8
|
+
exports.showCopyButton = exports.processCopyButtonItems = void 0;
|
|
9
|
+
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
10
|
+
var _messages = _interopRequireDefault(require("@atlaskit/editor-common/messages"));
|
|
11
|
+
var _copy = _interopRequireDefault(require("@atlaskit/icon/glyph/copy"));
|
|
12
|
+
var _commands = require("./commands");
|
|
13
|
+
var _pluginKey = require("./pm-plugins/plugin-key");
|
|
14
|
+
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
15
|
+
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; }
|
|
16
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
17
|
+
function isSeparator(item) {
|
|
18
|
+
return (item === null || item === void 0 ? void 0 : item.type) === 'separator';
|
|
19
|
+
}
|
|
20
|
+
function isNodeOptions(options) {
|
|
21
|
+
return 'nodeType' in options && options.nodeType !== undefined;
|
|
22
|
+
}
|
|
23
|
+
function getCopyButtonConfig(options, hoverDecoration, editorAnalyticsApi) {
|
|
24
|
+
var state = options.state,
|
|
25
|
+
formatMessage = options.formatMessage,
|
|
26
|
+
onMouseEnter = options.onMouseEnter,
|
|
27
|
+
onMouseLeave = options.onMouseLeave,
|
|
28
|
+
onFocus = options.onFocus,
|
|
29
|
+
onBlur = options.onBlur;
|
|
30
|
+
var copyButtonState = _pluginKey.copyButtonPluginKey.getState(state);
|
|
31
|
+
var buttonActionHandlers;
|
|
32
|
+
if (isNodeOptions(options)) {
|
|
33
|
+
buttonActionHandlers = {
|
|
34
|
+
onClick: (0, _commands.createToolbarCopyCommandForNode)(options.nodeType, editorAnalyticsApi),
|
|
35
|
+
// Note for future changes: these two handlers should perform
|
|
36
|
+
// the same action.
|
|
37
|
+
onMouseEnter: onMouseEnter || (hoverDecoration === null || hoverDecoration === void 0 ? void 0 : hoverDecoration(options.nodeType, true, 'ak-editor-selected-node')),
|
|
38
|
+
onFocus: onFocus || (hoverDecoration === null || hoverDecoration === void 0 ? void 0 : hoverDecoration(options.nodeType, true, 'ak-editor-selected-node')),
|
|
39
|
+
// Note for future changes: these two handlers should perform
|
|
40
|
+
// the same action.
|
|
41
|
+
onMouseLeave: (0, _commands.resetCopiedState)(options.nodeType, hoverDecoration, onMouseLeave),
|
|
42
|
+
onBlur: (0, _commands.resetCopiedState)(options.nodeType, hoverDecoration, onBlur)
|
|
43
|
+
};
|
|
44
|
+
} else {
|
|
45
|
+
buttonActionHandlers = {
|
|
46
|
+
onClick: (0, _commands.createToolbarCopyCommandForMark)(options.markType, editorAnalyticsApi),
|
|
47
|
+
onMouseEnter: (0, _commands.getProvideMarkVisualFeedbackForCopyButtonCommand)(options.markType),
|
|
48
|
+
onFocus: (0, _commands.getProvideMarkVisualFeedbackForCopyButtonCommand)(options.markType),
|
|
49
|
+
onMouseLeave: _commands.removeMarkVisualFeedbackForCopyButtonCommand,
|
|
50
|
+
onBlur: _commands.removeMarkVisualFeedbackForCopyButtonCommand
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
return _objectSpread(_objectSpread({
|
|
54
|
+
id: 'editor.floatingToolbar.copy',
|
|
55
|
+
type: 'button',
|
|
56
|
+
appearance: 'subtle',
|
|
57
|
+
icon: _copy.default,
|
|
58
|
+
title: formatMessage(copyButtonState !== null && copyButtonState !== void 0 && copyButtonState.copied ? _messages.default.copiedToClipboard : _messages.default.copyToClipboard)
|
|
59
|
+
}, buttonActionHandlers), {}, {
|
|
60
|
+
hideTooltipOnClick: false,
|
|
61
|
+
tabIndex: null
|
|
62
|
+
// TODO select and delete styling needs to be removed when keyboard cursor moves away
|
|
63
|
+
// problem already exist with delete as well
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
var showCopyButton = function showCopyButton(state) {
|
|
68
|
+
return state &&
|
|
69
|
+
// Check if the Copy button plugin is enabled
|
|
70
|
+
// @ts-ignore copyButtonPluginKey.key
|
|
71
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
72
|
+
state.plugins.find(function (p) {
|
|
73
|
+
return p.key === _pluginKey.copyButtonPluginKey.key;
|
|
74
|
+
});
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Process floatingToolbar items for copyButton
|
|
79
|
+
*
|
|
80
|
+
* If copy button plugin not enabled, remove copy button item from toolbar items
|
|
81
|
+
* else process copy button to standard floatingtoobarbutton
|
|
82
|
+
*/
|
|
83
|
+
exports.showCopyButton = showCopyButton;
|
|
84
|
+
var processCopyButtonItems = function processCopyButtonItems(editorAnalyticsApi) {
|
|
85
|
+
return function (state) {
|
|
86
|
+
return function (items, hoverDecoration) {
|
|
87
|
+
return items.flatMap(function (item) {
|
|
88
|
+
switch (item.type) {
|
|
89
|
+
case 'copy-button':
|
|
90
|
+
if (item !== null && item !== void 0 && item.hidden || !showCopyButton(state)) {
|
|
91
|
+
return [];
|
|
92
|
+
}
|
|
93
|
+
return item === null || item === void 0 ? void 0 : item.items.map(function (copyButtonItem) {
|
|
94
|
+
return isSeparator(copyButtonItem) ? copyButtonItem : getCopyButtonConfig(copyButtonItem, hoverDecoration, editorAnalyticsApi);
|
|
95
|
+
});
|
|
96
|
+
default:
|
|
97
|
+
return [item];
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
};
|
|
101
|
+
};
|
|
102
|
+
};
|
|
103
|
+
exports.processCopyButtonItems = processCopyButtonItems;
|
package/dist/cjs/types.js
CHANGED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.getSelectedNodeOrNodeParentByNodeType = getSelectedNodeOrNodeParentByNodeType;
|
|
7
|
+
exports.toDOM = void 0;
|
|
8
|
+
var _model = require("@atlaskit/editor-prosemirror/model");
|
|
9
|
+
var _utils = require("@atlaskit/editor-prosemirror/utils");
|
|
10
|
+
function getSelectedNodeOrNodeParentByNodeType(_ref) {
|
|
11
|
+
var nodeType = _ref.nodeType,
|
|
12
|
+
selection = _ref.selection;
|
|
13
|
+
var node = (0, _utils.findSelectedNodeOfType)(nodeType)(selection);
|
|
14
|
+
if (!node) {
|
|
15
|
+
node = (0, _utils.findParentNodeOfType)(nodeType)(selection);
|
|
16
|
+
}
|
|
17
|
+
return node;
|
|
18
|
+
}
|
|
19
|
+
var toDOM = function toDOM(node, schema) {
|
|
20
|
+
return _model.DOMSerializer.fromSchema(schema).serializeNode(node);
|
|
21
|
+
};
|
|
22
|
+
exports.toDOM = toDOM;
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { ACTION, INPUT_METHOD } from '@atlaskit/editor-common/analytics';
|
|
2
|
+
import { copyHTMLToClipboard, copyHTMLToClipboardPolyfill, getAnalyticsPayload } from '@atlaskit/editor-common/clipboard';
|
|
3
|
+
import { browser } from '@atlaskit/editor-common/utils';
|
|
4
|
+
import { NodeSelection } from '@atlaskit/editor-prosemirror/state';
|
|
5
|
+
import { copyButtonPluginKey } from './pm-plugins/plugin-key';
|
|
6
|
+
import { getSelectedNodeOrNodeParentByNodeType, toDOM } from './utils';
|
|
7
|
+
export function createToolbarCopyCommandForMark(markType, editorAnalyticsApi) {
|
|
8
|
+
function command(state, dispatch) {
|
|
9
|
+
const textNode = state.tr.selection.$head.parent.maybeChild(state.tr.selection.$head.index());
|
|
10
|
+
if (!textNode) {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
if (dispatch) {
|
|
14
|
+
// As calling copyHTMLToClipboard causes side effects -- we only run this when
|
|
15
|
+
// dispatch is provided -- as otherwise the consumer is only testing to see if
|
|
16
|
+
// the action is availble.
|
|
17
|
+
const domNode = toDOM(textNode, state.schema);
|
|
18
|
+
if (domNode) {
|
|
19
|
+
const div = document.createElement('div');
|
|
20
|
+
const p = document.createElement('p');
|
|
21
|
+
div.appendChild(p);
|
|
22
|
+
p.appendChild(domNode);
|
|
23
|
+
// The "1 1" refers to the start and end depth of the slice
|
|
24
|
+
// since we're copying the text inside a paragraph, it will always be 1 1
|
|
25
|
+
// https://github.com/ProseMirror/prosemirror-view/blob/master/src/clipboard.ts#L32
|
|
26
|
+
div.firstChild.setAttribute('data-pm-slice', '1 1 []');
|
|
27
|
+
|
|
28
|
+
// If we're copying a hyperlink, we'd copy the url as the fallback plain text
|
|
29
|
+
const linkUrl = domNode.getAttribute('href');
|
|
30
|
+
copyHTMLToClipboard(div, markType.name === 'link' && linkUrl ? linkUrl : undefined);
|
|
31
|
+
}
|
|
32
|
+
const copyToClipboardTr = state.tr;
|
|
33
|
+
copyToClipboardTr.setMeta(copyButtonPluginKey, {
|
|
34
|
+
copied: true
|
|
35
|
+
});
|
|
36
|
+
const analyticsPayload = getAnalyticsPayload(state, ACTION.COPIED);
|
|
37
|
+
if (analyticsPayload && editorAnalyticsApi) {
|
|
38
|
+
var _editorAnalyticsApi$a;
|
|
39
|
+
analyticsPayload.attributes.inputMethod = INPUT_METHOD.FLOATING_TB;
|
|
40
|
+
analyticsPayload.attributes.markType = markType.name;
|
|
41
|
+
editorAnalyticsApi === null || editorAnalyticsApi === void 0 ? void 0 : (_editorAnalyticsApi$a = editorAnalyticsApi.attachAnalyticsEvent) === null || _editorAnalyticsApi$a === void 0 ? void 0 : _editorAnalyticsApi$a.call(editorAnalyticsApi, analyticsPayload)(copyToClipboardTr);
|
|
42
|
+
}
|
|
43
|
+
dispatch(copyToClipboardTr);
|
|
44
|
+
}
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
return command;
|
|
48
|
+
}
|
|
49
|
+
export function getProvideMarkVisualFeedbackForCopyButtonCommand(markType) {
|
|
50
|
+
function provideMarkVisualFeedbackForCopyButtonCommand(state, dispatch) {
|
|
51
|
+
const tr = state.tr;
|
|
52
|
+
tr.setMeta(copyButtonPluginKey, {
|
|
53
|
+
showSelection: true,
|
|
54
|
+
markType
|
|
55
|
+
});
|
|
56
|
+
if (dispatch) {
|
|
57
|
+
dispatch(tr);
|
|
58
|
+
}
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
return provideMarkVisualFeedbackForCopyButtonCommand;
|
|
62
|
+
}
|
|
63
|
+
export function removeMarkVisualFeedbackForCopyButtonCommand(state, dispatch) {
|
|
64
|
+
const tr = state.tr;
|
|
65
|
+
tr.setMeta(copyButtonPluginKey, {
|
|
66
|
+
removeSelection: true
|
|
67
|
+
});
|
|
68
|
+
const copyButtonState = copyButtonPluginKey.getState(state);
|
|
69
|
+
if (copyButtonState !== null && copyButtonState !== void 0 && copyButtonState.copied) {
|
|
70
|
+
tr.setMeta(copyButtonPluginKey, {
|
|
71
|
+
copied: false
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
if (dispatch) {
|
|
75
|
+
dispatch(tr);
|
|
76
|
+
}
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
export const createToolbarCopyCommandForNode = (nodeType, editorAnalyticsApi) => (state, dispatch) => {
|
|
80
|
+
const {
|
|
81
|
+
tr,
|
|
82
|
+
schema
|
|
83
|
+
} = state;
|
|
84
|
+
|
|
85
|
+
// This command should only be triggered by the Copy button in the floating toolbar
|
|
86
|
+
// which is only visible when selection is inside the target node
|
|
87
|
+
let contentNodeWithPos = getSelectedNodeOrNodeParentByNodeType({
|
|
88
|
+
nodeType,
|
|
89
|
+
selection: tr.selection
|
|
90
|
+
});
|
|
91
|
+
if (!contentNodeWithPos) {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
const copyToClipboardTr = tr;
|
|
95
|
+
copyToClipboardTr.setMeta(copyButtonPluginKey, {
|
|
96
|
+
copied: true
|
|
97
|
+
});
|
|
98
|
+
const analyticsPayload = getAnalyticsPayload(state, ACTION.COPIED);
|
|
99
|
+
if (analyticsPayload && editorAnalyticsApi) {
|
|
100
|
+
var _editorAnalyticsApi$a2;
|
|
101
|
+
analyticsPayload.attributes.inputMethod = INPUT_METHOD.FLOATING_TB;
|
|
102
|
+
analyticsPayload.attributes.nodeType = contentNodeWithPos.node.type.name;
|
|
103
|
+
editorAnalyticsApi === null || editorAnalyticsApi === void 0 ? void 0 : (_editorAnalyticsApi$a2 = editorAnalyticsApi.attachAnalyticsEvent) === null || _editorAnalyticsApi$a2 === void 0 ? void 0 : _editorAnalyticsApi$a2.call(editorAnalyticsApi, analyticsPayload)(copyToClipboardTr);
|
|
104
|
+
}
|
|
105
|
+
if (dispatch) {
|
|
106
|
+
// As calling copyHTMLToClipboard causes side effects -- we only run this when
|
|
107
|
+
// dispatch is provided -- as otherwise the consumer is only testing to see if
|
|
108
|
+
// the action is availble.
|
|
109
|
+
const domNode = toDOM(contentNodeWithPos.node, schema);
|
|
110
|
+
if (domNode) {
|
|
111
|
+
const div = document.createElement('div');
|
|
112
|
+
div.appendChild(domNode);
|
|
113
|
+
|
|
114
|
+
// if copying inline content
|
|
115
|
+
if (contentNodeWithPos.node.type.inlineContent) {
|
|
116
|
+
// The "1 1" refers to the start and end depth of the slice
|
|
117
|
+
// since we're copying the text inside a paragraph, it will always be 1 1
|
|
118
|
+
// https://github.com/ProseMirror/prosemirror-view/blob/master/src/clipboard.ts#L32
|
|
119
|
+
div.firstChild.setAttribute('data-pm-slice', '1 1 []');
|
|
120
|
+
} else {
|
|
121
|
+
// The "0 0" refers to the start and end depth of the slice
|
|
122
|
+
// since we're copying the block node only, it will always be 0 0
|
|
123
|
+
// https://github.com/ProseMirror/prosemirror-view/blob/master/src/clipboard.ts#L32
|
|
124
|
+
div.firstChild.setAttribute('data-pm-slice', '0 0 []');
|
|
125
|
+
}
|
|
126
|
+
// ED-17083 safari seems have bugs for extension copy because exntension do not have a child text(innerText) and it will not recognized as html in clipboard, this could be merge into one if this extension fixed children issue or safari fix the copy bug
|
|
127
|
+
// MEX-2528 safari has a bug related to the mediaSingle node with border or link. The image tag within the clipboard is not recognized as HTML when using the ClipboardItem API. To address this, we have to switch to ClipboardPolyfill
|
|
128
|
+
if (browser.safari && state.selection instanceof NodeSelection && (state.selection.node.type === state.schema.nodes.extension || state.selection.node.type === state.schema.nodes.mediaSingle)) {
|
|
129
|
+
copyHTMLToClipboardPolyfill(div);
|
|
130
|
+
} else {
|
|
131
|
+
copyHTMLToClipboard(div);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
copyToClipboardTr.setMeta('scrollIntoView', false);
|
|
135
|
+
dispatch(copyToClipboardTr);
|
|
136
|
+
}
|
|
137
|
+
return true;
|
|
138
|
+
};
|
|
139
|
+
export const resetCopiedState = (nodeType, hoverDecoration, onMouseLeave) => (state, dispatch) => {
|
|
140
|
+
let customTr = state.tr;
|
|
141
|
+
|
|
142
|
+
// Avoid multipe dispatch
|
|
143
|
+
// https://product-fabric.atlassian.net/wiki/spaces/E/pages/2241659456/All+about+dispatch+and+why+there+shouldn+t+be+multiple#How-do-I-avoid-them%3F
|
|
144
|
+
const customDispatch = tr => {
|
|
145
|
+
customTr = tr;
|
|
146
|
+
};
|
|
147
|
+
onMouseLeave ? onMouseLeave(state, customDispatch) : hoverDecoration === null || hoverDecoration === void 0 ? void 0 : hoverDecoration(nodeType, false)(state, customDispatch);
|
|
148
|
+
const copyButtonState = copyButtonPluginKey.getState(state);
|
|
149
|
+
if (copyButtonState !== null && copyButtonState !== void 0 && copyButtonState.copied) {
|
|
150
|
+
customTr.setMeta(copyButtonPluginKey, {
|
|
151
|
+
copied: false
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
if (dispatch) {
|
|
155
|
+
dispatch(customTr);
|
|
156
|
+
}
|
|
157
|
+
return true;
|
|
158
|
+
};
|
package/dist/es2019/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export {};
|
|
1
|
+
export { copyButtonPlugin } from './plugin';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import createPlugin from './pm-plugins/main';
|
|
2
|
+
import { processCopyButtonItems } from './toolbar';
|
|
3
|
+
export const copyButtonPlugin = ({
|
|
4
|
+
api
|
|
5
|
+
}) => {
|
|
6
|
+
var _api$analytics;
|
|
7
|
+
return {
|
|
8
|
+
name: 'copyButton',
|
|
9
|
+
pmPlugins() {
|
|
10
|
+
return [{
|
|
11
|
+
name: 'copyButton',
|
|
12
|
+
plugin: () => createPlugin()
|
|
13
|
+
}];
|
|
14
|
+
},
|
|
15
|
+
actions: {
|
|
16
|
+
processCopyButtonItems: processCopyButtonItems(api === null || api === void 0 ? void 0 : (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions)
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
};
|