element is inline and is represented by an attribute in the model.\n *\t\t\t\t// This is why you need to convert only children.\n *\t\t\t\tconst { modelRange } = conversionApi.convertChildren( data.viewItem, data.modelCursor );\n *\n *\t\t\t\tfor ( let item of modelRange.getItems() ) {\n *\t\t\t\t\tif ( conversionApi.schema.checkAttribute( item, 'linkHref' ) ) {\n *\t\t\t\t\t\tconversionApi.writer.setAttribute( 'linkHref', data.viewItem.getAttribute( 'href' ), item );\n *\t\t\t\t\t}\n *\t\t\t\t}\n *\t\t\t}\n *\t\t} );\n *\n *\t\t// Convert element's font-size style.\n *\t\t// Note: You should use a low-priority observer in order to ensure that\n *\t\t// it is executed after the element-to-element converter.\n *\t\teditor.data.upcastDispatcher.on( 'element:p', ( evt, data, conversionApi ) => {\n *\t\t\tconst { consumable, schema, writer } = conversionApi;\n *\n *\t\t\tif ( !consumable.consume( data.viewItem, { style: 'font-size' } ) ) {\n *\t\t\t\treturn;\n *\t\t\t}\n *\n *\t\t\tconst fontSize = data.viewItem.getStyle( 'font-size' );\n *\n *\t\t\t// Do not go for the model element after data.modelCursor because it might happen\n *\t\t\t// that a single view element was converted to multiple model elements. Get all of them.\n *\t\t\tfor ( const item of data.modelRange.getItems( { shallow: true } ) ) {\n *\t\t\t\tif ( schema.checkAttribute( item, 'fontSize' ) ) {\n *\t\t\t\t\twriter.setAttribute( 'fontSize', fontSize, item );\n *\t\t\t\t}\n *\t\t\t}\n *\t\t}, { priority: 'low' } );\n *\n *\t\t// Convert all elements which have no custom converter into a paragraph (autoparagraphing).\n *\t\teditor.data.upcastDispatcher.on( 'element', ( evt, data, conversionApi ) => {\n *\t\t\t// Check if an element can be converted.\n *\t\t\tif ( !conversionApi.consumable.test( data.viewItem, { name: data.viewItem.name } ) ) {\n *\t\t\t\t// When an element is already consumed by higher priority converters, do nothing.\n *\t\t\t\treturn;\n *\t\t\t}\n *\n *\t\t\tconst paragraph = conversionApi.writer.createElement( 'paragraph' );\n *\n *\t\t\t// Try to safely insert a paragraph at the model cursor - it will find an allowed parent for the current element.\n *\t\t\tif ( !conversionApi.safeInsert( paragraph, data.modelCursor ) ) {\n *\t\t\t\t// When an element was not inserted, it means that you cannot insert a paragraph at this position.\n *\t\t\t\treturn;\n *\t\t\t}\n *\n *\t\t\t// Consume the inserted element.\n *\t\t\tconversionApi.consumable.consume( data.viewItem, { name: data.viewItem.name } ) );\n *\n *\t\t\t// Convert the children to a paragraph.\n *\t\t\tconst { modelRange } = conversionApi.convertChildren( data.viewItem, paragraph ) );\n *\n *\t\t\t// Update `modelRange` and `modelCursor` in the `data` as a conversion result.\n *\t\t\tconversionApi.updateConversionResult( paragraph, data );\n *\t\t}, { priority: 'low' } );\n *\n * @mixes module:utils/emittermixin~EmitterMixin\n * @fires viewCleanup\n * @fires element\n * @fires text\n * @fires documentFragment\n */\nexport default class UpcastDispatcher {\n\t/**\n\t * Creates an upcast dispatcher that operates using the passed API.\n\t *\n\t * @see module:engine/conversion/upcastdispatcher~UpcastConversionApi\n\t * @param {Object} [conversionApi] Additional properties for an interface that will be passed to events fired\n\t * by the upcast dispatcher.\n\t */\n\tconstructor( conversionApi = {} ) {\n\t\t/**\n\t\t * The list of elements that were created during splitting.\n\t\t *\n\t\t * After the conversion process the list is cleared.\n\t\t *\n\t\t * @private\n\t\t * @type {Map.>}\n\t\t */\n\t\tthis._splitParts = new Map();\n\n\t\t/**\n\t\t * The list of cursor parent elements that were created during splitting.\n\t\t *\n\t\t * After the conversion process the list is cleared.\n\t\t *\n\t\t * @private\n\t\t * @type {Map.>}\n\t\t */\n\t\tthis._cursorParents = new Map();\n\n\t\t/**\n\t\t * The position in the temporary structure where the converted content is inserted. The structure reflects the context of\n\t\t * the target position where the content will be inserted. This property is built based on the context parameter of the\n\t\t * convert method.\n\t\t *\n\t\t * @private\n\t\t * @type {module:engine/model/position~Position|null}\n\t\t */\n\t\tthis._modelCursor = null;\n\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/upcastdispatcher~UpcastConversionApi}\n\t\t */\n\t\tthis.conversionApi = Object.assign( {}, conversionApi );\n\n\t\t// The below methods are bound to this `UpcastDispatcher` instance and set on `conversionApi`.\n\t\t// This way only a part of `UpcastDispatcher` API is exposed.\n\t\tthis.conversionApi.convertItem = this._convertItem.bind( this );\n\t\tthis.conversionApi.convertChildren = this._convertChildren.bind( this );\n\t\tthis.conversionApi.safeInsert = this._safeInsert.bind( this );\n\t\tthis.conversionApi.updateConversionResult = this._updateConversionResult.bind( this );\n\t\t// Advanced API - use only if custom position handling is needed.\n\t\tthis.conversionApi.splitToAllowedParent = this._splitToAllowedParent.bind( this );\n\t\tthis.conversionApi.getSplitParts = this._getSplitParts.bind( this );\n\t}\n\n\t/**\n\t * Starts the conversion process. The entry point for the conversion.\n\t *\n\t * @fires element\n\t * @fires text\n\t * @fires documentFragment\n\t * @param {module:engine/view/documentfragment~DocumentFragment|module:engine/view/element~Element} viewItem\n\t * The part of the view to be converted.\n\t * @param {module:engine/model/writer~Writer} writer An instance of the model writer.\n\t * @param {module:engine/model/schema~SchemaContextDefinition} [context=['$root']] Elements will be converted according to this context.\n\t * @returns {module:engine/model/documentfragment~DocumentFragment} Model data that is the result of the conversion process\n\t * wrapped in `DocumentFragment`. Converted marker elements will be set as the document fragment's\n\t * {@link module:engine/model/documentfragment~DocumentFragment#markers static markers map}.\n\t */\n\tconvert( viewItem, writer, context = [ '$root' ] ) {\n\t\tthis.fire( 'viewCleanup', viewItem );\n\n\t\t// Create context tree and set position in the top element.\n\t\t// Items will be converted according to this position.\n\t\tthis._modelCursor = createContextTree( context, writer );\n\n\t\t// Store writer in conversion as a conversion API\n\t\t// to be sure that conversion process will use the same batch.\n\t\tthis.conversionApi.writer = writer;\n\n\t\t// Create consumable values list for conversion process.\n\t\tthis.conversionApi.consumable = ViewConsumable.createFrom( viewItem );\n\n\t\t// Custom data stored by converter for conversion process.\n\t\tthis.conversionApi.store = {};\n\n\t\t// Do the conversion.\n\t\tconst { modelRange } = this._convertItem( viewItem, this._modelCursor );\n\n\t\t// Conversion result is always a document fragment so let's create it.\n\t\tconst documentFragment = writer.createDocumentFragment();\n\n\t\t// When there is a conversion result.\n\t\tif ( modelRange ) {\n\t\t\t// Remove all empty elements that were create while splitting.\n\t\t\tthis._removeEmptyElements();\n\n\t\t\t// Move all items that were converted in context tree to the document fragment.\n\t\t\tfor ( const item of Array.from( this._modelCursor.parent.getChildren() ) ) {\n\t\t\t\twriter.append( item, documentFragment );\n\t\t\t}\n\n\t\t\t// Extract temporary markers elements from model and set as static markers collection.\n\t\t\tdocumentFragment.markers = extractMarkersFromModelFragment( documentFragment, writer );\n\t\t}\n\n\t\t// Clear context position.\n\t\tthis._modelCursor = null;\n\n\t\t// Clear split elements & parents lists.\n\t\tthis._splitParts.clear();\n\t\tthis._cursorParents.clear();\n\n\t\t// Clear conversion API.\n\t\tthis.conversionApi.writer = null;\n\t\tthis.conversionApi.store = null;\n\n\t\t// Return fragment as conversion result.\n\t\treturn documentFragment;\n\t}\n\n\t/**\n\t * @private\n\t * @see module:engine/conversion/upcastdispatcher~UpcastConversionApi#convertItem\n\t */\n\t_convertItem( viewItem, modelCursor ) {\n\t\tconst data = Object.assign( { viewItem, modelCursor, modelRange: null } );\n\n\t\tif ( viewItem.is( 'element' ) ) {\n\t\t\tthis.fire( 'element:' + viewItem.name, data, this.conversionApi );\n\t\t} else if ( viewItem.is( '$text' ) ) {\n\t\t\tthis.fire( 'text', data, this.conversionApi );\n\t\t} else {\n\t\t\tthis.fire( 'documentFragment', data, this.conversionApi );\n\t\t}\n\n\t\t// Handle incorrect conversion result.\n\t\tif ( data.modelRange && !( data.modelRange instanceof ModelRange ) ) {\n\t\t\t/**\n\t\t\t * Incorrect conversion result was dropped.\n\t\t\t *\n\t\t\t * {@link module:engine/model/range~Range Model range} should be a conversion result.\n\t\t\t *\n\t\t\t * @error view-conversion-dispatcher-incorrect-result\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-conversion-dispatcher-incorrect-result', this );\n\t\t}\n\n\t\treturn { modelRange: data.modelRange, modelCursor: data.modelCursor };\n\t}\n\n\t/**\n\t * @private\n\t * @see module:engine/conversion/upcastdispatcher~UpcastConversionApi#convertChildren\n\t */\n\t_convertChildren( viewItem, elementOrModelCursor ) {\n\t\tlet nextModelCursor = elementOrModelCursor.is( 'position' ) ?\n\t\t\telementOrModelCursor : ModelPosition._createAt( elementOrModelCursor, 0 );\n\n\t\tconst modelRange = new ModelRange( nextModelCursor );\n\n\t\tfor ( const viewChild of Array.from( viewItem.getChildren() ) ) {\n\t\t\tconst result = this._convertItem( viewChild, nextModelCursor );\n\n\t\t\tif ( result.modelRange instanceof ModelRange ) {\n\t\t\t\tmodelRange.end = result.modelRange.end;\n\t\t\t\tnextModelCursor = result.modelCursor;\n\t\t\t}\n\t\t}\n\n\t\treturn { modelRange, modelCursor: nextModelCursor };\n\t}\n\n\t/**\n\t * @private\n\t * @see module:engine/conversion/upcastdispatcher~UpcastConversionApi#safeInsert\n\t */\n\t_safeInsert( modelElement, position ) {\n\t\t// Find allowed parent for element that we are going to insert.\n\t\t// If current parent does not allow to insert element but one of the ancestors does\n\t\t// then split nodes to allowed parent.\n\t\tconst splitResult = this._splitToAllowedParent( modelElement, position );\n\n\t\t// When there is no split result it means that we can't insert element to model tree, so let's skip it.\n\t\tif ( !splitResult ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Insert element on allowed position.\n\t\tthis.conversionApi.writer.insert( modelElement, splitResult.position );\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * @private\n\t * @see module:engine/conversion/upcastdispatcher~UpcastConversionApi#updateConversionResult\n\t */\n\t_updateConversionResult( modelElement, data ) {\n\t\tconst parts = this._getSplitParts( modelElement );\n\n\t\tconst writer = this.conversionApi.writer;\n\n\t\t// Set conversion result range - only if not set already.\n\t\tif ( !data.modelRange ) {\n\t\t\tdata.modelRange = writer.createRange(\n\t\t\t\twriter.createPositionBefore( modelElement ),\n\t\t\t\twriter.createPositionAfter( parts[ parts.length - 1 ] )\n\t\t\t);\n\t\t}\n\n\t\tconst savedCursorParent = this._cursorParents.get( modelElement );\n\n\t\t// Now we need to check where the `modelCursor` should be.\n\t\tif ( savedCursorParent ) {\n\t\t\t// If we split parent to insert our element then we want to continue conversion in the new part of the split parent.\n\t\t\t//\n\t\t\t// before: foo[]\n\t\t\t// after: foo []\n\n\t\t\tdata.modelCursor = writer.createPositionAt( savedCursorParent, 0 );\n\t\t} else {\n\t\t\t// Otherwise just continue after inserted element.\n\n\t\t\tdata.modelCursor = data.modelRange.end;\n\t\t}\n\t}\n\n\t/**\n\t * @private\n\t * @see module:engine/conversion/upcastdispatcher~UpcastConversionApi#splitToAllowedParent\n\t */\n\t_splitToAllowedParent( node, modelCursor ) {\n\t\tconst { schema, writer } = this.conversionApi;\n\n\t\t// Try to find allowed parent.\n\t\tlet allowedParent = schema.findAllowedParent( modelCursor, node );\n\n\t\tif ( allowedParent ) {\n\t\t\t// When current position parent allows to insert node then return this position.\n\t\t\tif ( allowedParent === modelCursor.parent ) {\n\t\t\t\treturn { position: modelCursor };\n\t\t\t}\n\n\t\t\t// When allowed parent is in context tree (it's outside the converted tree).\n\t\t\tif ( this._modelCursor.parent.getAncestors().includes( allowedParent ) ) {\n\t\t\t\tallowedParent = null;\n\t\t\t}\n\t\t}\n\n\t\tif ( !allowedParent ) {\n\t\t\t// Check if the node wrapped with a paragraph would be accepted by the schema.\n\t\t\tif ( !isParagraphable( modelCursor, node, schema ) ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tposition: wrapInParagraph( modelCursor, writer )\n\t\t\t};\n\t\t}\n\n\t\t// Split element to allowed parent.\n\t\tconst splitResult = this.conversionApi.writer.split( modelCursor, allowedParent );\n\n\t\t// Using the range returned by `model.Writer#split`, we will pair original elements with their split parts.\n\t\t//\n\t\t// The range returned from the writer spans \"over the split\" or, precisely saying, from the end of the original element (the one\n\t\t// that got split) to the beginning of the other part of that element:\n\t\t//\n\t\t// X[]Y ->\n\t\t// X[]Y\n\t\t//\n\t\t// After the split there cannot be any full node between the positions in `splitRange`. The positions are touching.\n\t\t// Also, because of how splitting works, it is easy to notice, that \"closing tags\" are in the reverse order than \"opening tags\".\n\t\t// Also, since we split all those elements, each of them has to have the other part.\n\t\t//\n\t\t// With those observations in mind, we will pair the original elements with their split parts by saving \"closing tags\" and matching\n\t\t// them with \"opening tags\" in the reverse order. For that we can use a stack.\n\t\tconst stack = [];\n\n\t\tfor ( const treeWalkerValue of splitResult.range.getWalker() ) {\n\t\t\tif ( treeWalkerValue.type == 'elementEnd' ) {\n\t\t\t\tstack.push( treeWalkerValue.item );\n\t\t\t} else {\n\t\t\t\t// There should not be any text nodes after the element is split, so the only other value is `elementStart`.\n\t\t\t\tconst originalPart = stack.pop();\n\t\t\t\tconst splitPart = treeWalkerValue.item;\n\n\t\t\t\tthis._registerSplitPair( originalPart, splitPart );\n\t\t\t}\n\t\t}\n\n\t\tconst cursorParent = splitResult.range.end.parent;\n\t\tthis._cursorParents.set( node, cursorParent );\n\n\t\treturn {\n\t\t\tposition: splitResult.position,\n\t\t\tcursorParent\n\t\t};\n\t}\n\n\t/**\n\t * Registers that a `splitPart` element is a split part of the `originalPart` element.\n\t *\n\t * The data set by this method is used by {@link #_getSplitParts} and {@link #_removeEmptyElements}.\n\t *\n\t * @private\n\t * @param {module:engine/model/element~Element} originalPart\n\t * @param {module:engine/model/element~Element} splitPart\n\t */\n\t_registerSplitPair( originalPart, splitPart ) {\n\t\tif ( !this._splitParts.has( originalPart ) ) {\n\t\t\tthis._splitParts.set( originalPart, [ originalPart ] );\n\t\t}\n\n\t\tconst list = this._splitParts.get( originalPart );\n\n\t\tthis._splitParts.set( splitPart, list );\n\t\tlist.push( splitPart );\n\t}\n\n\t/**\n\t * @private\n\t * @see module:engine/conversion/upcastdispatcher~UpcastConversionApi#getSplitParts\n\t */\n\t_getSplitParts( element ) {\n\t\tlet parts;\n\n\t\tif ( !this._splitParts.has( element ) ) {\n\t\t\tparts = [ element ];\n\t\t} else {\n\t\t\tparts = this._splitParts.get( element );\n\t\t}\n\n\t\treturn parts;\n\t}\n\n\t/**\n\t * Checks if there are any empty elements created while splitting and removes them.\n\t *\n\t * This method works recursively to re-check empty elements again after at least one element was removed in the initial call,\n\t * as some elements might have become empty after other empty elements were removed from them.\n\t *\n\t * @private\n\t */\n\t_removeEmptyElements() {\n\t\tlet anyRemoved = false;\n\n\t\tfor ( const element of this._splitParts.keys() ) {\n\t\t\tif ( element.isEmpty ) {\n\t\t\t\tthis.conversionApi.writer.remove( element );\n\t\t\t\tthis._splitParts.delete( element );\n\n\t\t\t\tanyRemoved = true;\n\t\t\t}\n\t\t}\n\n\t\tif ( anyRemoved ) {\n\t\t\tthis._removeEmptyElements();\n\t\t}\n\t}\n\n\t/**\n\t * Fired before the first conversion event, at the beginning of the upcast (view-to-model conversion) process.\n\t *\n\t * @event viewCleanup\n\t * @param {module:engine/view/documentfragment~DocumentFragment|module:engine/view/element~Element}\n\t * viewItem A part of the view to be converted.\n\t */\n\n\t/**\n\t * Fired when an {@link module:engine/view/element~Element} is converted.\n\t *\n\t * `element` is a namespace event for a class of events. Names of actually called events follow the pattern of\n\t * `element:` where `elementName` is the name of the converted element. This way listeners may listen to\n\t * a conversion of all or just specific elements.\n\t *\n\t * @event element\n\t * @param {module:engine/conversion/upcastdispatcher~UpcastConversionData} data The conversion data. Keep in mind that this object is\n\t * shared by reference between all callbacks that will be called. This means that callbacks can override values if needed, and these\n\t * values will be available in other callbacks.\n\t * @param {module:engine/conversion/upcastdispatcher~UpcastConversionApi} conversionApi Conversion utilities to be used by the\n\t * callback.\n\t */\n\n\t/**\n\t * Fired when a {@link module:engine/view/text~Text} is converted.\n\t *\n\t * @event text\n\t * @see #event:element\n\t */\n\n\t/**\n\t * Fired when a {@link module:engine/view/documentfragment~DocumentFragment} is converted.\n\t *\n\t * @event documentFragment\n\t * @see #event:element\n\t */\n}\n\nmix( UpcastDispatcher, EmitterMixin );\n\n// Traverses given model item and searches elements which marks marker range. Found element is removed from\n// DocumentFragment but path of this element is stored in a Map which is then returned.\n//\n// @param {module:engine/view/documentfragment~DocumentFragment|module:engine/view/node~Node} modelItem Fragment of model.\n// @returns {Map} List of static markers.\nfunction extractMarkersFromModelFragment( modelItem, writer ) {\n\tconst markerElements = new Set();\n\tconst markers = new Map();\n\n\t// Create ModelTreeWalker.\n\tconst range = ModelRange._createIn( modelItem ).getItems();\n\n\t// Walk through DocumentFragment and collect marker elements.\n\tfor ( const item of range ) {\n\t\t// Check if current element is a marker.\n\t\tif ( item.name == '$marker' ) {\n\t\t\tmarkerElements.add( item );\n\t\t}\n\t}\n\n\t// Walk through collected marker elements store its path and remove its from the DocumentFragment.\n\tfor ( const markerElement of markerElements ) {\n\t\tconst markerName = markerElement.getAttribute( 'data-name' );\n\t\tconst currentPosition = writer.createPositionBefore( markerElement );\n\n\t\t// When marker of given name is not stored it means that we have found the beginning of the range.\n\t\tif ( !markers.has( markerName ) ) {\n\t\t\tmarkers.set( markerName, new ModelRange( currentPosition.clone() ) );\n\t\t// Otherwise is means that we have found end of the marker range.\n\t\t} else {\n\t\t\tmarkers.get( markerName ).end = currentPosition.clone();\n\t\t}\n\n\t\t// Remove marker element from DocumentFragment.\n\t\twriter.remove( markerElement );\n\t}\n\n\treturn markers;\n}\n\n// Creates model fragment according to given context and returns position in the bottom (the deepest) element.\nfunction createContextTree( contextDefinition, writer ) {\n\tlet position;\n\n\tfor ( const item of new SchemaContext( contextDefinition ) ) {\n\t\tconst attributes = {};\n\n\t\tfor ( const key of item.getAttributeKeys() ) {\n\t\t\tattributes[ key ] = item.getAttribute( key );\n\t\t}\n\n\t\tconst current = writer.createElement( item.name, attributes );\n\n\t\tif ( position ) {\n\t\t\twriter.append( current, position );\n\t\t}\n\n\t\tposition = ModelPosition._createAt( current, 0 );\n\t}\n\n\treturn position;\n}\n\n/**\n * A set of conversion utilities available as the third parameter of the\n * {@link module:engine/conversion/upcastdispatcher~UpcastDispatcher upcast dispatcher}'s events.\n *\n * @interface module:engine/conversion/upcastdispatcher~UpcastConversionApi\n */\n\n/**\n * Starts the conversion of a given item by firing an appropriate event.\n *\n * Every fired event is passed (as the first parameter) an object with the `modelRange` property. Every event may set and/or\n * modify that property. When all callbacks are done, the final value of the `modelRange` property is returned by this method.\n * The `modelRange` must be a {@link module:engine/model/range~Range model range} or `null` (as set by default).\n *\n * @method #convertItem\n * @fires module:engine/conversion/upcastdispatcher~UpcastDispatcher#event:element\n * @fires module:engine/conversion/upcastdispatcher~UpcastDispatcher#event:text\n * @fires module:engine/conversion/upcastdispatcher~UpcastDispatcher#event:documentFragment\n * @param {module:engine/view/item~Item} viewItem Item to convert.\n * @param {module:engine/model/position~Position} modelCursor The conversion position.\n * @returns {Object} result The conversion result.\n * @returns {module:engine/model/range~Range|null} result.modelRange The model range containing the result of the item conversion,\n * created and modified by callbacks attached to the fired event, or `null` if the conversion result was incorrect.\n * @returns {module:engine/model/position~Position} result.modelCursor The position where the conversion should be continued.\n */\n\n/**\n * Starts the conversion of all children of a given item by firing appropriate events for all the children.\n *\n * @method #convertChildren\n * @fires module:engine/conversion/upcastdispatcher~UpcastDispatcher#event:element\n * @fires module:engine/conversion/upcastdispatcher~UpcastDispatcher#event:text\n * @fires module:engine/conversion/upcastdispatcher~UpcastDispatcher#event:documentFragment\n * @param {module:engine/view/item~Item} viewItem An element whose children should be converted.\n * @param {module:engine/model/position~Position|module:engine/model/element~Element} positionOrElement A position or an element of\n * the conversion.\n * @returns {Object} result The conversion result.\n * @returns {module:engine/model/range~Range} result.modelRange The model range containing the results of the conversion of all children\n * of the given item. When no child was converted, the range is collapsed.\n * @returns {module:engine/model/position~Position} result.modelCursor The position where the conversion should be continued.\n */\n\n/**\n * Safely inserts an element to the document, checking the {@link module:engine/model/schema~Schema schema} to find an allowed parent for\n * an element that you are going to insert, starting from the given position. If the current parent does not allow to insert the element\n * but one of the ancestors does, then splits the nodes to allowed parent.\n *\n * If the schema allows to insert the node in a given position, nothing is split.\n *\n * If it was not possible to find an allowed parent, `false` is returned and nothing is split.\n *\n * Otherwise, ancestors are split.\n *\n * For instance, if `` is not allowed in `` but is allowed in `$root`:\n *\n *\t\tfoo[]bar\n *\n *\t\t-> safe insert for `` will split ->\n *\n *\t\tfoo[]bar\n *\n * Example usage:\n *\n *\t\tconst myElement = conversionApi.writer.createElement( 'myElement' );\n *\n *\t\tif ( !conversionApi.safeInsert( myElement, data.modelCursor ) ) {\n *\t\t\treturn;\n *\t\t}\n *\n * The split result is saved and {@link #updateConversionResult} should be used to update the\n * {@link module:engine/conversion/upcastdispatcher~UpcastConversionData conversion data}.\n *\n * @method #safeInsert\n * @param {module:engine/model/node~Node} node The node to insert.\n * @param {module:engine/model/position~Position} position The position where an element is going to be inserted.\n * @returns {Boolean} The split result. If it was not possible to find an allowed position, `false` is returned.\n */\n\n/**\n * Updates the conversion result and sets a proper {@link module:engine/conversion/upcastdispatcher~UpcastConversionData#modelRange} and\n * the next {@link module:engine/conversion/upcastdispatcher~UpcastConversionData#modelCursor} after the conversion.\n * Used together with {@link #safeInsert}, it enables you to easily convert elements without worrying if the node was split\n * during the conversion of its children.\n *\n * A usage example in converter code:\n *\n *\t\tconst myElement = conversionApi.writer.createElement( 'myElement' );\n *\n *\t\tif ( !conversionApi.safeInsert( myElement, data.modelCursor ) ) {\n *\t\t\treturn;\n *\t\t}\n *\n *\t\t// Children conversion may split `myElement`.\n *\t\tconversionApi.convertChildren( data.viewItem, myElement );\n *\n *\t\tconversionApi.updateConversionResult( myElement, data );\n *\n * @method #updateConversionResult\n * @param {module:engine/model/element~Element} element\n * @param {module:engine/conversion/upcastdispatcher~UpcastConversionData} data Conversion data.\n * @param {module:engine/conversion/upcastdispatcher~UpcastConversionApi} conversionApi Conversion utilities to be used by the callback.\n */\n\n/**\n * Checks the {@link module:engine/model/schema~Schema schema} to find an allowed parent for an element that is going to be inserted\n * starting from the given position. If the current parent does not allow inserting an element but one of the ancestors does, the method\n * splits nodes to allowed parent.\n *\n * If the schema allows inserting the node in the given position, nothing is split and an object with that position is returned.\n *\n * If it was not possible to find an allowed parent, `null` is returned and nothing is split.\n *\n * Otherwise, ancestors are split and an object with a position and the copy of the split element is returned.\n *\n * For instance, if `` is not allowed in `` but is allowed in `$root`:\n *\n *\t\tfoo[]bar\n *\n *\t\t-> split for `` ->\n *\n *\t\tfoo[]bar\n *\n * In the example above, the position between `` elements will be returned as `position` and the second `paragraph`\n * as `cursorParent`.\n *\n * **Note:** This is an advanced method. For most cases {@link #safeInsert} and {@link #updateConversionResult} should be used.\n *\n * @method #splitToAllowedParent\n * @param {module:engine/model/position~Position} position The position where the element is going to be inserted.\n * @param {module:engine/model/node~Node} node The node to insert.\n * @returns {Object|null} The split result. If it was not possible to find an allowed position, `null` is returned.\n * @returns {module:engine/model/position~Position} The position between split elements.\n * @returns {module:engine/model/element~Element} [cursorParent] The element inside which the cursor should be placed to\n * continue the conversion. When the element is not defined it means that there was no split.\n */\n\n/**\n * Returns all the split parts of the given `element` that were created during upcasting through using {@link #splitToAllowedParent}.\n * It enables you to easily track these elements and continue processing them after they are split during the conversion of their children.\n *\n *\t\tFoobarbaz ->\n *\t\tFoobarbaz\n *\n * For a reference to any of above paragraphs, the function will return all three paragraphs (the original element included),\n * sorted in the order of their creation (the original element is the first one).\n *\n * If the given `element` was not split, an array with a single element is returned.\n *\n * A usage example in the converter code:\n *\n *\t\tconst myElement = conversionApi.writer.createElement( 'myElement' );\n *\n *\t\t// Children conversion may split `myElement`.\n *\t\tconversionApi.convertChildren( data.viewItem, data.modelCursor );\n *\n *\t\tconst splitParts = conversionApi.getSplitParts( myElement );\n *\t\tconst lastSplitPart = splitParts[ splitParts.length - 1 ];\n *\n *\t\t// Setting `data.modelRange` basing on split parts:\n *\t\tdata.modelRange = conversionApi.writer.createRange(\n *\t\t\tconversionApi.writer.createPositionBefore( myElement ),\n *\t\t\tconversionApi.writer.createPositionAfter( lastSplitPart )\n *\t\t);\n *\n *\t\t// Setting `data.modelCursor` to continue after the last split element:\n *\t\tdata.modelCursor = conversionApi.writer.createPositionAfter( lastSplitPart );\n *\n * **Tip:** If you are unable to get a reference to the original element (for example because the code is split into multiple converters\n * or even classes) but it has already been converted, you may want to check the first element in `data.modelRange`. This is a common\n * situation if an attribute converter is separated from an element converter.\n *\n * **Note:** This is an advanced method. For most cases {@link #safeInsert} and {@link #updateConversionResult} should be used.\n *\n * @method #getSplitParts\n * @param {module:engine/model/element~Element} element\n * @returns {Array.}\n */\n\n/**\n * Stores information about what parts of the processed view item are still waiting to be handled. After a piece of view item\n * was converted, an appropriate consumable value should be\n * {@link module:engine/conversion/viewconsumable~ViewConsumable#consume consumed}.\n *\n * @member {module:engine/conversion/viewconsumable~ViewConsumable} #consumable\n */\n\n/**\n * Custom data stored by converters for the conversion process. Custom properties of this object can be defined and use to\n * pass parameters between converters.\n *\n * The difference between this property and the `data` parameter of\n * {@link module:engine/conversion/upcastdispatcher~UpcastDispatcher#event:element} is that the `data` parameters allow you\n * to pass parameters within a single event and `store` within the whole conversion.\n *\n * @member {Object} #store\n */\n\n/**\n * The model's schema instance.\n *\n * @member {module:engine/model/schema~Schema} #schema\n */\n\n/**\n * The {@link module:engine/model/writer~Writer} instance used to manipulate the data during conversion.\n *\n * @member {module:engine/model/writer~Writer} #writer\n */\n\n/**\n * Conversion data.\n *\n * **Note:** Keep in mind that this object is shared by reference between all conversion callbacks that will be called.\n * This means that callbacks can override values if needed, and these values will be available in other callbacks.\n *\n * @typedef {Object} module:engine/conversion/upcastdispatcher~UpcastConversionData\n *\n * @property {module:engine/view/item~Item} viewItem The converted item.\n * @property {module:engine/model/position~Position} modelCursor The position where the converter should start changes.\n * Change this value for the next converter to tell where the conversion should continue.\n * @property {module:engine/model/range~Range} [modelRange] The current state of conversion result. Every change to\n * the converted element should be reflected by setting or modifying this property.\n */\n"],"sourceRoot":""}