@ckeditor/ckeditor5-engine 34.2.0 → 35.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.
package/LICENSE.md CHANGED
@@ -11,6 +11,10 @@ Sources of Intellectual Property Included in CKEditor
11
11
 
12
12
  Where not otherwise indicated, all CKEditor content is authored by CKSource engineers and consists of CKSource-owned intellectual property. In some specific instances, CKEditor will incorporate work done by developers outside of CKSource with their express permission.
13
13
 
14
+ The following libraries are included in CKEditor under the [MIT license](https://opensource.org/licenses/MIT):
15
+
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
+
14
18
  Trademarks
15
19
  ----------
16
20
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ckeditor/ckeditor5-engine",
3
- "version": "34.2.0",
3
+ "version": "35.0.0",
4
4
  "description": "The editing engine of CKEditor 5 – the best browser-based rich text editor.",
5
5
  "keywords": [
6
6
  "wysiwyg",
@@ -23,30 +23,30 @@
23
23
  ],
24
24
  "main": "src/index.js",
25
25
  "dependencies": {
26
- "@ckeditor/ckeditor5-utils": "^34.2.0",
26
+ "@ckeditor/ckeditor5-utils": "^35.0.0",
27
27
  "lodash-es": "^4.17.15"
28
28
  },
29
29
  "devDependencies": {
30
- "@ckeditor/ckeditor5-basic-styles": "^34.2.0",
31
- "@ckeditor/ckeditor5-block-quote": "^34.2.0",
32
- "@ckeditor/ckeditor5-clipboard": "^34.2.0",
33
- "@ckeditor/ckeditor5-cloud-services": "^34.2.0",
34
- "@ckeditor/ckeditor5-core": "^34.2.0",
35
- "@ckeditor/ckeditor5-editor-classic": "^34.2.0",
36
- "@ckeditor/ckeditor5-enter": "^34.2.0",
37
- "@ckeditor/ckeditor5-essentials": "^34.2.0",
38
- "@ckeditor/ckeditor5-heading": "^34.2.0",
39
- "@ckeditor/ckeditor5-image": "^34.2.0",
40
- "@ckeditor/ckeditor5-link": "^34.2.0",
41
- "@ckeditor/ckeditor5-list": "^34.2.0",
42
- "@ckeditor/ckeditor5-mention": "^34.2.0",
43
- "@ckeditor/ckeditor5-paragraph": "^34.2.0",
44
- "@ckeditor/ckeditor5-table": "^34.2.0",
45
- "@ckeditor/ckeditor5-theme-lark": "^34.2.0",
46
- "@ckeditor/ckeditor5-typing": "^34.2.0",
47
- "@ckeditor/ckeditor5-ui": "^34.2.0",
48
- "@ckeditor/ckeditor5-undo": "^34.2.0",
49
- "@ckeditor/ckeditor5-widget": "^34.2.0",
30
+ "@ckeditor/ckeditor5-basic-styles": "^35.0.0",
31
+ "@ckeditor/ckeditor5-block-quote": "^35.0.0",
32
+ "@ckeditor/ckeditor5-clipboard": "^35.0.0",
33
+ "@ckeditor/ckeditor5-cloud-services": "^35.0.0",
34
+ "@ckeditor/ckeditor5-core": "^35.0.0",
35
+ "@ckeditor/ckeditor5-editor-classic": "^35.0.0",
36
+ "@ckeditor/ckeditor5-enter": "^35.0.0",
37
+ "@ckeditor/ckeditor5-essentials": "^35.0.0",
38
+ "@ckeditor/ckeditor5-heading": "^35.0.0",
39
+ "@ckeditor/ckeditor5-image": "^35.0.0",
40
+ "@ckeditor/ckeditor5-link": "^35.0.0",
41
+ "@ckeditor/ckeditor5-list": "^35.0.0",
42
+ "@ckeditor/ckeditor5-mention": "^35.0.0",
43
+ "@ckeditor/ckeditor5-paragraph": "^35.0.0",
44
+ "@ckeditor/ckeditor5-table": "^35.0.0",
45
+ "@ckeditor/ckeditor5-theme-lark": "^35.0.0",
46
+ "@ckeditor/ckeditor5-typing": "^35.0.0",
47
+ "@ckeditor/ckeditor5-ui": "^35.0.0",
48
+ "@ckeditor/ckeditor5-undo": "^35.0.0",
49
+ "@ckeditor/ckeditor5-widget": "^35.0.0",
50
50
  "webpack": "^5.58.1",
51
51
  "webpack-cli": "^4.9.0"
52
52
  },
@@ -67,6 +67,7 @@
67
67
  "lang",
68
68
  "src",
69
69
  "theme",
70
- "ckeditor5-metadata.json"
70
+ "ckeditor5-metadata.json",
71
+ "CHANGELOG.md"
71
72
  ]
