ckeditor5-elements-schema 49.0.0-alpha.2 → 49.0.0-alpha.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.
Files changed (114) hide show
  1. package/README.md +28 -2
  2. package/dist/augmentation.d.ts +7 -1
  3. package/dist/augmentation.d.ts.map +1 -1
  4. package/dist/commands/elementBlockCommand.d.ts +46 -0
  5. package/dist/commands/elementBlockCommand.d.ts.map +1 -0
  6. package/dist/commands/elementBlockCommand.js +71 -0
  7. package/dist/commands/elementBlockCommand.js.map +1 -0
  8. package/dist/commands/elementContainerCommand.d.ts +36 -0
  9. package/dist/commands/elementContainerCommand.d.ts.map +1 -0
  10. package/dist/commands/elementContainerCommand.js +67 -0
  11. package/dist/commands/elementContainerCommand.js.map +1 -0
  12. package/dist/commands/elementInlineCommand.d.ts +87 -0
  13. package/dist/commands/elementInlineCommand.d.ts.map +1 -0
  14. package/dist/commands/elementInlineCommand.js +253 -0
  15. package/dist/commands/elementInlineCommand.js.map +1 -0
  16. package/dist/commands/elementInsertCommand.d.ts +33 -0
  17. package/dist/commands/elementInsertCommand.d.ts.map +1 -0
  18. package/dist/commands/elementInsertCommand.js +61 -0
  19. package/dist/commands/elementInsertCommand.js.map +1 -0
  20. package/dist/commands/elementSchemaCommand.d.ts +62 -0
  21. package/dist/commands/elementSchemaCommand.d.ts.map +1 -0
  22. package/dist/commands/elementSchemaCommand.js +107 -0
  23. package/dist/commands/elementSchemaCommand.js.map +1 -0
  24. package/dist/{convertElementSchema.d.ts → conversion/convertElementSchema.d.ts} +3 -2
  25. package/dist/conversion/convertElementSchema.d.ts.map +1 -0
  26. package/dist/{convertElementSchema.js → conversion/convertElementSchema.js} +16 -4
  27. package/dist/conversion/convertElementSchema.js.map +1 -0
  28. package/dist/conversion/inlineTextElement.d.ts +24 -0
  29. package/dist/conversion/inlineTextElement.d.ts.map +1 -0
  30. package/dist/conversion/inlineTextElement.js +28 -0
  31. package/dist/conversion/inlineTextElement.js.map +1 -0
  32. package/dist/definition/canHold.d.ts.map +1 -0
  33. package/dist/definition/canHold.js.map +1 -0
  34. package/dist/definition/compileElementSchema.d.ts.map +1 -0
  35. package/dist/definition/compileElementSchema.js.map +1 -0
  36. package/dist/definition/elementSchemaError.d.ts.map +1 -0
  37. package/dist/definition/elementSchemaError.js.map +1 -0
  38. package/dist/definition/readDefinition.d.ts.map +1 -0
  39. package/dist/definition/readDefinition.js.map +1 -0
  40. package/dist/definition/suggest.d.ts.map +1 -0
  41. package/dist/definition/suggest.js.map +1 -0
  42. package/dist/definition/types.d.ts.map +1 -0
  43. package/dist/definition/types.js.map +1 -0
  44. package/dist/definition/validateElementSchema.d.ts.map +1 -0
  45. package/dist/definition/validateElementSchema.js.map +1 -0
  46. package/dist/elementSchema.js +4 -4
  47. package/dist/elementSchema.js.map +1 -1
  48. package/dist/elementSchemaCommands.d.ts +83 -0
  49. package/dist/elementSchemaCommands.d.ts.map +1 -0
  50. package/dist/elementSchemaCommands.js +137 -0
  51. package/dist/elementSchemaCommands.js.map +1 -0
  52. package/dist/index.d.ts +9 -1
  53. package/dist/index.d.ts.map +1 -1
  54. package/dist/index.js +11 -1
  55. package/dist/index.js.map +1 -1
  56. package/dist/typing/twoStepCaretMovement.d.ts +11 -0
  57. package/dist/typing/twoStepCaretMovement.d.ts.map +1 -0
  58. package/dist/typing/twoStepCaretMovement.js +76 -0
  59. package/dist/typing/twoStepCaretMovement.js.map +1 -0
  60. package/dist/validate.d.ts +4 -4
  61. package/dist/validate.d.ts.map +1 -1
  62. package/dist/validate.js +3 -3
  63. package/dist/validate.js.map +1 -1
  64. package/package.json +2 -2
  65. package/src/augmentation.ts +8 -1
  66. package/src/commands/elementBlockCommand.ts +87 -0
  67. package/src/commands/elementContainerCommand.ts +83 -0
  68. package/src/commands/elementInlineCommand.ts +311 -0
  69. package/src/commands/elementInsertCommand.ts +74 -0
  70. package/src/commands/elementSchemaCommand.ts +140 -0
  71. package/src/{convertElementSchema.ts → conversion/convertElementSchema.ts} +19 -5
  72. package/src/conversion/inlineTextElement.ts +31 -0
  73. package/src/elementSchema.ts +5 -5
  74. package/src/elementSchemaCommands.ts +202 -0
  75. package/src/index.ts +17 -1
  76. package/src/typing/twoStepCaretMovement.ts +119 -0
  77. package/src/validate.ts +4 -4
  78. package/dist/canHold.d.ts.map +0 -1
  79. package/dist/canHold.js.map +0 -1
  80. package/dist/compileElementSchema.d.ts.map +0 -1
  81. package/dist/compileElementSchema.js.map +0 -1
  82. package/dist/convertElementSchema.d.ts.map +0 -1
  83. package/dist/convertElementSchema.js.map +0 -1
  84. package/dist/elementSchemaError.d.ts.map +0 -1
  85. package/dist/elementSchemaError.js.map +0 -1
  86. package/dist/readDefinition.d.ts.map +0 -1
  87. package/dist/readDefinition.js.map +0 -1
  88. package/dist/suggest.d.ts.map +0 -1
  89. package/dist/suggest.js.map +0 -1
  90. package/dist/types.d.ts.map +0 -1
  91. package/dist/types.js.map +0 -1
  92. package/dist/validateElementSchema.d.ts.map +0 -1
  93. package/dist/validateElementSchema.js.map +0 -1
  94. /package/dist/{canHold.d.ts → definition/canHold.d.ts} +0 -0
  95. /package/dist/{canHold.js → definition/canHold.js} +0 -0
  96. /package/dist/{compileElementSchema.d.ts → definition/compileElementSchema.d.ts} +0 -0
  97. /package/dist/{compileElementSchema.js → definition/compileElementSchema.js} +0 -0
  98. /package/dist/{elementSchemaError.d.ts → definition/elementSchemaError.d.ts} +0 -0
  99. /package/dist/{elementSchemaError.js → definition/elementSchemaError.js} +0 -0
  100. /package/dist/{readDefinition.d.ts → definition/readDefinition.d.ts} +0 -0
  101. /package/dist/{readDefinition.js → definition/readDefinition.js} +0 -0
  102. /package/dist/{suggest.d.ts → definition/suggest.d.ts} +0 -0
  103. /package/dist/{suggest.js → definition/suggest.js} +0 -0
  104. /package/dist/{types.d.ts → definition/types.d.ts} +0 -0
  105. /package/dist/{types.js → definition/types.js} +0 -0
  106. /package/dist/{validateElementSchema.d.ts → definition/validateElementSchema.d.ts} +0 -0
  107. /package/dist/{validateElementSchema.js → definition/validateElementSchema.js} +0 -0
  108. /package/src/{canHold.ts → definition/canHold.ts} +0 -0
  109. /package/src/{compileElementSchema.ts → definition/compileElementSchema.ts} +0 -0
  110. /package/src/{elementSchemaError.ts → definition/elementSchemaError.ts} +0 -0
  111. /package/src/{readDefinition.ts → definition/readDefinition.ts} +0 -0
  112. /package/src/{suggest.ts → definition/suggest.ts} +0 -0
  113. /package/src/{types.ts → definition/types.ts} +0 -0
  114. /package/src/{validateElementSchema.ts → definition/validateElementSchema.ts} +0 -0
