@ckeditor/ckeditor5-engine 32.0.0 → 33.0.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.
@@ -35,6 +35,7 @@ const NBSP_FILLER_REF = NBSP_FILLER( document ); // eslint-disable-line new-cap
35
35
  const MARKED_NBSP_FILLER_REF = MARKED_NBSP_FILLER( document ); // eslint-disable-line new-cap
36
36
  const UNSAFE_ATTRIBUTE_NAME_PREFIX = 'data-ck-unsafe-attribute-';
37
37
  const UNSAFE_ELEMENT_REPLACEMENT_ATTRIBUTE = 'data-ck-unsafe-element';
38
+ const UNSAFE_ELEMENTS = [ 'script', 'style' ];
38
39
 
39
40
  /**
40
41
  * `DomConverter` is a set of tools to do transformations between DOM nodes and view nodes. It also handles
@@ -323,7 +324,7 @@ export default class DomConverter {
323
324
 
324
325
  // There are certain nodes, that should be renamed to <span> in editing pipeline.
325
326
  if ( this._shouldRenameElement( elementName ) ) {
326
- logWarning( 'domconverter-unsafe-element-detected', { unsafeElement: currentNode } );
327
+ _logUnsafeElement( elementName );
327
328
 
328
329
  currentNode.replaceWith( this._createReplacementDomElement( elementName, currentNode ) );
329
330
  }
@@ -384,7 +385,7 @@ export default class DomConverter {
384
385
  } else {
385
386
  // Create DOM element.
386
387
  if ( this._shouldRenameElement( viewNode.name ) ) {
387
- logWarning( 'domconverter-unsafe-element-detected', { unsafeElement: viewNode } );
388
+ _logUnsafeElement( viewNode.name );
388
389
 
389
390
  domElement = this._createReplacementDomElement( viewNode.name );
390
391
  } else if ( viewNode.hasAttribute( 'xmlns' ) ) {
@@ -428,7 +429,7 @@ export default class DomConverter {
428
429
  * @param {String} key The name of the attribute.
429
430
  * @param {String} value The value of the attribute.
430
431
  * @param {module:engine/view/element~Element} [relatedViewElement] The view element related to the `domElement` (if there is any).
431
- * It helps decide whether the attribute set is unsafe. For instance, view elements created via
432
+ * It helps decide whether the attribute set is unsafe. For instance, view elements created via the
432
433
  * {@link module:engine/view/downcastwriter~DowncastWriter} methods can allow certain attributes that would normally be filtered out.
433
434
  */
