@kerebron/extension-basic-editor 0.5.2 → 0.5.4
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/assets/image-resize.css +76 -0
- package/esm/BasicEditorKit.d.ts.map +1 -1
- package/esm/BasicEditorKit.js +7 -1
- package/esm/BasicEditorKit.js.map +1 -1
- package/esm/ExtensionBasicCodeEditor.d.ts.map +1 -1
- package/esm/ExtensionBasicCodeEditor.js +4 -2
- package/esm/ExtensionBasicCodeEditor.js.map +1 -1
- package/esm/ExtensionMediaUpload.d.ts +1 -1
- package/esm/ExtensionMediaUpload.d.ts.map +1 -1
- package/esm/ExtensionMediaUpload.js.map +1 -1
- package/esm/MarkLink.d.ts.map +1 -1
- package/esm/MarkLink.js +3 -1
- package/esm/MarkLink.js.map +1 -1
- package/esm/MarkUnderline.d.ts.map +1 -1
- package/esm/MarkUnderline.js +0 -5
- package/esm/MarkUnderline.js.map +1 -1
- package/esm/NodeBookmark.d.ts.map +1 -1
- package/esm/NodeBookmark.js +6 -2
- package/esm/NodeBookmark.js.map +1 -1
- package/esm/NodeBulletList.d.ts +8 -0
- package/esm/NodeBulletList.d.ts.map +1 -1
- package/esm/NodeBulletList.js +8 -0
- package/esm/NodeBulletList.js.map +1 -1
- package/esm/NodeCodeBlock.js +1 -1
- package/esm/NodeCodeBlock.js.map +1 -1
- package/esm/NodeCommentAnchor.d.ts +15 -0
- package/esm/NodeCommentAnchor.d.ts.map +1 -0
- package/esm/NodeCommentAnchor.js +133 -0
- package/esm/NodeCommentAnchor.js.map +1 -0
- package/esm/NodeHorizontalRule.d.ts.map +1 -1
- package/esm/NodeHorizontalRule.js +2 -1
- package/esm/NodeHorizontalRule.js.map +1 -1
- package/esm/NodeImage.d.ts +1 -1
- package/esm/NodeImage.d.ts.map +1 -1
- package/esm/NodeImage.js +4 -1
- package/esm/NodeImage.js.map +1 -1
- package/esm/NodeInlineShortCode.d.ts +1 -3
- package/esm/NodeInlineShortCode.d.ts.map +1 -1
- package/esm/NodeInlineShortCode.js +11 -3
- package/esm/NodeInlineShortCode.js.map +1 -1
- package/esm/NodeListItem.d.ts +12 -2
- package/esm/NodeListItem.d.ts.map +1 -1
- package/esm/NodeListItem.js +24 -4
- package/esm/NodeListItem.js.map +1 -1
- package/esm/NodeOrderedList.d.ts +11 -2
- package/esm/NodeOrderedList.d.ts.map +1 -1
- package/esm/NodeOrderedList.js +11 -2
- package/esm/NodeOrderedList.js.map +1 -1
- package/esm/NodeParagraph.d.ts +1 -0
- package/esm/NodeParagraph.d.ts.map +1 -1
- package/esm/NodeParagraph.js +4 -4
- package/esm/NodeParagraph.js.map +1 -1
- package/esm/NodeSoftBreak.d.ts +8 -0
- package/esm/NodeSoftBreak.d.ts.map +1 -0
- package/esm/NodeSoftBreak.js +17 -0
- package/esm/NodeSoftBreak.js.map +1 -0
- package/esm/pairing/ExtensionPairing.d.ts +7 -0
- package/esm/pairing/ExtensionPairing.d.ts.map +1 -0
- package/esm/pairing/ExtensionPairing.js +11 -0
- package/esm/pairing/ExtensionPairing.js.map +1 -0
- package/esm/pairing/PairNodesPlugin.d.ts +3 -0
- package/esm/pairing/PairNodesPlugin.d.ts.map +1 -0
- package/esm/pairing/PairNodesPlugin.js +45 -0
- package/esm/pairing/PairNodesPlugin.js.map +1 -0
- package/esm/pairing/pairNodes.d.ts +5 -0
- package/esm/pairing/pairNodes.d.ts.map +1 -0
- package/esm/pairing/pairNodes.js +81 -0
- package/esm/pairing/pairNodes.js.map +1 -0
- package/package.json +7 -3
- package/src/BasicEditorKit.ts +7 -1
- package/src/ExtensionBasicCodeEditor.ts +4 -2
- package/src/ExtensionMediaUpload.ts +1 -1
- package/src/MarkLink.ts +3 -1
- package/src/MarkUnderline.ts +0 -7
- package/src/NodeBookmark.ts +6 -2
- package/src/NodeBulletList.ts +9 -0
- package/src/NodeCodeBlock.ts +1 -1
- package/src/NodeCommentAnchor.ts +170 -0
- package/src/NodeHorizontalRule.ts +2 -1
- package/src/NodeImage.ts +6 -3
- package/src/NodeInlineShortCode.ts +17 -7
- package/src/NodeListItem.ts +35 -9
- package/src/NodeOrderedList.ts +11 -2
- package/src/NodeParagraph.ts +5 -5
- package/src/NodeSoftBreak.ts +19 -0
- package/src/pairing/ExtensionPairing.ts +14 -0
- package/src/pairing/PairNodesPlugin.ts +56 -0
- package/src/pairing/pairNodes.ts +108 -0
package/src/BasicEditorKit.ts
CHANGED
|
@@ -6,8 +6,9 @@ import { ExtensionDropcursor } from './ExtensionDropcursor.js';
|
|
|
6
6
|
import { ExtensionGapcursor } from './ExtensionGapcursor.js';
|
|
7
7
|
import { ExtensionHtml } from './ExtensionHtml.js';
|
|
8
8
|
import { ExtensionMediaUpload } from './ExtensionMediaUpload.js';
|
|
9
|
-
import { ExtensionRemoteSelection } from './remote-selection/ExtensionRemoteSelection.js';
|
|
10
9
|
import { ExtensionTextAlign } from './ExtensionTextAlign.js';
|
|
10
|
+
import { ExtensionRemoteSelection } from './remote-selection/ExtensionRemoteSelection.js';
|
|
11
|
+
import { ExtensionPairing } from './pairing/ExtensionPairing.js';
|
|
11
12
|
|
|
12
13
|
import { MarkLink } from './MarkLink.js';
|
|
13
14
|
import { MarkStrong } from './MarkStrong.js';
|
|
@@ -28,6 +29,7 @@ import { NodeCodeBlock } from './NodeCodeBlock.js';
|
|
|
28
29
|
import { NodeBookmark } from './NodeBookmark.js';
|
|
29
30
|
import { NodeParagraph } from './NodeParagraph.js';
|
|
30
31
|
import { NodeHardBreak } from './NodeHardBreak.js';
|
|
32
|
+
import { NodeSoftBreak } from './NodeSoftBreak.js';
|
|
31
33
|
import { NodeHorizontalRule } from './NodeHorizontalRule.js';
|
|
32
34
|
import { NodeOrderedList } from './NodeOrderedList.js';
|
|
33
35
|
import { NodeBulletList } from './NodeBulletList.js';
|
|
@@ -46,6 +48,7 @@ import { NodeTaskList } from './NodeTaskList.js';
|
|
|
46
48
|
import { NodeTaskItem } from './NodeTaskItem.js';
|
|
47
49
|
import { NodeInlineShortCode } from './NodeInlineShortCode.js';
|
|
48
50
|
import { NodeIframe } from './NodeIframe.js';
|
|
51
|
+
import { NodeCommentAnchor } from './NodeCommentAnchor.js';
|
|
49
52
|
|
|
50
53
|
export class BasicEditorKit implements EditorKit {
|
|
51
54
|
getExtensions(): AnyExtensionOrReq[] {
|
|
@@ -58,10 +61,12 @@ export class BasicEditorKit implements EditorKit {
|
|
|
58
61
|
new ExtensionRemoteSelection(),
|
|
59
62
|
new ExtensionSelection(),
|
|
60
63
|
new ExtensionTextAlign(),
|
|
64
|
+
new ExtensionPairing(),
|
|
61
65
|
new NodeDocument(),
|
|
62
66
|
new NodeText(),
|
|
63
67
|
new NodeParagraph(),
|
|
64
68
|
new NodeHardBreak(),
|
|
69
|
+
new NodeSoftBreak(),
|
|
65
70
|
new NodeCodeBlock(),
|
|
66
71
|
new NodeBookmark(),
|
|
67
72
|
new NodeHorizontalRule(),
|
|
@@ -84,6 +89,7 @@ export class BasicEditorKit implements EditorKit {
|
|
|
84
89
|
new NodeMath(),
|
|
85
90
|
new NodeInlineShortCode(),
|
|
86
91
|
new NodeIframe(),
|
|
92
|
+
new NodeCommentAnchor(),
|
|
87
93
|
new MarkLink(),
|
|
88
94
|
new MarkItalic(),
|
|
89
95
|
new MarkStrong(),
|
|
@@ -6,15 +6,16 @@ import {
|
|
|
6
6
|
RawTextMapEntry,
|
|
7
7
|
RawTextResult,
|
|
8
8
|
} from '@kerebron/editor';
|
|
9
|
-
import { NodeDocumentCode } from './NodeDocumentCode.js';
|
|
10
9
|
|
|
11
10
|
import { ExtensionSelection } from './ExtensionSelection.js';
|
|
12
11
|
import { ExtensionBaseKeymap } from './ExtensionBaseKeymap.js';
|
|
13
12
|
import { ExtensionDropcursor } from './ExtensionDropcursor.js';
|
|
14
13
|
import { ExtensionGapcursor } from './ExtensionGapcursor.js';
|
|
15
14
|
import { ExtensionHtml } from './ExtensionHtml.js';
|
|
16
|
-
import { NodeText } from './NodeText.js';
|
|
17
15
|
import { ExtensionRemoteSelection } from './remote-selection/ExtensionRemoteSelection.js';
|
|
16
|
+
import { NodeText } from './NodeText.js';
|
|
17
|
+
import { NodeDocumentCode } from './NodeDocumentCode.js';
|
|
18
|
+
import { NodeCodeBlock } from './NodeCodeBlock.js';
|
|
18
19
|
|
|
19
20
|
export class ExtensionBasicCodeEditor extends Extension {
|
|
20
21
|
name = 'basic-code-editor';
|
|
@@ -31,6 +32,7 @@ export class ExtensionBasicCodeEditor extends Extension {
|
|
|
31
32
|
new ExtensionRemoteSelection(),
|
|
32
33
|
new ExtensionSelection(),
|
|
33
34
|
new NodeDocumentCode({ lang }),
|
|
35
|
+
new NodeCodeBlock(),
|
|
34
36
|
new NodeText(),
|
|
35
37
|
];
|
|
36
38
|
}
|
|
@@ -248,7 +248,7 @@ function createMediaUploadPlugin(options: MediaUploadOptions = {}): Plugin {
|
|
|
248
248
|
export class ExtensionMediaUpload extends Extension {
|
|
249
249
|
name = 'mediaUpload';
|
|
250
250
|
|
|
251
|
-
constructor(
|
|
251
|
+
constructor(public override config: Partial<MediaUploadOptions> = {}) {
|
|
252
252
|
super(config);
|
|
253
253
|
}
|
|
254
254
|
|
package/src/MarkLink.ts
CHANGED
package/src/MarkUnderline.ts
CHANGED
|
@@ -15,13 +15,6 @@ export class MarkUnderline extends Mark {
|
|
|
15
15
|
{
|
|
16
16
|
tag: 'u',
|
|
17
17
|
},
|
|
18
|
-
{
|
|
19
|
-
style: 'text-decoration',
|
|
20
|
-
consuming: false,
|
|
21
|
-
getAttrs: (
|
|
22
|
-
style,
|
|
23
|
-
) => ((style as string).includes('underline') ? {} : false),
|
|
24
|
-
},
|
|
25
18
|
],
|
|
26
19
|
toDOM() {
|
|
27
20
|
return ['u', 0];
|
package/src/NodeBookmark.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { NodeSpec } from 'prosemirror-model';
|
|
2
2
|
|
|
3
|
-
import { Node } from '@kerebron/editor';
|
|
3
|
+
import { NESTING_SELF_CLOSING, Node } from '@kerebron/editor';
|
|
4
4
|
|
|
5
5
|
export class NodeBookmark extends Node {
|
|
6
|
-
override name = '
|
|
6
|
+
override name = 'node_bookmark';
|
|
7
7
|
requires = ['doc'];
|
|
8
8
|
|
|
9
9
|
override getNodeSpec(): NodeSpec {
|
|
@@ -11,8 +11,12 @@ export class NodeBookmark extends Node {
|
|
|
11
11
|
inline: true,
|
|
12
12
|
group: 'inline',
|
|
13
13
|
selectable: false,
|
|
14
|
+
atom: true,
|
|
14
15
|
attrs: {
|
|
15
16
|
id: {},
|
|
17
|
+
nesting: {
|
|
18
|
+
default: NESTING_SELF_CLOSING,
|
|
19
|
+
},
|
|
16
20
|
},
|
|
17
21
|
parseDOM: [],
|
|
18
22
|
toDOM(mark) {
|
package/src/NodeBulletList.ts
CHANGED
|
@@ -14,6 +14,15 @@ export class NodeBulletList extends Node {
|
|
|
14
14
|
override name = 'bullet_list';
|
|
15
15
|
requires = ['doc'];
|
|
16
16
|
|
|
17
|
+
override attributes = {
|
|
18
|
+
toc: {
|
|
19
|
+
default: undefined,
|
|
20
|
+
},
|
|
21
|
+
odtMarginLeft: {
|
|
22
|
+
default: undefined,
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
|
|
17
26
|
override getNodeSpec(): NodeSpec {
|
|
18
27
|
return {
|
|
19
28
|
content: 'list_item+',
|
package/src/NodeCodeBlock.ts
CHANGED
|
@@ -17,6 +17,7 @@ export class NodeCodeBlock extends Node {
|
|
|
17
17
|
group: 'block',
|
|
18
18
|
code: true,
|
|
19
19
|
defining: true,
|
|
20
|
+
attrs: { lang: { default: undefined } },
|
|
20
21
|
parseDOM: [
|
|
21
22
|
{
|
|
22
23
|
tag: 'pre',
|
|
@@ -42,7 +43,6 @@ export class NodeCodeBlock extends Node {
|
|
|
42
43
|
},
|
|
43
44
|
},
|
|
44
45
|
],
|
|
45
|
-
attrs: { lang: { default: null } },
|
|
46
46
|
toDOM(node) {
|
|
47
47
|
const { lang } = node.attrs;
|
|
48
48
|
return ['pre', { lang }, ['code', 0]];
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import type { NodeSpec, NodeType } from 'prosemirror-model';
|
|
2
|
+
import { Node as PmNode } from 'prosemirror-model';
|
|
3
|
+
import { Plugin } from 'prosemirror-state';
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
type CoreEditor,
|
|
7
|
+
NESTING_CLOSING,
|
|
8
|
+
NESTING_OPENING,
|
|
9
|
+
Node,
|
|
10
|
+
} from '@kerebron/editor';
|
|
11
|
+
import { type CommandFactories } from '@kerebron/editor/commands';
|
|
12
|
+
import { Decoration, DecorationSet } from 'prosemirror-view';
|
|
13
|
+
import { CommandFactory } from '@kerebron/editor/commands';
|
|
14
|
+
|
|
15
|
+
function collectCommentAnchors(doc: PmNode) {
|
|
16
|
+
const starts = new Map();
|
|
17
|
+
const ends = new Map();
|
|
18
|
+
|
|
19
|
+
doc.descendants((node, pos) => {
|
|
20
|
+
if (node.type.name === 'comment') {
|
|
21
|
+
if (node.attrs.nesting === NESTING_OPENING) {
|
|
22
|
+
starts.set(node.attrs.id, pos);
|
|
23
|
+
}
|
|
24
|
+
if (node.attrs.nesting === NESTING_CLOSING) {
|
|
25
|
+
ends.set(node.attrs.id, pos);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
return { starts, ends };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function buildCommentRanges(doc: PmNode) {
|
|
34
|
+
const { starts, ends } = collectCommentAnchors(doc);
|
|
35
|
+
const ranges = [];
|
|
36
|
+
|
|
37
|
+
for (const [id, from] of starts) {
|
|
38
|
+
const to = ends.get(id);
|
|
39
|
+
if (!to || to <= from) continue;
|
|
40
|
+
|
|
41
|
+
ranges.push({
|
|
42
|
+
id,
|
|
43
|
+
from: from + 1, // skip start atom
|
|
44
|
+
to, // end atom position
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return ranges;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function buildDecorations(doc: PmNode) {
|
|
52
|
+
const ranges = buildCommentRanges(doc);
|
|
53
|
+
|
|
54
|
+
return DecorationSet.create(
|
|
55
|
+
doc,
|
|
56
|
+
ranges.map(({ id, from, to }) =>
|
|
57
|
+
Decoration.inline(from, to, {
|
|
58
|
+
class: 'comment-highlight',
|
|
59
|
+
'data-comment-id': id,
|
|
60
|
+
})
|
|
61
|
+
),
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function commentsPlugin(): Plugin {
|
|
66
|
+
return new Plugin({
|
|
67
|
+
state: {
|
|
68
|
+
init(_, { doc }) {
|
|
69
|
+
return buildDecorations(doc);
|
|
70
|
+
},
|
|
71
|
+
apply(tr, oldDecos, oldState, newState) {
|
|
72
|
+
if (!tr.docChanged) return oldDecos;
|
|
73
|
+
return buildDecorations(newState.doc);
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
props: {
|
|
77
|
+
decorations(state) {
|
|
78
|
+
return this.getState(state);
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const addCommentBoundary: CommandFactory = (id) => {
|
|
85
|
+
return (state, dispatch) => {
|
|
86
|
+
const { schema, selection } = state;
|
|
87
|
+
const { from, to } = selection;
|
|
88
|
+
|
|
89
|
+
const commentType = schema.nodes.comment;
|
|
90
|
+
if (!commentType) return false;
|
|
91
|
+
|
|
92
|
+
const startNode = commentType.create({ id, nesting: NESTING_OPENING });
|
|
93
|
+
const endNode = commentType.create({ id, nesting: NESTING_CLOSING });
|
|
94
|
+
|
|
95
|
+
const tr = state.tr;
|
|
96
|
+
|
|
97
|
+
tr.insert(to, endNode);
|
|
98
|
+
tr.insert(from, startNode);
|
|
99
|
+
|
|
100
|
+
// Optional: restore selection
|
|
101
|
+
// tr = tr.setSelection(
|
|
102
|
+
// TextSelection.create(tr.doc, from, to + startNode.nodeSize)
|
|
103
|
+
// );
|
|
104
|
+
|
|
105
|
+
if (dispatch) dispatch(tr);
|
|
106
|
+
return true;
|
|
107
|
+
};
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
export class NodeCommentAnchor extends Node {
|
|
111
|
+
override name = 'comment';
|
|
112
|
+
requires = ['doc'];
|
|
113
|
+
|
|
114
|
+
options = {
|
|
115
|
+
keepMarks: true,
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
override getNodeSpec(): NodeSpec {
|
|
119
|
+
return {
|
|
120
|
+
inline: true,
|
|
121
|
+
group: 'inline',
|
|
122
|
+
selectable: false,
|
|
123
|
+
atom: true,
|
|
124
|
+
attrs: {
|
|
125
|
+
id: {},
|
|
126
|
+
active: {
|
|
127
|
+
default: false,
|
|
128
|
+
},
|
|
129
|
+
nesting: {
|
|
130
|
+
default: NESTING_OPENING,
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
parseDOM: [
|
|
134
|
+
{
|
|
135
|
+
tag: 'span[data-comment-id]',
|
|
136
|
+
getAttrs(dom: HTMLElement) {
|
|
137
|
+
return {
|
|
138
|
+
id: dom.getAttribute('data-comment-id'),
|
|
139
|
+
nesting: parseInt(dom.getAttribute('data-nesting') || '1'),
|
|
140
|
+
active: dom.hasAttribute('data-active'),
|
|
141
|
+
};
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
],
|
|
145
|
+
toDOM: (
|
|
146
|
+
node,
|
|
147
|
+
) => ['span', {
|
|
148
|
+
'data-comment-id': node.attrs.id,
|
|
149
|
+
'data-active': node.attrs.active ? 'true' : undefined,
|
|
150
|
+
'data-nesting': node.attrs.nesting,
|
|
151
|
+
}],
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
override getCommandFactories(
|
|
156
|
+
editor: CoreEditor,
|
|
157
|
+
type: NodeType,
|
|
158
|
+
): Partial<CommandFactories> {
|
|
159
|
+
return {
|
|
160
|
+
'addComment': (id, active) => addCommentBoundary(id, active),
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
override getProseMirrorPlugins(): Plugin[] {
|
|
165
|
+
return [
|
|
166
|
+
commentsPlugin(),
|
|
167
|
+
// dropCursor(this.options),
|
|
168
|
+
];
|
|
169
|
+
}
|
|
170
|
+
}
|
package/src/NodeImage.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
1
|
+
import type { Node as PmNode, NodeSpec } from 'prosemirror-model';
|
|
2
|
+
import { Selection } from 'prosemirror-state';
|
|
3
3
|
import type { EditorView, NodeViewConstructor } from 'prosemirror-view';
|
|
4
|
+
|
|
4
5
|
import { Node } from '@kerebron/editor';
|
|
5
6
|
import type { CoreEditor } from '@kerebron/editor';
|
|
6
7
|
|
|
@@ -17,6 +18,8 @@ export class NodeImage extends Node {
|
|
|
17
18
|
title: { default: null },
|
|
18
19
|
width: { default: null },
|
|
19
20
|
height: { default: null },
|
|
21
|
+
origUrl: { default: undefined },
|
|
22
|
+
mdTemplate: { default: undefined },
|
|
20
23
|
},
|
|
21
24
|
group: 'inline',
|
|
22
25
|
draggable: true,
|
|
@@ -194,7 +197,7 @@ export class NodeImage extends Node {
|
|
|
194
197
|
const pos = getPos();
|
|
195
198
|
if (typeof pos === 'number') {
|
|
196
199
|
const $pos = view.state.doc.resolve(pos);
|
|
197
|
-
const selection =
|
|
200
|
+
const selection = Selection.near($pos);
|
|
198
201
|
view.dispatch(view.state.tr.setSelection(selection));
|
|
199
202
|
}
|
|
200
203
|
});
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import { Node as PmNode, NodeSpec, NodeType, Schema } from 'prosemirror-model';
|
|
2
2
|
import { EditorState, Transaction } from 'prosemirror-state';
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
CommandFactories,
|
|
6
|
+
CoreEditor,
|
|
7
|
+
NESTING_SELF_CLOSING,
|
|
8
|
+
Node,
|
|
9
|
+
} from '@kerebron/editor';
|
|
10
|
+
import { Command } from '@kerebron/editor/commands';
|
|
5
11
|
import {
|
|
6
12
|
type InputRule,
|
|
7
13
|
replaceInlineNode,
|
|
8
14
|
} from '@kerebron/editor/plugins/input-rules';
|
|
9
|
-
import { CoreEditor } from '@kerebron/editor';
|
|
10
|
-
import { CommandFactories } from '@kerebron/editor';
|
|
11
|
-
import { Command } from '@kerebron/editor/commands';
|
|
12
15
|
|
|
13
16
|
export function fixCharacters(text: string) {
|
|
14
17
|
return text
|
|
@@ -37,8 +40,6 @@ function replaceAllNodesOfType(
|
|
|
37
40
|
}
|
|
38
41
|
});
|
|
39
42
|
|
|
40
|
-
console.log('replaceAllNodesOfType', replacements.length);
|
|
41
|
-
|
|
42
43
|
for (let i = replacements.length - 1; i >= 0; i--) {
|
|
43
44
|
const { node, pos } = replacements[i];
|
|
44
45
|
const newNode = factory(node, tr.doc.type.schema);
|
|
@@ -57,12 +58,21 @@ export class NodeInlineShortCode extends Node {
|
|
|
57
58
|
inline: true,
|
|
58
59
|
group: 'inline',
|
|
59
60
|
selectable: true,
|
|
61
|
+
atom: true,
|
|
60
62
|
attrs: {
|
|
63
|
+
id: {
|
|
64
|
+
default: undefined,
|
|
65
|
+
},
|
|
61
66
|
content: {
|
|
62
67
|
default: '',
|
|
63
68
|
},
|
|
69
|
+
nesting: {
|
|
70
|
+
default: NESTING_SELF_CLOSING,
|
|
71
|
+
},
|
|
72
|
+
error: {
|
|
73
|
+
default: '',
|
|
74
|
+
},
|
|
64
75
|
},
|
|
65
|
-
atom: true,
|
|
66
76
|
parseDOM: [{
|
|
67
77
|
tag: 'span.kb-shortcode-inline',
|
|
68
78
|
getAttrs: (dom) => ({ content: dom.textContent || null }),
|
package/src/NodeListItem.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
type Attrs,
|
|
3
3
|
Fragment,
|
|
4
|
+
Node as PMNode,
|
|
4
5
|
NodeRange,
|
|
5
6
|
NodeSpec,
|
|
6
7
|
type NodeType,
|
|
@@ -12,12 +13,6 @@ import type {
|
|
|
12
13
|
Transaction,
|
|
13
14
|
} from 'prosemirror-state';
|
|
14
15
|
import { Selection } from 'prosemirror-state';
|
|
15
|
-
import { type CoreEditor, Node } from '@kerebron/editor';
|
|
16
|
-
import {
|
|
17
|
-
type Command,
|
|
18
|
-
type CommandFactories,
|
|
19
|
-
type CommandShortcuts,
|
|
20
|
-
} from '@kerebron/editor/commands';
|
|
21
16
|
import {
|
|
22
17
|
canJoin,
|
|
23
18
|
canSplit,
|
|
@@ -25,6 +20,17 @@ import {
|
|
|
25
20
|
ReplaceAroundStep,
|
|
26
21
|
} from 'prosemirror-transform';
|
|
27
22
|
|
|
23
|
+
import { type CoreEditor, Node } from '@kerebron/editor';
|
|
24
|
+
import type {
|
|
25
|
+
Command,
|
|
26
|
+
CommandFactories,
|
|
27
|
+
CommandShortcuts,
|
|
28
|
+
} from '@kerebron/editor/commands';
|
|
29
|
+
import {
|
|
30
|
+
getHtmlAttributes,
|
|
31
|
+
setHtmlAttributes,
|
|
32
|
+
} from '@kerebron/editor/utilities';
|
|
33
|
+
|
|
28
34
|
/// Build a command that splits a non-empty textblock at the top level
|
|
29
35
|
/// of a list item by also splitting that list item.
|
|
30
36
|
export function splitListItem(itemType: NodeType, itemAttrs?: Attrs): Command {
|
|
@@ -288,13 +294,33 @@ export class NodeListItem extends Node {
|
|
|
288
294
|
override name = 'list_item';
|
|
289
295
|
requires = ['doc'];
|
|
290
296
|
|
|
297
|
+
override attributes = {
|
|
298
|
+
value: {
|
|
299
|
+
default: undefined,
|
|
300
|
+
},
|
|
301
|
+
type: {
|
|
302
|
+
default: undefined,
|
|
303
|
+
fromDom(element: HTMLElement) {
|
|
304
|
+
return element.hasAttribute('type')
|
|
305
|
+
? element.getAttribute('type')
|
|
306
|
+
: undefined;
|
|
307
|
+
},
|
|
308
|
+
toDom(node: PMNode) {
|
|
309
|
+
return node.attrs.type;
|
|
310
|
+
},
|
|
311
|
+
},
|
|
312
|
+
};
|
|
313
|
+
|
|
291
314
|
override getNodeSpec(): NodeSpec {
|
|
292
315
|
return {
|
|
293
316
|
content: 'paragraph block*',
|
|
294
|
-
parseDOM: [{
|
|
317
|
+
parseDOM: [{
|
|
318
|
+
tag: 'li',
|
|
319
|
+
getAttrs: (element) => setHtmlAttributes(this, element),
|
|
320
|
+
}],
|
|
295
321
|
defining: true,
|
|
296
|
-
toDOM() {
|
|
297
|
-
return ['li', 0];
|
|
322
|
+
toDOM: (node) => {
|
|
323
|
+
return ['li', getHtmlAttributes(this, node), 0];
|
|
298
324
|
},
|
|
299
325
|
};
|
|
300
326
|
}
|
package/src/NodeOrderedList.ts
CHANGED
|
@@ -29,13 +29,22 @@ export class NodeOrderedList extends Node {
|
|
|
29
29
|
},
|
|
30
30
|
},
|
|
31
31
|
start: {
|
|
32
|
-
default:
|
|
32
|
+
default: undefined,
|
|
33
33
|
fromDom(element: HTMLElement) {
|
|
34
34
|
return element.hasAttribute('start')
|
|
35
35
|
? +element.getAttribute('start')!
|
|
36
|
-
:
|
|
36
|
+
: undefined;
|
|
37
37
|
},
|
|
38
38
|
},
|
|
39
|
+
id: {
|
|
40
|
+
default: undefined,
|
|
41
|
+
},
|
|
42
|
+
continue: {
|
|
43
|
+
default: undefined,
|
|
44
|
+
},
|
|
45
|
+
odtMarginLeft: {
|
|
46
|
+
default: undefined,
|
|
47
|
+
},
|
|
39
48
|
};
|
|
40
49
|
|
|
41
50
|
override getNodeSpec(): NodeSpec {
|
package/src/NodeParagraph.ts
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
type CommandShortcuts,
|
|
6
6
|
} from '@kerebron/editor/commands';
|
|
7
7
|
|
|
8
|
-
type TextAlign = 'left' | 'center' | 'right' | 'justify';
|
|
8
|
+
export type TextAlign = 'left' | 'center' | 'right' | 'justify' | undefined;
|
|
9
9
|
|
|
10
10
|
export class NodeParagraph extends Node {
|
|
11
11
|
override name = 'paragraph';
|
|
@@ -16,7 +16,7 @@ export class NodeParagraph extends Node {
|
|
|
16
16
|
content: 'inline*',
|
|
17
17
|
group: 'block',
|
|
18
18
|
attrs: {
|
|
19
|
-
textAlign: { default:
|
|
19
|
+
textAlign: { default: undefined },
|
|
20
20
|
},
|
|
21
21
|
parseDOM: [
|
|
22
22
|
{
|
|
@@ -29,13 +29,13 @@ export class NodeParagraph extends Node {
|
|
|
29
29
|
) {
|
|
30
30
|
return { textAlign: style };
|
|
31
31
|
}
|
|
32
|
-
return
|
|
32
|
+
return false;
|
|
33
33
|
},
|
|
34
34
|
},
|
|
35
35
|
],
|
|
36
36
|
toDOM(node) {
|
|
37
|
-
const align = node.attrs.textAlign
|
|
38
|
-
if (
|
|
37
|
+
const align = node.attrs.textAlign || 'left';
|
|
38
|
+
if (['center', 'right', 'justify'].includes(align)) {
|
|
39
39
|
return ['p', { style: `text-align: ${align}` }, 0];
|
|
40
40
|
}
|
|
41
41
|
return ['p', 0];
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { NodeSpec } from 'prosemirror-model';
|
|
2
|
+
import { Node } from '@kerebron/editor';
|
|
3
|
+
|
|
4
|
+
export class NodeSoftBreak extends Node {
|
|
5
|
+
override name = 'softbreak';
|
|
6
|
+
requires = ['doc'];
|
|
7
|
+
|
|
8
|
+
override getNodeSpec(): NodeSpec {
|
|
9
|
+
return {
|
|
10
|
+
inline: true,
|
|
11
|
+
group: 'inline',
|
|
12
|
+
selectable: false,
|
|
13
|
+
parseDOM: [{ tag: 'wbr' }],
|
|
14
|
+
toDOM() {
|
|
15
|
+
return ['wbr'];
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Plugin } from 'prosemirror-state';
|
|
2
|
+
|
|
3
|
+
import { Extension } from '@kerebron/editor';
|
|
4
|
+
import { createPairingPlugin } from './PairNodesPlugin.js';
|
|
5
|
+
|
|
6
|
+
export class ExtensionPairing extends Extension {
|
|
7
|
+
name = 'pairing-nodes';
|
|
8
|
+
|
|
9
|
+
override getProseMirrorPlugins(): Plugin[] {
|
|
10
|
+
return [
|
|
11
|
+
createPairingPlugin(['shortcode_inline']),
|
|
12
|
+
];
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { Plugin, Transaction } from 'prosemirror-state';
|
|
2
|
+
import { ReplaceAroundStep, ReplaceStep } from 'prosemirror-transform';
|
|
3
|
+
import { buildPairingTransaction } from './pairNodes.js';
|
|
4
|
+
|
|
5
|
+
export const createPairingPlugin = (types: string[]) => {
|
|
6
|
+
return new Plugin({
|
|
7
|
+
appendTransaction(
|
|
8
|
+
transactions: readonly Transaction[],
|
|
9
|
+
oldState,
|
|
10
|
+
newState,
|
|
11
|
+
) {
|
|
12
|
+
const typesToRebuild: Set<string> = new Set();
|
|
13
|
+
|
|
14
|
+
for (const tr of transactions) {
|
|
15
|
+
if (!tr.docChanged) continue;
|
|
16
|
+
|
|
17
|
+
for (const step of tr.steps) {
|
|
18
|
+
if (
|
|
19
|
+
!(step instanceof ReplaceStep || step instanceof ReplaceAroundStep)
|
|
20
|
+
) {
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (step.slice) {
|
|
25
|
+
step.slice.content.descendants((node) => {
|
|
26
|
+
if (types.includes(node.type.name)) {
|
|
27
|
+
typesToRebuild.add(node.type.name);
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (step.from != null && step.to != null && step.from !== step.to) {
|
|
33
|
+
oldState.doc.nodesBetween(step.from, step.to, (node) => {
|
|
34
|
+
if (types.includes(node.type.name)) {
|
|
35
|
+
typesToRebuild.add(node.type.name);
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (typesToRebuild.size === types.length) break;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (typesToRebuild.size === types.length) break;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (typesToRebuild.size === 0) return null;
|
|
47
|
+
|
|
48
|
+
const tr = newState.tr;
|
|
49
|
+
for (const type of typesToRebuild) {
|
|
50
|
+
buildPairingTransaction(newState, type, tr);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return tr;
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
};
|