@@ -0,0 +1,83 @@
1
+ import { Plugin } from 'ckeditor5';
2
+ import ElementSchema from './elementSchema.js';
3
+ /**
4
+ * An element of {@link ElementSchemaCommands}: its command and its button.
5
+ */
6
+ export interface ElementSchemaCommandDefinition {
7
+ /**
8
+ * The model element: of the element schema, or of another plugin. Default: the name of the command.
9
+ */
10
+ element?: string;
11
+ /**
12
+ * The title of the command, and the label of its button, e.g. `'Bold'`.
13
+ */
14
+ title: string;
15
+ /**
16
+ * The icon of the command and of its button (an SVG string), e.g. `IconBold` of CKEditor.
17
+ */
18
+ icon?: string;
19
+ /**
20
+ * The keystroke that executes the command, e.g. `'Ctrl+B'`.
21
+ */
22
+ keystroke?: string;
23
+ /**
24
+ * The tag of the element in the data and in the editing view, e.g. `'strong'` or `'hr'`. The converters of the plugin
25
+ * replace the ones of the element schema (`elementSchemaConverters`) in the downcast, and the upcast takes both.
26
+ * Without it, the element is converted by the schema, or by your converters.
27
+ */
28
+ view?: string;
29
+ }
30
+ /**
31
+ * The `elementSchemaCommands` option: the elements, by the name of their command and of their button.
32
+ */
33
+ export type ElementSchemaCommandsConfig = Record<string, ElementSchemaCommandDefinition>;
34
+ /**
35
+ * Commands and toolbar buttons for the elements of the element schema, as CKEditor's features have for theirs: the
36
+ * command of an element is the one of its kind (see {@link ElementSchemaCommand}).
37
+ *
38
+ * | Element | Command | Works as CKEditor's |
39
+ * | ----------------------------- | --------------------------- | ----------------------------- |
40
+ * | inline `block` | {@link ElementInlineCommand} | bold: wraps text |
41
+ * | `block` | {@link ElementBlockCommand} | heading: renames blocks |
42
+ * | `container` | {@link ElementContainerCommand} | block quote: wraps blocks |
43
+ * | `empty`, inline `container` | {@link ElementInsertCommand} | horizontal line: inserts |
44
+ *
45
+ * ```ts
46
+ * elementSchema: schema,
47
+ * elementSchemaCommands: {
48
+ * bold: { title: 'Bold', icon: IconBold, keystroke: 'Ctrl+B', view: 'strong' },
49
+ * callout: { title: 'Callout', icon: IconQuote },
50
+ * divider: { title: 'Divider', icon: IconHorizontalLine, view: 'hr' }
51
+ * },
52
+ * toolbar: ['bold', 'callout', 'divider']
53
+ * ```
54
+ *
55
+ * Each key is the name of the command and of its toolbar button. The commands have titles and icons, so they can be
56
+ * menu items too, e.g. of the context menu.
57
+ *
58
+ * At the ends of the inline elements with text, the left and right arrow keys move in two steps, as CKEditor's two-step
59
+ * caret movement does at the ends of a bold: in the element, then in the text.
60
+ *
61
+ * The commands are made when the elements are registered, after `ElementSchema` and the other plugins are initialized.
62
+ * The editor is not created when an element is unknown.
63
+ */
64
+ export default class ElementSchemaCommands extends Plugin {
65
+ static get pluginName(): 'ElementSchemaCommands';
66
+ static get requires(): readonly [typeof ElementSchema];
67
+ /**
68
+ * The commands, by their name.
69
+ */
70
+ private readonly _commands;
71
+ init(): void;
72
+ /**
73
+ * Makes the commands of the elements, which are registered then, and their converters.
74
+ */
75
+ afterInit(): void;
76
+ private _getDefinitions;
77
+ /**
78
+ * Declares the converters of an element with the tag of its `view`: the downcast with the highest priority, so it
79
+ * replaces the ones of the element schema, and the upcast.
80
+ */
81
+ private _convert;
82
+ }
83
+ //# sourceMappingURL=elementSchemaCommands.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"elementSchemaCommands.d.ts","sourceRoot":"","sources":["../src/elementSchemaCommands.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAA+D,MAAM,WAAW,CAAC;AAOhG,OAAO,aAAa,MAAM,oBAAoB,CAAC;AAI/C;;GAEG;AACH,MAAM,WAAW,8BAA8B;IAC9C;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,MAAM,MAAM,2BAA2B,GAAG,MAAM,CAAC,MAAM,EAAE,8BAA8B,CAAC,CAAC;AAEzF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,CAAC,OAAO,OAAO,qBAAsB,SAAQ,MAAM;IACxD,WAAkB,UAAU,IAAI,uBAAuB,CAEtD;IAED,WAAkB,QAAQ,IAAI,SAAS,CAAC,OAAO,aAAa,CAAC,CAE5D;IAED;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA2C;IAE9D,IAAI,IAAI,IAAI;IA2BnB;;OAEG;IACI,SAAS,IAAI,IAAI;IA0CxB,OAAO,CAAC,eAAe;IAIvB;;;OAGG;IACH,OAAO,CAAC,QAAQ;CAWhB"}
@@ -0,0 +1,137 @@
1
+ import { Plugin } from 'ckeditor5';
2
+ import { ElementOrPositionButtonView } from 'ckeditor5-elements-core';
3
+ import { createInlineTextElement } from './conversion/inlineTextElement.js';
4
+ import ElementBlockCommand from './commands/elementBlockCommand.js';
5
+ import ElementContainerCommand from './commands/elementContainerCommand.js';
6
+ import ElementInlineCommand from './commands/elementInlineCommand.js';
7
+ import ElementInsertCommand from './commands/elementInsertCommand.js';
8
+ import ElementSchema from './elementSchema.js';
9
+ import { enableTwoStepCaretMovement } from './typing/twoStepCaretMovement.js';
10
+ /**
11
+ * Commands and toolbar buttons for the elements of the element schema, as CKEditor's features have for theirs: the
12
+ * command of an element is the one of its kind (see {@link ElementSchemaCommand}).
13
+ *
14
+ * | Element | Command | Works as CKEditor's |
15
+ * | ----------------------------- | --------------------------- | ----------------------------- |
16
+ * | inline `block` | {@link ElementInlineCommand} | bold: wraps text |
17
+ * | `block` | {@link ElementBlockCommand} | heading: renames blocks |
18
+ * | `container` | {@link ElementContainerCommand} | block quote: wraps blocks |
19
+ * | `empty`, inline `container` | {@link ElementInsertCommand} | horizontal line: inserts |
20
+ *
21
+ * ```ts
22
+ * elementSchema: schema,
23
+ * elementSchemaCommands: {
24
+ * bold: { title: 'Bold', icon: IconBold, keystroke: 'Ctrl+B', view: 'strong' },
25
+ * callout: { title: 'Callout', icon: IconQuote },
26
+ * divider: { title: 'Divider', icon: IconHorizontalLine, view: 'hr' }
27
+ * },
28
+ * toolbar: ['bold', 'callout', 'divider']
29
+ * ```
30
+ *
31
+ * Each key is the name of the command and of its toolbar button. The commands have titles and icons, so they can be
32
+ * menu items too, e.g. of the context menu.
33
+ *
34
+ * At the ends of the inline elements with text, the left and right arrow keys move in two steps, as CKEditor's two-step
35
+ * caret movement does at the ends of a bold: in the element, then in the text.
36
+ *
37
+ * The commands are made when the elements are registered, after `ElementSchema` and the other plugins are initialized.
38
+ * The editor is not created when an element is unknown.
39
+ */
40
+ export default class ElementSchemaCommands extends Plugin {
41
+ static get pluginName() {
42
+ return 'ElementSchemaCommands';
43
+ }
44
+ static get requires() {
45
+ return [ElementSchema];
46
+ }
47
+ /**
48
+ * The commands, by their name.
49
+ */
50
+ _commands = new Map();
51
+ init() {
52
+ const editor = this.editor;
53
+ for (const [name, { title, keystroke }] of this._getDefinitions()) {
54
+ if (keystroke) {
55
+ editor.keystrokes.set(keystroke, name);
56
+ editor.accessibility.addKeystrokeInfos({ keystrokes: [{ label: title, keystroke }] });
57
+ }
58
+ editor.ui.componentFactory.add(name, locale => {
59
+ const command = this._commands.get(name);
60
+ // The commands are made in `afterInit()`, and the toolbars after it.
61
+ if (!command) {
62
+ throw new Error(`elementSchemaCommands.${name}: the button is created before the command.`);
63
+ }
64
+ const button = new ElementOrPositionButtonView(locale, command);
65
+ button.bind('isOn').to(command, 'isOn');
66
+ button.keystroke = keystroke;
67
+ return button;
68
+ });
69
+ }
70
+ }
71
+ /**
72
+ * Makes the commands of the elements, which are registered then, and their converters.
73
+ */
74
+ afterInit() {
75
+ const editor = this.editor;
76
+ const schema = editor.model.schema;
77
+ const inlineNames = new Set();
78
+ for (const [name, { element, title, icon, view }] of this._getDefinitions()) {
79
+ const elementName = element ?? name;
80
+ if (!schema.isRegistered(elementName)) {
81
+ throw new Error(`elementSchemaCommands.${name}: unknown element "${elementName}". Declare it in the element schema, or ` +
82
+ `set "element" to an element of another plugin.`);
83
+ }
84
+ const CommandClass = getCommandClass(schema, elementName);
85
+ const command = new CommandClass(editor, elementName);
86
+ command.set({ title, icon });
87
+ editor.commands.add(name, command);
88
+ this._commands.set(name, command);
89
+ if (command instanceof ElementInlineCommand) {
90
+ inlineNames.add(elementName);
91
+ }
92
+ if (view) {
93
+ this._convert(elementName, view, (writer) => {
94
+ if (command instanceof ElementInlineCommand) {
95
+ return createInlineTextElement(writer, view);
96
+ }
97
+ return schema.isObject(elementName)
98
+ ? writer.createEmptyElement(view)
99
+ : writer.createContainerElement(view);
100
+ });
101
+ }
102
+ }
103
+ enableTwoStepCaretMovement(this, inlineNames);
104
+ }
105
+ _getDefinitions() {
106
+ return Object.entries(this.editor.config.get('elementSchemaCommands') ?? {});
107
+ }
108
+ /**
109
+ * Declares the converters of an element with the tag of its `view`: the downcast with the highest priority, so it
110
+ * replaces the ones of the element schema, and the upcast.
111
+ */
112
+ _convert(elementName, tag, createView) {
113
+ const conversion = this.editor.conversion;
114
+ conversion.for('upcast').elementToElement({ view: tag, model: elementName });
115
+ conversion.for('downcast').elementToElement({
116
+ model: elementName,
117
+ view: (_element, { writer }) => createView(writer),
118
+ // Over the ones of the schema, some of which are `high` already.
119
+ converterPriority: 'highest'
120
+ });
121
+ }
122
+ }
123
+ /**
124
+ * Returns the command of an element, by its kind: an object, or an inline element with no text, is inserted; an inline
125
+ * element with text wraps text; a block-level one with text is a block; the others are containers.
126
+ */
127
+ function getCommandClass(schema, name) {
128
+ const holdsText = schema.checkChild(name, '$text');
129
+ if (schema.isObject(name) || (schema.isInline(name) && !holdsText)) {
130
+ return ElementInsertCommand;
131
+ }
132
+ if (schema.isInline(name)) {
133
+ return ElementInlineCommand;
134
+ }
135
+ return holdsText ? ElementBlockCommand : ElementContainerCommand;
136
+ }
137
+ //# sourceMappingURL=elementSchemaCommands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"elementSchemaCommands.js","sourceRoot":"","sources":["../src/elementSchemaCommands.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,10 +1,18 @@
1
1
  /**
2
2
  * Element schema: declare elements in the model schema from a simple definition, e.g. a JSON file, with three types of
3
- * elements (`empty`, `block`, `container`), and a validation that rejects contradictory definitions.
3
+ * elements (`empty`, `block`, `container`), and a validation that rejects contradictory definitions. `ElementSchemaCommands`
4
+ * makes commands and buttons for its elements.
4
5
  *
5
6
  * @module ckeditor5-elements-schema
6
7
  */
