@kerebron/editor 0.4.31 → 0.5.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/README.md +3 -5
- package/esm/CoreEditor.d.ts +25 -7
- package/esm/CoreEditor.d.ts.map +1 -1
- package/esm/CoreEditor.js +93 -33
- package/esm/CoreEditor.js.map +1 -1
- package/esm/ExtensionManager.d.ts +6 -9
- package/esm/ExtensionManager.d.ts.map +1 -1
- package/esm/ExtensionManager.js +44 -50
- package/esm/ExtensionManager.js.map +1 -1
- package/esm/Node.d.ts +1 -1
- package/esm/Node.d.ts.map +1 -1
- package/esm/commands/CommandManager.d.ts +1 -2
- package/esm/commands/CommandManager.d.ts.map +1 -1
- package/esm/commands/CommandManager.js +2 -4
- package/esm/commands/CommandManager.js.map +1 -1
- package/esm/commands/baseCommandFactories.d.ts.map +1 -1
- package/esm/commands/baseCommandFactories.js +5 -3
- package/esm/commands/baseCommandFactories.js.map +1 -1
- package/esm/plugins/input-rules/InputRulesPlugin.d.ts +5 -4
- package/esm/plugins/input-rules/InputRulesPlugin.d.ts.map +1 -1
- package/esm/plugins/input-rules/InputRulesPlugin.js +88 -17
- package/esm/plugins/input-rules/InputRulesPlugin.js.map +1 -1
- package/esm/plugins/input-rules/rulebuilders.d.ts.map +1 -1
- package/esm/plugins/input-rules/rulebuilders.js +16 -9
- package/esm/plugins/input-rules/rulebuilders.js.map +1 -1
- package/esm/types.d.ts +4 -12
- package/esm/types.d.ts.map +1 -1
- package/esm/utilities/createNodeFromContent.js +1 -1
- package/esm/utilities/createNodeFromContent.js.map +1 -1
- package/package.json +1 -1
- package/src/CoreEditor.ts +144 -42
- package/src/ExtensionManager.ts +57 -60
- package/src/Node.ts +1 -1
- package/src/commands/CommandManager.ts +2 -5
- package/src/commands/baseCommandFactories.ts +6 -3
- package/src/plugins/input-rules/InputRulesPlugin.ts +126 -15
- package/src/plugins/input-rules/rulebuilders.ts +27 -10
- package/src/types.ts +4 -12
- package/src/utilities/createNodeFromContent.ts +2 -2
package/esm/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,IAAI,eAAe,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,IAAI,eAAe,EAAgB,MAAM,mBAAmB,CAAC;AAC/E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEtC,MAAM,WAAW,SAAS;IACxB,aAAa,IAAI,iBAAiB,EAAE,CAAC;CACtC;AAED,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,IAAI,GAAG,IAAI,CAAC;AACnD,MAAM,MAAM,iBAAiB,GAAG,YAAY,GAAG;IAC7C,QAAQ,EAAE,KAAK,CAAC,iBAAiB,GAAG,MAAM,CAAC,CAAC;CAC7C,CAAC;AAEF,MAAM,MAAM,OAAO,GAAG,WAAW,GAAG,WAAW,EAAE,GAAG,IAAI,CAAC;AAEzD,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC5B,OAAO,CAAC,EAAE,WAAW,EAAE,CAAC;IACxB,KAAK,CAAC,EAAE;QACN,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAC5B,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;KACpB,EAAE,CAAC;IACJ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,SAAS,CAAC,CAAC,IAAI;IACzB,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,CAAC,CAAC;IACtC,OAAO,EAAE,CAAC,CAAC;IACX,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,eAAe,KAAK,CAAC,CAAC;CACtC,CAAC;AAEF,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,KAAK,CAAC,eAAe,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,KAAK,GAAG,GAAG,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;CACvC;AAED,MAAM,MAAM,WAAW,GAAG,CACxB,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,iBAAiB,KACnB,OAAO,CAAC,MAAM,CAAC,CAAC"}
|
|
@@ -9,7 +9,7 @@ export function createNodeFromObject(content, schema, options) {
|
|
|
9
9
|
}
|
|
10
10
|
catch (error) {
|
|
11
11
|
if (options?.errorOnInvalidContent) {
|
|
12
|
-
throw new Error('Invalid JSON content', {
|
|
12
|
+
throw new Error('Invalid JSON content: ' + error.message, {
|
|
13
13
|
cause: error,
|
|
14
14
|
});
|
|
15
15
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createNodeFromContent.js","sourceRoot":"","sources":["../../src/utilities/createNodeFromContent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,IAAI,IAAI,eAAe,EAAU,MAAM,mBAAmB,CAAC;AAQ9E,MAAM,UAAU,oBAAoB,CAClC,OAAiD,EACjD,MAAc,EACd,OAAsC;IAEtC,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;QAE1C,IAAI,OAAO,EAAE,qBAAqB,EAAE,CAAC;YACnC,IAAI,CAAC,KAAK,EAAE,CAAC;QACf,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,
|
|
1
|
+
{"version":3,"file":"createNodeFromContent.js","sourceRoot":"","sources":["../../src/utilities/createNodeFromContent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,IAAI,IAAI,eAAe,EAAU,MAAM,mBAAmB,CAAC;AAQ9E,MAAM,UAAU,oBAAoB,CAClC,OAAiD,EACjD,MAAc,EACd,OAAsC;IAEtC,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;QAE1C,IAAI,OAAO,EAAE,qBAAqB,EAAE,CAAC;YACnC,IAAI,CAAC,KAAK,EAAE,CAAC;QACf,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,IAAI,OAAO,EAAE,qBAAqB,EAAE,CAAC;YACnC,MAAM,IAAI,KAAK,CAAC,wBAAwB,GAAG,KAAK,CAAC,OAAO,EAAE;gBACxD,KAAK,EAAE,KAAc;aACtB,CAAC,CAAC;QACL,CAAC;QAED,OAAO,CAAC,IAAI,CACV,kBAAkB,EAClB,eAAe,EACf,OAAO,EACP,QAAQ,EACR,KAAK,CACN,CAAC;QAEF,OAAO,MAAM,CAAC,WAAW,CAAC,aAAa,CAAC,IAAI,EAAE,EAAE,CAAE,CAAC;IACrD,CAAC;AACH,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,OAAsB,EACtB,MAAc;IAEd,OAAO,QAAQ,CAAC,SAAS,CACvB,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CACjD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,qBAAqB,CACnC,OAAiD,EACjD,MAAc,EACd,OAAsC;IAEtC,IAAI,OAAO,YAAY,eAAe,IAAI,OAAO,YAAY,QAAQ,EAAE,CAAC;QACtE,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,MAAM,aAAa,GAAG,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI,CAAC;IAEtE,IAAI,aAAa,EAAE,CAAC;QAClB,OAAO,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;IACxD,CAAC;IAED,OAAO,MAAM,CAAC,WAAW,CAAC,aAAa,CAAC,IAAI,EAAE,EAAE,CAAE,CAAC;AACrD,CAAC"}
|
package/package.json
CHANGED
package/src/CoreEditor.ts
CHANGED
|
@@ -1,16 +1,25 @@
|
|
|
1
1
|
import { EditorView } from 'prosemirror-view';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
Node as ProseMirrorNode,
|
|
4
|
+
ParseOptions,
|
|
5
|
+
Schema,
|
|
6
|
+
} from 'prosemirror-model';
|
|
3
7
|
|
|
4
8
|
import { ExtensionManager } from './ExtensionManager.js';
|
|
5
|
-
import type {
|
|
9
|
+
import type { Content, EditorKit, JSONContent } from './types.js';
|
|
6
10
|
import { EditorState, Transaction } from 'prosemirror-state';
|
|
7
11
|
import { CommandManager } from './commands/CommandManager.js';
|
|
8
12
|
import { nodeToTreeString } from './nodeToTreeString.js';
|
|
9
13
|
import { DummyEditorView } from './DummyEditorView.js';
|
|
10
|
-
import { ChainedCommands } from './commands/mod.js';
|
|
11
14
|
import { createNodeFromObject } from './utilities/createNodeFromContent.js';
|
|
12
15
|
import { Extension } from './Extension.js';
|
|
13
16
|
import { defaultUi, EditorUi } from './ui.js';
|
|
17
|
+
import { runInputRulesTexts } from './plugins/input-rules/InputRulesPlugin.js';
|
|
18
|
+
import {
|
|
19
|
+
ChainedCommands,
|
|
20
|
+
Command,
|
|
21
|
+
CommandFactories,
|
|
22
|
+
} from './commands/types.js';
|
|
14
23
|
|
|
15
24
|
function ensureDocSchema(
|
|
16
25
|
doc: ProseMirrorNode,
|
|
@@ -24,56 +33,83 @@ function ensureDocSchema(
|
|
|
24
33
|
return ProseMirrorNode.fromJSON(schema, json);
|
|
25
34
|
}
|
|
26
35
|
|
|
36
|
+
export interface EditorConfig {
|
|
37
|
+
element: HTMLElement;
|
|
38
|
+
content: Content;
|
|
39
|
+
parseOptions: ParseOptions;
|
|
40
|
+
// extensions: AnyExtensionOrReq[];
|
|
41
|
+
cdnUrl?: string;
|
|
42
|
+
uri?: string;
|
|
43
|
+
languageID?: string;
|
|
44
|
+
topNode?: string;
|
|
45
|
+
readOnly?: boolean;
|
|
46
|
+
}
|
|
47
|
+
|
|
27
48
|
export class CoreEditor extends EventTarget {
|
|
28
|
-
public readonly config: Partial<EditorConfig
|
|
29
|
-
element: undefined,
|
|
30
|
-
extensions: [],
|
|
31
|
-
};
|
|
32
|
-
private extensionManager: ExtensionManager;
|
|
49
|
+
public readonly config: Partial<EditorConfig>;
|
|
33
50
|
private commandManager: CommandManager;
|
|
34
51
|
public view!: EditorView | DummyEditorView;
|
|
35
52
|
public state!: EditorState;
|
|
36
53
|
public ui: EditorUi = defaultUi(this);
|
|
37
|
-
|
|
38
|
-
|
|
54
|
+
private linkListener?: EventListenerOrEventListenerObject;
|
|
55
|
+
private linkSource?: CoreEditor;
|
|
56
|
+
|
|
57
|
+
private constructor(
|
|
58
|
+
config: Partial<EditorConfig>,
|
|
59
|
+
public readonly schema: Schema,
|
|
60
|
+
private extensionManager: ExtensionManager,
|
|
61
|
+
) {
|
|
39
62
|
super();
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
...config,
|
|
43
|
-
};
|
|
63
|
+
|
|
64
|
+
this.config = { ...config };
|
|
44
65
|
|
|
45
66
|
this.commandManager = new CommandManager(
|
|
46
67
|
this,
|
|
47
68
|
);
|
|
69
|
+
}
|
|
48
70
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
71
|
+
static create(config: Partial<EditorConfig> & { editorKits: EditorKit[] }) {
|
|
72
|
+
const extensionManager = new ExtensionManager(config.editorKits);
|
|
73
|
+
|
|
74
|
+
const schema = extensionManager.getSchemaByResolvedExtensions();
|
|
75
|
+
|
|
76
|
+
const instance = new CoreEditor(config, schema, extensionManager);
|
|
77
|
+
extensionManager.created(instance, schema);
|
|
78
|
+
|
|
79
|
+
const content = config.content
|
|
80
|
+
? config.content
|
|
81
|
+
: schema.topNodeType.spec.EMPTY_DOC;
|
|
82
|
+
|
|
83
|
+
instance.createView(content);
|
|
84
|
+
instance.setupPlugins();
|
|
85
|
+
|
|
86
|
+
return instance;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
public clone(config?: EditorConfig): CoreEditor {
|
|
90
|
+
const extensionManager = new ExtensionManager(
|
|
91
|
+
this.extensionManager.editorKits,
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
const instance = new CoreEditor(
|
|
95
|
+
config || {},
|
|
96
|
+
this.schema,
|
|
97
|
+
extensionManager,
|
|
53
98
|
);
|
|
99
|
+
extensionManager.created(instance, this.schema);
|
|
54
100
|
|
|
55
|
-
this.
|
|
101
|
+
const content = this.getJSON();
|
|
56
102
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
// content: this.extensionManager.schema.topNodeType.spec.EMPTY_DOC,
|
|
60
|
-
// };
|
|
61
|
-
const content = this.config.content
|
|
62
|
-
? this.config.content
|
|
63
|
-
: this.extensionManager.schema.topNodeType.spec.EMPTY_DOC;
|
|
103
|
+
instance.createView(content);
|
|
104
|
+
instance.setupPlugins();
|
|
64
105
|
|
|
65
|
-
|
|
66
|
-
this.setupPlugins();
|
|
106
|
+
return instance;
|
|
67
107
|
}
|
|
68
108
|
|
|
69
109
|
getExtension<T extends Extension>(name: string): T | undefined {
|
|
70
110
|
return this.extensionManager.getExtension<T>(name);
|
|
71
111
|
}
|
|
72
112
|
|
|
73
|
-
public get schema() {
|
|
74
|
-
return this.extensionManager.schema;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
113
|
public get run() {
|
|
78
114
|
return this.commandManager.run;
|
|
79
115
|
}
|
|
@@ -90,6 +126,63 @@ export class CoreEditor extends EventTarget {
|
|
|
90
126
|
return this.commandManager.createCan();
|
|
91
127
|
}
|
|
92
128
|
|
|
129
|
+
public link(source: CoreEditor): ChainedCommands {
|
|
130
|
+
if (source === this) {
|
|
131
|
+
throw new Error('You cannot chain editor to itself');
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
this.unlink();
|
|
135
|
+
|
|
136
|
+
this.state = EditorState.create({ doc: source.getDocument() });
|
|
137
|
+
|
|
138
|
+
const { commandFactories } = this.commandManager;
|
|
139
|
+
const commands: Command[] = [];
|
|
140
|
+
|
|
141
|
+
const chain = {
|
|
142
|
+
...Object.fromEntries(
|
|
143
|
+
Object.entries(commandFactories).map(([name, commandFactory]) => {
|
|
144
|
+
const chainedCommand = (...args: never[]) => {
|
|
145
|
+
const command = commandFactory(...args);
|
|
146
|
+
commands.push(command);
|
|
147
|
+
return chain;
|
|
148
|
+
};
|
|
149
|
+
return [name, chainedCommand];
|
|
150
|
+
}),
|
|
151
|
+
),
|
|
152
|
+
run: () => {
|
|
153
|
+
this.linkSource = source;
|
|
154
|
+
this.linkListener = () => {
|
|
155
|
+
let state = source.state;
|
|
156
|
+
const dispatch = (tr: Transaction) => {
|
|
157
|
+
state = state.apply(tr);
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
for (const command of commands) {
|
|
161
|
+
if (!command(state, dispatch)) {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
this.state = state;
|
|
167
|
+
if (this.view) {
|
|
168
|
+
this.view.updateState(this.state);
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
source.addEventListener('changed', this.linkListener);
|
|
172
|
+
},
|
|
173
|
+
} as unknown as ChainedCommands;
|
|
174
|
+
|
|
175
|
+
return chain;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
public unlink() {
|
|
179
|
+
if (this.linkListener && this.linkSource) {
|
|
180
|
+
this.linkSource.removeEventListener('changed', this.linkListener);
|
|
181
|
+
this.linkListener = undefined;
|
|
182
|
+
this.linkSource = undefined;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
93
186
|
private createView(content: any) {
|
|
94
187
|
const doc = createNodeFromObject(content, this.schema);
|
|
95
188
|
|
|
@@ -175,8 +268,8 @@ export class CoreEditor extends EventTarget {
|
|
|
175
268
|
|
|
176
269
|
public clearDocument() {
|
|
177
270
|
const content = {
|
|
178
|
-
type: this.
|
|
179
|
-
content: this.
|
|
271
|
+
type: this.schema.topNodeType.name,
|
|
272
|
+
content: this.schema.topNodeType.spec.EMPTY_DOC.content,
|
|
180
273
|
};
|
|
181
274
|
|
|
182
275
|
this.setDocument(content);
|
|
@@ -216,7 +309,8 @@ export class CoreEditor extends EventTarget {
|
|
|
216
309
|
if (!converter) {
|
|
217
310
|
throw new Error('Converter not found for: ' + mediaType);
|
|
218
311
|
}
|
|
219
|
-
const
|
|
312
|
+
const parsedDoc = await converter.toDoc(content);
|
|
313
|
+
const doc = ProseMirrorNode.fromJSON(this.schema, parsedDoc.toJSON()); // TODO: WHY?!
|
|
220
314
|
|
|
221
315
|
this.state = EditorState.create({
|
|
222
316
|
doc,
|
|
@@ -224,6 +318,17 @@ export class CoreEditor extends EventTarget {
|
|
|
224
318
|
storedMarks: this.state.storedMarks,
|
|
225
319
|
});
|
|
226
320
|
|
|
321
|
+
const cmd = runInputRulesTexts();
|
|
322
|
+
let newState: EditorState | undefined;
|
|
323
|
+
const dispatch = (tr: Transaction) => {
|
|
324
|
+
newState = this.state.apply(tr);
|
|
325
|
+
};
|
|
326
|
+
const aa = cmd(this.state, dispatch);
|
|
327
|
+
|
|
328
|
+
if (newState) {
|
|
329
|
+
this.state = newState;
|
|
330
|
+
}
|
|
331
|
+
|
|
227
332
|
if (this.view) {
|
|
228
333
|
this.view.updateState(this.state);
|
|
229
334
|
}
|
|
@@ -253,13 +358,6 @@ export class CoreEditor extends EventTarget {
|
|
|
253
358
|
return this.state.doc.toJSON();
|
|
254
359
|
}
|
|
255
360
|
|
|
256
|
-
public clone(options: Partial<EditorConfig> = {}): CoreEditor {
|
|
257
|
-
return new CoreEditor({
|
|
258
|
-
...options,
|
|
259
|
-
extensions: [...(Array.from(this.extensionManager.extensions) || [])],
|
|
260
|
-
});
|
|
261
|
-
}
|
|
262
|
-
|
|
263
361
|
public debug(doc?: ProseMirrorNode) {
|
|
264
362
|
if (!doc) {
|
|
265
363
|
doc = this.state.doc;
|
|
@@ -274,4 +372,8 @@ export class CoreEditor extends EventTarget {
|
|
|
274
372
|
this.dispatchEvent(event);
|
|
275
373
|
this.view.destroy();
|
|
276
374
|
}
|
|
375
|
+
|
|
376
|
+
mergeCommandFactories(toInsert: Partial<CommandFactories>, name: string) {
|
|
377
|
+
this.commandManager.mergeCommandFactories(toInsert, name);
|
|
378
|
+
}
|
|
277
379
|
}
|
package/src/ExtensionManager.ts
CHANGED
|
@@ -3,8 +3,8 @@ import { Plugin } from 'prosemirror-state';
|
|
|
3
3
|
import { NodeViewConstructor } from 'prosemirror-view';
|
|
4
4
|
|
|
5
5
|
import { Converter, Extension } from './Extension.js';
|
|
6
|
-
import { AnyExtension, AnyExtensionOrReq } from './types.js';
|
|
7
|
-
import { CoreEditor } from './CoreEditor.js';
|
|
6
|
+
import type { AnyExtension, AnyExtensionOrReq, EditorKit } from './types.js';
|
|
7
|
+
import type { CoreEditor } from './CoreEditor.js';
|
|
8
8
|
import { Mark } from './Mark.js';
|
|
9
9
|
import { Node } from './Node.js';
|
|
10
10
|
import {
|
|
@@ -43,8 +43,6 @@ export function splitExtensions(extensions: Iterable<AnyExtension>) {
|
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
export class ExtensionManager {
|
|
46
|
-
public readonly schema: Schema;
|
|
47
|
-
|
|
48
46
|
public readonly extensions: Set<AnyExtension> = new Set();
|
|
49
47
|
readonly plugins: Plugin[] = [];
|
|
50
48
|
readonly nodeViews: Record<string, NodeViewConstructor> = {};
|
|
@@ -53,21 +51,14 @@ export class ExtensionManager {
|
|
|
53
51
|
|
|
54
52
|
private debug = true;
|
|
55
53
|
|
|
56
|
-
constructor(
|
|
57
|
-
extensions: AnyExtensionOrReq[]
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
54
|
+
constructor(public readonly editorKits: EditorKit[]) {
|
|
55
|
+
const extensions: AnyExtensionOrReq[] = editorKits
|
|
56
|
+
.reduce(
|
|
57
|
+
(prev: AnyExtensionOrReq[], cur) => prev.concat(cur.getExtensions()),
|
|
58
|
+
[],
|
|
59
|
+
);
|
|
60
|
+
|
|
61
61
|
this.setupExtensions(new Set(extensions));
|
|
62
|
-
this.schema = this.getSchemaByResolvedExtensions(editor);
|
|
63
|
-
|
|
64
|
-
const event = new CustomEvent('schema:ready', {
|
|
65
|
-
detail: {
|
|
66
|
-
editor,
|
|
67
|
-
schema: this.schema,
|
|
68
|
-
},
|
|
69
|
-
});
|
|
70
|
-
editor.dispatchEvent(event);
|
|
71
62
|
}
|
|
72
63
|
|
|
73
64
|
getExtension<T extends Extension>(name: string): T | undefined {
|
|
@@ -82,7 +73,7 @@ export class ExtensionManager {
|
|
|
82
73
|
}
|
|
83
74
|
}
|
|
84
75
|
|
|
85
|
-
private initPlugins() {
|
|
76
|
+
private initPlugins(editor: CoreEditor, schema: Schema) {
|
|
86
77
|
const inputRules: InputRule[] = [];
|
|
87
78
|
const keyBindings: Map<string, Command> = new Map();
|
|
88
79
|
|
|
@@ -95,8 +86,7 @@ export class ExtensionManager {
|
|
|
95
86
|
continue;
|
|
96
87
|
}
|
|
97
88
|
|
|
98
|
-
const commandFactory =
|
|
99
|
-
this.commandManager.commandFactories[toInsert[key]];
|
|
89
|
+
const commandFactory = editor.commandFactories[toInsert[key]];
|
|
100
90
|
if (!commandFactory) {
|
|
101
91
|
console.warn(`No command constructor: ${toInsert[key]}`);
|
|
102
92
|
continue;
|
|
@@ -115,40 +105,40 @@ export class ExtensionManager {
|
|
|
115
105
|
let converters = {};
|
|
116
106
|
|
|
117
107
|
for (const extension of this.extensions) {
|
|
118
|
-
extension.setEditor(
|
|
108
|
+
extension.setEditor(editor);
|
|
119
109
|
|
|
120
110
|
if (extension.type === 'node') {
|
|
121
|
-
const nodeType =
|
|
111
|
+
const nodeType = schema.nodes[extension.name];
|
|
122
112
|
inputRules.push(...extension.getInputRules(nodeType));
|
|
123
113
|
this.plugins.push(
|
|
124
114
|
...extension.getProseMirrorPlugins(),
|
|
125
115
|
);
|
|
126
|
-
|
|
127
|
-
extension.getCommandFactories(
|
|
116
|
+
editor.mergeCommandFactories(
|
|
117
|
+
extension.getCommandFactories(editor, nodeType),
|
|
128
118
|
extension.name,
|
|
129
119
|
);
|
|
130
120
|
mergeShortcuts(
|
|
131
|
-
extension.getKeyboardShortcuts(
|
|
121
|
+
extension.getKeyboardShortcuts(editor),
|
|
132
122
|
extension.name,
|
|
133
123
|
);
|
|
134
124
|
converters = {
|
|
135
125
|
...converters,
|
|
136
|
-
...extension.getConverters(
|
|
126
|
+
...extension.getConverters(editor, schema),
|
|
137
127
|
};
|
|
138
|
-
const nodeView = extension.getNodeView(
|
|
128
|
+
const nodeView = extension.getNodeView(editor);
|
|
139
129
|
if (nodeView) {
|
|
140
130
|
this.nodeViews[extension.name] = nodeView;
|
|
141
131
|
}
|
|
142
132
|
}
|
|
143
133
|
if (extension.type === 'mark') {
|
|
144
|
-
const markType =
|
|
134
|
+
const markType = schema.marks[extension.name];
|
|
145
135
|
inputRules.push(...extension.getInputRules(markType));
|
|
146
|
-
|
|
147
|
-
extension.getCommandFactories(
|
|
136
|
+
editor.mergeCommandFactories(
|
|
137
|
+
extension.getCommandFactories(editor, markType),
|
|
148
138
|
extension.name,
|
|
149
139
|
);
|
|
150
140
|
mergeShortcuts(
|
|
151
|
-
extension.getKeyboardShortcuts(
|
|
141
|
+
extension.getKeyboardShortcuts(editor),
|
|
152
142
|
extension.name,
|
|
153
143
|
);
|
|
154
144
|
}
|
|
@@ -156,17 +146,17 @@ export class ExtensionManager {
|
|
|
156
146
|
this.plugins.push(
|
|
157
147
|
...extension.getProseMirrorPlugins(),
|
|
158
148
|
);
|
|
159
|
-
|
|
160
|
-
extension.getCommandFactories(
|
|
149
|
+
editor.mergeCommandFactories(
|
|
150
|
+
extension.getCommandFactories(editor),
|
|
161
151
|
extension.name,
|
|
162
152
|
);
|
|
163
153
|
mergeShortcuts(
|
|
164
|
-
extension.getKeyboardShortcuts(
|
|
154
|
+
extension.getKeyboardShortcuts(editor),
|
|
165
155
|
extension.name,
|
|
166
156
|
);
|
|
167
157
|
converters = {
|
|
168
158
|
...converters,
|
|
169
|
-
...extension.getConverters(
|
|
159
|
+
...extension.getConverters(editor, schema),
|
|
170
160
|
};
|
|
171
161
|
}
|
|
172
162
|
}
|
|
@@ -193,7 +183,7 @@ export class ExtensionManager {
|
|
|
193
183
|
|
|
194
184
|
this.plugins.push(new InputRulesPlugin(inputRules));
|
|
195
185
|
this.plugins.push(new KeymapPlugin(Object.fromEntries(keyBindings)));
|
|
196
|
-
this.plugins.push(new TrackSelecionPlugin(
|
|
186
|
+
this.plugins.push(new TrackSelecionPlugin(editor));
|
|
197
187
|
}
|
|
198
188
|
|
|
199
189
|
private setupExtensions(extensions: Set<AnyExtensionOrReq>) {
|
|
@@ -202,7 +192,9 @@ export class ExtensionManager {
|
|
|
202
192
|
const createMap = (extensions: Set<AnyExtensionOrReq>) => {
|
|
203
193
|
for (const extension of extensions) {
|
|
204
194
|
if ('name' in extension) {
|
|
205
|
-
allExtensions.
|
|
195
|
+
if (!allExtensions.has(extension.name)) {
|
|
196
|
+
allExtensions.set(extension.name, extension);
|
|
197
|
+
}
|
|
206
198
|
}
|
|
207
199
|
if ('requires' in extension) {
|
|
208
200
|
const childExtensions = Array.from(extension.requires).filter((e) =>
|
|
@@ -268,24 +260,23 @@ export class ExtensionManager {
|
|
|
268
260
|
}
|
|
269
261
|
}
|
|
270
262
|
|
|
271
|
-
getSchemaByResolvedExtensions(
|
|
263
|
+
getSchemaByResolvedExtensions(): Schema {
|
|
272
264
|
const { nodeExtensions, markExtensions, baseExtensions } = splitExtensions(
|
|
273
265
|
this.extensions,
|
|
274
266
|
);
|
|
275
267
|
|
|
276
|
-
for (const extension of baseExtensions) {
|
|
277
|
-
if (Array.isArray(extension.conflicts)) {
|
|
278
|
-
for (const name of extension.conflicts) {
|
|
279
|
-
if (this.getExtension(name)) {
|
|
280
|
-
throw new Error(`Extension conflict: ${extension.name} vs ${name}`);
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
|
|
286
268
|
const nodes: { [name: string]: NodeSpec } = {};
|
|
269
|
+
let topNode = '';
|
|
287
270
|
for (const extension of nodeExtensions) {
|
|
288
271
|
nodes[extension.name] = extension.getNodeSpec();
|
|
272
|
+
|
|
273
|
+
if (nodes[extension.name].EMPTY_DOC) {
|
|
274
|
+
if (topNode) {
|
|
275
|
+
throw new Error(`Multiple topNodes: ${extension.name}, ${topNode}`);
|
|
276
|
+
}
|
|
277
|
+
topNode = extension.name;
|
|
278
|
+
}
|
|
279
|
+
|
|
289
280
|
addAttributesToSchema(nodes[extension.name], extension);
|
|
290
281
|
}
|
|
291
282
|
|
|
@@ -296,7 +287,7 @@ export class ExtensionManager {
|
|
|
296
287
|
}
|
|
297
288
|
|
|
298
289
|
const spec = {
|
|
299
|
-
topNode:
|
|
290
|
+
topNode: topNode || 'doc',
|
|
300
291
|
nodes,
|
|
301
292
|
marks,
|
|
302
293
|
};
|
|
@@ -307,19 +298,25 @@ export class ExtensionManager {
|
|
|
307
298
|
}
|
|
308
299
|
}
|
|
309
300
|
|
|
310
|
-
const event = new CustomEvent('schema:spec', {
|
|
311
|
-
detail: {
|
|
312
|
-
editor,
|
|
313
|
-
spec,
|
|
314
|
-
},
|
|
315
|
-
});
|
|
316
|
-
editor.dispatchEvent(event);
|
|
317
|
-
|
|
318
301
|
return new Schema(spec);
|
|
319
302
|
}
|
|
320
303
|
|
|
321
|
-
created() {
|
|
322
|
-
|
|
304
|
+
created(editor: CoreEditor, schema: Schema) {
|
|
305
|
+
const { nodeExtensions, markExtensions, baseExtensions } = splitExtensions(
|
|
306
|
+
this.extensions,
|
|
307
|
+
);
|
|
308
|
+
|
|
309
|
+
for (const extension of baseExtensions) {
|
|
310
|
+
if (Array.isArray(extension.conflicts)) {
|
|
311
|
+
for (const name of extension.conflicts) {
|
|
312
|
+
if (this.getExtension(name)) {
|
|
313
|
+
throw new Error(`Extension conflict: ${extension.name} vs ${name}`);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
this.initPlugins(editor, schema);
|
|
323
320
|
|
|
324
321
|
for (const extension of this.extensions) {
|
|
325
322
|
extension.created();
|
package/src/Node.ts
CHANGED
|
@@ -80,10 +80,6 @@ export class CommandManager {
|
|
|
80
80
|
};
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
get state(): EditorState {
|
|
84
|
-
return this.editor.state;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
83
|
get chain(): () => ChainedCommands {
|
|
88
84
|
return () => this.createChain();
|
|
89
85
|
}
|
|
@@ -96,7 +92,8 @@ export class CommandManager {
|
|
|
96
92
|
startTr?: Transaction,
|
|
97
93
|
shouldDispatch = true,
|
|
98
94
|
): ChainedCommands {
|
|
99
|
-
const { commandFactories, editor
|
|
95
|
+
const { commandFactories, editor } = this;
|
|
96
|
+
const state = this.editor.state;
|
|
100
97
|
const { view } = editor;
|
|
101
98
|
const callbacks: boolean[] = [];
|
|
102
99
|
const hasStartTransaction = !!startTr;
|
|
@@ -32,7 +32,8 @@ import { EditorView } from 'prosemirror-view';
|
|
|
32
32
|
|
|
33
33
|
import { type Command, CommandFactory } from './types.js';
|
|
34
34
|
import {
|
|
35
|
-
|
|
35
|
+
runInputRulesRange,
|
|
36
|
+
runInputRulesTexts,
|
|
36
37
|
undoInputRuleCommand,
|
|
37
38
|
} from '../plugins/input-rules/InputRulesPlugin.js';
|
|
38
39
|
|
|
@@ -54,7 +55,8 @@ const wrapInList = (
|
|
|
54
55
|
if (!range) return false;
|
|
55
56
|
// let tr = dispatch ? state.tr : null;
|
|
56
57
|
const tr = state.tr;
|
|
57
|
-
|
|
58
|
+
const cmd = wrapRangeInList(tr, range, listType, attrs);
|
|
59
|
+
if (!cmd(state, dispatch)) return false;
|
|
58
60
|
if (dispatch) dispatch(tr!.scrollIntoView());
|
|
59
61
|
return true;
|
|
60
62
|
};
|
|
@@ -1099,5 +1101,6 @@ export const baseCommandFactories: Record<string, CommandFactory> = {
|
|
|
1099
1101
|
setBlockType,
|
|
1100
1102
|
toggleMark,
|
|
1101
1103
|
undoInputRule,
|
|
1102
|
-
|
|
1104
|
+
runInputRulesRange,
|
|
1105
|
+
runInputRulesTexts,
|
|
1103
1106
|
};
|