{"version":3,"sources":["webpack:///./node_modules/@ckeditor/ckeditor5-engine/src/conversion/upcasthelpers.js"],"names":["UpcastHelpers","config","this","add","upcastElementToElement","upcastElementToAttribute","upcastAttributeToAttribute","upcastElementToMarker","upcastDataToMarker","ConversionHelpers","convertToModelFragment","evt","data","conversionApi","modelRange","consumable","consume","viewItem","name","_conversionApi$conver","convertChildren","modelCursor","convertText","_ref","schema","writer","position","test","checkChild","isParagraphable","wrapInParagraph","text","createText","insert","createRange","getShiftedBy","offsetSize","end","convertSelectionChange","model","mapper","_step","viewSelection","newSelection","ranges","_iterator","_createForOfIteratorHelper","getRanges","s","n","done","viewRange","value","push","toModelRange","err","e","f","modelSelection","createSelection","backward","isBackward","isEqual","document","selection","change","setSelection","cloneDeep","converter","prepareToElementConverter","elementName","getViewElementNameFromConfig","view","eventName","dispatcher","on","priority","converterPriority","normalizeModelAttributeConfig","prepareToAttributeConverter","viewKey","key","normalizeViewAttributeKeyValueConfig","normalizeElementToMarkerConfig","converterStart","normalizeDataToMarkerConfig","converterEnd","basePriority","priorities","get","maxPriority","priorityFactor","upcastAttributeToMarker","attrName","concat","addMarkerElements","markerViewNames","_step2","_iterator2","markerViewName","markerName","element","createElement","data-name","_getTransformedByInsertion","attributes","Object","assign","getAttribute","split","start","viewConfig","D_Projects_UA_repo_Source_Client_UA_User_Web_node_modules_babel_runtime_helpers_esm_typeof_js__WEBPACK_IMPORTED_MODULE_9__","matcher","Matcher","matcherResult","match","modelElement","getModelElement","safeInsert","updateConversionResult","input","Function","normalized","keyName","D_Projects_UA_repo_Source_Client_UA_User_Web_node_modules_babel_runtime_helpers_esm_defineProperty_js__WEBPACK_IMPORTED_MODULE_6__","viewAttributeKeyToCopy","arguments","length","undefined","defaultModelValue","viewElement","shallow","onlyViewNameIsDefined","modelKey","modelValue","attributeWasSet","setAttributeOn","configToTest","classes","styles","modelAttribute","result","_i","_Array$from","Array","from","getItems","node","checkAttribute","hasAttribute","setAttribute","oldModel","type","configForElements","viewName"],"mappings":"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","file":"js/chunk-2d2104a6.a9756348.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\nimport Matcher from '../view/matcher';\nimport ConversionHelpers from './conversionhelpers';\n\nimport { cloneDeep } from 'lodash-es';\n\nimport priorities from '@ckeditor/ckeditor5-utils/src/priorities';\nimport { isParagraphable, wrapInParagraph } from '../model/utils/autoparagraphing';\n\n/**\n * Contains {@link module:engine/view/view view} to {@link module:engine/model/model model} converters for\n * {@link module:engine/conversion/upcastdispatcher~UpcastDispatcher}.\n *\n * @module engine/conversion/upcasthelpers\n */\n\n/**\n * Upcast conversion helper functions.\n *\n * @extends module:engine/conversion/conversionhelpers~ConversionHelpers\n */\nexport default class UpcastHelpers extends ConversionHelpers {\n\t/**\n\t * View element to model element conversion helper.\n\t *\n\t * This conversion results in creating a model element. For example,\n\t * view `

Foo

` becomes `Foo` in the model.\n\t *\n\t * Keep in mind that the element will be inserted only if it is allowed\n\t * by {@link module:engine/model/schema~Schema schema} configuration.\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).elementToElement( {\n\t *\t\t\tview: 'p',\n\t *\t\t\tmodel: 'paragraph'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).elementToElement( {\n\t *\t\t\tview: 'p',\n\t *\t\t\tmodel: 'paragraph',\n\t *\t\t\tconverterPriority: 'high'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).elementToElement( {\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\tmodel: 'fancyParagraph'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).elementToElement( {\n\t * \t\t\tview: {\n\t *\t\t\t\tname: 'p',\n\t *\t\t\t\tclasses: 'heading'\n\t * \t\t\t},\n\t * \t\t\tmodel: ( viewElement, conversionApi ) => {\n\t * \t\t\t\tconst modelWriter = conversionApi.writer;\n\t *\n\t * \t\t\t\treturn modelWriter.createElement( 'heading', { level: viewElement.getAttribute( 'data-level' ) } );\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 #elementToElement\n\t * @param {Object} config Conversion configuration.\n\t * @param {module:engine/view/matcher~MatcherPattern} [config.view] Pattern matching all view elements which should be converted. If not\n\t * set, the converter will fire for every view element.\n\t * @param {String|module:engine/model/element~Element|Function} config.model Name of the model element, a model element instance or a\n\t * function that takes a view element and {@link module:engine/conversion/upcastdispatcher~UpcastConversionApi upcast conversion API}\n\t * and returns a model element. The model element will be inserted in the model.\n\t * @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.\n\t * @returns {module:engine/conversion/upcasthelpers~UpcastHelpers}\n\t */\n\telementToElement( config ) {\n\t\treturn this.add( upcastElementToElement( config ) );\n\t}\n\n\t/**\n\t * View element to model attribute conversion helper.\n\t *\n\t * This conversion results in setting an attribute on a model node. For example, view `Foo` becomes\n\t * `Foo` {@link module:engine/model/text~Text model text node} with `bold` attribute set to `true`.\n\t *\n\t * This helper is meant to set a model attribute on all the elements that are inside the converted element:\n\t *\n\t *\t\tFoo -->

Foo

--> <$text bold=\"true\">Foo\n\t *\n\t * Above is a sample of HTML code, that goes through autoparagraphing (first step) and then is converted (second step).\n\t * Even though `` is over `

` element, `bold=\"true\"` was added to the text. See\n\t * {@link module:engine/conversion/upcasthelpers~UpcastHelpers#attributeToAttribute} for comparison.\n\t *\n\t * Keep in mind that the attribute will be set only if it is allowed by {@link module:engine/model/schema~Schema schema} configuration.\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).elementToAttribute( {\n\t *\t\t\tview: 'strong',\n\t *\t\t\tmodel: 'bold'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).elementToAttribute( {\n\t *\t\t\tview: 'strong',\n\t *\t\t\tmodel: 'bold',\n\t *\t\t\tconverterPriority: 'high'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).elementToAttribute( {\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\tmodel: 'bold'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).elementToAttribute( {\n\t *\t\t\tview: {\n\t *\t\t\t\tname: 'span',\n\t *\t\t\t\tclasses: [ 'styled', 'styled-dark' ]\n\t *\t\t\t},\n\t *\t\t\tmodel: {\n\t *\t\t\t\tkey: 'styled',\n\t *\t\t\t\tvalue: 'dark'\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * \t\teditor.conversion.for( 'upcast' ).elementToAttribute( {\n\t *\t\t\tview: {\n\t *\t\t\t\tname: 'span',\n\t *\t\t\t\tstyles: {\n\t *\t\t\t\t\t'font-size': /[\\s\\S]+/\n\t *\t\t\t\t}\n\t *\t\t\t},\n\t *\t\t\tmodel: {\n\t *\t\t\t\tkey: 'fontSize',\n\t *\t\t\t\tvalue: ( viewElement, conversionApi ) => {\n\t *\t\t\t\t\tconst fontSize = viewElement.getStyle( 'font-size' );\n\t *\t\t\t\t\tconst value = fontSize.substr( 0, fontSize.length - 2 );\n\t *\n\t *\t\t\t\t\tif ( value <= 10 ) {\n\t *\t\t\t\t\t\treturn 'small';\n\t *\t\t\t\t\t} else if ( value > 12 ) {\n\t *\t\t\t\t\t\treturn 'big';\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 * 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 #elementToAttribute\n\t * @param {Object} config Conversion configuration.\n\t * @param {module:engine/view/matcher~MatcherPattern} config.view Pattern matching all view elements which should be converted.\n\t * @param {String|Object} config.model Model attribute key or an object with `key` and `value` properties, describing\n\t * the model attribute. `value` property may be set as a function that takes a view element and\n\t * {@link module:engine/conversion/upcastdispatcher~UpcastConversionApi upcast conversion API} and returns the value.\n\t * If `String` is given, the model attribute value will be set to `true`.\n\t * @param {module:utils/priorities~PriorityString} [config.converterPriority='low'] Converter priority.\n\t * @returns {module:engine/conversion/upcasthelpers~UpcastHelpers}\n\t */\n\telementToAttribute( config ) {\n\t\treturn this.add( upcastElementToAttribute( config ) );\n\t}\n\n\t/**\n\t * View attribute to model attribute conversion helper.\n\t *\n\t * This conversion results in setting an attribute on a model node. For example, view `` becomes\n\t * `` in the model.\n\t *\n\t * This helper is meant to convert view attributes from view elements which got converted to the model, so the view attribute\n\t * is set only on the corresponding model node:\n\t *\n\t *\t\t

foo
-->
foo
\n\t *\n\t * Above, `class=\"dark\"` attribute is added only to the `
` elements that has it. This is in contrary to\n\t * {@link module:engine/conversion/upcasthelpers~UpcastHelpers#elementToAttribute} which sets attributes for\n\t * all the children in the model:\n\t *\n\t *\t\tFoo -->

Foo

--> <$text bold=\"true\">Foo\n\t *\n\t * Above is a sample of HTML code, that goes through autoparagraphing (first step) and then is converted (second step).\n\t * Even though `` is over `

` element, `bold=\"true\"` was added to the text.\n\t *\n\t * Keep in mind that the attribute will be set only if it is allowed by {@link module:engine/model/schema~Schema schema} configuration.\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).attributeToAttribute( {\n\t *\t\t\tview: 'src',\n\t *\t\t\tmodel: 'source'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).attributeToAttribute( {\n\t *\t\t\tview: { key: 'src' },\n\t *\t\t\tmodel: 'source'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).attributeToAttribute( {\n\t *\t\t\tview: { key: 'src' },\n\t *\t\t\tmodel: 'source',\n\t *\t\t\tconverterPriority: 'normal'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).attributeToAttribute( {\n\t *\t\t\tview: {\n\t *\t\t\t\tkey: 'data-style',\n\t *\t\t\t\tvalue: /[\\s\\S]+/\n\t *\t\t\t},\n\t *\t\t\tmodel: 'styled'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).attributeToAttribute( {\n\t *\t\t\tview: {\n\t *\t\t\t\tname: 'img',\n\t *\t\t\t\tkey: 'class',\n\t *\t\t\t\tvalue: 'styled-dark'\n\t *\t\t\t},\n\t *\t\t\tmodel: {\n\t *\t\t\t\tkey: 'styled',\n\t *\t\t\t\tvalue: 'dark'\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).attributeToAttribute( {\n\t *\t\t\tview: {\n\t *\t\t\t\tkey: 'class',\n\t *\t\t\t\tvalue: /styled-[\\S]+/\n\t *\t\t\t},\n\t *\t\t\tmodel: {\n\t *\t\t\t\tkey: 'styled'\n\t *\t\t\t\tvalue: ( viewElement, conversionApi ) => {\n\t *\t\t\t\t\tconst regexp = /styled-([\\S]+)/;\n\t *\t\t\t\t\tconst match = viewElement.getAttribute( 'class' ).match( regexp );\n\t *\n\t *\t\t\t\t\treturn match[ 1 ];\n\t *\t\t\t\t}\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * Converting styles works a bit differently as it requires `view.styles` to be an object and by default\n\t * a model attribute will be set to `true` by such a converter. You can set the model attribute to any value by providing the `value`\n\t * callback that returns the desired value.\n\t *\n\t *\t\t// Default conversion of font-weight style will result in setting bold attribute to true.\n\t *\t\teditor.conversion.for( 'upcast' ).attributeToAttribute( {\n\t *\t\t\tview: {\n\t *\t\t\t\tstyles: {\n\t *\t\t\t\t\t'font-weight': 'bold'\n\t *\t\t\t\t}\n\t *\t\t\t},\n\t *\t\t\tmodel: 'bold'\n\t *\t\t} );\n\t *\n\t *\t\t// This converter will pass any style value to the `lineHeight` model attribute.\n\t *\t\teditor.conversion.for( 'upcast' ).attributeToAttribute( {\n\t *\t\t\tview: {\n\t *\t\t\t\tstyles: {\n\t *\t\t\t\t\t'line-height': /[\\s\\S]+/\n\t *\t\t\t\t}\n\t *\t\t\t},\n\t *\t\t\tmodel: {\n\t *\t\t\t\tkey: 'lineHeight',\n\t *\t\t\t\tvalue: ( viewElement, conversionApi ) => viewElement.getStyle( 'line-height' )\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.view Specifies which view attribute will be converted. If a `String` is passed,\n\t * attributes with given key will be converted. If an `Object` is passed, it must have a required `key` property,\n\t * specifying view attribute key, and may have an optional `value` property, specifying view attribute value and optional `name`\n\t * property specifying a view element name from/on which the attribute should be converted. `value` can be given as a `String`,\n\t * a `RegExp` or a function callback, that takes view attribute value as the only parameter and returns `Boolean`.\n\t * @param {String|Object} config.model Model attribute key or an object with `key` and `value` properties, describing\n\t * the model attribute. `value` property may be set as a function that takes a view element and\n\t * {@link module:engine/conversion/upcastdispatcher~UpcastConversionApi upcast conversion API} and returns the value.\n\t * If `String` is given, the model attribute value will be same as view attribute value.\n\t * @param {module:utils/priorities~PriorityString} [config.converterPriority='low'] Converter priority.\n\t * @returns {module:engine/conversion/upcasthelpers~UpcastHelpers}\n\t */\n\tattributeToAttribute( config ) {\n\t\treturn this.add( upcastAttributeToAttribute( config ) );\n\t}\n\n\t/**\n\t * View element to model marker conversion helper.\n\t *\n\t * This conversion results in creating a model marker. For example, if the marker was stored in a view as an element:\n\t * `

Foo

Bar

`,\n\t * after the conversion is done, the marker will be available in\n\t * {@link module:engine/model/model~Model#markers model document markers}.\n\t *\n\t * **Note**: When this helper is used in the data upcast in combination with\n\t * {@link module:engine/conversion/downcasthelpers~DowncastHelpers#markerToData `#markerToData()`} in the data downcast,\n\t * then invalid HTML code (e.g. a span between table cells) may be produced by the latter converter.\n\t *\n\t * In most of the cases, the {@link #dataToMarker} should be used instead.\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).elementToMarker( {\n\t *\t\t\tview: 'marker-search',\n\t *\t\t\tmodel: 'search'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).elementToMarker( {\n\t *\t\t\tview: 'marker-search',\n\t *\t\t\tmodel: 'search',\n\t *\t\t\tconverterPriority: 'high'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).elementToMarker( {\n\t *\t\t\tview: 'marker-search',\n\t *\t\t\tmodel: ( viewElement, conversionApi ) => 'comment:' + viewElement.getAttribute( 'data-comment-id' )\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).elementToMarker( {\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\tmodel: 'search'\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 #elementToMarker\n\t * @param {Object} config Conversion configuration.\n\t * @param {module:engine/view/matcher~MatcherPattern} config.view Pattern matching all view elements which should be converted.\n\t * @param {String|Function} config.model Name of the model marker, or a function that takes a view element and returns\n\t * a model marker name.\n\t * @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.\n\t * @returns {module:engine/conversion/upcasthelpers~UpcastHelpers}\n\t */\n\telementToMarker( config ) {\n\t\treturn this.add( upcastElementToMarker( config ) );\n\t}\n\n\t/**\n\t * View-to-model marker conversion helper.\n\t *\n\t * Converts view data created by {@link module:engine/conversion/downcasthelpers~DowncastHelpers#markerToData `#markerToData()`}\n\t * back to a model marker.\n\t *\n\t * This converter looks for specific view elements and view attributes that mark marker boundaries. See\n\t * {@link module:engine/conversion/downcasthelpers~DowncastHelpers#markerToData `#markerToData()`} to learn what view data\n\t * is expected by this converter.\n\t *\n\t * The `config.view` property is equal to the marker group name to convert.\n\t *\n\t * By default, this converter creates markers with the `group:name` name convention (to match the default `markerToData` conversion).\n\t *\n\t * The conversion configuration can take a function that will generate a marker name.\n\t * If such function is set as the `config.model` parameter, it is passed the `name` part from the view element or attribute and it is\n\t * expected to return a string with the marker name.\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 from the `comment` group will be converted.\n\t *\t\t// The conversion will look for `` and `` tags and\n\t *\t\t// `data-comment-start-before`, `data-comment-start-after`,\n\t *\t\t// `data-comment-end-before` and `data-comment-end-after` attributes.\n\t *\t\teditor.conversion.for( 'upcast' ).dataToMarker( {\n\t *\t\t\tview: 'comment'\n\t *\t\t} );\n\t *\n\t * An example of a model that may be generated by this conversion:\n\t *\n\t *\t\t// View:\n\t *\t\t

Foobar

\n\t *\t\t
\n\t *\n\t *\t\t// Model:\n\t *\t\tFoo[bar\n\t *\t\t]\n\t *\n\t * Where `[]` are boundaries of a marker that will receive the `comment:commentId:uid` name.\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( 'upcast' ).dataToMarker( {\n\t *\t\t\tview: 'comment',\n\t *\t\t\tmodel: ( name, conversionApi ) => 'comment:' + name,\n\t *\t\t} );\n\t *\n\t *\t\t// Using the converter priority:\n\t *\t\teditor.conversion.for( 'upcast' ).dataToMarker( {\n\t *\t\t\tview: 'comment',\n\t *\t\t\tmodel: ( name, conversionApi ) => 'comment:' + name,\n\t *\t\t\tconverterPriority: 'high'\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 #dataToMarker\n\t * @param {Object} config Conversion configuration.\n\t * @param {String} config.view The marker group name to convert.\n\t * @param {Function} [config.model] A function that takes the `name` part from the view element or attribute and\n\t * {@link module:engine/conversion/upcastdispatcher~UpcastConversionApi upcast conversion API} and returns the marker name.\n\t * @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.\n\t * @returns {module:engine/conversion/upcasthelpers~UpcastHelpers}\n\t */\n\tdataToMarker( config ) {\n\t\treturn this.add( upcastDataToMarker( config ) );\n\t}\n}\n\n/**\n * Function factory, creates a converter that converts {@link module:engine/view/documentfragment~DocumentFragment view document fragment}\n * or all children of {@link module:engine/view/element~Element} into\n * {@link module:engine/model/documentfragment~DocumentFragment model document fragment}.\n * This is the \"entry-point\" converter for upcast (view to model conversion). This converter starts the conversion of all children\n * of passed view document fragment. Those children {@link module:engine/view/node~Node view nodes} are then handled by other converters.\n *\n * This also a \"default\", last resort converter for all view elements that has not been converted by other converters.\n * When a view element is being converted to the model but it does not have converter specified, that view element\n * will be converted to {@link module:engine/model/documentfragment~DocumentFragment model document fragment} and returned.\n *\n * @returns {Function} Universal converter for view {@link module:engine/view/documentfragment~DocumentFragment fragments} and\n * {@link module:engine/view/element~Element elements} that returns\n * {@link module:engine/model/documentfragment~DocumentFragment model fragment} with children of converted view item.\n */\nexport function convertToModelFragment() {\n\treturn ( evt, data, conversionApi ) => {\n\t\t// Second argument in `consumable.consume` is discarded for ViewDocumentFragment but is needed for ViewElement.\n\t\tif ( !data.modelRange && conversionApi.consumable.consume( data.viewItem, { name: true } ) ) {\n\t\t\tconst { modelRange, modelCursor } = conversionApi.convertChildren( data.viewItem, data.modelCursor );\n\n\t\t\tdata.modelRange = modelRange;\n\t\t\tdata.modelCursor = modelCursor;\n\t\t}\n\t};\n}\n\n/**\n * Function factory, creates a converter that converts {@link module:engine/view/text~Text} to {@link module:engine/model/text~Text}.\n *\n * @returns {Function} {@link module:engine/view/text~Text View text} converter.\n */\nexport function convertText() {\n\treturn ( evt, data, { schema, consumable, writer } ) => {\n\t\tlet position = data.modelCursor;\n\n\t\t// When node is already converted then do nothing.\n\t\tif ( !consumable.test( data.viewItem ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !schema.checkChild( position, '$text' ) ) {\n\t\t\tif ( !isParagraphable( position, '$text', schema ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tposition = wrapInParagraph( position, writer );\n\t\t}\n\n\t\tconsumable.consume( data.viewItem );\n\n\t\tconst text = writer.createText( data.viewItem.data );\n\n\t\twriter.insert( text, position );\n\n\t\tdata.modelRange = writer.createRange(\n\t\t\tposition,\n\t\t\tposition.getShiftedBy( text.offsetSize )\n\t\t);\n\t\tdata.modelCursor = data.modelRange.end;\n\t};\n}\n\n/**\n * Function factory, creates a callback function which converts a {@link module:engine/view/selection~Selection\n * view selection} taken from the {@link module:engine/view/document~Document#event:selectionChange} event\n * and sets in on the {@link module:engine/model/document~Document#selection model}.\n *\n * **Note**: because there is no view selection change dispatcher nor any other advanced view selection to model\n * conversion mechanism, the callback should be set directly on view document.\n *\n *\t\tview.document.on( 'selectionChange', convertSelectionChange( modelDocument, mapper ) );\n *\n * @param {module:engine/model/model~Model} model Data model.\n * @param {module:engine/conversion/mapper~Mapper} mapper Conversion mapper.\n * @returns {Function} {@link module:engine/view/document~Document#event:selectionChange} callback function.\n */\nexport function convertSelectionChange( model, mapper ) {\n\treturn ( evt, data ) => {\n\t\tconst viewSelection = data.newSelection;\n\n\t\tconst ranges = [];\n\n\t\tfor ( const viewRange of viewSelection.getRanges() ) {\n\t\t\tranges.push( mapper.toModelRange( viewRange ) );\n\t\t}\n\n\t\tconst modelSelection = model.createSelection( ranges, { backward: viewSelection.isBackward } );\n\n\t\tif ( !modelSelection.isEqual( model.document.selection ) ) {\n\t\t\tmodel.change( writer => {\n\t\t\t\twriter.setSelection( modelSelection );\n\t\t\t} );\n\t\t}\n\t};\n}\n\n// View element to model element conversion helper.\n//\n// See {@link ~UpcastHelpers#elementToElement `.elementToElement()` upcast helper} for examples.\n//\n// @param {Object} config Conversion configuration.\n// @param {module:engine/view/matcher~MatcherPattern} [config.view] Pattern matching all view elements which should be converted. If not\n// set, the converter will fire for every view element.\n// @param {String|module:engine/model/element~Element|Function} config.model Name of the model element, a model element\n// instance or a function that takes a view element and returns a model element. The model element will be inserted in the model.\n// @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.\n// @returns {Function} Conversion helper.\nfunction upcastElementToElement( config ) {\n\tconfig = cloneDeep( config );\n\n\tconst converter = prepareToElementConverter( config );\n\n\tconst elementName = getViewElementNameFromConfig( config.view );\n\tconst eventName = elementName ? 'element:' + elementName : 'element';\n\n\treturn dispatcher => {\n\t\tdispatcher.on( eventName, converter, { priority: config.converterPriority || 'normal' } );\n\t};\n}\n\n// View element to model attribute conversion helper.\n//\n// See {@link ~UpcastHelpers#elementToAttribute `.elementToAttribute()` upcast helper} for examples.\n//\n// @param {Object} config Conversion configuration.\n// @param {module:engine/view/matcher~MatcherPattern} config.view Pattern matching all view elements which should be converted.\n// @param {String|Object} config.model Model attribute key or an object with `key` and `value` properties, describing\n// the model attribute. `value` property may be set as a function that takes a view element and returns the value.\n// If `String` is given, the model attribute value will be set to `true`.\n// @param {module:utils/priorities~PriorityString} [config.converterPriority='low'] Converter priority.\n// @returns {Function} Conversion helper.\nfunction upcastElementToAttribute( config ) {\n\tconfig = cloneDeep( config );\n\n\tnormalizeModelAttributeConfig( config );\n\n\tconst converter = prepareToAttributeConverter( config, false );\n\n\tconst elementName = getViewElementNameFromConfig( config.view );\n\tconst eventName = elementName ? 'element:' + elementName : 'element';\n\n\treturn dispatcher => {\n\t\tdispatcher.on( eventName, converter, { priority: config.converterPriority || 'low' } );\n\t};\n}\n\n// View attribute to model attribute conversion helper.\n//\n// See {@link ~UpcastHelpers#attributeToAttribute `.attributeToAttribute()` upcast helper} for examples.\n//\n// @param {Object} config Conversion configuration.\n// @param {String|Object} config.view Specifies which view attribute will be converted. If a `String` is passed,\n// attributes with given key will be converted. If an `Object` is passed, it must have a required `key` property,\n// specifying view attribute key, and may have an optional `value` property, specifying view attribute value and optional `name`\n// property specifying a view element name from/on which the attribute should be converted. `value` can be given as a `String`,\n// a `RegExp` or a function callback, that takes view attribute value as the only parameter and returns `Boolean`.\n// @param {String|Object} config.model Model attribute key or an object with `key` and `value` properties, describing\n// the model attribute. `value` property may be set as a function that takes a view element and returns the value.\n// If `String` is given, the model attribute value will be same as view attribute value.\n// @param {module:utils/priorities~PriorityString} [config.converterPriority='low'] Converter priority.\n// @returns {Function} Conversion helper.\nfunction upcastAttributeToAttribute( config ) {\n\tconfig = cloneDeep( config );\n\n\tlet viewKey = null;\n\n\tif ( typeof config.view == 'string' || config.view.key ) {\n\t\tviewKey = normalizeViewAttributeKeyValueConfig( config );\n\t}\n\n\tnormalizeModelAttributeConfig( config, viewKey );\n\n\tconst converter = prepareToAttributeConverter( config, true );\n\n\treturn dispatcher => {\n\t\tdispatcher.on( 'element', converter, { priority: config.converterPriority || 'low' } );\n\t};\n}\n\n// View element to model marker conversion helper.\n//\n// See {@link ~UpcastHelpers#elementToMarker `.elementToMarker()` upcast helper} for examples.\n//\n// @param {Object} config Conversion configuration.\n// @param {module:engine/view/matcher~MatcherPattern} config.view Pattern matching all view elements which should be converted.\n// @param {String|Function} config.model Name of the model marker, or a function that takes a view element and returns\n// a model marker name.\n// @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.\n// @returns {Function} Conversion helper.\nfunction upcastElementToMarker( config ) {\n\tconfig = cloneDeep( config );\n\n\tnormalizeElementToMarkerConfig( config );\n\n\treturn upcastElementToElement( config );\n}\n\n// View data to model marker conversion helper.\n//\n// See {@link ~UpcastHelpers#dataToMarker} to learn more.\n//\n// @param {Object} config\n// @param {String} config.view\n// @param {Function} [config.model]\n// @param {module:utils/priorities~PriorityString} [config.converterPriority='normal']\n// @returns {Function} Conversion helper.\nfunction upcastDataToMarker( config ) {\n\tconfig = cloneDeep( config );\n\n\t// Default conversion.\n\tif ( !config.model ) {\n\t\tconfig.model = name => {\n\t\t\treturn name ? config.view + ':' + name : config.view;\n\t\t};\n\t}\n\n\tconst converterStart = prepareToElementConverter( normalizeDataToMarkerConfig( config, 'start' ) );\n\tconst converterEnd = prepareToElementConverter( normalizeDataToMarkerConfig( config, 'end' ) );\n\n\treturn dispatcher => {\n\t\tdispatcher.on( 'element:' + config.view + '-start', converterStart, { priority: config.converterPriority || 'normal' } );\n\t\tdispatcher.on( 'element:' + config.view + '-end', converterEnd, { priority: config.converterPriority || 'normal' } );\n\n\t\t// Below is a hack that is needed to properly handle `converterPriority` for both elements and attributes.\n\t\t// Attribute conversion needs to be performed *after* element conversion.\n\t\t// This converter handles both element conversion and attribute conversion, which means that if a single\n\t\t// `config.converterPriority` is used, it will lead to problems. For example, if the `'high'` priority is used,\n\t\t// the attribute conversion will be performed before a lot of element upcast converters.\n\t\t// On the other hand, we want to support `config.converterPriority` and converter overwriting.\n\t\t//\n\t\t// To make it work, we need to do some extra processing for priority for attribute converter.\n\t\t// Priority `'low'` value should be the base value and then we will change it depending on `config.converterPriority` value.\n\t\t//\n\t\t// This hack probably would not be needed if attributes are upcasted separately.\n\t\t//\n\t\tconst basePriority = priorities.get( 'low' );\n\t\tconst maxPriority = priorities.get( 'highest' );\n\t\tconst priorityFactor = priorities.get( config.converterPriority ) / maxPriority; // Number in range [ -1, 1 ].\n\n\t\tdispatcher.on( 'element', upcastAttributeToMarker( config ), { priority: basePriority + priorityFactor } );\n\t};\n}\n\n// Function factory, returns a callback function which converts view attributes to a model marker.\n//\n// The converter looks for elements with `data-group-start-before`, `data-group-start-after`, `data-group-end-before`\n// and `data-group-end-after` attributes and inserts `$marker` model elements before/after those elements.\n// `group` part is specified in `config.view`.\n//\n// @param {Object} config\n// @param {String} config.view\n// @param {Function} [config.model]\n// @returns {Function} Marker converter.\nfunction upcastAttributeToMarker( config ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\tconst attrName = `data-${ config.view }`;\n\n\t\t// Check if any attribute for the given view item can be consumed before changing the conversion data\n\t\t// and consuming view items with these attributes.\n\t\tif (\n\t\t\t!conversionApi.consumable.test( data.viewItem, { attributes: attrName + '-end-after' } ) &&\n\t\t\t!conversionApi.consumable.test( data.viewItem, { attributes: attrName + '-start-after' } ) &&\n\t\t\t!conversionApi.consumable.test( data.viewItem, { attributes: attrName + '-end-before' } ) &&\n\t\t\t!conversionApi.consumable.test( data.viewItem, { attributes: attrName + '-start-before' } )\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\t// This converter wants to add a model element, marking a marker, before/after an element (or maybe even group of elements).\n\t\t// To do that, we can use `data.modelRange` which is set on an element (or a group of elements) that has been upcasted.\n\t\t// But, if the processed view element has not been upcasted yet (it does not have been converted), we need to\n\t\t// fire conversion for its children first, then we will have `data.modelRange` available.\n\t\tif ( !data.modelRange ) {\n\t\t\tObject.assign( data, conversionApi.convertChildren( data.viewItem, data.modelCursor ) );\n\t\t}\n\n\t\tif ( conversionApi.consumable.consume( data.viewItem, { attributes: attrName + '-end-after' } ) ) {\n\t\t\taddMarkerElements( data.modelRange.end, data.viewItem.getAttribute( attrName + '-end-after' ).split( ',' ) );\n\t\t}\n\n\t\tif ( conversionApi.consumable.consume( data.viewItem, { attributes: attrName + '-start-after' } ) ) {\n\t\t\taddMarkerElements( data.modelRange.end, data.viewItem.getAttribute( attrName + '-start-after' ).split( ',' ) );\n\t\t}\n\n\t\tif ( conversionApi.consumable.consume( data.viewItem, { attributes: attrName + '-end-before' } ) ) {\n\t\t\taddMarkerElements( data.modelRange.start, data.viewItem.getAttribute( attrName + '-end-before' ).split( ',' ) );\n\t\t}\n\n\t\tif ( conversionApi.consumable.consume( data.viewItem, { attributes: attrName + '-start-before' } ) ) {\n\t\t\taddMarkerElements( data.modelRange.start, data.viewItem.getAttribute( attrName + '-start-before' ).split( ',' ) );\n\t\t}\n\n\t\tfunction addMarkerElements( position, markerViewNames ) {\n\t\t\tfor ( const markerViewName of markerViewNames ) {\n\t\t\t\tconst markerName = config.model( markerViewName, conversionApi );\n\t\t\t\tconst element = conversionApi.writer.createElement( '$marker', { 'data-name': markerName } );\n\n\t\t\t\tconversionApi.writer.insert( element, position );\n\n\t\t\t\tif ( data.modelCursor.isEqual( position ) ) {\n\t\t\t\t\tdata.modelCursor = data.modelCursor.getShiftedBy( 1 );\n\t\t\t\t} else {\n\t\t\t\t\tdata.modelCursor = data.modelCursor._getTransformedByInsertion( position, 1 );\n\t\t\t\t}\n\n\t\t\t\tdata.modelRange = data.modelRange._getTransformedByInsertion( position, 1 )[ 0 ];\n\t\t\t}\n\t\t}\n\t};\n}\n\n// Helper function for from-view-element conversion. Checks if `config.view` directly specifies converted view element's name\n// and if so, returns it.\n//\n// @param {Object} config Conversion view config.\n// @returns {String|null} View element name or `null` if name is not directly set.\nfunction getViewElementNameFromConfig( viewConfig ) {\n\tif ( typeof viewConfig == 'string' ) {\n\t\treturn viewConfig;\n\t}\n\n\tif ( typeof viewConfig == 'object' && typeof viewConfig.name == 'string' ) {\n\t\treturn viewConfig.name;\n\t}\n\n\treturn null;\n}\n\n// Helper for to-model-element conversion. Takes a config object and returns a proper converter function.\n//\n// @param {Object} config Conversion configuration.\n// @returns {Function} View to model converter.\nfunction prepareToElementConverter( config ) {\n\tconst matcher = new Matcher( config.view );\n\n\treturn ( evt, data, conversionApi ) => {\n\t\tconst matcherResult = matcher.match( data.viewItem );\n\n\t\tif ( !matcherResult ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst match = matcherResult.match;\n\n\t\t// Force consuming element's name.\n\t\tmatch.name = true;\n\n\t\tif ( !conversionApi.consumable.test( data.viewItem, match ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst modelElement = getModelElement( config.model, data.viewItem, conversionApi );\n\n\t\tif ( !modelElement ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !conversionApi.safeInsert( modelElement, data.modelCursor ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconversionApi.consumable.consume( data.viewItem, match );\n\t\tconversionApi.convertChildren( data.viewItem, modelElement );\n\t\tconversionApi.updateConversionResult( modelElement, data );\n\t};\n}\n\n// Helper function for upcasting-to-element converter. Takes the model configuration, the converted view element\n// and a writer instance and returns a model element instance to be inserted in the model.\n//\n// @param {String|Function|module:engine/model/element~Element} model Model conversion configuration.\n// @param {module:engine/view/node~Node} input The converted view node.\n// @param {module:engine/conversion/upcastdispatcher~UpcastConversionApi} conversionApi The upcast conversion API.\nfunction getModelElement( model, input, conversionApi ) {\n\tif ( model instanceof Function ) {\n\t\treturn model( input, conversionApi );\n\t} else {\n\t\treturn conversionApi.writer.createElement( model );\n\t}\n}\n\n// Helper function view-attribute-to-model-attribute helper. Normalizes `config.view` which was set as `String` or\n// as an `Object` with `key`, `value` and `name` properties. Normalized `config.view` has is compatible with\n// {@link module:engine/view/matcher~MatcherPattern}.\n//\n// @param {Object} config Conversion config.\n// @returns {String} Key of the converted view attribute.\nfunction normalizeViewAttributeKeyValueConfig( config ) {\n\tif ( typeof config.view == 'string' ) {\n\t\tconfig.view = { key: config.view };\n\t}\n\n\tconst key = config.view.key;\n\tlet normalized;\n\n\tif ( key == 'class' || key == 'style' ) {\n\t\tconst keyName = key == 'class' ? 'classes' : 'styles';\n\n\t\tnormalized = {\n\t\t\t[ keyName ]: config.view.value\n\t\t};\n\t} else {\n\t\tconst value = typeof config.view.value == 'undefined' ? /[\\s\\S]*/ : config.view.value;\n\n\t\tnormalized = {\n\t\t\tattributes: {\n\t\t\t\t[ key ]: value\n\t\t\t}\n\t\t};\n\t}\n\n\tif ( config.view.name ) {\n\t\tnormalized.name = config.view.name;\n\t}\n\n\tconfig.view = normalized;\n\n\treturn key;\n}\n\n// Helper function that normalizes `config.model` in from-model-attribute conversion. `config.model` can be set\n// as a `String`, an `Object` with only `key` property or an `Object` with `key` and `value` properties. Normalized\n// `config.model` is an `Object` with `key` and `value` properties.\n//\n// @param {Object} config Conversion config.\n// @param {String} viewAttributeKeyToCopy Key of the converted view attribute. If it is set, model attribute value\n// will be equal to view attribute value.\nfunction normalizeModelAttributeConfig( config, viewAttributeKeyToCopy = null ) {\n\tconst defaultModelValue = viewAttributeKeyToCopy === null ? true : viewElement => viewElement.getAttribute( viewAttributeKeyToCopy );\n\n\tconst key = typeof config.model != 'object' ? config.model : config.model.key;\n\tconst value = typeof config.model != 'object' || typeof config.model.value == 'undefined' ? defaultModelValue : config.model.value;\n\n\tconfig.model = { key, value };\n}\n\n// Helper for to-model-attribute conversion. Takes the model attribute name and conversion configuration and returns\n// a proper converter function.\n//\n// @param {String} modelAttributeKey The key of the model attribute to set on a model node.\n// @param {Object|Array.} config Conversion configuration. It is possible to provide multiple configurations in an array.\n// @param {Boolean} shallow If set to `true` the attribute will be set only on top-level nodes. Otherwise, it will be set\n// on all elements in the range.\nfunction prepareToAttributeConverter( config, shallow ) {\n\tconst matcher = new Matcher( config.view );\n\n\treturn ( evt, data, conversionApi ) => {\n\t\tconst match = matcher.match( data.viewItem );\n\n\t\t// If there is no match, this callback should not do anything.\n\t\tif ( !match ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( onlyViewNameIsDefined( config.view, data.viewItem ) ) {\n\t\t\tmatch.match.name = true;\n\t\t} else {\n\t\t\t// Do not test or consume `name` consumable.\n\t\t\tdelete match.match.name;\n\t\t}\n\n\t\t// Try to consume appropriate values from consumable values list.\n\t\tif ( !conversionApi.consumable.test( data.viewItem, match.match ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst modelKey = config.model.key;\n\t\tconst modelValue = typeof config.model.value == 'function' ?\n\t\t\tconfig.model.value( data.viewItem, conversionApi ) : config.model.value;\n\n\t\t// Do not convert if attribute building function returned falsy value.\n\t\tif ( modelValue === null ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Since we are converting to attribute we need a range on which we will set the attribute.\n\t\t// If the range is not created yet, let's create it by converting children of the current node first.\n\t\tif ( !data.modelRange ) {\n\t\t\t// Convert children and set conversion result as a current data.\n\t\t\tObject.assign( data, conversionApi.convertChildren( data.viewItem, data.modelCursor ) );\n\t\t}\n\n\t\t// Set attribute on current `output`. `Schema` is checked inside this helper function.\n\t\tconst attributeWasSet = setAttributeOn( data.modelRange, { key: modelKey, value: modelValue }, shallow, conversionApi );\n\n\t\t// It may happen that a converter will try to set an attribute that is not allowed in the given context.\n\t\t// In such a situation we cannot consume the attribute. See: https://github.com/ckeditor/ckeditor5/pull/9249#issuecomment-815658459.\n\t\tif ( attributeWasSet ) {\n\t\t\tconversionApi.consumable.consume( data.viewItem, match.match );\n\t\t}\n\t};\n}\n\n// Helper function that checks if element name should be consumed in attribute converters.\n//\n// @param {Object} config Conversion view config.\n// @returns {Boolean}\nfunction onlyViewNameIsDefined( viewConfig, viewItem ) {\n\t// https://github.com/ckeditor/ckeditor5-engine/issues/1786\n\tconst configToTest = typeof viewConfig == 'function' ? viewConfig( viewItem ) : viewConfig;\n\n\tif ( typeof configToTest == 'object' && !getViewElementNameFromConfig( configToTest ) ) {\n\t\treturn false;\n\t}\n\n\treturn !configToTest.classes && !configToTest.attributes && !configToTest.styles;\n}\n\n// Helper function for to-model-attribute converter. Sets model attribute on given range. Checks {@link module:engine/model/schema~Schema}\n// to ensure proper model structure.\n//\n// If any node on the given range has already defined an attribute with the same name, its value will not be updated.\n//\n// @param {module:engine/model/range~Range} modelRange Model range on which attribute should be set.\n// @param {Object} modelAttribute Model attribute to set.\n// @param {module:engine/conversion/upcastdispatcher~UpcastConversionApi} conversionApi Conversion API.\n// @param {Boolean} shallow If set to `true` the attribute will be set only on top-level nodes. Otherwise, it will be set\n// on all elements in the range.\n// @returns {Boolean} `true` if attribute was set on at least one node from given `modelRange`.\nfunction setAttributeOn( modelRange, modelAttribute, shallow, conversionApi ) {\n\tlet result = false;\n\n\t// Set attribute on each item in range according to Schema.\n\tfor ( const node of Array.from( modelRange.getItems( { shallow } ) ) ) {\n\t\t// Skip if not allowed.\n\t\tif ( !conversionApi.schema.checkAttribute( node, modelAttribute.key ) ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Mark the node as consumed even if the attribute will not be updated because it's in a valid context (schema)\n\t\t// and would be converted if the attribute wouldn't be present. See #8921.\n\t\tresult = true;\n\n\t\t// Do not override the attribute if it's already present.\n\t\tif ( node.hasAttribute( modelAttribute.key ) ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconversionApi.writer.setAttribute( modelAttribute.key, modelAttribute.value, node );\n\t}\n\n\treturn result;\n}\n\n// Helper function for upcasting-to-marker conversion. Takes the config in a format requested by `upcastElementToMarker()`\n// function and converts it to a format that is supported by `upcastElementToElement()` function.\n//\n// @param {Object} config Conversion configuration.\nfunction normalizeElementToMarkerConfig( config ) {\n\tconst oldModel = config.model;\n\n\tconfig.model = ( viewElement, conversionApi ) => {\n\t\tconst markerName = typeof oldModel == 'string' ? oldModel : oldModel( viewElement, conversionApi );\n\n\t\treturn conversionApi.writer.createElement( '$marker', { 'data-name': markerName } );\n\t};\n}\n\n// Helper function for upcasting-to-marker conversion. Takes the config in a format requested by `upcastDataToMarker()`\n// function and converts it to a format that is supported by `upcastElementToElement()` function.\n//\n// @param {Object} config Conversion configuration.\nfunction normalizeDataToMarkerConfig( config, type ) {\n\tconst configForElements = {};\n\n\t// Upcast and elements.\n\tconfigForElements.view = config.view + '-' + type;\n\n\tconfigForElements.model = ( viewElement, conversionApi ) => {\n\t\tconst viewName = viewElement.getAttribute( 'name' );\n\t\tconst markerName = config.model( viewName, conversionApi );\n\n\t\treturn conversionApi.writer.createElement( '$marker', { 'data-name': markerName } );\n\t};\n\n\treturn configForElements;\n}\n"],"sourceRoot":""}