7
8
  export { default as ElementSchema } from './elementSchema.js';
9
+ export { default as ElementSchemaCommands, type ElementSchemaCommandDefinition, type ElementSchemaCommandsConfig } from './elementSchemaCommands.js';
10
+ export { default as ElementSchemaCommand } from './commands/elementSchemaCommand.js';
11
+ export { default as ElementInlineCommand } from './commands/elementInlineCommand.js';
12
+ export { default as ElementBlockCommand } from './commands/elementBlockCommand.js';
13
+ export { default as ElementContainerCommand } from './commands/elementContainerCommand.js';
14
+ export { default as ElementInsertCommand } from './commands/elementInsertCommand.js';
15
+ export { withoutBlockFiller } from './conversion/inlineTextElement.js';
8
16
  export * from './validate.js';
9
17
  import './augmentation.js';
10
18
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAG9D,cAAc,eAAe,CAAC;AAE9B,OAAO,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EACN,OAAO,IAAI,qBAAqB,EAChC,KAAK,8BAA8B,EACnC,KAAK,2BAA2B,EAChC,MAAM,4BAA4B,CAAC;AAGpC,OAAO,EAAE,OAAO,IAAI,oBAAoB,EAAE,MAAM,oCAAoC,CAAC;AACrF,OAAO,EAAE,OAAO,IAAI,oBAAoB,EAAE,MAAM,oCAAoC,CAAC;AACrF,OAAO,EAAE,OAAO,IAAI,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AACnF,OAAO,EAAE,OAAO,IAAI,uBAAuB,EAAE,MAAM,uCAAuC,CAAC;AAC3F,OAAO,EAAE,OAAO,IAAI,oBAAoB,EAAE,MAAM,oCAAoC,CAAC;AAGrF,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AAGvE,cAAc,eAAe,CAAC;AAE9B,OAAO,mBAAmB,CAAC"}
package/dist/index.js CHANGED
@@ -1,11 +1,21 @@
1
1
  /**
2
2
  * Element schema: declare elements in the model schema from a simple definition, e.g. a JSON file, with three types of
3
- * elements (`empty`, `block`, `container`), and a validation that rejects contradictory definitions.
3
+ * elements (`empty`, `block`, `container`), and a validation that rejects contradictory definitions. `ElementSchemaCommands`
4
+ * makes commands and buttons for its elements.
4
5
  *
5
6
  * @module ckeditor5-elements-schema
6
7
  */
