{"version":3,"sources":["webpack:///./node_modules/@ckeditor/ckeditor5-engine/src/conversion/downcastdispatcher.js","webpack:///./node_modules/@ckeditor/ckeditor5-engine/src/conversion/downcasthelpers.js","webpack:///./node_modules/@ckeditor/ckeditor5-engine/src/conversion/conversion.js","webpack:///./node_modules/@ckeditor/ckeditor5-engine/src/controller/editingcontroller.js","webpack:///./node_modules/@ckeditor/ckeditor5-engine/src/conversion/conversionhelpers.js","webpack:///./node_modules/@ckeditor/ckeditor5-engine/src/controller/datacontroller.js"],"names":["DowncastDispatcher","conversionApi","this","Object","assign","dispatcher","_reconversionEventsMapping","Map","differ","markers","writer","getMarkersToRemove","change","convertMarkerRemove","name","range","changes","_mapChangesWithAutomaticReconversion","entry","type","convertInsert","Range","_createFromPositionAndShift","position","length","convertRemove","reconvertElement","element","convertAttribute","attributeKey","attributeOldValue","attributeNewValue","mapper","flushUnboundMarkerNames","markerName","markerRange","get","getRange","convertMarkerAdd","getMarkersToAdd","consumable","_createInsertConsumable","Array","from","map","walkerValueToEventData","data","_convertInsertWithAttributes","_clearConversionApi","fire","key","oldValue","newValue","_createConsumableForRange","value","item","itemRange","previousPosition","_testAndFire","elementRange","_createOn","currentView","toViewElement","remove","convertedViewElement","_createIn","view","elementOrTextProxyToView","root","move","createRangeOn","toViewPosition","Position","_createBefore","unbindViewElement","selection","markersAtSelection","getMarkersAtPosition","getFirstPosition","_createSelectionConsumable","isCollapsed","marker","shouldMarkerChangeBeConverted","test","getAttributeKeys","getFirstRange","getAttribute","document","rootName","eventName","Consumable","add","getItems","modelName","set","getEventName","itemsToReconvert","Set","updated","getChanges","start","positionParent","parent","textNode","getTextNodeAtPosition","push","getNodeAfterPosition","is","_isReconvertTriggerEvent","has","elementName","modelPosition","ancestors","getAncestors","shift","reverse","hasCustomHandling","some","containsItem","viewElement","getCustomProperty","mappedPosition","mix","EmitterMixin","DowncastHelpers","config","downcastElementToElement","downcastAttributeToElement","downcastAttributeToAttribute","downcastMarkerToElement","downcastMarkerToHighlight","downcastMarkerToData","ConversionHelpers","insertText","evt","consume","viewWriter","viewPosition","viewText","createText","insert","viewStart","modelEnd","getShiftedBy","viewEnd","isPhantom","viewRange","createRange","removed","getTrimmed","createRangeIn","child","createViewElementFromHighlightDescriptor","descriptor","createAttributeElement","attributes","classes","_addClass","priority","_priority","_id","id","convertRangeSelection","viewRanges","getRanges","toViewRange","setSelection","backward","isBackward","convertCollapsedSelection","brokenPosition","breakAttributes","clearAttributes","viewSelection","end","isAttached","mergeAttributes","wrap","elementCreator","oldViewElement","newViewElement","ModelSelection","DocumentSelection","unwrap","insertElement","bindElements","insertUIElement","isOpening","viewStartElement","viewEndElement","bindElementToMarker","stop","removeUIElement","elements","markerNameToElements","unbindElementFromMarkerName","clear","clearClonedElementsGroup","insertMarkerData","viewCreator","viewMarkerData","handleMarkerBoundary","isStart","canInsertElement","schema","checkChild","insertMarkerAsElement","modelElement","isBefore","nodeAfter","nodeBefore","insertMarkerAsAttribute","attributeName","group","markerNames","hasAttribute","split","unshift","setAttribute","join","viewElementName","attrs","createUIElement","removeMarkerData","viewData","removeMarkerFromAttribute","delete","size","removeAttribute","changeAttribute","attributeCreator","oldAttribute","newAttribute","CKEditorError","toArray","className","removeClass","keys","removeStyle","addClass","setStyle","highlightText","highlightDescriptor","prepareDescriptor","rangeAfterWrap","isSimilar","highlightElement","ModelElement","ModelRange","removeHighlight","viewHighlightElement","cloneDeep","normalizeToElementConfig","on","model","converterPriority","triggerBy","_mapReconversionTriggerEvent","children","childName","modelKey","values","modelValue","getFromAttributeCreator","normalizeToAttributeConfig","substr","viewElementType","modelData","createViewElementFromDefinition","viewElementDefinition","createContainerElement","options","ViewAttributeElement","DEFAULT_PRIORITY","styles","modelAttributeValue","_getAllUpcastDefinitions","_getUpcastDefinition","Conversion","downcastDispatchers","upcastDispatchers","_helpers","_downcast","_createConversionHelpers","dispatchers","isDowncast","_upcast","alias","includes","isUpcast","groupName","definition","for","elementToElement","attributeToElement","elementToAttribute","attributeToAttribute","helpers","UpcastHelpers","upcastAlso","undefined","upcastAlsoItem","EditingController","stylesProcessor","View","Mapper","downcastDispatcher","doc","listenTo","_disableRendering","convertChanges","convertSelection","convertSelectionChange","roots","bindTo","using","viewRoot","RootEditableElement","destroy","stopListening","ObservableMixin","_dispatchers","conversionHelper","DataController","upcastDispatcher","UpcastDispatcher","viewDocument","ViewDocument","htmlProcessor","HtmlDataProcessor","processor","_viewWriter","ViewDowncastWriter","convertText","convertToModelFragment","decorate","enqueueChange","autoParagraphEmptyRoots","trim","_checkIfRootsExists","getRoot","hasContent","ignoreWhitespaces","stringify","modelElementOrFragment","viewDocumentFragment","toView","toData","clearBindings","modelRange","ViewDocumentFragment","_getMarkersRelativeToElement","version","initialData","main","modelRoot","parse","Promise","resolve","newData","removeSelectionAttribute","context","toModel","viewElementOrFragment","convert","callback","pattern","registerRawContentMatcher","rootNames","getRootNames","result","intersection","getIntersection"],"mappings":"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","file":"js/chunk-vendors~f30e1026.0762d2d5.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 * @module engine/conversion/downcastdispatcher\n */\n\nimport Consumable from './modelconsumable';\nimport Range from '../model/range';\nimport Position, { getNodeAfterPosition, getTextNodeAtPosition } from '../model/position';\n\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\n\n/**\n * The downcast dispatcher is a central point of downcasting (conversion from the model to the view), which is a process of reacting\n * to changes in the model and firing a set of events. Callbacks listening to these events are called converters. The\n * converters' role is to convert the model changes to changes in view (for example, adding view nodes or\n * changing attributes on view elements).\n *\n * During the conversion process, downcast dispatcher fires events basing on the state of the model and prepares\n * data for these events. It is important to understand that the events are connected with the changes done on the model,\n * for example: \"a node has been inserted\" or \"an attribute has changed\". This is in contrary to upcasting (a view-to-model conversion)\n * where you convert the view state (view nodes) to a model tree.\n *\n * The events are prepared basing on a diff created by {@link module:engine/model/differ~Differ Differ}, which buffers them\n * and then passes to the downcast dispatcher as a diff between the old model state and the new model state.\n *\n * Note that because the changes are converted, there is a need to have a mapping between the model structure and the view structure.\n * To map positions and elements during the downcast (a model-to-view conversion), use {@link module:engine/conversion/mapper~Mapper}.\n *\n * Downcast dispatcher fires the following events for model tree changes:\n *\n * * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:insert `insert`} –\n * If a range of nodes was inserted to the model tree.\n * * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:remove `remove`} –\n * If a range of nodes was removed from the model tree.\n * * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:attribute `attribute`} –\n * If an attribute was added, changed or removed from a model node.\n *\n * For {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:insert `insert`}\n * and {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:attribute `attribute`},\n * downcast dispatcher generates {@link module:engine/conversion/modelconsumable~ModelConsumable consumables}.\n * These are used to have control over which changes have already been consumed. It is useful when some converters\n * overwrite others or convert multiple changes (for example, it converts an insertion of an element and also converts that\n * element's attributes during the insertion).\n *\n * Additionally, downcast dispatcher fires events for {@link module:engine/model/markercollection~Marker marker} changes:\n *\n * * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:addMarker} – If a marker was added.\n * * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:removeMarker} – If a marker was removed.\n *\n * Note that changing a marker is done through removing the marker from the old range and adding it to the new range,\n * so both events are fired.\n *\n * Finally, downcast dispatcher also handles firing events for the {@link module:engine/model/selection model selection}\n * conversion:\n *\n * * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:selection}\n * – Converts the selection from the model to the view.\n * * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:attribute}\n * – Fired for every selection attribute.\n * * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:addMarker}\n * – Fired for every marker that contains a selection.\n *\n * Unlike the model tree and the markers, the events for selection are not fired for changes but for a selection state.\n *\n * When providing custom listeners for a downcast dispatcher, remember to check whether a given change has not been\n * {@link module:engine/conversion/modelconsumable~ModelConsumable#consume consumed} yet.\n *\n * When providing custom listeners for downcast dispatcher, keep in mind that any callback that has\n * {@link module:engine/conversion/modelconsumable~ModelConsumable#consume consumed} a value from a consumable and\n * converted the change should also stop the event (for efficiency purposes).\n *\n * When providing custom listeners for downcast dispatcher, remember to use the provided\n * {@link module:engine/view/downcastwriter~DowncastWriter view downcast writer} to apply changes to the view document.\n *\n * You can read more about conversion in the following guides:\n *\n * * {@glink framework/guides/deep-dive/conversion/conversion-introduction Advanced conversion concepts — attributes}\n * * {@glink framework/guides/deep-dive/conversion/conversion-extending-output Extending the editor output }\n * * {@glink framework/guides/deep-dive/conversion/custom-element-conversion Custom element conversion}\n *\n * An example of a custom converter for the downcast dispatcher:\n *\n *\t\t// You will convert inserting a \"paragraph\" model element into the model.\n *\t\tdowncastDispatcher.on( 'insert:paragraph', ( evt, data, conversionApi ) => {\n *\t\t\t// Remember to check whether the change has not been consumed yet and consume it.\n *\t\t\tif ( conversionApi.consumable.consume( data.item, 'insert' ) ) {\n *\t\t\t\treturn;\n *\t\t\t}\n *\n *\t\t\t// Translate the position in the model to a position in the view.\n *\t\t\tconst viewPosition = conversionApi.mapper.toViewPosition( data.range.start );\n *\n *\t\t\t// Create a

element that will be inserted into the view at the `viewPosition`.\n *\t\t\tconst viewElement = conversionApi.writer.createContainerElement( 'p' );\n *\n *\t\t\t// Bind the newly created view element to the model element so positions will map accordingly in the future.\n *\t\t\tconversionApi.mapper.bindElements( data.item, viewElement );\n *\n *\t\t\t// Add the newly created view element to the view.\n *\t\t\tconversionApi.writer.insert( viewPosition, viewElement );\n *\n *\t\t\t// Remember to stop the event propagation.\n *\t\t\tevt.stop();\n *\t\t} );\n */\nexport default class DowncastDispatcher {\n\t/**\n\t * Creates a downcast dispatcher instance.\n\t *\n\t * @see module:engine/conversion/downcastdispatcher~DowncastConversionApi\n\t * @param {Object} conversionApi Additional properties for an interface that will be passed to events fired\n\t * by the downcast dispatcher.\n\t */\n\tconstructor( conversionApi ) {\n\t\t/**\n\t\t * An interface passed by the dispatcher to the event callbacks.\n\t\t *\n\t\t * @member {module:engine/conversion/downcastdispatcher~DowncastConversionApi}\n\t\t */\n\t\tthis.conversionApi = Object.assign( { dispatcher: this }, conversionApi );\n\n\t\t/**\n\t\t * Maps conversion event names that will trigger element reconversion for a given element name.\n\t\t *\n\t\t * @type {Map}\n\t\t * @private\n\t\t */\n\t\tthis._reconversionEventsMapping = new Map();\n\t}\n\n\t/**\n\t * Takes a {@link module:engine/model/differ~Differ model differ} object with buffered changes and fires conversion basing on it.\n\t *\n\t * @param {module:engine/model/differ~Differ} differ The differ object with buffered changes.\n\t * @param {module:engine/model/markercollection~MarkerCollection} markers Markers connected with the converted model.\n\t * @param {module:engine/view/downcastwriter~DowncastWriter} writer The view writer that should be used to modify the view document.\n\t */\n\tconvertChanges( differ, markers, writer ) {\n\t\t// Before the view is updated, remove markers which have changed.\n\t\tfor ( const change of differ.getMarkersToRemove() ) {\n\t\t\tthis.convertMarkerRemove( change.name, change.range, writer );\n\t\t}\n\n\t\tconst changes = this._mapChangesWithAutomaticReconversion( differ );\n\n\t\t// Convert changes that happened on model tree.\n\t\tfor ( const entry of changes ) {\n\t\t\tif ( entry.type === 'insert' ) {\n\t\t\t\tthis.convertInsert( Range._createFromPositionAndShift( entry.position, entry.length ), writer );\n\t\t\t} else if ( entry.type === 'remove' ) {\n\t\t\t\tthis.convertRemove( entry.position, entry.length, entry.name, writer );\n\t\t\t} else if ( entry.type === 'reconvert' ) {\n\t\t\t\tthis.reconvertElement( entry.element, writer );\n\t\t\t} else {\n\t\t\t\t// Defaults to 'attribute' change.\n\t\t\t\tthis.convertAttribute( entry.range, entry.attributeKey, entry.attributeOldValue, entry.attributeNewValue, writer );\n\t\t\t}\n\t\t}\n\n\t\tfor ( const markerName of this.conversionApi.mapper.flushUnboundMarkerNames() ) {\n\t\t\tconst markerRange = markers.get( markerName ).getRange();\n\n\t\t\tthis.convertMarkerRemove( markerName, markerRange, writer );\n\t\t\tthis.convertMarkerAdd( markerName, markerRange, writer );\n\t\t}\n\n\t\t// After the view is updated, convert markers which have changed.\n\t\tfor ( const change of differ.getMarkersToAdd() ) {\n\t\t\tthis.convertMarkerAdd( change.name, change.range, writer );\n\t\t}\n\t}\n\n\t/**\n\t * Starts a conversion of a range insertion.\n\t *\n\t * For each node in the range, {@link #event:insert `insert` event is fired}. For each attribute on each node,\n\t * {@link #event:attribute `attribute` event is fired}.\n\t *\n\t * @fires insert\n\t * @fires attribute\n\t * @param {module:engine/model/range~Range} range The inserted range.\n\t * @param {module:engine/view/downcastwriter~DowncastWriter} writer The view writer that should be used to modify the view document.\n\t */\n\tconvertInsert( range, writer ) {\n\t\tthis.conversionApi.writer = writer;\n\n\t\t// Create a list of things that can be consumed, consisting of nodes and their attributes.\n\t\tthis.conversionApi.consumable = this._createInsertConsumable( range );\n\n\t\t// Fire a separate insert event for each node and text fragment contained in the range.\n\t\tfor ( const data of Array.from( range ).map( walkerValueToEventData ) ) {\n\t\t\tthis._convertInsertWithAttributes( data );\n\t\t}\n\n\t\tthis._clearConversionApi();\n\t}\n\n\t/**\n\t * Fires conversion of a single node removal. Fires {@link #event:remove remove event} with provided data.\n\t *\n\t * @param {module:engine/model/position~Position} position Position from which node was removed.\n\t * @param {Number} length Offset size of removed node.\n\t * @param {String} name Name of removed node.\n\t * @param {module:engine/view/downcastwriter~DowncastWriter} writer View writer that should be used to modify view document.\n\t */\n\tconvertRemove( position, length, name, writer ) {\n\t\tthis.conversionApi.writer = writer;\n\n\t\tthis.fire( 'remove:' + name, { position, length }, this.conversionApi );\n\n\t\tthis._clearConversionApi();\n\t}\n\n\t/**\n\t * Starts a conversion of an attribute change on a given `range`.\n\t *\n\t * For each node in the given `range`, {@link #event:attribute attribute event} is fired with the passed data.\n\t *\n\t * @fires attribute\n\t * @param {module:engine/model/range~Range} range Changed range.\n\t * @param {String} key Key of the attribute that has changed.\n\t * @param {*} oldValue Attribute value before the change or `null` if the attribute has not been set before.\n\t * @param {*} newValue New attribute value or `null` if the attribute has been removed.\n\t * @param {module:engine/view/downcastwriter~DowncastWriter} writer View writer that should be used to modify view document.\n\t */\n\tconvertAttribute( range, key, oldValue, newValue, writer ) {\n\t\tthis.conversionApi.writer = writer;\n\n\t\t// Create a list with attributes to consume.\n\t\tthis.conversionApi.consumable = this._createConsumableForRange( range, `attribute:${ key }` );\n\n\t\t// Create a separate attribute event for each node in the range.\n\t\tfor ( const value of range ) {\n\t\t\tconst item = value.item;\n\t\t\tconst itemRange = Range._createFromPositionAndShift( value.previousPosition, value.length );\n\t\t\tconst data = {\n\t\t\t\titem,\n\t\t\t\trange: itemRange,\n\t\t\t\tattributeKey: key,\n\t\t\t\tattributeOldValue: oldValue,\n\t\t\t\tattributeNewValue: newValue\n\t\t\t};\n\n\t\t\tthis._testAndFire( `attribute:${ key }`, data );\n\t\t}\n\n\t\tthis._clearConversionApi();\n\t}\n\n\t/**\n\t * Starts the reconversion of an element. It will:\n\t *\n\t * * Fire an {@link #event:insert `insert` event} for the element to reconvert.\n\t * * Fire an {@link #event:attribute `attribute` event} for element attributes.\n\t *\n\t * This will not reconvert children of the element if they have existing (already converted) views. For newly inserted child elements\n\t * it will behave the same as {@link #convertInsert}.\n\t *\n\t * Element reconversion is defined by the `triggerBy` configuration for the\n\t * {@link module:engine/conversion/downcasthelpers~DowncastHelpers#elementToElement `elementToElement()`} conversion helper.\n\t *\n\t * @fires insert\n\t * @fires attribute\n\t * @param {module:engine/model/element~Element} element The element to be reconverted.\n\t * @param {module:engine/view/downcastwriter~DowncastWriter} writer The view writer that should be used to modify the view document.\n\t */\n\treconvertElement( element, writer ) {\n\t\tconst elementRange = Range._createOn( element );\n\n\t\tthis.conversionApi.writer = writer;\n\n\t\t// Create a list of things that can be consumed, consisting of nodes and their attributes.\n\t\tthis.conversionApi.consumable = this._createInsertConsumable( elementRange );\n\n\t\tconst mapper = this.conversionApi.mapper;\n\t\tconst currentView = mapper.toViewElement( element );\n\n\t\t// Remove the old view but do not remove mapper mappings - those will be used to revive existing elements.\n\t\twriter.remove( currentView );\n\n\t\t// Convert the element - without converting children.\n\t\tthis._convertInsertWithAttributes( {\n\t\t\titem: element,\n\t\t\trange: elementRange\n\t\t} );\n\n\t\tconst convertedViewElement = mapper.toViewElement( element );\n\n\t\t// Iterate over children of reconverted element in order to...\n\t\tfor ( const value of Range._createIn( element ) ) {\n\t\t\tconst { item } = value;\n\n\t\t\tconst view = elementOrTextProxyToView( item, mapper );\n\n\t\t\t// ...either bring back previously converted view...\n\t\t\tif ( view ) {\n\t\t\t\t// Do not move views that are already in converted element - those might be created by the main element converter in case\n\t\t\t\t// when main element converts also its direct children.\n\t\t\t\tif ( view.root !== convertedViewElement.root ) {\n\t\t\t\t\twriter.move(\n\t\t\t\t\t\twriter.createRangeOn( view ),\n\t\t\t\t\t\tmapper.toViewPosition( Position._createBefore( item ) )\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\t// ... or by converting newly inserted elements.\n\t\t\telse {\n\t\t\t\tthis._convertInsertWithAttributes( walkerValueToEventData( value ) );\n\t\t\t}\n\t\t}\n\n\t\t// After reconversion is done we can unbind the old view.\n\t\tmapper.unbindViewElement( currentView );\n\n\t\tthis._clearConversionApi();\n\t}\n\n\t/**\n\t * Starts the model selection conversion.\n\t *\n\t * Fires events for a given {@link module:engine/model/selection~Selection selection} to start the selection conversion.\n\t *\n\t * @fires selection\n\t * @fires addMarker\n\t * @fires attribute\n\t * @param {module:engine/model/selection~Selection} selection The selection to convert.\n\t * @param {module:engine/model/markercollection~MarkerCollection} markers Markers connected with the converted model.\n\t * @param {module:engine/view/downcastwriter~DowncastWriter} writer View writer that should be used to modify the view document.\n\t */\n\tconvertSelection( selection, markers, writer ) {\n\t\tconst markersAtSelection = Array.from( markers.getMarkersAtPosition( selection.getFirstPosition() ) );\n\n\t\tthis.conversionApi.writer = writer;\n\t\tthis.conversionApi.consumable = this._createSelectionConsumable( selection, markersAtSelection );\n\n\t\tthis.fire( 'selection', { selection }, this.conversionApi );\n\n\t\tif ( !selection.isCollapsed ) {\n\t\t\treturn;\n\t\t}\n\n\t\tfor ( const marker of markersAtSelection ) {\n\t\t\tconst markerRange = marker.getRange();\n\n\t\t\tif ( !shouldMarkerChangeBeConverted( selection.getFirstPosition(), marker, this.conversionApi.mapper ) ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst data = {\n\t\t\t\titem: selection,\n\t\t\t\tmarkerName: marker.name,\n\t\t\t\tmarkerRange\n\t\t\t};\n\n\t\t\tif ( this.conversionApi.consumable.test( selection, 'addMarker:' + marker.name ) ) {\n\t\t\t\tthis.fire( 'addMarker:' + marker.name, data, this.conversionApi );\n\t\t\t}\n\t\t}\n\n\t\tfor ( const key of selection.getAttributeKeys() ) {\n\t\t\tconst data = {\n\t\t\t\titem: selection,\n\t\t\t\trange: selection.getFirstRange(),\n\t\t\t\tattributeKey: key,\n\t\t\t\tattributeOldValue: null,\n\t\t\t\tattributeNewValue: selection.getAttribute( key )\n\t\t\t};\n\n\t\t\t// Do not fire event if the attribute has been consumed.\n\t\t\tif ( this.conversionApi.consumable.test( selection, 'attribute:' + data.attributeKey ) ) {\n\t\t\t\tthis.fire( 'attribute:' + data.attributeKey + ':$text', data, this.conversionApi );\n\t\t\t}\n\t\t}\n\n\t\tthis._clearConversionApi();\n\t}\n\n\t/**\n\t * Converts the added marker. Fires the {@link #event:addMarker `addMarker`} event for each item\n\t * in the marker's range. If the range is collapsed, a single event is dispatched. See the event description for more details.\n\t *\n\t * @fires addMarker\n\t * @param {String} markerName Marker name.\n\t * @param {module:engine/model/range~Range} markerRange The marker range.\n\t * @param {module:engine/view/downcastwriter~DowncastWriter} writer View writer that should be used to modify the view document.\n\t */\n\tconvertMarkerAdd( markerName, markerRange, writer ) {\n\t\t// Do not convert if range is in graveyard or not in the document (e.g. in DocumentFragment).\n\t\tif ( !markerRange.root.document || markerRange.root.rootName == '$graveyard' ) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.conversionApi.writer = writer;\n\n\t\t// In markers' case, event name == consumable name.\n\t\tconst eventName = 'addMarker:' + markerName;\n\n\t\t//\n\t\t// First, fire an event for the whole marker.\n\t\t//\n\t\tconst consumable = new Consumable();\n\t\tconsumable.add( markerRange, eventName );\n\n\t\tthis.conversionApi.consumable = consumable;\n\n\t\tthis.fire( eventName, { markerName, markerRange }, this.conversionApi );\n\n\t\t//\n\t\t// Do not fire events for each item inside the range if the range got consumed.\n\t\t//\n\t\tif ( !consumable.test( markerRange, eventName ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t//\n\t\t// Then, fire an event for each item inside the marker range.\n\t\t//\n\t\tthis.conversionApi.consumable = this._createConsumableForRange( markerRange, eventName );\n\n\t\tfor ( const item of markerRange.getItems() ) {\n\t\t\t// Do not fire event for already consumed items.\n\t\t\tif ( !this.conversionApi.consumable.test( item, eventName ) ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst data = { item, range: Range._createOn( item ), markerName, markerRange };\n\n\t\t\tthis.fire( eventName, data, this.conversionApi );\n\t\t}\n\n\t\tthis._clearConversionApi();\n\t}\n\n\t/**\n\t * Fires the conversion of the marker removal. Fires the {@link #event:removeMarker `removeMarker`} event with the provided data.\n\t *\n\t * @fires removeMarker\n\t * @param {String} markerName Marker name.\n\t * @param {module:engine/model/range~Range} markerRange The marker range.\n\t * @param {module:engine/view/downcastwriter~DowncastWriter} writer View writer that should be used to modify the view document.\n\t */\n\tconvertMarkerRemove( markerName, markerRange, writer ) {\n\t\t// Do not convert if range is in graveyard or not in the document (e.g. in DocumentFragment).\n\t\tif ( !markerRange.root.document || markerRange.root.rootName == '$graveyard' ) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.conversionApi.writer = writer;\n\n\t\tthis.fire( 'removeMarker:' + markerName, { markerName, markerRange }, this.conversionApi );\n\n\t\tthis._clearConversionApi();\n\t}\n\n\t/**\n\t * Maps the model element \"insert\" reconversion for given event names. The event names must be fully specified:\n\t *\n\t * * For \"attribute\" change event, it should include the main element name, i.e: `'attribute:attributeName:elementName'`.\n\t * * For child node change events, these should use the child event name as well, i.e:\n\t * * For adding a node: `'insert:childElementName'`.\n\t * * For removing a node: `'remove:childElementName'`.\n\t *\n\t * **Note**: This method should not be used directly. The reconversion is defined by the `triggerBy()` configuration of the\n\t * `elementToElement()` conversion helper.\n\t *\n\t * @protected\n\t * @param {String} modelName The name of the main model element for which the events will trigger the reconversion.\n\t * @param {String} eventName The name of an event that would trigger conversion for a given model element.\n\t */\n\t_mapReconversionTriggerEvent( modelName, eventName ) {\n\t\tthis._reconversionEventsMapping.set( eventName, modelName );\n\t}\n\n\t/**\n\t * Creates {@link module:engine/conversion/modelconsumable~ModelConsumable} with values to consume from a given range,\n\t * assuming that the range has just been inserted to the model.\n\t *\n\t * @private\n\t * @param {module:engine/model/range~Range} range The inserted range.\n\t * @returns {module:engine/conversion/modelconsumable~ModelConsumable} The values to consume.\n\t */\n\t_createInsertConsumable( range ) {\n\t\tconst consumable = new Consumable();\n\n\t\tfor ( const value of range ) {\n\t\t\tconst item = value.item;\n\n\t\t\tconsumable.add( item, 'insert' );\n\n\t\t\tfor ( const key of item.getAttributeKeys() ) {\n\t\t\t\tconsumable.add( item, 'attribute:' + key );\n\t\t\t}\n\t\t}\n\n\t\treturn consumable;\n\t}\n\n\t/**\n\t * Creates {@link module:engine/conversion/modelconsumable~ModelConsumable} with values to consume for a given range.\n\t *\n\t * @private\n\t * @param {module:engine/model/range~Range} range The affected range.\n\t * @param {String} type Consumable type.\n\t * @returns {module:engine/conversion/modelconsumable~ModelConsumable} The values to consume.\n\t */\n\t_createConsumableForRange( range, type ) {\n\t\tconst consumable = new Consumable();\n\n\t\tfor ( const item of range.getItems() ) {\n\t\t\tconsumable.add( item, type );\n\t\t}\n\n\t\treturn consumable;\n\t}\n\n\t/**\n\t * Creates {@link module:engine/conversion/modelconsumable~ModelConsumable} with selection consumable values.\n\t *\n\t * @private\n\t * @param {module:engine/model/selection~Selection} selection The selection to create the consumable from.\n\t * @param {Iterable.} markers Markers that contain the selection.\n\t * @returns {module:engine/conversion/modelconsumable~ModelConsumable} The values to consume.\n\t */\n\t_createSelectionConsumable( selection, markers ) {\n\t\tconst consumable = new Consumable();\n\n\t\tconsumable.add( selection, 'selection' );\n\n\t\tfor ( const marker of markers ) {\n\t\t\tconsumable.add( selection, 'addMarker:' + marker.name );\n\t\t}\n\n\t\tfor ( const key of selection.getAttributeKeys() ) {\n\t\t\tconsumable.add( selection, 'attribute:' + key );\n\t\t}\n\n\t\treturn consumable;\n\t}\n\n\t/**\n\t * Tests passed `consumable` to check whether given event can be fired and if so, fires it.\n\t *\n\t * @private\n\t * @fires insert\n\t * @fires attribute\n\t * @param {String} type Event type.\n\t * @param {Object} data Event data.\n\t */\n\t_testAndFire( type, data ) {\n\t\tif ( !this.conversionApi.consumable.test( data.item, type ) ) {\n\t\t\t// Do not fire event if the item was consumed.\n\t\t\treturn;\n\t\t}\n\n\t\tthis.fire( getEventName( type, data ), data, this.conversionApi );\n\t}\n\n\t/**\n\t * Clears the conversion API object.\n\t *\n\t * @private\n\t */\n\t_clearConversionApi() {\n\t\tdelete this.conversionApi.writer;\n\t\tdelete this.conversionApi.consumable;\n\t}\n\n\t/**\n\t * Internal method for converting element insertion. It will fire events for the inserted element and events for its attributes.\n\t *\n\t * @private\n\t * @fires insert\n\t * @fires attribute\n\t * @param {Object} data Event data.\n\t */\n\t_convertInsertWithAttributes( data ) {\n\t\tthis._testAndFire( 'insert', data );\n\n\t\t// Fire a separate addAttribute event for each attribute that was set on inserted items.\n\t\t// This is important because most attributes converters will listen only to add/change/removeAttribute events.\n\t\t// If we would not add this part, attributes on inserted nodes would not be converted.\n\t\tfor ( const key of data.item.getAttributeKeys() ) {\n\t\t\tdata.attributeKey = key;\n\t\t\tdata.attributeOldValue = null;\n\t\t\tdata.attributeNewValue = data.item.getAttribute( key );\n\n\t\t\tthis._testAndFire( `attribute:${ key }`, data );\n\t\t}\n\t}\n\n\t/**\n\t * Returns differ changes together with added \"reconvert\" type changes for {@link #reconvertElement}. These are defined by\n\t * a the `triggerBy()` configuration for the\n\t * {@link module:engine/conversion/downcasthelpers~DowncastHelpers#elementToElement `elementToElement()`} conversion helper.\n\t *\n\t * This method will remove every mapped insert or remove change with a single \"reconvert\" change.\n\t *\n\t * For instance: Having a `triggerBy()` configuration defined for the `` element that issues this element reconversion on\n\t * `foo` and `bar` attributes change, and a set of changes for this element:\n\t *\n\t *\t\tconst differChanges = [\n\t *\t\t\t{ type: 'attribute', attributeKey: 'foo', ... },\n\t *\t\t\t{ type: 'attribute', attributeKey: 'bar', ... },\n\t *\t\t\t{ type: 'attribute', attributeKey: 'baz', ... }\n\t *\t\t];\n\t *\n\t * This method will return:\n\t *\n\t *\t\tconst updatedChanges = [\n\t *\t\t\t{ type: 'reconvert', element: complexElementInstance },\n\t *\t\t\t{ type: 'attribute', attributeKey: 'baz', ... }\n\t *\t\t];\n\t *\n\t * In the example above, the `'baz'` attribute change will fire an {@link #event:attribute attribute event}\n\t *\n\t * @param {module:engine/model/differ~Differ} differ The differ object with buffered changes.\n\t * @returns {Array.} Updated set of changes.\n\t * @private\n\t */\n\t_mapChangesWithAutomaticReconversion( differ ) {\n\t\tconst itemsToReconvert = new Set();\n\t\tconst updated = [];\n\n\t\tfor ( const entry of differ.getChanges() ) {\n\t\t\tconst position = entry.position || entry.range.start;\n\t\t\t// Cached parent - just in case. See https://github.com/ckeditor/ckeditor5/issues/6579.\n\t\t\tconst positionParent = position.parent;\n\t\t\tconst textNode = getTextNodeAtPosition( position, positionParent );\n\n\t\t\t// Reconversion is done only on elements so skip text changes.\n\t\t\tif ( textNode ) {\n\t\t\t\tupdated.push( entry );\n\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst element = entry.type === 'attribute' ? getNodeAfterPosition( position, positionParent, null ) : positionParent;\n\n\t\t\t// Case of text node set directly in root. For now used only in tests but can be possible when enabled in paragraph-like roots.\n\t\t\t// See: https://github.com/ckeditor/ckeditor5/issues/762.\n\t\t\tif ( element.is( '$text' ) ) {\n\t\t\t\tupdated.push( entry );\n\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tlet eventName;\n\n\t\t\tif ( entry.type === 'attribute' ) {\n\t\t\t\teventName = `attribute:${ entry.attributeKey }:${ element.name }`;\n\t\t\t} else {\n\t\t\t\teventName = `${ entry.type }:${ entry.name }`;\n\t\t\t}\n\n\t\t\tif ( this._isReconvertTriggerEvent( eventName, element.name ) ) {\n\t\t\t\tif ( itemsToReconvert.has( element ) ) {\n\t\t\t\t\t// Element is already reconverted, so skip this change.\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\titemsToReconvert.add( element );\n\n\t\t\t\t// Add special \"reconvert\" change.\n\t\t\t\tupdated.push( { type: 'reconvert', element } );\n\t\t\t} else {\n\t\t\t\tupdated.push( entry );\n\t\t\t}\n\t\t}\n\n\t\treturn updated;\n\t}\n\n\t/**\n\t * Checks if the resulting change should trigger element reconversion.\n\t *\n\t * These are defined by a `triggerBy()` configuration for the\n\t * {@link module:engine/conversion/downcasthelpers~DowncastHelpers#elementToElement `elementToElement()`} conversion helper.\n\t *\n\t * @private\n\t * @param {String} eventName The event name to check.\n\t * @param {String} elementName The element name to check.\n\t * @returns {Boolean}\n\t */\n\t_isReconvertTriggerEvent( eventName, elementName ) {\n\t\treturn this._reconversionEventsMapping.get( eventName ) === elementName;\n\t}\n\n\t/**\n\t * Fired for inserted nodes.\n\t *\n\t * `insert` is a namespace for a class of events. Names of actually called events follow this pattern:\n\t * `insert:name`. `name` is either `'$text'`, when {@link module:engine/model/text~Text a text node} has been inserted,\n\t * or {@link module:engine/model/element~Element#name name} of inserted element.\n\t *\n\t * This way listeners can either listen to a general `insert` event or specific event (for example `insert:paragraph`).\n\t *\n\t * @event insert\n\t * @param {Object} data Additional information about the change.\n\t * @param {module:engine/model/item~Item} data.item Inserted item.\n\t * @param {module:engine/model/range~Range} data.range Range spanning over inserted item.\n\t * @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi Conversion interface\n\t * to be used by callback, passed in `DowncastDispatcher` constructor.\n\t */\n\n\t/**\n\t * Fired for removed nodes.\n\t *\n\t * `remove` is a namespace for a class of events. Names of actually called events follow this pattern:\n\t * `remove:name`. `name` is either `'$text'`, when {@link module:engine/model/text~Text a text node} has been removed,\n\t * or the {@link module:engine/model/element~Element#name name} of removed element.\n\t *\n\t * This way listeners can either listen to a general `remove` event or specific event (for example `remove:paragraph`).\n\t *\n\t * @event remove\n\t * @param {Object} data Additional information about the change.\n\t * @param {module:engine/model/position~Position} data.position Position from which the node has been removed.\n\t * @param {Number} data.length Offset size of the removed node.\n\t * @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi Conversion interface\n\t * to be used by callback, passed in `DowncastDispatcher` constructor.\n\t */\n\n\t/**\n\t * Fired in the following cases:\n\t *\n\t * * when an attribute has been added, changed, or removed from a node,\n\t * * when a node with an attribute is inserted,\n\t * * when collapsed model selection attribute is converted.\n\t *\n\t * `attribute` is a namespace for a class of events. Names of actually called events follow this pattern:\n\t * `attribute:attributeKey:name`. `attributeKey` is the key of added/changed/removed attribute.\n\t * `name` is either `'$text'` if change was on {@link module:engine/model/text~Text a text node},\n\t * or the {@link module:engine/model/element~Element#name name} of element which attribute has changed.\n\t *\n\t * This way listeners can either listen to a general `attribute:bold` event or specific event (for example `attribute:src:image`).\n\t *\n\t * @event attribute\n\t * @param {Object} data Additional information about the change.\n\t * @param {module:engine/model/item~Item|module:engine/model/documentselection~DocumentSelection} data.item Changed item\n\t * or converted selection.\n\t * @param {module:engine/model/range~Range} data.range Range spanning over changed item or selection range.\n\t * @param {String} data.attributeKey Attribute key.\n\t * @param {*} data.attributeOldValue Attribute value before the change. This is `null` when selection attribute is converted.\n\t * @param {*} data.attributeNewValue New attribute value.\n\t * @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi Conversion interface\n\t * to be used by callback, passed in `DowncastDispatcher` constructor.\n\t */\n\n\t/**\n\t * Fired for {@link module:engine/model/selection~Selection selection} changes.\n\t *\n\t * @event selection\n\t * @param {module:engine/model/selection~Selection} selection Selection that is converted.\n\t * @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi Conversion interface\n\t * to be used by callback, passed in `DowncastDispatcher` constructor.\n\t */\n\n\t/**\n\t * Fired when a new marker is added to the model. Also fired when a collapsed model selection that is inside a marker is converted.\n\t *\n\t * `addMarker` is a namespace for a class of events. Names of actually called events follow this pattern:\n\t * `addMarker:markerName`. By specifying certain marker names, you can make the events even more gradual. For example,\n\t * if markers are named `foo:abc`, `foo:bar`, then it is possible to listen to `addMarker:foo` or `addMarker:foo:abc` and\n\t * `addMarker:foo:bar` events.\n\t *\n\t * If the marker range is not collapsed:\n\t *\n\t * * the event is fired for each item in the marker range one by one,\n\t * * `conversionApi.consumable` includes each item of the marker range and the consumable value is same as the event name.\n\t *\n\t * If the marker range is collapsed:\n\t *\n\t * * there is only one event,\n\t * * `conversionApi.consumable` includes marker range with the event name.\n\t *\n\t * If the selection inside a marker is converted:\n\t *\n\t * * there is only one event,\n\t * * `conversionApi.consumable` includes the selection instance with the event name.\n\t *\n\t * @event addMarker\n\t * @param {Object} data Additional information about the change.\n\t * @param {module:engine/model/item~Item|module:engine/model/selection~Selection} data.item Item inside the new marker or\n\t * the selection that is being converted.\n\t * @param {module:engine/model/range~Range} [data.range] Range spanning over converted item. Available only in marker conversion, if\n\t * the marker range was not collapsed.\n\t * @param {module:engine/model/range~Range} data.markerRange Marker range.\n\t * @param {String} data.markerName Marker name.\n\t * @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi Conversion interface\n\t * to be used by callback, passed in `DowncastDispatcher` constructor.\n\t */\n\n\t/**\n\t * Fired when a marker is removed from the model.\n\t *\n\t * `removeMarker` is a namespace for a class of events. Names of actually called events follow this pattern:\n\t * `removeMarker:markerName`. By specifying certain marker names, you can make the events even more gradual. For example,\n\t * if markers are named `foo:abc`, `foo:bar`, then it is possible to listen to `removeMarker:foo` or `removeMarker:foo:abc` and\n\t * `removeMarker:foo:bar` events.\n\t *\n\t * @event removeMarker\n\t * @param {Object} data Additional information about the change.\n\t * @param {module:engine/model/range~Range} data.markerRange Marker range.\n\t * @param {String} data.markerName Marker name.\n\t * @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi Conversion interface\n\t * to be used by callback, passed in `DowncastDispatcher` constructor.\n\t */\n}\n\nmix( DowncastDispatcher, EmitterMixin );\n\n// Helper function, checks whether change of `marker` at `modelPosition` should be converted. Marker changes are not\n// converted if they happen inside an element with custom conversion method.\n//\n// @param {module:engine/model/position~Position} modelPosition\n// @param {module:engine/model/markercollection~Marker} marker\n// @param {module:engine/conversion/mapper~Mapper} mapper\n// @returns {Boolean}\nfunction shouldMarkerChangeBeConverted( modelPosition, marker, mapper ) {\n\tconst range = marker.getRange();\n\tconst ancestors = Array.from( modelPosition.getAncestors() );\n\tancestors.shift(); // Remove root element. It cannot be passed to `model.Range#containsItem`.\n\tancestors.reverse();\n\n\tconst hasCustomHandling = ancestors.some( element => {\n\t\tif ( range.containsItem( element ) ) {\n\t\t\tconst viewElement = mapper.toViewElement( element );\n\n\t\t\treturn !!viewElement.getCustomProperty( 'addHighlight' );\n\t\t}\n\t} );\n\n\treturn !hasCustomHandling;\n}\n\nfunction getEventName( type, data ) {\n\tconst name = data.item.name || '$text';\n\n\treturn `${ type }:${ name }`;\n}\n\nfunction walkerValueToEventData( value ) {\n\tconst item = value.item;\n\tconst itemRange = Range._createFromPositionAndShift( value.previousPosition, value.length );\n\n\treturn {\n\t\titem,\n\t\trange: itemRange\n\t};\n}\n\nfunction elementOrTextProxyToView( item, mapper ) {\n\tif ( item.is( 'textProxy' ) ) {\n\t\tconst mappedPosition = mapper.toViewPosition( Position._createBefore( item ) );\n\t\tconst positionParent = mappedPosition.parent;\n\n\t\treturn positionParent.is( '$text' ) ? positionParent : null;\n\t}\n\n\treturn mapper.toViewElement( item );\n}\n\n/**\n * Conversion interface that is registered for given {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher}\n * and is passed as one of parameters when {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher dispatcher}\n * fires its events.\n *\n * @interface module:engine/conversion/downcastdispatcher~DowncastConversionApi\n */\n\n/**\n * The {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher} instance.\n *\n * @member {module:engine/conversion/downcastdispatcher~DowncastDispatcher} #dispatcher\n */\n\n/**\n * Stores the information about what parts of a processed model item are still waiting to be handled. After a piece of a model item was\n * converted, an appropriate consumable value should be {@link module:engine/conversion/modelconsumable~ModelConsumable#consume consumed}.\n *\n * @member {module:engine/conversion/modelconsumable~ModelConsumable} #consumable\n */\n\n/**\n * The {@link module:engine/conversion/mapper~Mapper} instance.\n *\n * @member {module:engine/conversion/mapper~Mapper} #mapper\n */\n\n/**\n * The {@link module:engine/model/schema~Schema} instance set for the model that is downcast.\n *\n * @member {module:engine/model/schema~Schema} #schema\n */\n\n/**\n * The {@link module:engine/view/downcastwriter~DowncastWriter} instance used to manipulate the data during conversion.\n *\n * @member {module:engine/view/downcastwriter~DowncastWriter} #writer\n */\n\n/**\n * An object with an additional configuration which can be used during the conversion process. Available only for data downcast conversion.\n *\n * @member {Object} #options\n */\n","/**\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: 'image',\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 only for editing downcast. For data downcast, use\n\t * {@link #markerToData `#markerToData()`} that produces valid HTML data.\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: `[]` becomes ``\n\t * 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: 'new-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, converstionApi ) => {\n\t *\t\t\t\t// Assuming that the marker name is in a form of comment:commentType.\n\t *\t\t\t\tconst commentType = data.markerName.split( ':' )[ 1 ];\n\t *\n\t *\t\t\t\treturn {\n\t *\t\t\t\t\tclasses: [ 'comment', 'comment-' + commentType ]\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 at a position where text nodes are allowed, then a view element with the specified tag name\n\t * and `name` attribute is added at this position.\n\t * * In other cases, a specified attribute is set on a view element that is before or after the marker boundary.\n\t *\n\t * Typically, 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 * * 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 * * 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 * Attributes `data-[group]-start-before` and `data-[group]-end-after` 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 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 whose name starts 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 `:`).\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 have it 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 {@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 #markerToData\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 {Function} [config.view] A function that takes the model marker name and\n\t * {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi downcast conversion API} as a 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 view range start position by mapping 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 a 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 ( descriptor.priority ) {\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 canInsertElement = conversionApi.schema.checkChild( modelPosition, '$text' );\n\n\tif ( canInsertElement ) {\n\t\tconst viewPosition = conversionApi.mapper.toViewPosition( modelPosition );\n\n\t\tinsertMarkerAsElement( viewPosition, isStart, conversionApi, data, viewMarkerData );\n\t} else {\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\t// Below `if` is constructed in a way that will favor adding these attributes.\n\t\t//\n\t\t// Also, I assume that there will be always an element either after or before the position.\n\t\t// If not, then it is a case when we are not in a position where text is allowed and also there are no elements around...\n\t\tif ( isStart && modelPosition.nodeAfter || !isStart && !modelPosition.nodeBefore ) {\n\t\t\tmodelElement = modelPosition.nodeAfter;\n\t\t\tisBefore = true;\n\t\t} else {\n\t\t\tmodelElement = modelPosition.nodeBefore;\n\t\t\tisBefore = false;\n\t\t}\n\n\t\tconst viewElement = conversionApi.mapper.toViewElement( modelElement );\n\n\t\tinsertMarkerAsAttribute( viewElement, isStart, isBefore, conversionApi, data, viewMarkerData );\n\t}\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","/**\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 * @module engine/conversion/conversion\n */\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport UpcastHelpers from './upcasthelpers';\nimport DowncastHelpers from './downcasthelpers';\nimport toArray from '@ckeditor/ckeditor5-utils/src/toarray';\n\n/**\n * A utility class that helps add converters to upcast and downcast dispatchers.\n *\n * We recommend reading the {@glink framework/guides/architecture/editing-engine Editing engine architecture} guide first to\n * understand the core concepts of the conversion mechanisms.\n *\n * An instance of the conversion manager is available in the\n * {@link module:core/editor/editor~Editor#conversion `editor.conversion`} property\n * and by default has the following groups of dispatchers (i.e. directions of conversion):\n *\n * * `downcast` (editing and data downcasts)\n * * `editingDowncast`\n * * `dataDowncast`\n * * `upcast`\n *\n * # One-way converters\n *\n * To add a converter to a specific group, use the {@link module:engine/conversion/conversion~Conversion#for `for()`}\n * method:\n *\n *\t\t// Add a converter to editing downcast and data downcast.\n *\t\teditor.conversion.for( 'downcast' ).elementToElement( config ) );\n *\n *\t\t// Add a converter to the data pipepline only:\n *\t\teditor.conversion.for( 'dataDowncast' ).elementToElement( dataConversionConfig ) );\n *\n *\t\t// And a slightly different one for the editing pipeline:\n *\t\teditor.conversion.for( 'editingDowncast' ).elementToElement( editingConversionConfig ) );\n *\n * See {@link module:engine/conversion/conversion~Conversion#for `for()`} method documentation to learn more about\n * available conversion helpers and how to use your custom ones.\n *\n * # Two-way converters\n *\n * Besides using one-way converters via the `for()` method, you can also use other methods available in this\n * class to add two-way converters (upcast and downcast):\n *\n * * {@link module:engine/conversion/conversion~Conversion#elementToElement `elementToElement()`} –\n * Model element to view element and vice versa.\n * * {@link module:engine/conversion/conversion~Conversion#attributeToElement `attributeToElement()`} –\n * Model attribute to view element and vice versa.\n * * {@link module:engine/conversion/conversion~Conversion#attributeToAttribute `attributeToAttribute()`} –\n * Model attribute to view element and vice versa.\n */\nexport default class Conversion {\n\t/**\n\t * Creates a new conversion instance.\n\t *\n\t * @param {module:engine/conversion/downcastdispatcher~DowncastDispatcher|\n\t * Array.} downcastDispatchers\n\t * @param {module:engine/conversion/upcastdispatcher~UpcastDispatcher|\n\t * Array.} upcastDispatchers\n\t */\n\tconstructor( downcastDispatchers, upcastDispatchers ) {\n\t\t/**\n\t\t * Maps dispatchers group name to ConversionHelpers instances.\n\t\t *\n\t\t * @private\n\t\t * @member {Map.}\n\t\t */\n\t\tthis._helpers = new Map();\n\n\t\t// Define default 'downcast' & 'upcast' dispatchers groups. Those groups are always available as two-way converters needs them.\n\t\tthis._downcast = toArray( downcastDispatchers );\n\t\tthis._createConversionHelpers( { name: 'downcast', dispatchers: this._downcast, isDowncast: true } );\n\n\t\tthis._upcast = toArray( upcastDispatchers );\n\t\tthis._createConversionHelpers( { name: 'upcast', dispatchers: this._upcast, isDowncast: false } );\n\t}\n\n\t/**\n\t * Define an alias for registered dispatcher.\n\t *\n\t *\t\tconst conversion = new Conversion(\n\t *\t\t\t[ dataDowncastDispatcher, editingDowncastDispatcher ],\n\t *\t\t\tupcastDispatcher\n\t *\t\t);\n\t *\n\t *\t\tconversion.addAlias( 'dataDowncast', dataDowncastDispatcher );\n\t *\n\t * @param {String} alias An alias of a dispatcher.\n\t * @param {module:engine/conversion/downcastdispatcher~DowncastDispatcher|\n\t * module:engine/conversion/upcastdispatcher~UpcastDispatcher} dispatcher Dispatcher which should have an alias.\n\t */\n\taddAlias( alias, dispatcher ) {\n\t\tconst isDowncast = this._downcast.includes( dispatcher );\n\t\tconst isUpcast = this._upcast.includes( dispatcher );\n\n\t\tif ( !isUpcast && !isDowncast ) {\n\t\t\t/**\n\t\t\t * Trying to register and alias for a dispatcher that nas not been registered.\n\t\t\t *\n\t\t\t * @error conversion-add-alias-dispatcher-not-registered\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'conversion-add-alias-dispatcher-not-registered',\n\t\t\t\tthis\n\t\t\t);\n\t\t}\n\n\t\tthis._createConversionHelpers( { name: alias, dispatchers: [ dispatcher ], isDowncast } );\n\t}\n\n\t/**\n\t * Provides a chainable API to assign converters to conversion dispatchers group.\n\t *\n\t * If the given group name has not been registered, the\n\t * {@link module:utils/ckeditorerror~CKEditorError `conversion-for-unknown-group` error} is thrown.\n\t *\n\t * You can use conversion helpers available directly in the `for()` chain or your custom ones via\n\t * the {@link module:engine/conversion/conversionhelpers~ConversionHelpers#add `add()`} method.\n\t *\n\t * # Using bulit-in conversion helpers\n\t *\n\t * The `for()` chain comes with a set of conversion helpers which you can use like this:\n\t *\n\t *\t\teditor.conversion.for( 'downcast' )\n\t *\t\t\t.elementToElement( config1 ) // Adds an element-to-element downcast converter.\n\t *\t\t\t.attributeToElement( config2 ); // Adds an attribute-to-element downcast converter.\n\t *\n\t *\t\teditor.conversion.for( 'upcast' )\n\t *\t\t\t.elementToAttribute( config3 ); // Adds an element-to-attribute upcast converter.\n\t *\n\t * Refer to the documentation of built-in conversion helpers to learn about their configuration options.\n\t *\n\t * * downcast (model-to-view) conversion helpers:\n\t *\n\t *\t* {@link module:engine/conversion/downcasthelpers~DowncastHelpers#elementToElement `elementToElement()`},\n\t *\t* {@link module:engine/conversion/downcasthelpers~DowncastHelpers#attributeToElement `attributeToElement()`},\n\t *\t* {@link module:engine/conversion/downcasthelpers~DowncastHelpers#attributeToAttribute `attributeToAttribute()`}.\n\t *\t* {@link module:engine/conversion/downcasthelpers~DowncastHelpers#markerToElement `markerToElement()`}.\n\t *\t* {@link module:engine/conversion/downcasthelpers~DowncastHelpers#markerToHighlight `markerToHighlight()`}.\n\t *\n\t * * upcast (view-to-model) conversion helpers:\n\t *\n\t *\t* {@link module:engine/conversion/upcasthelpers~UpcastHelpers#elementToElement `elementToElement()`},\n\t *\t* {@link module:engine/conversion/upcasthelpers~UpcastHelpers#elementToAttribute `elementToAttribute()`},\n\t *\t* {@link module:engine/conversion/upcasthelpers~UpcastHelpers#attributeToAttribute `attributeToAttribute()`}.\n\t *\t* {@link module:engine/conversion/upcasthelpers~UpcastHelpers#elementToMarker `elementToMarker()`}.\n\t *\n\t * # Using custom conversion helpers\n\t *\n\t * If you need to implement a nontypical converter, you can do so by calling:\n\t *\n\t *\t\teditor.conversion.for( direction ).add( customHelper );\n\t *\n\t * The `.add()` method takes exactly one parameter, which is a function. This function should accept one parameter that\n\t * is a dispatcher instance. The function should add an actual converter to the passed dispatcher instance.\n\t *\n\t * Example:\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).add( dispatcher => {\n\t *\t\t\tdispatcher.on( 'element:a', ( evt, data, conversionApi ) => {\n\t *\t\t\t\t// Do something with a view element.\n\t *\t\t\t} );\n\t *\t\t} );\n\t *\n\t * Refer to the documentation of {@link module:engine/conversion/upcastdispatcher~UpcastDispatcher}\n\t * and {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher} to learn how to write\n\t * custom converters.\n\t *\n\t * @param {String} groupName The name of dispatchers group to add the converters to.\n\t * @returns {module:engine/conversion/downcasthelpers~DowncastHelpers|module:engine/conversion/upcasthelpers~UpcastHelpers}\n\t */\n\tfor( groupName ) {\n\t\tif ( !this._helpers.has( groupName ) ) {\n\t\t\t/**\n\t\t\t * Trying to add a converter to an unknown dispatchers group.\n\t\t\t *\n\t\t\t * @error conversion-for-unknown-group\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'conversion-for-unknown-group', this );\n\t\t}\n\n\t\treturn this._helpers.get( groupName );\n\t}\n\n\t/**\n\t * Sets up converters between the model and the view that convert a model element to a view element (and vice versa).\n\t * For example, the model `Foo` is `

Foo

` in the view.\n\t *\n\t *\t\t// A simple conversion from the `paragraph` model element to the `

` view element (and vice versa).\n\t *\t\teditor.conversion.elementToElement( { model: 'paragraph', view: 'p' } );\n\t *\n\t *\t\t// Override other converters by specifying a converter definition with a higher priority.\n\t *\t\teditor.conversion.elementToElement( { model: 'paragraph', view: 'div', converterPriority: 'high' } );\n\t *\n\t *\t\t// View specified as an object instead of a string.\n\t *\t\teditor.conversion.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\t// Use `upcastAlso` to define other view elements that should also be converted to a `paragraph` element.\n\t *\t\teditor.conversion.elementToElement( {\n\t *\t\t\tmodel: 'paragraph',\n\t *\t\t\tview: 'p',\n\t *\t\t\tupcastAlso: [\n\t *\t\t\t\t'div',\n\t *\t\t\t\t{\n\t *\t\t\t\t\t// Any element with the `display: block` style.\n\t *\t\t\t\t\tstyles: {\n\t *\t\t\t\t\t\tdisplay: 'block'\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\t// `upcastAlso` set as callback enables a conversion of a wide range of different view elements.\n\t *\t\teditor.conversion.elementToElement( {\n\t *\t\t\tmodel: 'heading',\n\t *\t\t\tview: 'h2',\n\t *\t\t\t// Convert \"headling-like\" paragraphs to headings.\n\t *\t\t\tupcastAlso: viewElement => {\n\t *\t\t\t\tconst fontSize = viewElement.getStyle( 'font-size' );\n\t *\n\t *\t\t\t\tif ( !fontSize ) {\n\t *\t\t\t\t\treturn null;\n\t *\t\t\t\t}\n\t *\n\t *\t\t\t\tconst match = fontSize.match( /(\\d+)\\s*px/ );\n\t *\n\t *\t\t\t\tif ( !match ) {\n\t *\t\t\t\t\treturn null;\n\t *\t\t\t\t}\n\t *\n\t *\t\t\t\tconst size = Number( match[ 1 ] );\n\t *\n\t *\t\t\t\tif ( size > 26 ) {\n\t *\t\t\t\t\t// Returned value can be an object with the matched properties.\n\t *\t\t\t\t\t// These properties will be \"consumed\" during the conversion.\n\t *\t\t\t\t\t// See `engine.view.Matcher~MatcherPattern` and `engine.view.Matcher#match` for more details.\n\t *\n\t *\t\t\t\t\treturn { name: true, styles: [ 'font-size' ] };\n\t *\t\t\t\t}\n\t *\n\t *\t\t\t\treturn null;\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * `definition.model` is a `String` with a model element name to convert from or to.\n\t * See {@link module:engine/conversion/conversion~ConverterDefinition} to learn about other parameters.\n\t *\n\t * @param {module:engine/conversion/conversion~ConverterDefinition} definition The converter definition.\n\t */\n\telementToElement( definition ) {\n\t\t// Set up downcast converter.\n\t\tthis.for( 'downcast' ).elementToElement( definition );\n\n\t\t// Set up upcast converter.\n\t\tfor ( const { model, view } of _getAllUpcastDefinitions( definition ) ) {\n\t\t\tthis.for( 'upcast' )\n\t\t\t\t.elementToElement( {\n\t\t\t\t\tmodel,\n\t\t\t\t\tview,\n\t\t\t\t\tconverterPriority: definition.converterPriority\n\t\t\t\t} );\n\t\t}\n\t}\n\n\t/**\n\t * Sets up converters between the model and the view that convert a model attribute to a view element (and vice versa).\n\t * For example, a model text node with `\"Foo\"` as data and the `bold` attribute is `Foo` in the view.\n\t *\n\t *\t\t// A simple conversion from the `bold=true` attribute to the `` view element (and vice versa).\n\t *\t\teditor.conversion.attributeToElement( { model: 'bold', view: 'strong' } );\n\t *\n\t *\t\t// Override other converters by specifying a converter definition with a higher priority.\n\t *\t\teditor.conversion.attributeToElement( { model: 'bold', view: 'b', converterPriority: 'high' } );\n\t *\n\t *\t\t// View specified as an object instead of a string.\n\t *\t\teditor.conversion.attributeToElement( {\n\t *\t\t\tmodel: 'bold',\n\t *\t\t\tview: {\n\t *\t\t\t\tname: 'span',\n\t *\t\t\t\tclasses: 'bold'\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t *\t\t// Use `config.model.name` to define the conversion only from a given node type, `$text` in this case.\n\t *\t\t// The same attribute on different elements may then be handled by a different converter.\n\t *\t\teditor.conversion.attributeToElement( {\n\t *\t\t\tmodel: {\n\t *\t\t\t\tkey: 'textDecoration',\n\t *\t\t\t\tvalues: [ 'underline', 'lineThrough' ],\n\t *\t\t\t\tname: '$text'\n\t *\t\t\t},\n\t *\t\t\tview: {\n\t *\t\t\t\tunderline: {\n\t *\t\t\t\t\tname: 'span',\n\t *\t\t\t\t\tstyles: {\n\t *\t\t\t\t\t\t'text-decoration': 'underline'\n\t *\t\t\t\t\t}\n\t *\t\t\t\t},\n\t *\t\t\t\tlineThrough: {\n\t *\t\t\t\t\tname: 'span',\n\t *\t\t\t\t\tstyles: {\n\t *\t\t\t\t\t\t'text-decoration': 'line-through'\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\t// Use `upcastAlso` to define other view elements that should also be converted to the `bold` attribute.\n\t *\t\teditor.conversion.attributeToElement( {\n\t *\t\t\tmodel: 'bold',\n\t *\t\t\tview: 'strong',\n\t *\t\t\tupcastAlso: [\n\t *\t\t\t\t'b',\n\t *\t\t\t\t{\n\t *\t\t\t\t\tname: 'span',\n\t *\t\t\t\t\tclasses: 'bold'\n\t *\t\t\t\t},\n\t *\t\t\t\t{\n\t *\t\t\t\t\tname: 'span',\n\t *\t\t\t\t\tstyles: {\n\t *\t\t\t\t\t\t'font-weight': 'bold'\n\t *\t\t\t\t\t}\n\t *\t\t\t\t},\n\t *\t\t\t\tviewElement => {\n\t *\t\t\t\t\tconst fontWeight = viewElement.getStyle( 'font-weight' );\n\t *\n\t *\t\t\t\t\tif ( viewElement.is( 'element', 'span' ) && fontWeight && /\\d+/.test() && Number( fontWeight ) > 500 ) {\n\t *\t\t\t\t\t\t// Returned value can be an object with the matched properties.\n\t *\t\t\t\t\t\t// These properties will be \"consumed\" during the conversion.\n\t *\t\t\t\t\t\t// See `engine.view.Matcher~MatcherPattern` and `engine.view.Matcher#match` for more details.\n\t *\n\t *\t\t\t\t\t\treturn {\n\t *\t\t\t\t\t\t\tname: true,\n\t *\t\t\t\t\t\t\tstyles: [ 'font-weight' ]\n\t *\t\t\t\t\t\t};\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\t// Conversion from and to a model attribute key whose value is an enum (`fontSize=big|small`).\n\t *\t\t// `upcastAlso` set as callback enables a conversion of a wide range of different view elements.\n\t *\t\teditor.conversion.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\tupcastAlso: {\n\t *\t\t\t\tbig: viewElement => {\n\t *\t\t\t\t\tconst fontSize = viewElement.getStyle( 'font-size' );\n\t *\n\t *\t\t\t\t\tif ( !fontSize ) {\n\t *\t\t\t\t\t\treturn null;\n\t *\t\t\t\t\t}\n\t *\n\t *\t\t\t\t\tconst match = fontSize.match( /(\\d+)\\s*px/ );\n\t *\n\t *\t\t\t\t\tif ( !match ) {\n\t *\t\t\t\t\t\treturn null;\n\t *\t\t\t\t\t}\n\t *\n\t *\t\t\t\t\tconst size = Number( match[ 1 ] );\n\t *\n\t *\t\t\t\t\tif ( viewElement.is( 'element', 'span' ) && size > 10 ) {\n\t *\t\t\t\t\t\t// Returned value can be an object with the matched properties.\n\t *\t\t\t\t\t\t// These properties will be \"consumed\" during the conversion.\n\t *\t\t\t\t\t\t// See `engine.view.Matcher~MatcherPattern` and `engine.view.Matcher#match` for more details.\n\t *\n\t *\t\t\t\t\t\treturn { name: true, styles: [ 'font-size' ] };\n\t *\t\t\t\t\t}\n\t *\n\t *\t\t\t\t\treturn null;\n\t *\t\t\t\t},\n\t *\t\t\t\tsmall: viewElement => {\n\t *\t\t\t\t\tconst fontSize = viewElement.getStyle( 'font-size' );\n\t *\n\t *\t\t\t\t\tif ( !fontSize ) {\n\t *\t\t\t\t\t\treturn null;\n\t *\t\t\t\t\t}\n\t *\n\t *\t\t\t\t\tconst match = fontSize.match( /(\\d+)\\s*px/ );\n\t *\n\t *\t\t\t\t\tif ( !match ) {\n\t *\t\t\t\t\t\treturn null;\n\t *\t\t\t\t\t}\n\t *\n\t *\t\t\t\t\tconst size = Number( match[ 1 ] );\n\t *\n\t *\t\t\t\t\tif ( viewElement.is( 'element', 'span' ) && size < 10 ) {\n\t *\t\t\t\t\t\t// Returned value can be an object with the matched properties.\n\t *\t\t\t\t\t\t// These properties will be \"consumed\" during the conversion.\n\t *\t\t\t\t\t\t// See `engine.view.Matcher~MatcherPattern` and `engine.view.Matcher#match` for more details.\n\t *\n\t *\t\t\t\t\t\treturn { name: true, styles: [ 'font-size' ] };\n\t *\t\t\t\t\t}\n\t *\n\t *\t\t\t\t\treturn null;\n\t *\t\t\t\t}\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * The `definition.model` parameter specifies which model attribute should be converted from or to. It can be a `{ key, value }` object\n\t * describing the attribute key and value to convert or a `String` specifying just the attribute key (then `value` is set to `true`).\n\t * See {@link module:engine/conversion/conversion~ConverterDefinition} to learn about other parameters.\n\t *\n\t * @param {module:engine/conversion/conversion~ConverterDefinition} definition The converter definition.\n\t */\n\tattributeToElement( definition ) {\n\t\t// Set up downcast converter.\n\t\tthis.for( 'downcast' ).attributeToElement( definition );\n\n\t\t// Set up upcast converter.\n\t\tfor ( const { model, view } of _getAllUpcastDefinitions( definition ) ) {\n\t\t\tthis.for( 'upcast' )\n\t\t\t\t.elementToAttribute( {\n\t\t\t\t\tview,\n\t\t\t\t\tmodel,\n\t\t\t\t\tconverterPriority: definition.converterPriority\n\t\t\t\t} );\n\t\t}\n\t}\n\n\t/**\n\t * Sets up converters between the model and the view that convert a model attribute to a view attribute (and vice versa).\n\t * For example, `` is converted to `` (the same attribute key and value).\n\t * This type of converters is intended to be used with {@link module:engine/model/element~Element model element} nodes.\n\t * To convert text attributes {@link module:engine/conversion/conversion~Conversion#attributeToElement `attributeToElement converter`}\n\t * should be set up.\n\t *\n\t *\t\t// A simple conversion from the `source` model attribute to the `src` view attribute (and vice versa).\n\t *\t\teditor.conversion.attributeToAttribute( { model: 'source', view: 'src' } );\n\t *\n\t *\t\t// Attribute values are strictly specified.\n\t *\t\teditor.conversion.attributeToAttribute( {\n\t *\t\t\tmodel: {\n\t *\t\t\t\tname: 'image',\n\t *\t\t\t\tkey: 'aside',\n\t *\t\t\t\tvalues: [ 'aside' ]\n\t *\t\t\t},\n\t *\t\t\tview: {\n\t *\t\t\t\taside: {\n\t *\t\t\t\t\tname: 'img',\n\t *\t\t\t\t\tkey: 'class',\n\t *\t\t\t\t\tvalue: [ 'aside', 'half-size' ]\n\t *\t\t\t\t}\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t *\t\t// Set the style attribute.\n\t *\t\teditor.conversion.attributeToAttribute( {\n\t *\t\t\tmodel: {\n\t *\t\t\t\tname: 'image',\n\t *\t\t\t\tkey: 'aside',\n\t *\t\t\t\tvalues: [ 'aside' ]\n\t *\t\t\t},\n\t *\t\t\tview: {\n\t *\t\t\t\taside: {\n\t *\t\t\t\t\tname: 'img',\n\t *\t\t\t\t\tkey: 'style',\n\t *\t\t\t\t\tvalue: {\n\t *\t\t\t\t\t\tfloat: 'right',\n\t *\t\t\t\t\t\twidth: '50%',\n\t *\t\t\t\t\t\tmargin: '5px'\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\t// Conversion from and to a model attribute key whose value is an enum (`align=right|center`).\n\t *\t\t// Use `upcastAlso` to define other view elements that should also be converted to the `align=right` attribute.\n\t *\t\teditor.conversion.attributeToAttribute( {\n\t *\t\t\tmodel: {\n\t *\t\t\t\tkey: 'align',\n\t *\t\t\t\tvalues: [ 'right', 'center' ]\n\t *\t\t\t},\n\t *\t\t\tview: {\n\t *\t\t\t\tright: {\n\t *\t\t\t\t\tkey: 'class',\n\t *\t\t\t\t\tvalue: 'align-right'\n\t *\t\t\t\t},\n\t *\t\t\t\tcenter: {\n\t *\t\t\t\t\tkey: 'class',\n\t *\t\t\t\t\tvalue: 'align-center'\n\t *\t\t\t\t}\n\t *\t\t\t},\n\t *\t\t\tupcastAlso: {\n\t *\t\t\t\tright: {\n\t *\t\t\t\t\tstyles: {\n\t *\t\t\t\t\t\t'text-align': 'right'\n\t *\t\t\t\t\t}\n\t *\t\t\t\t},\n\t *\t\t\t\tcenter: {\n\t *\t\t\t\t\tstyles: {\n\t *\t\t\t\t\t\t'text-align': 'center'\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 * The `definition.model` parameter specifies which model attribute should be converted from and to.\n\t * It can be a `{ key, [ values ], [ name ] }` object or a `String`, which will be treated like `{ key: definition.model }`.\n\t * The `key` property is the model attribute key to convert from and to.\n\t * The `values` are the possible model attribute values. If `values` is not set, the model attribute value will be the same as the\n\t * view attribute value.\n\t * If `name` is set, the conversion will be set up only for model elements with the given name.\n\t *\n\t * The `definition.view` parameter specifies which view attribute should be converted from and to.\n\t * It can be a `{ key, value, [ name ] }` object or a `String`, which will be treated like `{ key: definition.view }`.\n\t * The `key` property is the view attribute key to convert from and to.\n\t * The `value` is the view attribute value to convert from and to. If `definition.value` is not set, the view attribute value will be\n\t * the same as the model attribute value.\n\t * If `key` is `'class'`, `value` can be a `String` or an array of `String`s.\n\t * If `key` is `'style'`, `value` is an object with key-value pairs.\n\t * In other cases, `value` is a `String`.\n\t * If `name` is set, the conversion will be set up only for model elements with the given name.\n\t * If `definition.model.values` is set, `definition.view` is an object that assigns values from `definition.model.values`\n\t * to `{ key, value, [ name ] }` objects.\n\t *\n\t * `definition.upcastAlso` specifies which other matching view elements should also be upcast to the given model configuration.\n\t * If `definition.model.values` is set, `definition.upcastAlso` should be an object assigning values from `definition.model.values`\n\t * to {@link module:engine/view/matcher~MatcherPattern}s or arrays of {@link module:engine/view/matcher~MatcherPattern}s.\n\t *\n\t * **Note:** `definition.model` and `definition.view` form should be mirrored, so the same types of parameters should\n\t * be given in both parameters.\n\t *\n\t * @param {Object} definition The converter definition.\n\t * @param {String|Object} definition.model The model attribute to convert from and to.\n\t * @param {String|Object} definition.view The view attribute to convert from and to.\n\t * @param {module:engine/view/matcher~MatcherPattern|Array.} [definition.upcastAlso]\n\t * Any view element matching `definition.upcastAlso` will also be converted to the given model attribute. `definition.upcastAlso`\n\t * is used only if `config.model.values` is specified.\n\t */\n\tattributeToAttribute( definition ) {\n\t\t// Set up downcast converter.\n\t\tthis.for( 'downcast' ).attributeToAttribute( definition );\n\n\t\t// Set up upcast converter.\n\t\tfor ( const { model, view } of _getAllUpcastDefinitions( definition ) ) {\n\t\t\tthis.for( 'upcast' )\n\t\t\t\t.attributeToAttribute( {\n\t\t\t\t\tview,\n\t\t\t\t\tmodel\n\t\t\t\t} );\n\t\t}\n\t}\n\n\t/**\n\t * Creates and caches conversion helpers for given dispatchers group.\n\t *\n\t * @private\n\t * @param {Object} options\n\t * @param {String} options.name Group name.\n\t * @param {Array.} options.dispatchers\n\t * @param {Boolean} options.isDowncast\n\t */\n\t_createConversionHelpers( { name, dispatchers, isDowncast } ) {\n\t\tif ( this._helpers.has( name ) ) {\n\t\t\t/**\n\t\t\t * Trying to register a group name that has already been registered.\n\t\t\t *\n\t\t\t * @error conversion-group-exists\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'conversion-group-exists', this );\n\t\t}\n\n\t\tconst helpers = isDowncast ? new DowncastHelpers( dispatchers ) : new UpcastHelpers( dispatchers );\n\n\t\tthis._helpers.set( name, helpers );\n\t}\n}\n\n/**\n * Defines how the model should be converted from and to the view.\n *\n * @typedef {Object} module:engine/conversion/conversion~ConverterDefinition\n *\n * @property {*} [model] The model conversion definition. Describes the model element or model attribute to convert. This parameter differs\n * for different functions that accept `ConverterDefinition`. See the description of the function to learn how to set it.\n * @property {module:engine/view/elementdefinition~ElementDefinition|Object} view The definition of the view element to convert from and\n * to. If `model` describes multiple values, `view` is an object that assigns these values (`view` object keys) to view element definitions\n * (`view` object values).\n * @property {module:engine/view/matcher~MatcherPattern|Array.} [upcastAlso]\n * Any view element matching `upcastAlso` will also be converted to the model. If `model` describes multiple values, `upcastAlso`\n * is an object that assigns these values (`upcastAlso` object keys) to {@link module:engine/view/matcher~MatcherPattern}s\n * (`upcastAlso` object values).\n * @property {module:utils/priorities~PriorityString} [converterPriority] The converter priority.\n */\n\n// Helper function that creates a joint array out of an item passed in `definition.view` and items passed in\n// `definition.upcastAlso`.\n//\n// @param {module:engine/conversion/conversion~ConverterDefinition} definition\n// @returns {Array} Array containing view definitions.\nfunction* _getAllUpcastDefinitions( definition ) {\n\tif ( definition.model.values ) {\n\t\tfor ( const value of definition.model.values ) {\n\t\t\tconst model = { key: definition.model.key, value };\n\t\t\tconst view = definition.view[ value ];\n\t\t\tconst upcastAlso = definition.upcastAlso ? definition.upcastAlso[ value ] : undefined;\n\n\t\t\tyield* _getUpcastDefinition( model, view, upcastAlso );\n\t\t}\n\t} else {\n\t\tyield* _getUpcastDefinition( definition.model, definition.view, definition.upcastAlso );\n\t}\n}\n\nfunction* _getUpcastDefinition( model, view, upcastAlso ) {\n\tyield { model, view };\n\n\tif ( upcastAlso ) {\n\t\tfor ( const upcastAlsoItem of toArray( upcastAlso ) ) {\n\t\t\tyield { model, view: upcastAlsoItem };\n\t\t}\n\t}\n}\n","/**\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 * @module engine/controller/editingcontroller\n */\n\nimport RootEditableElement from '../view/rooteditableelement';\nimport View from '../view/view';\nimport Mapper from '../conversion/mapper';\nimport DowncastDispatcher from '../conversion/downcastdispatcher';\nimport { clearAttributes, convertCollapsedSelection, convertRangeSelection, insertText, remove } from '../conversion/downcasthelpers';\n\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport { convertSelectionChange } from '../conversion/upcasthelpers';\n\n// @if CK_DEBUG_ENGINE // const { dumpTrees, initDocumentDumping } = require( '../dev-utils/utils' );\n\n/**\n * Controller for the editing pipeline. The editing pipeline controls {@link ~EditingController#model model} rendering,\n * including selection handling. It also creates the {@link ~EditingController#view view} which builds a\n * browser-independent virtualization over the DOM elements. The editing controller also attaches default converters.\n *\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class EditingController {\n\t/**\n\t * Creates an editing controller instance.\n\t *\n\t * @param {module:engine/model/model~Model} model Editing model.\n\t * @param {module:engine/view/stylesmap~StylesProcessor} stylesProcessor The styles processor instance.\n\t */\n\tconstructor( model, stylesProcessor ) {\n\t\t/**\n\t\t * Editor model.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/model~Model}\n\t\t */\n\t\tthis.model = model;\n\n\t\t/**\n\t\t * Editing view controller.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/view~View}\n\t\t */\n\t\tthis.view = new View( stylesProcessor );\n\n\t\t/**\n\t\t * Mapper which describes the model-view binding.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/conversion/mapper~Mapper}\n\t\t */\n\t\tthis.mapper = new Mapper();\n\n\t\t/**\n\t\t * Downcast dispatcher that converts changes from the model to {@link #view the editing view}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/conversion/downcastdispatcher~DowncastDispatcher} #downcastDispatcher\n\t\t */\n\t\tthis.downcastDispatcher = new DowncastDispatcher( {\n\t\t\tmapper: this.mapper,\n\t\t\tschema: model.schema\n\t\t} );\n\n\t\tconst doc = this.model.document;\n\t\tconst selection = doc.selection;\n\t\tconst markers = this.model.markers;\n\n\t\t// When plugins listen on model changes (on selection change, post fixers, etc.) and change the view as a result of\n\t\t// model's change, they might trigger view rendering before the conversion is completed (e.g. before the selection\n\t\t// is converted). We disable rendering for the length of the outermost model change() block to prevent that.\n\t\t//\n\t\t// See https://github.com/ckeditor/ckeditor5-engine/issues/1528\n\t\tthis.listenTo( this.model, '_beforeChanges', () => {\n\t\t\tthis.view._disableRendering( true );\n\t\t}, { priority: 'highest' } );\n\n\t\tthis.listenTo( this.model, '_afterChanges', () => {\n\t\t\tthis.view._disableRendering( false );\n\t\t}, { priority: 'lowest' } );\n\n\t\t// Whenever model document is changed, convert those changes to the view (using model.Document#differ).\n\t\t// Do it on 'low' priority, so changes are converted after other listeners did their job.\n\t\t// Also convert model selection.\n\t\tthis.listenTo( doc, 'change', () => {\n\t\t\tthis.view.change( writer => {\n\t\t\t\tthis.downcastDispatcher.convertChanges( doc.differ, markers, writer );\n\t\t\t\tthis.downcastDispatcher.convertSelection( selection, markers, writer );\n\t\t\t} );\n\t\t}, { priority: 'low' } );\n\n\t\t// Convert selection from the view to the model when it changes in the view.\n\t\tthis.listenTo( this.view.document, 'selectionChange', convertSelectionChange( this.model, this.mapper ) );\n\n\t\t// Attach default model converters.\n\t\tthis.downcastDispatcher.on( 'insert:$text', insertText(), { priority: 'lowest' } );\n\t\tthis.downcastDispatcher.on( 'remove', remove(), { priority: 'low' } );\n\n\t\t// Attach default model selection converters.\n\t\tthis.downcastDispatcher.on( 'selection', clearAttributes(), { priority: 'low' } );\n\t\tthis.downcastDispatcher.on( 'selection', convertRangeSelection(), { priority: 'low' } );\n\t\tthis.downcastDispatcher.on( 'selection', convertCollapsedSelection(), { priority: 'low' } );\n\n\t\t// Binds {@link module:engine/view/document~Document#roots view roots collection} to\n\t\t// {@link module:engine/model/document~Document#roots model roots collection} so creating\n\t\t// model root automatically creates corresponding view root.\n\t\tthis.view.document.roots.bindTo( this.model.document.roots ).using( root => {\n\t\t\t// $graveyard is a special root that has no reflection in the view.\n\t\t\tif ( root.rootName == '$graveyard' ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst viewRoot = new RootEditableElement( this.view.document, root.name );\n\n\t\t\tviewRoot.rootName = root.rootName;\n\t\t\tthis.mapper.bindElements( root, viewRoot );\n\n\t\t\treturn viewRoot;\n\t\t} );\n\n\t\t// @if CK_DEBUG_ENGINE // initDocumentDumping( this.model.document );\n\t\t// @if CK_DEBUG_ENGINE // initDocumentDumping( this.view.document );\n\n\t\t// @if CK_DEBUG_ENGINE // dumpTrees( this.model.document, this.model.document.version );\n\t\t// @if CK_DEBUG_ENGINE // dumpTrees( this.view.document, this.model.document.version );\n\n\t\t// @if CK_DEBUG_ENGINE // this.model.document.on( 'change', () => {\n\t\t// @if CK_DEBUG_ENGINE //\tdumpTrees( this.view.document, this.model.document.version );\n\t\t// @if CK_DEBUG_ENGINE // }, { priority: 'lowest' } );\n\t}\n\n\t/**\n\t * Removes all event listeners attached to the `EditingController`. Destroys all objects created\n\t * by `EditingController` that need to be destroyed.\n\t */\n\tdestroy() {\n\t\tthis.view.destroy();\n\t\tthis.stopListening();\n\t}\n}\n\nmix( EditingController, ObservableMixin );\n","/**\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 * @module engine/conversion/conversionhelpers\n */\n\n/**\n * Base class for conversion helpers.\n */\nexport default class ConversionHelpers {\n\t/**\n\t * Creates a conversion helpers instance.\n\t *\n\t * @param {Array.} dispatchers\n\t */\n\tconstructor( dispatchers ) {\n\t\tthis._dispatchers = dispatchers;\n\t}\n\n\t/**\n\t * Registers a conversion helper.\n\t *\n\t * **Note**: See full usage example in the `{@link module:engine/conversion/conversion~Conversion#for conversion.for()}`\n\t * method description.\n\t *\n\t * @param {Function} conversionHelper The function to be called on event.\n\t * @returns {module:engine/conversion/downcasthelpers~DowncastHelpers|module:engine/conversion/upcasthelpers~UpcastHelpers}\n\t */\n\tadd( conversionHelper ) {\n\t\tfor ( const dispatcher of this._dispatchers ) {\n\t\t\tconversionHelper( dispatcher );\n\t\t}\n\n\t\treturn this;\n\t}\n}\n","/**\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 * @module engine/controller/datacontroller\n */\n\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\nimport Mapper from '../conversion/mapper';\n\nimport DowncastDispatcher from '../conversion/downcastdispatcher';\nimport { insertText } from '../conversion/downcasthelpers';\n\nimport UpcastDispatcher from '../conversion/upcastdispatcher';\nimport { convertText, convertToModelFragment } from '../conversion/upcasthelpers';\n\nimport ViewDocumentFragment from '../view/documentfragment';\nimport ViewDocument from '../view/document';\nimport ViewDowncastWriter from '../view/downcastwriter';\n\nimport ModelRange from '../model/range';\nimport { autoParagraphEmptyRoots } from '../model/utils/autoparagraphing';\nimport HtmlDataProcessor from '../dataprocessor/htmldataprocessor';\n\n/**\n * Controller for the data pipeline. The data pipeline controls how data is retrieved from the document\n * and set inside it. Hence, the controller features two methods which allow to {@link ~DataController#get get}\n * and {@link ~DataController#set set} data of the {@link ~DataController#model model}\n * using given:\n *\n * * {@link module:engine/dataprocessor/dataprocessor~DataProcessor data processor},\n * * downcast converters,\n * * upcast converters.\n *\n * An instance of the data controller is always available in the {@link module:core/editor/editor~Editor#data `editor.data`}\n * property:\n *\n *\t\teditor.data.get( { rootName: 'customRoot' } ); // -> '

Hello!

'\n *\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class DataController {\n\t/**\n\t * Creates a data controller instance.\n\t *\n\t * @param {module:engine/model/model~Model} model Data model.\n\t * @param {module:engine/view/stylesmap~StylesProcessor} stylesProcessor The styles processor instance.\n\t */\n\tconstructor( model, stylesProcessor ) {\n\t\t/**\n\t\t * Data model.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/model~Model}\n\t\t */\n\t\tthis.model = model;\n\n\t\t/**\n\t\t * Mapper used for the conversion. It has no permanent bindings, because they are created when getting data and\n\t\t * cleared directly after the data are converted. However, the mapper is defined as a class property, because\n\t\t * it needs to be passed to the `DowncastDispatcher` as a conversion API.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/conversion/mapper~Mapper}\n\t\t */\n\t\tthis.mapper = new Mapper();\n\n\t\t/**\n\t\t * Downcast dispatcher used by the {@link #get get method}. Downcast converters should be attached to it.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/conversion/downcastdispatcher~DowncastDispatcher}\n\t\t */\n\t\tthis.downcastDispatcher = new DowncastDispatcher( {\n\t\t\tmapper: this.mapper,\n\t\t\tschema: model.schema\n\t\t} );\n\t\tthis.downcastDispatcher.on( 'insert:$text', insertText(), { priority: 'lowest' } );\n\n\t\t/**\n\t\t * Upcast dispatcher used by the {@link #set set method}. Upcast converters should be attached to it.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/conversion/upcastdispatcher~UpcastDispatcher}\n\t\t */\n\t\tthis.upcastDispatcher = new UpcastDispatcher( {\n\t\t\tschema: model.schema\n\t\t} );\n\n\t\t/**\n\t\t * The view document used by the data controller.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/document~Document}\n\t\t */\n\t\tthis.viewDocument = new ViewDocument( stylesProcessor );\n\n\t\t/**\n\t\t * Styles processor used during the conversion.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/stylesmap~StylesProcessor}\n\t\t */\n\t\tthis.stylesProcessor = stylesProcessor;\n\n\t\t/**\n\t\t * Data processor used specifically for HTML conversion.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/dataprocessor/htmldataprocessor~HtmlDataProcessor} #htmlProcessor\n\t\t */\n\t\tthis.htmlProcessor = new HtmlDataProcessor( this.viewDocument );\n\n\t\t/**\n\t\t * Data processor used during the conversion.\n\t\t * Same instance as {@link #htmlProcessor} by default. Can be replaced at run time to handle different format, e.g. XML or Markdown.\n\t\t *\n\t\t * @member {module:engine/dataprocessor/dataprocessor~DataProcessor} #processor\n\t\t */\n\t\tthis.processor = this.htmlProcessor;\n\n\t\t/**\n\t\t * The view downcast writer just for data conversion purposes, i.e. to modify\n\t\t * the {@link #viewDocument}.\n\t\t *\n\t\t * @private\n\t\t * @readonly\n\t\t * @member {module:engine/view/downcastwriter~DowncastWriter}\n\t\t */\n\t\tthis._viewWriter = new ViewDowncastWriter( this.viewDocument );\n\n\t\t// Define default converters for text and elements.\n\t\t//\n\t\t// Note that if there is no default converter for the element it will be skipped, for instance `foo` will be\n\t\t// converted to nothing. We therefore add `convertToModelFragment` as a last converter so it converts children of that\n\t\t// element to the document fragment and so `foo` will be converted to `foo` if there is no converter for ``.\n\t\tthis.upcastDispatcher.on( 'text', convertText(), { priority: 'lowest' } );\n\t\tthis.upcastDispatcher.on( 'element', convertToModelFragment(), { priority: 'lowest' } );\n\t\tthis.upcastDispatcher.on( 'documentFragment', convertToModelFragment(), { priority: 'lowest' } );\n\n\t\tthis.decorate( 'init' );\n\t\tthis.decorate( 'set' );\n\n\t\t// Fire the `ready` event when the initialization has completed. Such low-level listener gives possibility\n\t\t// to plug into the initialization pipeline without interrupting the initialization flow.\n\t\tthis.on( 'init', () => {\n\t\t\tthis.fire( 'ready' );\n\t\t}, { priority: 'lowest' } );\n\n\t\t// Fix empty roots after DataController is 'ready' (note that init method could be decorated and stopped).\n\t\t// We need to handle this event because initial data could be empty and post-fixer would not get triggered.\n\t\tthis.on( 'ready', () => {\n\t\t\tthis.model.enqueueChange( 'transparent', autoParagraphEmptyRoots );\n\t\t}, { priority: 'lowest' } );\n\t}\n\n\t/**\n\t * Returns the model's data converted by downcast dispatchers attached to {@link #downcastDispatcher} and\n\t * formatted by the {@link #processor data processor}.\n\t *\n\t * @param {Object} [options] Additional configuration for the retrieved data. `DataController` provides two optional\n\t * properties: `rootName` and `trim`. Other properties of this object are specified by various editor features.\n\t * @param {String} [options.rootName='main'] Root name.\n\t * @param {String} [options.trim='empty'] Whether returned data should be trimmed. This option is set to `empty` by default,\n\t * which means whenever editor content is considered empty, an empty string will be returned. To turn off trimming completely\n\t * use `'none'`. In such cases exact content will be returned (for example `

 

` for an empty editor).\n\t * @returns {String} Output data.\n\t */\n\tget( options = {} ) {\n\t\tconst { rootName = 'main', trim = 'empty' } = options;\n\n\t\tif ( !this._checkIfRootsExists( [ rootName ] ) ) {\n\t\t\t/**\n\t\t\t * Cannot get data from a non-existing root. This error is thrown when {@link #get DataController#get() method}\n\t\t\t * is called with non-existent root name. For example, if there is an editor instance with only `main` root,\n\t\t\t * calling {@link #get} like:\n\t\t\t *\n\t\t\t *\t\tdata.get( { rootName: 'root2' } );\n\t\t\t *\n\t\t\t * will throw this error.\n\t\t\t *\n\t\t\t * @error datacontroller-get-non-existent-root\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'datacontroller-get-non-existent-root', this );\n\t\t}\n\n\t\tconst root = this.model.document.getRoot( rootName );\n\n\t\tif ( trim === 'empty' && !this.model.hasContent( root, { ignoreWhitespaces: true } ) ) {\n\t\t\treturn '';\n\t\t}\n\n\t\treturn this.stringify( root, options );\n\t}\n\n\t/**\n\t * Returns the content of the given {@link module:engine/model/element~Element model's element} or\n\t * {@link module:engine/model/documentfragment~DocumentFragment model document fragment} converted by the downcast converters\n\t * attached to {@link #downcastDispatcher} and formatted by the {@link #processor data processor}.\n\t *\n\t * @param {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment} modelElementOrFragment\n\t * Element whose content will be stringified.\n\t * @param {Object} [options] Additional configuration passed to the conversion process.\n\t * @returns {String} Output data.\n\t */\n\tstringify( modelElementOrFragment, options ) {\n\t\t// Model -> view.\n\t\tconst viewDocumentFragment = this.toView( modelElementOrFragment, options );\n\n\t\t// View -> data.\n\t\treturn this.processor.toData( viewDocumentFragment );\n\t}\n\n\t/**\n\t * Returns the content of the given {@link module:engine/model/element~Element model element} or\n\t * {@link module:engine/model/documentfragment~DocumentFragment model document fragment} converted by the downcast\n\t * converters attached to {@link #downcastDispatcher} to a\n\t * {@link module:engine/view/documentfragment~DocumentFragment view document fragment}.\n\t *\n\t * @param {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment} modelElementOrFragment\n\t * Element or document fragment whose content will be converted.\n\t * @param {Object} [options] Additional configuration that will be available through\n\t * {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi#options} during the conversion process.\n\t * @returns {module:engine/view/documentfragment~DocumentFragment} Output view DocumentFragment.\n\t */\n\ttoView( modelElementOrFragment, options ) {\n\t\tconst viewDocument = this.viewDocument;\n\t\tconst viewWriter = this._viewWriter;\n\n\t\t// Clear bindings so the call to this method gives correct results.\n\t\tthis.mapper.clearBindings();\n\n\t\t// First, convert elements.\n\t\tconst modelRange = ModelRange._createIn( modelElementOrFragment );\n\t\tconst viewDocumentFragment = new ViewDocumentFragment( viewDocument );\n\n\t\tthis.mapper.bindElements( modelElementOrFragment, viewDocumentFragment );\n\n\t\t// Make additional options available during conversion process through `conversionApi`.\n\t\tthis.downcastDispatcher.conversionApi.options = options;\n\n\t\t// We have no view controller and rendering to DOM in DataController so view.change() block is not used here.\n\t\tthis.downcastDispatcher.convertInsert( modelRange, viewWriter );\n\n\t\tif ( !modelElementOrFragment.is( 'documentFragment' ) ) {\n\t\t\t// Then, if a document element is converted, convert markers.\n\t\t\t// From all document markers, get those, which \"intersect\" with the converter element.\n\t\t\tconst markers = _getMarkersRelativeToElement( modelElementOrFragment );\n\n\t\t\tfor ( const [ name, range ] of markers ) {\n\t\t\t\tthis.downcastDispatcher.convertMarkerAdd( name, range, viewWriter );\n\t\t\t}\n\t\t}\n\n\t\t// Clean `conversionApi`.\n\t\tdelete this.downcastDispatcher.conversionApi.options;\n\n\t\treturn viewDocumentFragment;\n\t}\n\n\t/**\n\t * Sets initial input data parsed by the {@link #processor data processor} and\n\t * converted by the {@link #upcastDispatcher view-to-model converters}.\n\t * Initial data can be set only to document that {@link module:engine/model/document~Document#version} is equal 0.\n\t *\n\t * **Note** This method is {@link module:utils/observablemixin~ObservableMixin#decorate decorated} which is\n\t * used by e.g. collaborative editing plugin that syncs remote data on init.\n\t *\n\t * When data is passed as a string it is initialized on a default `main` root:\n\t *\n\t *\t\tdataController.init( '

Foo

' ); // Initializes data on the `main` root.\n\t *\n\t * To initialize data on a different root or multiple roots at once, object containing `rootName` - `data` pairs should be passed:\n\t *\n\t *\t\tdataController.init( { main: '

Foo

', title: '

Bar

' } ); // Initializes data on the `main` and `title` roots.\n\t *\n\t * @fires init\n\t * @param {String|Object.} data Input data as a string or an object containing `rootName` - `data`\n\t * pairs to initialize data on multiple roots at once.\n\t * @returns {Promise} Promise that is resolved after the data is set on the editor.\n\t */\n\tinit( data ) {\n\t\tif ( this.model.document.version ) {\n\t\t\t/**\n\t\t\t * Cannot set initial data to not empty {@link module:engine/model/document~Document}.\n\t\t\t * Initial data should be set once, during {@link module:core/editor/editor~Editor} initialization,\n\t\t\t * when the {@link module:engine/model/document~Document#version} is equal 0.\n\t\t\t *\n\t\t\t * @error datacontroller-init-document-not-empty\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'datacontroller-init-document-not-empty', this );\n\t\t}\n\n\t\tlet initialData = {};\n\t\tif ( typeof data === 'string' ) {\n\t\t\tinitialData.main = data; // Default root is 'main'. To initiate data on a different root, object should be passed.\n\t\t} else {\n\t\t\tinitialData = data;\n\t\t}\n\n\t\tif ( !this._checkIfRootsExists( Object.keys( initialData ) ) ) {\n\t\t\t/**\n\t\t\t * Cannot init data on a non-existing root. This error is thrown when {@link #init DataController#init() method}\n\t\t\t * is called with non-existent root name. For example, if there is an editor instance with only `main` root,\n\t\t\t * calling {@link #init} like:\n\t\t\t *\n\t\t\t * \t\tdata.init( { main: '

Foo

', root2: '

Bar

' } );\n\t\t\t *\n\t\t\t * will throw this error.\n\t\t\t *\n\t\t\t * @error datacontroller-init-non-existent-root\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'datacontroller-init-non-existent-root', this );\n\t\t}\n\n\t\tthis.model.enqueueChange( 'transparent', writer => {\n\t\t\tfor ( const rootName of Object.keys( initialData ) ) {\n\t\t\t\tconst modelRoot = this.model.document.getRoot( rootName );\n\t\t\t\twriter.insert( this.parse( initialData[ rootName ], modelRoot ), modelRoot, 0 );\n\t\t\t}\n\t\t} );\n\n\t\treturn Promise.resolve();\n\t}\n\n\t/**\n\t * Sets input data parsed by the {@link #processor data processor} and\n\t * converted by the {@link #upcastDispatcher view-to-model converters}.\n\t * This method can be used any time to replace existing editor data by the new one without clearing the\n\t * {@link module:engine/model/document~Document#history document history}.\n\t *\n\t * This method also creates a batch with all the changes applied. If all you need is to parse data, use\n\t * the {@link #parse} method.\n\t *\n\t * When data is passed as a string it is set on a default `main` root:\n\t *\n\t *\t\tdataController.set( '

Foo

' ); // Sets data on the `main` root.\n\t *\n\t * To set data on a different root or multiple roots at once, object containing `rootName` - `data` pairs should be passed:\n\t *\n\t *\t\tdataController.set( { main: '

Foo

', title: '

Bar

' } ); // Sets data on the `main` and `title` roots.\n\t *\n\t * @fires set\n\t * @param {String|Object.} data Input data as a string or an object containing `rootName` - `data`\n\t * pairs to set data on multiple roots at once.\n\t */\n\tset( data ) {\n\t\tlet newData = {};\n\n\t\tif ( typeof data === 'string' ) {\n\t\t\tnewData.main = data; // Default root is 'main'. To set data on a different root, object should be passed.\n\t\t} else {\n\t\t\tnewData = data;\n\t\t}\n\n\t\tif ( !this._checkIfRootsExists( Object.keys( newData ) ) ) {\n\t\t\t/**\n\t\t\t * Cannot set data on a non-existing root. This error is thrown when {@link #set DataController#set() method}\n\t\t\t * is called with non-existent root name. For example, if there is an editor instance with only `main` root,\n\t\t\t * calling {@link #set} like:\n\t\t\t *\n\t\t\t * \t\tdata.set( { main: '

Foo

', root2: '

Bar

' } );\n\t\t\t *\n\t\t\t * will throw this error.\n\t\t\t *\n\t\t\t * @error datacontroller-set-non-existent-root\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'datacontroller-set-non-existent-root', this );\n\t\t}\n\n\t\tthis.model.enqueueChange( 'transparent', writer => {\n\t\t\twriter.setSelection( null );\n\t\t\twriter.removeSelectionAttribute( this.model.document.selection.getAttributeKeys() );\n\n\t\t\tfor ( const rootName of Object.keys( newData ) ) {\n\t\t\t\t// Save to model.\n\t\t\t\tconst modelRoot = this.model.document.getRoot( rootName );\n\n\t\t\t\twriter.remove( writer.createRangeIn( modelRoot ) );\n\t\t\t\twriter.insert( this.parse( newData[ rootName ], modelRoot ), modelRoot, 0 );\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Returns the data parsed by the {@link #processor data processor} and then converted by upcast converters\n\t * attached to the {@link #upcastDispatcher}.\n\t *\n\t * @see #set\n\t * @param {String} data Data to parse.\n\t * @param {module:engine/model/schema~SchemaContextDefinition} [context='$root'] Base context in which the view will\n\t * be converted to the model. See: {@link module:engine/conversion/upcastdispatcher~UpcastDispatcher#convert}.\n\t * @returns {module:engine/model/documentfragment~DocumentFragment} Parsed data.\n\t */\n\tparse( data, context = '$root' ) {\n\t\t// data -> view\n\t\tconst viewDocumentFragment = this.processor.toView( data );\n\n\t\t// view -> model\n\t\treturn this.toModel( viewDocumentFragment, context );\n\t}\n\n\t/**\n\t * Returns the result of the given {@link module:engine/view/element~Element view element} or\n\t * {@link module:engine/view/documentfragment~DocumentFragment view document fragment} converted by the\n\t * {@link #upcastDispatcher view-to-model converters}, wrapped by {@link module:engine/model/documentfragment~DocumentFragment}.\n\t *\n\t * When marker elements were converted during the conversion process, it will be set as a document fragment's\n\t * {@link module:engine/model/documentfragment~DocumentFragment#markers static markers map}.\n\t *\n\t * @param {module:engine/view/element~Element|module:engine/view/documentfragment~DocumentFragment} viewElementOrFragment\n\t * Element or document fragment whose content will be converted.\n\t * @param {module:engine/model/schema~SchemaContextDefinition} [context='$root'] Base context in which the view will\n\t * be converted to the model. See: {@link module:engine/conversion/upcastdispatcher~UpcastDispatcher#convert}.\n\t * @returns {module:engine/model/documentfragment~DocumentFragment} Output document fragment.\n\t */\n\ttoModel( viewElementOrFragment, context = '$root' ) {\n\t\treturn this.model.change( writer => {\n\t\t\treturn this.upcastDispatcher.convert( viewElementOrFragment, writer, context );\n\t\t} );\n\t}\n\n\t/**\n\t * Adds a style processor normalization rules.\n\t *\n\t * You can implement your own rules as well as use one of the available processor rules:\n\t *\n\t * * background: {@link module:engine/view/styles/background~addBackgroundRules}\n\t * * border: {@link module:engine/view/styles/border~addBorderRules}\n\t * * margin: {@link module:engine/view/styles/margin~addMarginRules}\n\t * * padding: {@link module:engine/view/styles/padding~addPaddingRules}\n\t *\n\t * @param {Function} callback\n\t */\n\taddStyleProcessorRules( callback ) {\n\t\tcallback( this.stylesProcessor );\n\t}\n\n\t/**\n\t * Registers a {@link module:engine/view/matcher~MatcherPattern} on {@link #htmlProcessor htmlProcessor}\n\t * and {@link #processor processor} for view elements whose content should be treated as a raw data\n\t * and not processed during conversion from DOM to view elements.\n\t *\n\t * The raw data can be later accessed by {@link module:engine/view/element~Element#getCustomProperty view element custom property}\n\t * `\"$rawContent\"`.\n\t *\n\t * @param {module:engine/view/matcher~MatcherPattern} pattern Pattern matching all view elements whose content should\n\t * be treated as a raw data.\n\t */\n\tregisterRawContentMatcher( pattern ) {\n\t\t// No need to register the pattern if both `htmlProcessor` and `processor` are the same instances.\n\t\tif ( this.processor && this.processor !== this.htmlProcessor ) {\n\t\t\tthis.processor.registerRawContentMatcher( pattern );\n\t\t}\n\n\t\tthis.htmlProcessor.registerRawContentMatcher( pattern );\n\t}\n\n\t/**\n\t * Removes all event listeners set by the DataController.\n\t */\n\tdestroy() {\n\t\tthis.stopListening();\n\t}\n\n\t/**\n\t * Checks if all provided root names are existing editor roots.\n\t *\n\t * @private\n\t * @param {Array.} rootNames Root names to check.\n\t * @returns {Boolean} Whether all provided root names are existing editor roots.\n\t */\n\t_checkIfRootsExists( rootNames ) {\n\t\tfor ( const rootName of rootNames ) {\n\t\t\tif ( !this.model.document.getRootNames().includes( rootName ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Event fired once the data initialization has finished.\n\t *\n\t * @event ready\n\t */\n\n\t/**\n\t * Event fired after the {@link #init `init()` method} was run. It can be {@link #listenTo listened to} in order to adjust or modify\n\t * the initialization flow. However, if the `init` event is stopped or prevented, the {@link #event:ready `ready` event}\n\t * should be fired manually.\n\t *\n\t * The `init` event is fired by the decorated {@link #init} method.\n\t * See {@link module:utils/observablemixin~ObservableMixin#decorate} for more information and samples.\n\t *\n\t * @event init\n\t */\n\n\t/**\n\t * Event fired after {@link #set set() method} has been run.\n\t *\n\t * The `set` event is fired by decorated {@link #set} method.\n\t * See {@link module:utils/observablemixin~ObservableMixin#decorate} for more information and samples.\n\t *\n\t * @event set\n\t */\n}\n\nmix( DataController, ObservableMixin );\n\n// Helper function for downcast conversion.\n//\n// Takes a document element (element that is added to a model document) and checks which markers are inside it\n// and which markers are containing it. If the marker is intersecting with element, the intersection is returned.\nfunction _getMarkersRelativeToElement( element ) {\n\tconst result = [];\n\tconst doc = element.root.document;\n\n\tif ( !doc ) {\n\t\treturn [];\n\t}\n\n\tconst elementRange = ModelRange._createIn( element );\n\n\tfor ( const marker of doc.model.markers ) {\n\t\tconst intersection = elementRange.getIntersection( marker.getRange() );\n\n\t\tif ( intersection ) {\n\t\t\tresult.push( [ marker.name, intersection ] );\n\t\t}\n\t}\n\n\treturn result;\n}\n"],"sourceRoot":""}