Przeglądaj źródła

Merge branch 'master' into t/1210

Szymon Kupś 8 lat temu
rodzic
commit
e556ad051a
100 zmienionych plików z 552 dodań i 415 usunięć
  1. 1 1
      packages/ckeditor5-engine/.eslintrc.js
  2. 1 1
      packages/ckeditor5-engine/LICENSE.md
  3. 1 1
      packages/ckeditor5-engine/src/controller/datacontroller.js
  4. 5 38
      packages/ckeditor5-engine/src/controller/editingcontroller.js
  5. 1 1
      packages/ckeditor5-engine/src/conversion/buildmodelconverter.js
  6. 1 1
      packages/ckeditor5-engine/src/conversion/buildviewconverter.js
  7. 1 1
      packages/ckeditor5-engine/src/conversion/definition-based-converters.js
  8. 1 1
      packages/ckeditor5-engine/src/conversion/mapper.js
  9. 1 1
      packages/ckeditor5-engine/src/conversion/model-selection-to-view-converters.js
  10. 1 1
      packages/ckeditor5-engine/src/conversion/model-to-view-converters.js
  11. 1 1
      packages/ckeditor5-engine/src/conversion/modelconsumable.js
  12. 1 12
      packages/ckeditor5-engine/src/conversion/modelconversiondispatcher.js
  13. 1 1
      packages/ckeditor5-engine/src/conversion/view-selection-to-model-converters.js
  14. 1 1
      packages/ckeditor5-engine/src/conversion/view-to-model-converters.js
  15. 1 1
      packages/ckeditor5-engine/src/conversion/viewconsumable.js
  16. 1 1
      packages/ckeditor5-engine/src/conversion/viewconversiondispatcher.js
  17. 1 1
      packages/ckeditor5-engine/src/dataprocessor/basichtmlwriter.js
  18. 1 1
      packages/ckeditor5-engine/src/dataprocessor/dataprocessor.jsdoc
  19. 1 1
      packages/ckeditor5-engine/src/dataprocessor/htmldataprocessor.js
  20. 1 1
      packages/ckeditor5-engine/src/dataprocessor/htmlwriter.js
  21. 1 1
      packages/ckeditor5-engine/src/dataprocessor/xmldataprocessor.js
  22. 1 1
      packages/ckeditor5-engine/src/dev-utils/deltareplayer.js
  23. 5 4
      packages/ckeditor5-engine/src/dev-utils/enableenginedebug.js
  24. 1 1
      packages/ckeditor5-engine/src/dev-utils/model.js
  25. 1 1
      packages/ckeditor5-engine/src/dev-utils/view.js
  26. 1 1
      packages/ckeditor5-engine/src/model/batch.js
  27. 1 1
      packages/ckeditor5-engine/src/model/delta/attributedelta.js
  28. 1 1
      packages/ckeditor5-engine/src/model/delta/basic-deltas.js
  29. 1 1
      packages/ckeditor5-engine/src/model/delta/basic-transformations.js
  30. 1 1
      packages/ckeditor5-engine/src/model/delta/delta.js
  31. 1 1
      packages/ckeditor5-engine/src/model/delta/deltafactory.js
  32. 1 1
      packages/ckeditor5-engine/src/model/delta/insertdelta.js
  33. 1 1
      packages/ckeditor5-engine/src/model/delta/markerdelta.js
  34. 1 1
      packages/ckeditor5-engine/src/model/delta/mergedelta.js
  35. 1 1
      packages/ckeditor5-engine/src/model/delta/movedelta.js
  36. 1 1
      packages/ckeditor5-engine/src/model/delta/removedelta.js
  37. 1 1
      packages/ckeditor5-engine/src/model/delta/renamedelta.js
  38. 1 1
      packages/ckeditor5-engine/src/model/delta/rootattributedelta.js
  39. 1 1
      packages/ckeditor5-engine/src/model/delta/splitdelta.js
  40. 1 1
      packages/ckeditor5-engine/src/model/delta/transform.js
  41. 1 1
      packages/ckeditor5-engine/src/model/delta/unwrapdelta.js
  42. 1 1
      packages/ckeditor5-engine/src/model/delta/weakinsertdelta.js
  43. 1 1
      packages/ckeditor5-engine/src/model/delta/wrapdelta.js
  44. 72 3
      packages/ckeditor5-engine/src/model/differ.js
  45. 126 61
      packages/ckeditor5-engine/src/model/document.js
  46. 1 1
      packages/ckeditor5-engine/src/model/documentfragment.js
  47. 41 15
      packages/ckeditor5-engine/src/model/documentselection.js
  48. 1 1
      packages/ckeditor5-engine/src/model/element.js
  49. 1 1
      packages/ckeditor5-engine/src/model/history.js
  50. 1 1
      packages/ckeditor5-engine/src/model/item.jsdoc
  51. 33 13
      packages/ckeditor5-engine/src/model/liveposition.js
  52. 29 14
      packages/ckeditor5-engine/src/model/liverange.js
  53. 1 1
      packages/ckeditor5-engine/src/model/markercollection.js
  54. 129 116
      packages/ckeditor5-engine/src/model/model.js
  55. 1 1
      packages/ckeditor5-engine/src/model/node.js
  56. 1 1
      packages/ckeditor5-engine/src/model/nodelist.js
  57. 1 3
      packages/ckeditor5-engine/src/model/operation/attributeoperation.js
  58. 2 4
      packages/ckeditor5-engine/src/model/operation/detachoperation.js
  59. 2 4
      packages/ckeditor5-engine/src/model/operation/insertoperation.js
  60. 1 3
      packages/ckeditor5-engine/src/model/operation/markeroperation.js
  61. 2 7
      packages/ckeditor5-engine/src/model/operation/moveoperation.js
  62. 1 5
      packages/ckeditor5-engine/src/model/operation/nooperation.js
  63. 2 4
      packages/ckeditor5-engine/src/model/operation/operation.js
  64. 1 1
      packages/ckeditor5-engine/src/model/operation/operationfactory.js
  65. 1 8
      packages/ckeditor5-engine/src/model/operation/reinsertoperation.js
  66. 1 8
      packages/ckeditor5-engine/src/model/operation/removeoperation.js
  67. 1 3
      packages/ckeditor5-engine/src/model/operation/renameoperation.js
  68. 1 3
      packages/ckeditor5-engine/src/model/operation/rootattributeoperation.js
  69. 1 1
      packages/ckeditor5-engine/src/model/operation/transform.js
  70. 1 1
      packages/ckeditor5-engine/src/model/operation/utils.js
  71. 1 1
      packages/ckeditor5-engine/src/model/position.js
  72. 1 1
      packages/ckeditor5-engine/src/model/range.js
  73. 1 1
      packages/ckeditor5-engine/src/model/rootelement.js
  74. 13 4
      packages/ckeditor5-engine/src/model/schema.js
  75. 1 1
      packages/ckeditor5-engine/src/model/selection.js
  76. 1 1
      packages/ckeditor5-engine/src/model/text.js
  77. 1 1
      packages/ckeditor5-engine/src/model/textproxy.js
  78. 1 1
      packages/ckeditor5-engine/src/model/treewalker.js
  79. 1 1
      packages/ckeditor5-engine/src/model/utils/deletecontent.js
  80. 1 1
      packages/ckeditor5-engine/src/model/utils/getselectedcontent.js
  81. 1 1
      packages/ckeditor5-engine/src/model/utils/insertcontent.js
  82. 1 1
      packages/ckeditor5-engine/src/model/utils/modifyselection.js
  83. 5 3
      packages/ckeditor5-engine/src/model/writer.js
  84. 1 1
      packages/ckeditor5-engine/src/view/attributeelement.js
  85. 1 1
      packages/ckeditor5-engine/src/view/containerelement.js
  86. 1 3
      packages/ckeditor5-engine/src/view/document.js
  87. 1 1
      packages/ckeditor5-engine/src/view/documentfragment.js
  88. 1 1
      packages/ckeditor5-engine/src/view/domconverter.js
  89. 1 1
      packages/ckeditor5-engine/src/view/editableelement.js
  90. 1 1
      packages/ckeditor5-engine/src/view/element.js
  91. 1 1
      packages/ckeditor5-engine/src/view/emptyelement.js
  92. 1 1
      packages/ckeditor5-engine/src/view/filler.js
  93. 1 1
      packages/ckeditor5-engine/src/view/item.jsdoc
  94. 1 1
      packages/ckeditor5-engine/src/view/matcher.js
  95. 1 1
      packages/ckeditor5-engine/src/view/node.js
  96. 1 1
      packages/ckeditor5-engine/src/view/observer/clickobserver.js
  97. 1 1
      packages/ckeditor5-engine/src/view/observer/domeventdata.js
  98. 1 1
      packages/ckeditor5-engine/src/view/observer/domeventobserver.js
  99. 1 1
      packages/ckeditor5-engine/src/view/observer/fakeselectionobserver.js
  100. 1 1
      packages/ckeditor5-engine/src/view/observer/focusobserver.js

