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

Commit

Permalink
Merge pull request #1613 from ckeditor/t/1556
Browse files Browse the repository at this point in the history
Enhancement: Expose conversion utilities. Closes #1556.

BREAKING CHANGE: The conversion.register() method now accepts single options object as a parameter.
BREAKING CHANGE: The downcastElementToElement() helper was removed from public API. Use conversion.for( 'downcast' ).elementToElement() instead.
BREAKING CHANGE: The downcastAttributeToElement() helper was removed from public API. Use conversion.for( 'downcast' ).attributeToElement() instead.
BREAKING CHANGE: The downcastAttributeToAttribute() helper was removed from public API. Use conversion.for( 'downcast' ).attributeToAttribute() instead.
BREAKING CHANGE: The downcastMarkerToElement() helper was removed from public API. Use conversion.for( 'downcast' ).markerToElement() instead.
BREAKING CHANGE: The downcastMarkerToHighlight() helper was removed from public API. Use conversion.for( 'downcast' ).markerToHighlight() instead.
BREAKING CHANGE: The upcastElementToElement() helper was removed from public API. Use conversion.for( 'upcast' ).elementToElement() instead.
BREAKING CHANGE: The upcastElementToAttribute() helper was removed from public API. Use conversion.for( 'upcast' ).elementToAttribute() instead.
BREAKING CHANGE: The upcastAttributeToAttribute() helper was removed from public API. Use conversion.for( 'upcast' ).attributeToAttribute() instead.
BREAKING CHANGE: The upcastElementToMarker() helper was removed from public API. Use conversion.for( 'upcast' ).elementToMarker() instead.
BREAKING CHANGE: The insertUIElement() and removeUIElement() downcast converters were removed from public API. Use conversion.for( 'downcast' ).markerToElement() instead.
BREAKING CHANGE: The highlightText(), highlightElement() and removeHighlight() downcast converters were removed from public API. Use conversion.for( 'downcast' ).markerToHighlight() instead.
BREAKING CHANGE: The insertElement() downcast converter was removed from public API. Use conversion.for( 'downcast' ).elementToElement() instead.
BREAKING CHANGE: The changeAttribute() downcast converter was removed from public API. Use conversion.for( 'downcast' ).attributeToAttribute() instead.
  • Loading branch information
Piotr Jasiun authored Dec 21, 2018
2 parents da5a390 + 49b8ad3 commit 9306c22
Show file tree
Hide file tree
Showing 23 changed files with 2,827 additions and 2,563 deletions.
4 changes: 2 additions & 2 deletions src/controller/datacontroller.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
import Mapper from '../conversion/mapper';

import DowncastDispatcher from '../conversion/downcastdispatcher';
import { insertText } from '../conversion/downcast-converters';
import { insertText } from '../conversion/downcasthelpers';

import UpcastDispatcher from '../conversion/upcastdispatcher';
import { convertText, convertToModelFragment } from '../conversion/upcast-converters';
import { convertText, convertToModelFragment } from '../conversion/upcasthelpers';

import ViewDocumentFragment from '../view/documentfragment';
import ViewDocument from '../view/document';
Expand Down
2 changes: 1 addition & 1 deletion src/controller/editingcontroller.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import RootEditableElement from '../view/rooteditableelement';
import View from '../view/view';
import Mapper from '../conversion/mapper';
import DowncastDispatcher from '../conversion/downcastdispatcher';
import { insertText, remove } from '../conversion/downcast-converters';
import { insertText, remove } from '../conversion/downcasthelpers';
import { convertSelectionChange } from '../conversion/upcast-selection-converters';
import { clearAttributes, convertCollapsedSelection, convertRangeSelection } from '../conversion/downcast-selection-converters';

Expand Down
191 changes: 105 additions & 86 deletions src/conversion/conversion.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,6 @@

import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';

import {
downcastElementToElement,
downcastAttributeToElement,
downcastAttributeToAttribute
} from './downcast-converters';

import {
upcastElementToElement,
upcastElementToAttribute,
upcastAttributeToAttribute
} from './upcast-converters';