434
435
  setDomElementAttribute( domElement, key, value, relatedViewElement = null ) {
@@ -1546,7 +1547,9 @@ export default class DomConverter {
1546
1547
  * @returns {Boolean}
1547
1548
  */
1548
1549
  _shouldRenameElement( elementName ) {
1549
- return this.renderingMode == 'editing' && elementName.toLowerCase() == 'script';
1550
+ const name = elementName.toLowerCase();
1551
+
1552
+ return this.renderingMode === 'editing' && UNSAFE_ELEMENTS.includes( name );
1550
1553
  }
1551
1554
 
1552
1555
  /**
@@ -1626,6 +1629,20 @@ function hasBlockParent( domNode, blockElements ) {
1626
1629
  return parent && parent.tagName && blockElements.includes( parent.tagName.toLowerCase() );
1627
1630
  }
1628
1631
 
1632
+ // Log to console the information about element that was replaced.
1633
+ // Check UNSAFE_ELEMENTS for all recognized unsafe elements.
1634
+ //
1635
+ // @param {String} elementName The name of the view element
1636
+ function _logUnsafeElement( elementName ) {
1637
+ if ( elementName === 'script' ) {
1638
+ logWarning( 'domconverter-unsafe-script-element-detected' );
1639
+ }
1640
+
1641
+ if ( elementName === 'style' ) {
1642
+ logWarning( 'domconverter-unsafe-style-element-detected' );
1643
+ }
1644
+ }
1645
+
1629
1646
  /**
1630
1647
  * Enum representing the type of the block filler.
1631
1648
  *
@@ -1640,13 +1657,17 @@ function hasBlockParent( domNode, blockElements ) {
1640
1657
  */
1641
1658
 
1642
1659
  /**
1643
- * The {@link module:engine/view/domconverter~DomConverter} detected a `<script>` element that may disrupt the
1644
- * {@glink framework/guides/architecture/editing-engine#editing-pipeline editing pipeline} of the editor. To avoid this,
1645
- * the `<script>` element was renamed to `<span data-ck-unsafe-element="script"></span>`.
1660
+ * While rendering the editor content, the {@link module:engine/view/domconverter~DomConverter} detected a `<script>` element that may
1661
+ * disrupt the editing experience. To avoid this, the `<script>` element was replaced with `<span data-ck-unsafe-element="script"></span>`.
1662
+ *
1663
+ * @error domconverter-unsafe-script-element-detected
1664
+ */
1665
+
1666
+ /**
1667
+ * While rendering the editor content, the {@link module:engine/view/domconverter~DomConverter} detected a `<style>` element that may affect
1668
+ * the editing experience. To avoid this, the `<style>` element was replaced with `<span data-ck-unsafe-element="style"></span>`.
1646
1669
  *
1647
- * @error domconverter-unsafe-element-detected
1648
- * @param {module:engine/model/element~Element|HTMLElement} unsafeElement The editing view or DOM element
1649
- * that was renamed.
1670
+ * @error domconverter-unsafe-style-element-detected
1650
1671
  */
1651
1672
 
1652
1673
  /**
@@ -58,6 +58,14 @@ export default class DowncastWriter {
58
58
  * @type {Map.<String,Set>}
59
59
  */
60
60
  this._cloneGroups = new Map();
61
+
62
+ /**
63
+ * The slot factory used by the `elementToStructure` downcast helper.
64
+ *
65
+ * @private
66
+ * @type {Function|null}
67
+ */
68
+ this._slotFactory = null;
61
69
  }
62
70
 
63
71
  /**
@@ -222,8 +230,20 @@ export default class DowncastWriter {
222
230
  * // Create element with custom classes.
223
231
  * writer.createContainerElement( 'p', { class: 'foo bar baz' } );
224
232
  *
233
+ * // Create element with children.
234
+ * writer.createContainerElement( 'figure', { class: 'image' }, [
235
+ * writer.createEmptyElement( 'img' ),
236
+ * writer.createContainerElement( 'figcaption' )
237
+ * ] );
238
+ *
239
+ * // Create element with specific options.
240
+ * writer.createContainerElement( 'span', { class: 'placeholder' }, { isAllowedInsideAttributeElement: true } );
241
+ *
225
242
  * @param {String} name Name of the element.
226
243
  * @param {Object} [attributes] Elements attributes.
244
+ * @param {module:engine/view/node~Node|Iterable.<module:engine/view/node~Node>|Object} [childrenOrOptions]
245
+ * A node or a list of nodes to be inserted into the created element. If no children were specified, element's `options`
246
+ * can be passed in this argument.
227
247
  * @param {Object} [options] Element's options.
228
248
  * @param {Boolean} [options.isAllowedInsideAttributeElement=false] Whether an element is
229
249
  * {@link module:engine/view/element~Element#isAllowedInsideAttributeElement allowed inside an AttributeElement} and can be wrapped
@@ -232,8 +252,16 @@ export default class DowncastWriter {
232
252
  * pipeline even though they would normally be filtered out by unsafe attribute detection mechanisms.
233
253
  * @returns {module:engine/view/containerelement~ContainerElement} Created element.
234
254
  */
235
- createContainerElement( name, attributes, options = {} ) {
236
- const containerElement = new ContainerElement( this.document, name, attributes );
255
+ createContainerElement( name, attributes, childrenOrOptions = {}, options = {} ) {
256
+ let children = null;
257
+
258
+ if ( isPlainObject( childrenOrOptions ) ) {
259
+ options = childrenOrOptions;
260
+ } else {
261
+ children = childrenOrOptions;
262
+ }
263
+
264
+ const containerElement = new ContainerElement( this.document, name, attributes, children );
237
265
 
238
266
  if ( options.isAllowedInsideAttributeElement !== undefined ) {
239
267
  containerElement._isAllowedInsideAttributeElement = options.isAllowedInsideAttributeElement;
@@ -1167,7 +1195,7 @@ export default class DowncastWriter {
1167
1195
  }
1168
1196
 
1169
1197
  /**
1170
- Creates new {@link module:engine/view/selection~Selection} instance.
1198
+ * Creates new {@link module:engine/view/selection~Selection} instance.
1171
1199
  *
1172
1200
  * // Creates empty selection without ranges.
1173
1201
  * const selection = writer.createSelection();
@@ -1230,6 +1258,63 @@ export default class DowncastWriter {
1230
1258
  return new Selection( selectable, placeOrOffset, options );
1231
1259
  }
1232
1260
 
1261
+ /**
1262
+ * Creates placeholders for child elements of the {@link module:engine/conversion/downcasthelpers~DowncastHelpers#elementToStructure
1263
+ * `elementToStructure()`} conversion helper.
1264
+ *
1265
+ * const viewSlot = conversionApi.writer.createSlot();
1266
+ * const viewPosition = conversionApi.writer.createPositionAt( viewElement, 0 );
1267
+ *
1268
+ * conversionApi.writer.insert( viewPosition, viewSlot );
1269
+ *
1270
+ * It could be filtered down to a specific subset of children (only `<foo>` model elements in this case):
1271
+ *
1272
+ * const viewSlot = conversionApi.writer.createSlot( node => node.is( 'element', 'foo' ) );
1273
+ * const viewPosition = conversionApi.writer.createPositionAt( viewElement, 0 );
1274
+ *
1275
+ * conversionApi.writer.insert( viewPosition, viewSlot );
1276
+ *
1277
+ * While providing a filtered slot, make sure to provide slots for all child nodes. A single node can not be downcasted into
1278
+ * multiple slots.
1279
+ *
1280
+ * **Note**: You should not change the order of nodes. View elements should be in the same order as model nodes.
1281
+ *
1282
+ * @param {'children'|module:engine/conversion/downcasthelpers~SlotFilter} [modeOrFilter='children'] The filter for child nodes.
1283
+ * @returns {module:engine/view/element~Element} The slot element to be placed in to the view structure while processing
1284
+ * {@link module:engine/conversion/downcasthelpers~DowncastHelpers#elementToStructure `elementToStructure()`}.
1285
+ */
1286
+ createSlot( modeOrFilter ) {
1287
+ if ( !this._slotFactory ) {
1288
+ /**
1289
+ * The `createSlot()` method is only allowed inside the `elementToStructure` downcast helper callback.
1290
+ *
1291
+ * @error view-writer-invalid-create-slot-context
1292
+ */
1293
+ throw new CKEditorError( 'view-writer-invalid-create-slot-context', this.document );
1294
+ }
1295
+
1296
+ return this._slotFactory( this, modeOrFilter );
1297
+ }
1298
+
1299
+ /**
1300
+ * Registers a slot factory.
1301
+ *
1302
+ * @protected
1303
+ * @param {Function} slotFactory The slot factory.
1304
+ */
1305
+ _registerSlotFactory( slotFactory ) {
1306
+ this._slotFactory = slotFactory;
1307
+ }
1308
+
1309
+ /**
1310
+ * Clears the registered slot factory.
1311
+ *
1312
+ * @protected
1313
+ */
1314
+ _clearSlotFactory() {
1315
+ this._slotFactory = null;
1316
+ }
1317
+
1233
1318
  /**
1234
1319
  * Inserts a node or nodes at the specified position. Takes care of breaking attributes before insertion
1235
1320
  * and merging them afterwards if requested by the breakAttributes param.
@@ -25,3 +25,12 @@
25
25
  display: none;
26
26
  }
27
27
  }
28
+
29
+ /*
30
+ * Rules for the `ck-placeholder` are loaded before the rules for `ck-reset_all` in the base CKEditor 5 DLL build.
31
+ * This fix overwrites the incorrectly set `position: static` from `ck-reset_all`.
32
+ * See https://github.com/ckeditor/ckeditor5/issues/11418.
33
+ */
34
+ .ck.ck-reset_all .ck-placeholder {
35
+ position: relative;
36
+ }