@ckeditor/ckeditor5-enter 48.8.1-alpha.4 → 49.0.0-alpha.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/dist/augmentation.d.ts +13 -13
- package/dist/enter.d.ts +21 -21
- package/dist/entercommand.d.ts +44 -44
- package/dist/enterobserver.d.ts +34 -34
- package/dist/index-content.css +3 -0
- package/dist/index-content.css.map +1 -0
- package/dist/index-editor.css +3 -0
- package/dist/index-editor.css.map +1 -0
- package/dist/index.d.ts +12 -12
- package/dist/index.js +347 -393
- package/dist/index.js.map +1 -1
- package/dist/shiftenter.d.ts +19 -19
- package/dist/shiftentercommand.d.ts +26 -26
- package/dist/translations/af.js +1 -1
- package/dist/translations/af.umd.js +5 -3
- package/dist/translations/ar.js +1 -1
- package/dist/translations/ar.umd.js +5 -3
- package/dist/translations/ast.js +1 -1
- package/dist/translations/ast.umd.js +5 -3
- package/dist/translations/az.js +1 -1
- package/dist/translations/az.umd.js +5 -3
- package/dist/translations/be.js +1 -1
- package/dist/translations/be.umd.js +5 -3
- package/dist/translations/bg.js +1 -1
- package/dist/translations/bg.umd.js +5 -3
- package/dist/translations/bn.js +1 -1
- package/dist/translations/bn.umd.js +5 -3
- package/dist/translations/bs.js +1 -1
- package/dist/translations/bs.umd.js +5 -3
- package/dist/translations/ca.js +1 -1
- package/dist/translations/ca.umd.js +5 -3
- package/dist/translations/cs.js +1 -1
- package/dist/translations/cs.umd.js +5 -3
- package/dist/translations/da.js +1 -1
- package/dist/translations/da.umd.js +5 -3
- package/dist/translations/de-ch.js +1 -1
- package/dist/translations/de-ch.umd.js +5 -3
- package/dist/translations/de.js +1 -1
- package/dist/translations/de.umd.js +5 -3
- package/dist/translations/el.js +1 -1
- package/dist/translations/el.umd.js +5 -3
- package/dist/translations/en-au.js +1 -1
- package/dist/translations/en-au.umd.js +5 -3
- package/dist/translations/en-gb.js +1 -1
- package/dist/translations/en-gb.umd.js +5 -3
- package/dist/translations/en.js +1 -1
- package/dist/translations/en.umd.js +5 -3
- package/dist/translations/eo.js +1 -1
- package/dist/translations/eo.umd.js +5 -3
- package/dist/translations/es-co.js +1 -1
- package/dist/translations/es-co.umd.js +5 -3
- package/dist/translations/es.js +1 -1
- package/dist/translations/es.umd.js +5 -3
- package/dist/translations/et.js +1 -1
- package/dist/translations/et.umd.js +5 -3
- package/dist/translations/eu.js +1 -1
- package/dist/translations/eu.umd.js +5 -3
- package/dist/translations/fa.js +1 -1
- package/dist/translations/fa.umd.js +5 -3
- package/dist/translations/fi.js +1 -1
- package/dist/translations/fi.umd.js +5 -3
- package/dist/translations/fr.js +1 -1
- package/dist/translations/fr.umd.js +5 -3
- package/dist/translations/gl.js +1 -1
- package/dist/translations/gl.umd.js +5 -3
- package/dist/translations/gu.js +1 -1
- package/dist/translations/gu.umd.js +5 -3
- package/dist/translations/he.js +1 -1
- package/dist/translations/he.umd.js +5 -3
- package/dist/translations/hi.js +1 -1
- package/dist/translations/hi.umd.js +5 -3
- package/dist/translations/hr.js +1 -1
- package/dist/translations/hr.umd.js +5 -3
- package/dist/translations/hu.js +1 -1
- package/dist/translations/hu.umd.js +5 -3
- package/dist/translations/hy.js +1 -1
- package/dist/translations/hy.umd.js +5 -3
- package/dist/translations/id.js +1 -1
- package/dist/translations/id.umd.js +5 -3
- package/dist/translations/it.js +1 -1
- package/dist/translations/it.umd.js +5 -3
- package/dist/translations/ja.js +1 -1
- package/dist/translations/ja.umd.js +5 -3
- package/dist/translations/jv.js +1 -1
- package/dist/translations/jv.umd.js +5 -3
- package/dist/translations/kk.js +1 -1
- package/dist/translations/kk.umd.js +5 -3
- package/dist/translations/km.js +1 -1
- package/dist/translations/km.umd.js +5 -3
- package/dist/translations/kn.js +1 -1
- package/dist/translations/kn.umd.js +5 -3
- package/dist/translations/ko.js +1 -1
- package/dist/translations/ko.umd.js +5 -3
- package/dist/translations/ku.js +1 -1
- package/dist/translations/ku.umd.js +5 -3
- package/dist/translations/lt.js +1 -1
- package/dist/translations/lt.umd.js +5 -3
- package/dist/translations/lv.js +1 -1
- package/dist/translations/lv.umd.js +5 -3
- package/dist/translations/ms.js +1 -1
- package/dist/translations/ms.umd.js +5 -3
- package/dist/translations/nb.js +1 -1
- package/dist/translations/nb.umd.js +5 -3
- package/dist/translations/ne.js +1 -1
- package/dist/translations/ne.umd.js +5 -3
- package/dist/translations/nl.js +1 -1
- package/dist/translations/nl.umd.js +5 -3
- package/dist/translations/no.js +1 -1
- package/dist/translations/no.umd.js +5 -3
- package/dist/translations/oc.js +1 -1
- package/dist/translations/oc.umd.js +5 -3
- package/dist/translations/pl.js +1 -1
- package/dist/translations/pl.umd.js +5 -3
- package/dist/translations/pt-br.js +1 -1
- package/dist/translations/pt-br.umd.js +5 -3
- package/dist/translations/pt.js +1 -1
- package/dist/translations/pt.umd.js +5 -3
- package/dist/translations/ro.js +1 -1
- package/dist/translations/ro.umd.js +5 -3
- package/dist/translations/ru.js +1 -1
- package/dist/translations/ru.umd.js +5 -3
- package/dist/translations/si.js +1 -1
- package/dist/translations/si.umd.js +5 -3
- package/dist/translations/sk.js +1 -1
- package/dist/translations/sk.umd.js +5 -3
- package/dist/translations/sl.js +1 -1
- package/dist/translations/sl.umd.js +5 -3
- package/dist/translations/sq.js +1 -1
- package/dist/translations/sq.umd.js +5 -3
- package/dist/translations/sr-latn.js +1 -1
- package/dist/translations/sr-latn.umd.js +5 -3
- package/dist/translations/sr.js +1 -1
- package/dist/translations/sr.umd.js +5 -3
- package/dist/translations/sv.js +1 -1
- package/dist/translations/sv.umd.js +5 -3
- package/dist/translations/th.js +1 -1
- package/dist/translations/th.umd.js +5 -3
- package/dist/translations/ti.js +1 -1
- package/dist/translations/ti.umd.js +5 -3
- package/dist/translations/tk.js +1 -1
- package/dist/translations/tk.umd.js +5 -3
- package/dist/translations/tr.js +1 -1
- package/dist/translations/tr.umd.js +5 -3
- package/dist/translations/tt.js +1 -1
- package/dist/translations/tt.umd.js +5 -3
- package/dist/translations/ug.js +1 -1
- package/dist/translations/ug.umd.js +5 -3
- package/dist/translations/uk.js +1 -1
- package/dist/translations/uk.umd.js +5 -3
- package/dist/translations/ur.js +1 -1
- package/dist/translations/ur.umd.js +5 -3
- package/dist/translations/uz.js +1 -1
- package/dist/translations/uz.umd.js +5 -3
- package/dist/translations/vi.js +1 -1
- package/dist/translations/vi.umd.js +5 -3
- package/dist/translations/zh-cn.js +1 -1
- package/dist/translations/zh-cn.umd.js +5 -3
- package/dist/translations/zh.js +1 -1
- package/dist/translations/zh.umd.js +5 -3
- package/dist/utils.d.ts +15 -15
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -2,427 +2,381 @@
|
|
|
2
2
|
* @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
3
|
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
|
|
4
4
|
*/
|
|
5
|
-
import { Command, Plugin } from
|
|
6
|
-
import {
|
|
7
|
-
import { env } from
|
|
5
|
+
import { Command, Plugin } from "@ckeditor/ckeditor5-core";
|
|
6
|
+
import { BubblingEventInfo, Observer, ViewDocumentDomEventData } from "@ckeditor/ckeditor5-engine";
|
|
7
|
+
import { env } from "@ckeditor/ckeditor5-utils";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
if (attribute && schema.getAttributeProperties(attribute[0]).copyOnEnter) {
|
|
26
|
-
yield attribute;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
10
|
+
* @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
|
|
11
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Returns attributes that should be preserved on the enter keystroke.
|
|
15
|
+
*
|
|
16
|
+
* Filtering is realized based on `copyOnEnter` attribute property. Read more about attribute properties
|
|
17
|
+
* {@link module:engine/model/schema~ModelSchema#setAttributeProperties here}.
|
|
18
|
+
*
|
|
19
|
+
* @param schema Model's schema.
|
|
20
|
+
* @param allAttributes Attributes to filter.
|
|
21
|
+
* @internal
|
|
22
|
+
*/
|
|
23
|
+
function* getCopyOnEnterAttributes(schema, allAttributes) {
|
|
24
|
+
for (const attribute of allAttributes) if (attribute && schema.getAttributeProperties(attribute[0]).copyOnEnter) yield attribute;
|
|
29
25
|
}
|
|
30
26
|
|
|
31
27
|
/**
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
return false;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
28
|
+
* @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
|
|
29
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
|
|
30
|
+
*/
|
|
31
|
+
/**
|
|
32
|
+
* @module enter/entercommand
|
|
33
|
+
*/
|
|
34
|
+
/**
|
|
35
|
+
* Enter command used by the {@link module:enter/enter~Enter Enter feature} to handle the <kbd>Enter</kbd> keystroke.
|
|
36
|
+
*/
|
|
37
|
+
var EnterCommand = class extends Command {
|
|
38
|
+
/**
|
|
39
|
+
* @inheritDoc
|
|
40
|
+
*/
|
|
41
|
+
execute() {
|
|
42
|
+
this.editor.model.change((writer) => {
|
|
43
|
+
this.enterBlock(writer);
|
|
44
|
+
this.fire("afterExecute", { writer });
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Splits a block where the document selection is placed, in the way how the <kbd>Enter</kbd> key is expected to work:
|
|
49
|
+
*
|
|
50
|
+
* ```
|
|
51
|
+
* <p>Foo[]bar</p> -> <p>Foo</p><p>[]bar</p>
|
|
52
|
+
* <p>Foobar[]</p> -> <p>Foobar</p><p>[]</p>
|
|
53
|
+
* <p>Fo[ob]ar</p> -> <p>Fo</p><p>[]ar</p>
|
|
54
|
+
* ```
|
|
55
|
+
*
|
|
56
|
+
* In some cases, the split will not happen:
|
|
57
|
+
*
|
|
58
|
+
* ```
|
|
59
|
+
* // The selection parent is a limit element:
|
|
60
|
+
* <figcaption>A[bc]d</figcaption> -> <figcaption>A[]d</figcaption>
|
|
61
|
+
*
|
|
62
|
+
* // The selection spans over multiple elements:
|
|
63
|
+
* <h>x[x</h><p>y]y<p> -> <h>x</h><p>[]y</p>
|
|
64
|
+
* ```
|
|
65
|
+
*
|
|
66
|
+
* @param writer Writer to use when performing the enter action.
|
|
67
|
+
* @returns Boolean indicating if the block was split.
|
|
68
|
+
*/
|
|
69
|
+
enterBlock(writer) {
|
|
70
|
+
const model = this.editor.model;
|
|
71
|
+
const selection = model.document.selection;
|
|
72
|
+
const schema = model.schema;
|
|
73
|
+
const isSelectionEmpty = selection.isCollapsed;
|
|
74
|
+
const range = selection.getFirstRange();
|
|
75
|
+
const startElement = range.start.parent;
|
|
76
|
+
const endElement = range.end.parent;
|
|
77
|
+
if (schema.isLimit(startElement) || schema.isLimit(endElement)) {
|
|
78
|
+
if (!isSelectionEmpty && startElement == endElement) model.deleteContent(selection);
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
if (isSelectionEmpty) {
|
|
82
|
+
const attributesToCopy = getCopyOnEnterAttributes(writer.model.schema, selection.getAttributes());
|
|
83
|
+
splitBlock(writer, range.start);
|
|
84
|
+
writer.setSelectionAttribute(attributesToCopy);
|
|
85
|
+
return true;
|
|
86
|
+
} else {
|
|
87
|
+
const leaveUnmerged = !(range.start.isAtStart && range.end.isAtEnd);
|
|
88
|
+
const isContainedWithinOneElement = startElement == endElement;
|
|
89
|
+
model.deleteContent(selection, { leaveUnmerged });
|
|
90
|
+
if (leaveUnmerged) {
|
|
91
|
+
if (isContainedWithinOneElement) {
|
|
92
|
+
splitBlock(writer, selection.focus);
|
|
93
|
+
return true;
|
|
94
|
+
} else writer.setSelection(endElement, 0);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
};
|
|
110
100
|
function splitBlock(writer, splitPos) {
|
|
111
|
-
|
|
112
|
-
|
|
101
|
+
writer.split(splitPos);
|
|
102
|
+
writer.setSelection(splitPos.parent.nextSibling, 0);
|
|
113
103
|
}
|
|
114
104
|
|
|
105
|
+
/**
|
|
106
|
+
* @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
|
|
107
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
|
|
108
|
+
*/
|
|
109
|
+
/**
|
|
110
|
+
* @module enter/enterobserver
|
|
111
|
+
*/
|
|
115
112
|
const ENTER_EVENT_TYPES = {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
},
|
|
119
|
-
insertLineBreak: {
|
|
120
|
-
isSoft: true
|
|
121
|
-
}
|
|
113
|
+
insertParagraph: { isSoft: false },
|
|
114
|
+
insertLineBreak: { isSoft: true }
|
|
122
115
|
};
|
|
123
116
|
/**
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
});
|
|
159
|
-
}
|
|
160
|
-
/**
|
|
161
|
-
* @inheritDoc
|
|
162
|
-
*/ observe() {}
|
|
163
|
-
/**
|
|
164
|
-
* @inheritDoc
|
|
165
|
-
*/ stopObserving() {}
|
|
166
|
-
}
|
|
117
|
+
* Enter observer introduces the {@link module:engine/view/document~ViewDocument#event:enter `Document#enter`} event.
|
|
118
|
+
*/
|
|
119
|
+
var EnterObserver = class extends Observer {
|
|
120
|
+
/**
|
|
121
|
+
* @inheritDoc
|
|
122
|
+
*/
|
|
123
|
+
constructor(view) {
|
|
124
|
+
super(view);
|
|
125
|
+
const doc = this.document;
|
|
126
|
+
let shiftPressed = false;
|
|
127
|
+
doc.on("keydown", (evt, data) => {
|
|
128
|
+
shiftPressed = data.shiftKey;
|
|
129
|
+
});
|
|
130
|
+
doc.on("beforeinput", (evt, data) => {
|
|
131
|
+
if (!this.isEnabled) return;
|
|
132
|
+
let inputType = data.inputType;
|
|
133
|
+
if (env.isSafari && shiftPressed && inputType == "insertParagraph") inputType = "insertLineBreak";
|
|
134
|
+
const domEvent = data.domEvent;
|
|
135
|
+
const enterEventSpec = ENTER_EVENT_TYPES[inputType];
|
|
136
|
+
if (!enterEventSpec) return;
|
|
137
|
+
const event = new BubblingEventInfo(doc, "enter", data.targetRanges[0]);
|
|
138
|
+
doc.fire(event, new ViewDocumentDomEventData(view, domEvent, { isSoft: enterEventSpec.isSoft }));
|
|
139
|
+
if (event.stop.called) evt.stop();
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* @inheritDoc
|
|
144
|
+
*/
|
|
145
|
+
observe() {}
|
|
146
|
+
/**
|
|
147
|
+
* @inheritDoc
|
|
148
|
+
*/
|
|
149
|
+
stopObserving() {}
|
|
150
|
+
};
|
|
167
151
|
|
|
168
152
|
/**
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
]
|
|
215
|
-
});
|
|
216
|
-
}
|
|
217
|
-
}
|
|
153
|
+
* @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
|
|
154
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
|
|
155
|
+
*/
|
|
156
|
+
/**
|
|
157
|
+
* @module enter/enter
|
|
158
|
+
*/
|
|
159
|
+
/**
|
|
160
|
+
* This plugin handles the <kbd>Enter</kbd> keystroke (hard line break) in the editor.
|
|
161
|
+
*
|
|
162
|
+
* See also the {@link module:enter/shiftenter~ShiftEnter} plugin.
|
|
163
|
+
*
|
|
164
|
+
* For more information about this feature see the {@glink api/enter package page}.
|
|
165
|
+
*/
|
|
166
|
+
var Enter = class extends Plugin {
|
|
167
|
+
/**
|
|
168
|
+
* @inheritDoc
|
|
169
|
+
*/
|
|
170
|
+
static get pluginName() {
|
|
171
|
+
return "Enter";
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* @inheritDoc
|
|
175
|
+
*/
|
|
176
|
+
static get isOfficialPlugin() {
|
|
177
|
+
return true;
|
|
178
|
+
}
|
|
179
|
+
init() {
|
|
180
|
+
const editor = this.editor;
|
|
181
|
+
const view = editor.editing.view;
|
|
182
|
+
const viewDocument = view.document;
|
|
183
|
+
const t = this.editor.t;
|
|
184
|
+
view.addObserver(EnterObserver);
|
|
185
|
+
editor.commands.add("enter", new EnterCommand(editor));
|
|
186
|
+
this.listenTo(viewDocument, "enter", (evt, data) => {
|
|
187
|
+
if (!viewDocument.isComposing) data.preventDefault();
|
|
188
|
+
if (data.isSoft) return;
|
|
189
|
+
editor.execute("enter");
|
|
190
|
+
view.scrollToTheSelection();
|
|
191
|
+
}, { priority: "low" });
|
|
192
|
+
editor.accessibility.addKeystrokeInfos({ keystrokes: [{
|
|
193
|
+
label: t("Insert a hard break (a new paragraph)"),
|
|
194
|
+
keystroke: "Enter"
|
|
195
|
+
}] });
|
|
196
|
+
}
|
|
197
|
+
};
|
|
218
198
|
|
|
219
199
|
/**
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
200
|
+
* @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
|
|
201
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
|
|
202
|
+
*/
|
|
203
|
+
/**
|
|
204
|
+
* @module enter/shiftentercommand
|
|
205
|
+
*/
|
|
206
|
+
/**
|
|
207
|
+
* ShiftEnter command. It is used by the {@link module:enter/shiftenter~ShiftEnter ShiftEnter feature} to handle
|
|
208
|
+
* the <kbd>Shift</kbd>+<kbd>Enter</kbd> keystroke.
|
|
209
|
+
*/
|
|
210
|
+
var ShiftEnterCommand = class extends Command {
|
|
211
|
+
/**
|
|
212
|
+
* @inheritDoc
|
|
213
|
+
*/
|
|
214
|
+
execute() {
|
|
215
|
+
const model = this.editor.model;
|
|
216
|
+
const doc = model.document;
|
|
217
|
+
model.change((writer) => {
|
|
218
|
+
softBreakAction(model, writer, doc.selection);
|
|
219
|
+
this.fire("afterExecute", { writer });
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* @inheritDoc
|
|
224
|
+
*/
|
|
225
|
+
refresh() {
|
|
226
|
+
const model = this.editor.model;
|
|
227
|
+
const doc = model.document;
|
|
228
|
+
this.isEnabled = isEnabled(model.schema, doc.selection);
|
|
229
|
+
}
|
|
230
|
+
};
|
|
243
231
|
/**
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
}
|
|
256
|
-
const range = selection.getFirstRange();
|
|
257
|
-
const startElement = range.start.parent;
|
|
258
|
-
const endElement = range.end.parent;
|
|
259
|
-
// Do not modify the content if selection is cross-limit elements.
|
|
260
|
-
if ((isInsideLimitElement(startElement, schema) || isInsideLimitElement(endElement, schema)) && startElement !== endElement) {
|
|
261
|
-
return false;
|
|
262
|
-
}
|
|
263
|
-
return true;
|
|
232
|
+
* Checks whether the ShiftEnter command should be enabled in the specified selection.
|
|
233
|
+
*/
|
|
234
|
+
function isEnabled(schema, selection) {
|
|
235
|
+
if (selection.rangeCount > 1) return false;
|
|
236
|
+
const anchorPos = selection.anchor;
|
|
237
|
+
if (!anchorPos || !schema.checkChild(anchorPos, "softBreak")) return false;
|
|
238
|
+
const range = selection.getFirstRange();
|
|
239
|
+
const startElement = range.start.parent;
|
|
240
|
+
const endElement = range.end.parent;
|
|
241
|
+
if ((isInsideLimitElement(startElement, schema) || isInsideLimitElement(endElement, schema)) && startElement !== endElement) return false;
|
|
242
|
+
return true;
|
|
264
243
|
}
|
|
265
244
|
/**
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
//
|
|
282
|
-
// <h>x[xx]x</h> -> <h>x^x</h> -> <h>x<br>^x</h>
|
|
283
|
-
if (isContainedWithinOneElement) {
|
|
284
|
-
insertBreak(model, writer, selection.focus, selection.getAttributes());
|
|
285
|
-
} else {
|
|
286
|
-
// Move the selection to the 2nd element (last step of the example above).
|
|
287
|
-
if (leaveUnmerged) {
|
|
288
|
-
writer.setSelection(endElement, 0);
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
}
|
|
245
|
+
* Creates a break in the way that the <kbd>Shift</kbd>+<kbd>Enter</kbd> keystroke is expected to work.
|
|
246
|
+
*/
|
|
247
|
+
function softBreakAction(model, writer, selection) {
|
|
248
|
+
const isSelectionEmpty = selection.isCollapsed;
|
|
249
|
+
const range = selection.getFirstRange();
|
|
250
|
+
const startElement = range.start.parent;
|
|
251
|
+
const endElement = range.end.parent;
|
|
252
|
+
const isContainedWithinOneElement = startElement == endElement;
|
|
253
|
+
if (isSelectionEmpty) insertBreak(model, writer, range.end, selection.getAttributes());
|
|
254
|
+
else {
|
|
255
|
+
const leaveUnmerged = !(range.start.isAtStart && range.end.isAtEnd);
|
|
256
|
+
model.deleteContent(selection, { leaveUnmerged });
|
|
257
|
+
if (isContainedWithinOneElement) insertBreak(model, writer, selection.focus, selection.getAttributes());
|
|
258
|
+
else if (leaveUnmerged) writer.setSelection(endElement, 0);
|
|
259
|
+
}
|
|
292
260
|
}
|
|
293
261
|
/**
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
262
|
+
* Inserts a softBreak with applicable attributes.
|
|
263
|
+
*/
|
|
264
|
+
function insertBreak(model, writer, position, selectionAttributes) {
|
|
265
|
+
const attributes = Array.from(getCopyOnEnterAttributes(model.schema, selectionAttributes));
|
|
266
|
+
const breakLineElement = writer.createElement("softBreak", attributes);
|
|
267
|
+
model.insertContent(breakLineElement, position);
|
|
268
|
+
writer.setSelection(breakLineElement, "after");
|
|
300
269
|
}
|
|
301
270
|
/**
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
}
|
|
312
|
-
return schema.isLimit(element) || isInsideLimitElement(element.parent, schema);
|
|
271
|
+
* Checks whether the specified `element` is a child of the limit element.
|
|
272
|
+
*
|
|
273
|
+
* Checking whether the `<p>` element is inside a limit element:
|
|
274
|
+
* - `<$root><p>Text.</p></$root> => false`
|
|
275
|
+
* - `<$root><limitElement><p>Text</p></limitElement></$root> => true`
|
|
276
|
+
*/
|
|
277
|
+
function isInsideLimitElement(element, schema) {
|
|
278
|
+
if (element.is("rootElement")) return false;
|
|
279
|
+
return schema.isLimit(element) || isInsideLimitElement(element.parent, schema);
|
|
313
280
|
}
|
|
314
281
|
|
|
315
282
|
/**
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
keystroke: 'Shift+Enter'
|
|
378
|
-
}
|
|
379
|
-
]
|
|
380
|
-
});
|
|
381
|
-
}
|
|
382
|
-
}
|
|
283
|
+
* @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
|
|
284
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
|
|
285
|
+
*/
|
|
286
|
+
/**
|
|
287
|
+
* @module enter/shiftenter
|
|
288
|
+
*/
|
|
289
|
+
/**
|
|
290
|
+
* This plugin handles the <kbd>Shift</kbd>+<kbd>Enter</kbd> keystroke (soft line break) in the editor.
|
|
291
|
+
*
|
|
292
|
+
* See also the {@link module:enter/enter~Enter} plugin.
|
|
293
|
+
*
|
|
294
|
+
* For more information about this feature see the {@glink api/enter package page}.
|
|
295
|
+
*/
|
|
296
|
+
var ShiftEnter = class extends Plugin {
|
|
297
|
+
/**
|
|
298
|
+
* @inheritDoc
|
|
299
|
+
*/
|
|
300
|
+
static get pluginName() {
|
|
301
|
+
return "ShiftEnter";
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* @inheritDoc
|
|
305
|
+
*/
|
|
306
|
+
static get isOfficialPlugin() {
|
|
307
|
+
return true;
|
|
308
|
+
}
|
|
309
|
+
init() {
|
|
310
|
+
const editor = this.editor;
|
|
311
|
+
const schema = editor.model.schema;
|
|
312
|
+
const conversion = editor.conversion;
|
|
313
|
+
const view = editor.editing.view;
|
|
314
|
+
const viewDocument = view.document;
|
|
315
|
+
const t = this.editor.t;
|
|
316
|
+
schema.register("softBreak", {
|
|
317
|
+
allowWhere: "$text",
|
|
318
|
+
allowAttributesOf: "$text",
|
|
319
|
+
isInline: true
|
|
320
|
+
});
|
|
321
|
+
conversion.for("upcast").elementToElement({
|
|
322
|
+
model: "softBreak",
|
|
323
|
+
view: "br"
|
|
324
|
+
});
|
|
325
|
+
conversion.for("downcast").elementToElement({
|
|
326
|
+
model: "softBreak",
|
|
327
|
+
view: (modelElement, { writer }) => writer.createEmptyElement("br")
|
|
328
|
+
});
|
|
329
|
+
view.addObserver(EnterObserver);
|
|
330
|
+
editor.commands.add("shiftEnter", new ShiftEnterCommand(editor));
|
|
331
|
+
editor.model.document.registerPostFixer((writer) => removeStaleSoftBreakAttributes(writer));
|
|
332
|
+
this.listenTo(viewDocument, "enter", (evt, data) => {
|
|
333
|
+
if (!viewDocument.isComposing) data.preventDefault();
|
|
334
|
+
if (!data.isSoft) return;
|
|
335
|
+
editor.execute("shiftEnter");
|
|
336
|
+
view.scrollToTheSelection();
|
|
337
|
+
}, { priority: "low" });
|
|
338
|
+
editor.accessibility.addKeystrokeInfos({ keystrokes: [{
|
|
339
|
+
label: t("Insert a soft break (a <code><br></code> element)"),
|
|
340
|
+
keystroke: "Shift+Enter"
|
|
341
|
+
}] });
|
|
342
|
+
}
|
|
343
|
+
};
|
|
383
344
|
/**
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
// Do not remove attributes when softBreak is the last element or there is some element after it.
|
|
408
|
-
if (!nextSibling || nextSibling.is('element')) {
|
|
409
|
-
continue;
|
|
410
|
-
}
|
|
411
|
-
// Remove the attribute if the next sibling does not have the same attribute.
|
|
412
|
-
const attributesToRemove = Array.from(child.getAttributes()).filter(([key, value])=>!hasSameAttribute(nextSibling, key, value));
|
|
413
|
-
for (const [key] of attributesToRemove){
|
|
414
|
-
writer.removeAttribute(key, child);
|
|
415
|
-
wasChanged = true;
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
return wasChanged;
|
|
345
|
+
* The post-fixer that removes attributes from stale soft-break elements.
|
|
346
|
+
*/
|
|
347
|
+
function removeStaleSoftBreakAttributes(writer) {
|
|
348
|
+
const parentsToCheck = /* @__PURE__ */ new Set();
|
|
349
|
+
for (const change of writer.model.document.differ.getChanges()) if (change.type == "insert" || change.type == "remove") {
|
|
350
|
+
/* v8 ignore else -- @preserve */
|
|
351
|
+
if (change.position.parent.is("element")) parentsToCheck.add(change.position.parent);
|
|
352
|
+
} else if (change.type == "attribute") {
|
|
353
|
+
/* v8 ignore else -- @preserve */
|
|
354
|
+
if (change.range.start.parent.is("element")) parentsToCheck.add(change.range.start.parent);
|
|
355
|
+
}
|
|
356
|
+
let wasChanged = false;
|
|
357
|
+
for (const parent of parentsToCheck) for (const child of parent.getChildren()) {
|
|
358
|
+
if (!child.is("element", "softBreak")) continue;
|
|
359
|
+
const nextSibling = child.nextSibling;
|
|
360
|
+
if (!nextSibling || nextSibling.is("element")) continue;
|
|
361
|
+
const attributesToRemove = Array.from(child.getAttributes()).filter(([key, value]) => !hasSameAttribute(nextSibling, key, value));
|
|
362
|
+
for (const [key] of attributesToRemove) {
|
|
363
|
+
writer.removeAttribute(key, child);
|
|
364
|
+
wasChanged = true;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
return wasChanged;
|
|
420
368
|
}
|
|
421
369
|
/**
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
370
|
+
* Returns `true` if the given node has the same attribute as the one provided in the parameters.
|
|
371
|
+
*/
|
|
372
|
+
function hasSameAttribute(node, key, value) {
|
|
373
|
+
return node?.getAttribute(key) === value;
|
|
425
374
|
}
|
|
426
375
|
|
|
376
|
+
/**
|
|
377
|
+
* @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
|
|
378
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
|
|
379
|
+
*/
|
|
380
|
+
|
|
427
381
|
export { Enter, EnterCommand, EnterObserver, ShiftEnter, ShiftEnterCommand, getCopyOnEnterAttributes as _getCopyOnEnterAttributes };
|
|
428
|
-
//# sourceMappingURL=index.js.map
|
|
382
|
+
//# sourceMappingURL=index.js.map
|