{"version":3,"sources":["webpack:///./node_modules/@ckeditor/ckeditor5-engine/src/conversion/downcasthelpers.js"],"names":["DowncastHelpers","config","this","add","downcastElementToElement","downcastAttributeToElement","downcastAttributeToAttribute","downcastMarkerToElement","downcastMarkerToHighlight","downcastMarkerToData","ConversionHelpers","insertText","evt","data","conversionApi","consumable","consume","item","viewWriter","writer","viewPosition","mapper","toViewPosition","range","start","viewText","createText","insert","remove","_step","viewStart","position","modelEnd","getShiftedBy","length","viewEnd","isPhantom","viewRange","createRange","removed","getTrimmed","_iterator","_createForOfIteratorHelper","createRangeIn","getItems","s","n","done","child","value","unbindViewElement","err","e","f","createViewElementFromHighlightDescriptor","descriptor","viewElement","createAttributeElement","attributes","classes","_addClass","priority","_priority","_id","id","convertRangeSelection","selection","isCollapsed","_step2","viewRanges","_iterator2","getRanges","toViewRange","push","setSelection","backward","isBackward","convertCollapsedSelection","modelPosition","getFirstPosition","brokenPosition","breakAttributes","clearAttributes","_step3","viewSelection","document","_iterator3","end","parent","isAttached","mergeAttributes","wrap","elementCreator","oldViewElement","attributeOldValue","newViewElement","attributeNewValue","name","ModelSelection","DocumentSelection","getFirstRange","unwrap","insertElement","bindElements","insertUIElement","isOpening","viewStartElement","viewEndElement","markerRange","_step4","_iterator4","bindElementToMarker","markerName","stop","removeUIElement","elements","markerNameToElements","_step5","_iterator5","element","unbindElementFromMarkerName","clear","createRangeOn","clearClonedElementsGroup","insertMarkerData","viewCreator","viewMarkerData","handleMarkerBoundary","isStart","elementAfter","nodeAfter","is","elementBefore","nodeBefore","modelElement","isBefore","toViewElement","insertMarkerAsAttribute","insertMarkerAsElement","attributeName","concat","group","markerNames","hasAttribute","getAttribute","split","unshift","setAttribute","join","viewElementName","attrs","createUIElement","removeMarkerData","viewData","_step6","_iterator6","removeMarkerFromAttribute","Set","delete","size","removeAttribute","Array","from","changeAttribute","attributeCreator","oldAttribute","newAttribute","CKEditorError","key","_step7","toArray","_iterator7","className","removeClass","keys","Object","_i","_keys","removeStyle","_step8","_iterator8","addClass","_i2","_keys3","setStyle","highlightText","highlightDescriptor","prepareDescriptor","_step9","rangeAfterWrap","_iterator9","isSimilar","highlightElement","ModelElement","test","getCustomProperty","_step10","_iterator10","ModelRange","_createIn","removeHighlight","viewHighlightElement","_step11","_iterator11","cloneDeep","view","normalizeToElementConfig","dispatcher","on","model","converterPriority","triggerBy","_step12","_iterator12","attributeKey","_mapReconversionTriggerEvent","children","_step13","_iterator13","childName","modelKey","eventName","values","_step14","_iterator14","modelValue","getFromAttributeCreator","_step15","_iterator15","normalizeToAttributeConfig","substr","viewElementType","modelData","createViewElementFromDefinition","viewElementDefinition","assign","createContainerElement","options","ViewAttributeElement","DEFAULT_PRIORITY","styles","_i3","_keys4","_step16","_iterator16","modelAttributeValue","D_Projects_UA_repo_Source_Client_UA_User_Web_node_modules_babel_runtime_helpers_esm_typeof_js__WEBPACK_IMPORTED_MODULE_4__"],"mappings":"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","file":"js/chunk-2d0daec7.25e8ea85.js","sourcesContent":["/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * Contains downcast (model-to-view) converters for {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher}.\n *\n * @module engine/conversion/downcasthelpers\n */\n\nimport ModelRange from '../model/range';\nimport ModelSelection from '../model/selection';\nimport ModelElement from '../model/element';\n\nimport ViewAttributeElement from '../view/attributeelement';\nimport DocumentSelection from '../model/documentselection';\nimport ConversionHelpers from './conversionhelpers';\n\nimport { cloneDeep } from 'lodash-es';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport toArray from '@ckeditor/ckeditor5-utils/src/toarray';\n\n/**\n * Downcast conversion helper functions.\n *\n * @extends module:engine/conversion/conversionhelpers~ConversionHelpers\n */\nexport default class DowncastHelpers extends ConversionHelpers {\n\t/**\n\t * Model element to view element conversion helper.\n\t *\n\t * This conversion results in creating a view element. For example, model `Foo` becomes `

Foo

` in the view.\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).elementToElement( {\n\t *\t\t\tmodel: 'paragraph',\n\t *\t\t\tview: 'p'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).elementToElement( {\n\t *\t\t\tmodel: 'paragraph',\n\t *\t\t\tview: 'div',\n\t *\t\t\tconverterPriority: 'high'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).elementToElement( {\n\t *\t\t\tmodel: 'fancyParagraph',\n\t *\t\t\tview: {\n\t *\t\t\t\tname: 'p',\n\t *\t\t\t\tclasses: 'fancy'\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).elementToElement( {\n\t *\t\t\tmodel: 'heading',\n\t *\t\t\tview: ( modelElement, conversionApi ) => {\n\t *\t\t\t\tconst { writer } = conversionApi;\n\t *\n\t *\t\t\t\treturn writer.createContainerElement( 'h' + modelElement.getAttribute( 'level' ) );\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * The element-to-element conversion supports the reconversion mechanism. This is helpful in the conversion to complex view structures\n\t * where multiple atomic element-to-element and attribute-to-attribute or attribute-to-element could be used. By specifying\n\t * `triggerBy()` events you can trigger reconverting the model to full view tree structures at once.\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).elementToElement( {\n\t *\t\t\tmodel: 'complex',\n\t *\t\t\tview: ( modelElement, conversionApi ) => createComplexViewFromModel( modelElement, conversionApi ),\n\t *\t\t\ttriggerBy: {\n\t *\t\t\t\tattributes: [ 'foo', 'bar' ],\n\t *\t\t\t\tchildren: [ 'slot' ]\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * See {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} to learn how to add a converter\n\t * to the conversion process.\n\t *\n\t * You can read more about element-to-element conversion in the\n\t * {@glink framework/guides/deep-dive/conversion/custom-element-conversion Custom element conversion} guide.\n\t *\n\t * @method #elementToElement\n\t * @param {Object} config Conversion configuration.\n\t * @param {String} config.model The name of the model element to convert.\n\t * @param {module:engine/view/elementdefinition~ElementDefinition|Function} config.view A view element definition or a function\n\t * that takes the model element and {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi downcast conversion API}\n\t * as parameters and returns a view container element.\n\t * @param {Object} [config.triggerBy] Reconversion triggers. At least one trigger must be defined.\n\t * @param {Array.} config.triggerBy.attributes The name of the element's attributes whose change will trigger element\n\t * reconversion.\n\t * @param {Array.} config.triggerBy.children The name of direct children whose adding or removing will trigger element\n\t * reconversion.\n\t * @returns {module:engine/conversion/downcasthelpers~DowncastHelpers}\n\t */\n\telementToElement( config ) {\n\t\treturn this.add( downcastElementToElement( config ) );\n\t}\n\n\t/**\n\t * Model attribute to view element conversion helper.\n\t *\n\t * This conversion results in wrapping view nodes with a view attribute element. For example, a model text node with\n\t * `\"Foo\"` as data and the `bold` attribute becomes `Foo` in the view.\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).attributeToElement( {\n\t *\t\t\tmodel: 'bold',\n\t *\t\t\tview: 'strong'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).attributeToElement( {\n\t *\t\t\tmodel: 'bold',\n\t *\t\t\tview: 'b',\n\t *\t\t\tconverterPriority: 'high'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).attributeToElement( {\n\t *\t\t\tmodel: 'invert',\n\t *\t\t\tview: {\n\t *\t\t\t\tname: 'span',\n\t *\t\t\t\tclasses: [ 'font-light', 'bg-dark' ]\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).attributeToElement( {\n\t *\t\t\tmodel: {\n\t *\t\t\t\tkey: 'fontSize',\n\t *\t\t\t\tvalues: [ 'big', 'small' ]\n\t *\t\t\t},\n\t *\t\t\tview: {\n\t *\t\t\t\tbig: {\n\t *\t\t\t\t\tname: 'span',\n\t *\t\t\t\t\tstyles: {\n\t *\t\t\t\t\t\t'font-size': '1.2em'\n\t *\t\t\t\t\t}\n\t *\t\t\t\t},\n\t *\t\t\t\tsmall: {\n\t *\t\t\t\t\tname: 'span',\n\t *\t\t\t\t\tstyles: {\n\t *\t\t\t\t\t\t'font-size': '0.8em'\n\t *\t\t\t\t\t}\n\t *\t\t\t\t}\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).attributeToElement( {\n\t *\t\t\tmodel: 'bold',\n\t *\t\t\tview: ( modelAttributeValue, conversionApi ) => {\n\t *\t\t\t\tconst { writer } = conversionApi;\n\t *\n\t *\t\t\t\treturn writer.createAttributeElement( 'span', {\n\t *\t\t\t\t\tstyle: 'font-weight:' + modelAttributeValue\n\t *\t\t\t\t} );\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).attributeToElement( {\n\t *\t\t\tmodel: {\n\t *\t\t\t\tkey: 'color',\n\t *\t\t\t\tname: '$text'\n\t *\t\t\t},\n\t *\t\t\tview: ( modelAttributeValue, conversionApi ) => {\n\t *\t\t\t\tconst { writer } = conversionApi;\n\t *\n\t *\t\t\t\treturn writer.createAttributeElement( 'span', {\n\t *\t\t\t\t\tstyle: 'color:' + modelAttributeValue\n\t *\t\t\t\t} );\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * See {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} to learn how to add a converter\n\t * to the conversion process.\n\t *\n\t * @method #attributeToElement\n\t * @param {Object} config Conversion configuration.\n\t * @param {String|Object} config.model The key of the attribute to convert from or a `{ key, values }` object. `values` is an array\n\t * of `String`s with possible values if the model attribute is an enumerable.\n\t * @param {module:engine/view/elementdefinition~ElementDefinition|Function|Object} config.view A view element definition or a function\n\t * that takes the model attribute value and\n\t * {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi downcast conversion API} as parameters and returns a view\n\t * attribute element. If `config.model.values` is given, `config.view` should be an object assigning values from `config.model.values`\n\t * to view element definitions or functions.\n\t * @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.\n\t * @returns {module:engine/conversion/downcasthelpers~DowncastHelpers}\n\t */\n\tattributeToElement( config ) {\n\t\treturn this.add( downcastAttributeToElement( config ) );\n\t}\n\n\t/**\n\t * Model attribute to view attribute conversion helper.\n\t *\n\t * This conversion results in adding an attribute to a view node, basing on an attribute from a model node. For example,\n\t * `` is converted to ``.\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).attributeToAttribute( {\n\t *\t\t\tmodel: 'source',\n\t *\t\t\tview: 'src'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).attributeToAttribute( {\n\t *\t\t\tmodel: 'source',\n\t *\t\t\tview: 'href',\n\t *\t\t\tconverterPriority: 'high'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).attributeToAttribute( {\n\t *\t\t\tmodel: {\n\t *\t\t\t\tname: 'imageInline',\n\t *\t\t\t\tkey: 'source'\n\t *\t\t\t},\n\t *\t\t\tview: 'src'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).attributeToAttribute( {\n\t *\t\t\tmodel: {\n\t *\t\t\t\tname: 'styled',\n\t *\t\t\t\tvalues: [ 'dark', 'light' ]\n\t *\t\t\t},\n\t *\t\t\tview: {\n\t *\t\t\t\tdark: {\n\t *\t\t\t\t\tkey: 'class',\n\t *\t\t\t\t\tvalue: [ 'styled', 'styled-dark' ]\n\t *\t\t\t\t},\n\t *\t\t\t\tlight: {\n\t *\t\t\t\t\tkey: 'class',\n\t *\t\t\t\t\tvalue: [ 'styled', 'styled-light' ]\n\t *\t\t\t\t}\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).attributeToAttribute( {\n\t *\t\t\tmodel: 'styled',\n\t *\t\t\tview: modelAttributeValue => ( {\n\t *\t\t\t\tkey: 'class',\n\t *\t\t\t\tvalue: 'styled-' + modelAttributeValue\n\t *\t\t\t} )\n\t *\t\t} );\n\t *\n\t * **Note**: Downcasting to a style property requires providing `value` as an object:\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).attributeToAttribute( {\n\t *\t\t\tmodel: 'lineHeight',\n\t *\t\t\tview: modelAttributeValue => ( {\n\t *\t\t\t\tkey: 'style',\n\t *\t\t\t\tvalue: {\n\t *\t\t\t\t\t'line-height': modelAttributeValue,\n\t *\t\t\t\t\t'border-bottom': '1px dotted #ba2'\n\t *\t\t\t\t}\n\t *\t\t\t} )\n\t *\t\t} );\n\t *\n\t * See {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} to learn how to add a converter\n\t * to the conversion process.\n\t *\n\t * @method #attributeToAttribute\n\t * @param {Object} config Conversion configuration.\n\t * @param {String|Object} config.model The key of the attribute to convert from or a `{ key, values, [ name ] }` object describing\n\t * the attribute key, possible values and, optionally, an element name to convert from.\n\t * @param {String|Object|Function} config.view A view attribute key, or a `{ key, value }` object or a function that takes\n\t * the model attribute value and {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi downcast conversion API}\n\t * as parameters and returns a `{ key, value }` object. If `key` is `'class'`, `value` can be a `String` or an\n\t * array of `String`s. If `key` is `'style'`, `value` is an object with key-value pairs. In other cases, `value` is a `String`.\n\t * If `config.model.values` is set, `config.view` should be an object assigning values from `config.model.values` to\n\t * `{ key, value }` objects or a functions.\n\t * @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.\n\t * @returns {module:engine/conversion/downcasthelpers~DowncastHelpers}\n\t */\n\tattributeToAttribute( config ) {\n\t\treturn this.add( downcastAttributeToAttribute( config ) );\n\t}\n\n\t/**\n\t * Model marker to view element conversion helper.\n\t *\n\t * **Note**: This method should be used mainly for editing downcast and it is recommended\n\t * to use {@link #markerToData `#markerToData()`} helper instead.\n\t *\n\t * This helper may produce invalid HTML code (e.g. a span between table cells).\n\t * It should be used only when you are sure that the produced HTML will be semantically correct.\n\t *\n\t * This conversion results in creating a view element on the boundaries of the converted marker. If the converted marker\n\t * is collapsed, only one element is created. For example, model marker set like this: `F[oo b]ar`\n\t * becomes `

Foo bar

` in the view.\n\t *\n\t *\t\teditor.conversion.for( 'editingDowncast' ).markerToElement( {\n\t *\t\t\tmodel: 'search',\n\t *\t\t\tview: 'marker-search'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'editingDowncast' ).markerToElement( {\n\t *\t\t\tmodel: 'search',\n\t *\t\t\tview: 'search-result',\n\t *\t\t\tconverterPriority: 'high'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'editingDowncast' ).markerToElement( {\n\t *\t\t\tmodel: 'search',\n\t *\t\t\tview: {\n\t *\t\t\t\tname: 'span',\n\t *\t\t\t\tattributes: {\n\t *\t\t\t\t\t'data-marker': 'search'\n\t *\t\t\t\t}\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'editingDowncast' ).markerToElement( {\n\t *\t\t\tmodel: 'search',\n\t *\t\t\tview: ( markerData, conversionApi ) => {\n\t *\t\t\t\tconst { writer } = conversionApi;\n\t *\n\t *\t\t\t\treturn writer.createUIElement( 'span', {\n\t *\t\t\t\t\t'data-marker': 'search',\n\t *\t\t\t\t\t'data-start': markerData.isOpening\n\t *\t\t\t\t} );\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * If a function is passed as the `config.view` parameter, it will be used to generate both boundary elements. The function\n\t * receives the `data` object and {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi downcast conversion API}\n\t * as a parameters and should return an instance of the\n\t * {@link module:engine/view/uielement~UIElement view UI element}. The `data` object and\n\t * {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi `conversionApi`} are passed from\n\t * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:addMarker}. Additionally,\n\t * the `data.isOpening` parameter is passed, which is set to `true` for the marker start boundary element, and `false` to\n\t * the marker end boundary element.\n\t *\n\t * See {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} to learn how to add a converter\n\t * to the conversion process.\n\t *\n\t * @method #markerToElement\n\t * @param {Object} config Conversion configuration.\n\t * @param {String} config.model The name of the model marker (or model marker group) to convert.\n\t * @param {module:engine/view/elementdefinition~ElementDefinition|Function} config.view A view element definition or a function that\n\t * takes the model marker data and {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi downcast conversion API}\n\t * as a parameters and returns a view UI element.\n\t * @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.\n\t * @returns {module:engine/conversion/downcasthelpers~DowncastHelpers}\n\t */\n\tmarkerToElement( config ) {\n\t\treturn this.add( downcastMarkerToElement( config ) );\n\t}\n\n\t/**\n\t * Model marker to highlight conversion helper.\n\t *\n\t * This conversion results in creating a highlight on view nodes. For this kind of conversion,\n\t * {@link module:engine/conversion/downcasthelpers~HighlightDescriptor} should be provided.\n\t *\n\t * For text nodes, a `` {@link module:engine/view/attributeelement~AttributeElement} is created and it wraps all text nodes\n\t * in the converted marker range. For example, a model marker set like this: `F[oo b]ar` becomes\n\t * `

Foo bar

` in the view.\n\t *\n\t * {@link module:engine/view/containerelement~ContainerElement} may provide a custom way of handling highlight. Most often,\n\t * the element itself is given classes and attributes described in the highlight descriptor (instead of being wrapped in ``).\n\t * For example, a model marker set like this:\n\t * `[]` becomes `` in the view.\n\t *\n\t * For container elements, the conversion is two-step. While the converter processes the highlight descriptor and passes it\n\t * to a container element, it is the container element instance itself that applies values from the highlight descriptor.\n\t * So, in a sense, the converter takes care of stating what should be applied on what, while the element decides how to apply that.\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).markerToHighlight( { model: 'comment', view: { classes: 'comment' } } );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).markerToHighlight( {\n\t *\t\t\tmodel: 'comment',\n\t *\t\t\tview: { classes: 'comment' },\n\t *\t\t\tconverterPriority: 'high'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).markerToHighlight( {\n\t *\t\t\tmodel: 'comment',\n\t *\t\t\tview: ( data, conversionApi ) => {\n\t *\t\t\t\t// Assuming that the marker name is in a form of comment:commentType:commentId.\n\t *\t\t\t\tconst [ , commentType, commentId ] = data.markerName.split( ':' );\n\t *\n\t *\t\t\t\treturn {\n\t *\t\t\t\t\tclasses: [ 'comment', 'comment-' + commentType ],\n\t *\t\t\t\t\tattributes: { 'data-comment-id': commentId }\n\t *\t\t\t\t};\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * If a function is passed as the `config.view` parameter, it will be used to generate the highlight descriptor. The function\n\t * receives the `data` object and {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi downcast conversion API}\n\t * as a parameters and should return a\n\t * {@link module:engine/conversion/downcasthelpers~HighlightDescriptor highlight descriptor}.\n\t * The `data` object properties are passed from {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:addMarker}.\n\t *\n\t * See {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} to learn how to add a converter\n\t * to the conversion process.\n\t *\n\t * @method #markerToHighlight\n\t * @param {Object} config Conversion configuration.\n\t * @param {String} config.model The name of the model marker (or model marker group) to convert.\n\t * @param {module:engine/conversion/downcasthelpers~HighlightDescriptor|Function} config.view A highlight descriptor\n\t * that will be used for highlighting or a function that takes the model marker data and\n\t * {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi downcast conversion API} as a parameters\n\t * and returns a highlight descriptor.\n\t * @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.\n\t * @returns {module:engine/conversion/downcasthelpers~DowncastHelpers}\n\t */\n\tmarkerToHighlight( config ) {\n\t\treturn this.add( downcastMarkerToHighlight( config ) );\n\t}\n\n\t/**\n\t * Model marker converter for data downcast.\n\t *\n\t * This conversion creates a representation for model marker boundaries in the view:\n\t *\n\t * * If the marker boundary is before or after a model element, a view attribute is set on a corresponding view element.\n\t * * In other cases, a view element with the specified tag name is inserted at the corresponding view position.\n\t *\n\t * Typically, the marker names use the `group:uniqueId:otherData` convention. For example: `comment:e34zfk9k2n459df53sjl34:zx32c`.\n\t * The default configuration for this conversion is that the first part is the `group` part and the rest of\n\t * the marker name becomes the `name` part.\n\t *\n\t * Tag and attribute names and values are generated from the marker name:\n\t *\n\t * * The templates for attributes are `data-[group]-start-before=\"[name]\"`, `data-[group]-start-after=\"[name]\"`,\n\t * `data-[group]-end-before=\"[name]\"` and `data-[group]-end-after=\"[name]\"`.\n\t * * The templates for view elements are `<[group]-start name=\"[name]\">` and `<[group]-end name=\"[name]\">`.\n\t *\n\t * Attributes mark whether the given marker's start or end boundary is before or after the given element.\n\t * The `data-[group]-start-before` and `data-[group]-end-after` attributes are favored.\n\t * The other two are used when the former two cannot be used.\n\t *\n\t * The conversion configuration can take a function that will generate different group and name parts.\n\t * If such a function is set as the `config.view` parameter, it is passed a marker name and it is expected to return an object with two\n\t * properties: `group` and `name`. If the function returns a falsy value, the conversion will not take place.\n\t *\n\t * Basic usage:\n\t *\n\t *\t\t// Using the default conversion.\n\t *\t\t// In this case, all markers with names starting with 'comment:' will be converted.\n\t *\t\t// The `group` parameter will be set to `comment`.\n\t *\t\t// The `name` parameter will be the rest of the marker name (without the `:`).\n\t *\t\teditor.conversion.for( 'dataDowncast' ).markerToData( {\n\t *\t\t\tmodel: 'comment'\n\t *\t\t} );\n\t *\n\t * An example of a view that may be generated by this conversion (assuming a marker with the name `comment:commentId:uid` marked\n\t * by `[]`):\n\t *\n\t *\t\t// Model:\n\t *\t\tFoo[bar\n\t *\t\t]\n\t *\n\t *\t\t// View:\n\t *\t\t

Foobar

\n\t *\t\t
\n\t *\n\t * In the example above, the comment starts before \"bar\" and ends after the image.\n\t *\n\t * If the `name` part is empty, the following view may be generated:\n\t *\n\t *\t\t

Foo bar

\n\t *\t\t
\n\t *\n\t * **Note:** A situation where some markers have the `name` part and some do not, is incorrect and should be avoided.\n\t *\n\t * Examples where `data-group-start-after` and `data-group-end-before` are used:\n\t *\n\t *\t\t// Model:\n\t *\t\t
[]Foo
\n\t *\n\t * \t\t// View:\n\t *\t\t

Foo

\n\t *\n\t * Similarly, when a marker is collapsed after the last element:\n\t *\n\t *\t\t// Model:\n\t *\t\t
Foo[]
\n\t *\n\t *\t\t// View:\n\t *\t\t

Foo

\n\t *\n\t * When there are multiple markers from the same group stored in the same attribute of the same element, their\n\t * name parts are put together in the attribute value, for example: `data-group-start-before=\"name1,name2,name3\"`.\n\t *\n\t * Other examples of usage:\n\t *\n\t *\t\t// Using a custom function which is the same as the default conversion:\n\t *\t\teditor.conversion.for( 'dataDowncast' ).markerToData( {\n\t *\t\t\tmodel: 'comment'\n\t *\t\t\tview: markerName => ( {\n\t *\t\t\t\tgroup: 'comment',\n\t *\t\t\t\tname: markerName.substr( 8 ) // Removes 'comment:' part.\n\t *\t\t\t} )\n\t *\t\t} );\n\t *\n\t *\t\t// Using the converter priority:\n\t *\t\teditor.conversion.for( 'dataDowncast' ).markerToData( {\n\t *\t\t\tmodel: 'comment'\n\t *\t\t\tview: markerName => ( {\n\t *\t\t\t\tgroup: 'comment',\n\t *\t\t\t\tname: markerName.substr( 8 ) // Removes 'comment:' part.\n\t *\t\t\t} ),\n\t *\t\t\tconverterPriority: 'high'\n\t *\t\t} );\n\t *\n\t * This kind of conversion is useful for saving data into the database, so it should be used in the data conversion pipeline.\n\t *\n\t * See the {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} API guide to learn how to\n\t * add a converter to the conversion process.\n\t *\n\t * @method #markerToData\n\t * @param {Object} config Conversion configuration.\n\t * @param {String} config.model The name of the model marker (or the model marker group) to convert.\n\t * @param {Function} [config.view] A function that takes the model marker name and\n\t * {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi downcast conversion API} as the parameters\n\t * and returns an object with the `group` and `name` properties.\n\t * @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.\n\t * @returns {module:engine/conversion/downcasthelpers~DowncastHelpers}\n\t */\n\tmarkerToData( config ) {\n\t\treturn this.add( downcastMarkerToData( config ) );\n\t}\n}\n\n/**\n * Function factory that creates a default downcast converter for text insertion changes.\n *\n * The converter automatically consumes the corresponding value from the consumables list and stops the event (see\n * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher}).\n *\n *\t\tmodelDispatcher.on( 'insert:$text', insertText() );\n *\n * @returns {Function} Insert text event converter.\n */\nexport function insertText() {\n\treturn ( evt, data, conversionApi ) => {\n\t\tif ( !conversionApi.consumable.consume( data.item, 'insert' ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst viewWriter = conversionApi.writer;\n\t\tconst viewPosition = conversionApi.mapper.toViewPosition( data.range.start );\n\t\tconst viewText = viewWriter.createText( data.item.data );\n\n\t\tviewWriter.insert( viewPosition, viewText );\n\t};\n}\n\n/**\n * Function factory that creates a default downcast converter for node remove changes.\n *\n *\t\tmodelDispatcher.on( 'remove', remove() );\n *\n * @returns {Function} Remove event converter.\n */\nexport function remove() {\n\treturn ( evt, data, conversionApi ) => {\n\t\t// Find the view range start position by mapping the model position at which the remove happened.\n\t\tconst viewStart = conversionApi.mapper.toViewPosition( data.position );\n\n\t\tconst modelEnd = data.position.getShiftedBy( data.length );\n\t\tconst viewEnd = conversionApi.mapper.toViewPosition( modelEnd, { isPhantom: true } );\n\n\t\tconst viewRange = conversionApi.writer.createRange( viewStart, viewEnd );\n\n\t\t// Trim the range to remove in case some UI elements are on the view range boundaries.\n\t\tconst removed = conversionApi.writer.remove( viewRange.getTrimmed() );\n\n\t\t// After the range is removed, unbind all view elements from the model.\n\t\t// Range inside view document fragment is used to unbind deeply.\n\t\tfor ( const child of conversionApi.writer.createRangeIn( removed ).getItems() ) {\n\t\t\tconversionApi.mapper.unbindViewElement( child );\n\t\t}\n\t};\n}\n\n/**\n * Creates a `` {@link module:engine/view/attributeelement~AttributeElement view attribute element} from the information\n * provided by the {@link module:engine/conversion/downcasthelpers~HighlightDescriptor highlight descriptor} object. If the priority\n * is not provided in the descriptor, the default priority will be used.\n *\n * @param {module:engine/view/downcastwriter~DowncastWriter} writer\n * @param {module:engine/conversion/downcasthelpers~HighlightDescriptor} descriptor\n * @returns {module:engine/view/attributeelement~AttributeElement}\n */\nexport function createViewElementFromHighlightDescriptor( writer, descriptor ) {\n\tconst viewElement = writer.createAttributeElement( 'span', descriptor.attributes );\n\n\tif ( descriptor.classes ) {\n\t\tviewElement._addClass( descriptor.classes );\n\t}\n\n\tif ( typeof descriptor.priority === 'number' ) {\n\t\tviewElement._priority = descriptor.priority;\n\t}\n\n\tviewElement._id = descriptor.id;\n\n\treturn viewElement;\n}\n\n/**\n * Function factory that creates a converter which converts a non-collapsed {@link module:engine/model/selection~Selection model selection}\n * to a {@link module:engine/view/documentselection~DocumentSelection view selection}. The converter consumes appropriate\n * value from the `consumable` object and maps model positions from the selection to view positions.\n *\n *\t\tmodelDispatcher.on( 'selection', convertRangeSelection() );\n *\n * @returns {Function} Selection converter.\n */\nexport function convertRangeSelection() {\n\treturn ( evt, data, conversionApi ) => {\n\t\tconst selection = data.selection;\n\n\t\tif ( selection.isCollapsed ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !conversionApi.consumable.consume( selection, 'selection' ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst viewRanges = [];\n\n\t\tfor ( const range of selection.getRanges() ) {\n\t\t\tconst viewRange = conversionApi.mapper.toViewRange( range );\n\t\t\tviewRanges.push( viewRange );\n\t\t}\n\n\t\tconversionApi.writer.setSelection( viewRanges, { backward: selection.isBackward } );\n\t};\n}\n\n/**\n * Function factory that creates a converter which converts a collapsed {@link module:engine/model/selection~Selection model selection} to\n * a {@link module:engine/view/documentselection~DocumentSelection view selection}. The converter consumes appropriate\n * value from the `consumable` object, maps the model selection position to the view position and breaks\n * {@link module:engine/view/attributeelement~AttributeElement attribute elements} at the selection position.\n *\n *\t\tmodelDispatcher.on( 'selection', convertCollapsedSelection() );\n *\n * An example of the view state before and after converting the collapsed selection:\n *\n *\t\t

f^oobar

\n *\t\t->

f^oobar

\n *\n * By breaking attribute elements like ``, the selection is in a correct element. Then, when the selection attribute is\n * converted, broken attributes might be merged again, or the position where the selection is may be wrapped\n * with different, appropriate attribute elements.\n *\n * See also {@link module:engine/conversion/downcasthelpers~clearAttributes} which does a clean-up\n * by merging attributes.\n *\n * @returns {Function} Selection converter.\n */\nexport function convertCollapsedSelection() {\n\treturn ( evt, data, conversionApi ) => {\n\t\tconst selection = data.selection;\n\n\t\tif ( !selection.isCollapsed ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !conversionApi.consumable.consume( selection, 'selection' ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst viewWriter = conversionApi.writer;\n\t\tconst modelPosition = selection.getFirstPosition();\n\t\tconst viewPosition = conversionApi.mapper.toViewPosition( modelPosition );\n\t\tconst brokenPosition = viewWriter.breakAttributes( viewPosition );\n\n\t\tviewWriter.setSelection( brokenPosition );\n\t};\n}\n\n/**\n * Function factory that creates a converter which clears artifacts after the previous\n * {@link module:engine/model/selection~Selection model selection} conversion. It removes all empty\n * {@link module:engine/view/attributeelement~AttributeElement view attribute elements} and merges sibling attributes at all start and end\n * positions of all ranges.\n *\n *\t\t

^

\n *\t\t->

^

\n *\n *\t\t

foo^barbar

\n *\t\t->

foo^barbar

\n *\n *\t\t

foo^barbar

\n *\t\t->

foo^barbar

\n *\n * This listener should be assigned before any converter for the new selection:\n *\n *\t\tmodelDispatcher.on( 'selection', clearAttributes() );\n *\n * See {@link module:engine/conversion/downcasthelpers~convertCollapsedSelection}\n * which does the opposite by breaking attributes in the selection position.\n *\n * @returns {Function} Selection converter.\n */\nexport function clearAttributes() {\n\treturn ( evt, data, conversionApi ) => {\n\t\tconst viewWriter = conversionApi.writer;\n\t\tconst viewSelection = viewWriter.document.selection;\n\n\t\tfor ( const range of viewSelection.getRanges() ) {\n\t\t\t// Not collapsed selection should not have artifacts.\n\t\t\tif ( range.isCollapsed ) {\n\t\t\t\t// Position might be in the node removed by the view writer.\n\t\t\t\tif ( range.end.parent.isAttached() ) {\n\t\t\t\t\tconversionApi.writer.mergeAttributes( range.start );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tviewWriter.setSelection( null );\n\t};\n}\n\n/**\n * Function factory that creates a converter which converts set/change/remove attribute changes from the model to the view.\n * It can also be used to convert selection attributes. In that case, an empty attribute element will be created and the\n * selection will be put inside it.\n *\n * Attributes from the model are converted to a view element that will be wrapping these view nodes that are bound to\n * model elements having the given attribute. This is useful for attributes like `bold` that may be set on text nodes in the model\n * but are represented as an element in the view:\n *\n *\t\t[paragraph] MODEL ====> VIEW

\n *\t\t\t|- a {bold: true} |- \n *\t\t\t|- b {bold: true} | |- ab\n *\t\t\t|- c |- c\n *\n * Passed `Function` will be provided with the attribute value and then all the parameters of the\n * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:attribute `attribute` event}.\n * It is expected that the function returns an {@link module:engine/view/element~Element}.\n * The result of the function will be the wrapping element.\n * When the provided `Function` does not return any element, no conversion will take place.\n *\n * The converter automatically consumes the corresponding value from the consumables list and stops the event (see\n * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher}).\n *\n *\t\tmodelDispatcher.on( 'attribute:bold', wrap( ( modelAttributeValue, { writer } ) => {\n *\t\t\treturn writer.createAttributeElement( 'strong' );\n *\t\t} );\n *\n * @protected\n * @param {Function} elementCreator Function returning a view element that will be used for wrapping.\n * @returns {Function} Set/change attribute converter.\n */\nexport function wrap( elementCreator ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\t// Recreate current wrapping node. It will be used to unwrap view range if the attribute value has changed\n\t\t// or the attribute was removed.\n\t\tconst oldViewElement = elementCreator( data.attributeOldValue, conversionApi );\n\n\t\t// Create node to wrap with.\n\t\tconst newViewElement = elementCreator( data.attributeNewValue, conversionApi );\n\n\t\tif ( !oldViewElement && !newViewElement ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !conversionApi.consumable.consume( data.item, evt.name ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst viewWriter = conversionApi.writer;\n\t\tconst viewSelection = viewWriter.document.selection;\n\n\t\tif ( data.item instanceof ModelSelection || data.item instanceof DocumentSelection ) {\n\t\t\t// Selection attribute conversion.\n\t\t\tviewWriter.wrap( viewSelection.getFirstRange(), newViewElement );\n\t\t} else {\n\t\t\t// Node attribute conversion.\n\t\t\tlet viewRange = conversionApi.mapper.toViewRange( data.range );\n\n\t\t\t// First, unwrap the range from current wrapper.\n\t\t\tif ( data.attributeOldValue !== null && oldViewElement ) {\n\t\t\t\tviewRange = viewWriter.unwrap( viewRange, oldViewElement );\n\t\t\t}\n\n\t\t\tif ( data.attributeNewValue !== null && newViewElement ) {\n\t\t\t\tviewWriter.wrap( viewRange, newViewElement );\n\t\t\t}\n\t\t}\n\t};\n}\n\n/**\n * Function factory that creates a converter which converts node insertion changes from the model to the view.\n * The function passed will be provided with all the parameters of the dispatcher's\n * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:insert `insert` event}.\n * It is expected that the function returns an {@link module:engine/view/element~Element}.\n * The result of the function will be inserted into the view.\n *\n * The converter automatically consumes the corresponding value from the consumables list, stops the event (see\n * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher}) and binds the model and view elements.\n *\n *\t\tdowncastDispatcher.on(\n *\t\t\t'insert:myElem',\n *\t\t\tinsertElement( ( modelItem, { writer } ) => {\n *\t\t\t\tconst text = writer.createText( 'myText' );\n *\t\t\t\tconst myElem = writer.createElement( 'myElem', { myAttr: 'my-' + modelItem.getAttribute( 'myAttr' ) }, text );\n *\n *\t\t\t\t// Do something fancy with `myElem` using `modelItem` or other parameters.\n *\n *\t\t\t\treturn myElem;\n *\t\t\t}\n *\t\t) );\n *\n * @protected\n * @param {Function} elementCreator Function returning a view element, which will be inserted.\n * @returns {Function} Insert element event converter.\n */\nexport function insertElement( elementCreator ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\tconst viewElement = elementCreator( data.item, conversionApi );\n\n\t\tif ( !viewElement ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !conversionApi.consumable.consume( data.item, 'insert' ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst viewPosition = conversionApi.mapper.toViewPosition( data.range.start );\n\n\t\tconversionApi.mapper.bindElements( data.item, viewElement );\n\t\tconversionApi.writer.insert( viewPosition, viewElement );\n\t};\n}\n\n/**\n * Function factory that creates a converter which converts marker adding change to the\n * {@link module:engine/view/uielement~UIElement view UI element}.\n *\n * The view UI element that will be added to the view depends on the passed parameter. See {@link ~insertElement}.\n * In case of a non-collapsed range, the UI element will not wrap nodes but separate elements will be placed at the beginning\n * and at the end of the range.\n *\n * This converter binds created UI elements with the marker name using {@link module:engine/conversion/mapper~Mapper#bindElementToMarker}.\n *\n * @protected\n * @param {module:engine/view/uielement~UIElement|Function} elementCreator A view UI element or a function returning the view element\n * that will be inserted.\n * @returns {Function} Insert element event converter.\n */\nexport function insertUIElement( elementCreator ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\t// Create two view elements. One will be inserted at the beginning of marker, one at the end.\n\t\t// If marker is collapsed, only \"opening\" element will be inserted.\n\t\tdata.isOpening = true;\n\t\tconst viewStartElement = elementCreator( data, conversionApi );\n\n\t\tdata.isOpening = false;\n\t\tconst viewEndElement = elementCreator( data, conversionApi );\n\n\t\tif ( !viewStartElement || !viewEndElement ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst markerRange = data.markerRange;\n\n\t\t// Marker that is collapsed has consumable build differently that non-collapsed one.\n\t\t// For more information see `addMarker` event description.\n\t\t// If marker's range is collapsed - check if it can be consumed.\n\t\tif ( markerRange.isCollapsed && !conversionApi.consumable.consume( markerRange, evt.name ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If marker's range is not collapsed - consume all items inside.\n\t\tfor ( const value of markerRange ) {\n\t\t\tif ( !conversionApi.consumable.consume( value.item, evt.name ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tconst mapper = conversionApi.mapper;\n\t\tconst viewWriter = conversionApi.writer;\n\n\t\t// Add \"opening\" element.\n\t\tviewWriter.insert( mapper.toViewPosition( markerRange.start ), viewStartElement );\n\t\tconversionApi.mapper.bindElementToMarker( viewStartElement, data.markerName );\n\n\t\t// Add \"closing\" element only if range is not collapsed.\n\t\tif ( !markerRange.isCollapsed ) {\n\t\t\tviewWriter.insert( mapper.toViewPosition( markerRange.end ), viewEndElement );\n\t\t\tconversionApi.mapper.bindElementToMarker( viewEndElement, data.markerName );\n\t\t}\n\n\t\tevt.stop();\n\t};\n}\n\n// Function factory that returns a default downcast converter for removing a {@link module:engine/view/uielement~UIElement UI element}\n// based on marker remove change.\n//\n// This converter unbinds elements from the marker name.\n//\n// @returns {Function} Removed UI element converter.\nfunction removeUIElement() {\n\treturn ( evt, data, conversionApi ) => {\n\t\tconst elements = conversionApi.mapper.markerNameToElements( data.markerName );\n\n\t\tif ( !elements ) {\n\t\t\treturn;\n\t\t}\n\n\t\tfor ( const element of elements ) {\n\t\t\tconversionApi.mapper.unbindElementFromMarkerName( element, data.markerName );\n\t\t\tconversionApi.writer.clear( conversionApi.writer.createRangeOn( element ), element );\n\t\t}\n\n\t\tconversionApi.writer.clearClonedElementsGroup( data.markerName );\n\n\t\tevt.stop();\n\t};\n}\n\n// Function factory that creates a default converter for model markers.\n//\n// See {@link DowncastHelpers#markerToData} for more information what type of view is generated.\n//\n// This converter binds created UI elements and affected view elements with the marker name\n// using {@link module:engine/conversion/mapper~Mapper#bindElementToMarker}.\n//\n// @returns {Function} Add marker converter.\nfunction insertMarkerData( viewCreator ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\tconst viewMarkerData = viewCreator( data.markerName, conversionApi );\n\n\t\tif ( !viewMarkerData ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst markerRange = data.markerRange;\n\n\t\tif ( !conversionApi.consumable.consume( markerRange, evt.name ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Adding closing data first to keep the proper order in the view.\n\t\thandleMarkerBoundary( markerRange, false, conversionApi, data, viewMarkerData );\n\t\thandleMarkerBoundary( markerRange, true, conversionApi, data, viewMarkerData );\n\n\t\tevt.stop();\n\t};\n}\n\n// Helper function for `insertMarkerData()` that marks a marker boundary at the beginning or end of given `range`.\nfunction handleMarkerBoundary( range, isStart, conversionApi, data, viewMarkerData ) {\n\tconst modelPosition = isStart ? range.start : range.end;\n\tconst elementAfter = modelPosition.nodeAfter && modelPosition.nodeAfter.is( 'element' ) ? modelPosition.nodeAfter : null;\n\tconst elementBefore = modelPosition.nodeBefore && modelPosition.nodeBefore.is( 'element' ) ? modelPosition.nodeBefore : null;\n\n\tif ( elementAfter || elementBefore ) {\n\t\tlet modelElement;\n\t\tlet isBefore;\n\n\t\t// If possible, we want to add `data-group-start-before` and `data-group-end-after` attributes.\n\t\tif ( isStart && elementAfter || !isStart && !elementBefore ) {\n\t\t\t// [... -> ...\n\t\t\t// ] -> \n\t\t\tmodelElement = elementAfter;\n\t\t\tisBefore = true;\n\t\t} else {\n\t\t\t// ...] -> ...\n\t\t\t// [ -> \n\t\t\tmodelElement = elementBefore;\n\t\t\tisBefore = false;\n\t\t}\n\n\t\tconst viewElement = conversionApi.mapper.toViewElement( modelElement );\n\n\t\t// In rare circumstances, the model element may be not mapped to any view element and that would cause an error.\n\t\t// One of those situations is a soft break inside code block.\n\t\tif ( viewElement ) {\n\t\t\tinsertMarkerAsAttribute( viewElement, isStart, isBefore, conversionApi, data, viewMarkerData );\n\n\t\t\treturn;\n\t\t}\n\t}\n\n\tconst viewPosition = conversionApi.mapper.toViewPosition( modelPosition );\n\n\tinsertMarkerAsElement( viewPosition, isStart, conversionApi, data, viewMarkerData );\n}\n\n// Helper function for `insertMarkerData()` that marks a marker boundary in the view as an attribute on a view element.\nfunction insertMarkerAsAttribute( viewElement, isStart, isBefore, conversionApi, data, viewMarkerData ) {\n\tconst attributeName = `data-${ viewMarkerData.group }-${ isStart ? 'start' : 'end' }-${ isBefore ? 'before' : 'after' }`;\n\n\tconst markerNames = viewElement.hasAttribute( attributeName ) ? viewElement.getAttribute( attributeName ).split( ',' ) : [];\n\n\t// Adding marker name at the beginning to have the same order in the attribute as there is with marker elements.\n\tmarkerNames.unshift( viewMarkerData.name );\n\n\tconversionApi.writer.setAttribute( attributeName, markerNames.join( ',' ), viewElement );\n\tconversionApi.mapper.bindElementToMarker( viewElement, data.markerName );\n}\n\n// Helper function for `insertMarkerData()` that marks a marker boundary in the view as a separate view ui element.\nfunction insertMarkerAsElement( position, isStart, conversionApi, data, viewMarkerData ) {\n\tconst viewElementName = `${ viewMarkerData.group }-${ isStart ? 'start' : 'end' }`;\n\n\tconst attrs = viewMarkerData.name ? { 'name': viewMarkerData.name } : null;\n\tconst viewElement = conversionApi.writer.createUIElement( viewElementName, attrs );\n\n\tconversionApi.writer.insert( position, viewElement );\n\tconversionApi.mapper.bindElementToMarker( viewElement, data.markerName );\n}\n\n// Function factory that creates a converter for removing a model marker data added by the {@link #insertMarkerData} converter.\n//\n// @returns {Function} Remove marker converter.\nfunction removeMarkerData( viewCreator ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\tconst viewData = viewCreator( data.markerName, conversionApi );\n\n\t\tif ( !viewData ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst elements = conversionApi.mapper.markerNameToElements( data.markerName );\n\n\t\tif ( !elements ) {\n\t\t\treturn;\n\t\t}\n\n\t\tfor ( const element of elements ) {\n\t\t\tconversionApi.mapper.unbindElementFromMarkerName( element, data.markerName );\n\n\t\t\tif ( element.is( 'containerElement' ) ) {\n\t\t\t\tremoveMarkerFromAttribute( `data-${ viewData.group }-start-before`, element );\n\t\t\t\tremoveMarkerFromAttribute( `data-${ viewData.group }-start-after`, element );\n\t\t\t\tremoveMarkerFromAttribute( `data-${ viewData.group }-end-before`, element );\n\t\t\t\tremoveMarkerFromAttribute( `data-${ viewData.group }-end-after`, element );\n\t\t\t} else {\n\t\t\t\tconversionApi.writer.clear( conversionApi.writer.createRangeOn( element ), element );\n\t\t\t}\n\t\t}\n\n\t\tconversionApi.writer.clearClonedElementsGroup( data.markerName );\n\n\t\tevt.stop();\n\n\t\tfunction removeMarkerFromAttribute( attributeName, element ) {\n\t\t\tif ( element.hasAttribute( attributeName ) ) {\n\t\t\t\tconst markerNames = new Set( element.getAttribute( attributeName ).split( ',' ) );\n\t\t\t\tmarkerNames.delete( viewData.name );\n\n\t\t\t\tif ( markerNames.size == 0 ) {\n\t\t\t\t\tconversionApi.writer.removeAttribute( attributeName, element );\n\t\t\t\t} else {\n\t\t\t\t\tconversionApi.writer.setAttribute( attributeName, Array.from( markerNames ).join( ',' ), element );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n}\n\n// Function factory that creates a converter which converts set/change/remove attribute changes from the model to the view.\n//\n// Attributes from the model are converted to the view element attributes in the view. You may provide a custom function to generate\n// a key-value attribute pair to add/change/remove. If not provided, model attributes will be converted to view element\n// attributes on a one-to-one basis.\n//\n// *Note:** The provided attribute creator should always return the same `key` for a given attribute from the model.\n//\n// The converter automatically consumes the corresponding value from the consumables list and stops the event (see\n// {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher}).\n//\n//\t\tmodelDispatcher.on( 'attribute:customAttr:myElem', changeAttribute( ( value, data ) => {\n//\t\t\t// Change attribute key from `customAttr` to `class` in the view.\n//\t\t\tconst key = 'class';\n//\t\t\tlet value = data.attributeNewValue;\n//\n//\t\t\t// Force attribute value to 'empty' if the model element is empty.\n//\t\t\tif ( data.item.childCount === 0 ) {\n//\t\t\t\tvalue = 'empty';\n//\t\t\t}\n//\n//\t\t\t// Return the key-value pair.\n//\t\t\treturn { key, value };\n//\t\t} ) );\n//\n// @param {Function} [attributeCreator] Function returning an object with two properties: `key` and `value`, which\n// represent the attribute key and attribute value to be set on a {@link module:engine/view/element~Element view element}.\n// The function is passed the model attribute value as the first parameter and additional data about the change as the second parameter.\n// @returns {Function} Set/change attribute converter.\nfunction changeAttribute( attributeCreator ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\tconst oldAttribute = attributeCreator( data.attributeOldValue, conversionApi );\n\t\tconst newAttribute = attributeCreator( data.attributeNewValue, conversionApi );\n\n\t\tif ( !oldAttribute && !newAttribute ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !conversionApi.consumable.consume( data.item, evt.name ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst viewElement = conversionApi.mapper.toViewElement( data.item );\n\t\tconst viewWriter = conversionApi.writer;\n\n\t\t// If model item cannot be mapped to a view element, it means item is not an `Element` instance but a `TextProxy` node.\n\t\t// Only elements can have attributes in a view so do not proceed for anything else (#1587).\n\t\tif ( !viewElement ) {\n\t\t\t/**\n\t\t\t * This error occurs when a {@link module:engine/model/textproxy~TextProxy text node's} attribute is to be downcasted\n\t\t\t * by {@link module:engine/conversion/conversion~Conversion#attributeToAttribute `Attribute to Attribute converter`}.\n\t\t\t * In most cases it is caused by converters misconfiguration when only \"generic\" converter is defined:\n\t\t\t *\n\t\t\t *\t\teditor.conversion.for( 'downcast' ).attributeToAttribute( {\n\t\t\t *\t\t\tmodel: 'attribute-name',\n\t\t\t *\t\t\tview: 'attribute-name'\n\t\t\t *\t\t} ) );\n\t\t\t *\n\t\t\t * and given attribute is used on text node, for example:\n\t\t\t *\n\t\t\t *\t\tmodel.change( writer => {\n\t\t\t *\t\t\twriter.insertText( 'Foo', { 'attribute-name': 'bar' }, parent, 0 );\n\t\t\t *\t\t} );\n\t\t\t *\n\t\t\t * In such cases, to convert the same attribute for both {@link module:engine/model/element~Element}\n\t\t\t * and {@link module:engine/model/textproxy~TextProxy `Text`} nodes, text specific\n\t\t\t * {@link module:engine/conversion/conversion~Conversion#attributeToElement `Attribute to Element converter`}\n\t\t\t * with higher {@link module:utils/priorities~PriorityString priority} must also be defined:\n\t\t\t *\n\t\t\t *\t\teditor.conversion.for( 'downcast' ).attributeToElement( {\n\t\t\t *\t\t\tmodel: {\n\t\t\t *\t\t\t\tkey: 'attribute-name',\n\t\t\t *\t\t\t\tname: '$text'\n\t\t\t *\t\t\t},\n\t\t\t *\t\t\tview: ( value, { writer } ) => {\n\t\t\t *\t\t\t\treturn writer.createAttributeElement( 'span', { 'attribute-name': value } );\n\t\t\t *\t\t\t},\n\t\t\t *\t\t\tconverterPriority: 'high'\n\t\t\t *\t\t} ) );\n\t\t\t *\n\t\t\t * @error conversion-attribute-to-attribute-on-text\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'conversion-attribute-to-attribute-on-text',\n\t\t\t\t[ data, conversionApi ]\n\t\t\t);\n\t\t}\n\n\t\t// First remove the old attribute if there was one.\n\t\tif ( data.attributeOldValue !== null && oldAttribute ) {\n\t\t\tif ( oldAttribute.key == 'class' ) {\n\t\t\t\tconst classes = toArray( oldAttribute.value );\n\n\t\t\t\tfor ( const className of classes ) {\n\t\t\t\t\tviewWriter.removeClass( className, viewElement );\n\t\t\t\t}\n\t\t\t} else if ( oldAttribute.key == 'style' ) {\n\t\t\t\tconst keys = Object.keys( oldAttribute.value );\n\n\t\t\t\tfor ( const key of keys ) {\n\t\t\t\t\tviewWriter.removeStyle( key, viewElement );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tviewWriter.removeAttribute( oldAttribute.key, viewElement );\n\t\t\t}\n\t\t}\n\n\t\t// Then set the new attribute.\n\t\tif ( data.attributeNewValue !== null && newAttribute ) {\n\t\t\tif ( newAttribute.key == 'class' ) {\n\t\t\t\tconst classes = toArray( newAttribute.value );\n\n\t\t\t\tfor ( const className of classes ) {\n\t\t\t\t\tviewWriter.addClass( className, viewElement );\n\t\t\t\t}\n\t\t\t} else if ( newAttribute.key == 'style' ) {\n\t\t\t\tconst keys = Object.keys( newAttribute.value );\n\n\t\t\t\tfor ( const key of keys ) {\n\t\t\t\t\tviewWriter.setStyle( key, newAttribute.value[ key ], viewElement );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tviewWriter.setAttribute( newAttribute.key, newAttribute.value, viewElement );\n\t\t\t}\n\t\t}\n\t};\n}\n\n// Function factory that creates a converter which converts the text inside marker's range. The converter wraps the text with\n// {@link module:engine/view/attributeelement~AttributeElement} created from the provided descriptor.\n// See {link module:engine/conversion/downcasthelpers~createViewElementFromHighlightDescriptor}.\n//\n// It can also be used to convert the selection that is inside a marker. In that case, an empty attribute element will be\n// created and the selection will be put inside it.\n//\n// If the highlight descriptor does not provide the `priority` property, `10` will be used.\n//\n// If the highlight descriptor does not provide the `id` property, the name of the marker will be used.\n//\n// This converter binds the created {@link module:engine/view/attributeelement~AttributeElement attribute elemens} with the marker name\n// using the {@link module:engine/conversion/mapper~Mapper#bindElementToMarker} method.\n//\n// @param {module:engine/conversion/downcasthelpers~HighlightDescriptor|Function} highlightDescriptor\n// @returns {Function}\nfunction highlightText( highlightDescriptor ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\tif ( !data.item ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !( data.item instanceof ModelSelection || data.item instanceof DocumentSelection ) && !data.item.is( '$textProxy' ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst descriptor = prepareDescriptor( highlightDescriptor, data, conversionApi );\n\n\t\tif ( !descriptor ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !conversionApi.consumable.consume( data.item, evt.name ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst viewWriter = conversionApi.writer;\n\t\tconst viewElement = createViewElementFromHighlightDescriptor( viewWriter, descriptor );\n\t\tconst viewSelection = viewWriter.document.selection;\n\n\t\tif ( data.item instanceof ModelSelection || data.item instanceof DocumentSelection ) {\n\t\t\tviewWriter.wrap( viewSelection.getFirstRange(), viewElement, viewSelection );\n\t\t} else {\n\t\t\tconst viewRange = conversionApi.mapper.toViewRange( data.range );\n\t\t\tconst rangeAfterWrap = viewWriter.wrap( viewRange, viewElement );\n\n\t\t\tfor ( const element of rangeAfterWrap.getItems() ) {\n\t\t\t\tif ( element.is( 'attributeElement' ) && element.isSimilar( viewElement ) ) {\n\t\t\t\t\tconversionApi.mapper.bindElementToMarker( element, data.markerName );\n\n\t\t\t\t\t// One attribute element is enough, because all of them are bound together by the view writer.\n\t\t\t\t\t// Mapper uses this binding to get all the elements no matter how many of them are registered in the mapper.\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n}\n\n// Converter function factory. It creates a function which applies the marker's highlight to an element inside the marker's range.\n//\n// The converter checks if an element has the `addHighlight` function stored as a\n// {@link module:engine/view/element~Element#_setCustomProperty custom property} and, if so, uses it to apply the highlight.\n// In such case the converter will consume all element's children, assuming that they were handled by the element itself.\n//\n// When the `addHighlight` custom property is not present, the element is not converted in any special way.\n// This means that converters will proceed to convert the element's child nodes.\n//\n// If the highlight descriptor does not provide the `priority` property, `10` will be used.\n//\n// If the highlight descriptor does not provide the `id` property, the name of the marker will be used.\n//\n// This converter binds altered {@link module:engine/view/containerelement~ContainerElement container elements} with the marker name using\n// the {@link module:engine/conversion/mapper~Mapper#bindElementToMarker} method.\n//\n// @param {module:engine/conversion/downcasthelpers~HighlightDescriptor|Function} highlightDescriptor\n// @returns {Function}\nfunction highlightElement( highlightDescriptor ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\tif ( !data.item ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !( data.item instanceof ModelElement ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst descriptor = prepareDescriptor( highlightDescriptor, data, conversionApi );\n\n\t\tif ( !descriptor ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !conversionApi.consumable.test( data.item, evt.name ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst viewElement = conversionApi.mapper.toViewElement( data.item );\n\n\t\tif ( viewElement && viewElement.getCustomProperty( 'addHighlight' ) ) {\n\t\t\t// Consume element itself.\n\t\t\tconversionApi.consumable.consume( data.item, evt.name );\n\n\t\t\t// Consume all children nodes.\n\t\t\tfor ( const value of ModelRange._createIn( data.item ) ) {\n\t\t\t\tconversionApi.consumable.consume( value.item, evt.name );\n\t\t\t}\n\n\t\t\tviewElement.getCustomProperty( 'addHighlight' )( viewElement, descriptor, conversionApi.writer );\n\n\t\t\tconversionApi.mapper.bindElementToMarker( viewElement, data.markerName );\n\t\t}\n\t};\n}\n\n// Function factory that creates a converter which converts the removing model marker to the view.\n//\n// Both text nodes and elements are handled by this converter but they are handled a bit differently.\n//\n// Text nodes are unwrapped using the {@link module:engine/view/attributeelement~AttributeElement attribute element} created from the\n// provided highlight descriptor. See {link module:engine/conversion/downcasthelpers~HighlightDescriptor}.\n//\n// For elements, the converter checks if an element has the `removeHighlight` function stored as a\n// {@link module:engine/view/element~Element#_setCustomProperty custom property}. If so, it uses it to remove the highlight.\n// In such case, the children of that element will not be converted.\n//\n// When `removeHighlight` is not present, the element is not converted in any special way.\n// The converter will proceed to convert the element's child nodes instead.\n//\n// If the highlight descriptor does not provide the `priority` property, `10` will be used.\n//\n// If the highlight descriptor does not provide the `id` property, the name of the marker will be used.\n//\n// This converter unbinds elements from the marker name.\n//\n// @param {module:engine/conversion/downcasthelpers~HighlightDescriptor|Function} highlightDescriptor\n// @returns {Function}\nfunction removeHighlight( highlightDescriptor ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\t// This conversion makes sense only for non-collapsed range.\n\t\tif ( data.markerRange.isCollapsed ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst descriptor = prepareDescriptor( highlightDescriptor, data, conversionApi );\n\n\t\tif ( !descriptor ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// View element that will be used to unwrap `AttributeElement`s.\n\t\tconst viewHighlightElement = createViewElementFromHighlightDescriptor( conversionApi.writer, descriptor );\n\n\t\t// Get all elements bound with given marker name.\n\t\tconst elements = conversionApi.mapper.markerNameToElements( data.markerName );\n\n\t\tif ( !elements ) {\n\t\t\treturn;\n\t\t}\n\n\t\tfor ( const element of elements ) {\n\t\t\tconversionApi.mapper.unbindElementFromMarkerName( element, data.markerName );\n\n\t\t\tif ( element.is( 'attributeElement' ) ) {\n\t\t\t\tconversionApi.writer.unwrap( conversionApi.writer.createRangeOn( element ), viewHighlightElement );\n\t\t\t} else {\n\t\t\t\t// if element.is( 'containerElement' ).\n\t\t\t\telement.getCustomProperty( 'removeHighlight' )( element, descriptor.id, conversionApi.writer );\n\t\t\t}\n\t\t}\n\n\t\tconversionApi.writer.clearClonedElementsGroup( data.markerName );\n\n\t\tevt.stop();\n\t};\n}\n\n// Model element to view element conversion helper.\n//\n// See {@link ~DowncastHelpers#elementToElement `.elementToElement()` downcast helper} for examples and config params description.\n//\n// @param {Object} config Conversion configuration.\n// @param {String} config.model\n// @param {module:engine/view/elementdefinition~ElementDefinition|Function} config.view\n// @param {Object} [config.triggerBy]\n// @param {Array.} [config.triggerBy.attributes]\n// @param {Array.} [config.triggerBy.children]\n// @returns {Function} Conversion helper.\nfunction downcastElementToElement( config ) {\n\tconfig = cloneDeep( config );\n\n\tconfig.view = normalizeToElementConfig( config.view, 'container' );\n\n\treturn dispatcher => {\n\t\tdispatcher.on( 'insert:' + config.model, insertElement( config.view ), { priority: config.converterPriority || 'normal' } );\n\n\t\tif ( config.triggerBy ) {\n\t\t\tif ( config.triggerBy.attributes ) {\n\t\t\t\tfor ( const attributeKey of config.triggerBy.attributes ) {\n\t\t\t\t\tdispatcher._mapReconversionTriggerEvent( config.model, `attribute:${ attributeKey }:${ config.model }` );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( config.triggerBy.children ) {\n\t\t\t\tfor ( const childName of config.triggerBy.children ) {\n\t\t\t\t\tdispatcher._mapReconversionTriggerEvent( config.model, `insert:${ childName }` );\n\t\t\t\t\tdispatcher._mapReconversionTriggerEvent( config.model, `remove:${ childName }` );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n}\n\n// Model attribute to view element conversion helper.\n//\n// See {@link ~DowncastHelpers#attributeToElement `.attributeToElement()` downcast helper} for examples.\n//\n// @param {Object} config Conversion configuration.\n// @param {String|Object} config.model The key of the attribute to convert from or a `{ key, values }` object. `values` is an array\n// of `String`s with possible values if the model attribute is an enumerable.\n// @param {module:engine/view/elementdefinition~ElementDefinition|Function|Object} config.view A view element definition or a function\n// that takes the model attribute value and {@link module:engine/view/downcastwriter~DowncastWriter view downcast writer}\n// as parameters and returns a view attribute element. If `config.model.values` is\n// given, `config.view` should be an object assigning values from `config.model.values` to view element definitions or functions.\n// @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.\n// @returns {Function} Conversion helper.\nfunction downcastAttributeToElement( config ) {\n\tconfig = cloneDeep( config );\n\n\tconst modelKey = config.model.key ? config.model.key : config.model;\n\tlet eventName = 'attribute:' + modelKey;\n\n\tif ( config.model.name ) {\n\t\teventName += ':' + config.model.name;\n\t}\n\n\tif ( config.model.values ) {\n\t\tfor ( const modelValue of config.model.values ) {\n\t\t\tconfig.view[ modelValue ] = normalizeToElementConfig( config.view[ modelValue ], 'attribute' );\n\t\t}\n\t} else {\n\t\tconfig.view = normalizeToElementConfig( config.view, 'attribute' );\n\t}\n\n\tconst elementCreator = getFromAttributeCreator( config );\n\n\treturn dispatcher => {\n\t\tdispatcher.on( eventName, wrap( elementCreator ), { priority: config.converterPriority || 'normal' } );\n\t};\n}\n\n// Model attribute to view attribute conversion helper.\n//\n// See {@link ~DowncastHelpers#attributeToAttribute `.attributeToAttribute()` downcast helper} for examples.\n//\n// @param {Object} config Conversion configuration.\n// @param {String|Object} config.model The key of the attribute to convert from or a `{ key, values, [ name ] }` object describing\n// the attribute key, possible values and, optionally, an element name to convert from.\n// @param {String|Object|Function} config.view A view attribute key, or a `{ key, value }` object or a function that takes\n// the model attribute value and returns a `{ key, value }` object. If `key` is `'class'`, `value` can be a `String` or an\n// array of `String`s. If `key` is `'style'`, `value` is an object with key-value pairs. In other cases, `value` is a `String`.\n// If `config.model.values` is set, `config.view` should be an object assigning values from `config.model.values` to\n// `{ key, value }` objects or a functions.\n// @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.\n// @returns {Function} Conversion helper.\nfunction downcastAttributeToAttribute( config ) {\n\tconfig = cloneDeep( config );\n\n\tconst modelKey = config.model.key ? config.model.key : config.model;\n\tlet eventName = 'attribute:' + modelKey;\n\n\tif ( config.model.name ) {\n\t\teventName += ':' + config.model.name;\n\t}\n\n\tif ( config.model.values ) {\n\t\tfor ( const modelValue of config.model.values ) {\n\t\t\tconfig.view[ modelValue ] = normalizeToAttributeConfig( config.view[ modelValue ] );\n\t\t}\n\t} else {\n\t\tconfig.view = normalizeToAttributeConfig( config.view );\n\t}\n\n\tconst elementCreator = getFromAttributeCreator( config );\n\n\treturn dispatcher => {\n\t\tdispatcher.on( eventName, changeAttribute( elementCreator ), { priority: config.converterPriority || 'normal' } );\n\t};\n}\n\n// Model marker to view element conversion helper.\n//\n// See {@link ~DowncastHelpers#markerToElement `.markerToElement()` downcast helper} for examples.\n//\n// @param {Object} config Conversion configuration.\n// @param {String} config.model The name of the model marker (or model marker group) to convert.\n// @param {module:engine/view/elementdefinition~ElementDefinition|Function} config.view A view element definition or a function\n// that takes the model marker data as a parameter and returns a view UI element.\n// @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.\n// @returns {Function} Conversion helper.\nfunction downcastMarkerToElement( config ) {\n\tconfig = cloneDeep( config );\n\n\tconfig.view = normalizeToElementConfig( config.view, 'ui' );\n\n\treturn dispatcher => {\n\t\tdispatcher.on( 'addMarker:' + config.model, insertUIElement( config.view ), { priority: config.converterPriority || 'normal' } );\n\t\tdispatcher.on( 'removeMarker:' + config.model, removeUIElement( config.view ), { priority: config.converterPriority || 'normal' } );\n\t};\n}\n\n// Model marker to view data conversion helper.\n//\n// See {@link ~DowncastHelpers#markerToData `markerToData()` downcast helper} to learn more.\n//\n// @param {Object} config\n// @param {String} config.model\n// @param {Function} [config.view]\n// @param {module:utils/priorities~PriorityString} [config.converterPriority='normal']\n// @returns {Function} Conversion helper.\nfunction downcastMarkerToData( config ) {\n\tconfig = cloneDeep( config );\n\n\tconst group = config.model;\n\n\t// Default conversion.\n\tif ( !config.view ) {\n\t\tconfig.view = markerName => ( {\n\t\t\tgroup,\n\t\t\tname: markerName.substr( config.model.length + 1 )\n\t\t} );\n\t}\n\n\treturn dispatcher => {\n\t\tdispatcher.on( 'addMarker:' + group, insertMarkerData( config.view ), { priority: config.converterPriority || 'normal' } );\n\t\tdispatcher.on( 'removeMarker:' + group, removeMarkerData( config.view ), { priority: config.converterPriority || 'normal' } );\n\t};\n}\n\n// Model marker to highlight conversion helper.\n//\n// See {@link ~DowncastHelpers#markerToElement `.markerToElement()` downcast helper} for examples.\n//\n// @param {Object} config Conversion configuration.\n// @param {String} config.model The name of the model marker (or model marker group) to convert.\n// @param {module:engine/conversion/downcasthelpers~HighlightDescriptor|Function} config.view A highlight descriptor\n// that will be used for highlighting or a function that takes the model marker data as a parameter and returns a highlight descriptor.\n// @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.\n// @returns {Function} Conversion helper.\nfunction downcastMarkerToHighlight( config ) {\n\treturn dispatcher => {\n\t\tdispatcher.on( 'addMarker:' + config.model, highlightText( config.view ), { priority: config.converterPriority || 'normal' } );\n\t\tdispatcher.on( 'addMarker:' + config.model, highlightElement( config.view ), { priority: config.converterPriority || 'normal' } );\n\t\tdispatcher.on( 'removeMarker:' + config.model, removeHighlight( config.view ), { priority: config.converterPriority || 'normal' } );\n\t};\n}\n\n// Takes `config.view`, and if it is an {@link module:engine/view/elementdefinition~ElementDefinition}, converts it\n// to a function (because lower level converters accept only element creator functions).\n//\n// @param {module:engine/view/elementdefinition~ElementDefinition|Function} view View configuration.\n// @param {'container'|'attribute'|'ui'} viewElementType View element type to create.\n// @returns {Function} Element creator function to use in lower level converters.\nfunction normalizeToElementConfig( view, viewElementType ) {\n\tif ( typeof view == 'function' ) {\n\t\t// If `view` is already a function, don't do anything.\n\t\treturn view;\n\t}\n\n\treturn ( modelData, conversionApi ) => createViewElementFromDefinition( view, conversionApi, viewElementType );\n}\n\n// Creates a view element instance from the provided {@link module:engine/view/elementdefinition~ElementDefinition} and class.\n//\n// @param {module:engine/view/elementdefinition~ElementDefinition} viewElementDefinition\n// @param {module:engine/view/downcastwriter~DowncastWriter} viewWriter\n// @param {'container'|'attribute'|'ui'} viewElementType\n// @returns {module:engine/view/element~Element}\nfunction createViewElementFromDefinition( viewElementDefinition, conversionApi, viewElementType ) {\n\tif ( typeof viewElementDefinition == 'string' ) {\n\t\t// If `viewElementDefinition` is given as a `String`, normalize it to an object with `name` property.\n\t\tviewElementDefinition = { name: viewElementDefinition };\n\t}\n\n\tlet element;\n\tconst viewWriter = conversionApi.writer;\n\tconst attributes = Object.assign( {}, viewElementDefinition.attributes );\n\n\tif ( viewElementType == 'container' ) {\n\t\telement = viewWriter.createContainerElement( viewElementDefinition.name, attributes );\n\t} else if ( viewElementType == 'attribute' ) {\n\t\tconst options = {\n\t\t\tpriority: viewElementDefinition.priority || ViewAttributeElement.DEFAULT_PRIORITY\n\t\t};\n\n\t\telement = viewWriter.createAttributeElement( viewElementDefinition.name, attributes, options );\n\t} else {\n\t\t// 'ui'.\n\t\telement = viewWriter.createUIElement( viewElementDefinition.name, attributes );\n\t}\n\n\tif ( viewElementDefinition.styles ) {\n\t\tconst keys = Object.keys( viewElementDefinition.styles );\n\n\t\tfor ( const key of keys ) {\n\t\t\tviewWriter.setStyle( key, viewElementDefinition.styles[ key ], element );\n\t\t}\n\t}\n\n\tif ( viewElementDefinition.classes ) {\n\t\tconst classes = viewElementDefinition.classes;\n\n\t\tif ( typeof classes == 'string' ) {\n\t\t\tviewWriter.addClass( classes, element );\n\t\t} else {\n\t\t\tfor ( const className of classes ) {\n\t\t\t\tviewWriter.addClass( className, element );\n\t\t\t}\n\t\t}\n\t}\n\n\treturn element;\n}\n\nfunction getFromAttributeCreator( config ) {\n\tif ( config.model.values ) {\n\t\treturn ( modelAttributeValue, conversionApi ) => {\n\t\t\tconst view = config.view[ modelAttributeValue ];\n\n\t\t\tif ( view ) {\n\t\t\t\treturn view( modelAttributeValue, conversionApi );\n\t\t\t}\n\n\t\t\treturn null;\n\t\t};\n\t} else {\n\t\treturn config.view;\n\t}\n}\n\n// Takes the configuration, adds default parameters if they do not exist and normalizes other parameters to be used in downcast converters\n// for generating a view attribute.\n//\n// @param {Object} view View configuration.\nfunction normalizeToAttributeConfig( view ) {\n\tif ( typeof view == 'string' ) {\n\t\treturn modelAttributeValue => ( { key: view, value: modelAttributeValue } );\n\t} else if ( typeof view == 'object' ) {\n\t\t// { key, value, ... }\n\t\tif ( view.value ) {\n\t\t\treturn () => view;\n\t\t}\n\t\t// { key, ... }\n\t\telse {\n\t\t\treturn modelAttributeValue => ( { key: view.key, value: modelAttributeValue } );\n\t\t}\n\t} else {\n\t\t// function.\n\t\treturn view;\n\t}\n}\n\n// Helper function for `highlight`. Prepares the actual descriptor object using value passed to the converter.\nfunction prepareDescriptor( highlightDescriptor, data, conversionApi ) {\n\t// If passed descriptor is a creator function, call it. If not, just use passed value.\n\tconst descriptor = typeof highlightDescriptor == 'function' ?\n\t\thighlightDescriptor( data, conversionApi ) :\n\t\thighlightDescriptor;\n\n\tif ( !descriptor ) {\n\t\treturn null;\n\t}\n\n\t// Apply default descriptor priority.\n\tif ( !descriptor.priority ) {\n\t\tdescriptor.priority = 10;\n\t}\n\n\t// Default descriptor id is marker name.\n\tif ( !descriptor.id ) {\n\t\tdescriptor.id = data.markerName;\n\t}\n\n\treturn descriptor;\n}\n\n/**\n * An object describing how the marker highlight should be represented in the view.\n *\n * Each text node contained in a highlighted range will be wrapped in a ``\n * {@link module:engine/view/attributeelement~AttributeElement view attribute element} with CSS class(es), attributes and a priority\n * described by this object.\n *\n * Additionally, each {@link module:engine/view/containerelement~ContainerElement container element} can handle displaying the highlight\n * separately by providing the `addHighlight` and `removeHighlight` custom properties. In this case:\n *\n * * The `HighlightDescriptor` object is passed to the `addHighlight` function upon conversion and should be used to apply the highlight to\n * the element.\n * * The descriptor `id` is passed to the `removeHighlight` function upon conversion and should be used to remove the highlight with the\n * given ID from the element.\n *\n * @typedef {Object} module:engine/conversion/downcasthelpers~HighlightDescriptor\n *\n * @property {String|Array.} classes A CSS class or an array of classes to set. If the descriptor is used to\n * create an {@link module:engine/view/attributeelement~AttributeElement attribute element} over text nodes, these classes will be set\n * on that attribute element. If the descriptor is applied to an element, usually these classes will be set on that element, however,\n * this depends on how the element converts the descriptor.\n *\n * @property {String} [id] Descriptor identifier. If not provided, it defaults to the converted marker's name.\n *\n * @property {Number} [priority] Descriptor priority. If not provided, it defaults to `10`. If the descriptor is used to create\n * an {@link module:engine/view/attributeelement~AttributeElement attribute element}, it will be that element's\n * {@link module:engine/view/attributeelement~AttributeElement#priority priority}. If the descriptor is applied to an element,\n * the priority will be used to determine which descriptor is more important.\n *\n * @property {Object} [attributes] Attributes to set. If the descriptor is used to create\n * an {@link module:engine/view/attributeelement~AttributeElement attribute element} over text nodes, these attributes will be set on that\n * attribute element. If the descriptor is applied to an element, usually these attributes will be set on that element, however,\n * this depends on how the element converts the descriptor.\n */\n"],"sourceRoot":""}