7
8
  // Plugins.
8
9
  export { default as ElementSchema } from './elementSchema.js';
10
+ export { default as ElementSchemaCommands } from './elementSchemaCommands.js';
11
+ // Commands.
12
+ export { default as ElementSchemaCommand } from './commands/elementSchemaCommand.js';
13
+ export { default as ElementInlineCommand } from './commands/elementInlineCommand.js';
14
+ export { default as ElementBlockCommand } from './commands/elementBlockCommand.js';
15
+ export { default as ElementContainerCommand } from './commands/elementContainerCommand.js';
16
+ export { default as ElementInsertCommand } from './commands/elementInsertCommand.js';
17
+ // Utils.
18
+ export { withoutBlockFiller } from './conversion/inlineTextElement.js';
9
19
  // Validation and compiling, which do not need an editor (also in `validate.ts`, for Node.js).
10
20
  export * from './validate.js';
11
21
  import './augmentation.js';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,WAAW;AACX,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAE9D,8FAA8F;AAC9F,cAAc,eAAe,CAAC;AAE9B,OAAO,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,WAAW;AACX,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EACN,OAAO,IAAI,qBAAqB,EAGhC,MAAM,4BAA4B,CAAC;AAEpC,YAAY;AACZ,OAAO,EAAE,OAAO,IAAI,oBAAoB,EAAE,MAAM,oCAAoC,CAAC;AACrF,OAAO,EAAE,OAAO,IAAI,oBAAoB,EAAE,MAAM,oCAAoC,CAAC;AACrF,OAAO,EAAE,OAAO,IAAI,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AACnF,OAAO,EAAE,OAAO,IAAI,uBAAuB,EAAE,MAAM,uCAAuC,CAAC;AAC3F,OAAO,EAAE,OAAO,IAAI,oBAAoB,EAAE,MAAM,oCAAoC,CAAC;AAErF,SAAS;AACT,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AAEvE,8FAA8F;AAC9F,cAAc,eAAe,CAAC;AAE9B,OAAO,mBAAmB,CAAC"}
