@ckeditor/ckeditor5-engine 47.2.0 → 47.3.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/LICENSE.md +4 -4
- package/dist/index.js +57 -8
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/engineconfig.d.ts +56 -0
- package/src/engineconfig.js +5 -0
- package/src/index.d.ts +1 -0
- package/src/index.js +0 -3
- package/src/model/model.d.ts +9 -2
- package/src/model/model.js +8 -1
- package/src/model/utils/insertcontent.js +50 -7
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ckeditor/ckeditor5-engine",
|
|
3
|
-
"version": "47.
|
|
3
|
+
"version": "47.3.0-alpha.1",
|
|
4
4
|
"description": "The editing engine of CKEditor 5 – the best browser-based rich text editor.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"wysiwyg",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"type": "module",
|
|
25
25
|
"main": "src/index.js",
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@ckeditor/ckeditor5-utils": "47.
|
|
27
|
+
"@ckeditor/ckeditor5-utils": "47.3.0-alpha.1",
|
|
28
28
|
"es-toolkit": "1.39.5"
|
|
29
29
|
},
|
|
30
30
|
"author": "CKSource (http://cksource.com/)",
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
|
+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* @module engine/engineconfig
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* CKEditor engine configuration options.
|
|
10
|
+
*
|
|
11
|
+
* This is a base class for {@link module:core/editor/editorconfig~EditorConfig `EditorConfig`}.
|
|
12
|
+
*/
|
|
13
|
+
export interface EngineConfig {
|
|
14
|
+
/**
|
|
15
|
+
* Enables specific experimental features in the editor for testing and feedback.
|
|
16
|
+
*/
|
|
17
|
+
experimentalFlags?: ExperimentalFlagsConfig;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* The `experimentalFlags` configuration option enables integrators to turn on specific experimental
|
|
21
|
+
* or pre-release features in CKEditor 5. These flags are primarily intended for testing and feedback purposes
|
|
22
|
+
* during the development of new functionality.
|
|
23
|
+
*
|
|
24
|
+
* Each key in the `experimentalFlags` object represents a unique experimental feature identifier.
|
|
25
|
+
* Setting the flag’s value to true activates the feature, while false (or absence of the key) keeps it disabled.
|
|
26
|
+
*
|
|
27
|
+
* Example
|
|
28
|
+
*
|
|
29
|
+
* ```ts
|
|
30
|
+
* EditorClass
|
|
31
|
+
* .create( {
|
|
32
|
+
* experimentalFlags: {
|
|
33
|
+
* modelInsertContentDeepSchemaVerification: true
|
|
34
|
+
* }
|
|
35
|
+
* } )
|
|
36
|
+
* .then( ... )
|
|
37
|
+
* .catch( ... );
|
|
38
|
+
* ```
|
|
39
|
+
*
|
|
40
|
+
* **Notes:**
|
|
41
|
+
* * Use with caution: Experimental features are not guaranteed to be stable and may change or be removed in future releases.
|
|
42
|
+
* * No compatibility guarantees: Their APIs, behavior, and configuration may change without notice.
|
|
43
|
+
* * Intended audience: This option is mainly for developers testing upcoming features, contributors, or early adopters
|
|
44
|
+
* evaluating new editor capabilities.
|
|
45
|
+
*/
|
|
46
|
+
export interface ExperimentalFlagsConfig {
|
|
47
|
+
/**
|
|
48
|
+
* When enabled, the editor performs deep schema verification during
|
|
49
|
+
* {@link module:engine/model/model~Model#insertContent `model.insertContent()`} operations.
|
|
50
|
+
* This ensures that all elements and attributes in the inserted content fully conform to the schema — not just
|
|
51
|
+
* at the top level — which helps identify structural inconsistencies early.
|
|
52
|
+
*
|
|
53
|
+
* This feature may impact performance on large inserts.
|
|
54
|
+
*/
|
|
55
|
+
modelInsertContentDeepSchemaVerification?: boolean;
|
|
56
|
+
}
|
package/src/index.d.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
/**
|
|
6
6
|
* @module engine
|
|
7
7
|
*/
|
|
8
|
+
export type { EngineConfig, ExperimentalFlagsConfig } from './engineconfig.js';
|
|
8
9
|
export { type PlaceholderableViewElement, disableViewPlaceholder, enableViewPlaceholder, hideViewPlaceholder, needsViewPlaceholder, showViewPlaceholder } from './view/placeholder.js';
|
|
9
10
|
export { EditingController } from './controller/editingcontroller.js';
|
|
10
11
|
export { DataController, type DataControllerInitEvent, type DataControllerSetEvent, type DataControllerToModelEvent, type DataControllerToViewEvent, type DataControllerReadyEvent, type DataControllerGetEvent } from './controller/datacontroller.js';
|
package/src/index.js
CHANGED
|
@@ -2,9 +2,6 @@
|
|
|
2
2
|
* @license Copyright (c) 2003-2025, 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
|
-
/**
|
|
6
|
-
* @module engine
|
|
7
|
-
*/
|
|
8
5
|
export { disableViewPlaceholder, enableViewPlaceholder, hideViewPlaceholder, needsViewPlaceholder, showViewPlaceholder } from './view/placeholder.js';
|
|
9
6
|
// Controller.
|
|
10
7
|
export { EditingController } from './controller/editingcontroller.js';
|
package/src/model/model.d.ts
CHANGED
|
@@ -19,7 +19,8 @@ import { type ModelDocumentFragment } from './documentfragment.js';
|
|
|
19
19
|
import { type ModelItem } from './item.js';
|
|
20
20
|
import { type ModelElement } from './element.js';
|
|
21
21
|
import { type Operation } from './operation/operation.js';
|
|
22
|
-
import { type DecoratedMethodEvent } from '@ckeditor/ckeditor5-utils';
|
|
22
|
+
import { type DecoratedMethodEvent, type Config } from '@ckeditor/ckeditor5-utils';
|
|
23
|
+
import type { EngineConfig } from '../engineconfig.js';
|
|
23
24
|
declare const Model_base: {
|
|
24
25
|
new (): import("@ckeditor/ckeditor5-utils").Observable;
|
|
25
26
|
prototype: import("@ckeditor/ckeditor5-utils").Observable;
|
|
@@ -41,6 +42,12 @@ export declare class Model extends /* #__PURE__ */ Model_base {
|
|
|
41
42
|
* Model's schema.
|
|
42
43
|
*/
|
|
43
44
|
readonly schema: ModelSchema;
|
|
45
|
+
/**
|
|
46
|
+
* Stores all configurations specific to editor instance.
|
|
47
|
+
*
|
|
48
|
+
* @internal
|
|
49
|
+
*/
|
|
50
|
+
readonly _config?: Config<EngineConfig>;
|
|
44
51
|
/**
|
|
45
52
|
* All callbacks added by {@link module:engine/model/model~Model#change} or
|
|
46
53
|
* {@link module:engine/model/model~Model#enqueueChange} methods waiting to be executed.
|
|
@@ -50,7 +57,7 @@ export declare class Model extends /* #__PURE__ */ Model_base {
|
|
|
50
57
|
* The last created and currently used writer instance.
|
|
51
58
|
*/
|
|
52
59
|
private _currentWriter;
|
|
53
|
-
constructor();
|
|
60
|
+
constructor(config?: Config<EngineConfig>);
|
|
54
61
|
/**
|
|
55
62
|
* The `change()` method is the primary way of changing the model. You should use it to modify all document nodes
|
|
56
63
|
* (including detached nodes – i.e. nodes not added to the {@link module:engine/model/model~Model#document model document}),
|
package/src/model/model.js
CHANGED
|
@@ -43,6 +43,12 @@ export class Model extends /* #__PURE__ */ ObservableMixin() {
|
|
|
43
43
|
* Model's schema.
|
|
44
44
|
*/
|
|
45
45
|
schema;
|
|
46
|
+
/**
|
|
47
|
+
* Stores all configurations specific to editor instance.
|
|
48
|
+
*
|
|
49
|
+
* @internal
|
|
50
|
+
*/
|
|
51
|
+
_config;
|
|
46
52
|
/**
|
|
47
53
|
* All callbacks added by {@link module:engine/model/model~Model#change} or
|
|
48
54
|
* {@link module:engine/model/model~Model#enqueueChange} methods waiting to be executed.
|
|
@@ -54,11 +60,12 @@ export class Model extends /* #__PURE__ */ ObservableMixin() {
|
|
|
54
60
|
_currentWriter;
|
|
55
61
|
// @if CK_DEBUG_ENGINE // private _operationLogs: Array<string>;
|
|
56
62
|
// @if CK_DEBUG_ENGINE // private _appliedOperations: Array<Operation>;
|
|
57
|
-
constructor() {
|
|
63
|
+
constructor(config) {
|
|
58
64
|
super();
|
|
59
65
|
this.markers = new MarkerCollection();
|
|
60
66
|
this.document = new ModelDocument(this);
|
|
61
67
|
this.schema = new ModelSchema();
|
|
68
|
+
this._config = config;
|
|
62
69
|
this._pendingChanges = [];
|
|
63
70
|
this._currentWriter = null;
|
|
64
71
|
['deleteContent', 'modifySelection', 'getSelectedContent', 'applyOperation']
|
|
@@ -234,9 +234,9 @@ class Insertion {
|
|
|
234
234
|
*/
|
|
235
235
|
_lastAutoParagraph = null;
|
|
236
236
|
/**
|
|
237
|
-
* The array of nodes that should be cleaned of not allowed attributes.
|
|
237
|
+
* The array of nodes that should be cleaned of not allowed attributes and sub-nodes.
|
|
238
238
|
*/
|
|
239
|
-
|
|
239
|
+
_filterAttributesAndChildrenOf = [];
|
|
240
240
|
/**
|
|
241
241
|
* Beginning of the affected range. See {@link module:engine/model/utils/insertcontent~Insertion#getAffectedRange}.
|
|
242
242
|
*/
|
|
@@ -277,8 +277,51 @@ class Insertion {
|
|
|
277
277
|
// Merging with the previous sibling was performed just after inserting the first node to the document.
|
|
278
278
|
this._mergeOnRight();
|
|
279
279
|
// TMP this will become a post-fixer.
|
|
280
|
-
this.schema.removeDisallowedAttributes(this.
|
|
281
|
-
this.
|
|
280
|
+
this.schema.removeDisallowedAttributes(this._filterAttributesAndChildrenOf, this.writer);
|
|
281
|
+
if (this.model._config?.get('experimentalFlags.modelInsertContentDeepSchemaVerification')) {
|
|
282
|
+
this._removeDisallowedChildren(this._filterAttributesAndChildrenOf);
|
|
283
|
+
}
|
|
284
|
+
this._filterAttributesAndChildrenOf = [];
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Removes disallowed children from nodes that were inserted or modified during insertion.
|
|
288
|
+
*/
|
|
289
|
+
_removeDisallowedChildren(nodes) {
|
|
290
|
+
// Make sure we do not modify the original iterable.
|
|
291
|
+
const nodesArray = Array.from(nodes);
|
|
292
|
+
// Check all sub-nodes of top level inserted nodes.
|
|
293
|
+
// We do it at this point so node is already in the model tree and schema checks will be correct.
|
|
294
|
+
for (const node of nodesArray) {
|
|
295
|
+
if (!node.is('element')) {
|
|
296
|
+
continue;
|
|
297
|
+
}
|
|
298
|
+
const remove = [];
|
|
299
|
+
const unwrap = [];
|
|
300
|
+
const walker = this.writer.createRangeIn(node).getWalker({ ignoreElementEnd: true });
|
|
301
|
+
for (const { item } of walker) {
|
|
302
|
+
const itemParent = item.parent;
|
|
303
|
+
if (!this.schema.checkChild(itemParent, item)) {
|
|
304
|
+
if (item.is('element') && !this.schema.isObject(item)) {
|
|
305
|
+
// Unwrap non-object element.
|
|
306
|
+
unwrap.push(item);
|
|
307
|
+
// Store the parent for re-checking children after unwrap.
|
|
308
|
+
nodesArray.push(itemParent);
|
|
309
|
+
}
|
|
310
|
+
else {
|
|
311
|
+
// Remove object with children, or text.
|
|
312
|
+
remove.push(item);
|
|
313
|
+
}
|
|
314
|
+
// Skip the whole subtree as it will be removed or processed later.
|
|
315
|
+
walker.jumpTo(this.writer.createPositionAfter(item));
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
for (const item of unwrap) {
|
|
319
|
+
this.writer.unwrap(item);
|
|
320
|
+
}
|
|
321
|
+
for (const item of remove) {
|
|
322
|
+
this.writer.remove(item);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
282
325
|
}
|
|
283
326
|
/**
|
|
284
327
|
* Updates the last node after the auto paragraphing.
|
|
@@ -423,7 +466,7 @@ class Insertion {
|
|
|
423
466
|
else {
|
|
424
467
|
this._nodeToSelect = null;
|
|
425
468
|
}
|
|
426
|
-
this.
|
|
469
|
+
this._filterAttributesAndChildrenOf.push(node);
|
|
427
470
|
return node;
|
|
428
471
|
}
|
|
429
472
|
/**
|
|
@@ -514,7 +557,7 @@ class Insertion {
|
|
|
514
557
|
livePosition.detach();
|
|
515
558
|
// After merge elements that were marked by _insert() to be filtered might be gone so
|
|
516
559
|
// we need to mark the new container.
|
|
517
|
-
this.
|
|
560
|
+
this._filterAttributesAndChildrenOf.push(this.position.parent);
|
|
518
561
|
mergePosLeft.detach();
|
|
519
562
|
}
|
|
520
563
|
/**
|
|
@@ -584,7 +627,7 @@ class Insertion {
|
|
|
584
627
|
livePosition.detach();
|
|
585
628
|
// After merge elements that were marked by _insert() to be filtered might be gone so
|
|
586
629
|
// we need to mark the new container.
|
|
587
|
-
this.
|
|
630
|
+
this._filterAttributesAndChildrenOf.push(this.position.parent);
|
|
588
631
|
mergePosRight.detach();
|
|
589
632
|
}
|
|
590
633
|
/**
|