72
73
  }
@@ -7,7 +7,7 @@
7
7
  * @module engine/dataprocessor/htmldataprocessor
8
8
  */
9
9
 
10
- /* globals document, DOMParser */
10
+ /* globals DOMParser */
11
11
 
12
12
  import BasicHtmlWriter from './basichtmlwriter';
13
13
  import DomConverter from '../view/domconverter';
@@ -56,7 +56,7 @@ export default class HtmlDataProcessor {
56
56
  */
57
57
  toData( viewFragment ) {
58
58
  // Convert view DocumentFragment to DOM DocumentFragment.
59
- const domFragment = this.domConverter.viewToDom( viewFragment, document );
59
+ const domFragment = this.domConverter.viewToDom( viewFragment );
60
60
 
61
61
  // Convert DOM DocumentFragment to HTML output.
62
62
  return this.htmlWriter.getHtml( domFragment );
@@ -7,7 +7,7 @@
7
7
  * @module engine/dataprocessor/xmldataprocessor
8
8
  */
9
9
 
10
- /* globals DOMParser, document */
10
+ /* globals DOMParser */
11
11
 
12
12
  import BasicHtmlWriter from './basichtmlwriter';
13
13
  import DomConverter from '../view/domconverter';
@@ -71,7 +71,7 @@ export default class XmlDataProcessor {
71
71
  */
72
72
  toData( viewFragment ) {
73
73
  // Convert view DocumentFragment to DOM DocumentFragment.
74
- const domFragment = this.domConverter.viewToDom( viewFragment, document );
74
+ const domFragment = this.domConverter.viewToDom( viewFragment );
75
75
 
76
76
  // Convert DOM DocumentFragment to XML output.
77
77
  // There is no need to use dedicated for XML serializing method because BasicHtmlWriter works well in this case.
@@ -7,7 +7,7 @@
7
7
  * @module engine/view/domconverter
8
8
  */
9
9
 
10
- /* globals document, Node, NodeFilter, DOMParser, Text */
10
+ /* globals Node, NodeFilter, DOMParser, Text */
11
11
 
12
12
  import ViewText from './text';
13
13
  import ViewElement from './element';
@@ -30,9 +30,9 @@ import getAncestors from '@ckeditor/ckeditor5-utils/src/dom/getancestors';
30
30
  import isText from '@ckeditor/ckeditor5-utils/src/dom/istext';
31
31
  import isComment from '@ckeditor/ckeditor5-utils/src/dom/iscomment';
32
32
 
33
- const BR_FILLER_REF = BR_FILLER( document ); // eslint-disable-line new-cap
34
- const NBSP_FILLER_REF = NBSP_FILLER( document ); // eslint-disable-line new-cap
35
- const MARKED_NBSP_FILLER_REF = MARKED_NBSP_FILLER( document ); // eslint-disable-line new-cap
33
+ const BR_FILLER_REF = BR_FILLER( global.document ); // eslint-disable-line new-cap
34
+ const NBSP_FILLER_REF = NBSP_FILLER( global.document ); // eslint-disable-line new-cap
35
+ const MARKED_NBSP_FILLER_REF = MARKED_NBSP_FILLER( global.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
38
 
@@ -135,6 +135,14 @@ export default class DomConverter {
135
135
  */
136
136
  this.unsafeElements = [ 'script', 'style' ];
137
137
 
138
+ /**
139
+ * The DOM Document used to create DOM nodes.
140
+ *
141
+ * @type {Document}
142
+ * @private
143
+ */
144
+ this._domDocument = this.renderingMode === 'editing' ? global.document : global.document.implementation.createHTMLDocument( '' );
145
+
138
146
  /**
139
147
  * The DOM-to-view mapping.
140
148
  *
@@ -352,17 +360,16 @@ export default class DomConverter {
352
360
  *
353
361
  * @param {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment} viewNode
354
362
  * View node or document fragment to transform.
355
- * @param {Document} domDocument Document which will be used to create DOM nodes.
356
363
  * @param {Object} [options] Conversion options.
357
364
  * @param {Boolean} [options.bind=false] Determines whether new elements will be bound.
358
365
  * @param {Boolean} [options.withChildren=true] If `true`, node's and document fragment's children will be converted too.
359
366
  * @returns {Node|DocumentFragment} Converted node or DocumentFragment.
360
367
  */
361
- viewToDom( viewNode, domDocument, options = {} ) {
368
+ viewToDom( viewNode, options = {} ) {
362
369
  if ( viewNode.is( '$text' ) ) {
363
370
  const textData = this._processDataFromViewText( viewNode );
364
371
 
365
- return domDocument.createTextNode( textData );
372
+ return this._domDocument.createTextNode( textData );
366
373
  } else {
367
374
  if ( this.mapViewToDom( viewNode ) ) {
368
375
  return this.mapViewToDom( viewNode );
@@ -372,17 +379,17 @@ export default class DomConverter {
372
379
 
373
380
  if ( viewNode.is( 'documentFragment' ) ) {
374
381
  // Create DOM document fragment.
375
- domElement = domDocument.createDocumentFragment();
382
+ domElement = this._domDocument.createDocumentFragment();
376
383
 
377
384
  if ( options.bind ) {
378
385
  this.bindDocumentFragments( domElement, viewNode );
379
386
  }
380
387
  } else if ( viewNode.is( 'uiElement' ) ) {
381
388
  if ( viewNode.name === '$comment' ) {
382
- domElement = domDocument.createComment( viewNode.getCustomProperty( '$rawContent' ) );
389
+ domElement = this._domDocument.createComment( viewNode.getCustomProperty( '$rawContent' ) );
383
390
  } else {
384
391
  // UIElement has its own render() method (see #799).
385
- domElement = viewNode.render( domDocument, this );
392
+ domElement = viewNode.render( this._domDocument, this );
386
393
  }
387
394
 
388
395
  if ( options.bind ) {
@@ -397,9 +404,9 @@ export default class DomConverter {
397
404
 
398
405
  domElement = this._createReplacementDomElement( viewNode.name );
399
406
  } else if ( viewNode.hasAttribute( 'xmlns' ) ) {
400
- domElement = domDocument.createElementNS( viewNode.getAttribute( 'xmlns' ), viewNode.name );
407
+ domElement = this._domDocument.createElementNS( viewNode.getAttribute( 'xmlns' ), viewNode.name );
401
408
  } else {
402
- domElement = domDocument.createElement( viewNode.name );
409
+ domElement = this._domDocument.createElement( viewNode.name );
403
410
  }
404
411
 
405
412
  // RawElement take care of their children in RawElement#render() method which can be customized
@@ -419,7 +426,7 @@ export default class DomConverter {
419
426
  }
420
427
 
421
428
  if ( options.withChildren !== false ) {
422
- for ( const child of this.viewChildrenToDom( viewNode, domDocument, options ) ) {
429
+ for ( const child of this.viewChildrenToDom( viewNode, options ) ) {
423
430
  domElement.appendChild( child );
424
431
  }
425
432
  }
@@ -488,23 +495,22 @@ export default class DomConverter {
488
495
  * Additionally, this method adds block {@link module:engine/view/filler filler} to the list of children, if needed.
489
496
  *
490
497
  * @param {module:engine/view/element~Element|module:engine/view/documentfragment~DocumentFragment} viewElement Parent view element.
491
- * @param {Document} domDocument Document which will be used to create DOM nodes.
492
498
  * @param {Object} options See {@link module:engine/view/domconverter~DomConverter#viewToDom} options parameter.
493
499
  * @returns {Iterable.<Node>} DOM nodes.
494
500
  */
495
- * viewChildrenToDom( viewElement, domDocument, options = {} ) {
501
+ * viewChildrenToDom( viewElement, options = {} ) {
496
502
  const fillerPositionOffset = viewElement.getFillerOffset && viewElement.getFillerOffset();
497
503
  let offset = 0;
498
504
 
499
505
  for ( const childView of viewElement.getChildren() ) {
500
506
  if ( fillerPositionOffset === offset ) {
501
- yield this._getBlockFiller( domDocument );
507
+ yield this._getBlockFiller();
502
508
  }
503
509
 
504
510
  const transparentRendering = childView.is( 'element' ) && childView.getCustomProperty( 'dataPipeline:transparentRendering' );
505
511
 
506
512
  if ( transparentRendering && this.renderingMode == 'data' ) {
507
- yield* this.viewChildrenToDom( childView, domDocument, options );
513
+ yield* this.viewChildrenToDom( childView, options );
508
514
  } else {
509
515
  if ( transparentRendering ) {
510
516
  /**
@@ -515,14 +521,14 @@ export default class DomConverter {
515
521
  logWarning( 'domconverter-transparent-rendering-unsupported-in-editing-pipeline', { viewElement: childView } );
516
522
  }
517
523
 
518
- yield this.viewToDom( childView, domDocument, options );
524
+ yield this.viewToDom( childView, options );
519
525
  }
520
526
 
521
527
  offset++;
522
528
  }
523
529
 
524
530
  if ( fillerPositionOffset === offset ) {
525
- yield this._getBlockFiller( domDocument );
531
+ yield this._getBlockFiller();
526
532
  }
527
533
  }
528
534
 
@@ -537,7 +543,7 @@ export default class DomConverter {
537
543
  const domStart = this.viewPositionToDom( viewRange.start );
538
544
  const domEnd = this.viewPositionToDom( viewRange.end );
539
545
 
540
- const domRange = document.createRange();
546
+ const domRange = this._domDocument.createRange();
541
547
  domRange.setStart( domStart.parent, domStart.offset );
542
548
  domRange.setEnd( domEnd.parent, domEnd.offset );
543
549
 
@@ -1099,7 +1105,7 @@ export default class DomConverter {
1099
1105
 
1100
1106
  // Since it takes multiple lines of code to check whether a "DOM Position" is before/after another "DOM Position",
1101
1107
  // we will use the fact that range will collapse if it's end is before it's start.
1102
- const range = document.createRange();
1108
+ const range = this._domDocument.createRange();
1103
1109
 
1104
1110
  range.setStart( selection.anchorNode, selection.anchorOffset );
1105
1111
  range.setEnd( selection.focusNode, selection.focusOffset );
@@ -1174,17 +1180,16 @@ export default class DomConverter {
1174
1180
  * Returns the block {@link module:engine/view/filler filler} node based on the current {@link #blockFillerMode} setting.
1175
1181
  *
1176
1182
  * @private
1177
- * @params {Document} domDocument
1178
1183
  * @returns {Node} filler
1179
1184
  */
1180
- _getBlockFiller( domDocument ) {
1185
+ _getBlockFiller() {
1181
1186
  switch ( this.blockFillerMode ) {
1182
1187
  case 'nbsp':
1183
- return NBSP_FILLER( domDocument ); // eslint-disable-line new-cap
1188
+ return NBSP_FILLER( this._domDocument ); // eslint-disable-line new-cap
1184
1189
  case 'markedNbsp':
1185
- return MARKED_NBSP_FILLER( domDocument ); // eslint-disable-line new-cap
1190
+ return MARKED_NBSP_FILLER( this._domDocument ); // eslint-disable-line new-cap
1186
1191
  case 'br':
1187
- return BR_FILLER( domDocument ); // eslint-disable-line new-cap
1192
+ return BR_FILLER( this._domDocument ); // eslint-disable-line new-cap
1188
1193
  }
1189
1194
  }
1190
1195
 
@@ -1585,7 +1590,7 @@ export default class DomConverter {
1585
1590
  * @returns {Element}
1586
1591
  */
1587
1592
  _createReplacementDomElement( elementName, originalDomElement = null ) {
1588
- const newDomElement = document.createElement( 'span' );
1593
+ const newDomElement = this._domDocument.createElement( 'span' );
1589
1594
 
1590
1595
  // Mark the span replacing a script as hidden.
1591
1596
  newDomElement.setAttribute( UNSAFE_ELEMENT_REPLACEMENT_ATTRIBUTE, elementName );
@@ -229,13 +229,17 @@ export default class Renderer {
229
229
  this.markedChildren.add( inlineFillerPosition.parent );
230
230
  }
231
231
  }
232
- // Paranoid check: we make sure the inline filler has any parent so it can be mapped to view position
233
- // by DomConverter.
232
+ // Make sure the inline filler has any parent, so it can be mapped to view position by DomConverter.
234
233
  else if ( this._inlineFiller && this._inlineFiller.parentNode ) {
235
234
  // While the user is making selection, preserve the inline filler at its original position.
236
235
  inlineFillerPosition = this.domConverter.domPositionToView( this._inlineFiller );
237
236
 
238
- if ( inlineFillerPosition.parent.is( '$text' ) ) {
237
+ // While down-casting the document selection attributes, all existing empty
238
+ // attribute elements (for selection position) are removed from the view and DOM,
239
+ // so make sure that we were able to map filler position.
240
+ // https://github.com/ckeditor/ckeditor5/issues/12026
241
+ if ( inlineFillerPosition && inlineFillerPosition.parent.is( '$text' ) ) {
242
+ // The inline filler position is expected to be before the text node.
239
243
  inlineFillerPosition = ViewPosition._createBefore( inlineFillerPosition.parent );
240
244
  }
241
245
  }
@@ -318,7 +322,7 @@ export default class Renderer {
318
322
  this.domConverter.mapViewToDom( viewElement ).childNodes
319
323
  );
320
324
  const expectedDomChildren = Array.from(
321
- this.domConverter.viewChildrenToDom( viewElement, domElement.ownerDocument, { withChildren: false } )
325
+ this.domConverter.viewChildrenToDom( viewElement, { withChildren: false } )
322
326
  );
323
327
  const diff = this._diffNodeLists( actualDomChildren, expectedDomChildren );
324
328
  const actions = this._findReplaceActions( diff, actualDomChildren, expectedDomChildren );
@@ -514,7 +518,7 @@ export default class Renderer {
514
518
  */
515
519
  _updateText( viewText, options ) {
516
520
  const domText = this.domConverter.findCorrespondingDomText( viewText );
517
- const newDomText = this.domConverter.viewToDom( viewText, domText.ownerDocument );
521
+ const newDomText = this.domConverter.viewToDom( viewText );
518
522
 
519
523
  const actualText = domText.data;
520
524
  let expectedText = newDomText.data;
@@ -593,7 +597,7 @@ export default class Renderer {
593
597
  const inlineFillerPosition = options.inlineFillerPosition;
594
598
  const actualDomChildren = this.domConverter.mapViewToDom( viewElement ).childNodes;
595
599
  const expectedDomChildren = Array.from(
596
- this.domConverter.viewChildrenToDom( viewElement, domElement.ownerDocument, { bind: true } )
600
+ this.domConverter.viewChildrenToDom( viewElement, { bind: true } )
597
601
  );
598
602
 
599
603
  // Inline filler element has to be created as it is present in the DOM, but not in the view. It is required