@@ -0,0 +1,11 @@
1
+ import { type Plugin } from 'ckeditor5';
2
+ /**
3
+ * Makes the left and right arrow keys move in two steps at the ends of inline elements, as CKEditor's two-step caret
4
+ * movement does at the ends of a bold: the first step goes into the element (or out of it), where the cursor looks the
5
+ * same, the next one moves in the text. `a[]<b>bc</b>` is `a<b>[]bc</b>`, then `a<b>b[]c</b>`. The browser would move by
6
+ * a character at once, and the positions on both sides of the end of an element would be out of reach.
7
+ *
8
+ * What is typed then goes where the cursor is. The listeners are the plugin's.
9
+ */
10
+ export declare function enableTwoStepCaretMovement(plugin: Plugin, names: ReadonlySet<string>): void;
11
+ //# sourceMappingURL=twoStepCaretMovement.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"twoStepCaretMovement.d.ts","sourceRoot":"","sources":["../../src/typing/twoStepCaretMovement.ts"],"names":[],"mappings":"AAAA,OAAO,EAON,KAAK,MAAM,EAGX,MAAM,WAAW,CAAC;AAEnB;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,IAAI,CA8C3F"}
@@ -0,0 +1,76 @@
1
+ import { isForwardArrowKeyCode, keyCodes } from 'ckeditor5';
2
+ /**
3
+ * Makes the left and right arrow keys move in two steps at the ends of inline elements, as CKEditor's two-step caret
4
+ * movement does at the ends of a bold: the first step goes into the element (or out of it), where the cursor looks the
5
+ * same, the next one moves in the text. `a[]<b>bc</b>` is `a<b>[]bc</b>`, then `a<b>b[]c</b>`. The browser would move by
6
+ * a character at once, and the positions on both sides of the end of an element would be out of reach.
7
+ *
8
+ * What is typed then goes where the cursor is. The listeners are the plugin's.
9
+ */
10
+ export function enableTwoStepCaretMovement(plugin, names) {
11
+ const editor = plugin.editor;
12
+ const viewDocument = editor.editing.view.document;
13
+ const isElement = (node) => !!node?.is('element') && names.has(node.name);
14
+ // Before the other features: e.g. `ElementSelectable` selects an inline object that the cursor reaches, and it may
15
+ // be just after the end of an element.
16
+ plugin.listenTo(viewDocument, 'keydown', (evt, data) => {
17
+ const isPlain = !data.shiftKey && !data.ctrlKey && !data.altKey && !data.metaKey;
18
+ const isHorizontal = data.keyCode === keyCodes.arrowleft || data.keyCode === keyCodes.arrowright;
19
+ const isForward = isForwardArrowKeyCode(data.keyCode, editor.locale.contentLanguageDirection);
20
+ const position = isPlain && isHorizontal ? getStep(editor, isForward, isElement) : null;
21
+ if (position) {
22
+ editor.model.change(writer => {
23
+ writer.setSelection(position);
24
+ });
25
+ data.preventDefault();
26
+ evt.stop();
27
+ }
28
+ }, { priority: 'highest' });
29
+ // The browser types at a place of its own at an end of an element, e.g. at the end of the text before it, whichever
30
+ // side of the end the cursor is on. When that place differs from the cursor only by ends of elements, the text goes
31
+ // where the cursor is: at the view selection, which is the model one. The browser must not type it at its place, as
32
+ // CKEditor does for a fake selection; a composition is left to the browser.
33
+ plugin.listenTo(viewDocument, 'insertText', (evt, data) => {
34
+ const target = data.selection?.rangeCount === 1 ? data.selection.getFirstRange() : null;
35
+ const position = target?.isCollapsed ? editor.editing.mapper.toModelPosition(target.start) : null;
36
+ if (position && !data.isComposing && isAtCursor(editor, position, isElement)) {
37
+ data.selection = viewDocument.selection;
38
+ data.preventDefault();
39
+ }
40
+ }, { priority: 'high' });
41
+ }
42
+ /**
43
+ * Returns where the cursor goes with one step in the direction, when it is at an end of an element: into the element
44
+ * next to it, or out of the element it is in. `null` elsewhere, or for a selection that is not collapsed.
45
+ */
46
+ function getStep(editor, isForward, isElement) {
47
+ const model = editor.model;
48
+ const selection = model.document.selection;
49
+ const position = selection.getFirstPosition();
50
+ if (!selection.isCollapsed || !position) {
51
+ return null;
52
+ }
53
+ const next = isForward ? position.nodeAfter : position.nodeBefore;
54
+ if (isElement(next)) {
55
+ return model.createPositionAt(next, isForward ? 0 : 'end');
56
+ }
57
+ if ((isForward ? position.isAtEnd : position.isAtStart) && isElement(position.parent)) {
58
+ return isForward ? model.createPositionAfter(position.parent) : model.createPositionBefore(position.parent);
59
+ }
60
+ return null;
61
+ }
62
+ /**
63
+ * Whether a position differs from the cursor only by ends of elements: `a[]<b>c</b>` and `a<b>[]c</b>` look the same.
64
+ */
65
+ function isAtCursor(editor, position, isElement) {
66
+ const model = editor.model;
67
+ const selection = model.document.selection;
68
+ const cursor = selection.getFirstPosition();
69
+ // Where the cursor is exactly, the browser types as usual.
70
+ if (!selection.isCollapsed || !cursor || cursor.isEqual(position)) {
71
+ return false;
72
+ }
73
+ const range = cursor.isBefore(position) ? model.createRange(cursor, position) : model.createRange(position, cursor);
74
+ return Array.from(range.getWalker()).every(({ item }) => item.is('element') && isElement(item));
75
+ }
76
+ //# sourceMappingURL=twoStepCaretMovement.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"twoStepCaretMovement.js","sourceRoot":"","sources":["../../src/typing/twoStepCaretMovement.ts"],"names":[],"mappings":"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"}
@@ -5,8 +5,8 @@
5
5
  *