/**
* A utility class that helps add converters to upcast and downcast dispatchers.
*
Expand All @@ -40,17 +28,18 @@ import {
* method:
*
* // Add a converter to editing downcast and data downcast.
* editor.conversion.for( 'downcast' ).add( downcastElementToElement( config ) );
* editor.conversion.for( 'downcast' ).elementToElement( config ) );
*
* // Add a converter to the data pipepline only:
* editor.conversion.for( 'dataDowncast' ).add( downcastElementToElement( dataConversionConfig ) );
* editor.conversion.for( 'dataDowncast' ).elementToElement( dataConversionConfig ) );
*
* // And a slightly different one for the editing pipeline:
* editor.conversion.for( 'editingDowncast' ).add( downcastElementToElement( editingConversionConfig ) );
* editor.conversion.for( 'editingDowncast' ).elementToElement( editingConversionConfig ) );
*
* The functions used in `add()` calls are one-way converters (i.e. you need to remember yourself to add
* a converter in the other direction, if your feature requires that). They are also called "conversion helpers".
* You can find a set of them in the {@link module:engine/conversion/downcast-converters} and
* {@link module:engine/conversion/upcast-converters} modules.
* You can find a set of them in the {@link module:engine/conversion/downcasthelpers} and
* {@link module:engine/conversion/upcasthelpers} modules.
*
* Besides allowing to register converters to specific dispatchers, you can also use methods available in this
* class to add two-way converters (upcast and downcast):
Expand Down Expand Up @@ -81,13 +70,17 @@ export default class Conversion {
* If a given group name is used for the second time, the
* {@link module:utils/ckeditorerror~CKEditorError `conversion-register-group-exists` error} is thrown.
*
* @param {String} groupName The name for dispatchers group.
* @param {Array.<module:engine/conversion/downcastdispatcher~DowncastDispatcher|
* module:engine/conversion/upcastdispatcher~UpcastDispatcher>} dispatchers Dispatchers to register
* @param {Object} options
* @param {String} options.name The name for dispatchers group.
* @param {module:engine/conversion/downcastdispatcher~DowncastDispatcher|
* module:engine/conversion/upcastdispatcher~UpcastDispatcher|Array.<module:engine/conversion/downcastdispatcher~DowncastDispatcher|
* module:engine/conversion/upcastdispatcher~UpcastDispatcher>} options.dispatcher Dispatcher or array of dispatchers to register
* under the given name.
* @param {module:engine/conversion/downcasthelpers~DowncastHelpers|
* module:engine/conversion/upcasthelpers~UpcastHelpers} helpers
*/
register( groupName, dispatchers ) {
if ( this._dispatchersGroups.has( groupName ) ) {
register( name, group ) {
if ( this._dispatchersGroups.has( name ) ) {
/**
* Trying to register a group name that was already registered.
*
Expand All @@ -96,16 +89,18 @@ export default class Conversion {
throw new CKEditorError( 'conversion-register-group-exists: Trying to register a group name that was already registered.' );
}

this._dispatchersGroups.set( groupName, dispatchers );
this._dispatchersGroups.set( name, group );
}

/**
* Provides chainable API to assign converters to dispatchers registered under a given group name. Converters are added
* by calling the `.add()` method of an object returned by this function.
* by calling the {@link module:engine/conversion/conversion~ConversionHelpers#add `.add()`} method of an
* {@link module:engine/conversion/conversion~ConversionHelpers conversion helpers} returned by this function.
*
* conversion.for( 'downcast' )
* .add( conversionHelperA )
* .add( conversionHelperB );
* editor.conversion.for( 'downcast' )
* .add( conversionHelperA ) // Adds a custom converter A.
* .add( conversionHelperB ) // Adds a custom converter B.
* .elementToElement( config ); // Adds a custom element-to-element downcast converter.
*
* In this example `conversionHelperA` and `conversionHelperB` will be called for all dispatchers from the `'model'` group.
*
Expand All @@ -117,43 +112,35 @@ export default class Conversion {
*
* For downcast (model-to-view conversion), these are:
*
* * {@link module:engine/conversion/downcast-converters~downcastElementToElement Downcast element-to-element converter},
* * {@link module:engine/conversion/downcast-converters~downcastAttributeToElement Downcast attribute-to-element converter},
* * {@link module:engine/conversion/downcast-converters~downcastAttributeToAttribute Downcast attribute-to-attribute converter}.
* * {@link module:engine/conversion/downcasthelpers~DowncastHelpers#elementToElement Downcast element-to-element converter},
* * {@link module:engine/conversion/downcasthelpers~DowncastHelpers#attributeToElement Downcast attribute-to-element converter},
* * {@link module:engine/conversion/downcasthelpers~DowncastHelpers#attributeToAttribute Downcast attribute-to-attribute converter}.
* * {@link module:engine/conversion/downcasthelpers~DowncastHelpers#markerToElement Downcast marker-to-element converter}.
* * {@link module:engine/conversion/downcasthelpers~DowncastHelpers#markerToHighlight Downcast marker-to-highlight converter}.
*
* For upcast (view-to-model conversion), these are:
*
* * {@link module:engine/conversion/upcast-converters~upcastElementToElement Upcast element-to-element converter},
* * {@link module:engine/conversion/upcast-converters~upcastElementToAttribute Upcast attribute-to-element converter},
* * {@link module:engine/conversion/upcast-converters~upcastAttributeToAttribute Upcast attribute-to-attribute converter}.
* * {@link module:engine/conversion/upcasthelpers~UpcastHelpers#elementToElement Upcast element-to-element converter},
* * {@link module:engine/conversion/upcasthelpers~UpcastHelpers#elementToAttribute Upcast attribute-to-element converter},
* * {@link module:engine/conversion/upcasthelpers~UpcastHelpers#attributeToAttribute Upcast attribute-to-attribute converter}.
* * {@link module:engine/conversion/upcasthelpers~UpcastHelpers#elementToMarker Upcast element-to-marker converter}.
*
* An example of using conversion helpers to convert the `paragraph` model element to the `p` view element (and back):
*
* // Define conversion configuration - model element 'paragraph' should be converted to view element 'p'.
* const config = { model: 'paragraph', view: 'p' };
*
* // Add converters to proper dispatchers using conversion helpers.
* conversion.for( 'downcast' ).add( downcastElementToElement( config ) );
* conversion.for( 'upcast' ).add( upcastElementToElement( config ) );
*
* An example of providing a custom conversion helper that uses a custom converter function:
*
* // Adding a custom `myConverter` converter for 'paragraph' element insertion, with the default priority ('normal').
* conversion.for( 'downcast' ).add( conversion.customConverter( 'insert:paragraph', myConverter ) );
* editor.conversion.for( 'downcast' ).elementToElement( config ) );
* editor.conversion.for( 'upcast' ).elementToElement( config ) );
*
* @param {String} groupName The name of dispatchers group to add the converters to.
* @returns {Object} An object with the `.add()` method, providing a way to add converters.
* @returns {module:engine/conversion/downcasthelpers~DowncastHelpers|module:engine/conversion/upcasthelpers~UpcastHelpers}
*/
for( groupName ) {
const dispatchers = this._getDispatchers( groupName );

return {
add( conversionHelper ) {
_addToDispatchers( dispatchers, conversionHelper );
const group = this._getDispatchersGroup( groupName );

return this;
}
};
return group;
}

/**
Expand Down Expand Up @@ -229,17 +216,16 @@ export default class Conversion {
*/
elementToElement( definition ) {
// Set up downcast converter.
this.for( 'downcast' ).add( downcastElementToElement( definition ) );
this.for( 'downcast' ).elementToElement( definition );

// Set up upcast converter.
for ( const { model, view } of _getAllUpcastDefinitions( definition ) ) {
this.for( 'upcast' ).add(
upcastElementToElement( {
this.for( 'upcast' )
.elementToElement( {
model,
view,
converterPriority: definition.converterPriority
} )
);
} );
}
}

Expand Down Expand Up @@ -402,17 +388,16 @@ export default class Conversion {
*/
attributeToElement( definition ) {
// Set up downcast converter.
this.for( 'downcast' ).add( downcastAttributeToElement( definition ) );
this.for( 'downcast' ).attributeToElement( definition );

// Set up upcast converter.
for ( const { model, view } of _getAllUpcastDefinitions( definition ) ) {
this.for( 'upcast' ).add(
upcastElementToAttribute( {
this.for( 'upcast' )
.elementToAttribute( {
view,
model,
converterPriority: definition.priority
} )
);
} );
}
}

Expand Down Expand Up @@ -528,34 +513,30 @@ export default class Conversion {
*/
attributeToAttribute( definition ) {
// Set up downcast converter.
this.for( 'downcast' ).add( downcastAttributeToAttribute( definition ) );
this.for( 'downcast' ).attributeToAttribute( definition );

// Set up upcast converter.
for ( const { model, view } of _getAllUpcastDefinitions( definition ) ) {
this.for( 'upcast' ).add(
upcastAttributeToAttribute( {
this.for( 'upcast' )
.attributeToAttribute( {
view,
model
} )
);
} );
}
}

/**
* Returns dispatchers registered under a given group name.
* Returns dispatchers group registered under a given group name.
*
* If the given group name has not been registered, the
* {@link module:utils/ckeditorerror~CKEditorError `conversion-for-unknown-group` error} is thrown.
*
* @private
* @param {String} groupName
* @returns {Array.<module:engine/conversion/downcastdispatcher~DowncastDispatcher|
* module:engine/conversion/upcastdispatcher~UpcastDispatcher>}
* @returns {module:engine/conversion/conversion~DispatchersGroup}
*/
_getDispatchers( groupName ) {
const dispatchers = this._dispatchersGroups.get( groupName );

if ( !dispatchers ) {
_getDispatchersGroup( groupName ) {
if ( !this._dispatchersGroups.has( groupName ) ) {
/**
* Trying to add a converter to an unknown dispatchers group.
*
Expand All @@ -564,7 +545,7 @@ export default class Conversion {
throw new CKEditorError( 'conversion-for-unknown-group: Trying to add a converter to an unknown dispatchers group.' );
}

return dispatchers;
return this._dispatchersGroups.get( groupName );
}
}

Expand All @@ -585,20 +566,13 @@ export default class Conversion {
* @property {module:utils/priorities~PriorityString} [converterPriority] The converter priority.
*/

// Helper function for the `Conversion` `.add()` method.
//
// Calls `conversionHelper` on each dispatcher from the group specified earlier in the `.for()` call, effectively
// adding converters to all specified dispatchers.
//
// @private
// @param {Array.<module:engine/conversion/downcastdispatcher~DowncastDispatcher|
// module:engine/conversion/upcastdispatcher~UpcastDispatcher>} dispatchers
// @param {Function} conversionHelper
function _addToDispatchers( dispatchers, conversionHelper ) {
for ( const dispatcher of dispatchers ) {
conversionHelper( dispatcher );
}
}
/**
* @typedef {Object} module:engine/conversion/conversion~DispatchersGroup
* @property {String} name Group name
* @property {Array.<module:engine/conversion/downcastdispatcher~DowncastDispatcher|
* module:engine/conversion/upcastdispatcher~UpcastDispatcher>} dispatchers
* @property {module:engine/conversion/downcasthelpers~DowncastHelpers|module:engine/conversion/upcasthelpers~UpcastHelpers} helpers
*/

// Helper function that creates a joint array out of an item passed in `definition.view` and items passed in
// `definition.upcastAlso`.
Expand Down Expand Up @@ -630,3 +604,48 @@ function* _getUpcastDefinition( model, view, upcastAlso ) {
}
}
}

/**
* Base class for conversion helpers.
*/
export class ConversionHelpers {
/**
* Creates ConversionHelpers instance.
*
* @param {Array.<module:engine/conversion/downcastdispatcher~DowncastDispatcher|
* module:engine/conversion/upcastdispatcher~UpcastDispatcher>} dispatcher
*/
constructor( dispatcher ) {
this._dispatchers = Array.isArray( dispatcher ) ? dispatcher : [ dispatcher ];
}

/**
* Registers a conversion helper.
*
* **Note**: See full usage example in the `{@link module:engine/conversion/conversion~Conversion#for conversion.for()}`
* method description
*
* @param {Function} conversionHelper The function to be called on event.
* @returns {module:engine/conversion/downcasthelpers~DowncastHelpers|module:engine/conversion/upcasthelpers~UpcastHelpers}
*/
add( conversionHelper ) {
this._addToDispatchers( conversionHelper );

return this;
}

/**
* Helper function for the `Conversion` `.add()` method.
*
* Calls `conversionHelper` on each dispatcher from the group specified earlier in the `.for()` call, effectively
* adding converters to all specified dispatchers.
*
* @private
* @param {Function} conversionHelper
*/
_addToDispatchers( conversionHelper ) {
for ( const dispatcher of this._dispatchers ) {
conversionHelper( dispatcher );
}
}
}
Loading

0 comments on commit 9306c22

Please sign in to comment.