@ckeditor/ckeditor5-engine 39.0.2 → 40.1.0
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 +3 -3
- package/package.json +2 -2
- package/src/controller/datacontroller.d.ts +1 -1
- package/src/conversion/downcastdispatcher.js +1 -1
- package/src/conversion/downcasthelpers.js +5 -10
- package/src/conversion/upcastdispatcher.js +1 -1
- package/src/conversion/viewconsumable.js +6 -2
- package/src/dataprocessor/basichtmlwriter.js +2 -1
- package/src/index.d.ts +3 -3
- package/src/model/batch.d.ts +1 -1
- package/src/model/document.js +1 -2
- package/src/model/markercollection.d.ts +4 -4
- package/src/model/markercollection.js +4 -4
- package/src/model/operation/operation.d.ts +3 -3
- package/src/model/operation/operation.js +0 -3
- package/src/model/operation/transform.js +3 -3
- package/src/model/operation/utils.js +5 -1
- package/src/view/document.d.ts +2 -2
- package/src/view/document.js +3 -1
- package/src/view/documentfragment.d.ts +4 -0
- package/src/view/documentfragment.js +6 -0
- package/src/view/domconverter.d.ts +25 -13
- package/src/view/domconverter.js +71 -23
- package/src/view/downcastwriter.d.ts +1 -1
- package/src/view/element.d.ts +1 -1
- package/src/view/renderer.js +3 -2
- package/src/view/stylesmap.d.ts +1 -1
- package/src/view/stylesmap.js +4 -5
- package/src/view/uielement.js +2 -1
- package/src/view/view.d.ts +1 -1
package/LICENSE.md
CHANGED
|
@@ -2,7 +2,7 @@ Software License Agreement
|
|
|
2
2
|
==========================
|
|
3
3
|
|
|
4
4
|
**CKEditor 5 editing engine** – https://github.com/ckeditor/ckeditor5-engine <br>
|
|
5
|
-
Copyright (c) 2003
|
|
5
|
+
Copyright (c) 2003–2023, [CKSource Holding sp. z o.o.](https://cksource.com) All rights reserved.
|
|
6
6
|
|
|
7
7
|
Licensed under the terms of [GNU General Public License Version 2 or later](http://www.gnu.org/licenses/gpl.html).
|
|
8
8
|
|
|
@@ -13,9 +13,9 @@ Where not otherwise indicated, all CKEditor content is authored by CKSource engi
|
|
|
13
13
|
|
|
14
14
|
The following libraries are included in CKEditor under the [MIT license](https://opensource.org/licenses/MIT):
|
|
15
15
|
|
|
16
|
-
*
|
|
16
|
+
* Lodash - Copyright (c) JS Foundation and other contributors https://js.foundation/. Based on Underscore.js, copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors http://underscorejs.org/.
|
|
17
17
|
|
|
18
18
|
Trademarks
|
|
19
19
|
----------
|
|
20
20
|
|
|
21
|
-
**CKEditor** is a trademark of [CKSource Holding sp. z o.o.](https://cksource.com) All other brand and product names are trademarks, registered trademarks or service marks of their respective holders.
|
|
21
|
+
**CKEditor** is a trademark of [CKSource Holding sp. z o.o.](https://cksource.com) All other brand and product names are trademarks, registered trademarks, or service marks of their respective holders.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ckeditor/ckeditor5-engine",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "40.1.0",
|
|
4
4
|
"description": "The editing engine of CKEditor 5 – the best browser-based rich text editor.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"wysiwyg",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
],
|
|
24
24
|
"main": "src/index.js",
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@ckeditor/ckeditor5-utils": "
|
|
26
|
+
"@ckeditor/ckeditor5-utils": "40.1.0",
|
|
27
27
|
"lodash-es": "4.17.21"
|
|
28
28
|
},
|
|
29
29
|
"author": "CKSource (http://cksource.com/)",
|
|
@@ -45,7 +45,7 @@ export default class DataController extends DataController_base {
|
|
|
45
45
|
readonly model: Model;
|
|
46
46
|
/**
|
|
47
47
|
* Mapper used for the conversion. It has no permanent bindings, because these are created while getting data and
|
|
48
|
-
*
|
|
48
|
+
* are cleared directly after the data are converted. However, the mapper is defined as a class property, because
|
|
49
49
|
* it needs to be passed to the `DowncastDispatcher` as a conversion API.
|
|
50
50
|
*/
|
|
51
51
|
readonly mapper: Mapper;
|
|
@@ -258,7 +258,7 @@ export default class DowncastDispatcher extends EmitterMixin() {
|
|
|
258
258
|
_convertInsert(range, conversionApi, options = {}) {
|
|
259
259
|
if (!options.doNotAddConsumables) {
|
|
260
260
|
// Collect a list of things that can be consumed, consisting of nodes and their attributes.
|
|
261
|
-
this._addConsumablesForInsert(conversionApi.consumable,
|
|
261
|
+
this._addConsumablesForInsert(conversionApi.consumable, range);
|
|
262
262
|
}
|
|
263
263
|
// Fire a separate insert event for each node and text fragment contained in the range.
|
|
264
264
|
for (const data of Array.from(range.getWalker({ shallow: true })).map(walkerValueToEventData)) {
|
|
@@ -1810,16 +1810,11 @@ function normalizeModelElementConfig(model) {
|
|
|
1810
1810
|
if (typeof model == 'string') {
|
|
1811
1811
|
model = { name: model };
|
|
1812
1812
|
}
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
model.attributes
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
model.attributes = [model.attributes];
|
|
1819
|
-
}
|
|
1820
|
-
// Whether a children insertion/deletion should trigger reconversion.
|
|
1821
|
-
model.children = !!model.children;
|
|
1822
|
-
return model;
|
|
1813
|
+
return {
|
|
1814
|
+
name: model.name,
|
|
1815
|
+
attributes: model.attributes ? toArray(model.attributes) : [],
|
|
1816
|
+
children: !!model.children
|
|
1817
|
+
};
|
|
1823
1818
|
}
|
|
1824
1819
|
/**
|
|
1825
1820
|
* Takes `config.view`, and if it is an {@link module:engine/view/elementdefinition~ElementDefinition}, converts it
|
|
@@ -187,7 +187,7 @@ export default class UpcastDispatcher extends EmitterMixin() {
|
|
|
187
187
|
const documentFragment = writer.createDocumentFragment();
|
|
188
188
|
// When there is a conversion result.
|
|
189
189
|
if (modelRange) {
|
|
190
|
-
// Remove all empty elements that were
|
|
190
|
+
// Remove all empty elements that were created while splitting.
|
|
191
191
|
this._removeEmptyElements();
|
|
192
192
|
// Move all items that were converted in context tree to the document fragment.
|
|
193
193
|
for (const item of Array.from(this._modelCursor.parent.getChildren())) {
|
|
@@ -430,11 +430,15 @@ export class ViewElementConsumables {
|
|
|
430
430
|
*
|
|
431
431
|
* What you have done is trying to use:
|
|
432
432
|
*
|
|
433
|
-
*
|
|
433
|
+
* ```ts
|
|
434
|
+
* consumables.add( { attributes: [ 'class', 'style' ] } );
|
|
435
|
+
* ```
|
|
434
436
|
*
|
|
435
437
|
* While each class and style should be registered separately:
|
|
436
438
|
*
|
|
437
|
-
*
|
|
439
|
+
* ```ts
|
|
440
|
+
* consumables.add( { classes: 'some-class', styles: 'font-weight' } );
|
|
441
|
+
* ```
|
|
438
442
|
*
|
|
439
443
|
* @error viewconsumable-invalid-attribute
|
|
440
444
|
*/
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
3
|
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
|
4
4
|
*/
|
|
5
|
+
import { global } from '@ckeditor/ckeditor5-utils';
|
|
5
6
|
/**
|
|
6
7
|
* Basic HTML writer. It uses the native `innerHTML` property for basic conversion
|
|
7
8
|
* from a document fragment to an HTML string.
|
|
@@ -11,7 +12,7 @@ export default class BasicHtmlWriter {
|
|
|
11
12
|
* Returns an HTML string created from the document fragment.
|
|
12
13
|
*/
|
|
13
14
|
getHtml(fragment) {
|
|
14
|
-
const doc = document.implementation.createHTMLDocument('');
|
|
15
|
+
const doc = global.document.implementation.createHTMLDocument('');
|
|
15
16
|
const container = doc.createElement('div');
|
|
16
17
|
container.appendChild(fragment);
|
|
17
18
|
return container.innerHTML;
|
package/src/index.d.ts
CHANGED
|
@@ -30,7 +30,7 @@ export { default as RootAttributeOperation } from './model/operation/rootattribu
|
|
|
30
30
|
export { default as RootOperation } from './model/operation/rootoperation';
|
|
31
31
|
export { default as NoOperation } from './model/operation/nooperation';
|
|
32
32
|
export { transformSets } from './model/operation/transform';
|
|
33
|
-
export { default as DocumentSelection, type DocumentSelectionChangeRangeEvent } from './model/documentselection';
|
|
33
|
+
export { default as DocumentSelection, type DocumentSelectionChangeRangeEvent, type DocumentSelectionChangeMarkerEvent } from './model/documentselection';
|
|
34
34
|
export { default as Range } from './model/range';
|
|
35
35
|
export { default as LiveRange, type LiveRangeChangeRangeEvent } from './model/liverange';
|
|
36
36
|
export { default as LivePosition } from './model/liveposition';
|
|
@@ -47,7 +47,7 @@ export type { Marker } from './model/markercollection';
|
|
|
47
47
|
export type { default as Batch } from './model/batch';
|
|
48
48
|
export type { default as Differ, DiffItem, DiffItemAttribute, DiffItemInsert, DiffItemRemove } from './model/differ';
|
|
49
49
|
export type { default as Item } from './model/item';
|
|
50
|
-
export type { default as Node } from './model/node';
|
|
50
|
+
export type { default as Node, NodeAttributes } from './model/node';
|
|
51
51
|
export type { default as RootElement } from './model/rootelement';
|
|
52
52
|
export type { default as Schema, SchemaAttributeCheckCallback, SchemaChildCheckCallback, AttributeProperties, SchemaItemDefinition } from './model/schema';
|
|
53
53
|
export type { default as Selection, Selectable } from './model/selection';
|
|
@@ -74,7 +74,7 @@ export { default as ViewRawElement } from './view/rawelement';
|
|
|
74
74
|
export { default as ViewUIElement } from './view/uielement';
|
|
75
75
|
export { default as ViewDocumentFragment } from './view/documentfragment';
|
|
76
76
|
export { default as ViewTreeWalker, type TreeWalkerValue as ViewTreeWalkerValue } from './view/treewalker';
|
|
77
|
-
export type { default as ViewElementDefinition } from './view/elementdefinition';
|
|
77
|
+
export type { default as ViewElementDefinition, ElementObjectDefinition } from './view/elementdefinition';
|
|
78
78
|
export type { default as ViewDocumentSelection } from './view/documentselection';
|
|
79
79
|
export { default as AttributeElement } from './view/attributeelement';
|
|
80
80
|
export type { default as ViewItem } from './view/item';
|
package/src/model/batch.d.ts
CHANGED
|
@@ -17,7 +17,7 @@ import type Operation from './operation/operation';
|
|
|
17
17
|
* @see module:engine/model/model~Model#enqueueChange
|
|
18
18
|
* @see module:engine/model/model~Model#change
|
|
19
19
|
*/
|
|
20
|
-
export default class Batch {
|
|
20
|
+
export default class Batch implements BatchType {
|
|
21
21
|
/**
|
|
22
22
|
* An array of operations that compose this batch.
|
|
23
23
|
*/
|
package/src/model/document.js
CHANGED
|
@@ -192,8 +192,7 @@ export default class Document extends EmitterMixin() {
|
|
|
192
192
|
* @param includeDetached Specified whether detached roots should be returned as well.
|
|
193
193
|
*/
|
|
194
194
|
getRoots(includeDetached = false) {
|
|
195
|
-
return
|
|
196
|
-
.filter(root => root != this.graveyard && (includeDetached || root.isAttached()) && root._isLoaded);
|
|
195
|
+
return this.roots.filter(root => root != this.graveyard && (includeDetached || root.isAttached()) && root._isLoaded);
|
|
197
196
|
}
|
|
198
197
|
/**
|
|
199
198
|
* Used to register a post-fixer callback. A post-fixer mechanism guarantees that the features
|
|
@@ -107,10 +107,10 @@ export default class MarkerCollection extends MarkerCollection_base implements I
|
|
|
107
107
|
* Iterates over all markers that starts with given `prefix`.
|
|
108
108
|
*
|
|
109
109
|
* ```ts
|
|
110
|
-
* const markerFooA = markersCollection.
|
|
111
|
-
* const markerFooB = markersCollection.
|
|
112
|
-
* const markerBarA = markersCollection.
|
|
113
|
-
* const markerFooBarA = markersCollection.
|
|
110
|
+
* const markerFooA = markersCollection._set( 'foo:a', rangeFooA );
|
|
111
|
+
* const markerFooB = markersCollection._set( 'foo:b', rangeFooB );
|
|
112
|
+
* const markerBarA = markersCollection._set( 'bar:a', rangeBarA );
|
|
113
|
+
* const markerFooBarA = markersCollection._set( 'foobar:a', rangeFooBarA );
|
|
114
114
|
* Array.from( markersCollection.getMarkersGroup( 'foo' ) ); // [ markerFooA, markerFooB ]
|
|
115
115
|
* Array.from( markersCollection.getMarkersGroup( 'a' ) ); // []
|
|
116
116
|
* ```
|
|
@@ -190,10 +190,10 @@ export default class MarkerCollection extends EmitterMixin() {
|
|
|
190
190
|
* Iterates over all markers that starts with given `prefix`.
|
|
191
191
|
*
|
|
192
192
|
* ```ts
|
|
193
|
-
* const markerFooA = markersCollection.
|
|
194
|
-
* const markerFooB = markersCollection.
|
|
195
|
-
* const markerBarA = markersCollection.
|
|
196
|
-
* const markerFooBarA = markersCollection.
|
|
193
|
+
* const markerFooA = markersCollection._set( 'foo:a', rangeFooA );
|
|
194
|
+
* const markerFooB = markersCollection._set( 'foo:b', rangeFooB );
|
|
195
|
+
* const markerBarA = markersCollection._set( 'bar:a', rangeBarA );
|
|
196
|
+
* const markerFooBarA = markersCollection._set( 'foobar:a', rangeFooBarA );
|
|
197
197
|
* Array.from( markersCollection.getMarkersGroup( 'foo' ) ); // [ markerFooA, markerFooB ]
|
|
198
198
|
* Array.from( markersCollection.getMarkersGroup( 'a' ) ); // []
|
|
199
199
|
* ```
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
3
|
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
|
4
4
|
*/
|
|
5
|
-
import type Batch from '../batch';
|
|
6
|
-
import type Document from '../document';
|
|
7
|
-
import type { Selectable } from '../selection';
|
|
8
5
|
/**
|
|
9
6
|
* @module engine/model/operation/operation
|
|
10
7
|
*/
|
|
8
|
+
import type Batch from '../batch';
|
|
9
|
+
import type Document from '../document';
|
|
10
|
+
import type { Selectable } from '../selection';
|
|
11
11
|
/**
|
|
12
12
|
* Abstract base operation class.
|
|
13
13
|
*/
|
|
@@ -2,9 +2,6 @@
|
|
|
2
2
|
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
3
|
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
|
4
4
|
*/
|
|
5
|
-
/**
|
|
6
|
-
* @module engine/model/operation/operation
|
|
7
|
-
*/
|
|
8
5
|
/**
|
|
9
6
|
* Abstract base operation class.
|
|
10
7
|
*/
|
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
3
|
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
|
4
4
|
*/
|
|
5
|
+
/**
|
|
6
|
+
* @module engine/model/operation/transform
|
|
7
|
+
*/
|
|
5
8
|
import InsertOperation from './insertoperation';
|
|
6
9
|
import AttributeOperation from './attributeoperation';
|
|
7
10
|
import RenameOperation from './renameoperation';
|
|
@@ -16,9 +19,6 @@ import Range from '../range';
|
|
|
16
19
|
import Position from '../position';
|
|
17
20
|
import { compareArrays } from '@ckeditor/ckeditor5-utils';
|
|
18
21
|
const transformations = new Map();
|
|
19
|
-
/**
|
|
20
|
-
* @module engine/model/operation/transform
|
|
21
|
-
*/
|
|
22
22
|
/**
|
|
23
23
|
* Sets a transformation function to be be used to transform instances of class `OperationA` by instances of class `OperationB`.
|
|
24
24
|
*
|
|
@@ -138,7 +138,11 @@ export function _normalizeNodes(nodes) {
|
|
|
138
138
|
convert(node);
|
|
139
139
|
}
|
|
140
140
|
}
|
|
141
|
-
|
|
141
|
+
else {
|
|
142
|
+
// Skip unrecognized type.
|
|
143
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
144
|
+
const unreachable = nodes;
|
|
145
|
+
}
|
|
142
146
|
}
|
|
143
147
|
convert(nodes);
|
|
144
148
|
// Merge text nodes.
|
package/src/view/document.d.ts
CHANGED
|
@@ -128,6 +128,8 @@ export default class Document extends Document_base {
|
|
|
128
128
|
* // Let other post-fixers know that something changed.
|
|
129
129
|
* return true;
|
|
130
130
|
* }
|
|
131
|
+
*
|
|
132
|
+
* return false;
|
|
131
133
|
* } );
|
|
132
134
|
* ```
|
|
133
135
|
*
|
|
@@ -166,8 +168,6 @@ export type ViewDocumentPostFixer = (writer: DowncastWriter) => boolean;
|
|
|
166
168
|
* * `children` - for child list changes,
|
|
167
169
|
* * `attributes` - for element attributes changes,
|
|
168
170
|
* * `text` - for text nodes changes.
|
|
169
|
-
*
|
|
170
|
-
* @typedef {String} module:engine/view/document~ChangeType
|
|
171
171
|
*/
|
|
172
172
|
export type ChangeType = 'children' | 'attributes' | 'text';
|
|
173
173
|
/**
|
package/src/view/document.js
CHANGED
|
@@ -79,6 +79,8 @@ export default class Document extends BubblingEmitterMixin(ObservableMixin()) {
|
|
|
79
79
|
* // Let other post-fixers know that something changed.
|
|
80
80
|
* return true;
|
|
81
81
|
* }
|
|
82
|
+
*
|
|
83
|
+
* return false;
|
|
82
84
|
* } );
|
|
83
85
|
* ```
|
|
84
86
|
*
|
|
@@ -98,7 +100,7 @@ export default class Document extends BubblingEmitterMixin(ObservableMixin()) {
|
|
|
98
100
|
* Destroys this instance. Makes sure that all observers are destroyed and listeners removed.
|
|
99
101
|
*/
|
|
100
102
|
destroy() {
|
|
101
|
-
this.roots.
|
|
103
|
+
this.roots.forEach(root => root.destroy());
|
|
102
104
|
this.stopListening();
|
|
103
105
|
}
|
|
104
106
|
/**
|
|
@@ -65,6 +65,10 @@ export default class DocumentFragment extends DocumentFragment_base implements I
|
|
|
65
65
|
* Artificial element name. Returns `undefined`. Added for compatibility reasons.
|
|
66
66
|
*/
|
|
67
67
|
get name(): undefined;
|
|
68
|
+
/**
|
|
69
|
+
* Artificial element getFillerOffset. Returns `undefined`. Added for compatibility reasons.
|
|
70
|
+
*/
|
|
71
|
+
get getFillerOffset(): undefined;
|
|
68
72
|
/**
|
|
69
73
|
* Returns the custom property value for the given key.
|
|
70
74
|
*/
|
|
@@ -78,6 +78,12 @@ export default class DocumentFragment extends EmitterMixin(TypeCheckable) {
|
|
|
78
78
|
get name() {
|
|
79
79
|
return undefined;
|
|
80
80
|
}
|
|
81
|
+
/**
|
|
82
|
+
* Artificial element getFillerOffset. Returns `undefined`. Added for compatibility reasons.
|
|
83
|
+
*/
|
|
84
|
+
get getFillerOffset() {
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
81
87
|
/**
|
|
82
88
|
* Returns the custom property value for the given key.
|
|
83
89
|
*/
|
|
@@ -101,6 +101,10 @@ export default class DomConverter {
|
|
|
101
101
|
* Matcher for inline object view elements. This is an extension of a simple {@link #inlineObjectElements} array of element names.
|
|
102
102
|
*/
|
|
103
103
|
private readonly _inlineObjectElementMatcher;
|
|
104
|
+
/**
|
|
105
|
+
* Set of elements with temporary custom properties that require clearing after render.
|
|
106
|
+
*/
|
|
107
|
+
private readonly _elementsWithTemporaryCustomProperties;
|
|
104
108
|
/**
|
|
105
109
|
* Creates a DOM converter.
|
|
106
110
|
*
|
|
@@ -167,20 +171,22 @@ export default class DomConverter {
|
|
|
167
171
|
* @param html Textual representation of the HTML that will be set on `domElement`.
|
|
168
172
|
*/
|
|
169
173
|
setContentOf(domElement: DomElement, html: string): void;
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
* @param options Conversion options.
|
|
176
|
-
* @param options.bind Determines whether new elements will be bound.
|
|
177
|
-
* @param options.withChildren If `false`, node's and document fragment's children will not be converted.
|
|
178
|
-
* @returns Converted node or DocumentFragment.
|
|
179
|
-
*/
|
|
180
|
-
viewToDom(viewNode: ViewNode | ViewDocumentFragment, options?: {
|
|
174
|
+
viewToDom(viewNode: ViewText, options?: {
|
|
175
|
+
bind?: boolean;
|
|
176
|
+
withChildren?: boolean;
|
|
177
|
+
}): DomText;
|
|
178
|
+
viewToDom(viewNode: ViewElement, options?: {
|
|
181
179
|
bind?: boolean;
|
|
182
180
|
withChildren?: boolean;
|
|
183
|
-
}):
|
|
181
|
+
}): DomElement;
|
|
182
|
+
viewToDom(viewNode: ViewNode, options?: {
|
|
183
|
+
bind?: boolean;
|
|
184
|
+
withChildren?: boolean;
|
|
185
|
+
}): DomNode;
|
|
186
|
+
viewToDom(viewNode: ViewDocumentFragment, options?: {
|
|
187
|
+
bind?: boolean;
|
|
188
|
+
withChildren?: boolean;
|
|
189
|
+
}): DomDocumentFragment;
|
|
184
190
|
/**
|
|
185
191
|
* Sets the attribute on a DOM element.
|
|
186
192
|
*
|
|
@@ -212,7 +218,7 @@ export default class DomConverter {
|
|
|
212
218
|
* @param options See {@link module:engine/view/domconverter~DomConverter#viewToDom} options parameter.
|
|
213
219
|
* @returns DOM nodes.
|
|
214
220
|
*/
|
|
215
|
-
viewChildrenToDom(viewElement: ViewElement, options?: {
|
|
221
|
+
viewChildrenToDom(viewElement: ViewElement | ViewDocumentFragment, options?: {
|
|
216
222
|
bind?: boolean;
|
|
217
223
|
withChildren?: boolean;
|
|
218
224
|
}): IterableIterator<Node>;
|
|
@@ -477,6 +483,12 @@ export default class DomConverter {
|
|
|
477
483
|
* @param pattern Pattern matching a view element which should be treated as an inline object.
|
|
478
484
|
*/
|
|
479
485
|
registerInlineObjectMatcher(pattern: MatcherPattern): void;
|
|
486
|
+
/**
|
|
487
|
+
* Clear temporary custom properties.
|
|
488
|
+
*
|
|
489
|
+
* @internal
|
|
490
|
+
*/
|
|
491
|
+
_clearTemporaryCustomProperties(): void;
|
|
480
492
|
/**
|
|
481
493
|
* Returns the block {@link module:engine/view/filler filler} node based on the current {@link #blockFillerMode} setting.
|
|
482
494
|
*/
|
package/src/view/domconverter.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
/**
|
|
6
6
|
* @module engine/view/domconverter
|
|
7
7
|
*/
|
|
8
|
-
/* globals Node, NodeFilter, DOMParser
|
|
8
|
+
/* globals Node, NodeFilter, DOMParser */
|
|
9
9
|
import ViewText from './text';
|
|
10
10
|
import ViewElement from './element';
|
|
11
11
|
import ViewUIElement from './uielement';
|
|
@@ -16,7 +16,7 @@ import ViewDocumentFragment from './documentfragment';
|
|
|
16
16
|
import ViewTreeWalker from './treewalker';
|
|
17
17
|
import { default as Matcher } from './matcher';
|
|
18
18
|
import { BR_FILLER, INLINE_FILLER_LENGTH, NBSP_FILLER, MARKED_NBSP_FILLER, getDataWithoutFiller, isInlineFiller, startsWithFiller } from './filler';
|
|
19
|
-
import { global, logWarning, indexOf, getAncestors, isText, isComment, isValidAttributeName, first } from '@ckeditor/ckeditor5-utils';
|
|
19
|
+
import { global, logWarning, indexOf, getAncestors, isText, isComment, isValidAttributeName, first, env } from '@ckeditor/ckeditor5-utils';
|
|
20
20
|
const BR_FILLER_REF = BR_FILLER(global.document); // eslint-disable-line new-cap
|
|
21
21
|
const NBSP_FILLER_REF = NBSP_FILLER(global.document); // eslint-disable-line new-cap
|
|
22
22
|
const MARKED_NBSP_FILLER_REF = MARKED_NBSP_FILLER(global.document); // eslint-disable-line new-cap
|
|
@@ -70,6 +70,10 @@ export default class DomConverter {
|
|
|
70
70
|
* Matcher for inline object view elements. This is an extension of a simple {@link #inlineObjectElements} array of element names.
|
|
71
71
|
*/
|
|
72
72
|
this._inlineObjectElementMatcher = new Matcher();
|
|
73
|
+
/**
|
|
74
|
+
* Set of elements with temporary custom properties that require clearing after render.
|
|
75
|
+
*/
|
|
76
|
+
this._elementsWithTemporaryCustomProperties = new Set();
|
|
73
77
|
this.document = document;
|
|
74
78
|
this.renderingMode = renderingMode;
|
|
75
79
|
this.blockFillerMode = blockFillerMode || (renderingMode === 'editing' ? 'br' : 'nbsp');
|
|
@@ -230,57 +234,65 @@ export default class DomConverter {
|
|
|
230
234
|
return this._domDocument.createTextNode(textData);
|
|
231
235
|
}
|
|
232
236
|
else {
|
|
233
|
-
|
|
234
|
-
|
|
237
|
+
const viewElementOrFragment = viewNode;
|
|
238
|
+
if (this.mapViewToDom(viewElementOrFragment)) {
|
|
239
|
+
// Do not reuse element that is marked to not reuse (for example an IMG element
|
|
240
|
+
// so it can immediately display a placeholder background instead of waiting for the new src to load).
|
|
241
|
+
if (viewElementOrFragment.getCustomProperty('editingPipeline:doNotReuseOnce')) {
|
|
242
|
+
this._elementsWithTemporaryCustomProperties.add(viewElementOrFragment);
|
|
243
|
+
}
|
|
244
|
+
else {
|
|
245
|
+
return this.mapViewToDom(viewElementOrFragment);
|
|
246
|
+
}
|
|
235
247
|
}
|
|
236
248
|
let domElement;
|
|
237
|
-
if (
|
|
249
|
+
if (viewElementOrFragment.is('documentFragment')) {
|
|
238
250
|
// Create DOM document fragment.
|
|
239
251
|
domElement = this._domDocument.createDocumentFragment();
|
|
240
252
|
if (options.bind) {
|
|
241
|
-
this.bindDocumentFragments(domElement,
|
|
253
|
+
this.bindDocumentFragments(domElement, viewElementOrFragment);
|
|
242
254
|
}
|
|
243
255
|
}
|
|
244
|
-
else if (
|
|
245
|
-
if (
|
|
246
|
-
domElement = this._domDocument.createComment(
|
|
256
|
+
else if (viewElementOrFragment.is('uiElement')) {
|
|
257
|
+
if (viewElementOrFragment.name === '$comment') {
|
|
258
|
+
domElement = this._domDocument.createComment(viewElementOrFragment.getCustomProperty('$rawContent'));
|
|
247
259
|
}
|
|
248
260
|
else {
|
|
249
261
|
// UIElement has its own render() method (see #799).
|
|
250
|
-
domElement =
|
|
262
|
+
domElement = viewElementOrFragment.render(this._domDocument, this);
|
|
251
263
|
}
|
|
252
264
|
if (options.bind) {
|
|
253
|
-
this.bindElements(domElement,
|
|
265
|
+
this.bindElements(domElement, viewElementOrFragment);
|
|
254
266
|
}
|
|
255
267
|
return domElement;
|
|
256
268
|
}
|
|
257
269
|
else {
|
|
258
270
|
// Create DOM element.
|
|
259
|
-
if (this._shouldRenameElement(
|
|
260
|
-
_logUnsafeElement(
|
|
261
|
-
domElement = this._createReplacementDomElement(
|
|
271
|
+
if (this._shouldRenameElement(viewElementOrFragment.name)) {
|
|
272
|
+
_logUnsafeElement(viewElementOrFragment.name);
|
|
273
|
+
domElement = this._createReplacementDomElement(viewElementOrFragment.name);
|
|
262
274
|
}
|
|
263
|
-
else if (
|
|
264
|
-
domElement = this._domDocument.createElementNS(
|
|
275
|
+
else if (viewElementOrFragment.hasAttribute('xmlns')) {
|
|
276
|
+
domElement = this._domDocument.createElementNS(viewElementOrFragment.getAttribute('xmlns'), viewElementOrFragment.name);
|
|
265
277
|
}
|
|
266
278
|
else {
|
|
267
|
-
domElement = this._domDocument.createElement(
|
|
279
|
+
domElement = this._domDocument.createElement(viewElementOrFragment.name);
|
|
268
280
|
}
|
|
269
281
|
// RawElement take care of their children in RawElement#render() method which can be customized
|
|
270
282
|
// (see https://github.com/ckeditor/ckeditor5/issues/4469).
|
|
271
|
-
if (
|
|
272
|
-
|
|
283
|
+
if (viewElementOrFragment.is('rawElement')) {
|
|
284
|
+
viewElementOrFragment.render(domElement, this);
|
|
273
285
|
}
|
|
274
286
|
if (options.bind) {
|
|
275
|
-
this.bindElements(domElement,
|
|
287
|
+
this.bindElements(domElement, viewElementOrFragment);
|
|
276
288
|
}
|
|
277
289
|
// Copy element's attributes.
|
|
278
|
-
for (const key of
|
|
279
|
-
this.setDomElementAttribute(domElement, key,
|
|
290
|
+
for (const key of viewElementOrFragment.getAttributeKeys()) {
|
|
291
|
+
this.setDomElementAttribute(domElement, key, viewElementOrFragment.getAttribute(key), viewElementOrFragment);
|
|
280
292
|
}
|
|
281
293
|
}
|
|
282
294
|
if (options.withChildren !== false) {
|
|
283
|
-
for (const child of this.viewChildrenToDom(
|
|
295
|
+
for (const child of this.viewChildrenToDom(viewElementOrFragment, options)) {
|
|
284
296
|
domElement.appendChild(child);
|
|
285
297
|
}
|
|
286
298
|
}
|
|
@@ -526,6 +538,10 @@ export default class DomConverter {
|
|
|
526
538
|
* @returns View selection.
|
|
527
539
|
*/
|
|
528
540
|
domSelectionToView(domSelection) {
|
|
541
|
+
// See: https://github.com/ckeditor/ckeditor5/issues/9635.
|
|
542
|
+
if (isGeckoRestrictedDomSelection(domSelection)) {
|
|
543
|
+
return new ViewSelection([]);
|
|
544
|
+
}
|
|
529
545
|
// DOM selection might be placed in fake selection container.
|
|
530
546
|
// If container contains fake selection - return corresponding view selection.
|
|
531
547
|
if (domSelection.rangeCount === 1) {
|
|
@@ -921,6 +937,17 @@ export default class DomConverter {
|
|
|
921
937
|
registerInlineObjectMatcher(pattern) {
|
|
922
938
|
this._inlineObjectElementMatcher.add(pattern);
|
|
923
939
|
}
|
|
940
|
+
/**
|
|
941
|
+
* Clear temporary custom properties.
|
|
942
|
+
*
|
|
943
|
+
* @internal
|
|
944
|
+
*/
|
|
945
|
+
_clearTemporaryCustomProperties() {
|
|
946
|
+
for (const element of this._elementsWithTemporaryCustomProperties) {
|
|
947
|
+
element._removeCustomProperty('editingPipeline:doNotReuseOnce');
|
|
948
|
+
}
|
|
949
|
+
this._elementsWithTemporaryCustomProperties.clear();
|
|
950
|
+
}
|
|
924
951
|
/**
|
|
925
952
|
* Returns the block {@link module:engine/view/filler filler} node based on the current {@link #blockFillerMode} setting.
|
|
926
953
|
*/
|
|
@@ -1379,6 +1406,27 @@ function _logUnsafeElement(elementName) {
|
|
|
1379
1406
|
logWarning('domconverter-unsafe-style-element-detected');
|
|
1380
1407
|
}
|
|
1381
1408
|
}
|
|
1409
|
+
/**
|
|
1410
|
+
* In certain cases, Firefox mysteriously assigns so called "restricted objects" to native DOM Range properties.
|
|
1411
|
+
* Any attempt at accessing restricted object's properties causes errors.
|
|
1412
|
+
* See: https://github.com/ckeditor/ckeditor5/issues/9635.
|
|
1413
|
+
*/
|
|
1414
|
+
function isGeckoRestrictedDomSelection(domSelection) {
|
|
1415
|
+
if (!env.isGecko) {
|
|
1416
|
+
return false;
|
|
1417
|
+
}
|
|
1418
|
+
if (!domSelection.rangeCount) {
|
|
1419
|
+
return false;
|
|
1420
|
+
}
|
|
1421
|
+
const container = domSelection.getRangeAt(0).startContainer;
|
|
1422
|
+
try {
|
|
1423
|
+
Object.prototype.toString.call(container);
|
|
1424
|
+
}
|
|
1425
|
+
catch (error) {
|
|
1426
|
+
return true;
|
|
1427
|
+
}
|
|
1428
|
+
return false;
|
|
1429
|
+
}
|
|
1382
1430
|
/**
|
|
1383
1431
|
* While rendering the editor content, the {@link module:engine/view/domconverter~DomConverter} detected a `<script>` element that may
|
|
1384
1432
|
* disrupt the editing experience. To avoid this, the `<script>` element was replaced with `<span data-ck-unsafe-element="script"></span>`.
|
|
@@ -877,7 +877,7 @@ export default class DowncastWriter {
|
|
|
877
877
|
* @internal
|
|
878
878
|
* @param slotFactory The slot factory.
|
|
879
879
|
*/
|
|
880
|
-
_registerSlotFactory(slotFactory: (writer: DowncastWriter, modeOrFilter:
|
|
880
|
+
_registerSlotFactory(slotFactory: (writer: DowncastWriter, modeOrFilter: 'children' | SlotFilter) => Element): void;
|
|
881
881
|
/**
|
|
882
882
|
* Clears the registered slot factory.
|
|
883
883
|
*
|
package/src/view/element.d.ts
CHANGED
package/src/view/renderer.js
CHANGED
|
@@ -230,6 +230,7 @@ export default class Renderer extends ObservableMixin() {
|
|
|
230
230
|
// Otherwise, FF may throw an error (https://github.com/ckeditor/ckeditor5/issues/721).
|
|
231
231
|
this._updateFocus();
|
|
232
232
|
this._updateSelection();
|
|
233
|
+
this.domConverter._clearTemporaryCustomProperties();
|
|
233
234
|
this.markedTexts.clear();
|
|
234
235
|
this.markedAttributes.clear();
|
|
235
236
|
this.markedChildren.clear();
|
|
@@ -258,7 +259,7 @@ export default class Renderer extends ObservableMixin() {
|
|
|
258
259
|
// This would produce incorrect element mappings.
|
|
259
260
|
//
|
|
260
261
|
// Converting live list to an array to make the list static.
|
|
261
|
-
const actualDomChildren = Array.from(
|
|
262
|
+
const actualDomChildren = Array.from(domElement.childNodes);
|
|
262
263
|
const expectedDomChildren = Array.from(this.domConverter.viewChildrenToDom(viewElement, { withChildren: false }));
|
|
263
264
|
const diff = this._diffNodeLists(actualDomChildren, expectedDomChildren);
|
|
264
265
|
const actions = this._findUpdateActions(diff, actualDomChildren, expectedDomChildren, areSimilarElements);
|
|
@@ -272,7 +273,7 @@ export default class Renderer extends ObservableMixin() {
|
|
|
272
273
|
// UIElement and RawElement are special cases. Their children are not stored in a view (#799)
|
|
273
274
|
// so we cannot use them with replacing flow (since they use view children during rendering
|
|
274
275
|
// which will always result in rendering empty elements).
|
|
275
|
-
if (viewChild && !
|
|
276
|
+
if (viewChild && !viewChild.is('uiElement') && !viewChild.is('rawElement')) {
|
|
276
277
|
this._updateElementMappings(viewChild, actualDomChildren[deleteIndex]);
|
|
277
278
|
}
|
|
278
279
|
remove(expectedDomChildren[insertIndex]);
|
package/src/view/stylesmap.d.ts
CHANGED
|
@@ -593,7 +593,7 @@ export declare class StylesProcessor {
|
|
|
593
593
|
private _mapStyleNames;
|
|
594
594
|
}
|
|
595
595
|
/**
|
|
596
|
-
* A CSS style property descriptor that contains
|
|
596
|
+
* A CSS style property descriptor that contains tuple of two strings:
|
|
597
597
|
*
|
|
598
598
|
* - first string describes property name
|
|
599
599
|
* - second string describes property value
|
package/src/view/stylesmap.js
CHANGED
|
@@ -24,8 +24,7 @@ export default class StylesMap {
|
|
|
24
24
|
*/
|
|
25
25
|
get isEmpty() {
|
|
26
26
|
const entries = Object.entries(this._styles);
|
|
27
|
-
|
|
28
|
-
return !from.length;
|
|
27
|
+
return !entries.length;
|
|
29
28
|
}
|
|
30
29
|
/**
|
|
31
30
|
* Number of styles defined.
|
|
@@ -45,7 +44,7 @@ export default class StylesMap {
|
|
|
45
44
|
*/
|
|
46
45
|
setTo(inlineStyle) {
|
|
47
46
|
this.clear();
|
|
48
|
-
const parsedStyles =
|
|
47
|
+
const parsedStyles = parseInlineStyles(inlineStyle);
|
|
49
48
|
for (const [key, value] of parsedStyles) {
|
|
50
49
|
this._styleProcessor.toNormalizedForm(key, value, this._styles);
|
|
51
50
|
}
|
|
@@ -325,7 +324,7 @@ export default class StylesMap {
|
|
|
325
324
|
if (!parentObject) {
|
|
326
325
|
return;
|
|
327
326
|
}
|
|
328
|
-
const isParentEmpty = !
|
|
327
|
+
const isParentEmpty = !Object.keys(parentObject).length;
|
|
329
328
|
if (isParentEmpty) {
|
|
330
329
|
this.remove(parentPath);
|
|
331
330
|
}
|
|
@@ -484,7 +483,7 @@ export class StylesProcessor {
|
|
|
484
483
|
...expandedStyleNames,
|
|
485
484
|
...Object.keys(styles)
|
|
486
485
|
]);
|
|
487
|
-
return Array.from(styleNamesKeysSet
|
|
486
|
+
return Array.from(styleNamesKeysSet);
|
|
488
487
|
}
|
|
489
488
|
/**
|
|
490
489
|
* Returns related style names.
|
package/src/view/uielement.js
CHANGED
|
@@ -84,7 +84,8 @@ export default class UIElement extends Element {
|
|
|
84
84
|
*
|
|
85
85
|
* @param domConverter Instance of the DomConverter used to optimize the output.
|
|
86
86
|
*/
|
|
87
|
-
render(domDocument, domConverter
|
|
87
|
+
render(domDocument, domConverter // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
88
|
+
) {
|
|
88
89
|
// Provide basic, default output.
|
|
89
90
|
return this.toDomElement(domDocument);
|
|
90
91
|
}
|
package/src/view/view.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ import Selection, { type PlaceOrOffset, type Selectable, type SelectionOptions }
|
|
|
15
15
|
import type { default as Observer, ObserverConstructor } from './observer/observer';
|
|
16
16
|
import type { StylesProcessor } from './stylesmap';
|
|
17
17
|
import type Element from './element';
|
|
18
|
-
import type Node from './node';
|
|
18
|
+
import type { default as Node } from './node';
|
|
19
19
|
import type Item from './item';
|
|
20
20
|
import KeyObserver from './observer/keyobserver';
|
|
21
21
|
import FakeSelectionObserver from './observer/fakeselectionobserver';
|