6
6
  * @module ckeditor5-elements-schema/validate
7
7
  */
8
- export { validateElementSchema } from './validateElementSchema.js';
9
- export { compileElementSchema, type CompiledElementSchema } from './compileElementSchema.js';
10
- export { default as ElementSchemaError } from './elementSchemaError.js';
11
- export type { ElementSchemaDefinition, ElementSchemaElement, ElementSchemaInput, ElementSchemaIssue, ElementSchemaKind, ElementSchemaType, ValidateElementSchemaOptions } from './types.js';
8
+ export { validateElementSchema } from './definition/validateElementSchema.js';
9
+ export { compileElementSchema, type CompiledElementSchema } from './definition/compileElementSchema.js';
10
+ export { default as ElementSchemaError } from './definition/elementSchemaError.js';
11
+ export type { ElementSchemaDefinition, ElementSchemaElement, ElementSchemaInput, ElementSchemaIssue, ElementSchemaKind, ElementSchemaType, ValidateElementSchemaOptions } from './definition/types.js';
12
12
  //# sourceMappingURL=validate.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,KAAK,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAC7F,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AACxE,YAAY,EACX,uBAAuB,EACvB,oBAAoB,EACpB,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,EACjB,4BAA4B,EAC5B,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAC;AAC9E,OAAO,EAAE,oBAAoB,EAAE,KAAK,qBAAqB,EAAE,MAAM,sCAAsC,CAAC;AACxG,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AACnF,YAAY,EACX,uBAAuB,EACvB,oBAAoB,EACpB,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,EACjB,4BAA4B,EAC5B,MAAM,uBAAuB,CAAC"}
