Skip to content
This repository was archived by the owner on Jun 26, 2020. It is now read-only.

Commit f56bddf

Browse files
author
Piotr Jasiun
authored
Merge pull request #1216 from ckeditor/t/1207
Other: Refactored events fired by model classes. Closes #1207.
2 parents b1333dc + 61538d1 commit f56bddf

35 files changed

+1201
-1117
lines changed

src/controller/editingcontroller.js

Lines changed: 4 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
*/
99

1010
import RootEditableElement from '../view/rooteditableelement';
11-
import ModelDiffer from '../model/differ';
1211
import ViewDocument from '../view/document';
1312
import Mapper from '../conversion/mapper';
1413
import ModelConversionDispatcher from '../conversion/modelconversiondispatcher';
@@ -84,47 +83,15 @@ export default class EditingController {
8483
viewSelection: this.view.selection
8584
} );
8685

87-
// Model differ object. It's role is to buffer changes done on model and then calculates a diff of those changes.
88-
// The diff is then passed to model conversion dispatcher which generates proper events and kicks-off conversion.
89-
const modelDiffer = new ModelDiffer();
90-
91-
// Before an operation is applied on model, buffer the change in differ.
92-
this.listenTo( this.model, 'applyOperation', ( evt, args ) => {
93-
const operation = args[ 0 ];
94-
95-
if ( operation.isDocumentOperation ) {
96-
modelDiffer.bufferOperation( operation );
97-
}
98-
}, { priority: 'high' } );
99-
100-
// Buffer marker changes.
101-
// This is not covered in buffering operations because markers may change outside of them (when they
102-
// are modified using `model.document.markers` collection, not through `MarkerOperation`).
103-
this.listenTo( this.model.markers, 'add', ( evt, marker ) => {
104-
// Whenever a new marker is added, buffer that change.
105-
modelDiffer.bufferMarkerChange( marker.name, null, marker.getRange() );
106-
107-
// Whenever marker changes, buffer that.
108-
marker.on( 'change', ( evt, oldRange ) => {
109-
modelDiffer.bufferMarkerChange( marker.name, oldRange, marker.getRange() );
110-
} );
111-
} );
112-
113-
this.listenTo( this.model.markers, 'remove', ( evt, marker ) => {
114-
// Whenever marker is removed, buffer that change.
115-
modelDiffer.bufferMarkerChange( marker.name, marker.getRange(), null );
116-
} );
86+
const doc = this.model.document;
11787

