@atlaskit/editor-plugin-card 0.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/.eslintrc.js +15 -0
- package/CHANGELOG.md +1 -0
- package/LICENSE.md +13 -0
- package/README.md +7 -0
- package/dist/cjs/index.js +12 -0
- package/dist/cjs/messages.js +20 -0
- package/dist/cjs/nodeviews/blockCard.js +164 -0
- package/dist/cjs/nodeviews/datasource.js +173 -0
- package/dist/cjs/nodeviews/embedCard.js +398 -0
- package/dist/cjs/nodeviews/genericCard.js +118 -0
- package/dist/cjs/nodeviews/inlineCard.js +132 -0
- package/dist/cjs/plugin.js +138 -0
- package/dist/cjs/pm-plugins/actions.js +122 -0
- package/dist/cjs/pm-plugins/analytics/create-analytics-queue.js +48 -0
- package/dist/cjs/pm-plugins/analytics/events-from-tr.js +359 -0
- package/dist/cjs/pm-plugins/analytics/index.js +19 -0
- package/dist/cjs/pm-plugins/analytics/types.js +5 -0
- package/dist/cjs/pm-plugins/analytics/utils.js +178 -0
- package/dist/cjs/pm-plugins/doc.js +479 -0
- package/dist/cjs/pm-plugins/keymap.js +64 -0
- package/dist/cjs/pm-plugins/main.js +212 -0
- package/dist/cjs/pm-plugins/mountHyperlink.js +47 -0
- package/dist/cjs/pm-plugins/plugin-key.js +9 -0
- package/dist/cjs/pm-plugins/reducers.js +111 -0
- package/dist/cjs/pm-plugins/shouldReplaceLink.js +35 -0
- package/dist/cjs/pm-plugins/util/resolve.js +59 -0
- package/dist/cjs/pm-plugins/util/state.js +49 -0
- package/dist/cjs/toolbar.js +364 -0
- package/dist/cjs/types.js +5 -0
- package/dist/cjs/ui/DatasourceModal/ModalWithState.js +25 -0
- package/dist/cjs/ui/DatasourceModal/index.js +60 -0
- package/dist/cjs/ui/EditLinkToolbar.js +258 -0
- package/dist/cjs/ui/EditorSmartCardEvents.js +21 -0
- package/dist/cjs/ui/EditorSmartCardEventsNext.js +215 -0
- package/dist/cjs/ui/HyperlinkToolbarAppearance.js +174 -0
- package/dist/cjs/ui/LayoutButton/index.js +121 -0
- package/dist/cjs/ui/LayoutButton/types.js +5 -0
- package/dist/cjs/ui/LayoutButton/utils.js +19 -0
- package/dist/cjs/ui/LinkToolbarAppearance.js +152 -0
- package/dist/cjs/ui/ResizableEmbedCard.js +364 -0
- package/dist/cjs/ui/SmallerEditIcon.js +22 -0
- package/dist/cjs/utils.js +60 -0
- package/dist/cjs/version.json +5 -0
- package/dist/es2019/index.js +1 -0
- package/dist/es2019/messages.js +13 -0
- package/dist/es2019/nodeviews/blockCard.js +131 -0
- package/dist/es2019/nodeviews/datasource.js +137 -0
- package/dist/es2019/nodeviews/embedCard.js +370 -0
- package/dist/es2019/nodeviews/genericCard.js +92 -0
- package/dist/es2019/nodeviews/inlineCard.js +113 -0
- package/dist/es2019/plugin.js +129 -0
- package/dist/es2019/pm-plugins/actions.js +57 -0
- package/dist/es2019/pm-plugins/analytics/create-analytics-queue.js +38 -0
- package/dist/es2019/pm-plugins/analytics/events-from-tr.js +339 -0
- package/dist/es2019/pm-plugins/analytics/index.js +2 -0
- package/dist/es2019/pm-plugins/analytics/types.js +1 -0
- package/dist/es2019/pm-plugins/analytics/utils.js +160 -0
- package/dist/es2019/pm-plugins/doc.js +451 -0
- package/dist/es2019/pm-plugins/keymap.js +59 -0
- package/dist/es2019/pm-plugins/main.js +208 -0
- package/dist/es2019/pm-plugins/mountHyperlink.js +37 -0
- package/dist/es2019/pm-plugins/plugin-key.js +2 -0
- package/dist/es2019/pm-plugins/reducers.js +110 -0
- package/dist/es2019/pm-plugins/shouldReplaceLink.js +25 -0
- package/dist/es2019/pm-plugins/util/resolve.js +50 -0
- package/dist/es2019/pm-plugins/util/state.js +26 -0
- package/dist/es2019/toolbar.js +359 -0
- package/dist/es2019/types.js +1 -0
- package/dist/es2019/ui/DatasourceModal/ModalWithState.js +19 -0
- package/dist/es2019/ui/DatasourceModal/index.js +48 -0
- package/dist/es2019/ui/EditLinkToolbar.js +226 -0
- package/dist/es2019/ui/EditorSmartCardEvents.js +15 -0
- package/dist/es2019/ui/EditorSmartCardEventsNext.js +199 -0
- package/dist/es2019/ui/HyperlinkToolbarAppearance.js +86 -0
- package/dist/es2019/ui/LayoutButton/index.js +114 -0
- package/dist/es2019/ui/LayoutButton/types.js +1 -0
- package/dist/es2019/ui/LayoutButton/utils.js +15 -0
- package/dist/es2019/ui/LinkToolbarAppearance.js +118 -0
- package/dist/es2019/ui/ResizableEmbedCard.js +335 -0
- package/dist/es2019/ui/SmallerEditIcon.js +14 -0
- package/dist/es2019/utils.js +46 -0
- package/dist/es2019/version.json +5 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/messages.js +13 -0
- package/dist/esm/nodeviews/blockCard.js +156 -0
- package/dist/esm/nodeviews/datasource.js +165 -0
- package/dist/esm/nodeviews/embedCard.js +389 -0
- package/dist/esm/nodeviews/genericCard.js +111 -0
- package/dist/esm/nodeviews/inlineCard.js +124 -0
- package/dist/esm/plugin.js +130 -0
- package/dist/esm/pm-plugins/actions.js +102 -0
- package/dist/esm/pm-plugins/analytics/create-analytics-queue.js +41 -0
- package/dist/esm/pm-plugins/analytics/events-from-tr.js +350 -0
- package/dist/esm/pm-plugins/analytics/index.js +2 -0
- package/dist/esm/pm-plugins/analytics/types.js +1 -0
- package/dist/esm/pm-plugins/analytics/utils.js +160 -0
- package/dist/esm/pm-plugins/doc.js +460 -0
- package/dist/esm/pm-plugins/keymap.js +58 -0
- package/dist/esm/pm-plugins/main.js +199 -0
- package/dist/esm/pm-plugins/mountHyperlink.js +39 -0
- package/dist/esm/pm-plugins/plugin-key.js +2 -0
- package/dist/esm/pm-plugins/reducers.js +103 -0
- package/dist/esm/pm-plugins/shouldReplaceLink.js +29 -0
- package/dist/esm/pm-plugins/util/resolve.js +52 -0
- package/dist/esm/pm-plugins/util/state.js +40 -0
- package/dist/esm/toolbar.js +350 -0
- package/dist/esm/types.js +1 -0
- package/dist/esm/ui/DatasourceModal/ModalWithState.js +17 -0
- package/dist/esm/ui/DatasourceModal/index.js +49 -0
- package/dist/esm/ui/EditLinkToolbar.js +244 -0
- package/dist/esm/ui/EditorSmartCardEvents.js +14 -0
- package/dist/esm/ui/EditorSmartCardEventsNext.js +203 -0
- package/dist/esm/ui/HyperlinkToolbarAppearance.js +163 -0
- package/dist/esm/ui/LayoutButton/index.js +110 -0
- package/dist/esm/ui/LayoutButton/types.js +1 -0
- package/dist/esm/ui/LayoutButton/utils.js +12 -0
- package/dist/esm/ui/LinkToolbarAppearance.js +141 -0
- package/dist/esm/ui/ResizableEmbedCard.js +358 -0
- package/dist/esm/ui/SmallerEditIcon.js +14 -0
- package/dist/esm/utils.js +48 -0
- package/dist/esm/version.json +5 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/messages.d.ts +12 -0
- package/dist/types/nodeviews/blockCard.d.ts +26 -0
- package/dist/types/nodeviews/datasource.d.ts +42 -0
- package/dist/types/nodeviews/embedCard.d.ts +46 -0
- package/dist/types/nodeviews/genericCard.d.ts +37 -0
- package/dist/types/nodeviews/inlineCard.d.ts +23 -0
- package/dist/types/plugin.d.ts +24 -0
- package/dist/types/pm-plugins/actions.d.ts +23 -0
- package/dist/types/pm-plugins/analytics/create-analytics-queue.d.ts +10 -0
- package/dist/types/pm-plugins/analytics/events-from-tr.d.ts +17 -0
- package/dist/types/pm-plugins/analytics/index.d.ts +2 -0
- package/dist/types/pm-plugins/analytics/types.d.ts +12 -0
- package/dist/types/pm-plugins/analytics/utils.d.ts +32 -0
- package/dist/types/pm-plugins/doc.d.ts +22 -0
- package/dist/types/pm-plugins/keymap.d.ts +3 -0
- package/dist/types/pm-plugins/main.d.ts +6 -0
- package/dist/types/pm-plugins/mountHyperlink.d.ts +5 -0
- package/dist/types/pm-plugins/plugin-key.d.ts +3 -0
- package/dist/types/pm-plugins/reducers.d.ts +3 -0
- package/dist/types/pm-plugins/shouldReplaceLink.d.ts +2 -0
- package/dist/types/pm-plugins/util/resolve.d.ts +8 -0
- package/dist/types/pm-plugins/util/state.d.ts +31 -0
- package/dist/types/toolbar.d.ts +9 -0
- package/dist/types/types.d.ts +163 -0
- package/dist/types/ui/DatasourceModal/ModalWithState.d.ts +9 -0
- package/dist/types/ui/DatasourceModal/index.d.ts +11 -0
- package/dist/types/ui/EditLinkToolbar.d.ts +47 -0
- package/dist/types/ui/EditorSmartCardEvents.d.ts +5 -0
- package/dist/types/ui/EditorSmartCardEventsNext.d.ts +18 -0
- package/dist/types/ui/HyperlinkToolbarAppearance.d.ts +32 -0
- package/dist/types/ui/LayoutButton/index.d.ts +9 -0
- package/dist/types/ui/LayoutButton/types.d.ts +19 -0
- package/dist/types/ui/LayoutButton/utils.d.ts +5 -0
- package/dist/types/ui/LinkToolbarAppearance.d.ts +29 -0
- package/dist/types/ui/ResizableEmbedCard.d.ts +61 -0
- package/dist/types/ui/SmallerEditIcon.d.ts +3 -0
- package/dist/types/utils.d.ts +19 -0
- package/dist/types-ts4.5/index.d.ts +2 -0
- package/dist/types-ts4.5/messages.d.ts +12 -0
- package/dist/types-ts4.5/nodeviews/blockCard.d.ts +26 -0
- package/dist/types-ts4.5/nodeviews/datasource.d.ts +42 -0
- package/dist/types-ts4.5/nodeviews/embedCard.d.ts +46 -0
- package/dist/types-ts4.5/nodeviews/genericCard.d.ts +37 -0
- package/dist/types-ts4.5/nodeviews/inlineCard.d.ts +23 -0
- package/dist/types-ts4.5/plugin.d.ts +24 -0
- package/dist/types-ts4.5/pm-plugins/actions.d.ts +23 -0
- package/dist/types-ts4.5/pm-plugins/analytics/create-analytics-queue.d.ts +10 -0
- package/dist/types-ts4.5/pm-plugins/analytics/events-from-tr.d.ts +17 -0
- package/dist/types-ts4.5/pm-plugins/analytics/index.d.ts +2 -0
- package/dist/types-ts4.5/pm-plugins/analytics/types.d.ts +12 -0
- package/dist/types-ts4.5/pm-plugins/analytics/utils.d.ts +32 -0
- package/dist/types-ts4.5/pm-plugins/doc.d.ts +22 -0
- package/dist/types-ts4.5/pm-plugins/keymap.d.ts +3 -0
- package/dist/types-ts4.5/pm-plugins/main.d.ts +6 -0
- package/dist/types-ts4.5/pm-plugins/mountHyperlink.d.ts +5 -0
- package/dist/types-ts4.5/pm-plugins/plugin-key.d.ts +3 -0
- package/dist/types-ts4.5/pm-plugins/reducers.d.ts +3 -0
- package/dist/types-ts4.5/pm-plugins/shouldReplaceLink.d.ts +2 -0
- package/dist/types-ts4.5/pm-plugins/util/resolve.d.ts +8 -0
- package/dist/types-ts4.5/pm-plugins/util/state.d.ts +31 -0
- package/dist/types-ts4.5/toolbar.d.ts +9 -0
- package/dist/types-ts4.5/types.d.ts +163 -0
- package/dist/types-ts4.5/ui/DatasourceModal/ModalWithState.d.ts +9 -0
- package/dist/types-ts4.5/ui/DatasourceModal/index.d.ts +11 -0
- package/dist/types-ts4.5/ui/EditLinkToolbar.d.ts +47 -0
- package/dist/types-ts4.5/ui/EditorSmartCardEvents.d.ts +5 -0
- package/dist/types-ts4.5/ui/EditorSmartCardEventsNext.d.ts +18 -0
- package/dist/types-ts4.5/ui/HyperlinkToolbarAppearance.d.ts +32 -0
- package/dist/types-ts4.5/ui/LayoutButton/index.d.ts +9 -0
- package/dist/types-ts4.5/ui/LayoutButton/types.d.ts +19 -0
- package/dist/types-ts4.5/ui/LayoutButton/utils.d.ts +5 -0
- package/dist/types-ts4.5/ui/LinkToolbarAppearance.d.ts +29 -0
- package/dist/types-ts4.5/ui/ResizableEmbedCard.d.ts +61 -0
- package/dist/types-ts4.5/ui/SmallerEditIcon.d.ts +3 -0
- package/dist/types-ts4.5/utils.d.ts +19 -0
- package/package.json +126 -0
- package/report.api.md +146 -0
- package/tmp/api-report-tmp.d.ts +117 -0
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { isLinkMark } from '@atlaskit/editor-common/utils';
|
|
2
|
+
import { appearanceForNodeType } from '../../utils';
|
|
3
|
+
/**
|
|
4
|
+
* Whether a node is a "link" node, ie inline card, block card, embed card
|
|
5
|
+
* (but not a text node with a link mark)
|
|
6
|
+
*/
|
|
7
|
+
export function isLinkNode(node) {
|
|
8
|
+
return !!appearanceForNodeType(node.type);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Analytics appearance for link object
|
|
13
|
+
*/
|
|
14
|
+
export function appearanceForLink(link) {
|
|
15
|
+
if (link.type === 'node') {
|
|
16
|
+
const appearance = appearanceForNodeType(link.node.type);
|
|
17
|
+
if (appearance) {
|
|
18
|
+
return appearance;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return 'url';
|
|
22
|
+
}
|
|
23
|
+
const nodeHasLinkMark = (schema, node) => {
|
|
24
|
+
if (node.marks) {
|
|
25
|
+
for (let i = 0; i < node.marks.length; i++) {
|
|
26
|
+
const mark = node.marks[i];
|
|
27
|
+
if (isLinkMark(mark, schema)) {
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return false;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Determine if a node is considered to be a link
|
|
37
|
+
*/
|
|
38
|
+
export const isLink = (schema, node) => {
|
|
39
|
+
if (isLinkNode(node)) {
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
return nodeHasLinkMark(schema, node);
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Given a node, find all nodes and marks that are considered "links"
|
|
47
|
+
* @param state EditorState
|
|
48
|
+
* @param fragment Fragment to search
|
|
49
|
+
* @returns Array of nodes and marks found in the fragment that are "links"
|
|
50
|
+
*/
|
|
51
|
+
export function findLinksInNode(doc, schema, node, offset) {
|
|
52
|
+
const links = [];
|
|
53
|
+
node.descendants((node, pos) => {
|
|
54
|
+
const nodeContext = getLinkNodeContext(doc, pos);
|
|
55
|
+
|
|
56
|
+
// Nodes
|
|
57
|
+
if (isLinkNode(node)) {
|
|
58
|
+
links.push({
|
|
59
|
+
type: 'node',
|
|
60
|
+
pos: pos + offset,
|
|
61
|
+
node,
|
|
62
|
+
nodeContext
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Marks
|
|
67
|
+
if (node.marks) {
|
|
68
|
+
for (let i = 0; i < node.marks.length; i++) {
|
|
69
|
+
const mark = node.marks[i];
|
|
70
|
+
if (isLinkMark(mark, schema)) {
|
|
71
|
+
links.push({
|
|
72
|
+
type: 'mark',
|
|
73
|
+
pos: pos + offset,
|
|
74
|
+
mark,
|
|
75
|
+
nodeContext
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
return links;
|
|
82
|
+
}
|
|
83
|
+
export function getLinkUrl(link) {
|
|
84
|
+
var _link$mark$attrs;
|
|
85
|
+
if (link.type === 'node') {
|
|
86
|
+
var _link$node$attrs;
|
|
87
|
+
return (_link$node$attrs = link.node.attrs) === null || _link$node$attrs === void 0 ? void 0 : _link$node$attrs.url;
|
|
88
|
+
}
|
|
89
|
+
return (_link$mark$attrs = link.mark.attrs) === null || _link$mark$attrs === void 0 ? void 0 : _link$mark$attrs.href;
|
|
90
|
+
}
|
|
91
|
+
export const getLinkNodeContext = (doc, pos) => {
|
|
92
|
+
const $pos = doc.resolve(pos);
|
|
93
|
+
const maxDepth = 3;
|
|
94
|
+
for (let i = 0; i <= maxDepth; i++) {
|
|
95
|
+
const node = $pos.node($pos.depth - i);
|
|
96
|
+
if (node && node.type.name !== 'paragraph') {
|
|
97
|
+
return node.type.name;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return 'unknown';
|
|
101
|
+
};
|
|
102
|
+
export const linkObjectFromNode = (doc, schema, node, pos) => {
|
|
103
|
+
const nodeContext = getLinkNodeContext(doc, pos);
|
|
104
|
+
if (isLinkNode(node)) {
|
|
105
|
+
return {
|
|
106
|
+
type: 'node',
|
|
107
|
+
pos,
|
|
108
|
+
node,
|
|
109
|
+
nodeContext
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
if (node.marks) {
|
|
113
|
+
for (let i = 0; i < node.marks.length; i++) {
|
|
114
|
+
const mark = node.marks[i];
|
|
115
|
+
if (isLinkMark(mark, schema)) {
|
|
116
|
+
return {
|
|
117
|
+
type: 'mark',
|
|
118
|
+
pos,
|
|
119
|
+
mark,
|
|
120
|
+
nodeContext
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
export const findLinksAtPositions = (tr, positions) => {
|
|
127
|
+
const schema = tr.doc.type.schema;
|
|
128
|
+
const links = [];
|
|
129
|
+
for (let i = 0; i < positions.length; i++) {
|
|
130
|
+
const pos = positions[i];
|
|
131
|
+
const node = tr.doc.nodeAt(pos);
|
|
132
|
+
if (!node) {
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
const link = linkObjectFromNode(tr.doc, schema, node, pos);
|
|
136
|
+
if (!link) {
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
links.push(link);
|
|
140
|
+
}
|
|
141
|
+
return links;
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Returns whether or not two sets of links appear to likely be the same set of links
|
|
146
|
+
* That they are in the same order and that both their hrefs and appearances match
|
|
147
|
+
*/
|
|
148
|
+
export const areSameLinks = (linksA, linksB) => {
|
|
149
|
+
if (linksA.length !== linksB.length) {
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
for (let i = 0; i < linksA.length; i++) {
|
|
153
|
+
const linkA = linksA[i];
|
|
154
|
+
const linkB = linksB[i];
|
|
155
|
+
if (getLinkUrl(linkA) !== getLinkUrl(linkB) || appearanceForLink(linkA) !== appearanceForLink(linkB)) {
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return true;
|
|
160
|
+
};
|
|
@@ -0,0 +1,451 @@
|
|
|
1
|
+
import isEqual from 'lodash/isEqual';
|
|
2
|
+
import { closeHistory } from 'prosemirror-history';
|
|
3
|
+
import { NodeSelection, TextSelection } from 'prosemirror-state';
|
|
4
|
+
import { isSafeUrl } from '@atlaskit/adf-schema';
|
|
5
|
+
import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE, INPUT_METHOD, SMART_LINK_TYPE, unlinkPayload } from '@atlaskit/editor-common/analytics';
|
|
6
|
+
import { addLinkMetadata } from '@atlaskit/editor-common/card';
|
|
7
|
+
import { getLinkCreationAnalyticsEvent, isFromCurrentDomain, nodesBetweenChanged, processRawValue } from '@atlaskit/editor-common/utils';
|
|
8
|
+
import { appearanceForNodeType, selectedCardAppearance } from '../utils';
|
|
9
|
+
import { hideDatasourceModal, queueCards, resolveCard } from './actions';
|
|
10
|
+
import { pluginKey } from './plugin-key';
|
|
11
|
+
import { shouldReplaceLink } from './shouldReplaceLink';
|
|
12
|
+
/**
|
|
13
|
+
* Attempt to replace the link into the respective card.
|
|
14
|
+
*/
|
|
15
|
+
function replaceLinksToCards(tr, cardAdf, schema, request) {
|
|
16
|
+
const {
|
|
17
|
+
inlineCard
|
|
18
|
+
} = schema.nodes;
|
|
19
|
+
const {
|
|
20
|
+
url
|
|
21
|
+
} = request;
|
|
22
|
+
if (!isSafeUrl(url)) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// replace all the outstanding links with their cards
|
|
27
|
+
const pos = tr.mapping.map(request.pos);
|
|
28
|
+
const $pos = tr.doc.resolve(pos);
|
|
29
|
+
const node = tr.doc.nodeAt(pos);
|
|
30
|
+
if (!node || !node.type.isText) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const replaceLink = request.shouldReplaceLink || shouldReplaceLink(node, request.compareLinkText, url);
|
|
34
|
+
if (!replaceLink) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// ED-5638: add an extra space after inline cards to avoid re-rendering them
|
|
39
|
+
const nodes = [cardAdf];
|
|
40
|
+
if (cardAdf.type === inlineCard) {
|
|
41
|
+
nodes.push(schema.text(' '));
|
|
42
|
+
}
|
|
43
|
+
tr.replaceWith(pos, pos + (node.text || url).length, nodes);
|
|
44
|
+
return $pos.node($pos.depth - 1).type.name;
|
|
45
|
+
}
|
|
46
|
+
export const replaceQueuedUrlWithCard = (url, cardData, analyticsAction, editorAnalyticsApi, createAnalyticsEvent) => (editorState, dispatch) => {
|
|
47
|
+
const state = pluginKey.getState(editorState);
|
|
48
|
+
if (!state) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// find the requests for this URL
|
|
53
|
+
const requests = state.requests.filter(req => req.url === url);
|
|
54
|
+
|
|
55
|
+
// try to transform response to ADF
|
|
56
|
+
const schema = editorState.schema;
|
|
57
|
+
const cardAdf = processRawValue(schema, cardData);
|
|
58
|
+
let tr = editorState.tr;
|
|
59
|
+
if (cardAdf) {
|
|
60
|
+
// Should prevent any other node than cards? [inlineCard, blockCard].includes(cardAdf.type)
|
|
61
|
+
const nodeContexts = requests.map(request => replaceLinksToCards(tr, cardAdf, schema, request)).filter(context => !!context); // context exist
|
|
62
|
+
|
|
63
|
+
// Send analytics information
|
|
64
|
+
if (nodeContexts.length) {
|
|
65
|
+
const nodeContext = nodeContexts.every(context => context === nodeContexts[0]) ? nodeContexts[0] : 'mixed';
|
|
66
|
+
|
|
67
|
+
/** For block links v1, default to inline links */
|
|
68
|
+
const nodeType = 'inlineCard';
|
|
69
|
+
const [,, domainName] = url.split('/');
|
|
70
|
+
if (state.smartLinkEvents) {
|
|
71
|
+
state.smartLinkEvents.insertSmartLink(domainName, 'inline', createAnalyticsEvent);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* TODO:
|
|
76
|
+
* What if each request has a different source?
|
|
77
|
+
* Unlikely, but need to define behaviour.
|
|
78
|
+
* Ignore analytics event? take first? provide 'mixed' as well?
|
|
79
|
+
*/
|
|
80
|
+
const inputMethod = requests[0].source;
|
|
81
|
+
const sourceEvent = requests[0].sourceEvent;
|
|
82
|
+
editorAnalyticsApi === null || editorAnalyticsApi === void 0 ? void 0 : editorAnalyticsApi.attachAnalyticsEvent({
|
|
83
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
84
|
+
action: analyticsAction || ACTION.INSERTED,
|
|
85
|
+
actionSubject: ACTION_SUBJECT.DOCUMENT,
|
|
86
|
+
actionSubjectId: ACTION_SUBJECT_ID.SMART_LINK,
|
|
87
|
+
eventType: EVENT_TYPE.TRACK,
|
|
88
|
+
attributes: {
|
|
89
|
+
inputMethod,
|
|
90
|
+
nodeType,
|
|
91
|
+
nodeContext: nodeContext,
|
|
92
|
+
fromCurrentDomain: isFromCurrentDomain(url)
|
|
93
|
+
},
|
|
94
|
+
nonPrivacySafeAttributes: {
|
|
95
|
+
domainName
|
|
96
|
+
}
|
|
97
|
+
})(tr);
|
|
98
|
+
addLinkMetadata(editorState.selection, tr, {
|
|
99
|
+
action: analyticsAction,
|
|
100
|
+
inputMethod,
|
|
101
|
+
cardAction: 'RESOLVE',
|
|
102
|
+
sourceEvent
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if (dispatch) {
|
|
107
|
+
dispatch(resolveCard(url)(closeHistory(tr)));
|
|
108
|
+
}
|
|
109
|
+
return true;
|
|
110
|
+
};
|
|
111
|
+
export const handleFallbackWithAnalytics = (request, editorAnalyticsApi) => (state, dispatch) => {
|
|
112
|
+
const cardState = pluginKey.getState(state);
|
|
113
|
+
if (!cardState) {
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
const tr = state.tr;
|
|
117
|
+
if (request.source !== INPUT_METHOD.FLOATING_TB) {
|
|
118
|
+
editorAnalyticsApi === null || editorAnalyticsApi === void 0 ? void 0 : editorAnalyticsApi.attachAnalyticsEvent(getLinkCreationAnalyticsEvent(request.source, request.url))(tr);
|
|
119
|
+
}
|
|
120
|
+
addLinkMetadata(state.selection, tr, {
|
|
121
|
+
action: request.analyticsAction,
|
|
122
|
+
inputMethod: request.source
|
|
123
|
+
});
|
|
124
|
+
if (dispatch) {
|
|
125
|
+
dispatch(resolveCard(request.url)(tr));
|
|
126
|
+
}
|
|
127
|
+
return true;
|
|
128
|
+
};
|
|
129
|
+
export const queueCardsFromChangedTr = (state, tr, source, analyticsAction, normalizeLinkText = true, sourceEvent = undefined) => {
|
|
130
|
+
const {
|
|
131
|
+
schema
|
|
132
|
+
} = state;
|
|
133
|
+
const {
|
|
134
|
+
link
|
|
135
|
+
} = schema.marks;
|
|
136
|
+
const requests = [];
|
|
137
|
+
nodesBetweenChanged(tr, (node, pos) => {
|
|
138
|
+
if (!node.isText) {
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
141
|
+
const linkMark = node.marks.find(mark => mark.type === link);
|
|
142
|
+
if (linkMark) {
|
|
143
|
+
if (!shouldReplaceLink(node, normalizeLinkText)) {
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
requests.push({
|
|
147
|
+
url: linkMark.attrs.href,
|
|
148
|
+
pos,
|
|
149
|
+
appearance: 'inline',
|
|
150
|
+
compareLinkText: normalizeLinkText,
|
|
151
|
+
source,
|
|
152
|
+
analyticsAction,
|
|
153
|
+
sourceEvent
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
return false;
|
|
157
|
+
});
|
|
158
|
+
if (analyticsAction) {
|
|
159
|
+
addLinkMetadata(state.selection, tr, {
|
|
160
|
+
action: analyticsAction
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
return queueCards(requests)(tr);
|
|
164
|
+
};
|
|
165
|
+
export const queueCardFromChangedTr = (state, tr, source, analyticsAction, normalizeLinkText = true, sourceEvent = undefined, previousAppearance) => {
|
|
166
|
+
const {
|
|
167
|
+
schema
|
|
168
|
+
} = state;
|
|
169
|
+
const {
|
|
170
|
+
link
|
|
171
|
+
} = schema.marks;
|
|
172
|
+
let requests = [];
|
|
173
|
+
nodesBetweenChanged(tr, (node, pos) => {
|
|
174
|
+
if (!node.isText) {
|
|
175
|
+
return true;
|
|
176
|
+
}
|
|
177
|
+
const linkMark = node.marks.find(mark => mark.type === link);
|
|
178
|
+
if (linkMark) {
|
|
179
|
+
if (!shouldReplaceLink(node, normalizeLinkText)) {
|
|
180
|
+
return false;
|
|
181
|
+
}
|
|
182
|
+
requests.push({
|
|
183
|
+
url: linkMark.attrs.href,
|
|
184
|
+
pos,
|
|
185
|
+
appearance: 'inline',
|
|
186
|
+
previousAppearance: previousAppearance,
|
|
187
|
+
compareLinkText: normalizeLinkText,
|
|
188
|
+
source,
|
|
189
|
+
analyticsAction,
|
|
190
|
+
sourceEvent
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
return false;
|
|
194
|
+
});
|
|
195
|
+
addLinkMetadata(state.selection, tr, {
|
|
196
|
+
action: analyticsAction
|
|
197
|
+
});
|
|
198
|
+
return queueCards(requests)(tr);
|
|
199
|
+
};
|
|
200
|
+
export const convertHyperlinkToSmartCard = (state, source, appearance, normalizeLinkText = true) => {
|
|
201
|
+
const {
|
|
202
|
+
schema
|
|
203
|
+
} = state;
|
|
204
|
+
const {
|
|
205
|
+
link
|
|
206
|
+
} = schema.marks;
|
|
207
|
+
const requests = [];
|
|
208
|
+
state.tr.doc.nodesBetween(state.selection.from, state.selection.to, (node, pos) => {
|
|
209
|
+
const linkMark = node.marks.find(mark => mark.type === link);
|
|
210
|
+
if (linkMark) {
|
|
211
|
+
requests.push({
|
|
212
|
+
url: linkMark.attrs.href,
|
|
213
|
+
pos,
|
|
214
|
+
appearance,
|
|
215
|
+
previousAppearance: 'url',
|
|
216
|
+
compareLinkText: normalizeLinkText,
|
|
217
|
+
source,
|
|
218
|
+
analyticsAction: ACTION.CHANGED_TYPE,
|
|
219
|
+
shouldReplaceLink: true
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
addLinkMetadata(state.selection, state.tr, {
|
|
224
|
+
action: ACTION.CHANGED_TYPE
|
|
225
|
+
});
|
|
226
|
+
return queueCards(requests)(state.tr);
|
|
227
|
+
};
|
|
228
|
+
export const changeSelectedCardToLink = (text, href, sendAnalytics, node, pos, editorAnalyticsApi) => (state, dispatch) => {
|
|
229
|
+
let tr;
|
|
230
|
+
if (node && pos) {
|
|
231
|
+
tr = cardNodeToLinkWithTransaction(state, text, href, node, pos);
|
|
232
|
+
} else {
|
|
233
|
+
tr = cardToLinkWithTransaction(state, text, href);
|
|
234
|
+
}
|
|
235
|
+
const selectedNode = state.selection instanceof NodeSelection && state.selection.node;
|
|
236
|
+
if (sendAnalytics) {
|
|
237
|
+
if (selectedNode) {
|
|
238
|
+
editorAnalyticsApi === null || editorAnalyticsApi === void 0 ? void 0 : editorAnalyticsApi.attachAnalyticsEvent({
|
|
239
|
+
action: ACTION.CHANGED_TYPE,
|
|
240
|
+
actionSubject: ACTION_SUBJECT.SMART_LINK,
|
|
241
|
+
eventType: EVENT_TYPE.TRACK,
|
|
242
|
+
attributes: {
|
|
243
|
+
newType: SMART_LINK_TYPE.URL,
|
|
244
|
+
previousType: appearanceForNodeType(selectedNode.type)
|
|
245
|
+
}
|
|
246
|
+
})(tr);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
if (dispatch) {
|
|
250
|
+
dispatch(tr.scrollIntoView());
|
|
251
|
+
}
|
|
252
|
+
return true;
|
|
253
|
+
};
|
|
254
|
+
export const changeSelectedCardToLinkFallback = (text, href, sendAnalytics, node, pos, editorAnalyticsApi) => (state, dispatch) => {
|
|
255
|
+
let tr;
|
|
256
|
+
if (node && pos) {
|
|
257
|
+
tr = cardNodeToLinkWithTransaction(state, text, href, node, pos);
|
|
258
|
+
} else {
|
|
259
|
+
tr = cardToLinkWithTransaction(state, text, href);
|
|
260
|
+
}
|
|
261
|
+
if (sendAnalytics) {
|
|
262
|
+
editorAnalyticsApi === null || editorAnalyticsApi === void 0 ? void 0 : editorAnalyticsApi.attachAnalyticsEvent({
|
|
263
|
+
action: ACTION.ERRORED,
|
|
264
|
+
actionSubject: ACTION_SUBJECT.SMART_LINK,
|
|
265
|
+
eventType: EVENT_TYPE.OPERATIONAL,
|
|
266
|
+
attributes: {
|
|
267
|
+
error: 'Smart card falling back to link.'
|
|
268
|
+
}
|
|
269
|
+
})(tr);
|
|
270
|
+
}
|
|
271
|
+
if (dispatch) {
|
|
272
|
+
dispatch(tr.scrollIntoView());
|
|
273
|
+
}
|
|
274
|
+
return true;
|
|
275
|
+
};
|
|
276
|
+
export const updateCard = (href, sourceEvent) => (state, dispatch) => {
|
|
277
|
+
const selectedNode = state.selection instanceof NodeSelection && state.selection.node;
|
|
278
|
+
if (!selectedNode) {
|
|
279
|
+
return false;
|
|
280
|
+
}
|
|
281
|
+
const cardAppearance = selectedCardAppearance(state);
|
|
282
|
+
const tr = cardToLinkWithTransaction(state, href, href);
|
|
283
|
+
queueCardFromChangedTr(state, tr, INPUT_METHOD.MANUAL, ACTION.UPDATED, undefined, sourceEvent, cardAppearance);
|
|
284
|
+
if (dispatch) {
|
|
285
|
+
dispatch(tr.scrollIntoView());
|
|
286
|
+
}
|
|
287
|
+
return true;
|
|
288
|
+
};
|
|
289
|
+
function cardToLinkWithTransaction(state, text, href) {
|
|
290
|
+
const selectedNode = state.selection instanceof NodeSelection && state.selection.node;
|
|
291
|
+
if (!selectedNode) {
|
|
292
|
+
return state.tr;
|
|
293
|
+
}
|
|
294
|
+
const {
|
|
295
|
+
link
|
|
296
|
+
} = state.schema.marks;
|
|
297
|
+
const url = selectedNode.attrs.url || selectedNode.attrs.data.url;
|
|
298
|
+
const tr = state.tr.replaceSelectionWith(state.schema.text(text || url, [link.create({
|
|
299
|
+
href: href || url
|
|
300
|
+
})]), false);
|
|
301
|
+
return tr;
|
|
302
|
+
}
|
|
303
|
+
function cardNodeToLinkWithTransaction(state, text, href, node, pos) {
|
|
304
|
+
const {
|
|
305
|
+
link
|
|
306
|
+
} = state.schema.marks;
|
|
307
|
+
const url = node.attrs.url || node.attrs.data.url;
|
|
308
|
+
return state.tr.replaceWith(pos, pos + node.nodeSize, state.schema.text(text || url, [link.create({
|
|
309
|
+
href: href || url
|
|
310
|
+
})]));
|
|
311
|
+
}
|
|
312
|
+
export const changeSelectedCardToText = (text, editorAnalyticsApi) => (state, dispatch) => {
|
|
313
|
+
const selectedNode = state.selection instanceof NodeSelection && state.selection.node;
|
|
314
|
+
if (!selectedNode) {
|
|
315
|
+
return false;
|
|
316
|
+
}
|
|
317
|
+
const tr = state.tr.replaceSelectionWith(state.schema.text(text), false);
|
|
318
|
+
if (dispatch) {
|
|
319
|
+
addLinkMetadata(state.selection, tr, {
|
|
320
|
+
action: ACTION.UNLINK
|
|
321
|
+
});
|
|
322
|
+
tr.scrollIntoView();
|
|
323
|
+
editorAnalyticsApi === null || editorAnalyticsApi === void 0 ? void 0 : editorAnalyticsApi.attachAnalyticsEvent(unlinkPayload(ACTION_SUBJECT_ID.CARD_INLINE))(tr);
|
|
324
|
+
dispatch(tr);
|
|
325
|
+
}
|
|
326
|
+
return true;
|
|
327
|
+
};
|
|
328
|
+
export const setSelectedCardAppearance = (appearance, editorAnalyticsApi) => (state, dispatch) => {
|
|
329
|
+
var _previousNode$type;
|
|
330
|
+
const selectedNode = state.selection instanceof NodeSelection && state.selection.node;
|
|
331
|
+
if (!selectedNode) {
|
|
332
|
+
// When there is no selected node, we insert a new one
|
|
333
|
+
// and replace the existing blue link
|
|
334
|
+
const tr = convertHyperlinkToSmartCard(state, INPUT_METHOD.FLOATING_TB, appearance);
|
|
335
|
+
if (dispatch) {
|
|
336
|
+
addLinkMetadata(state.selection, tr, {
|
|
337
|
+
action: ACTION.CHANGED_TYPE
|
|
338
|
+
});
|
|
339
|
+
dispatch(tr.scrollIntoView());
|
|
340
|
+
}
|
|
341
|
+
return false;
|
|
342
|
+
}
|
|
343
|
+
if (appearanceForNodeType(selectedNode.type) === appearance) {
|
|
344
|
+
return false;
|
|
345
|
+
}
|
|
346
|
+
const isEmbed = appearance === 'embed';
|
|
347
|
+
const attrs = isEmbed ? {
|
|
348
|
+
...selectedNode.attrs,
|
|
349
|
+
layout: 'center'
|
|
350
|
+
} : selectedNode.attrs;
|
|
351
|
+
const {
|
|
352
|
+
from,
|
|
353
|
+
to
|
|
354
|
+
} = state.selection;
|
|
355
|
+
const nodeType = getLinkNodeType(appearance, state.schema.nodes);
|
|
356
|
+
const tr = state.tr.setNodeMarkup(from, nodeType, attrs, selectedNode.marks);
|
|
357
|
+
|
|
358
|
+
// When the selected card is the last element in the doc we add a new paragraph after it for consistent replacement
|
|
359
|
+
if (tr.doc.nodeSize - 2 === to) {
|
|
360
|
+
tr.insertText(' ', to);
|
|
361
|
+
}
|
|
362
|
+
tr.setSelection(TextSelection.create(tr.doc, to + 1));
|
|
363
|
+
const previousNodePos = from - 1 > 0 ? from - 1 : 0;
|
|
364
|
+
const previousNode = tr.doc.nodeAt(previousNodePos);
|
|
365
|
+
if ((previousNode === null || previousNode === void 0 ? void 0 : (_previousNode$type = previousNode.type) === null || _previousNode$type === void 0 ? void 0 : _previousNode$type.name) === 'paragraph') {
|
|
366
|
+
tr.delete(previousNodePos, from);
|
|
367
|
+
}
|
|
368
|
+
editorAnalyticsApi === null || editorAnalyticsApi === void 0 ? void 0 : editorAnalyticsApi.attachAnalyticsEvent({
|
|
369
|
+
action: ACTION.CHANGED_TYPE,
|
|
370
|
+
actionSubject: ACTION_SUBJECT.SMART_LINK,
|
|
371
|
+
eventType: EVENT_TYPE.TRACK,
|
|
372
|
+
attributes: {
|
|
373
|
+
newType: appearance,
|
|
374
|
+
previousType: appearanceForNodeType(selectedNode.type)
|
|
375
|
+
}
|
|
376
|
+
})(tr);
|
|
377
|
+
addLinkMetadata(state.selection, tr, {
|
|
378
|
+
action: ACTION.CHANGED_TYPE
|
|
379
|
+
});
|
|
380
|
+
if (dispatch) {
|
|
381
|
+
dispatch(tr.scrollIntoView());
|
|
382
|
+
}
|
|
383
|
+
return true;
|
|
384
|
+
};
|
|
385
|
+
const getLinkNodeType = (appearance, linkNodes) => {
|
|
386
|
+
switch (appearance) {
|
|
387
|
+
case 'inline':
|
|
388
|
+
return linkNodes.inlineCard;
|
|
389
|
+
case 'block':
|
|
390
|
+
return linkNodes.blockCard;
|
|
391
|
+
case 'embed':
|
|
392
|
+
return linkNodes.embedCard;
|
|
393
|
+
}
|
|
394
|
+
};
|
|
395
|
+
|
|
396
|
+
// Apply an update to a datasource (aka blockCard) node
|
|
397
|
+
export const updateExistingDatasource = (state, node, newAdf, view) => {
|
|
398
|
+
const {
|
|
399
|
+
tr,
|
|
400
|
+
selection: {
|
|
401
|
+
from
|
|
402
|
+
},
|
|
403
|
+
schema: {
|
|
404
|
+
nodes: schemaNodes
|
|
405
|
+
}
|
|
406
|
+
} = state;
|
|
407
|
+
|
|
408
|
+
// datasource to datasource
|
|
409
|
+
if (newAdf.type === 'blockCard' && newAdf.attrs.datasource && node.attrs.datasource) {
|
|
410
|
+
var _ref, _ref2, _newViews$properties, _oldViews$properties, _newAdf$attrs, _node$attrs;
|
|
411
|
+
const [newViews] = (_ref = newAdf.attrs.datasource.views) !== null && _ref !== void 0 ? _ref : [];
|
|
412
|
+
const [oldViews] = (_ref2 = node.attrs.datasource.views) !== null && _ref2 !== void 0 ? _ref2 : [];
|
|
413
|
+
const newColumnKeys = newViews === null || newViews === void 0 ? void 0 : (_newViews$properties = newViews.properties) === null || _newViews$properties === void 0 ? void 0 : _newViews$properties.columns.map(column => column.key);
|
|
414
|
+
const oldColumnKeys = oldViews === null || oldViews === void 0 ? void 0 : (_oldViews$properties = oldViews.properties) === null || _oldViews$properties === void 0 ? void 0 : _oldViews$properties.columns.map(column => column.key);
|
|
415
|
+
const isColumnChange = !isEqual(oldColumnKeys, newColumnKeys);
|
|
416
|
+
const isUrlChange = ((_newAdf$attrs = newAdf.attrs) === null || _newAdf$attrs === void 0 ? void 0 : _newAdf$attrs.url) !== ((_node$attrs = node.attrs) === null || _node$attrs === void 0 ? void 0 : _node$attrs.url);
|
|
417
|
+
if (isColumnChange || isUrlChange) {
|
|
418
|
+
tr.setNodeMarkup(from, schemaNodes.blockCard, {
|
|
419
|
+
...node.attrs,
|
|
420
|
+
...newAdf.attrs
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
} else if (newAdf.type === 'inlineCard') {
|
|
424
|
+
// datasource to inline
|
|
425
|
+
tr.setNodeMarkup(from, schemaNodes.inlineCard, newAdf.attrs);
|
|
426
|
+
}
|
|
427
|
+
hideDatasourceModal(tr);
|
|
428
|
+
view.dispatch(tr.scrollIntoView());
|
|
429
|
+
};
|
|
430
|
+
export const insertDatasource = (state, adf, view) => {
|
|
431
|
+
const {
|
|
432
|
+
tr,
|
|
433
|
+
selection: {
|
|
434
|
+
from
|
|
435
|
+
},
|
|
436
|
+
schema: {
|
|
437
|
+
nodes: schemaNodes
|
|
438
|
+
}
|
|
439
|
+
} = state;
|
|
440
|
+
const {
|
|
441
|
+
attrs,
|
|
442
|
+
type
|
|
443
|
+
} = adf;
|
|
444
|
+
const schemaNode = type === 'inlineCard' ? schemaNodes.inlineCard : schemaNodes.blockCard;
|
|
445
|
+
const newNode = schemaNode.createChecked(attrs);
|
|
446
|
+
// in future, if we decide to do datasource insertion from the main toolbar, we should probably consider editor-plugin-content-insertion instead of tr.insert
|
|
447
|
+
// this will allow us to deal with insertions from multiple paths in a more consistent way
|
|
448
|
+
newNode && tr.insert(from, newNode);
|
|
449
|
+
hideDatasourceModal(tr);
|
|
450
|
+
view.dispatch(tr.scrollIntoView());
|
|
451
|
+
};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { keymap } from 'prosemirror-keymap';
|
|
2
|
+
import { NodeSelection } from 'prosemirror-state';
|
|
3
|
+
import { findChildren, flatten } from 'prosemirror-utils';
|
|
4
|
+
import { bindKeymapWithCommand, moveDown, moveUp } from '@atlaskit/editor-common/keymaps';
|
|
5
|
+
import { browser } from '@atlaskit/editor-common/utils';
|
|
6
|
+
const lookupPixel = 10;
|
|
7
|
+
const getClosestInlineCardPos = (state, editorView, direction) => {
|
|
8
|
+
var _editorView$posAtCoor;
|
|
9
|
+
const {
|
|
10
|
+
selection
|
|
11
|
+
} = state;
|
|
12
|
+
const {
|
|
13
|
+
parent
|
|
14
|
+
} = selection.$from;
|
|
15
|
+
const inlineCardType = state.schema.nodes.inlineCard;
|
|
16
|
+
if (!flatten(parent, false).some(({
|
|
17
|
+
node
|
|
18
|
+
}) => node.type === inlineCardType)) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
const coord = editorView.coordsAtPos(selection.$anchor.pos);
|
|
22
|
+
const nearPos = (_editorView$posAtCoor = editorView.posAtCoords({
|
|
23
|
+
left: coord.left,
|
|
24
|
+
top: direction === 'up' ? coord.top - lookupPixel : coord.bottom + lookupPixel
|
|
25
|
+
})) === null || _editorView$posAtCoor === void 0 ? void 0 : _editorView$posAtCoor.pos;
|
|
26
|
+
if (nearPos) {
|
|
27
|
+
const newNode = state.doc.nodeAt(nearPos);
|
|
28
|
+
if (newNode) {
|
|
29
|
+
if (newNode.type !== inlineCardType || findChildren(parent, node => node === newNode, false).length === 0 || newNode === selection.node) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
return nearPos;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return null;
|
|
36
|
+
};
|
|
37
|
+
const selectAboveBelowInlineCard = direction => {
|
|
38
|
+
return (state, dispatch, editorView) => {
|
|
39
|
+
if (!editorView || !dispatch) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
const pos = getClosestInlineCardPos(state, editorView, direction);
|
|
43
|
+
if (pos) {
|
|
44
|
+
dispatch(state.tr.setSelection(new NodeSelection(state.doc.resolve(pos))));
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
return false;
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
export function cardKeymap(featureFlags) {
|
|
51
|
+
const list = {};
|
|
52
|
+
|
|
53
|
+
// https://bugs.chromium.org/p/chromium/issues/detail?id=1227468 introduced since Chrome 91
|
|
54
|
+
if (browser.chrome && browser.chrome_version > 90 && featureFlags.chromeCursorHandlerFixedVersion && browser.chrome_version < featureFlags.chromeCursorHandlerFixedVersion) {
|
|
55
|
+
bindKeymapWithCommand(moveUp.common, selectAboveBelowInlineCard('up'), list);
|
|
56
|
+
bindKeymapWithCommand(moveDown.common, selectAboveBelowInlineCard('down'), list);
|
|
57
|
+
}
|
|
58
|
+
return keymap(list);
|
|
59
|
+
}
|