package/dist/validate.js CHANGED
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * @module ckeditor5-elements-schema/validate
7
7
  */
8
- export { validateElementSchema } from './validateElementSchema.js';
9
- export { compileElementSchema } from './compileElementSchema.js';
10
- export { default as ElementSchemaError } from './elementSchemaError.js';
8
+ export { validateElementSchema } from './definition/validateElementSchema.js';
9
+ export { compileElementSchema } from './definition/compileElementSchema.js';
10
+ export { default as ElementSchemaError } from './definition/elementSchemaError.js';
11
11
  //# sourceMappingURL=validate.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"validate.js","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAA8B,MAAM,2BAA2B,CAAC;AAC7F,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,yBAAyB,CAAC"}
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAC;AAC9E,OAAO,EAAE,oBAAoB,EAA8B,MAAM,sCAAsC,CAAC;AACxG,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,oCAAoC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ckeditor5-elements-schema",
3
- "version": "49.0.0-alpha.2",
3
+ "version": "49.0.0-alpha.4",
4
4
  "description": "Element schema for CKEditor 5: declare elements in the model schema from a simple definition, e.g. a JSON file, with three types of elements and a validation.",
5
5
  "keywords": [
6
6
  "ckeditor",
@@ -41,7 +41,7 @@
41
41
  ],
42
42
  "sideEffects": false,
43
43
  "dependencies": {
44
- "ckeditor5-elements-core": "49.0.0-alpha.2"
44
+ "ckeditor5-elements-core": "49.0.0-alpha.4"
45
45
  },