11888
// When all changes are done, get the model diff containing all the changes and convert them to view and then render to DOM.
119-
this.listenTo( this.model, 'changesDone', () => {
89+
this.listenTo( doc, 'change', () => {
12090
// Convert changes stored in `modelDiffer`.
121-
this.modelToView.convertChanges( modelDiffer );
122-
123-
// Reset model diff object. When next operation is applied, new diff will be created.
124-
modelDiffer.reset();
91+
this.modelToView.convertChanges( doc.differ );
12592

12693
// After the view is ready, convert selection from model to view.
127-
this.modelToView.convertSelection( this.model.document.selection );
94+
this.modelToView.convertSelection( doc.selection );
12895

12996
// When everything is converted to the view, render it to DOM.
13097
this.view.render();

src/conversion/modelconversiondispatcher.js

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -135,11 +135,6 @@ export default class ModelConversionDispatcher {
135135

136136
// Convert changes that happened on model tree.
137137
for ( const entry of differ.getChanges() ) {
138-
// Skip all the changes that happens in graveyard. These are not converted.
139-
if ( _isInGraveyard( entry ) ) {
140-
continue;
141-
}
142-
143138
if ( entry.type == 'insert' ) {
144139
this.convertInsert( Range.createFromPositionAndShift( entry.position, entry.length ) );
145140
} else if ( entry.type == 'remove' ) {
@@ -596,9 +591,3 @@ function shouldMarkerChangeBeConverted( modelPosition, marker, mapper ) {
596591

597592
return !hasCustomHandling;
598593
}
599-
600-
// Checks whether entry change describes changes that happen in graveyard.
601-
function _isInGraveyard( entry ) {
602-
return ( entry.position && entry.position.root.rootName == '$graveyard' ) ||
603-
( entry.range && entry.range.root.rootName == '$graveyard' );
604-
}

src/dev-utils/enableenginedebug.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -656,7 +656,8 @@ class DebugPlugin extends Plugin {
656656
constructor( editor ) {
657657
super( editor );
658658

659-
const modelDocument = this.editor.model.document;
659+
const model = this.editor.model;
660+
const modelDocument = model.document;
660661
const viewDocument = this.editor.editing.view;
661662

662663
modelDocument[ treeDump ] = [];
@@ -665,11 +666,11 @@ class DebugPlugin extends Plugin {
665666
dumpTrees( modelDocument, modelDocument.version );
666667
dumpTrees( viewDocument, modelDocument.version );
667668

668-
modelDocument.on( 'change', () => {
669+
model.on( 'applyOperation', () => {
669670
dumpTrees( modelDocument, modelDocument.version );
670671
}, { priority: 'lowest' } );
671672

672-
modelDocument.on( 'changesDone', () => {
673+
model.document.on( 'change', () => {
673674
dumpTrees( viewDocument, modelDocument.version );
674675
}, { priority: 'lowest' } );
675676
}

src/model/differ.js

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,40 @@ export default class Differ {
6161
* @type {Number}
6262
*/
6363
this._changeCount = 0;
64+
65+
/**
66+
* For efficiency purposes, `Differ` stores the change set returned by the differ after {@link #getChanges} call.
67+
* Cache is reset each time a new operation is buffered. If the cache has not been reset, {@link #getChanges} will
68+
* return the cached value instead of calculating it again.
69+
*
70+
* This property stores those changes that did not take place in graveyard root.
71+
*
72+
* @private
73+
* @type {Array.<Object>|null}
74+
*/
75+
this._cachedChanges = null;
76+
77+
/**
78+
* For efficiency purposes, `Differ` stores the change set returned by the differ after {@link #getChanges} call.
79+
* Cache is reset each time a new operation is buffered. If the cache has not been reset, {@link #getChanges} will
80+
* return the cached value instead of calculating it again.
81+
*
82+
* This property stores all changes evaluated by `Differ`, also those that took place in graveyard.
83+
*
84+
* @private
85+
* @type {Array.<Object>|null}
86+
*/
87+
this._cachedChangesWithGraveyard = null;
88+
}
89+
90+
/**
91+
* Informs whether there are any changes buffered in `Differ`.
92+
*
93+
* @readonly
94+
* @type {Boolean}
95+
*/
96+
get isEmpty() {
97+
return this._changesInElement.size == 0 && this._changedMarkers.size == 0;
6498
}
6599

66100
/**
@@ -98,6 +132,9 @@ export default class Differ {
98132

99133
break;
100134
}
135+
136+
// Clear cache after each buffered operation as it is no longer valid.
137+
this._cachedChanges = null;
101138
}
102139

103140
/**
@@ -168,9 +205,24 @@ export default class Differ {
168205
* the position on which the change happened. If a position {@link module:engine/model/position~Position#isBefore is before}
169206
* another one, it will be on an earlier index in the diff set.
170207
*
208+
* Because calculating diff is a costly operation, the result is cached. If no new operation was buffered since the
209+
* previous {@link #getChanges} call, the next call with return the cached value.
210+
*
211+
* @param {Object} options Additional options.
212+
* @param {Boolean} [options.includeChangesInGraveyard=false] If set to `true`, also changes that happened
213+
* in graveyard root will be returned. By default, changes in graveyard root are not returned.
171214
* @returns {Array.<Object>} Diff between old and new model tree state.
172215
*/
173-
getChanges() {
216+
getChanges( options = { includeChangesInGraveyard: false } ) {
217+
// If there are cached changes, just return them instead of calculating changes again.
218+
if ( this._cachedChanges ) {
219+
if ( options.includeChangesInGraveyard ) {
220+
return this._cachedChangesWithGraveyard.slice();
221+
} else {
222+
return this._cachedChanges.slice();
223+
}
224+
}
225+
174226
// Will contain returned results.
175227
const diffSet = [];
176228

@@ -320,7 +372,15 @@ export default class Differ {
320372

321373
this._changeCount = 0;
322374

323-
return diffSet;
375+
// Cache changes.
376+
this._cachedChangesWithGraveyard = diffSet.slice();
377+
this._cachedChanges = diffSet.slice().filter( _changesInGraveyardFilter );
378+
379+
if ( options.includeChangesInGraveyard ) {
380+
return this._cachedChangesWithGraveyard;
381+
} else {
382+
return this._cachedChanges;
383+
}
324384
}
325385

326386
/**
@@ -330,6 +390,7 @@ export default class Differ {
330390
this._changesInElement.clear();
331391
this._elementSnapshots.clear();
332392
this._changedMarkers.clear();
393+
this._cachedChanges = null;
333394
}
334395

335396
/**
@@ -865,3 +926,11 @@ function _generateActionsFromChanges( oldChildrenLength, changes ) {
865926

866927
return actions;
867928
}
929+
930+
// Filter callback for Array.filter that filters out change entries that are in graveyard.
931+
function _changesInGraveyardFilter( entry ) {
932+
const posInGy = entry.position && entry.position.root.rootName == '$graveyard';
933+
const rangeInGy = entry.range && entry.range.root.rootName == '$graveyard';
934+
935+
return !posInGy && !rangeInGy;
936+
}

0 commit comments

Comments
 (0)