|
@@ -7,13 +7,8 @@ import ModelRange from '../model/range';
|
|
|
import ModelSelection from '../model/selection';
|
|
import ModelSelection from '../model/selection';
|
|
|
import ModelElement from '../model/element';
|
|
import ModelElement from '../model/element';
|
|
|
|
|
|
|
|
-import ViewContainerElement from '../view/containerelement';
|
|
|
|
|
-import ViewUIElement from '../view/uielement';
|
|
|
|
|
-import ViewElement from '../view/element';
|
|
|
|
|
import ViewAttributeElement from '../view/attributeelement';
|
|
import ViewAttributeElement from '../view/attributeelement';
|
|
|
-import ViewText from '../view/text';
|
|
|
|
|
import ViewRange from '../view/range';
|
|
import ViewRange from '../view/range';
|
|
|
-import viewWriter from '../view/writer';
|
|
|
|
|
import DocumentSelection from '../model/documentselection';
|
|
import DocumentSelection from '../model/documentselection';
|
|
|
|
|
|
|
|
import cloneDeep from '@ckeditor/ckeditor5-utils/src/lib/lodash/cloneDeep';
|
|
import cloneDeep from '@ckeditor/ckeditor5-utils/src/lib/lodash/cloneDeep';
|
|
@@ -31,9 +26,7 @@ import cloneDeep from '@ckeditor/ckeditor5-utils/src/lib/lodash/cloneDeep';
|
|
|
*
|
|
*
|
|
|
* downcastElementToElement( { model: 'paragraph', view: 'p' } );
|
|
* downcastElementToElement( { model: 'paragraph', view: 'p' } );
|
|
|
*
|
|
*
|
|
|
- * downcastElementToElement( { model: 'paragraph', view: 'p' }, 'high' );
|
|
|
|
|
- *
|
|
|
|
|
- * downcastElementToElement( { model: 'paragraph', view: new ViewContainerElement( 'p' ) } );
|
|
|
|
|
|
|
+ * downcastElementToElement( { model: 'paragraph', view: 'div', priority: 'high' } );
|
|
|
*
|
|
*
|
|
|
* downcastElementToElement( {
|
|
* downcastElementToElement( {
|
|
|
* model: 'fancyParagraph',
|
|
* model: 'fancyParagraph',
|
|
@@ -45,27 +38,24 @@ import cloneDeep from '@ckeditor/ckeditor5-utils/src/lib/lodash/cloneDeep';
|
|
|
*
|
|
*
|
|
|
* downcastElementToElement( {
|
|
* downcastElementToElement( {
|
|
|
* model: 'heading',
|
|
* model: 'heading',
|
|
|
- * view: modelElement => new ViewContainerElement( 'h' + modelElement.getAttribute( 'level' ) )
|
|
|
|
|
|
|
+ * view: ( modelElement, viewWriter ) => viewWriter.createContainerElement( 'h' + modelElement.getAttribute( 'level' ) )
|
|
|
* } );
|
|
* } );
|
|
|
*
|
|
*
|
|
|
* See {@link module:engine/conversion/conversion~Conversion#for} to learn how to add converter to conversion process.
|
|
* See {@link module:engine/conversion/conversion~Conversion#for} to learn how to add converter to conversion process.
|
|
|
*
|
|
*
|
|
|
* @param {Object} config Conversion configuration.
|
|
* @param {Object} config Conversion configuration.
|
|
|
* @param {String} config.model Name of the model element to convert.
|
|
* @param {String} config.model Name of the model element to convert.
|
|
|
- * @param {String|module:engine/view/elementdefinition~ElementDefinition|Function|
|
|
|
|
|
- * module:engine/view/containerelement~ContainerElement} config.view View element name, or a view element definition,
|
|
|
|
|
- * or a function that takes model element as a parameter and returns a view container element,
|
|
|
|
|
- * or a view container element instance. The view element will be used then in conversion.
|
|
|
|
|
- * @param {module:utils/priorities~PriorityString} [priority='normal'] Converter priority.
|
|
|
|
|
|
|
+ * @param {module:engine/view/elementdefinition~ElementDefinition|Function} config.view View element definition or a function
|
|
|
|
|
+ * that takes model element and view writer as a parameters and returns a view container element.
|
|
|
* @returns {Function} Conversion helper.
|
|
* @returns {Function} Conversion helper.
|
|
|
*/
|
|
*/
|
|
|
-export function downcastElementToElement( config, priority = 'normal' ) {
|
|
|
|
|
|
|
+export function downcastElementToElement( config ) {
|
|
|
config = cloneDeep( config );
|
|
config = cloneDeep( config );
|
|
|
|
|
|
|
|
- _normalizeToElementConfig( config, ViewContainerElement );
|
|
|
|
|
|
|
+ config.view = _normalizeToElementConfig( config.view, 'container' );
|
|
|
|
|
|
|
|
return dispatcher => {
|
|
return dispatcher => {
|
|
|
- dispatcher.on( 'insert:' + config.model, insertElement( config.view ), { priority } );
|
|
|
|
|
|
|
+ dispatcher.on( 'insert:' + config.model, insertElement( config.view ), { priority: config.priority || 'normal' } );
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -75,74 +65,74 @@ export function downcastElementToElement( config, priority = 'normal' ) {
|
|
|
* This conversion results in wrapping view nodes in a view attribute element. For example, model text node with data
|
|
* This conversion results in wrapping view nodes in a view attribute element. For example, model text node with data
|
|
|
* `"Foo"` and `bold` attribute becomes `<strong>Foo</strong>` in the view.
|
|
* `"Foo"` and `bold` attribute becomes `<strong>Foo</strong>` in the view.
|
|
|
*
|
|
*
|
|
|
- * downcastAttributeToElement( 'bold', { view: 'strong' } );
|
|
|
|
|
- *
|
|
|
|
|
- * downcastAttributeToElement( 'bold', { view: 'strong' }, 'high' );
|
|
|
|
|
|
|
+ * downcastAttributeToElement( { model: 'bold', view: 'strong' } );
|
|
|
*
|
|
*
|
|
|
- * downcastAttributeToElement( 'bold', { view: new ViewAttributeElement( 'strong' ) } );
|
|
|
|
|
|
|
+ * downcastAttributeToElement( { model: 'bold', view: 'b', priority: 'high' } );
|
|
|
*
|
|
*
|
|
|
- * downcastAttributeToElement( 'bold', {
|
|
|
|
|
|
|
+ * downcastAttributeToElement( {
|
|
|
|
|
+ * model: 'invert',
|
|
|
* view: {
|
|
* view: {
|
|
|
* name: 'span',
|
|
* name: 'span',
|
|
|
- * class: 'bold'
|
|
|
|
|
|
|
+ * class: [ 'font-light', 'bg-dark' ]
|
|
|
* }
|
|
* }
|
|
|
* } );
|
|
* } );
|
|
|
*
|
|
*
|
|
|
- * downcastAttributeToElement( 'styled', {
|
|
|
|
|
- * model: 'dark',
|
|
|
|
|
|
|
+ * downcastAttributeToElement( {
|
|
|
|
|
+ * model: {
|
|
|
|
|
+ * key: 'fontSize',
|
|
|
|
|
+ * values: [ 'big', 'small' ]
|
|
|
|
|
+ * },
|
|
|
* view: {
|
|
* view: {
|
|
|
- * name: 'span',
|
|
|
|
|
- * class: [ 'styled', 'styled-dark' ]
|
|
|
|
|
- * }
|
|
|
|
|
- * } );
|
|
|
|
|
- *
|
|
|
|
|
- * downcastAttributeToElement( 'fontSize', [
|
|
|
|
|
- * {
|
|
|
|
|
- * model: 'big',
|
|
|
|
|
- * view: {
|
|
|
|
|
|
|
+ * big: {
|
|
|
* name: 'span',
|
|
* name: 'span',
|
|
|
* style: {
|
|
* style: {
|
|
|
* 'font-size': '1.2em'
|
|
* 'font-size': '1.2em'
|
|
|
* }
|
|
* }
|
|
|
- * }
|
|
|
|
|
- * },
|
|
|
|
|
- * {
|
|
|
|
|
- * model: 'small',
|
|
|
|
|
- * view: {
|
|
|
|
|
|
|
+ * },
|
|
|
|
|
+ * small: {
|
|
|
* name: 'span',
|
|
* name: 'span',
|
|
|
* style: {
|
|
* style: {
|
|
|
* 'font-size': '0.8em'
|
|
* 'font-size': '0.8em'
|
|
|
* }
|
|
* }
|
|
|
* }
|
|
* }
|
|
|
* }
|
|
* }
|
|
|
- * ] );
|
|
|
|
|
|
|
+ * } );
|
|
|
*
|
|
*
|
|
|
- * downcastAttributeToElement( 'bold', {
|
|
|
|
|
- * view: modelAttributeValue => new ViewAttributeElement( 'span', { style: 'font-weight:' + modelAttributeValue } )
|
|
|
|
|
|
|
+ * downcastAttributeToElement( {
|
|
|
|
|
+ * model: 'bold',
|
|
|
|
|
+ * view: ( modelAttributeValue, viewWriter ) => {
|
|
|
|
|
+ * return viewWriter.createAttributeElement( 'span', { style: 'font-weight:' + modelAttributeValue } );
|
|
|
|
|
+ * }
|
|
|
* } );
|
|
* } );
|
|
|
*
|
|
*
|
|
|
* See {@link module:engine/conversion/conversion~Conversion#for} to learn how to add converter to conversion process.
|
|
* See {@link module:engine/conversion/conversion~Conversion#for} to learn how to add converter to conversion process.
|
|
|
*
|
|
*
|
|
|
- * @param {String} modelAttributeKey The key of the attribute to convert.
|
|
|
|
|
- * @param {Object|Array.<Object>} config Conversion configuration. It is possible to provide multiple configurations in an array.
|
|
|
|
|
- * @param {*} [config.model] The value of the converted model attribute for which the `view` property is defined.
|
|
|
|
|
- * If omitted, the configuration item will be used as a "default" configuration when no other item matches the attribute value.
|
|
|
|
|
- * @param {String|module:engine/view/elementdefinition~ElementDefinition|Function|
|
|
|
|
|
- * module:engine/view/attributeelement~AttributeElement} config.view View element name, or a view element definition,
|
|
|
|
|
- * or a function that takes model element as a parameter and returns a view attribute element, or a view attribute element instance.
|
|
|
|
|
- * The view element will be used then in conversion.
|
|
|
|
|
- * @param {module:utils/priorities~PriorityString} [priority='normal'] Converter priority.
|
|
|
|
|
|
|
+ * @param {Object} config Conversion configuration.
|
|
|
|
|
+ * @param {String|Object} config.model Key of the attribute to convert from or a `{ key, values }` object. `values` is an array
|
|
|
|
|
+ * of `String`s with possible values if the model attribute is enumerable.
|
|
|
|
|
+ * @param {module:engine/view/elementdefinition~ElementDefinition|Function|Object} config.view View element definition or a function
|
|
|
|
|
+ * that takes model attribute value and view writer as parameters and returns a view attribute element. If `config.model.values` is
|
|
|
|
|
+ * given, `config.view` should be an object assigning values from `config.model.values` to view element definitions or functions.
|
|
|
|
|
+ * @param {module:utils/priorities~PriorityString} [config.priority='normal'] Converter priority.
|
|
|
* @returns {Function} Conversion helper.
|
|
* @returns {Function} Conversion helper.
|
|
|
*/
|
|
*/
|
|
|
-export function downcastAttributeToElement( modelAttributeKey, config, priority = 'normal' ) {
|
|
|
|
|
|
|
+export function downcastAttributeToElement( config ) {
|
|
|
config = cloneDeep( config );
|
|
config = cloneDeep( config );
|
|
|
|
|
|
|
|
- _normalizeToElementConfig( config, ViewAttributeElement );
|
|
|
|
|
|
|
+ const modelKey = config.model.key ? config.model.key : config.model;
|
|
|
|
|
|
|
|
- const elementCreator = _getCreatorForArrayConfig( config );
|
|
|
|
|
|
|
+ if ( config.model.values ) {
|
|
|
|
|
+ for ( const modelValue of config.model.values ) {
|
|
|
|
|
+ config.view[ modelValue ] = _normalizeToElementConfig( config.view[ modelValue ], 'attribute' );
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ config.view = _normalizeToElementConfig( config.view, 'attribute' );
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const elementCreator = _getFromAttributeCreator( config );
|
|
|
|
|
|
|
|
return dispatcher => {
|
|
return dispatcher => {
|
|
|
- dispatcher.on( 'attribute:' + modelAttributeKey, wrap( elementCreator ), { priority } );
|
|
|
|
|
|
|
+ dispatcher.on( 'attribute:' + modelKey, wrap( elementCreator ), { priority: config.priority || 'normal' } );
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -152,74 +142,75 @@ export function downcastAttributeToElement( modelAttributeKey, config, priority
|
|
|
* This conversion results in adding an attribute on a view node, basing on an attribute from a model node. For example,
|
|
* This conversion results in adding an attribute on a view node, basing on an attribute from a model node. For example,
|
|
|
* `<image src='foo.jpg'></image>` is converted to `<img src='foo.jpg'></img>`.
|
|
* `<image src='foo.jpg'></image>` is converted to `<img src='foo.jpg'></img>`.
|
|
|
*
|
|
*
|
|
|
- * downcastAttributeToAttribute( 'src' );
|
|
|
|
|
|
|
+ * downcastAttributeToAttribute( { model: 'source', view: 'src' } );
|
|
|
*
|
|
*
|
|
|
- * downcastAttributeToAttribute( 'source', { view: 'src' } );
|
|
|
|
|
|
|
+ * downcastAttributeToAttribute( { model: 'source', view: 'href', priority: 'high' } );
|
|
|
*
|
|
*
|
|
|
- * downcastAttributeToAttribute( 'source', { view: 'src' }, 'high' );
|
|
|
|
|
- *
|
|
|
|
|
- * downcastAttributeToAttribute( 'stylish', {
|
|
|
|
|
- * view: {
|
|
|
|
|
- * key: 'class',
|
|
|
|
|
- * value: 'styled'
|
|
|
|
|
- * }
|
|
|
|
|
|
|
+ * downcastAttributeToAttribute( {
|
|
|
|
|
+ * model: {
|
|
|
|
|
+ * name: 'image',
|
|
|
|
|
+ * key: 'source'
|
|
|
|
|
+ * },
|
|
|
|
|
+ * view: 'src'
|
|
|
* } );
|
|
* } );
|
|
|
*
|
|
*
|
|
|
- * downcastAttributeToAttribute( 'styled', {
|
|
|
|
|
- * model: 'dark',
|
|
|
|
|
|
|
+ * downcastAttributeToAttribute( {
|
|
|
|
|
+ * model: {
|
|
|
|
|
+ * name: 'styled',
|
|
|
|
|
+ * values: [ 'dark', 'light' ]
|
|
|
|
|
+ * },
|
|
|
* view: {
|
|
* view: {
|
|
|
- * key: 'class',
|
|
|
|
|
- * value: 'styled styled-dark'
|
|
|
|
|
- * }
|
|
|
|
|
- * } );
|
|
|
|
|
- *
|
|
|
|
|
- * downcastAttributeToAttribute( 'style', [
|
|
|
|
|
- * {
|
|
|
|
|
- * model: 'dark',
|
|
|
|
|
- * view: {
|
|
|
|
|
|
|
+ * dark: {
|
|
|
* key: 'class',
|
|
* key: 'class',
|
|
|
- * value: 'styled-dark'
|
|
|
|
|
- * }
|
|
|
|
|
- * },
|
|
|
|
|
- * {
|
|
|
|
|
- * model: 'light',
|
|
|
|
|
- * view: {
|
|
|
|
|
|
|
+ * value: [ 'styled', 'styled-dark' ]
|
|
|
|
|
+ * },
|
|
|
|
|
+ * light: {
|
|
|
* key: 'class',
|
|
* key: 'class',
|
|
|
- * value: 'styled-light'
|
|
|
|
|
|
|
+ * value: [ 'styled', 'styled-light' ]
|
|
|
* }
|
|
* }
|
|
|
* }
|
|
* }
|
|
|
- * ] );
|
|
|
|
|
|
|
+ * } );
|
|
|
*
|
|
*
|
|
|
- * downcastAttributeToAttribute( 'style', {
|
|
|
|
|
- * view: attributeValue => ( { key: 'class', value: 'style-' + attributeValue } )
|
|
|
|
|
|
|
+ * downcastAttributeToAttribute( {
|
|
|
|
|
+ * model: 'styled',
|
|
|
|
|
+ * view: modelAttributeValue => ( { key: 'class', value: 'styled-' + modelAttributeValue } )
|
|
|
* } );
|
|
* } );
|
|
|
*
|
|
*
|
|
|
* See {@link module:engine/conversion/conversion~Conversion#for} to learn how to add converter to conversion process.
|
|
* See {@link module:engine/conversion/conversion~Conversion#for} to learn how to add converter to conversion process.
|
|
|
*
|
|
*
|
|
|
- * @param {String} modelAttributeKey The key of the attribute to convert.
|
|
|
|
|
- * @param {Object|Array.<Object>} [config] Conversion configuration. It is possible to provide multiple configurations in an array.
|
|
|
|
|
- * If not set, the conversion helper will assume 1-to-1 conversion, that is the view attribute key and view attribute value
|
|
|
|
|
- * will be same as model attribute key and model attribute value.
|
|
|
|
|
- * @param {*} [config.model] The value of the converted model attribute for which the `view` property is defined.
|
|
|
|
|
- * If `true` is provided, the configuration item will be used as a "default" configuration when no other item matches
|
|
|
|
|
- * the attribute value.
|
|
|
|
|
- * @param {String|Object|Function} [config.view] View attribute key, or an object with `key` and `value` properties (both `String`),
|
|
|
|
|
- * or a function that takes model attribute value and returns an object with `key` and `value` properties (both `String`).
|
|
|
|
|
- * If nothing is passed, the view attribute key and value will be equal to the model attribute key and value.
|
|
|
|
|
- * If a `String` is passed, it will be used as view attribute key and view attribute value will be equal to model attribute value.
|
|
|
|
|
- * If an object or a function returning an object is passed, its properties will be used to set view attribute key and value.
|
|
|
|
|
- * @param {module:utils/priorities~PriorityString} [priority='normal'] Converter priority.
|
|
|
|
|
|
|
+ * @param {Object} config Conversion configuration.
|
|
|
|
|
+ * @param {String|Object} config.model Key of the attribute to convert from or a `{ key, values, [ name ] }` object describing
|
|
|
|
|
+ * the attribute key, possible values and, optionally, an element name to convert from.
|
|
|
|
|
+ * @param {String|Object|Function} config.view View attribute key, or a `{ key, value }` object or a function that takes
|
|
|
|
|
+ * model attribute value and returns a `{ key, value }` object. If `key` is `'class'`, `value` can be a `String` or an
|
|
|
|
|
+ * array of `String`s. If `key` is `'style'`, `value` is an object with key-value pairs. In other cases, `value` is a `String`.
|
|
|
|
|
+ * If `config.model.values` is set, `config.view` should be an object assigning values from `config.model.values` to
|
|
|
|
|
+ * `{ key, value }` objects or a functions.
|
|
|
|
|
+ * @param {module:utils/priorities~PriorityString} [config.priority='normal'] Converter priority.
|
|
|
* @returns {Function} Conversion helper.
|
|
* @returns {Function} Conversion helper.
|
|
|
*/
|
|
*/
|
|
|
-export function downcastAttributeToAttribute( modelAttributeKey, config = {}, priority = 'normal' ) {
|
|
|
|
|
|
|
+export function downcastAttributeToAttribute( config ) {
|
|
|
config = cloneDeep( config );
|
|
config = cloneDeep( config );
|
|
|
|
|
|
|
|
- _normalizeToAttributeConfig( modelAttributeKey, config );
|
|
|
|
|
|
|
+ const modelKey = config.model.key ? config.model.key : config.model;
|
|
|
|
|
+ let eventName = 'attribute:' + modelKey;
|
|
|
|
|
+
|
|
|
|
|
+ if ( config.model.name ) {
|
|
|
|
|
+ eventName += ':' + config.model.name;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if ( config.model.values ) {
|
|
|
|
|
+ for ( const modelValue of config.model.values ) {
|
|
|
|
|
+ config.view[ modelValue ] = _normalizeToAttributeConfig( config.view[ modelValue ] );
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ config.view = _normalizeToAttributeConfig( config.view );
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- const elementCreator = _getCreatorForArrayConfig( config );
|
|
|
|
|
|
|
+ const elementCreator = _getFromAttributeCreator( config );
|
|
|
|
|
|
|
|
return dispatcher => {
|
|
return dispatcher => {
|
|
|
- dispatcher.on( 'attribute:' + modelAttributeKey, changeAttribute( elementCreator ), { priority } );
|
|
|
|
|
|
|
+ dispatcher.on( eventName, changeAttribute( elementCreator ), { priority: config.priority || 'normal' } );
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -232,9 +223,7 @@ export function downcastAttributeToAttribute( modelAttributeKey, config = {}, pr
|
|
|
*
|
|
*
|
|
|
* downcastMarkerToElement( { model: 'search', view: 'marker-search' } );
|
|
* downcastMarkerToElement( { model: 'search', view: 'marker-search' } );
|
|
|
*
|
|
*
|
|
|
- * downcastMarkerToElement( { model: 'search', view: 'marker-search' }, 'high' );
|
|
|
|
|
- *
|
|
|
|
|
- * downcastMarkerToElement( { model: 'search', view: new ViewUIElement( 'span', { data-marker: 'search' } ) } );
|
|
|
|
|
|
|
+ * downcastMarkerToElement( { model: 'search', view: 'search-result', priority: 'high' } );
|
|
|
*
|
|
*
|
|
|
* downcastMarkerToElement( {
|
|
* downcastMarkerToElement( {
|
|
|
* model: 'search',
|
|
* model: 'search',
|
|
@@ -248,14 +237,14 @@ export function downcastAttributeToAttribute( modelAttributeKey, config = {}, pr
|
|
|
*
|
|
*
|
|
|
* downcastMarkerToElement( {
|
|
* downcastMarkerToElement( {
|
|
|
* model: 'search',
|
|
* model: 'search',
|
|
|
- * view: data => {
|
|
|
|
|
- * return new ViewUIElement( 'span', { 'data-marker': 'search', 'data-start': data.isOpening } );
|
|
|
|
|
|
|
+ * view: ( markerData, viewWriter ) => {
|
|
|
|
|
+ * return viewWriter.createUIElement( 'span', { 'data-marker': 'search', 'data-start': markerData.isOpening } );
|
|
|
* }
|
|
* }
|
|
|
* } );
|
|
* } );
|
|
|
*
|
|
*
|
|
|
* If function is passed as `config.view` parameter, it will be used to generate both boundary elements. The function
|
|
* If function is passed as `config.view` parameter, it will be used to generate both boundary elements. The function
|
|
|
* receives `data` object as parameter and should return an instance of {@link module:engine/view/uielement~UIElement view.UIElement}.
|
|
* receives `data` object as parameter and should return an instance of {@link module:engine/view/uielement~UIElement view.UIElement}.
|
|
|
- * The `data` object properties are passed from
|
|
|
|
|
|
|
+ * The `data` and `conversionApi` objects are passed from
|
|
|
* {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:addMarker}. Additionally,
|
|
* {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:addMarker}. Additionally,
|
|
|
* `data.isOpening` parameter is passed, which is set to `true` for marker start boundary element, and `false` to
|
|
* `data.isOpening` parameter is passed, which is set to `true` for marker start boundary element, and `false` to
|
|
|
* marker end boundary element.
|
|
* marker end boundary element.
|
|
@@ -266,20 +255,19 @@ export function downcastAttributeToAttribute( modelAttributeKey, config = {}, pr
|
|
|
*
|
|
*
|
|
|
* @param {Object} config Conversion configuration.
|
|
* @param {Object} config Conversion configuration.
|
|
|
* @param {String} config.model Name of the model marker (or model marker group) to convert.
|
|
* @param {String} config.model Name of the model marker (or model marker group) to convert.
|
|
|
- * @param {module:engine/view/elementdefinition~ElementDefinition|Function} config.view View element definition
|
|
|
|
|
- * which will be used to build a view element for conversion or a function that takes model marker data as a parameter and
|
|
|
|
|
- * returns view element to use in conversion.
|
|
|
|
|
- * @param {module:utils/priorities~PriorityString} [priority='normal'] Converter priority.
|
|
|
|
|
|
|
+ * @param {module:engine/view/elementdefinition~ElementDefinition|Function} config.view View element definition or a function
|
|
|
|
|
+ * that takes model marker data as a parameter and returns view ui element.
|
|
|
|
|
+ * @param {module:utils/priorities~PriorityString} [config.priority='normal'] Converter priority.
|
|
|
* @returns {Function} Conversion helper.
|
|
* @returns {Function} Conversion helper.
|
|
|
*/
|
|
*/
|
|
|
-export function downcastMarkerToElement( config, priority = 'normal' ) {
|
|
|
|
|
|
|
+export function downcastMarkerToElement( config ) {
|
|
|
config = cloneDeep( config );
|
|
config = cloneDeep( config );
|
|
|
|
|
|
|
|
- _normalizeToElementConfig( config, ViewUIElement );
|
|
|
|
|
|
|
+ config.view = _normalizeToElementConfig( config.view, 'ui' );
|
|
|
|
|
|
|
|
return dispatcher => {
|
|
return dispatcher => {
|
|
|
- dispatcher.on( 'addMarker:' + config.model, insertUIElement( config.view ), { priority } );
|
|
|
|
|
- dispatcher.on( 'removeMarker:' + config.model, removeUIElement( config.view ), { priority } );
|
|
|
|
|
|
|
+ dispatcher.on( 'addMarker:' + config.model, insertUIElement( config.view ), { priority: config.priority || 'normal' } );
|
|
|
|
|
+ dispatcher.on( 'removeMarker:' + config.model, removeUIElement( config.view ), { priority: config.priority || 'normal' } );
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -304,7 +292,7 @@ export function downcastMarkerToElement( config, priority = 'normal' ) {
|
|
|
*
|
|
*
|
|
|
* downcastMarkerToHighlight( { model: 'comment', view: { class: 'comment' } } );
|
|
* downcastMarkerToHighlight( { model: 'comment', view: { class: 'comment' } } );
|
|
|
*
|
|
*
|
|
|
- * downcastMarkerToHighlight( { model: 'comment', view: { class: 'new-comment' } }, 'high' );
|
|
|
|
|
|
|
+ * downcastMarkerToHighlight( { model: 'comment', view: { class: 'new-comment' }, priority: 'high' } );
|
|
|
*
|
|
*
|
|
|
* downcastMarkerToHighlight( {
|
|
* downcastMarkerToHighlight( {
|
|
|
* model: 'comment',
|
|
* model: 'comment',
|
|
@@ -319,9 +307,8 @@ export function downcastMarkerToElement( config, priority = 'normal' ) {
|
|
|
* } );
|
|
* } );
|
|
|
*
|
|
*
|
|
|
* If function is passed as `config.view` parameter, it will be used to generate highlight descriptor. The function
|
|
* If function is passed as `config.view` parameter, it will be used to generate highlight descriptor. The function
|
|
|
- * receives `data` object as parameter and should return an instance of {@link module:engine/view/uielement~UIElement view.UIElement}.
|
|
|
|
|
- * The `data` object properties are passed from
|
|
|
|
|
- * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:addMarker}.
|
|
|
|
|
|
|
+ * receives `data` object as parameter and should return a {@link module:engine/conversion/downcast-converters~HighlightDescriptor}.
|
|
|
|
|
+ * The `data` object properties are passed from {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:addMarker}.
|
|
|
*
|
|
*
|
|
|
* See {@link module:engine/conversion/conversion~Conversion#for} to learn how to add converter to conversion process.
|
|
* See {@link module:engine/conversion/conversion~Conversion#for} to learn how to add converter to conversion process.
|
|
|
*
|
|
*
|
|
@@ -329,166 +316,124 @@ export function downcastMarkerToElement( config, priority = 'normal' ) {
|
|
|
* @param {String} config.model Name of the model marker (or model marker group) to convert.
|
|
* @param {String} config.model Name of the model marker (or model marker group) to convert.
|
|
|
* @param {module:engine/conversion/downcast-converters~HighlightDescriptor|Function} config.view Highlight descriptor
|
|
* @param {module:engine/conversion/downcast-converters~HighlightDescriptor|Function} config.view Highlight descriptor
|
|
|
* which will be used for highlighting or a function that takes model marker data as a parameter and returns a highlight descriptor.
|
|
* which will be used for highlighting or a function that takes model marker data as a parameter and returns a highlight descriptor.
|
|
|
- * @param {module:utils/priorities~PriorityString} [priority='normal'] Converter priority.
|
|
|
|
|
|
|
+ * @param {module:utils/priorities~PriorityString} [config.priority='normal'] Converter priority.
|
|
|
* @returns {Function} Conversion helper.
|
|
* @returns {Function} Conversion helper.
|
|
|
*/
|
|
*/
|
|
|
-export function downcastMarkerToHighlight( config, priority = 'normal' ) {
|
|
|
|
|
|
|
+export function downcastMarkerToHighlight( config ) {
|
|
|
return dispatcher => {
|
|
return dispatcher => {
|
|
|
- dispatcher.on( 'addMarker:' + config.model, highlightText( config.view ), { priority } );
|
|
|
|
|
- dispatcher.on( 'addMarker:' + config.model, highlightElement( config.view ), { priority } );
|
|
|
|
|
- dispatcher.on( 'removeMarker:' + config.model, removeHighlight( config.view ), { priority } );
|
|
|
|
|
|
|
+ dispatcher.on( 'addMarker:' + config.model, highlightText( config.view ), { priority: config.priority || 'normal' } );
|
|
|
|
|
+ dispatcher.on( 'addMarker:' + config.model, highlightElement( config.view ), { priority: config.priority || 'normal' } );
|
|
|
|
|
+ dispatcher.on( 'removeMarker:' + config.model, removeHighlight( config.view ), { priority: config.priority || 'normal' } );
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-// Takes config and adds default parameters if they don't exist and normalizes other parameters to be used in downcast converters
|
|
|
|
|
-// for generating a view element.
|
|
|
|
|
|
|
+// Takes `config.view`, and if it is a {@link module:engine/view/elementdefinition~ElementDefinition}, converts it
|
|
|
|
|
+// to a function (because lower level converters accepts only element creator functions).
|
|
|
//
|
|
//
|
|
|
-// @param {Object} config Object with conversion helper configuration.
|
|
|
|
|
-// @param {Function} ViewElementClass View element class to use when generating view element from config.
|
|
|
|
|
-function _normalizeToElementConfig( config, ViewElementClass ) {
|
|
|
|
|
- // If config is given as an array, normalize each entry separately.
|
|
|
|
|
- if ( Array.isArray( config ) ) {
|
|
|
|
|
- for ( const configEntry of config ) {
|
|
|
|
|
- _normalizeToElementConfig( configEntry, ViewElementClass );
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return;
|
|
|
|
|
|
|
+// @param {module:engine/view/elementdefinition~ElementDefinition|Function} view View configuration.
|
|
|
|
|
+// @param {'container'|'attribute'|'ui'} viewElementType View element type to create.
|
|
|
|
|
+// @returns {Function} Element creator function to use in lower level converters.
|
|
|
|
|
+function _normalizeToElementConfig( view, viewElementType ) {
|
|
|
|
|
+ if ( typeof view == 'function' ) {
|
|
|
|
|
+ // If `view` is already a function, don't do anything.
|
|
|
|
|
+ return view;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // Build `.view` property.
|
|
|
|
|
- // It is expected to be either creator function or view element instance.
|
|
|
|
|
- if ( typeof config.view == 'string' ) {
|
|
|
|
|
- // If `.view` is a string, create a proper view element instance out of given `ViewElementClass` and name given in `.view`.
|
|
|
|
|
- config.view = new ViewElementClass( config.view );
|
|
|
|
|
- } else if ( typeof config.view == 'object' && !( config.view instanceof ViewElementClass ) ) {
|
|
|
|
|
- // If `.view` is an object, use it to build view element instance.
|
|
|
|
|
- config.view = _createViewElementFromDefinition( config.view, ViewElementClass );
|
|
|
|
|
- }
|
|
|
|
|
- // `.view` can be also a function or already a view element instance.
|
|
|
|
|
- // These are already valid types which don't have to be normalized.
|
|
|
|
|
|
|
+ return ( modelData, viewWriter ) => _createViewElementFromDefinition( view, viewWriter, viewElementType );
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Creates view element instance from provided viewElementDefinition and class.
|
|
// Creates view element instance from provided viewElementDefinition and class.
|
|
|
//
|
|
//
|
|
|
// @param {module:engine/view/elementdefinition~ElementDefinition} viewElementDefinition
|
|
// @param {module:engine/view/elementdefinition~ElementDefinition} viewElementDefinition
|
|
|
-// @param {Function} ViewElementClass
|
|
|
|
|
|
|
+// @param {module:engine/view/writer~Writer} viewWriter
|
|
|
|
|
+// @param {'container'|'attribute'|'ui'} viewElementType
|
|
|
// @returns {module:engine/view/element~Element}
|
|
// @returns {module:engine/view/element~Element}
|
|
|
-function _createViewElementFromDefinition( viewElementDefinition, ViewElementClass ) {
|
|
|
|
|
- const element = new ViewElementClass( viewElementDefinition.name, Object.assign( {}, viewElementDefinition.attribute ) );
|
|
|
|
|
|
|
+function _createViewElementFromDefinition( viewElementDefinition, viewWriter, viewElementType ) {
|
|
|
|
|
+ if ( typeof viewElementDefinition == 'string' ) {
|
|
|
|
|
+ // If `viewElementDefinition` is given as a `String`, normalize it to an object with `name` property.
|
|
|
|
|
+ viewElementDefinition = { name: viewElementDefinition };
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ let element;
|
|
|
|
|
+
|
|
|
|
|
+ if ( viewElementType == 'container' ) {
|
|
|
|
|
+ element = viewWriter.createContainerElement( viewElementDefinition.name, Object.assign( {}, viewElementDefinition.attribute ) );
|
|
|
|
|
+ } else if ( viewElementType == 'attribute' ) {
|
|
|
|
|
+ element = viewWriter.createAttributeElement( viewElementDefinition.name, Object.assign( {}, viewElementDefinition.attribute ) );
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 'ui'.
|
|
|
|
|
+ element = viewWriter.createUIElement( viewElementDefinition.name, Object.assign( {}, viewElementDefinition.attribute ) );
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
if ( viewElementDefinition.style ) {
|
|
if ( viewElementDefinition.style ) {
|
|
|
- element.setStyle( viewElementDefinition.style );
|
|
|
|
|
|
|
+ const keys = Object.keys( viewElementDefinition.style );
|
|
|
|
|
+
|
|
|
|
|
+ for ( const key of keys ) {
|
|
|
|
|
+ viewWriter.setStyle( key, viewElementDefinition.style[ key ], element );
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if ( viewElementDefinition.class ) {
|
|
if ( viewElementDefinition.class ) {
|
|
|
const classes = viewElementDefinition.class;
|
|
const classes = viewElementDefinition.class;
|
|
|
|
|
|
|
|
if ( typeof classes == 'string' ) {
|
|
if ( typeof classes == 'string' ) {
|
|
|
- element.addClass( classes );
|
|
|
|
|
|
|
+ viewWriter.addClass( classes, element );
|
|
|
} else {
|
|
} else {
|
|
|
- element.addClass( ...classes );
|
|
|
|
|
|
|
+ for ( const className of classes ) {
|
|
|
|
|
+ viewWriter.addClass( className, element );
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
return element;
|
|
return element;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-// Takes config and adds default parameters if they don't exist and normalizes other parameters to be used in downcast converters
|
|
|
|
|
-// for generating view attribute.
|
|
|
|
|
-//
|
|
|
|
|
-// @param {String} modelAttributeKey Model attribute key for which config is defined.
|
|
|
|
|
-// @param {Object} [config] Config with conversion helper configuration.
|
|
|
|
|
-function _normalizeToAttributeConfig( modelAttributeKey, config ) {
|
|
|
|
|
- // If config is given as an array, normalize each entry separately.
|
|
|
|
|
- if ( Array.isArray( config ) ) {
|
|
|
|
|
- for ( const configEntry of config ) {
|
|
|
|
|
- _normalizeToAttributeConfig( modelAttributeKey, configEntry );
|
|
|
|
|
- }
|
|
|
|
|
|
|
+function _getFromAttributeCreator( config ) {
|
|
|
|
|
+ if ( config.model.values ) {
|
|
|
|
|
+ return ( modelAttributeValue, viewWriter ) => {
|
|
|
|
|
+ const view = config.view[ modelAttributeValue ];
|
|
|
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ if ( view ) {
|
|
|
|
|
+ return view( modelAttributeValue, viewWriter );
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- // Build `.view` property.
|
|
|
|
|
- // It is expected to be a creator function, that takes attribute value and model item and returns an object
|
|
|
|
|
- // with `key` property and `value` property which are view attribute key and view attribute value.
|
|
|
|
|
- if ( !config.view ) {
|
|
|
|
|
- // If `.view` is not set, take both attribute name and attribute value from model.
|
|
|
|
|
- const viewAttributeKey = modelAttributeKey;
|
|
|
|
|
- config.view = modelAttributeValue => ( { key: viewAttributeKey, value: modelAttributeValue } );
|
|
|
|
|
- } else if ( typeof config.view == 'string' ) {
|
|
|
|
|
- // If `.view` is set as a string, use it as a view attribute name. Value will be taken from model attribute value.
|
|
|
|
|
- const viewAttributeKey = config.view;
|
|
|
|
|
- config.view = modelAttributeValue => ( { key: viewAttributeKey, value: modelAttributeValue } );
|
|
|
|
|
- } else if ( typeof config.view == 'object' ) {
|
|
|
|
|
- // If `.view` is set as an object, use set key and value.
|
|
|
|
|
- const viewAttributeKey = config.view.key;
|
|
|
|
|
- const viewAttributeValue = config.view.value;
|
|
|
|
|
- config.view = () => ( { key: viewAttributeKey, value: viewAttributeValue } );
|
|
|
|
|
|
|
+ return null;
|
|
|
|
|
+ };
|
|
|
|
|
+ } else {
|
|
|
|
|
+ return config.view;
|
|
|
}
|
|
}
|
|
|
- // `.view` can be also already a function.
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-// Takes config and creates a view element creator function that chooses an appropriate entry from the config depending on
|
|
|
|
|
-// the value of model attribute.
|
|
|
|
|
-//
|
|
|
|
|
-// Supports specifying config as a single object or an array of objects.
|
|
|
|
|
-// Supports `.view` defined as an object and as a function.
|
|
|
|
|
|
|
+// Takes config and adds default parameters if they don't exist and normalizes other parameters to be used in downcast converters
|
|
|
|
|
+// for generating view attribute.
|
|
|
//
|
|
//
|
|
|
-// @param {Object|Array.<Object>} config Config with conversion helper configuration.
|
|
|
|
|
-function _getCreatorForArrayConfig( config ) {
|
|
|
|
|
- if ( !Array.isArray( config ) ) {
|
|
|
|
|
- config = [ config ];
|
|
|
|
|
|
|
+// @param {Object} view View configuration.
|
|
|
|
|
+function _normalizeToAttributeConfig( view ) {
|
|
|
|
|
+ if ( typeof view == 'string' ) {
|
|
|
|
|
+ return modelAttributeValue => ( { key: view, value: modelAttributeValue } );
|
|
|
|
|
+ } else if ( typeof view == 'object' ) {
|
|
|
|
|
+ return () => view;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // function.
|
|
|
|
|
+ return view;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- // Get "default config" entry. It is the entry with `.model` property set to `true`.
|
|
|
|
|
- // "Default" entry should be used if no other entry matched model attribute value.
|
|
|
|
|
- const defaultConfig = config.find( configEntry => configEntry.model === undefined );
|
|
|
|
|
-
|
|
|
|
|
- // Return a creator function.
|
|
|
|
|
- return modelAttributeValue => {
|
|
|
|
|
- // Set default config at first. It will be used if no other entry matches model attribute value.
|
|
|
|
|
- let matchedConfigEntry = defaultConfig;
|
|
|
|
|
-
|
|
|
|
|
- // Creator should check all entries from the config...
|
|
|
|
|
- for ( const configEntry of config ) {
|
|
|
|
|
- if ( configEntry.model === modelAttributeValue ) {
|
|
|
|
|
- // If `.model` specified in entry matches converted attribute's value, choose it.
|
|
|
|
|
- matchedConfigEntry = configEntry;
|
|
|
|
|
- break;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // If there was default config or matched config...
|
|
|
|
|
- if ( matchedConfigEntry ) {
|
|
|
|
|
- // If the entry `.view` is a function, execute it and return the value...
|
|
|
|
|
- if ( typeof matchedConfigEntry.view == 'function' ) {
|
|
|
|
|
- return matchedConfigEntry.view( modelAttributeValue );
|
|
|
|
|
- }
|
|
|
|
|
- // Else, just return `.view`, it should be a view element instance after it got normalized earlier.
|
|
|
|
|
- return matchedConfigEntry.view;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return null;
|
|
|
|
|
- };
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* Function factory, creates a converter that converts node insertion changes from the model to the view.
|
|
* Function factory, creates a converter that converts node insertion changes from the model to the view.
|
|
|
- * The view element that will be added to the view depends on passed parameter. If {@link module:engine/view/element~Element} was passed,
|
|
|
|
|
- * it will be cloned and the copy will be inserted. If `Function` is provided, it is passed all the parameters of the
|
|
|
|
|
- * dispatcher's {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:insert insert event}.
|
|
|
|
|
|
|
+ * Passed function will be provided with all the parameters of the dispatcher's
|
|
|
|
|
+ * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:insert insert event}.
|
|
|
* It's expected that the function returns a {@link module:engine/view/element~Element}.
|
|
* It's expected that the function returns a {@link module:engine/view/element~Element}.
|
|
|
* The result of the function will be inserted to the view.
|
|
* The result of the function will be inserted to the view.
|
|
|
*
|
|
*
|
|
|
* The converter automatically consumes corresponding value from consumables list, stops the event (see
|
|
* The converter automatically consumes corresponding value from consumables list, stops the event (see
|
|
|
* {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher}) and bind model and view elements.
|
|
* {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher}) and bind model and view elements.
|
|
|
*
|
|
*
|
|
|
- * modelDispatcher.on( 'insert:paragraph', insertElement( new ViewElement( 'p' ) ) );
|
|
|
|
|
- *
|
|
|
|
|
- * modelDispatcher.on(
|
|
|
|
|
|
|
+ * downcastDispatcher.on(
|
|
|
* 'insert:myElem',
|
|
* 'insert:myElem',
|
|
|
- * insertElement( ( modelItem, consumable, conversionApi ) => {
|
|
|
|
|
- * let myElem = new ViewElement( 'myElem', { myAttr: 'my-' + modelItem.getAttribute( 'myAttr' ) }, new ViewText( 'myText' ) );
|
|
|
|
|
|
|
+ * insertElement( ( modelItem, viewWriter ) => {
|
|
|
|
|
+ * const text = viewWriter.createText( 'myText' );
|
|
|
|
|
+ * const myElem = viewWriter.createElement( 'myElem', { myAttr: 'my-' + modelItem.getAttribute( 'myAttr' ) }, text );
|
|
|
*
|
|
*
|
|
|
* // Do something fancy with myElem using `modelItem` or other parameters.
|
|
* // Do something fancy with myElem using `modelItem` or other parameters.
|
|
|
*
|
|
*
|
|
@@ -496,28 +441,25 @@ function _getCreatorForArrayConfig( config ) {
|
|
|
* }
|
|
* }
|
|
|
* ) );
|
|
* ) );
|
|
|
*
|
|
*
|
|
|
- * @param {module:engine/view/element~Element|Function} elementCreator View element, or function returning a view element, which
|
|
|
|
|
- * will be inserted.
|
|
|
|
|
|
|
+ * @param {Function} elementCreator Function returning a view element, which will be inserted.
|
|
|
* @returns {Function} Insert element event converter.
|
|
* @returns {Function} Insert element event converter.
|
|
|
*/
|
|
*/
|
|
|
export function insertElement( elementCreator ) {
|
|
export function insertElement( elementCreator ) {
|
|
|
- return ( evt, data, consumable, conversionApi ) => {
|
|
|
|
|
- const viewElement = ( elementCreator instanceof ViewElement ) ?
|
|
|
|
|
- elementCreator.clone( true ) :
|
|
|
|
|
- elementCreator( data.item, consumable, conversionApi );
|
|
|
|
|
|
|
+ return ( evt, data, conversionApi ) => {
|
|
|
|
|
+ const viewElement = elementCreator( data.item, conversionApi.writer );
|
|
|
|
|
|
|
|
if ( !viewElement ) {
|
|
if ( !viewElement ) {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if ( !consumable.consume( data.item, 'insert' ) ) {
|
|
|
|
|
|
|
+ if ( !conversionApi.consumable.consume( data.item, 'insert' ) ) {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const viewPosition = conversionApi.mapper.toViewPosition( data.range.start );
|
|
const viewPosition = conversionApi.mapper.toViewPosition( data.range.start );
|
|
|
|
|
|
|
|
conversionApi.mapper.bindElements( data.item, viewElement );
|
|
conversionApi.mapper.bindElements( data.item, viewElement );
|
|
|
- viewWriter.insert( viewPosition, viewElement );
|
|
|
|
|
|
|
+ conversionApi.writer.insert( viewPosition, viewElement );
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -532,13 +474,14 @@ export function insertElement( elementCreator ) {
|
|
|
* @returns {Function} Insert text event converter.
|
|
* @returns {Function} Insert text event converter.
|
|
|
*/
|
|
*/
|
|
|
export function insertText() {
|
|
export function insertText() {
|
|
|
- return ( evt, data, consumable, conversionApi ) => {
|
|
|
|
|
- if ( !consumable.consume( data.item, 'insert' ) ) {
|
|
|
|
|
|
|
+ return ( evt, data, conversionApi ) => {
|
|
|
|
|
+ if ( !conversionApi.consumable.consume( data.item, 'insert' ) ) {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ const viewWriter = conversionApi.writer;
|
|
|
const viewPosition = conversionApi.mapper.toViewPosition( data.range.start );
|
|
const viewPosition = conversionApi.mapper.toViewPosition( data.range.start );
|
|
|
- const viewText = new ViewText( data.item.data );
|
|
|
|
|
|
|
+ const viewText = viewWriter.createText( data.item.data );
|
|
|
|
|
|
|
|
viewWriter.insert( viewPosition, viewText );
|
|
viewWriter.insert( viewPosition, viewText );
|
|
|
};
|
|
};
|
|
@@ -562,7 +505,7 @@ export function remove() {
|
|
|
const viewRange = new ViewRange( viewStart, viewEnd );
|
|
const viewRange = new ViewRange( viewStart, viewEnd );
|
|
|
|
|
|
|
|
// Trim the range to remove in case some UI elements are on the view range boundaries.
|
|
// Trim the range to remove in case some UI elements are on the view range boundaries.
|
|
|
- const removed = viewWriter.remove( viewRange.getTrimmed() );
|
|
|
|
|
|
|
+ const removed = conversionApi.writer.remove( viewRange.getTrimmed() );
|
|
|
|
|
|
|
|
// After the range is removed, unbind all view elements from the model.
|
|
// After the range is removed, unbind all view elements from the model.
|
|
|
// Range inside view document fragment is used to unbind deeply.
|
|
// Range inside view document fragment is used to unbind deeply.
|
|
@@ -586,21 +529,14 @@ export function remove() {
|
|
|
* @returns {Function} Insert element event converter.
|
|
* @returns {Function} Insert element event converter.
|
|
|
*/
|
|
*/
|
|
|
export function insertUIElement( elementCreator ) {
|
|
export function insertUIElement( elementCreator ) {
|
|
|
- return ( evt, data, consumable, conversionApi ) => {
|
|
|
|
|
- let viewStartElement, viewEndElement;
|
|
|
|
|
-
|
|
|
|
|
|
|
+ return ( evt, data, conversionApi ) => {
|
|
|
// Create two view elements. One will be inserted at the beginning of marker, one at the end.
|
|
// Create two view elements. One will be inserted at the beginning of marker, one at the end.
|
|
|
// If marker is collapsed, only "opening" element will be inserted.
|
|
// If marker is collapsed, only "opening" element will be inserted.
|
|
|
- if ( elementCreator instanceof ViewElement ) {
|
|
|
|
|
- viewStartElement = elementCreator.clone( true );
|
|
|
|
|
- viewEndElement = elementCreator.clone( true );
|
|
|
|
|
- } else {
|
|
|
|
|
- data.isOpening = true;
|
|
|
|
|
- viewStartElement = elementCreator( data, conversionApi );
|
|
|
|
|
|
|
+ data.isOpening = true;
|
|
|
|
|
+ const viewStartElement = elementCreator( data, conversionApi.writer );
|
|
|
|
|
|
|
|
- data.isOpening = false;
|
|
|
|
|
- viewEndElement = elementCreator( data, conversionApi );
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ data.isOpening = false;
|
|
|
|
|
+ const viewEndElement = elementCreator( data, conversionApi.writer );
|
|
|
|
|
|
|
|
if ( !viewStartElement || !viewEndElement ) {
|
|
if ( !viewStartElement || !viewEndElement ) {
|
|
|
return;
|
|
return;
|
|
@@ -611,18 +547,19 @@ export function insertUIElement( elementCreator ) {
|
|
|
// Marker that is collapsed has consumable build differently that non-collapsed one.
|
|
// Marker that is collapsed has consumable build differently that non-collapsed one.
|
|
|
// For more information see `addMarker` event description.
|
|
// For more information see `addMarker` event description.
|
|
|
// If marker's range is collapsed - check if it can be consumed.
|
|
// If marker's range is collapsed - check if it can be consumed.
|
|
|
- if ( markerRange.isCollapsed && !consumable.consume( markerRange, evt.name ) ) {
|
|
|
|
|
|
|
+ if ( markerRange.isCollapsed && !conversionApi.consumable.consume( markerRange, evt.name ) ) {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// If marker's range is not collapsed - consume all items inside.
|
|
// If marker's range is not collapsed - consume all items inside.
|
|
|
for ( const value of markerRange ) {
|
|
for ( const value of markerRange ) {
|
|
|
- if ( !consumable.consume( value.item, evt.name ) ) {
|
|
|
|
|
|
|
+ if ( !conversionApi.consumable.consume( value.item, evt.name ) ) {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const mapper = conversionApi.mapper;
|
|
const mapper = conversionApi.mapper;
|
|
|
|
|
+ const viewWriter = conversionApi.writer;
|
|
|
|
|
|
|
|
// Add "opening" element.
|
|
// Add "opening" element.
|
|
|
viewWriter.insert( mapper.toViewPosition( markerRange.start ), viewStartElement );
|
|
viewWriter.insert( mapper.toViewPosition( markerRange.start ), viewStartElement );
|
|
@@ -646,26 +583,20 @@ export function insertUIElement( elementCreator ) {
|
|
|
*/
|
|
*/
|
|
|
export function removeUIElement( elementCreator ) {
|
|
export function removeUIElement( elementCreator ) {
|
|
|
return ( evt, data, conversionApi ) => {
|
|
return ( evt, data, conversionApi ) => {
|
|
|
- let viewStartElement, viewEndElement;
|
|
|
|
|
-
|
|
|
|
|
// Create two view elements. One will be used to remove "opening element", the other for "closing element".
|
|
// Create two view elements. One will be used to remove "opening element", the other for "closing element".
|
|
|
// If marker was collapsed, only "opening" element will be removed.
|
|
// If marker was collapsed, only "opening" element will be removed.
|
|
|
- if ( elementCreator instanceof ViewElement ) {
|
|
|
|
|
- viewStartElement = elementCreator.clone( true );
|
|
|
|
|
- viewEndElement = elementCreator.clone( true );
|
|
|
|
|
- } else {
|
|
|
|
|
- data.isOpening = true;
|
|
|
|
|
- viewStartElement = elementCreator( data, conversionApi );
|
|
|
|
|
|
|
+ data.isOpening = true;
|
|
|
|
|
+ const viewStartElement = elementCreator( data, conversionApi.writer );
|
|
|
|
|
|
|
|
- data.isOpening = false;
|
|
|
|
|
- viewEndElement = elementCreator( data, conversionApi );
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ data.isOpening = false;
|
|
|
|
|
+ const viewEndElement = elementCreator( data, conversionApi.writer );
|
|
|
|
|
|
|
|
if ( !viewStartElement || !viewEndElement ) {
|
|
if ( !viewStartElement || !viewEndElement ) {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const markerRange = data.markerRange;
|
|
const markerRange = data.markerRange;
|
|
|
|
|
+ const viewWriter = conversionApi.writer;
|
|
|
|
|
|
|
|
// When removing the ui elements, we map the model range to view twice, because that view range
|
|
// When removing the ui elements, we map the model range to view twice, because that view range
|
|
|
// may change after the first clearing.
|
|
// may change after the first clearing.
|
|
@@ -708,30 +639,60 @@ export function removeUIElement( elementCreator ) {
|
|
|
*
|
|
*
|
|
|
* @param {Function} [attributeCreator] Function returning an object with two properties: `key` and `value`, which
|
|
* @param {Function} [attributeCreator] Function returning an object with two properties: `key` and `value`, which
|
|
|
* represents attribute key and attribute value to be set on a {@link module:engine/view/element~Element view element}.
|
|
* represents attribute key and attribute value to be set on a {@link module:engine/view/element~Element view element}.
|
|
|
- * The function is passed all the parameters of the
|
|
|
|
|
- * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:attribute} event.
|
|
|
|
|
|
|
+ * The function is passed model attribute value as first parameter and additional data about the change as a second parameter.
|
|
|
* @returns {Function} Set/change attribute converter.
|
|
* @returns {Function} Set/change attribute converter.
|
|
|
*/
|
|
*/
|
|
|
export function changeAttribute( attributeCreator ) {
|
|
export function changeAttribute( attributeCreator ) {
|
|
|
attributeCreator = attributeCreator || ( ( value, data ) => ( { value, key: data.attributeKey } ) );
|
|
attributeCreator = attributeCreator || ( ( value, data ) => ( { value, key: data.attributeKey } ) );
|
|
|
|
|
|
|
|
- return ( evt, data, consumable, conversionApi ) => {
|
|
|
|
|
- if ( !consumable.consume( data.item, evt.name ) ) {
|
|
|
|
|
|
|
+ return ( evt, data, conversionApi ) => {
|
|
|
|
|
+ if ( !conversionApi.consumable.consume( data.item, evt.name ) ) {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ const viewElement = conversionApi.mapper.toViewElement( data.item );
|
|
|
|
|
+ const viewWriter = conversionApi.writer;
|
|
|
|
|
+
|
|
|
// First remove the old attribute if there was one.
|
|
// First remove the old attribute if there was one.
|
|
|
- const oldAttribute = attributeCreator( data.attributeOldValue, data, consumable, conversionApi );
|
|
|
|
|
|
|
+ const oldAttribute = attributeCreator( data.attributeOldValue, data );
|
|
|
|
|
|
|
|
if ( data.attributeOldValue !== null && oldAttribute ) {
|
|
if ( data.attributeOldValue !== null && oldAttribute ) {
|
|
|
- conversionApi.mapper.toViewElement( data.item ).removeAttribute( oldAttribute.key );
|
|
|
|
|
|
|
+ if ( oldAttribute.key == 'class' ) {
|
|
|
|
|
+ const classes = Array.isArray( oldAttribute.value ) ? oldAttribute.value : [ oldAttribute.value ];
|
|
|
|
|
+
|
|
|
|
|
+ for ( const className of classes ) {
|
|
|
|
|
+ viewWriter.removeClass( className, viewElement );
|
|
|
|
|
+ }
|
|
|
|
|
+ } else if ( oldAttribute.key == 'style' ) {
|
|
|
|
|
+ const keys = Object.keys( oldAttribute.value );
|
|
|
|
|
+
|
|
|
|
|
+ for ( const key of keys ) {
|
|
|
|
|
+ viewWriter.removeStyle( key, viewElement );
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ viewWriter.removeAttribute( oldAttribute.key, viewElement );
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Then, if conversion was successful, set the new attribute.
|
|
// Then, if conversion was successful, set the new attribute.
|
|
|
- const newAttribute = attributeCreator( data.attributeNewValue, data, consumable, conversionApi );
|
|
|
|
|
|
|
+ const newAttribute = attributeCreator( data.attributeNewValue, data );
|
|
|
|
|
|
|
|
if ( data.attributeNewValue !== null && newAttribute ) {
|
|
if ( data.attributeNewValue !== null && newAttribute ) {
|
|
|
- conversionApi.mapper.toViewElement( data.item ).setAttribute( newAttribute.key, newAttribute.value );
|
|
|
|
|
|
|
+ if ( newAttribute.key == 'class' ) {
|
|
|
|
|
+ const classes = Array.isArray( newAttribute.value ) ? newAttribute.value : [ newAttribute.value ];
|
|
|
|
|
+
|
|
|
|
|
+ for ( const className of classes ) {
|
|
|
|
|
+ viewWriter.addClass( className, viewElement );
|
|
|
|
|
+ }
|
|
|
|
|
+ } else if ( newAttribute.key == 'style' ) {
|
|
|
|
|
+ const keys = Object.keys( newAttribute.value );
|
|
|
|
|
+
|
|
|
|
|
+ for ( const key of keys ) {
|
|
|
|
|
+ viewWriter.setStyle( key, newAttribute.value[ key ], viewElement );
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ viewWriter.setAttribute( newAttribute.key, newAttribute.value, viewElement );
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
@@ -750,8 +711,7 @@ export function changeAttribute( attributeCreator ) {
|
|
|
* |- b {bold: true} | |- ab
|
|
* |- b {bold: true} | |- ab
|
|
|
* |- c |- c
|
|
* |- c |- c
|
|
|
*
|
|
*
|
|
|
- * The wrapping node depends on passed parameter. If {@link module:engine/view/element~Element} was passed, it will be cloned and
|
|
|
|
|
- * the copy will become the wrapping element. If `Function` is provided, it is passed attribute value and then all the parameters of the
|
|
|
|
|
|
|
+ * Passed `Function` will be provided with attribute value and then all the parameters of the
|
|
|
* {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:attribute attribute event}.
|
|
* {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:attribute attribute event}.
|
|
|
* It's expected that the function returns a {@link module:engine/view/element~Element}.
|
|
* It's expected that the function returns a {@link module:engine/view/element~Element}.
|
|
|
* The result of the function will be the wrapping element.
|
|
* The result of the function will be the wrapping element.
|
|
@@ -760,36 +720,36 @@ export function changeAttribute( attributeCreator ) {
|
|
|
* The converter automatically consumes corresponding value from consumables list, stops the event (see
|
|
* The converter automatically consumes corresponding value from consumables list, stops the event (see
|
|
|
* {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher}).
|
|
* {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher}).
|
|
|
*
|
|
*
|
|
|
- * modelDispatcher.on( 'attribute:bold', wrapItem( new ViewAttributeElement( 'strong' ) ) );
|
|
|
|
|
|
|
+ * modelDispatcher.on( 'attribute:bold', wrapItem( ( modelAttributeValue, viewWriter ) => {
|
|
|
|
|
+ * return viewWriter.createAttributeElement( 'strong' );
|
|
|
|
|
+ * } );
|
|
|
*
|
|
*
|
|
|
- * @param {module:engine/view/element~Element|Function} elementCreator View element, or function returning a view element, which will
|
|
|
|
|
- * be used for wrapping.
|
|
|
|
|
|
|
+ * @param {Function} elementCreator Function returning a view element, which will be used for wrapping.
|
|
|
* @returns {Function} Set/change attribute converter.
|
|
* @returns {Function} Set/change attribute converter.
|
|
|
*/
|
|
*/
|
|
|
export function wrap( elementCreator ) {
|
|
export function wrap( elementCreator ) {
|
|
|
- return ( evt, data, consumable, conversionApi ) => {
|
|
|
|
|
|
|
+ return ( evt, data, conversionApi ) => {
|
|
|
// Recreate current wrapping node. It will be used to unwrap view range if the attribute value has changed
|
|
// Recreate current wrapping node. It will be used to unwrap view range if the attribute value has changed
|
|
|
// or the attribute was removed.
|
|
// or the attribute was removed.
|
|
|
- const oldViewElement = ( elementCreator instanceof ViewElement ) ?
|
|
|
|
|
- elementCreator.clone( true ) :
|
|
|
|
|
- elementCreator( data.attributeOldValue, data, consumable, conversionApi );
|
|
|
|
|
|
|
+ const oldViewElement = elementCreator( data.attributeOldValue, conversionApi.writer );
|
|
|
|
|
|
|
|
// Create node to wrap with.
|
|
// Create node to wrap with.
|
|
|
- const newViewElement = ( elementCreator instanceof ViewElement ) ?
|
|
|
|
|
- elementCreator.clone( true ) :
|
|
|
|
|
- elementCreator( data.attributeNewValue, data, consumable, conversionApi );
|
|
|
|
|
|
|
+ const newViewElement = elementCreator( data.attributeNewValue, conversionApi.writer );
|
|
|
|
|
|
|
|
if ( !oldViewElement && !newViewElement ) {
|
|
if ( !oldViewElement && !newViewElement ) {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if ( !consumable.consume( data.item, evt.name ) ) {
|
|
|
|
|
|
|
+ if ( !conversionApi.consumable.consume( data.item, evt.name ) ) {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ const viewWriter = conversionApi.writer;
|
|
|
|
|
+ const viewSelection = viewWriter.document.selection;
|
|
|
|
|
+
|
|
|
if ( data.item instanceof ModelSelection || data.item instanceof DocumentSelection ) {
|
|
if ( data.item instanceof ModelSelection || data.item instanceof DocumentSelection ) {
|
|
|
// Selection attribute conversion.
|
|
// Selection attribute conversion.
|
|
|
- viewWriter.wrap( conversionApi.viewSelection.getFirstRange(), newViewElement, conversionApi.viewSelection );
|
|
|
|
|
|
|
+ viewWriter.wrap( viewSelection.getFirstRange(), newViewElement );
|
|
|
} else {
|
|
} else {
|
|
|
// Node attribute conversion.
|
|
// Node attribute conversion.
|
|
|
let viewRange = conversionApi.mapper.toViewRange( data.range );
|
|
let viewRange = conversionApi.mapper.toViewRange( data.range );
|
|
@@ -822,7 +782,7 @@ export function wrap( elementCreator ) {
|
|
|
* @return {Function}
|
|
* @return {Function}
|
|
|
*/
|
|
*/
|
|
|
export function highlightText( highlightDescriptor ) {
|
|
export function highlightText( highlightDescriptor ) {
|
|
|
- return ( evt, data, consumable, conversionApi ) => {
|
|
|
|
|
|
|
+ return ( evt, data, conversionApi ) => {
|
|
|
if ( data.markerRange.isCollapsed ) {
|
|
if ( data.markerRange.isCollapsed ) {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
@@ -837,14 +797,16 @@ export function highlightText( highlightDescriptor ) {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if ( !consumable.consume( data.item, evt.name ) ) {
|
|
|
|
|
|
|
+ if ( !conversionApi.consumable.consume( data.item, evt.name ) ) {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const viewElement = createViewElementFromHighlightDescriptor( descriptor );
|
|
const viewElement = createViewElementFromHighlightDescriptor( descriptor );
|
|
|
|
|
+ const viewWriter = conversionApi.writer;
|
|
|
|
|
+ const viewSelection = viewWriter.document.selection;
|
|
|
|
|
|
|
|
if ( data.item instanceof ModelSelection || data.item instanceof DocumentSelection ) {
|
|
if ( data.item instanceof ModelSelection || data.item instanceof DocumentSelection ) {
|
|
|
- viewWriter.wrap( conversionApi.viewSelection.getFirstRange(), viewElement, conversionApi.viewSelection );
|
|
|
|
|
|
|
+ viewWriter.wrap( viewSelection.getFirstRange(), viewElement, viewSelection );
|
|
|
} else {
|
|
} else {
|
|
|
const viewRange = conversionApi.mapper.toViewRange( data.range );
|
|
const viewRange = conversionApi.mapper.toViewRange( data.range );
|
|
|
viewWriter.wrap( viewRange, viewElement );
|
|
viewWriter.wrap( viewRange, viewElement );
|
|
@@ -856,7 +818,7 @@ export function highlightText( highlightDescriptor ) {
|
|
|
* Converter function factory. Creates a function which applies the marker's highlight to an element inside the marker's range.
|
|
* Converter function factory. Creates a function which applies the marker's highlight to an element inside the marker's range.
|
|
|
*
|
|
*
|
|
|
* The converter checks if an element has `addHighlight` function stored as
|
|
* The converter checks if an element has `addHighlight` function stored as
|
|
|
- * {@link module:engine/view/element~Element#setCustomProperty custom property} and, if so, uses it to apply the highlight.
|
|
|
|
|
|
|
+ * {@link module:engine/view/element~Element#_setCustomProperty custom property} and, if so, uses it to apply the highlight.
|
|
|
* In such case converter will consume all element's children, assuming that they were handled by element itself.
|
|
* In such case converter will consume all element's children, assuming that they were handled by element itself.
|
|
|
*
|
|
*
|
|
|
* When `addHighlight` custom property is not present, element is not converted in any special way.
|
|
* When `addHighlight` custom property is not present, element is not converted in any special way.
|
|
@@ -870,7 +832,7 @@ export function highlightText( highlightDescriptor ) {
|
|
|
* @return {Function}
|
|
* @return {Function}
|
|
|
*/
|
|
*/
|
|
|
export function highlightElement( highlightDescriptor ) {
|
|
export function highlightElement( highlightDescriptor ) {
|
|
|
- return ( evt, data, consumable, conversionApi ) => {
|
|
|
|
|
|
|
+ return ( evt, data, conversionApi ) => {
|
|
|
if ( data.markerRange.isCollapsed ) {
|
|
if ( data.markerRange.isCollapsed ) {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
@@ -885,7 +847,7 @@ export function highlightElement( highlightDescriptor ) {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if ( !consumable.test( data.item, evt.name ) ) {
|
|
|
|
|
|
|
+ if ( !conversionApi.consumable.test( data.item, evt.name ) ) {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -893,14 +855,14 @@ export function highlightElement( highlightDescriptor ) {
|
|
|
|
|
|
|
|
if ( viewElement && viewElement.getCustomProperty( 'addHighlight' ) ) {
|
|
if ( viewElement && viewElement.getCustomProperty( 'addHighlight' ) ) {
|
|
|
// Consume element itself.
|
|
// Consume element itself.
|
|
|
- consumable.consume( data.item, evt.name );
|
|
|
|
|
|
|
+ conversionApi.consumable.consume( data.item, evt.name );
|
|
|
|
|
|
|
|
// Consume all children nodes.
|
|
// Consume all children nodes.
|
|
|
for ( const value of ModelRange.createIn( data.item ) ) {
|
|
for ( const value of ModelRange.createIn( data.item ) ) {
|
|
|
- consumable.consume( value.item, evt.name );
|
|
|
|
|
|
|
+ conversionApi.consumable.consume( value.item, evt.name );
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- viewElement.getCustomProperty( 'addHighlight' )( viewElement, descriptor );
|
|
|
|
|
|
|
+ viewElement.getCustomProperty( 'addHighlight' )( viewElement, descriptor, conversionApi.writer );
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
@@ -914,7 +876,7 @@ export function highlightElement( highlightDescriptor ) {
|
|
|
* highlight descriptor. See {link module:engine/conversion/downcast-converters~highlightDescriptorToAttributeElement}.
|
|
* highlight descriptor. See {link module:engine/conversion/downcast-converters~highlightDescriptorToAttributeElement}.
|
|
|
*
|
|
*
|
|
|
* For elements, the converter checks if an element has `removeHighlight` function stored as
|
|
* For elements, the converter checks if an element has `removeHighlight` function stored as
|
|
|
- * {@link module:engine/view/element~Element#setCustomProperty custom property}. If so, it uses it to remove the highlight.
|
|
|
|
|
|
|
+ * {@link module:engine/view/element~Element#_setCustomProperty custom property}. If so, it uses it to remove the highlight.
|
|
|
* In such case, children of that element will not be converted.
|
|
* In such case, children of that element will not be converted.
|
|
|
*
|
|
*
|
|
|
* When `removeHighlight` is not present, element is not converted in any special way.
|
|
* When `removeHighlight` is not present, element is not converted in any special way.
|
|
@@ -948,7 +910,7 @@ export function removeHighlight( highlightDescriptor ) {
|
|
|
// First, iterate through all items and remove highlight from those container elements that have custom highlight handling.
|
|
// First, iterate through all items and remove highlight from those container elements that have custom highlight handling.
|
|
|
for ( const item of items ) {
|
|
for ( const item of items ) {
|
|
|
if ( item.is( 'containerElement' ) && item.getCustomProperty( 'removeHighlight' ) ) {
|
|
if ( item.is( 'containerElement' ) && item.getCustomProperty( 'removeHighlight' ) ) {
|
|
|
- item.getCustomProperty( 'removeHighlight' )( item, descriptor.id );
|
|
|
|
|
|
|
+ item.getCustomProperty( 'removeHighlight' )( item, descriptor.id, conversionApi.writer );
|
|
|
|
|
|
|
|
// If container element had custom handling, remove all it's children from further processing.
|
|
// If container element had custom handling, remove all it's children from further processing.
|
|
|
for ( const descendant of ViewRange.createIn( item ) ) {
|
|
for ( const descendant of ViewRange.createIn( item ) ) {
|
|
@@ -960,6 +922,7 @@ export function removeHighlight( highlightDescriptor ) {
|
|
|
// Then, iterate through all other items. Look for text nodes and unwrap them. Start from the end
|
|
// Then, iterate through all other items. Look for text nodes and unwrap them. Start from the end
|
|
|
// to prevent errors when view structure changes when unwrapping (and, for example, some attributes are merged).
|
|
// to prevent errors when view structure changes when unwrapping (and, for example, some attributes are merged).
|
|
|
const viewHighlightElement = createViewElementFromHighlightDescriptor( descriptor );
|
|
const viewHighlightElement = createViewElementFromHighlightDescriptor( descriptor );
|
|
|
|
|
+ const viewWriter = conversionApi.writer;
|
|
|
|
|
|
|
|
for ( const item of Array.from( items ).reverse() ) {
|
|
for ( const item of Array.from( items ).reverse() ) {
|
|
|
if ( item.is( 'textProxy' ) ) {
|
|
if ( item.is( 'textProxy' ) ) {
|
|
@@ -1005,15 +968,14 @@ export function createViewElementFromHighlightDescriptor( descriptor ) {
|
|
|
const viewElement = new HighlightAttributeElement( 'span', descriptor.attributes );
|
|
const viewElement = new HighlightAttributeElement( 'span', descriptor.attributes );
|
|
|
|
|
|
|
|
if ( descriptor.class ) {
|
|
if ( descriptor.class ) {
|
|
|
- const cssClasses = Array.isArray( descriptor.class ) ? descriptor.class : [ descriptor.class ];
|
|
|
|
|
- viewElement.addClass( ...cssClasses );
|
|
|
|
|
|
|
+ viewElement._addClass( descriptor.class );
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if ( descriptor.priority ) {
|
|
if ( descriptor.priority ) {
|
|
|
- viewElement.priority = descriptor.priority;
|
|
|
|
|
|
|
+ viewElement._priority = descriptor.priority;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- viewElement.setCustomProperty( 'highlightDescriptorId', descriptor.id );
|
|
|
|
|
|
|
+ viewElement._setCustomProperty( 'highlightDescriptorId', descriptor.id );
|
|
|
|
|
|
|
|
return viewElement;
|
|
return viewElement;
|
|
|
}
|
|
}
|