46
46
  "peerDependencies": {
47
47
  "ckeditor5": "^49.0.0"
@@ -1,8 +1,9 @@
1
- import type { ElementSchema, ElementSchemaInput } from './index.js';
1
+ import type { ElementSchema, ElementSchemaCommands, ElementSchemaCommandsConfig, ElementSchemaInput } from './index.js';
2
2
 
3
3
  declare module 'ckeditor5' {
4
4
  interface PluginsMap {
5
5
  [ElementSchema.pluginName]: ElementSchema;
6
+ [ElementSchemaCommands.pluginName]: ElementSchemaCommands;
6
7
  }
7
8
 
8
9
  interface EditorConfig {
@@ -17,5 +18,11 @@ declare module 'ckeditor5' {
17
18
  * element sets another tag for the editing view. See {@link ElementSchema}. Default: `false`.
18
19
  */
19
20
  elementSchemaConverters?: boolean;
21
+
22
+ /**
23
+ * The commands and the buttons of elements of the schema, as CKEditor's bold, heading, block quote or horizontal
24
+ * line, by the name of the command. See {@link ElementSchemaCommands}.
25
+ */
26
+ elementSchemaCommands?: ElementSchemaCommandsConfig;
20
27
  }
21
28
  }
@@ -0,0 +1,87 @@
1
+ import type { ModelElement } from 'ckeditor5';
2
+ import type { ElementOrPosition } from 'ckeditor5-elements-core';
3
+ import ElementSchemaCommand from './elementSchemaCommand.js';
4
+
5
+ /**
6
+ * Turns blocks into the element, as CKEditor's heading command does, e.g. a `title` that is a `block` of the element
7
+ * schema: the selected blocks, or the block of the target, are renamed, and keep their content.
8
+ *
9
+ * ```ts
10
+ * editor.execute('title'); // The blocks of the selection.
11
+ * editor.commands.get('title').executeFor(paragraph);
12
+ * ```
13
+ *
14
+ * When all the blocks are the element already, it turns them back into paragraphs (the {@link defaultElement}). The
15
+ * blocks that cannot be renamed, e.g. where the element is not allowed, are left as they are.
16
+ *
17
+ * It is "on" when all the blocks are the element.
18
+ */
19
+ export default class ElementBlockCommand extends ElementSchemaCommand {
20
+ public override isToggleable = true;
21
+
22
+ /**
23
+ * The element the blocks are turned back into.
24
+ */
25
+ public defaultElement = 'paragraph';
26
+
27
+ /**
28
+ * Renames the blocks of the target: to the element, or back to the {@link defaultElement} when they are all the
29
+ * element.
30
+ */
31
+ public override execute(elementOrPosition?: ElementOrPosition): void {
32
+ const name = this._getNewName(elementOrPosition);
33
+ const schema = this.editor.model.schema;
34
+
35
+ this.editor.model.change(writer => {
36
+ for (const block of this._getBlocks(elementOrPosition)) {
37
+ if (this._canRename(block, name)) {
38
+ writer.rename(block, name);
39
+ schema.removeDisallowedAttributes([block], writer);
40
+ }
41
+ }
42
+ });
43
+ }
44
+
45
+ /**
46
+ * Enabled when the target can be edited, and one of its blocks can be renamed.
47
+ */
48
+ protected override _isEnabledFor(elementOrPosition?: ElementOrPosition): boolean {
49
+ const name = this._getNewName(elementOrPosition);
50
+
51
+ return (
52
+ super._isEnabledFor(elementOrPosition) &&
53
+ this._getBlocks(elementOrPosition).some(block => this._canRename(block, name))
54
+ );
55
+ }
56
+
57
+ /**
58
+ * "On" when all the blocks of the target are the element.
59
+ */
60
+ protected override _isOnFor(elementOrPosition?: ElementOrPosition): boolean {
61
+ const blocks = this._getBlocks(elementOrPosition);
62
+
63
+ return blocks.length > 0 && blocks.every(block => this.isElement(block));
64
+ }
65
+
66
+ /**
67
+ * Returns the name the blocks get: the element, or the {@link defaultElement} when they are the element already.
68
+ */
69
+ private _getNewName(elementOrPosition?: ElementOrPosition): string {
70
+ return this._isOnFor(elementOrPosition) ? this.defaultElement : this.elementName;
71
+ }
72
+
73
+ /**
74
+ * Whether a block can be renamed: it is not an object, nor the name already, and the schema allows it with its
75
+ * content.
76
+ */
77
+ private _canRename(block: ModelElement, name: string): boolean {
78
+ const schema = this.editor.model.schema;
79
+
80
+ return (
81
+ block.name !== name &&
82
+ !schema.isObject(block) &&
83
+ schema.isRegistered(name) &&
84
+ this._canHold(this.editor.model.createPositionBefore(block), block.getChildren(), name)
85
+ );
86
+ }
87
+ }
@@ -0,0 +1,83 @@
1
+ import type { ModelElement, ModelRange } from 'ckeditor5';
2
+ import type { ElementOrPosition } from 'ckeditor5-elements-core';
3
+ import ElementSchemaCommand from './elementSchemaCommand.js';
4
+
5
+ /**
6
+ * Wraps blocks with the element, as CKEditor's block quote command does, e.g. a `callout` that is a `container` of the
7
+ * element schema: the selected blocks, or the block-level element of the target, go in a new element.
8
+ *
9
+ * ```ts
10
+ * editor.execute('callout'); // The blocks of the selection.
11
+ * editor.commands.get('callout').executeFor(paragraph);
12
+ * ```
13
+ *
14
+ * In the element, it unwraps it: the whole element, not only the selected blocks.
15
+ *
16
+ * It is "on" when the target is in the element.
17
+ */
18
+ export default class ElementContainerCommand extends ElementSchemaCommand {
19
+ public override isToggleable = true;
20
+
21
+ /**
22
+ * Unwraps the element the target is in, or wraps the blocks of the target with a new one.
23
+ */
24
+ public override execute(elementOrPosition?: ElementOrPosition): void {
25
+ const element = this._findElement(elementOrPosition);
26
+ const range = element ? null : this._getWrapRange(elementOrPosition);
27
+
28
+ this.editor.model.change(writer => {
29
+ if (element) {
30
+ writer.unwrap(element);
31
+ } else if (range) {
32
+ writer.wrap(range, this.elementName);
33
+ }
34
+ });
35
+ }
36
+
37
+ /**
38
+ * Enabled when the target can be edited, and the element it is in can be unwrapped, or its blocks can be wrapped.
39
+ */
40
+ protected override _isEnabledFor(elementOrPosition?: ElementOrPosition): boolean {
41
+ const element = this._findElement(elementOrPosition);
42
+
43
+ return (
44
+ super._isEnabledFor(elementOrPosition) &&
45
+ (element ? this._canUnwrap(element) : !!this._getWrapRange(elementOrPosition))
46
+ );
47
+ }
48
+
49
+ /**
50
+ * "On" when the target is in the element.
51
+ */
52
+ protected override _isOnFor(elementOrPosition?: ElementOrPosition): boolean {
53
+ return !!this._findElement(elementOrPosition);
54
+ }
55
+
56
+ /**
57
+ * Returns the range to wrap: from the first block of the target to the last, as siblings: the blocks themselves, or
58
+ * their ancestors in the parent they share. `null` when the schema does not allow the element there.
59
+ */
60
+ private _getWrapRange(elementOrPosition?: ElementOrPosition): ModelRange | null {
61
+ const model = this.editor.model;
62
+ const blocks = this._getBlocks(elementOrPosition);
63
+ const first = blocks[0] as ModelElement | undefined;
64
+ const last = blocks.at(-1);
65
+
66
+ if (!first || !last) {
67
+ return null;
68
+ }
69
+
70
+ const parent = first === last ? first.parent : first.getCommonAncestor(last);
71
+ const [start, end] = [first, last].map(block =>
72
+ block.getAncestors({ includeSelf: true }).find((node): node is ModelElement => node.parent === parent)
73
+ );
74
+
75
+ if (!start || !end) {
76
+ return null;
77
+ }
78
+
79
+ const range = model.createRange(model.createPositionBefore(start), model.createPositionAfter(end));
80
+
81
+ return this._canHold(range.start, range.getItems({ shallow: true })) ? range : null;
82
+ }
83
+ }