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

Commit

Permalink
Changed: Aligned code to correctly use new model.Differ and refacto…
Browse files Browse the repository at this point in the history
…red `conversion.ModelConversionDispatcher`.
  • Loading branch information
scofalik committed Dec 14, 2017
1 parent 2f4759c commit 846519d
Show file tree
Hide file tree
Showing 13 changed files with 1,170 additions and 1,726 deletions.
2 changes: 1 addition & 1 deletion src/controller/datacontroller.js
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ export default class DataController {
const viewDocumentFragment = new ViewDocumentFragment();
this.mapper.bindElements( modelElementOrFragment, viewDocumentFragment );

this.modelToView.convertInsertion( modelRange );
this.modelToView.convertInsert( modelRange );

this.mapper.clearBindings();

Expand Down
62 changes: 43 additions & 19 deletions src/controller/editingcontroller.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
* @module engine/controller/editingcontroller
*/

import ModelDiffer from '../model/differ';
import ViewDocument from '../view/document';
import Mapper from '../conversion/mapper';
import ModelConversionDispatcher from '../conversion/modelconversiondispatcher';
Expand Down Expand Up @@ -64,10 +65,9 @@ export default class EditingController {
this.mapper = new Mapper();

/**
* Model to view conversion dispatcher, which converts changes from the model to
* {@link #view editing view}.
* Model to view conversion dispatcher, which converts changes from the model to {@link #view the editing view}.
*
* To attach model to view converter to the editing pipeline you need to add lister to this property:
* To attach model-to-view converter to the editing pipeline you need to add a listener to this dispatcher:
*
* editing.modelToView( 'insert:$element', customInsertConverter );
*
Expand All @@ -83,36 +83,60 @@ export default class EditingController {
viewSelection: this.view.selection
} );

// Convert changes in model to view.
this.listenTo( this.model.document, 'change', ( evt, type, changes ) => {
this.modelToView.convertChange( type, changes );
}, { priority: 'low' } );
// 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();

// Convert model selection to view.
this.listenTo( this.model.document, 'changesDone', () => {
const selection = this.model.document.selection;
// Before an operation is applied on model, buffer the change in differ.
this.listenTo( this.model, 'applyOperation', ( evt, args ) => {
const operation = args[ 0 ];

this.modelToView.convertSelection( selection );
this.view.render();
}, { priority: 'low' } );
if ( operation.isDocumentOperation ) {
modelDiffer.bufferOperation( operation );
}
}, { priority: 'high' } );

// Convert model markers changes.
// 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 ) => {
this.modelToView.convertMarker( 'addMarker', marker.name, marker.getRange() );
// 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 ) => {
this.modelToView.convertMarker( 'removeMarker', marker.name, marker.getRange() );
// Whenever marker is removed, buffer that change.
modelDiffer.bufferMarkerChange( marker.name, marker.getRange(), null );
} );

// Convert view selection to model.
// 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', () => {
// 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();

// After the view is ready, convert selection from model to view.
this.modelToView.convertSelection( this.model.document.selection );

// When everything is converted to the view, render it to DOM.
this.view.render();
}, { priority: 'low' } );

// Convert selection from view to model.
this.listenTo( this.view, 'selectionChange', convertSelectionChange( this.model, this.mapper ) );

// Attach default content converters.
// Attach default model converters.
this.modelToView.on( 'insert:$text', insertText(), { priority: 'lowest' } );
this.modelToView.on( 'remove', remove(), { priority: 'low' } );

// Attach default selection converters.
// Attach default model selection converters.
this.modelToView.on( 'selection', clearAttributes(), { priority: 'low' } );
this.modelToView.on( 'selection', clearFakeSelection(), { priority: 'low' } );
this.modelToView.on( 'selection', convertRangeSelection(), { priority: 'low' } );
Expand Down
29 changes: 11 additions & 18 deletions src/conversion/buildmodelconverter.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,12 @@
import {
insertElement,
insertUIElement,
setAttribute,
removeAttribute,
removeUIElement,
wrapItem,
unwrapItem,
changeAttribute,
wrap,
highlightText,
highlightElement
highlightElement,
removeHighlight
} from './model-to-view-converters';

import { convertSelectionAttribute, convertSelectionMarker } from './model-selection-to-view-converters';
Expand Down Expand Up @@ -254,15 +253,13 @@ class ModelConverterBuilder {

dispatcher.on( 'insert:' + this._from.name, insertElement( element ), { priority } );
} else if ( this._from.type == 'attribute' ) {
// From model attribute to view element -> wrap and unwrap.
// From model attribute to view element -> wrap.
element = typeof element == 'string' ? new ViewAttributeElement( element ) : element;

dispatcher.on( 'addAttribute:' + this._from.key, wrapItem( element ), { priority } );
dispatcher.on( 'changeAttribute:' + this._from.key, wrapItem( element ), { priority } );
dispatcher.on( 'removeAttribute:' + this._from.key, unwrapItem( element ), { priority } );

dispatcher.on( 'attribute:' + this._from.key, wrap( element ), { priority } );
dispatcher.on( 'selectionAttribute:' + this._from.key, convertSelectionAttribute( element ), { priority } );
} else { // From marker to element.
} else {
// From marker to element.
const priority = this._from.priority === null ? 'normal' : this._from.priority;

element = typeof element == 'string' ? new ViewUIElement( element ) : element;
Expand Down Expand Up @@ -326,12 +323,10 @@ class ModelConverterBuilder {
}

for ( const dispatcher of this._dispatchers ) {
// Separate converters for converting texts and elements inside marker's range.
dispatcher.on( 'addMarker:' + this._from.name, highlightText( highlightDescriptor ), { priority } );
dispatcher.on( 'addMarker:' + this._from.name, highlightElement( highlightDescriptor ), { priority } );

dispatcher.on( 'removeMarker:' + this._from.name, highlightText( highlightDescriptor ), { priority } );
dispatcher.on( 'removeMarker:' + this._from.name, highlightElement( highlightDescriptor ), { priority } );
dispatcher.on( 'removeMarker:' + this._from.name, removeHighlight( highlightDescriptor ), { priority } );

dispatcher.on( 'selectionMarker:' + this._from.name, convertSelectionMarker( highlightDescriptor ), { priority } );
}
Expand Down Expand Up @@ -383,7 +378,7 @@ class ModelConverterBuilder {

if ( !keyOrCreator ) {
// If `keyOrCreator` is not set, we assume default behavior which is 1:1 attribute re-write.
// This is also a default behavior for `setAttribute` converter when no attribute creator is passed.
// This is also a default behavior for `changeAttribute` converter when no attribute creator is passed.
attributeCreator = undefined;
} else if ( typeof keyOrCreator == 'string' ) {
// `keyOrCreator` is an attribute key.
Expand All @@ -407,9 +402,7 @@ class ModelConverterBuilder {
for ( const dispatcher of this._dispatchers ) {
const options = { priority: this._from.priority || 'normal' };

dispatcher.on( 'addAttribute:' + this._from.key, setAttribute( attributeCreator ), options );
dispatcher.on( 'changeAttribute:' + this._from.key, setAttribute( attributeCreator ), options );
dispatcher.on( 'removeAttribute:' + this._from.key, removeAttribute( attributeCreator ), options );
dispatcher.on( 'attribute:' + this._from.key, changeAttribute( attributeCreator ), options );
}
}
}
Expand Down
Loading

0 comments on commit 846519d

Please sign in to comment.