+ 1 - 1
packages/ckeditor5-engine/.eslintrc.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/LICENSE.md

@@ -2,7 +2,7 @@ Software License Agreement
 ==========================
 
 **CKEditor 5 Editing Engine** – https://github.com/ckeditor/ckeditor5-engine <br>
-Copyright (c) 2003-2017, [CKSource](http://cksource.com) Frederico Knabben. All rights reserved.
+Copyright (c) 2003-2018, [CKSource](http://cksource.com) Frederico Knabben. All rights reserved.
 
 Licensed under the terms of any of the following licenses at your choice:
 

+ 1 - 1
packages/ckeditor5-engine/src/controller/datacontroller.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 5 - 38
packages/ckeditor5-engine/src/controller/editingcontroller.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 
@@ -8,7 +8,6 @@
  */
 
 import RootEditableElement from '../view/rooteditableelement';
-import ModelDiffer from '../model/differ';
 import View from '../view/view';
 import Mapper from '../conversion/mapper';
 import ModelConversionDispatcher from '../conversion/modelconversiondispatcher';
@@ -84,47 +83,15 @@ export default class EditingController {
 			viewSelection: this.view.document.selection
 		} );
 
-		// Model differ object. It's role is to buffer changes done on model and then calculates a diff of those changes.
-		// The diff is then passed to model conversion dispatcher which generates proper events and kicks-off conversion.
-		const modelDiffer = new ModelDiffer();
-
-		// Before an operation is applied on model, buffer the change in differ.
-		this.listenTo( this.model, 'applyOperation', ( evt, args ) => {
-			const operation = args[ 0 ];
-
-			if ( operation.isDocumentOperation ) {
-				modelDiffer.bufferOperation( operation );
-			}
-		}, { priority: 'high' } );
-
-		// Buffer marker changes.
-		// This is not covered in buffering operations because markers may change outside of them (when they
-		// are modified using `model.document.markers` collection, not through `MarkerOperation`).
-		this.listenTo( this.model.markers, 'add', ( evt, marker ) => {
-			// Whenever a new marker is added, buffer that change.
-			modelDiffer.bufferMarkerChange( marker.name, null, marker.getRange() );
-
-			// Whenever marker changes, buffer that.
-			marker.on( 'change', ( evt, oldRange ) => {
-				modelDiffer.bufferMarkerChange( marker.name, oldRange, marker.getRange() );
-			} );
-		} );
-
-		this.listenTo( this.model.markers, 'remove', ( evt, marker ) => {
-			// Whenever marker is removed, buffer that change.
-			modelDiffer.bufferMarkerChange( marker.name, marker.getRange(), null );
-		} );
+		const doc = this.model.document;
 
 		// When all changes are done, get the model diff containing all the changes and convert them to view and then render to DOM.
-		this.listenTo( this.model, 'changesDone', () => {
+		this.listenTo( doc, 'change', () => {
 			// Convert changes stored in `modelDiffer`.
-			this.modelToView.convertChanges( modelDiffer );
-
-			// Reset model diff object. When next operation is applied, new diff will be created.
-			modelDiffer.reset();
+			this.modelToView.convertChanges( doc.differ );
 
 			// After the view is ready, convert selection from model to view.
-			this.modelToView.convertSelection( this.model.document.selection );
+			this.modelToView.convertSelection( doc.selection );
 
 			// When everything is converted to the view, render it to DOM.
 			this.view.render();

+ 1 - 1
packages/ckeditor5-engine/src/conversion/buildmodelconverter.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/conversion/buildviewconverter.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/conversion/definition-based-converters.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/conversion/mapper.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/conversion/model-selection-to-view-converters.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/conversion/model-to-view-converters.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/conversion/modelconsumable.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 12
packages/ckeditor5-engine/src/conversion/modelconversiondispatcher.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 
@@ -135,11 +135,6 @@ export default class ModelConversionDispatcher {
 
 		// Convert changes that happened on model tree.
 		for ( const entry of differ.getChanges() ) {
-			// Skip all the changes that happens in graveyard. These are not converted.
-			if ( _isInGraveyard( entry ) ) {
-				continue;
-			}
-
 			if ( entry.type == 'insert' ) {
 				this.convertInsert( Range.createFromPositionAndShift( entry.position, entry.length ) );
 			} else if ( entry.type == 'remove' ) {
@@ -596,9 +591,3 @@ function shouldMarkerChangeBeConverted( modelPosition, marker, mapper ) {
 
 	return !hasCustomHandling;
 }
-
-// Checks whether entry change describes changes that happen in graveyard.
-function _isInGraveyard( entry ) {
-	return ( entry.position && entry.position.root.rootName == '$graveyard' ) ||
-		( entry.range && entry.range.root.rootName == '$graveyard' );
-}

+ 1 - 1
packages/ckeditor5-engine/src/conversion/view-selection-to-model-converters.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/conversion/view-to-model-converters.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/conversion/viewconsumable.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/conversion/viewconversiondispatcher.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/dataprocessor/basichtmlwriter.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/dataprocessor/dataprocessor.jsdoc

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/dataprocessor/htmldataprocessor.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/dataprocessor/htmlwriter.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/dataprocessor/xmldataprocessor.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/dev-utils/deltareplayer.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 5 - 4
packages/ckeditor5-engine/src/dev-utils/enableenginedebug.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 
@@ -656,7 +656,8 @@ class DebugPlugin extends Plugin {
 	constructor( editor ) {
 		super( editor );
 
-		const modelDocument = this.editor.model.document;
+		const model = this.editor.model;
+		const modelDocument = model.document;
 		const viewDocument = this.editor.editing.view;
 
 		modelDocument[ treeDump ] = [];
@@ -665,11 +666,11 @@ class DebugPlugin extends Plugin {
 		dumpTrees( modelDocument, modelDocument.version );
 		dumpTrees( viewDocument, modelDocument.version );
 
-		modelDocument.on( 'change', () => {
+		model.on( 'applyOperation', () => {
 			dumpTrees( modelDocument, modelDocument.version );
 		}, { priority: 'lowest' } );
 
-		modelDocument.on( 'changesDone', () => {
+		model.document.on( 'change', () => {
 			dumpTrees( viewDocument, modelDocument.version );
 		}, { priority: 'lowest' } );
 	}

+ 1 - 1
packages/ckeditor5-engine/src/dev-utils/model.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/dev-utils/view.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/model/batch.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/model/delta/attributedelta.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/model/delta/basic-deltas.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/model/delta/basic-transformations.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/model/delta/delta.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/model/delta/deltafactory.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/model/delta/insertdelta.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/model/delta/markerdelta.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/model/delta/mergedelta.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/model/delta/movedelta.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/model/delta/removedelta.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/model/delta/renamedelta.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/model/delta/rootattributedelta.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/model/delta/splitdelta.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/model/delta/transform.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/model/delta/unwrapdelta.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/model/delta/weakinsertdelta.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/model/delta/wrapdelta.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 72 - 3
packages/ckeditor5-engine/src/model/differ.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 
@@ -61,6 +61,40 @@ export default class Differ {
 		 * @type {Number}
 		 */
 		this._changeCount = 0;
+
+		/**
+		 * For efficiency purposes, `Differ` stores the change set returned by the differ after {@link #getChanges} call.
+		 * Cache is reset each time a new operation is buffered. If the cache has not been reset, {@link #getChanges} will
+		 * return the cached value instead of calculating it again.
+		 *
+		 * This property stores those changes that did not take place in graveyard root.
+		 *
+		 * @private
+		 * @type {Array.<Object>|null}
+		 */
+		this._cachedChanges = null;
+
+		/**
+		 * For efficiency purposes, `Differ` stores the change set returned by the differ after {@link #getChanges} call.
+		 * Cache is reset each time a new operation is buffered. If the cache has not been reset, {@link #getChanges} will
+		 * return the cached value instead of calculating it again.
+		 *
+		 * This property stores all changes evaluated by `Differ`, also those that took place in graveyard.
+		 *
+		 * @private
+		 * @type {Array.<Object>|null}
+		 */
+		this._cachedChangesWithGraveyard = null;
+	}
+
+	/**
+	 * Informs whether there are any changes buffered in `Differ`.
+	 *
+	 * @readonly
+	 * @type {Boolean}
+	 */
+	get isEmpty() {
+		return this._changesInElement.size == 0 && this._changedMarkers.size == 0;
 	}
 
 	/**
@@ -98,6 +132,9 @@ export default class Differ {
 
 				break;
 		}
+
+		// Clear cache after each buffered operation as it is no longer valid.
+		this._cachedChanges = null;
 	}
 
 	/**
@@ -168,9 +205,24 @@ export default class Differ {
 	 * the position on which the change happened. If a position {@link module:engine/model/position~Position#isBefore is before}
 	 * another one, it will be on an earlier index in the diff set.
 	 *
+	 * Because calculating diff is a costly operation, the result is cached. If no new operation was buffered since the
+	 * previous {@link #getChanges} call, the next call with return the cached value.
+	 *
+	 * @param {Object} options Additional options.
+	 * @param {Boolean} [options.includeChangesInGraveyard=false] If set to `true`, also changes that happened
+	 * in graveyard root will be returned. By default, changes in graveyard root are not returned.
 	 * @returns {Array.<Object>} Diff between old and new model tree state.
 	 */
-	getChanges() {
+	getChanges( options = { includeChangesInGraveyard: false } ) {
+		// If there are cached changes, just return them instead of calculating changes again.
+		if ( this._cachedChanges ) {
+			if ( options.includeChangesInGraveyard ) {
+				return this._cachedChangesWithGraveyard.slice();
+			} else {
+				return this._cachedChanges.slice();
+			}
+		}
+
 		// Will contain returned results.
 		const diffSet = [];
 
@@ -320,7 +372,15 @@ export default class Differ {
 
 		this._changeCount = 0;
 
-		return diffSet;
+		// Cache changes.
+		this._cachedChangesWithGraveyard = diffSet.slice();
+		this._cachedChanges = diffSet.slice().filter( _changesInGraveyardFilter );
+
+		if ( options.includeChangesInGraveyard ) {
+			return this._cachedChangesWithGraveyard;
+		} else {
+			return this._cachedChanges;
+		}
 	}
 
 	/**
@@ -330,6 +390,7 @@ export default class Differ {
 		this._changesInElement.clear();
 		this._elementSnapshots.clear();
 		this._changedMarkers.clear();
+		this._cachedChanges = null;
 	}
 
 	/**
@@ -865,3 +926,11 @@ function _generateActionsFromChanges( oldChildrenLength, changes ) {
 
 	return actions;
 }
+
+// Filter callback for Array.filter that filters out change entries that are in graveyard.
+function _changesInGraveyardFilter( entry ) {
+	const posInGy = entry.position && entry.position.root.rootName == '$graveyard';
+	const rangeInGy = entry.range && entry.range.root.rootName == '$graveyard';
+
+	return !posInGy && !rangeInGy;
+}

+ 126 - 61
packages/ckeditor5-engine/src/model/document.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 
@@ -7,6 +7,7 @@
  * @module engine/model/document
  */
 
+import Differ from './differ';
 import Range from './range';
 import Position from './position';
 import RootElement from './rootelement';
@@ -81,28 +82,26 @@ export default class Document {
 		 */
 		this.roots = new Collection( { idProperty: 'rootName' } );
 
-		// Add events that will ensure selection correctness.
-		this.selection.on( 'change:range', () => {
-			for ( const range of this.selection.getRanges() ) {
-				if ( !this._validateSelectionRange( range ) ) {
-					/**
-					 * Range from {@link module:engine/model/documentselection~DocumentSelection document selection}
-					 * starts or ends at incorrect position.
-					 *
-					 * @error document-selection-wrong-position
-					 * @param {module:engine/model/range~Range} range
-					 */
-					throw new CKEditorError(
-						'document-selection-wrong-position: Range from document selection starts or ends at incorrect position.',
-						{ range }
-					);
-				}
-			}
-		} );
+		/**
+		 * Model differ object. Its role is to buffer changes done on model document and then calculate a diff of those changes.
+		 *
+		 * @readonly
+		 * @member {module:engine/model/differ~Differ}
+		 */
+		this.differ = new Differ();
+
+		/**
+		 * Post-fixer callbacks registered to the model document.
+		 *
+		 * @private
+		 * @member {Set}
+		 */
+		this._postFixers = new Set();
 
 		// Graveyard tree root. Document always have a graveyard root, which stores removed nodes.
 		this.createRoot( '$root', graveyardName );
 
+		// First, if the operation is a document operation check if it's base version is correct.
 		this.listenTo( model, 'applyOperation', ( evt, args ) => {
 			const operation = args[ 0 ];
 
@@ -118,22 +117,67 @@ export default class Document {
 					{ operation }
 				);
 			}
-
-			operation._validate();
 		}, { priority: 'highest' } );
 
+		// Then, still before an operation is applied on model, buffer the change in differ.
+		this.listenTo( model, 'applyOperation', ( evt, args ) => {
+			const operation = args[ 0 ];
+
+			if ( operation.isDocumentOperation ) {
+				this.differ.bufferOperation( operation );
+			}
+		}, { priority: 'high' } );
+
+		// After the operation is applied, bump document's version and add the operation to the history.
 		this.listenTo( model, 'applyOperation', ( evt, args ) => {
 			const operation = args[ 0 ];
 
 			if ( operation.isDocumentOperation ) {
 				this.version++;
 				this.history.addDelta( operation.delta );
-				this.fire( 'change', operation.type, evt.return, operation.delta.batch, operation.delta.type );
 			}
 		}, { priority: 'low' } );
 
-		// Temporary compatibility.
-		model.delegate( 'changesDone' ).to( this );
+		// Listen to selection changes. If selection changed, mark it.
+		let hasSelectionChanged = false;
+
+		this.listenTo( this.selection, 'change', () => {
+			hasSelectionChanged = true;
+		} );
+
+		// Wait for `_change` event from model, which signalizes that outermost change block has finished.
+		// When this happens, check if there were any changes done on document, and if so, call post fixers,
+		// fire `change` event for features and conversion and then reset the differ.
+		this.listenTo( model, '_change', ( evt, writer ) => {
+			if ( !this.differ.isEmpty || hasSelectionChanged ) {
+				this._callPostFixers( writer );
+
+				this.fire( 'change', writer.batch );
+
+				this.differ.reset();
+				hasSelectionChanged = false;
+			}
+		} );
+
+		// Buffer marker changes.
+		// This is not covered in buffering operations because markers may change outside of them (when they
+		// are modified using `model.markers` collection, not through `MarkerOperation`).
+		this.listenTo( model.markers, 'add', ( evt, marker ) => {
+			// TODO: Should filter out changes of markers that are not in document.
+			// Whenever a new marker is added, buffer that change.
+			this.differ.bufferMarkerChange( marker.name, null, marker.getRange() );
+
+			// Whenever marker changes, buffer that.
+			marker.on( 'change', ( evt, oldRange ) => {
+				this.differ.bufferMarkerChange( marker.name, oldRange, marker.getRange() );
+			} );
+		} );
+
+		this.listenTo( model.markers, 'remove', ( evt, marker ) => {
+			// TODO: Should filter out changes of markers that are not in document.
+			// Whenever marker is removed, buffer that change.
+			this.differ.bufferMarkerChange( marker.name, marker.getRange(), null );
+		} );
 	}
 
 	/**
@@ -257,6 +301,44 @@ export default class Document {
 		return null;
 	}
 
+	/**
+	 * Used to register a post-fixer callback. Post-fixers mechanism guarantees that the features that listen to
+	 * {@link module:engine/model/model~Model#event:_change model's change event} will operate on a correct model state.
+	 *
+	 * Execution of a feature may lead to an incorrect document tree state. The callbacks are used to fix document tree after
+	 * it has changed. Post-fixers are fired just after all changes from the outermost change block were applied but
+	 * before {@link module:engine/model/document~Document#event:change} is fired. If a post-fixer callback made a change,
+	 * it should return `true`. When this happens, all post-fixers are fired again to check if something else should
+	 * not be fixed in the new document tree state.
+	 *
+	 * As a parameter, a post-fixer callback receives {@link module:engine/model/writer~Writer} instance connected with the executed
+	 * changes block. Thanks to that, all changes done by the callback will be added to the same {@link module:engine/model/batch~Batch}
+	 * (and undo step) as the original changes. This makes post-fixer changes transparent for the user.
+	 *
+	 * An example of a post-fixer is a callback that checks if all the data was removed from the editor. If so, the
+	 * callback should add an empty paragraph, so that the editor is never empty:
+	 *
+	 *		document.registerPostFixer( writer => {
+	 *			const changes = document.differ.getChanges();
+	 *
+	 *			// Check if the changes lead to an empty root in an editor.
+	 *			for ( const entry of changes ) {
+	 *				if ( entry.type == 'remove' && entry.position.root.isEmpty ) {
+	 *					writer.insertElement( 'paragraph', entry.position.root, 0 );
+	 *
+	 *					// It is fine to return early, even if multiple roots would need to be fixed.
+	 *					// All post-fixers will be fired again, so if there more empty roots, those will be fixed too.
+	 *					return true;
+	 *				}
+	 *			}
+	 *		} );
+	 *
+	 * @param {Function} postFixer
+	 */
+	registerPostFixer( postFixer ) {
+		this._postFixers.add( postFixer );
+	}
+
 	/**
 	 * Custom toJSON method to solve child-parent circular dependencies.
 	 *
@@ -320,48 +402,31 @@ export default class Document {
 	}
 
 	/**
-	 * Fired when document changes by applying an operation.
-	 *
-	 * There are several types of change:
+	 * Performs post-fixer loops. Executes post-fixer callbacks as long as neither of them has done any changes to model.
 	 *
-	 * * 'insert' when nodes are inserted,
-	 * * 'remove' when nodes are removed,
-	 * * 'reinsert' when remove is undone,
-	 * * 'move' when nodes are moved,
-	 * * 'rename' when element is renamed,
-	 * * 'marker' when a marker changes (added, removed or its range is changed),
-	 * * 'addAttribute' when attributes are added,
-	 * * 'removeAttribute' when attributes are removed,
-	 * * 'changeAttribute' when attributes change,
-	 * * 'addRootAttribute' when attribute for root is added,
-	 * * 'removeRootAttribute' when attribute for root is removed,
-	 * * 'changeRootAttribute' when attribute for root changes.
-	 *
-	 * @event change
-	 * @param {String} type Change type.
-	 * @param {Object} data Additional information about the change.
-	 * @param {module:engine/model/range~Range} [data.range] Range in model containing changed nodes. Note that the range state is
-	 * after changes has been done, i.e. for 'remove' the range will be in the {@link #graveyard graveyard root}.
-	 * The range is not defined for root, rename and marker types.
-	 * @param {module:engine/model/position~Position} [data.sourcePosition] Change source position.
-	 * Exists for 'remove', 'reinsert' and 'move'.
-	 * Note that this position state is before changes has been done, i.e. for 'reinsert' the source position will be in the
-	 * {@link #graveyard graveyard root}.
-	 * @param {String} [data.key] Only for attribute types. Key of changed / inserted / removed attribute.
-	 * @param {*} [data.oldValue] Only for 'removeAttribute', 'removeRootAttribute', 'changeAttribute' or
-	 * 'changeRootAttribute' type.
-	 * @param {*} [data.newValue] Only for 'addAttribute', 'addRootAttribute', 'changeAttribute' or
-	 * 'changeRootAttribute' type.
-	 * @param {module:engine/model/rootelement~RootElement} [data.root] Root element which attributes got changed. This is defined
-	 * only for root types.
-	 * @param {module:engine/model/batch~Batch} batch A {@link module:engine/model/batch~Batch batch}
-	 * of changes which this change is a part of.
+	 * @private
 	 */
+	_callPostFixers( writer ) {
+		let wasFixed = false;
+
+		do {
+			for ( const callback of this._postFixers ) {
+				wasFixed = callback( writer );
+
+				if ( wasFixed ) {
+					break;
+				}
+			}
+		} while ( wasFixed );
+	}
 
 	/**
-	 * Fired when all queued document changes are done. See {@link module:engine/model/model~Model#change}.
+	 * Fired after an {@link module:engine/model/model~Model#enqueueChange enqueueChange block} or the outermost
+	 * {@link module:engine/model/model~Model#change change block} has been executed and the document model tree was changed
+	 * during that block execution.
 	 *
-	 * @event changesDone
+	 * @event change
+	 * @param {@link module:engine/model/batch~Batch} batch Batch which was used in the executed changes block.
 	 */
 }
 

+ 1 - 1
packages/ckeditor5-engine/src/model/documentfragment.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 41 - 15
packages/ckeditor5-engine/src/model/documentselection.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 
@@ -84,22 +84,48 @@ export default class DocumentSelection extends Selection {
 		 */
 		this._attributePriority = new Map();
 
-		this.listenTo( this._document, 'change', ( evt, type, changes, batch ) => {
+		// Add events that will ensure selection correctness.
+		this.on( 'change:range', () => {
+			for ( const range of this.getRanges() ) {
+				if ( !this._document._validateSelectionRange( range ) ) {
+					/**
+					 * Range from {@link module:engine/model/documentselection~DocumentSelection document selection}
+					 * starts or ends at incorrect position.
+					 *
+					 * @error document-selection-wrong-position
+					 * @param {module:engine/model/range~Range} range
+					 */
+					throw new CKEditorError(
+						'document-selection-wrong-position: Range from document selection starts or ends at incorrect position.',
+						{ range }
+					);
+				}
+			}
+		} );
+
+		this.listenTo( this._model, 'applyOperation', ( evt, args ) => {
+			const operation = args[ 0 ];
+
+			if ( !operation.isDocumentOperation ) {
+				return;
+			}
+
 			// Whenever attribute operation is performed on document, update selection attributes.
 			// This is not the most efficient way to update selection attributes, but should be okay for now.
-			if ( attrOpTypes.has( type ) ) {
+			if ( attrOpTypes.has( operation.type ) ) {
 				this._updateAttributes( false );
 			}
 
+			const batch = operation.delta.batch;
+
 			// Batch may not be passed to the document#change event in some tests.
 			// See https://github.com/ckeditor/ckeditor5-engine/issues/1001#issuecomment-314202352
-			// Ignore also transparent batches because they are... transparent.
-			if ( batch && batch.type !== 'transparent' ) {
+			if ( batch ) {
 				// Whenever element which had selection's attributes stored in it stops being empty,
 				// the attributes need to be removed.
-				clearAttributesStoredInElement( changes, this._model, batch );
+				clearAttributesStoredInElement( operation, this._model, batch );
 			}
-		} );
+		}, { priority: 'low' } );
 	}
 
 	/**
@@ -710,10 +736,6 @@ export default class DocumentSelection extends Selection {
 	}
 }
 
-/**
- * @event change:attribute
- */
-
 // Helper function for {@link module:engine/model/documentselection~DocumentSelection#_updateAttributes}.
 //
 // It takes model item, checks whether it is a text node (or text proxy) and, if so, returns it's attributes. If not, returns `null`.
@@ -729,11 +751,15 @@ function getAttrsIfCharacter( node ) {
 }
 
 // Removes selection attributes from element which is not empty anymore.
-function clearAttributesStoredInElement( changes, model, batch ) {
-	const changeParent = changes.range && changes.range.start.parent;
+function clearAttributesStoredInElement( operation, model, batch ) {
+	let changeParent = null;
+
+	if ( operation.type == 'insert' ) {
+		changeParent = operation.position.parent;
+	} else if ( operation.type == 'move' || operation.type == 'reinsert' || operation.type == 'remove' ) {
+		changeParent = operation.getMovedRangeStart().parent;
+	}
 
-	// `changes.range` is not set in case of rename, root and marker operations.
-	// None of them may lead to the element becoming non-empty.
 	if ( !changeParent || changeParent.isEmpty ) {
 		return;
 	}

+ 1 - 1
packages/ckeditor5-engine/src/model/element.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/model/history.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/model/item.jsdoc

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 33 - 13
packages/ckeditor5-engine/src/model/liveposition.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 
@@ -140,14 +140,20 @@ function bindWithDocument() {
 	const supportedTypes = new Set( [ 'insert', 'move', 'remove', 'reinsert' ] );
 
 	this.listenTo(
-		this.root.document,
-		'change',
-		( event, type, changes ) => {
-			if ( supportedTypes.has( type ) ) {
-				transform.call( this, type, changes.range, changes.sourcePosition );
+		this.root.document.model,
+		'applyOperation',
+		( event, args ) => {
+			const operation = args[ 0 ];
+
+			if ( !operation.isDocumentOperation ) {
+				return;
+			}
+
+			if ( supportedTypes.has( operation.type ) ) {
+				transform.call( this, operation );
 			}
 		},
-		{ priority: 'high' }
+		{ priority: 'low' }
 	);
 }
 
@@ -157,16 +163,24 @@ function bindWithDocument() {
  * @ignore
  * @private
  * @method transform
- * @param {String} type Type of changes applied to the Tree Model.
- * @param {module:engine/model/range~Range} range Range containing the result of applied change.
- * @param {module:engine/model/position~Position} [position] Additional position parameter provided by some change events.
+ * @param {module:engine/model/operation/operation~Operation} operation Executed operation.
  */
-function transform( type, range, position ) {
+function transform( operation ) {
 	/* eslint-disable no-case-declarations */
+	let range;
+	let position;
+
+	if ( operation.type == 'insert' ) {
+		range = Range.createFromPositionAndShift( operation.position, operation.nodes.maxOffset );
+	} else {
+		range = Range.createFromPositionAndShift( operation.getMovedRangeStart(), operation.howMany );
+		position = operation.sourcePosition;
+	}
+
 	const howMany = range.end.offset - range.start.offset;
 	let transformed;
 
-	switch ( type ) {
+	switch ( operation.type ) {
 		case 'insert':
 			const insertBefore = this.stickiness == 'sticksToNext';
 			transformed = this._getTransformedByInsertion( range.start, howMany, insertBefore );
@@ -186,7 +200,13 @@ function transform( type, range, position ) {
 				transformed = this._getCombined( position, range.start );
 			} else {
 				const insertBefore = this.stickiness == 'sticksToNext';
-				transformed = this._getTransformedByMove( position, range.start, howMany, insertBefore );
+
+				// `Position._getTransformedByMove` is expecting `targetPosition` to be "before" move
+				// (before transformation). `range.start` is already after the move happened.
+				// We have to revert `targetPosition` to the state before the move.
+				const targetPosition = range.start._getTransformedByInsertion( position, howMany );
+
+				transformed = this._getTransformedByMove( position, targetPosition, howMany, insertBefore );
 			}
 			break;
 	}

+ 29 - 14
packages/ckeditor5-engine/src/model/liverange.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 
@@ -120,14 +120,20 @@ function bindWithDocument() {
 	const supportedTypes = new Set( [ 'insert', 'move', 'remove', 'reinsert' ] );
 
 	this.listenTo(
-		this.root.document,
-		'change',
-		( event, type, changes, batch, deltaType ) => {
-			if ( supportedTypes.has( type ) ) {
-				transform.call( this, type, deltaType, batch, changes.range, changes.sourcePosition );
+		this.root.document.model,
+		'applyOperation',
+		( event, args ) => {
+			const operation = args[ 0 ];
+
+			if ( !operation.isDocumentOperation ) {
+				return;
+			}
+
+			if ( supportedTypes.has( operation.type ) ) {
+				transform.call( this, operation );
 			}
 		},
-		{ priority: 'high' }
+		{ priority: 'low' }
 	);
 }
 
@@ -137,13 +143,22 @@ function bindWithDocument() {
  * @ignore
  * @private
  * @method transform
- * @param {String} [changeType] Type of change applied to the model document.
- * @param {String} [deltaType] Type of delta which introduced the change.
- * @param {module:engine/model/batch~Batch} batch Batch which changes the live range.
- * @param {module:engine/model/range~Range} targetRange Range containing the result of applied change.
- * @param {module:engine/model/position~Position} [sourcePosition] Source position for move, remove and reinsert change types.
+ * @param {module:engine/model/operation/operation~Operation} operation Executed operation.
  */
-function transform( changeType, deltaType, batch, targetRange, sourcePosition ) {
+function transform( operation ) {
+	const changeType = operation.type;
+	const batch = operation.delta.batch;
+
+	let targetRange;
+	let sourcePosition;
+
+	if ( changeType == 'insert' ) {
+		targetRange = Range.createFromPositionAndShift( operation.position, operation.nodes.maxOffset );
+	} else {
+		targetRange = Range.createFromPositionAndShift( operation.getMovedRangeStart(), operation.howMany );
+		sourcePosition = operation.sourcePosition;
+	}
+
 	const howMany = targetRange.end.offset - targetRange.start.offset;
 	let targetPosition = targetRange.start;
 
@@ -154,7 +169,7 @@ function transform( changeType, deltaType, batch, targetRange, sourcePosition )
 		targetPosition = targetPosition._getTransformedByInsertion( sourcePosition, howMany );
 	}
 
-	const result = this._getTransformedByDocumentChange( changeType, deltaType, targetPosition, howMany, sourcePosition );
+	const result = this._getTransformedByDocumentChange( changeType, operation.delta.type, targetPosition, howMany, sourcePosition );
 
 	// Decide whether moved part should be included in the range.
 	//

+ 1 - 1
packages/ckeditor5-engine/src/model/markercollection.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 129 - 116
packages/ckeditor5-engine/src/model/model.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 
@@ -28,10 +28,12 @@ import modifySelection from './utils/modifyselection';
 import getSelectedContent from './utils/getselectedcontent';
 
 /**
- * Editors data model class. Model defines all data: either nodes users see in editable roots, grouped as the
- * {@link module:engine/model/model~Model#document}, and all detached nodes, used to data manipulation. All of them are
- * created and modified by the {@link module:engine/model/writer~Writer}, which can be get using
- * {@link module:engine/model/model~Model#change} or {@link module:engine/model/model~Model#enqueueChange} methods.
+ * Editor's data model class. Model defines all the data: both nodes that are attached to the roots of the
+ * {@link module:engine/model/model~Model#document model document}, and also all detached nodes which has not been yet
+ * added to the document.
+ *
+ * All those nodes are created and modified by the {@link module:engine/model/writer~Writer model writer}, which can be
+ * accessed by using {@link module:engine/model/model~Model#change} or {@link module:engine/model/model~Model#enqueueChange} methods.
  *
  * @mixes module:utils/observablemixin~ObservableMixin
  */
@@ -46,6 +48,14 @@ export default class Model {
 		 */
 		this._pendingChanges = [];
 
+		/**
+		 * Models markers' collection.
+		 *
+		 * @readonly
+		 * @member {module:engine/model/markercollection~MarkerCollection}
+		 */
+		this.markers = new MarkerCollection();
+
 		/**
 		 * Editors document model.
 		 *
@@ -54,23 +64,31 @@ export default class Model {
 		this.document = new Document( this );
 
 		/**
-		 * Schema for editors model.
+		 * The last created and currently used writer instance.
 		 *
-		 * @member {module:engine/model/schema~Schema}
+		 * @private
+		 * @member {module:engine/model/writer~Writer}
 		 */
-		this.schema = new Schema();
+		this._currentWriter = null;
 
 		/**
-		 * Models markers' collection.
+		 * Schema for editors model.
 		 *
-		 * @readonly
-		 * @member {module:engine/model/markercollection~MarkerCollection}
+		 * @member {module:engine/model/schema~Schema}
 		 */
-		this.markers = new MarkerCollection();
+		this.schema = new Schema();
 
 		[ 'insertContent', 'deleteContent', 'modifySelection', 'getSelectedContent', 'applyOperation' ]
 			.forEach( methodName => this.decorate( methodName ) );
 
+		// Adding operation validation with `highest` priority, so it is called before any other feature would like
+		// to do anything with the operation. If the operation has incorrect parameters it should throw on the earliest occasion.
+		this.on( 'applyOperation', ( evt, args ) => {
+			const operation = args[ 0 ];
+
+			operation._validate();
+		}, { priority: 'highest' } );
+
 		// Register some default abstract entities.
 		this.schema.register( '$root', {
 			isLimit: true
@@ -91,26 +109,26 @@ export default class Model {
 
 	/**
 	 * Change method is the primary way of changing the model. You should use it to modify any node, including detached
-	 * nodes, not added to the {@link module:engine/model/model~Model#document}.
+	 * nodes (not added to the {@link module:engine/model/model~Model#document model document}).
 	 *
 	 *		model.change( writer => {
 	 *			writer.insertText( 'foo', paragraph, 'end' );
 	 *		} );
 	 *
-	 * All changes inside the change block use the same {@link module:engine/model/batch~Batch} so share the same
+	 * All changes inside the change block use the same {@link module:engine/model/batch~Batch} so they share the same
 	 * undo step.
 	 *
 	 *		model.change( writer => {
-	 *			writer.insertText( 'foo', paragraph, 'end' ); // foo
+	 *			writer.insertText( 'foo', paragraph, 'end' ); // foo.
 	 *
 	 *			model.change( writer => {
-	 *				writer.insertText( 'bar', paragraph, 'end' ); // foobar
+	 *				writer.insertText( 'bar', paragraph, 'end' ); // foobar.
 	 *			} );
 	 *
-	 * 			writer.insertText( 'bom', paragraph, 'end' ); // foobarbom
+	 * 			writer.insertText( 'bom', paragraph, 'end' ); // foobarbom.
 	 *		} );
 	 *
-	 * Change block is executed imminently.
+	 * Change block is executed immediately.
 	 *
 	 * You can also return a value from the change block.
 	 *
@@ -118,43 +136,43 @@ export default class Model {
 	 *			return writer.createElement( 'img' );
 	 *		} );
 	 *
-	 * When the outermost block is done the {@link #event:change} event is fired.
+	 * When the outermost block is done the {@link #event:_change} event is fired.
 	 *
 	 * @see #enqueueChange
-	 * @fires event:change
-	 * @fires event:changesDone
 	 * @param {Function} callback Callback function which may modify the model.
-	 * @returns {*} Value returned by the callback
+	 * @returns {*} Value returned by the callback.
 	 */
 	change( callback ) {
 		if ( this._pendingChanges.length === 0 ) {
+			// If this is the outermost block, create a new batch and start `_runPendingChanges` execution flow.
 			this._pendingChanges.push( { batch: new Batch(), callback } );
 
 			return this._runPendingChanges()[ 0 ];
 		} else {
+			// If this is not the outermost block, just execute the callback.
 			return callback( this._currentWriter );
 		}
 	}
 
 	/**
-	 * `enqueueChange` method is very similar to the {@link #change change method}, with two major differences.
+	 * `enqueueChange` method performs similar task as the {@link #change change method}, with two major differences.
 	 *
 	 * First, the callback of the `enqueueChange` is executed when all other changes are done. It might be executed
-	 * imminently if it is not nested in any other change block, but if it is nested in another change it will be delayed
-	 * and executed after the outermost block. If will be also executed after all previous `enqueueChange` blocks.
+	 * immediately if it is not nested in any other change block, but if it is nested in another (enqueue)change block,
+	 * it will be delayed and executed after the outermost block.
 	 *
 	 *		model.change( writer => {
 	 *			console.log( 1 );
 	 *
 	 *			model.enqueueChange( writer => {
-	 *				console.log( 3 );
+	 *				console.log( 2 );
 	 *			} );
 	 *
-	 * 			console.log( 2 );
-	 *		} );
+	 * 			console.log( 3 );
+	 *		} ); // Will log: 1, 3, 2.
 	 *
-	 * Second, it let you define the {@link module:engine/model/batch~Batch} to which you want to add your changes.
-	 * By default it creates a new batch, note that in the sample above `change` and `enqueueChange` blocks use a different
+	 * Second, it lets you define the {@link module:engine/model/batch~Batch} into which you want to add your changes.
+	 * By default, a new batch is created. In the sample above, `change` and `enqueueChange` blocks use a different
 	 * batch (and different {@link module:engine/model/writer~Writer} since each of them operates on the separate batch).
 	 *
 	 * Using `enqueueChange` block you can also add some changes to the batch you used before.
@@ -163,10 +181,10 @@ export default class Model {
 	 *			writer.insertText( 'foo', paragraph, 'end' );
 	 *		} );
 	 *
-	 * @fires event:change
-	 * @fires event:changesDone
+	 * `Batch` instance can be obtained from {@link module:engine/model/writer~Writer#batch the writer}.
+	 *
 	 * @param {module:engine/model/batch~Batch|String} batchOrType Batch or batch type should be used in the callback.
-	 * If not defined new batch will be created.
+	 * If not defined, a new batch will be created.
 	 * @param {Function} callback Callback function which may modify the model.
 	 */
 	enqueueChange( batchOrType, callback ) {
@@ -195,19 +213,21 @@ export default class Model {
 		const ret = [];
 
 		while ( this._pendingChanges.length ) {
-			this._currentWriter = new Writer( this, this._pendingChanges[ 0 ].batch );
+			// Create a new writer using batch instance created for this chain of changes.
+			const currentBatch = this._pendingChanges[ 0 ].batch;
+			this._currentWriter = new Writer( this, currentBatch );
 
-			ret.push( this._pendingChanges[ 0 ].callback( this._currentWriter ) );
+			// Execute changes callback and gather the returned value.
+			const callbackReturnValue = this._pendingChanges[ 0 ].callback( this._currentWriter );
+			ret.push( callbackReturnValue );
 
-			this.fire( 'change' );
+			// Fire internal `_change` event.
+			this.fire( '_change', this._currentWriter );
 
 			this._pendingChanges.shift();
-
 			this._currentWriter = null;
 		}
 
-		this.fire( 'changesDone' );
-
 		return ret;
 	}
 
@@ -216,11 +236,9 @@ export default class Model {
 	 * {@link module:engine/model/operation/operation~Operation operations} on the model.
 	 *
 	 * @param {module:engine/model/operation/operation~Operation} operation Operation to apply
-	 * @returns {Object} Object with additional information about the applied changes. It properties depends on the
-	 * operation type.
 	 */
 	applyOperation( operation ) {
-		return operation._execute();
+		operation._execute();
 	}
 
 	/**
@@ -324,89 +342,84 @@ export default class Model {
 	}
 
 	/**
-	 * Removes all events listeners set by model instance and destroy Document.
+	 * Removes all events listeners set by model instance and destroys {@link module:engine/model/document~Document}.
 	 */
 	destroy() {
 		this.document.destroy();
 		this.stopListening();
 	}
-}
 
-mix( Model, ObservableMixin );
-
-/**
- * Fired after leaving each {@link module:engine/model/model~Model#enqueueChange} block or outermost
- * {@link module:engine/model/model~Model#change} block.
- * Have the same parameters as {@link module:engine/model/model~Model#change}.
- *
- * @event change
- */
+	/**
+	 * Fired after leaving each {@link module:engine/model/model~Model#enqueueChange} block or outermost
+	 * {@link module:engine/model/model~Model#change} block.
+	 *
+	 * **Note:** This is an internal event! Use {@link module:engine/model/document~Document#event:change} instead.
+	 *
+	 * @protected
+	 * @event _change
+	 * @param {module:engine/model/writer~Writer} writer `Writer` instance that has been used in the change block.
+	 */
 
-/**
- * Fired when all queued model changes are done.
- *
- * @see #change
- * @see #enqueueChange
- * @event changesDone
- */
+	/**
+	 * Fired every time any {@link module:engine/model/operation/operation~Operation operation} is applied on the model
+	 * using {@link #applyOperation}.
+	 *
+	 * Note that this event is suitable only for very specific use-cases. Use it if you need to listen to every single operation
+	 * applied on the document. However, in most cases {@link module:engine/model/document~Document#event:change} should
+	 * be used.
+	 *
+	 * A few callbacks are already added to this event by engine internal classes:
+	 *
+	 * * with `highest` priority operation is validated,
+	 * * with `normal` priority operation is executed,
+	 * * with `low` priority the {@link module:engine/model/document~Document} updates its version,
+	 * * with `low` priority {@link module:engine/model/liveposition~LivePosition} and {@link module:engine/model/liverange~LiveRange}
+	 * update themselves.
+	 *
+	 * @event applyOperation
+	 * @param {Array} args Arguments of the `applyOperation` which is an array with a single element - applied
+	 * {@link module:engine/model/operation/operation~Operation operation}.
+	 */
 
-/**
- * Fired every time any {@link module:engine/model/operation/operation~Operation operation} is applied on the model
- * using {@link #applyOperation}.
- *
- * Note that this is an internal event for the specific use-cases. You can use it if you need to know about each operation
- * applied on the document, but in most cases {@link #change} event which is fired when all changes in a
- * {@link module:engine/model/batch~Batch} are applied, is a better choice.
- *
- * With the high priority operation is validated.
- *
- * With the normal priority operation is executed. After that priority you will be able to get additional
- * information about the applied changes returned by {@link module:engine/model/operation/operation~Operation#_execute}
- * as `evt.return`.
- *
- * With the low priority the {@link module:engine/model/document~Document} listen on this event and updates its version.
- *
- * @event applyOperation
- * @param {Array} args Arguments of the `applyOperation` which are an array with a single element:
- * {@link module:engine/model/operation/operation~Operation operation}.
- */
+	/**
+	 * Event fired when {@link #insertContent} method is called.
+	 *
+	 * The {@link #insertContent default action of that method} is implemented as a
+	 * listener to this event so it can be fully customized by the features.
+	 *
+	 * @event insertContent
+	 * @param {Array} args The arguments passed to the original method.
+	 */
 
-/**
- * Event fired when {@link #insertContent} method is called.
- *
- * The {@link #insertContent default action of that method} is implemented as a
- * listener to this event so it can be fully customized by the features.
- *
- * @event insertContent
- * @param {Array} args The arguments passed to the original method.
- */
+	/**
+	 * Event fired when {@link #deleteContent} method is called.
+	 *
+	 * The {@link #deleteContent default action of that method} is implemented as a
+	 * listener to this event so it can be fully customized by the features.
+	 *
+	 * @event deleteContent
+	 * @param {Array} args The arguments passed to the original method.
+	 */
 
-/**
- * Event fired when {@link #deleteContent} method is called.
- *
- * The {@link #deleteContent default action of that method} is implemented as a
- * listener to this event so it can be fully customized by the features.
- *
- * @event deleteContent
- * @param {Array} args The arguments passed to the original method.
- */
+	/**
+	 * Event fired when {@link #modifySelection} method is called.
+	 *
+	 * The {@link #modifySelection default action of that method} is implemented as a
+	 * listener to this event so it can be fully customized by the features.
+	 *
+	 * @event modifySelection
+	 * @param {Array} args The arguments passed to the original method.
+	 */
 
-/**
- * Event fired when {@link #modifySelection} method is called.
- *
- * The {@link #modifySelection default action of that method} is implemented as a
- * listener to this event so it can be fully customized by the features.
- *
- * @event modifySelection
- * @param {Array} args The arguments passed to the original method.
- */
+	/**
+	 * Event fired when {@link #getSelectedContent} method is called.
+	 *
+	 * The {@link #getSelectedContent default action of that method} is implemented as a
+	 * listener to this event so it can be fully customized by the features.
+	 *
+	 * @event getSelectedContent
+	 * @param {Array} args The arguments passed to the original method.
+	 */
+}
 
-/**
- * Event fired when {@link #getSelectedContent} method is called.
- *
- * The {@link #getSelectedContent default action of that method} is implemented as a
- * listener to this event so it can be fully customized by the features.
- *
- * @event getSelectedContent
- * @param {Array} args The arguments passed to the original method.
- */
+mix( Model, ObservableMixin );

+ 1 - 1
packages/ckeditor5-engine/src/model/node.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/model/nodelist.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 3
packages/ckeditor5-engine/src/model/operation/attributeoperation.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 
@@ -157,8 +157,6 @@ export default class AttributeOperation extends Operation {
 			// Execution.
 			_setAttribute( this.range, this.key, this.newValue );
 		}
-
-		return { range: this.range, key: this.key, oldValue: this.oldValue, newValue: this.newValue };
 	}
 
 	/**

+ 2 - 4
packages/ckeditor5-engine/src/model/operation/detachoperation.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 
@@ -78,9 +78,7 @@ export default class DetachOperation extends Operation {
 	 * @inheritDoc
 	 */
 	_execute() {
-		const nodes = _remove( Range.createFromPositionAndShift( this.sourcePosition, this.howMany ) );
-
-		return { nodes };
+		_remove( Range.createFromPositionAndShift( this.sourcePosition, this.howMany ) );
 	}
 
 	/**

+ 2 - 4
packages/ckeditor5-engine/src/model/operation/insertoperation.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 
@@ -113,9 +113,7 @@ export default class InsertOperation extends Operation {
 		const originalNodes = this.nodes;
 		this.nodes = new NodeList( [ ...originalNodes ].map( node => node.clone( true ) ) );
 
-		const range = _insert( this.position, originalNodes );
-
-		return { range };
+		_insert( this.position, originalNodes );
 	}
 
 	/**

+ 1 - 3
packages/ckeditor5-engine/src/model/operation/markeroperation.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 
@@ -112,8 +112,6 @@ export default class MarkerOperation extends Operation {
 		const type = this.newRange ? 'set' : 'remove';
 
 		this._markers[ type ]( this.name, this.newRange );
-
-		return { name: this.name, type };
 	}
 
 	/**

+ 2 - 7
packages/ckeditor5-engine/src/model/operation/moveoperation.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 
@@ -189,12 +189,7 @@ export default class MoveOperation extends Operation {
 	 * @inheritDoc
 	 */
 	_execute() {
-		const range = _move( Range.createFromPositionAndShift( this.sourcePosition, this.howMany ), this.targetPosition );
-
-		return {
-			sourcePosition: this.sourcePosition,
-			range
-		};
+		_move( Range.createFromPositionAndShift( this.sourcePosition, this.howMany ), this.targetPosition );
 	}
 
 	/**

+ 1 - 5
packages/ckeditor5-engine/src/model/operation/nooperation.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 
@@ -54,11 +54,7 @@ export default class NoOperation extends Operation {
 		return new NoOperation( this.baseVersion + 1 );
 	}
 
-	/**
-	 * @inheritDoc
-	 */
 	_execute() {
-		return {};
 	}
 
 	/**

+ 2 - 4
packages/ckeditor5-engine/src/model/operation/operation.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 
@@ -73,12 +73,10 @@ export default class Operation {
 		 */
 
 		/**
-		 * Executes the operation - modifications described by the operation attributes will be applied to the tree model.
+		 * Executes the operation - modifications described by the operation properties will be applied to the model tree.
 		 *
 		 * @protected
 		 * @method #_execute
-		 * @returns {Object} Object with additional information about the applied changes. It properties depends on the
-		 * operation type.
 		 */
 	}
 

+ 1 - 1
packages/ckeditor5-engine/src/model/operation/operationfactory.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 8
packages/ckeditor5-engine/src/model/operation/reinsertoperation.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 
@@ -82,13 +82,6 @@ export default class ReinsertOperation extends MoveOperation {
 		}
 	}
 
-	/**
-	 * @inheritDoc
-	 */
-	_execute() {
-		return super._execute();
-	}
-
 	/**
 	 * @inheritDoc
 	 */

+ 1 - 8
packages/ckeditor5-engine/src/model/operation/removeoperation.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 
@@ -67,13 +67,6 @@ export default class RemoveOperation extends MoveOperation {
 		}
 	}
 
-	/**
-	 * @inheritDoc
-	 */
-	_execute() {
-		return super._execute();
-	}
-
 	/**
 	 * @inheritDoc
 	 */

+ 1 - 3
packages/ckeditor5-engine/src/model/operation/renameoperation.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 
@@ -117,8 +117,6 @@ export default class RenameOperation extends Operation {
 		const element = this.position.nodeAfter;
 
 		element.name = this.newName;
-
-		return { element, oldName: this.oldName };
 	}
 
 	/**

+ 1 - 3
packages/ckeditor5-engine/src/model/operation/rootattributeoperation.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 
@@ -149,8 +149,6 @@ export default class RootAttributeOperation extends Operation {
 		} else {
 			this.root.removeAttribute( this.key );
 		}
-
-		return { root: this.root, key: this.key, oldValue: this.oldValue, newValue: this.newValue };
 	}
 
 	/**

+ 1 - 1
packages/ckeditor5-engine/src/model/operation/transform.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/model/operation/utils.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/model/position.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/model/range.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/model/rootelement.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 13 - 4
packages/ckeditor5-engine/src/model/schema.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 
@@ -871,12 +871,21 @@ export class SchemaContext {
 	 */
 	constructor( context ) {
 		if ( Array.isArray( context ) ) {
-			this._items = context.map( mapContextItem );
+			if ( context[ 0 ] && typeof context[ 0 ] != 'string' && context[ 0 ].is( 'documentFragment' ) ) {
+				context.shift();
+			}
 		}
-		// Item or position (PS. It's ok that Position#getAncestors() doesn't accept params).
 		else {
-			this._items = context.getAncestors( { includeSelf: true } ).map( mapContextItem );
+			// `context` is item or position.
+			// Position#getAncestors() doesn't accept any parameters but it works just fine here.
+			context = context.getAncestors( { includeSelf: true } );
+
+			if ( context[ 0 ].is( 'documentFragment' ) ) {
+				context.shift();
+			}
 		}
+
+		this._items = context.map( mapContextItem );
 	}
 
 	/**

+ 1 - 1
packages/ckeditor5-engine/src/model/selection.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/model/text.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/model/textproxy.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/model/treewalker.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/model/utils/deletecontent.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/model/utils/getselectedcontent.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/model/utils/insertcontent.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/model/utils/modifyselection.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 5 - 3
packages/ckeditor5-engine/src/model/writer.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 
@@ -68,11 +68,13 @@ export default class Writer {
 	 */
 	constructor( model, batch ) {
 		/**
+		 * @readonly
 		 * @type {module:engine/model/model~Model}
 		 */
 		this.model = model;
 
 		/**
+		 * @readonly
 		 * @type {module:engine/model/batch~Batch}
 		 */
 		this.batch = batch;
@@ -143,8 +145,8 @@ export default class Writer {
 	 * If you want to move {@link module:engine/model/range~Range range} instead of an
 	 * {@link module:engine/model/item~Item item} use {@link module:engine/model/writer~Writer#move move}.
 	 *
-	 * @param {module:engine/model/item~Item|module:engine/model/documentfragment~DocumentFragment}
-	 * item Item or document fragment to insert.
+	 * @param {module:engine/model/item~Item|module:engine/model/documentfragment~DocumentFragment} item Item or document
+	 * fragment to insert.
 	 * @param {module:engine/model/item~Item|module:engine/model/position~Position} itemOrPosition
 	 * @param {Number|'end'|'before'|'after'} [offset=0] Offset or one of the flags. Used only when
 	 * second parameter is a {@link module:engine/model/item~Item model item}.

+ 1 - 1
packages/ckeditor5-engine/src/view/attributeelement.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/view/containerelement.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 3
packages/ckeditor5-engine/src/view/document.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 
@@ -8,8 +8,6 @@
  */
 
 import Selection from './selection';
-import Renderer from './renderer';
-import DomConverter from './domconverter';
 import { injectQuirksHandling } from './filler';
 import { injectUiElementHandling } from './uielement';
 import log from '@ckeditor/ckeditor5-utils/src/log';

+ 1 - 1
packages/ckeditor5-engine/src/view/documentfragment.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/view/domconverter.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/view/editableelement.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/view/element.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/view/emptyelement.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/view/filler.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/view/item.jsdoc

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/view/matcher.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/view/node.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/view/observer/clickobserver.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/view/observer/domeventdata.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/view/observer/domeventobserver.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/view/observer/fakeselectionobserver.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-engine/src/view/observer/focusobserver.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików