{"version":3,"sources":["webpack:///./node_modules/@ckeditor/ckeditor5-engine/src/view/editableelement.js","webpack:///./node_modules/@ckeditor/ckeditor5-engine/src/view/attributeelement.js","webpack:///./node_modules/@ckeditor/ckeditor5-engine/src/view/documentselection.js","webpack:///./node_modules/@ckeditor/ckeditor5-engine/src/view/containerelement.js","webpack:///./node_modules/@ckeditor/ckeditor5-engine/src/view/downcastwriter.js","webpack:///./node_modules/@ckeditor/ckeditor5-engine/src/view/domconverter.js","webpack:///./node_modules/@ckeditor/ckeditor5-engine/src/view/document.js","webpack:///./node_modules/@ckeditor/ckeditor5-engine/src/view/documentfragment.js"],"names":["EditableElement","document","name","attrs","children","set","bind","to","isFocused","selection","editableElement","listenTo","type","this","stopListening","ContainerElement","mix","ObservableMixin","DEFAULT_PRIORITY","AttributeElement","getFillerOffset","_priority","_id","_clonesGroup","id","CKEditorError","Set","otherElement","priority","deep","cloned","Element","nonUiChildrenCount","element","parent","is","childCount","Array","from","getChildren","filter","length","DocumentSelection","selectable","placeOrOffset","options","_selection","Selection","delegate","setTo","getRanges","getFirstRange","getLastRange","getFirstPosition","getLastPosition","getSelectedElement","otherSelection","isEqual","isSimilar","itemOrPosition","offset","setFocus","isFake","fakeSelectionLabel","anchor","focus","isCollapsed","rangeCount","isBackward","_ranges","EmitterMixin","lastChild","child","DowncastWriter","_cloneGroups","Map","_setTo","_setFocus","DocumentFragment","data","Text","attributes","attributeElement","containerElement","undefined","isAllowedInsideAttributeElement","_isAllowedInsideAttributeElement","_document","emptyElement","EmptyElement","renderFunction","uiElement","UIElement","render","rawElement","RawElement","key","value","_setAttribute","_removeAttribute","className","_addClass","_removeClass","property","isPlainObject","_setStyle","_removeStyle","_setCustomProperty","_removeCustomProperty","positionOrRange","Position","_breakAttributes","_breakAttributesRange","position","isAtStart","_createBefore","isAtEnd","newElement","_clone","insert","_createAfter","sourceRange","Range","_createAt","targetPosition","move","positionOffset","positionParent","index","_remove","_removeFromClonedElementsGroup","mergeAttributes","nodeBefore","getChild","nodeAfter","mergeTextNodes","count","_appendChild","prev","next","newPosition","_createIn","remove","_createOn","nodes","isIterable","validateNodesToInsert","nodeGroups","reduce","groups","node","lastGroup","breakAttributes","push","start","end","range","_insertNodes","rangeOrItem","validateRangeContainer","breakStart","breakEnd","parentContainer","removed","_removeChildren","mergePosition","clone","walker","getWalker","direction","ignoreElementEnd","current","item","rangeToRemove","nextPosition","isAfter","parentElement","getAncestors","find","ancestor","isBefore","countBefore","attribute","_hasNonUiChildren","getLastMatchingPosition","_wrapPosition","viewSelection","setSelection","_wrapRange","newRange","_unwrapChildren","newName","viewElement","getAttributes","groupName","delete","insertionPosition","getParentContainer","breakTextNode","_insertChild","_addToClonedElementsGroup","endPosition","getShiftedBy","startOffset","endOffset","wrapElement","i","wrapPositions","isText","isAttribute","_wrapAttributeElement","shouldABeOutsideB","newAttribute","_wrapChildren","offsetChange","_createFromParentsAndOffsets","unwrapElement","unwrapPositions","unwrapped","_unwrapAttributeElement","movePositionToTextNode","fakePosition","createAttributeElement","Number","POSITIVE_INFINITY","wrapRange","wrap","wrapper","toWrap","canBeJoined","getAttributeKeys","hasAttribute","getAttribute","getStyleNames","hasStyle","getStyle","setAttribute","setStyle","getClassNames","hasClass","addClass","toUnwrap","removeAttribute","removeClass","removeStyle","forceSplitText","rangeStart","rangeEnd","isContainerOrFragment","offsetAfter","clonedNode","nodesToMove","root","group","get","add","some","a","b","getIdentity","textToMove","slice","_data","t1","t2","nodeBeforeLength","errorContext","validNodesToInsert","validNode","startContainer","endContainer","BR_FILLER_REF","BR_FILLER","DomConverter","blockFillerMode","preElements","blockElements","_blockFiller","NBSP_FILLER","_domToViewMapping","WeakMap","_viewToDomMapping","_fakeSelectionMapping","_rawContentElementMatcher","Matcher","_encounteredRawContentDomNodes","WeakSet","domElement","viewDocumentSelection","ViewSelection","childNodes","unbindDomElement","domFragment","viewFragment","viewNode","domDocument","textData","_processDataFromViewText","createTextNode","mapViewToDom","createDocumentFragment","bindDocumentFragments","bindElements","createElementNS","createElement","withChildren","viewChildrenToDom","appendChild","fillerPositionOffset","childView","viewToDom","viewRange","domStart","viewPositionToDom","domEnd","domRange","createRange","setStart","setEnd","viewPosition","domParent","domBefore","domAfter","viewParent","findCorrespondingDomText","startsWithFiller","INLINE_FILLER_LENGTH","parentNode","nextSibling","indexOf","domNode","isBlockFiller","hostElement","getHostViewElement","isInlineFiller","_processDataFromDomText","ViewText","isComment","mapDomToView","isDocumentFragment","ViewDocumentFragment","viewName","keepOriginalCase","tagName","toLowerCase","ViewElement","match","innerHTML","domChildrenToView","domChild","viewChild","domToView","domSelection","container","getRangeAt","fakeSelectionToView","isDomSelectionBackward","viewRanges","domRangeToView","backward","viewStart","domPositionToView","viewEnd","ViewRange","domOffset","ViewPosition","findCorrespondingViewText","viewBefore","domElementOrDocumentFragment","domText","previousSibling","isElement","firstChild","documentFragmentOrElement","viewText","viewEditable","domEditable","ownerDocument","activeElement","global","window","scrollX","scrollY","scrollPositions","forEachDomNodeAncestor","scrollLeft","scrollTop","shift","scrollTo","nodeType","Node","ELEMENT_NODE","DOCUMENT_FRAGMENT_NODE","COMMENT_NODE","isEqualNode","hasBlockParent","isNbspBlockFiller","anchorNode","anchorOffset","focusNode","focusOffset","collapsed","detach","ancestors","pop","_isDomSelectionPositionCorrect","pattern","includes","charAt","prevNode","_getTouchingViewTextNode","prevEndsWithSpace","_nodeEndsWithSpace","substr","nextNode","replace","_hasDomParentOfType","getDataWithoutFiller","_getTouchingInlineDomNode","shouldLeftTrim","_checkShouldLeftTrimDomText","shouldRightTrim","_checkShouldRightTrimDomText","test","has","getNext","treeWalker","ViewTreeWalker","startPosition","topmostParent","createTreeWalker","NodeFilter","SHOW_TEXT","SHOW_ELEMENT","acceptNode","FILTER_ACCEPT","FILTER_SKIP","currentNode","touchingNode","lca","getCommonAncestor","types","boundaryParent","parents","callback","isNBSP","Document","stylesProcessor","roots","Collection","idProperty","_postFixers","postFixer","map","destroy","writer","wasFixed","_children","Symbol","iterator","items","_fireChange","normalize","splice","howMany","fire","TextProxy"],"mappings":"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","file":"js/chunk-vendors~e32493f1.2709c871.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/view/editableelement\n */\n\nimport ContainerElement from './containerelement';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\n\n/**\n * Editable element which can be a {@link module:engine/view/rooteditableelement~RootEditableElement root}\n * or nested editable area in the editor.\n *\n * Editable is automatically read-only when its {@link module:engine/view/document~Document Document} is read-only.\n *\n * The constructor of this class shouldn't be used directly. To create new `EditableElement` use the\n * {@link module:engine/view/downcastwriter~DowncastWriter#createEditableElement `downcastWriter#createEditableElement()`} method.\n *\n * @extends module:engine/view/containerelement~ContainerElement\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class EditableElement extends ContainerElement {\n\t/**\n\t * Creates an editable element.\n\t *\n\t * @see module:engine/view/downcastwriter~DowncastWriter#createEditableElement\n\t * @protected\n\t */\n\tconstructor( document, name, attrs, children ) {\n\t\tsuper( document, name, attrs, children );\n\n\t\t/**\n\t\t * Whether the editable is in read-write or read-only mode.\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} module:engine/view/editableelement~EditableElement#isReadOnly\n\t\t */\n\t\tthis.set( 'isReadOnly', false );\n\n\t\t/**\n\t\t * Whether the editable is focused.\n\t\t *\n\t\t * This property updates when {@link module:engine/view/document~Document#isFocused document.isFocused} or view\n\t\t * selection is changed.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Boolean} module:engine/view/editableelement~EditableElement#isFocused\n\t\t */\n\t\tthis.set( 'isFocused', false );\n\n\t\tthis.bind( 'isReadOnly' ).to( document );\n\n\t\tthis.bind( 'isFocused' ).to(\n\t\t\tdocument,\n\t\t\t'isFocused',\n\t\t\tisFocused => isFocused && document.selection.editableElement == this\n\t\t);\n\n\t\t// Update focus state based on selection changes.\n\t\tthis.listenTo( document.selection, 'change', () => {\n\t\t\tthis.isFocused = document.isFocused && document.selection.editableElement == this;\n\t\t} );\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\teditableElement.is( 'editableElement' ); // -> true\n\t *\t\teditableElement.is( 'element' ); // -> true\n\t *\t\teditableElement.is( 'node' ); // -> true\n\t *\t\teditableElement.is( 'view:editableElement' ); // -> true\n\t *\t\teditableElement.is( 'view:element' ); // -> true\n\t *\t\teditableElement.is( 'view:node' ); // -> true\n\t *\n\t *\t\teditableElement.is( 'model:element' ); // -> false\n\t *\t\teditableElement.is( 'documentFragment' ); // -> false\n\t *\n\t * Assuming that the object being checked is an editbale element, you can also check its\n\t * {@link module:engine/view/editableelement~EditableElement#name name}:\n\t *\n\t *\t\teditableElement.is( 'element', 'div' ); // -> true if this is a div element\n\t *\t\teditableElement.is( 'editableElement', 'div' ); // -> same as above\n\t *\t\ttext.is( 'element', 'div' ); -> false\n\t *\n\t * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.\n\t *\n\t * @param {String} type Type to check.\n\t * @param {String} [name] Element name.\n\t * @returns {Boolean}\n\t */\n\tis( type, name = null ) {\n\t\tif ( !name ) {\n\t\t\treturn type === 'editableElement' || type === 'view:editableElement' ||\n\t\t\t\t// From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.\n\t\t\t\ttype === 'containerElement' || type === 'view:containerElement' ||\n\t\t\t\ttype === 'element' || type === 'view:element' ||\n\t\t\t\ttype === 'node' || type === 'view:node';\n\t\t} else {\n\t\t\treturn name === this.name && (\n\t\t\t\ttype === 'editableElement' || type === 'view:editableElement' ||\n\t\t\t\t// From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.\n\t\t\t\ttype === 'containerElement' || type === 'view:containerElement' ||\n\t\t\t\ttype === 'element' || type === 'view:element'\n\t\t\t);\n\t\t}\n\t}\n\n\tdestroy() {\n\t\tthis.stopListening();\n\t}\n}\n\nmix( EditableElement, 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/view/attributeelement\n */\n\nimport Element from './element';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n// Default attribute priority.\nconst DEFAULT_PRIORITY = 10;\n\n/**\n * Attribute elements are used to represent formatting elements in the view (think – ``, ``, etc.).\n * Most often they are created when downcasting model text attributes.\n *\n * Editing engine does not define a fixed HTML DTD. This is why a feature developer needs to choose between various\n * types (container element, {@link module:engine/view/attributeelement~AttributeElement attribute element},\n * {@link module:engine/view/emptyelement~EmptyElement empty element}, etc) when developing a feature.\n *\n * To create a new attribute element instance use the\n * {@link module:engine/view/downcastwriter~DowncastWriter#createAttributeElement `DowncastWriter#createAttributeElement()`} method.\n *\n * **Note:** Attribute elements by default can wrap {@link module:engine/view/text~Text},\n * {@link module:engine/view/emptyelement~EmptyElement}, {@link module:engine/view/uielement~UIElement},\n * {@link module:engine/view/rawelement~RawElement} and other attribute elements with higher priority. Other elements while placed inside\n * an attribute element will split it (or nest in case of an `AttributeElement`). This behavior can be modified by changing\n * the `isAllowedInsideAttributeElement` option while creating\n * {@link module:engine/view/downcastwriter~DowncastWriter#createContainerElement},\n * {@link module:engine/view/downcastwriter~DowncastWriter#createEmptyElement},\n * {@link module:engine/view/downcastwriter~DowncastWriter#createUIElement} or\n * {@link module:engine/view/downcastwriter~DowncastWriter#createRawElement}.\n *\n * @extends module:engine/view/element~Element\n */\nexport default class AttributeElement extends Element {\n\t/**\n\t * Creates an attribute element.\n\t *\n\t * @see module:engine/view/downcastwriter~DowncastWriter#createAttributeElement\n\t * @see module:engine/view/element~Element\n\t * @protected\n\t * @param {module:engine/view/document~Document} document The document instance to which this element belongs.\n\t * @param {String} name Node name.\n\t * @param {Object|Iterable} [attrs] Collection of attributes.\n\t * @param {module:engine/view/node~Node|Iterable.} [children]\n\t * A list of nodes to be inserted into created element.\n\t */\n\tconstructor( document, name, attrs, children ) {\n\t\tsuper( document, name, attrs, children );\n\n\t\t/**\n\t\t * Returns block {@link module:engine/view/filler filler} offset or `null` if block filler is not needed.\n\t\t *\n\t\t * @method #getFillerOffset\n\t\t * @returns {Number|null} Block filler offset or `null` if block filler is not needed.\n\t\t */\n\t\tthis.getFillerOffset = getFillerOffset;\n\n\t\t/**\n\t\t * Element priority. Decides in what order elements are wrapped by {@link module:engine/view/downcastwriter~DowncastWriter}.\n\t\t *\n\t\t * @protected\n\t\t * @member {Number}\n\t\t */\n\t\tthis._priority = DEFAULT_PRIORITY;\n\n\t\t/**\n\t\t * Element identifier. If set, it is used by {@link module:engine/view/element~Element#isSimilar},\n\t\t * and then two elements are considered similar if, and only if they have the same `_id`.\n\t\t *\n\t\t * @protected\n\t\t * @member {String|Number}\n\t\t */\n\t\tthis._id = null;\n\n\t\t/**\n\t\t * Keeps all the attribute elements that have the same {@link module:engine/view/attributeelement~AttributeElement#id ids}\n\t\t * and still exist in the view tree.\n\t\t *\n\t\t * This property is managed by {@link module:engine/view/downcastwriter~DowncastWriter}.\n\t\t *\n\t\t * @protected\n\t\t * @member {Set.|null}\n\t\t */\n\t\tthis._clonesGroup = null;\n\t}\n\n\t/**\n\t * Element priority. Decides in what order elements are wrapped by {@link module:engine/view/downcastwriter~DowncastWriter}.\n\t *\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget priority() {\n\t\treturn this._priority;\n\t}\n\n\t/**\n\t * Element identifier. If set, it is used by {@link module:engine/view/element~Element#isSimilar},\n\t * and then two elements are considered similar if, and only if they have the same `id`.\n\t *\n\t * @readonly\n\t * @type {String|Number}\n\t */\n\tget id() {\n\t\treturn this._id;\n\t}\n\n\t/**\n\t * Returns all {@link module:engine/view/attributeelement~AttributeElement attribute elements} that has the\n\t * same {@link module:engine/view/attributeelement~AttributeElement#id id} and are in the view tree (were not removed).\n\t *\n\t * Note: If this element has been removed from the tree, returned set will not include it.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError attribute-element-get-elements-with-same-id-no-id}\n\t * if this element has no `id`.\n\t *\n\t * @returns {Set.} Set containing all the attribute elements\n\t * with the same `id` that were added and not removed from the view tree.\n\t */\n\tgetElementsWithSameId() {\n\t\tif ( this.id === null ) {\n\t\t\t/**\n\t\t\t * Cannot get elements with the same id for an attribute element without id.\n\t\t\t *\n\t\t\t * @error attribute-element-get-elements-with-same-id-no-id\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'attribute-element-get-elements-with-same-id-no-id',\n\t\t\t\tthis\n\t\t\t);\n\t\t}\n\n\t\treturn new Set( this._clonesGroup );\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\tattributeElement.is( 'attributeElement' ); // -> true\n\t *\t\tattributeElement.is( 'element' ); // -> true\n\t *\t\tattributeElement.is( 'node' ); // -> true\n\t *\t\tattributeElement.is( 'view:attributeElement' ); // -> true\n\t *\t\tattributeElement.is( 'view:element' ); // -> true\n\t *\t\tattributeElement.is( 'view:node' ); // -> true\n\t *\n\t *\t\tattributeElement.is( 'model:element' ); // -> false\n\t *\t\tattributeElement.is( 'documentFragment' ); // -> false\n\t *\n\t * Assuming that the object being checked is an attribute element, you can also check its\n\t * {@link module:engine/view/attributeelement~AttributeElement#name name}:\n\t *\n\t *\t\tattributeElement.is( 'element', 'b' ); // -> true if this is a bold element\n\t *\t\tattributeElement.is( 'attributeElement', 'b' ); // -> same as above\n\t *\t\ttext.is( 'element', 'b' ); -> false\n\t *\n\t * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.\n\t *\n\t * @param {String} type Type to check.\n\t * @param {String} [name] Element name.\n\t * @returns {Boolean}\n\t */\n\tis( type, name = null ) {\n\t\tif ( !name ) {\n\t\t\treturn type === 'attributeElement' || type === 'view:attributeElement' ||\n\t\t\t\t// From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.\n\t\t\t\ttype === 'element' || type === 'view:element' ||\n\t\t\t\ttype === 'node' || type === 'view:node';\n\t\t} else {\n\t\t\treturn name === this.name && (\n\t\t\t\ttype === 'attributeElement' || type === 'view:attributeElement' ||\n\t\t\t\t// From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.\n\t\t\t\ttype === 'element' || type === 'view:element'\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Checks if this element is similar to other element.\n\t *\n\t * If none of elements has set {@link module:engine/view/attributeelement~AttributeElement#id}, then both elements\n\t * should have the same name, attributes and priority to be considered as similar. Two similar elements can contain\n\t * different set of children nodes.\n\t *\n\t * If at least one element has {@link module:engine/view/attributeelement~AttributeElement#id} set, then both\n\t * elements have to have the same {@link module:engine/view/attributeelement~AttributeElement#id} value to be\n\t * considered similar.\n\t *\n\t * Similarity is important for {@link module:engine/view/downcastwriter~DowncastWriter}. For example:\n\t *\n\t * * two following similar elements can be merged together into one, longer element,\n\t * * {@link module:engine/view/downcastwriter~DowncastWriter#unwrap} checks similarity of passed element and processed element to\n\t * decide whether processed element should be unwrapped,\n\t * * etc.\n\t *\n\t * @param {module:engine/view/element~Element} otherElement\n\t * @returns {Boolean}\n\t */\n\tisSimilar( otherElement ) {\n\t\t// If any element has an `id` set, just compare the ids.\n\t\tif ( this.id !== null || otherElement.id !== null ) {\n\t\t\treturn this.id === otherElement.id;\n\t\t}\n\n\t\treturn super.isSimilar( otherElement ) && this.priority == otherElement.priority;\n\t}\n\n\t/**\n\t * Clones provided element with priority.\n\t *\n\t * @protected\n\t * @param {Boolean} deep If set to `true` clones element and all its children recursively. When set to `false`,\n\t * element will be cloned without any children.\n\t * @returns {module:engine/view/attributeelement~AttributeElement} Clone of this element.\n\t */\n\t_clone( deep ) {\n\t\tconst cloned = super._clone( deep );\n\n\t\t// Clone priority too.\n\t\tcloned._priority = this._priority;\n\n\t\t// And id too.\n\t\tcloned._id = this._id;\n\n\t\treturn cloned;\n\t}\n}\n\n/**\n * Default attribute priority.\n *\n * @member {Number} module:engine/view/attributeelement~AttributeElement.DEFAULT_PRIORITY\n */\nAttributeElement.DEFAULT_PRIORITY = DEFAULT_PRIORITY;\n\n// Returns block {@link module:engine/view/filler~Filler filler} offset or `null` if block filler is not needed.\n//\n// @returns {Number|null} Block filler offset or `null` if block filler is not needed.\nfunction getFillerOffset() {\n\t// foo does not need filler.\n\tif ( nonUiChildrenCount( this ) ) {\n\t\treturn null;\n\t}\n\n\tlet element = this.parent;\n\n\t//

needs filler ->


\n\twhile ( element && element.is( 'attributeElement' ) ) {\n\t\tif ( nonUiChildrenCount( element ) > 1 ) {\n\t\t\treturn null;\n\t\t}\n\n\t\telement = element.parent;\n\t}\n\n\tif ( !element || nonUiChildrenCount( element ) > 1 ) {\n\t\treturn null;\n\t}\n\n\t// Render block filler at the end of element (after all ui elements).\n\treturn this.childCount;\n}\n\n// Returns total count of children that are not {@link module:engine/view/uielement~UIElement UIElements}.\n//\n// @param {module:engine/view/element~Element} element\n// @returns {Number}\nfunction nonUiChildrenCount( element ) {\n\treturn Array.from( element.getChildren() ).filter( element => !element.is( 'uiElement' ) ).length;\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/view/documentselection\n */\n\nimport Selection from './selection';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\n\n/**\n * Class representing the document selection in the view.\n *\n * Its instance is available in {@link module:engine/view/document~Document#selection `Document#selection`}.\n *\n * It is similar to {@link module:engine/view/selection~Selection} but\n * it has a read-only API and can be modified only by the writer available in\n * the {@link module:engine/view/view~View#change `View#change()`} block\n * (so via {@link module:engine/view/downcastwriter~DowncastWriter#setSelection `DowncastWriter#setSelection()`}).\n */\nexport default class DocumentSelection {\n\t/**\n\t * Creates new DocumentSelection instance.\n\t *\n\t * \t\t// Creates empty selection without ranges.\n\t *\t\tconst selection = new DocumentSelection();\n\t *\n\t *\t\t// Creates selection at the given range.\n\t *\t\tconst range = writer.createRange( start, end );\n\t *\t\tconst selection = new DocumentSelection( range );\n\t *\n\t *\t\t// Creates selection at the given ranges\n\t * \t\tconst ranges = [ writer.createRange( start1, end2 ), writer.createRange( start2, end2 ) ];\n\t *\t\tconst selection = new DocumentSelection( ranges );\n\t *\n\t *\t\t// Creates selection from the other selection.\n\t *\t\tconst otherSelection = writer.createSelection();\n\t *\t\tconst selection = new DocumentSelection( otherSelection );\n\t *\n\t * \t\t// Creates selection at the given position.\n\t *\t\tconst position = writer.createPositionAt( root, offset );\n\t *\t\tconst selection = new DocumentSelection( position );\n\t *\n\t *\t\t// Creates collapsed selection at the position of given item and offset.\n\t *\t\tconst paragraph = writer.createContainerElement( 'paragraph' );\n\t *\t\tconst selection = new DocumentSelection( paragraph, offset );\n\t *\n\t *\t\t// Creates a range inside an {@link module:engine/view/element~Element element} which starts before the\n\t *\t\t// first child of that element and ends after the last child of that element.\n\t *\t\tconst selection = new DocumentSelection( paragraph, 'in' );\n\t *\n\t *\t\t// Creates a range on an {@link module:engine/view/item~Item item} which starts before the item and ends\n\t *\t\t// just after the item.\n\t *\t\tconst selection = new DocumentSelection( paragraph, 'on' );\n\t *\n\t * `Selection`'s constructor allow passing additional options (`backward`, `fake` and `label`) as the last argument.\n\t *\n\t *\t\t// Creates backward selection.\n\t *\t\tconst selection = new DocumentSelection( range, { backward: true } );\n\t *\n\t * Fake selection does not render as browser native selection over selected elements and is hidden to the user.\n\t * This way, no native selection UI artifacts are displayed to the user and selection over elements can be\n\t * represented in other way, for example by applying proper CSS class.\n\t *\n\t * Additionally fake's selection label can be provided. It will be used to describe fake selection in DOM\n\t * (and be properly handled by screen readers).\n\t *\n\t *\t\t// Creates fake selection with label.\n\t *\t\tconst selection = new DocumentSelection( range, { fake: true, label: 'foo' } );\n\t *\n\t * @param {module:engine/view/selection~Selectable} [selectable=null]\n\t * @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] Offset or place when selectable is an `Item`.\n\t * @param {Object} [options]\n\t * @param {Boolean} [options.backward] Sets this selection instance to be backward.\n\t * @param {Boolean} [options.fake] Sets this selection instance to be marked as `fake`.\n\t * @param {String} [options.label] Label for the fake selection.\n\t */\n\tconstructor( selectable = null, placeOrOffset, options ) {\n\t\t/**\n\t\t * Selection is used internally (`DocumentSelection` is a proxy to that selection).\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/view/selection~Selection}\n\t\t */\n\t\tthis._selection = new Selection();\n\n\t\t// Delegate change event to be fired on DocumentSelection instance.\n\t\tthis._selection.delegate( 'change' ).to( this );\n\n\t\t// Set selection data.\n\t\tthis._selection.setTo( selectable, placeOrOffset, options );\n\t}\n\n\t/**\n\t * Returns true if selection instance is marked as `fake`.\n\t *\n\t * @see #_setTo\n\t * @returns {Boolean}\n\t */\n\tget isFake() {\n\t\treturn this._selection.isFake;\n\t}\n\n\t/**\n\t * Returns fake selection label.\n\t *\n\t * @see #_setTo\n\t * @returns {String}\n\t */\n\tget fakeSelectionLabel() {\n\t\treturn this._selection.fakeSelectionLabel;\n\t}\n\n\t/**\n\t * Selection anchor. Anchor may be described as a position where the selection starts. Together with\n\t * {@link #focus focus} they define the direction of selection, which is important\n\t * when expanding/shrinking selection. Anchor is always the start or end of the most recent added range.\n\t * It may be a bit unintuitive when there are multiple ranges in selection.\n\t *\n\t * @see #focus\n\t * @type {module:engine/view/position~Position}\n\t */\n\tget anchor() {\n\t\treturn this._selection.anchor;\n\t}\n\n\t/**\n\t * Selection focus. Focus is a position where the selection ends.\n\t *\n\t * @see #anchor\n\t * @type {module:engine/view/position~Position}\n\t */\n\tget focus() {\n\t\treturn this._selection.focus;\n\t}\n\n\t/**\n\t * Returns whether the selection is collapsed. Selection is collapsed when there is exactly one range which is\n\t * collapsed.\n\t *\n\t * @type {Boolean}\n\t */\n\tget isCollapsed() {\n\t\treturn this._selection.isCollapsed;\n\t}\n\n\t/**\n\t * Returns number of ranges in selection.\n\t *\n\t * @type {Number}\n\t */\n\tget rangeCount() {\n\t\treturn this._selection.rangeCount;\n\t}\n\n\t/**\n\t * Specifies whether the {@link #focus} precedes {@link #anchor}.\n\t *\n\t * @type {Boolean}\n\t */\n\tget isBackward() {\n\t\treturn this._selection.isBackward;\n\t}\n\n\t/**\n\t * {@link module:engine/view/editableelement~EditableElement EditableElement} instance that contains this selection, or `null`\n\t * if the selection is not inside an editable element.\n\t *\n\t * @type {module:engine/view/editableelement~EditableElement|null}\n\t */\n\tget editableElement() {\n\t\treturn this._selection.editableElement;\n\t}\n\n\t/**\n\t * Used for the compatibility with the {@link module:engine/view/selection~Selection#isEqual} method.\n\t *\n\t * @protected\n\t */\n\tget _ranges() {\n\t\treturn this._selection._ranges;\n\t}\n\n\t/**\n\t * Returns an iterable that contains copies of all ranges added to the selection.\n\t *\n\t * @returns {Iterable.}\n\t */\n\t* getRanges() {\n\t\tyield* this._selection.getRanges();\n\t}\n\n\t/**\n\t * Returns copy of the first range in the selection. First range is the one which\n\t * {@link module:engine/view/range~Range#start start} position {@link module:engine/view/position~Position#isBefore is before} start\n\t * position of all other ranges (not to confuse with the first range added to the selection).\n\t * Returns `null` if no ranges are added to selection.\n\t *\n\t * @returns {module:engine/view/range~Range|null}\n\t */\n\tgetFirstRange() {\n\t\treturn this._selection.getFirstRange();\n\t}\n\n\t/**\n\t * Returns copy of the last range in the selection. Last range is the one which {@link module:engine/view/range~Range#end end}\n\t * position {@link module:engine/view/position~Position#isAfter is after} end position of all other ranges (not to confuse\n\t * with the last range added to the selection). Returns `null` if no ranges are added to selection.\n\t *\n\t * @returns {module:engine/view/range~Range|null}\n\t */\n\tgetLastRange() {\n\t\treturn this._selection.getLastRange();\n\t}\n\n\t/**\n\t * Returns copy of the first position in the selection. First position is the position that\n\t * {@link module:engine/view/position~Position#isBefore is before} any other position in the selection ranges.\n\t * Returns `null` if no ranges are added to selection.\n\t *\n\t * @returns {module:engine/view/position~Position|null}\n\t */\n\tgetFirstPosition() {\n\t\treturn this._selection.getFirstPosition();\n\t}\n\n\t/**\n\t * Returns copy of the last position in the selection. Last position is the position that\n\t * {@link module:engine/view/position~Position#isAfter is after} any other position in the selection ranges.\n\t * Returns `null` if no ranges are added to selection.\n\t *\n\t * @returns {module:engine/view/position~Position|null}\n\t */\n\tgetLastPosition() {\n\t\treturn this._selection.getLastPosition();\n\t}\n\n\t/**\n\t * Returns the selected element. {@link module:engine/view/element~Element Element} is considered as selected if there is only\n\t * one range in the selection, and that range contains exactly one element.\n\t * Returns `null` if there is no selected element.\n\t *\n\t * @returns {module:engine/view/element~Element|null}\n\t */\n\tgetSelectedElement() {\n\t\treturn this._selection.getSelectedElement();\n\t}\n\n\t/**\n\t * Checks whether, this selection is equal to given selection. Selections are equal if they have same directions,\n\t * same number of ranges and all ranges from one selection equal to a range from other selection.\n\t *\n\t * @param {module:engine/view/selection~Selection|module:engine/view/documentselection~DocumentSelection} otherSelection\n\t * Selection to compare with.\n\t * @returns {Boolean} `true` if selections are equal, `false` otherwise.\n\t */\n\tisEqual( otherSelection ) {\n\t\treturn this._selection.isEqual( otherSelection );\n\t}\n\n\t/**\n\t * Checks whether this selection is similar to given selection. Selections are similar if they have same directions, same\n\t * number of ranges, and all {@link module:engine/view/range~Range#getTrimmed trimmed} ranges from one selection are\n\t * equal to any trimmed range from other selection.\n\t *\n\t * @param {module:engine/view/selection~Selection|module:engine/view/documentselection~DocumentSelection} otherSelection\n\t * Selection to compare with.\n\t * @returns {Boolean} `true` if selections are similar, `false` otherwise.\n\t */\n\tisSimilar( otherSelection ) {\n\t\treturn this._selection.isSimilar( otherSelection );\n\t}\n\n\t/**\n\t * Checks whether this object is of the given type.\n\t *\n\t *\t\tdocSelection.is( 'selection' ); // -> true\n\t *\t\tdocSelection.is( 'documentSelection' ); // -> true\n\t *\t\tdocSelection.is( 'view:selection' ); // -> true\n\t *\t\tdocSelection.is( 'view:documentSelection' ); // -> true\n\t *\n\t *\t\tdocSelection.is( 'model:documentSelection' ); // -> false\n\t *\t\tdocSelection.is( 'element' ); // -> false\n\t *\t\tdocSelection.is( 'node' ); // -> false\n\t *\n\t * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.\n\t *\n\t * @param {String} type\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type === 'selection' ||\n\t\t\ttype == 'documentSelection' ||\n\t\t\ttype == 'view:selection' ||\n\t\t\ttype == 'view:documentSelection';\n\t}\n\n\t/**\n\t * Sets this selection's ranges and direction to the specified location based on the given\n\t * {@link module:engine/view/selection~Selectable selectable}.\n\t *\n\t *\t\t// Sets selection to the given range.\n\t *\t\tconst range = writer.createRange( start, end );\n\t *\t\tdocumentSelection._setTo( range );\n\t *\n\t *\t\t// Sets selection to given ranges.\n\t * \t\tconst ranges = [ writer.createRange( start1, end2 ), writer.createRange( start2, end2 ) ];\n\t *\t\tdocumentSelection._setTo( range );\n\t *\n\t *\t\t// Sets selection to the other selection.\n\t *\t\tconst otherSelection = writer.createSelection();\n\t *\t\tdocumentSelection._setTo( otherSelection );\n\t *\n\t * \t\t// Sets collapsed selection at the given position.\n\t *\t\tconst position = writer.createPositionAt( root, offset );\n\t *\t\tdocumentSelection._setTo( position );\n\t *\n\t * \t\t// Sets collapsed selection at the position of given item and offset.\n\t *\t\tdocumentSelection._setTo( paragraph, offset );\n\t *\n\t * Creates a range inside an {@link module:engine/view/element~Element element} which starts before the first child of\n\t * that element and ends after the last child of that element.\n\t *\n\t *\t\tdocumentSelection._setTo( paragraph, 'in' );\n\t *\n\t * Creates a range on an {@link module:engine/view/item~Item item} which starts before the item and ends just after the item.\n\t *\n\t *\t\tdocumentSelection._setTo( paragraph, 'on' );\n\t *\n\t * \t\t// Clears selection. Removes all ranges.\n\t *\t\tdocumentSelection._setTo( null );\n\t *\n\t * `Selection#_setTo()` method allow passing additional options (`backward`, `fake` and `label`) as the last argument.\n\t *\n\t *\t\t// Sets selection as backward.\n\t *\t\tdocumentSelection._setTo( range, { backward: true } );\n\t *\n\t * Fake selection does not render as browser native selection over selected elements and is hidden to the user.\n\t * This way, no native selection UI artifacts are displayed to the user and selection over elements can be\n\t * represented in other way, for example by applying proper CSS class.\n\t *\n\t * Additionally fake's selection label can be provided. It will be used to des cribe fake selection in DOM\n\t * (and be properly handled by screen readers).\n\t *\n\t *\t\t// Creates fake selection with label.\n\t *\t\tdocumentSelection._setTo( range, { fake: true, label: 'foo' } );\n\t *\n\t * @protected\n\t * @fires change\n\t * @param {module:engine/view/selection~Selectable} selectable\n\t * @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] Sets place or offset of the selection.\n\t * @param {Object} [options]\n\t * @param {Boolean} [options.backward] Sets this selection instance to be backward.\n\t * @param {Boolean} [options.fake] Sets this selection instance to be marked as `fake`.\n\t * @param {String} [options.label] Label for the fake selection.\n\t */\n\t_setTo( selectable, placeOrOffset, options ) {\n\t\tthis._selection.setTo( selectable, placeOrOffset, options );\n\t}\n\n\t/**\n\t * Moves {@link #focus} to the specified location.\n\t *\n\t * The location can be specified in the same form as {@link module:engine/view/view~View#createPositionAt view.createPositionAt()}\n\t * parameters.\n\t *\n\t * @protected\n\t * @fires change\n\t * @param {module:engine/view/item~Item|module:engine/view/position~Position} itemOrPosition\n\t * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when\n\t * first parameter is a {@link module:engine/view/item~Item view item}.\n\t */\n\t_setFocus( itemOrPosition, offset ) {\n\t\tthis._selection.setFocus( itemOrPosition, offset );\n\t}\n\n\t/**\n\t * Fired whenever selection ranges are changed through {@link ~DocumentSelection Selection API}.\n\t *\n\t * @event change\n\t */\n}\n\nmix( DocumentSelection, EmitterMixin );\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/view/containerelement\n */\n\nimport Element from './element';\n\n/**\n * Containers are elements which define document structure. They define boundaries for\n * {@link module:engine/view/attributeelement~AttributeElement attributes}. They are mostly used for block elements like `

` or `

`.\n *\n * Editing engine does not define a fixed HTML DTD. This is why a feature developer needs to choose between various\n * types (container element, {@link module:engine/view/attributeelement~AttributeElement attribute element},\n * {@link module:engine/view/emptyelement~EmptyElement empty element}, etc) when developing a feature.\n *\n * The container element should be your default choice when writing a converter, unless:\n *\n * * this element represents a model text attribute (then use {@link module:engine/view/attributeelement~AttributeElement}),\n * * this is an empty element like `` (then use {@link module:engine/view/emptyelement~EmptyElement}),\n * * this is a root element,\n * * this is a nested editable element (then use {@link module:engine/view/editableelement~EditableElement}).\n *\n * To create a new container element instance use the\n * {@link module:engine/view/downcastwriter~DowncastWriter#createContainerElement `DowncastWriter#createContainerElement()`}\n * method.\n *\n * @extends module:engine/view/element~Element\n */\nexport default class ContainerElement extends Element {\n\t/**\n\t * Creates a container element.\n\t *\n\t * @see module:engine/view/downcastwriter~DowncastWriter#createContainerElement\n\t * @see module:engine/view/element~Element\n\t * @protected\n\t * @param {module:engine/view/document~Document} document The document instance to which this element belongs.\n\t * @param {String} name Node name.\n\t * @param {Object|Iterable} [attrs] Collection of attributes.\n\t * @param {module:engine/view/node~Node|Iterable.} [children]\n\t * A list of nodes to be inserted into created element.\n\t */\n\tconstructor( document, name, attrs, children ) {\n\t\tsuper( document, name, attrs, children );\n\n\t\t/**\n\t\t * Returns block {@link module:engine/view/filler filler} offset or `null` if block filler is not needed.\n\t\t *\n\t\t * @method #getFillerOffset\n\t\t * @returns {Number|null} Block filler offset or `null` if block filler is not needed.\n\t\t */\n\t\tthis.getFillerOffset = getFillerOffset;\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\tcontainerElement.is( 'containerElement' ); // -> true\n\t *\t\tcontainerElement.is( 'element' ); // -> true\n\t *\t\tcontainerElement.is( 'node' ); // -> true\n\t *\t\tcontainerElement.is( 'view:containerElement' ); // -> true\n\t *\t\tcontainerElement.is( 'view:element' ); // -> true\n\t *\t\tcontainerElement.is( 'view:node' ); // -> true\n\t *\n\t *\t\tcontainerElement.is( 'model:element' ); // -> false\n\t *\t\tcontainerElement.is( 'documentFragment' ); // -> false\n\t *\n\t * Assuming that the object being checked is a container element, you can also check its\n\t * {@link module:engine/view/containerelement~ContainerElement#name name}:\n\t *\n\t *\t\tcontainerElement.is( 'element', 'div' ); // -> true if this is a div container element\n\t *\t\tcontainerElement.is( 'contaienrElement', 'div' ); // -> same as above\n\t *\t\ttext.is( 'element', 'div' ); -> false\n\t *\n\t * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.\n\t *\n\t * @param {String} type Type to check.\n\t * @param {String} [name] Element name.\n\t * @returns {Boolean}\n\t */\n\tis( type, name = null ) {\n\t\tif ( !name ) {\n\t\t\treturn type === 'containerElement' || type === 'view:containerElement' ||\n\t\t\t\t// From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.\n\t\t\t\ttype === 'element' || type === 'view:element' ||\n\t\t\t\ttype === 'node' || type === 'view:node';\n\t\t} else {\n\t\t\treturn name === this.name && (\n\t\t\t\ttype === 'containerElement' || type === 'view:containerElement' ||\n\t\t\t\t// From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.\n\t\t\t\ttype === 'element' || type === 'view:element'\n\t\t\t);\n\t\t}\n\t}\n}\n\n/**\n * Returns block {@link module:engine/view/filler filler} offset or `null` if block filler is not needed.\n *\n * @returns {Number|null} Block filler offset or `null` if block filler is not needed.\n */\nexport function getFillerOffset() {\n\tconst children = [ ...this.getChildren() ];\n\tconst lastChild = children[ this.childCount - 1 ];\n\n\t// Block filler is required after a `
` if it's the last element in its container. See #1422.\n\tif ( lastChild && lastChild.is( 'element', 'br' ) ) {\n\t\treturn this.childCount;\n\t}\n\n\tfor ( const child of children ) {\n\t\t// If there's any non-UI element – don't render the bogus.\n\t\tif ( !child.is( 'uiElement' ) ) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t// If there are only UI elements – render the bogus at the end of the element.\n\treturn this.childCount;\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 module:engine/view/downcastwriter\n */\n\nimport Position from './position';\nimport Range from './range';\nimport Selection from './selection';\nimport ContainerElement from './containerelement';\nimport AttributeElement from './attributeelement';\nimport EmptyElement from './emptyelement';\nimport UIElement from './uielement';\nimport RawElement from './rawelement';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport DocumentFragment from './documentfragment';\nimport isIterable from '@ckeditor/ckeditor5-utils/src/isiterable';\nimport Text from './text';\nimport EditableElement from './editableelement';\nimport { isPlainObject } from 'lodash-es';\n\n/**\n * View downcast writer.\n *\n * It provides a set of methods used to manipulate view nodes.\n *\n * Do not create an instance of this writer manually. To modify a view structure, use\n * the {@link module:engine/view/view~View#change `View#change()`} block.\n *\n * The `DowncastWriter` is designed to work with semantic views which are the views that were/are being downcasted from the model.\n * To work with ordinary views (e.g. parsed from a pasted content) use the\n * {@link module:engine/view/upcastwriter~UpcastWriter upcast writer}.\n *\n * Read more about changing the view in the {@glink framework/guides/architecture/editing-engine#changing-the-view Changing the view}\n * section of the {@glink framework/guides/architecture/editing-engine Editing engine architecture} guide.\n */\nexport default class DowncastWriter {\n\t/**\n\t * @param {module:engine/view/document~Document} document The view document instance.\n\t */\n\tconstructor( document ) {\n\t\t/**\n\t\t * The view document instance in which this writer operates.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:engine/view/document~Document}\n\t\t */\n\t\tthis.document = document;\n\n\t\t/**\n\t\t * Holds references to the attribute groups that share the same {@link module:engine/view/attributeelement~AttributeElement#id id}.\n\t\t * The keys are `id`s, the values are `Set`s holding {@link module:engine/view/attributeelement~AttributeElement}s.\n\t\t *\n\t\t * @private\n\t\t * @type {Map.}\n\t\t */\n\t\tthis._cloneGroups = new Map();\n\t}\n\n\t/**\n\t * Sets {@link module:engine/view/documentselection~DocumentSelection selection's} ranges and direction to the\n\t * specified location based on the given {@link module:engine/view/selection~Selectable selectable}.\n\t *\n\t * Usage:\n\t *\n\t *\t\t// Sets selection to the given range.\n\t *\t\tconst range = writer.createRange( start, end );\n\t *\t\twriter.setSelection( range );\n\t *\n\t *\t\t// Sets backward selection to the given range.\n\t *\t\tconst range = writer.createRange( start, end );\n\t *\t\twriter.setSelection( range );\n\t *\n\t *\t\t// Sets selection to given ranges.\n\t * \t\tconst ranges = [ writer.createRange( start1, end2 ), writer.createRange( start2, end2 ) ];\n\t *\t\twriter.setSelection( range );\n\t *\n\t *\t\t// Sets selection to the other selection.\n\t *\t\tconst otherSelection = writer.createSelection();\n\t *\t\twriter.setSelection( otherSelection );\n\t *\n\t * \t\t// Sets collapsed selection at the given position.\n\t *\t\tconst position = writer.createPositionFromPath( root, path );\n\t *\t\twriter.setSelection( position );\n\t *\n\t * \t\t// Sets collapsed selection at the position of given item and offset.\n\t *\t\tconst paragraph = writer.createContainerElement( 'p' );\n\t *\t\twriter.setSelection( paragraph, offset );\n\t *\n\t * Creates a range inside an {@link module:engine/view/element~Element element} which starts before the first child of\n \t * that element and ends after the last child of that element.\n\t *\n\t * \t\twriter.setSelection( paragraph, 'in' );\n\t *\n\t * Creates a range on the {@link module:engine/view/item~Item item} which starts before the item and ends just after the item.\n\t *\n\t *\t\twriter.setSelection( paragraph, 'on' );\n\t *\n\t * \t\t// Removes all ranges.\n\t *\t\twriter.setSelection( null );\n\t *\n\t * `DowncastWriter#setSelection()` allow passing additional options (`backward`, `fake` and `label`) as the last argument.\n\t *\n\t *\t\t// Sets selection as backward.\n\t *\t\twriter.setSelection( range, { backward: true } );\n\t *\n\t *\t\t// Sets selection as fake.\n\t *\t\t// Fake selection does not render as browser native selection over selected elements and is hidden to the user.\n\t * \t\t// This way, no native selection UI artifacts are displayed to the user and selection over elements can be\n\t * \t\t// represented in other way, for example by applying proper CSS class.\n\t *\t\twriter.setSelection( range, { fake: true } );\n\t *\n\t * \t\t// Additionally fake's selection label can be provided. It will be used to describe fake selection in DOM\n\t * \t\t// (and be properly handled by screen readers).\n\t *\t\twriter.setSelection( range, { fake: true, label: 'foo' } );\n\t *\n\t * @param {module:engine/view/selection~Selectable} selectable\n\t * @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] Sets place or offset of the selection.\n\t * @param {Object} [options]\n\t * @param {Boolean} [options.backward] Sets this selection instance to be backward.\n\t * @param {Boolean} [options.fake] Sets this selection instance to be marked as `fake`.\n\t * @param {String} [options.label] Label for the fake selection.\n\t */\n\tsetSelection( selectable, placeOrOffset, options ) {\n\t\tthis.document.selection._setTo( selectable, placeOrOffset, options );\n\t}\n\n\t/**\n\t * Moves {@link module:engine/view/documentselection~DocumentSelection#focus selection's focus} to the specified location.\n\t *\n\t * The location can be specified in the same form as {@link module:engine/view/view~View#createPositionAt view.createPositionAt()}\n\t * parameters.\n\t *\n\t * @param {module:engine/view/item~Item|module:engine/view/position~Position} itemOrPosition\n\t * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when\n\t * first parameter is a {@link module:engine/view/item~Item view item}.\n\t */\n\tsetSelectionFocus( itemOrPosition, offset ) {\n\t\tthis.document.selection._setFocus( itemOrPosition, offset );\n\t}\n\n\t/**\n\t * Creates a new {@link module:engine/view/documentfragment~DocumentFragment} instance.\n\t *\n\t * @param {module:engine/view/node~Node|Iterable.} [children]\n\t * A list of nodes to be inserted into the created document fragment.\n\t * @returns {module:engine/view/documentfragment~DocumentFragment} The created document fragment.\n\t */\n\tcreateDocumentFragment( children ) {\n\t\treturn new DocumentFragment( this.document, children );\n\t}\n\n\t/**\n\t * Creates a new {@link module:engine/view/text~Text text node}.\n\t *\n\t *\t\twriter.createText( 'foo' );\n\t *\n\t * @param {String} data The text's data.\n\t * @returns {module:engine/view/text~Text} The created text node.\n\t */\n\tcreateText( data ) {\n\t\treturn new Text( this.document, data );\n\t}\n\n\t/**\n\t * Creates a new {@link module:engine/view/attributeelement~AttributeElement}.\n\t *\n\t *\t\twriter.createAttributeElement( 'strong' );\n\t *\t\twriter.createAttributeElement( 'a', { href: 'foo.bar' } );\n\t *\n\t *\t\t// Make `` element contain other attributes element so the `` element is not broken.\n\t *\t\twriter.createAttributeElement( 'a', { href: 'foo.bar' }, { priority: 5 } );\n\t *\n\t *\t\t// Set `id` of a marker element so it is not joined or merged with \"normal\" elements.\n\t *\t\twriter.createAttributeElement( 'span', { class: 'my-marker' }, { id: 'marker:my' } );\n\t *\n\t * **Note:** By default an `AttributeElement` is split by a\n\t * {@link module:engine/view/containerelement~ContainerElement `ContainerElement`} but this behavior can be modified\n\t * with `isAllowedInsideAttributeElement` option set while {@link #createContainerElement creating the element}.\n\t *\n\t * @param {String} name Name of the element.\n\t * @param {Object} [attributes] Element's attributes.\n\t * @param {Object} [options] Element's options.\n\t * @param {Number} [options.priority] Element's {@link module:engine/view/attributeelement~AttributeElement#priority priority}.\n\t * @param {Number|String} [options.id] Element's {@link module:engine/view/attributeelement~AttributeElement#id id}.\n\t * @returns {module:engine/view/attributeelement~AttributeElement} Created element.\n\t */\n\tcreateAttributeElement( name, attributes, options = {} ) {\n\t\tconst attributeElement = new AttributeElement( this.document, name, attributes );\n\n\t\tif ( options.priority ) {\n\t\t\tattributeElement._priority = options.priority;\n\t\t}\n\n\t\tif ( options.id ) {\n\t\t\tattributeElement._id = options.id;\n\t\t}\n\n\t\treturn attributeElement;\n\t}\n\n\t/**\n\t * Creates a new {@link module:engine/view/containerelement~ContainerElement}.\n\t *\n\t *\t\twriter.createContainerElement( 'p' );\n\t *\n\t *\t\t// Create element with custom attributes.\n\t *\t\twriter.createContainerElement( 'div', { id: 'foo-bar', 'data-baz': '123' } );\n\t *\n\t *\t\t// Create element with custom styles.\n\t *\t\twriter.createContainerElement( 'p', { style: 'font-weight: bold; padding-bottom: 10px' } );\n\t *\n\t *\t\t// Create element with custom classes.\n\t *\t\twriter.createContainerElement( 'p', { class: 'foo bar baz' } );\n\t *\n\t * @param {String} name Name of the element.\n\t * @param {Object} [attributes] Elements attributes.\n\t * @param {Object} [options] Element's options.\n\t * @param {Boolean} [options.isAllowedInsideAttributeElement=false] Whether an element is\n\t * {@link module:engine/view/element~Element#isAllowedInsideAttributeElement allowed inside an AttributeElement} and can be wrapped\n\t * with {@link module:engine/view/attributeelement~AttributeElement} by {@link module:engine/view/downcastwriter~DowncastWriter}.\n\t * @returns {module:engine/view/containerelement~ContainerElement} Created element.\n\t */\n\tcreateContainerElement( name, attributes, options = {} ) {\n\t\tconst containerElement = new ContainerElement( this.document, name, attributes );\n\n\t\tif ( options.isAllowedInsideAttributeElement !== undefined ) {\n\t\t\tcontainerElement._isAllowedInsideAttributeElement = options.isAllowedInsideAttributeElement;\n\t\t}\n\n\t\treturn containerElement;\n\t}\n\n\t/**\n\t * Creates a new {@link module:engine/view/editableelement~EditableElement}.\n\t *\n\t *\t\twriter.createEditableElement( 'div' );\n\t *\t\twriter.createEditableElement( 'div', { id: 'foo-1234' } );\n\t *\n\t * Note: The editable element is to be used in the editing pipeline. Usually, together with\n\t * {@link module:widget/utils~toWidgetEditable `toWidgetEditable()`}.\n\t *\n\t * @param {String} name Name of the element.\n\t * @param {Object} [attributes] Elements attributes.\n\t * @returns {module:engine/view/editableelement~EditableElement} Created element.\n\t */\n\tcreateEditableElement( name, attributes ) {\n\t\tconst editableElement = new EditableElement( this.document, name, attributes );\n\t\teditableElement._document = this.document;\n\n\t\treturn editableElement;\n\t}\n\n\t/**\n\t * Creates a new {@link module:engine/view/emptyelement~EmptyElement}.\n\t *\n\t *\t\twriter.createEmptyElement( 'img' );\n\t *\t\twriter.createEmptyElement( 'img', { id: 'foo-1234' } );\n\t *\n\t * @param {String} name Name of the element.\n\t * @param {Object} [attributes] Elements attributes.\n\t * @param {Object} [options] Element's options.\n\t * @param {Boolean} [options.isAllowedInsideAttributeElement=true] Whether an element is\n\t * {@link module:engine/view/element~Element#isAllowedInsideAttributeElement allowed inside an AttributeElement} and can be wrapped\n\t * with {@link module:engine/view/attributeelement~AttributeElement} by {@link module:engine/view/downcastwriter~DowncastWriter}.\n\t * @returns {module:engine/view/emptyelement~EmptyElement} Created element.\n\t */\n\tcreateEmptyElement( name, attributes, options = {} ) {\n\t\tconst emptyElement = new EmptyElement( this.document, name, attributes );\n\n\t\tif ( options.isAllowedInsideAttributeElement !== undefined ) {\n\t\t\temptyElement._isAllowedInsideAttributeElement = options.isAllowedInsideAttributeElement;\n\t\t}\n\n\t\treturn emptyElement;\n\t}\n\n\t/**\n\t * Creates a new {@link module:engine/view/uielement~UIElement}.\n\t *\n\t *\t\twriter.createUIElement( 'span' );\n\t *\t\twriter.createUIElement( 'span', { id: 'foo-1234' } );\n\t *\n\t * A custom render function can be provided as the third parameter:\n\t *\n\t *\t\twriter.createUIElement( 'span', null, function( domDocument ) {\n\t *\t\t\tconst domElement = this.toDomElement( domDocument );\n\t *\t\t\tdomElement.innerHTML = 'this is ui element';\n\t *\n\t *\t\t\treturn domElement;\n\t *\t\t} );\n\t *\n\t * Unlike {@link #createRawElement raw elements}, UI elements are by no means editor content, for instance,\n\t * they are ignored by the editor selection system.\n\t *\n\t * You should not use UI elements as data containers. Check out {@link #createRawElement} instead.\n\t *\n\t * @param {String} name The name of the element.\n\t * @param {Object} [attributes] Element attributes.\n\t * @param {Function} [renderFunction] A custom render function.\n\t * @param {Object} [options] Element's options.\n\t * @param {Boolean} [options.isAllowedInsideAttributeElement=true] Whether an element is\n\t * {@link module:engine/view/element~Element#isAllowedInsideAttributeElement allowed inside an AttributeElement} and can be wrapped\n\t * with {@link module:engine/view/attributeelement~AttributeElement} by {@link module:engine/view/downcastwriter~DowncastWriter}.\n\t * @returns {module:engine/view/uielement~UIElement} The created element.\n\t */\n\tcreateUIElement( name, attributes, renderFunction, options = {} ) {\n\t\tconst uiElement = new UIElement( this.document, name, attributes );\n\n\t\tif ( renderFunction ) {\n\t\t\tuiElement.render = renderFunction;\n\t\t}\n\n\t\tif ( options.isAllowedInsideAttributeElement !== undefined ) {\n\t\t\tuiElement._isAllowedInsideAttributeElement = options.isAllowedInsideAttributeElement;\n\t\t}\n\n\t\treturn uiElement;\n\t}\n\n\t/**\n\t * Creates a new {@link module:engine/view/rawelement~RawElement}.\n\t *\n\t *\t\twriter.createRawElement( 'span', { id: 'foo-1234' }, function( domElement ) {\n\t *\t\t\tdomElement.innerHTML = 'This is the raw content of the raw element.';\n\t *\t\t} );\n\t *\n\t * Raw elements work as data containers (\"wrappers\", \"sandboxes\") but their children are not managed or\n\t * even recognized by the editor. This encapsulation allows integrations to maintain custom DOM structures\n\t * in the editor content without, for instance, worrying about compatibility with other editor features.\n\t * Raw elements are a perfect tool for integration with external frameworks and data sources.\n\t *\n\t * Unlike {@link #createUIElement UI elements}, raw elements act like \"real\" editor content (similar to\n\t * {@link module:engine/view/containerelement~ContainerElement} or {@link module:engine/view/emptyelement~EmptyElement}),\n\t * and they are considered by the editor selection.\n\t *\n\t * You should not use raw elements to render the UI in the editor content. Check out {@link #createUIElement `#createUIElement()`}\n\t * instead.\n\t *\n\t * @param {String} name The name of the element.\n\t * @param {Object} [attributes] Element attributes.\n\t * @param {Function} [renderFunction] A custom render function.\n\t * @param {Object} [options] Element's options.\n\t * @param {Boolean} [options.isAllowedInsideAttributeElement=true] Whether an element is\n\t * {@link module:engine/view/element~Element#isAllowedInsideAttributeElement allowed inside an AttributeElement} and can be wrapped\n\t * with {@link module:engine/view/attributeelement~AttributeElement} by {@link module:engine/view/downcastwriter~DowncastWriter}.\n\t * @returns {module:engine/view/rawelement~RawElement} The created element.\n\t */\n\tcreateRawElement( name, attributes, renderFunction, options = {} ) {\n\t\tconst rawElement = new RawElement( this.document, name, attributes );\n\n\t\trawElement.render = renderFunction || ( () => {} );\n\n\t\tif ( options.isAllowedInsideAttributeElement !== undefined ) {\n\t\t\trawElement._isAllowedInsideAttributeElement = options.isAllowedInsideAttributeElement;\n\t\t}\n\n\t\treturn rawElement;\n\t}\n\n\t/**\n\t * Adds or overwrites the element's attribute with a specified key and value.\n\t *\n\t *\t\twriter.setAttribute( 'href', 'http://ckeditor.com', linkElement );\n\t *\n\t * @param {String} key The attribute key.\n\t * @param {String} value The attribute value.\n\t * @param {module:engine/view/element~Element} element\n\t */\n\tsetAttribute( key, value, element ) {\n\t\telement._setAttribute( key, value );\n\t}\n\n\t/**\n\t * Removes attribute from the element.\n\t *\n\t *\t\twriter.removeAttribute( 'href', linkElement );\n\t *\n\t * @param {String} key Attribute key.\n\t * @param {module:engine/view/element~Element} element\n\t */\n\tremoveAttribute( key, element ) {\n\t\telement._removeAttribute( key );\n\t}\n\n\t/**\n\t * Adds specified class to the element.\n\t *\n\t *\t\twriter.addClass( 'foo', linkElement );\n\t *\t\twriter.addClass( [ 'foo', 'bar' ], linkElement );\n\t *\n\t * @param {Array.|String} className\n\t * @param {module:engine/view/element~Element} element\n\t */\n\taddClass( className, element ) {\n\t\telement._addClass( className );\n\t}\n\n\t/**\n\t * Removes specified class from the element.\n\t *\n\t *\t\twriter.removeClass( 'foo', linkElement );\n\t *\t\twriter.removeClass( [ 'foo', 'bar' ], linkElement );\n\t *\n\t * @param {Array.|String} className\n\t * @param {module:engine/view/element~Element} element\n\t */\n\tremoveClass( className, element ) {\n\t\telement._removeClass( className );\n\t}\n\n\t/**\n\t * Adds style to the element.\n\t *\n\t *\t\twriter.setStyle( 'color', 'red', element );\n\t *\t\twriter.setStyle( {\n\t *\t\t\tcolor: 'red',\n\t *\t\t\tposition: 'fixed'\n\t *\t\t}, element );\n\t *\n\t * **Note**: The passed style can be normalized if\n\t * {@link module:engine/controller/datacontroller~DataController#addStyleProcessorRules a particular style processor rule is enabled}.\n\t * See {@link module:engine/view/stylesmap~StylesMap#set `StylesMap#set()`} for details.\n\t *\n\t * @param {String|Object} property Property name or object with key - value pairs.\n\t * @param {String} [value] Value to set. This parameter is ignored if object is provided as the first parameter.\n\t * @param {module:engine/view/element~Element} element Element to set styles on.\n\t */\n\tsetStyle( property, value, element ) {\n\t\tif ( isPlainObject( property ) && element === undefined ) {\n\t\t\telement = value;\n\t\t}\n\n\t\telement._setStyle( property, value );\n\t}\n\n\t/**\n\t * Removes specified style from the element.\n\t *\n\t *\t\twriter.removeStyle( 'color', element ); // Removes 'color' style.\n\t *\t\twriter.removeStyle( [ 'color', 'border-top' ], element ); // Removes both 'color' and 'border-top' styles.\n\t *\n\t * **Note**: This method can work with normalized style names if\n\t * {@link module:engine/controller/datacontroller~DataController#addStyleProcessorRules a particular style processor rule is enabled}.\n\t * See {@link module:engine/view/stylesmap~StylesMap#remove `StylesMap#remove()`} for details.\n\t *\n\t * @param {Array.|String} property\n\t * @param {module:engine/view/element~Element} element\n\t */\n\tremoveStyle( property, element ) {\n\t\telement._removeStyle( property );\n\t}\n\n\t/**\n\t * Sets a custom property on element. Unlike attributes, custom properties are not rendered to the DOM,\n\t * so they can be used to add special data to elements.\n\t *\n\t * @param {String|Symbol} key\n\t * @param {*} value\n\t * @param {module:engine/view/element~Element} element\n\t */\n\tsetCustomProperty( key, value, element ) {\n\t\telement._setCustomProperty( key, value );\n\t}\n\n\t/**\n\t * Removes a custom property stored under the given key.\n\t *\n\t * @param {String|Symbol} key\n\t * @param {module:engine/view/element~Element} element\n\t * @returns {Boolean} Returns true if property was removed.\n\t */\n\tremoveCustomProperty( key, element ) {\n\t\treturn element._removeCustomProperty( key );\n\t}\n\n\t/**\n\t * Breaks attribute elements at the provided position or at the boundaries of a provided range. It breaks attribute elements\n\t * up to their first ancestor that is a container element.\n\t *\n\t * In following examples `

` is a container, `` and `` are attribute elements:\n\t *\n\t *\t\t

foobar{}

->

foobar[]

\n\t *\t\t

foo{}bar

->

foo{}bar

\n\t *\t\t

foob{}ar

->

foob[]ar

\n\t *\t\t

fo{oba}r

->

foobar

\n\t *\n\t * **Note:** {@link module:engine/view/documentfragment~DocumentFragment DocumentFragment} is treated like a container.\n\t *\n\t * **Note:** The difference between {@link module:engine/view/downcastwriter~DowncastWriter#breakAttributes breakAttributes()} and\n\t * {@link module:engine/view/downcastwriter~DowncastWriter#breakContainer breakContainer()} is that `breakAttributes()` breaks all\n\t * {@link module:engine/view/attributeelement~AttributeElement attribute elements} that are ancestors of a given `position`,\n\t * up to the first encountered {@link module:engine/view/containerelement~ContainerElement container element}.\n\t * `breakContainer()` assumes that a given `position` is directly in the container element and breaks that container element.\n\t *\n\t * Throws the `view-writer-invalid-range-container` {@link module:utils/ckeditorerror~CKEditorError CKEditorError}\n\t * when the {@link module:engine/view/range~Range#start start}\n\t * and {@link module:engine/view/range~Range#end end} positions of a passed range are not placed inside same parent container.\n\t *\n\t * Throws the `view-writer-cannot-break-empty-element` {@link module:utils/ckeditorerror~CKEditorError CKEditorError}\n\t * when trying to break attributes inside an {@link module:engine/view/emptyelement~EmptyElement EmptyElement}.\n\t *\n\t * Throws the `view-writer-cannot-break-ui-element` {@link module:utils/ckeditorerror~CKEditorError CKEditorError}\n\t * when trying to break attributes inside a {@link module:engine/view/uielement~UIElement UIElement}.\n\t *\n\t * @see module:engine/view/attributeelement~AttributeElement\n\t * @see module:engine/view/containerelement~ContainerElement\n\t * @see module:engine/view/downcastwriter~DowncastWriter#breakContainer\n\t * @param {module:engine/view/position~Position|module:engine/view/range~Range} positionOrRange The position where\n\t * to break attribute elements.\n\t * @returns {module:engine/view/position~Position|module:engine/view/range~Range} The new position or range, after breaking the\n\t * attribute elements.\n\t */\n\tbreakAttributes( positionOrRange ) {\n\t\tif ( positionOrRange instanceof Position ) {\n\t\t\treturn this._breakAttributes( positionOrRange );\n\t\t} else {\n\t\t\treturn this._breakAttributesRange( positionOrRange );\n\t\t}\n\t}\n\n\t/**\n\t * Breaks a {@link module:engine/view/containerelement~ContainerElement container view element} into two, at the given position.\n\t * The position has to be directly inside the container element and cannot be in the root. It does not break the conrainer view element\n\t * if the position is at the beginning or at the end of its parent element.\n\t *\n\t *\t\t

foo^bar

->

foo

bar

\n\t *\t\t

foo

^

bar

->

foo

bar

\n\t *\t\t

^foobar

-> ^

foobar

\n\t *\t\t

foobar^

->

foobar

^\n\t *\n\t * **Note:** The difference between {@link module:engine/view/downcastwriter~DowncastWriter#breakAttributes breakAttributes()} and\n\t * {@link module:engine/view/downcastwriter~DowncastWriter#breakContainer breakContainer()} is that `breakAttributes()` breaks all\n\t * {@link module:engine/view/attributeelement~AttributeElement attribute elements} that are ancestors of a given `position`,\n\t * up to the first encountered {@link module:engine/view/containerelement~ContainerElement container element}.\n\t * `breakContainer()` assumes that the given `position` is directly in the container element and breaks that container element.\n\t *\n\t * @see module:engine/view/attributeelement~AttributeElement\n\t * @see module:engine/view/containerelement~ContainerElement\n\t * @see module:engine/view/downcastwriter~DowncastWriter#breakAttributes\n\t * @param {module:engine/view/position~Position} position The position where to break the element.\n\t * @returns {module:engine/view/position~Position} The position between broken elements. If an element has not been broken,\n\t * the returned position is placed either before or after it.\n\t */\n\tbreakContainer( position ) {\n\t\tconst element = position.parent;\n\n\t\tif ( !( element.is( 'containerElement' ) ) ) {\n\t\t\t/**\n\t\t\t * Trying to break an element which is not a container element.\n\t\t\t *\n\t\t\t * @error view-writer-break-non-container-element\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-writer-break-non-container-element', this.document );\n\t\t}\n\n\t\tif ( !element.parent ) {\n\t\t\t/**\n\t\t\t * Trying to break root element.\n\t\t\t *\n\t\t\t * @error view-writer-break-root\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-writer-break-root', this.document );\n\t\t}\n\n\t\tif ( position.isAtStart ) {\n\t\t\treturn Position._createBefore( element );\n\t\t} else if ( !position.isAtEnd ) {\n\t\t\tconst newElement = element._clone( false );\n\n\t\t\tthis.insert( Position._createAfter( element ), newElement );\n\n\t\t\tconst sourceRange = new Range( position, Position._createAt( element, 'end' ) );\n\t\t\tconst targetPosition = new Position( newElement, 0 );\n\n\t\t\tthis.move( sourceRange, targetPosition );\n\t\t}\n\n\t\treturn Position._createAfter( element );\n\t}\n\n\t/**\n\t * Merges {@link module:engine/view/attributeelement~AttributeElement attribute elements}. It also merges text nodes if needed.\n\t * Only {@link module:engine/view/attributeelement~AttributeElement#isSimilar similar} attribute elements can be merged.\n\t *\n\t * In following examples `

` is a container and `` is an attribute element:\n\t *\n\t *\t\t

foo[]bar

->

foo{}bar

\n\t *\t\t

foo[]bar

->

foo{}bar

\n\t *\t\t

a[]b

->

a[]b

\n\t *\n\t * It will also take care about empty attributes when merging:\n\t *\n\t *\t\t

[]

->

[]

\n\t *\t\t

foo[]bar

->

foo{}bar

\n\t *\n\t * **Note:** Difference between {@link module:engine/view/downcastwriter~DowncastWriter#mergeAttributes mergeAttributes} and\n\t * {@link module:engine/view/downcastwriter~DowncastWriter#mergeContainers mergeContainers} is that `mergeAttributes` merges two\n\t * {@link module:engine/view/attributeelement~AttributeElement attribute elements} or {@link module:engine/view/text~Text text nodes}\n\t * while `mergeContainer` merges two {@link module:engine/view/containerelement~ContainerElement container elements}.\n\t *\n\t * @see module:engine/view/attributeelement~AttributeElement\n\t * @see module:engine/view/containerelement~ContainerElement\n\t * @see module:engine/view/downcastwriter~DowncastWriter#mergeContainers\n\t * @param {module:engine/view/position~Position} position Merge position.\n\t * @returns {module:engine/view/position~Position} Position after merge.\n\t */\n\tmergeAttributes( position ) {\n\t\tconst positionOffset = position.offset;\n\t\tconst positionParent = position.parent;\n\n\t\t// When inside text node - nothing to merge.\n\t\tif ( positionParent.is( '$text' ) ) {\n\t\t\treturn position;\n\t\t}\n\n\t\t// When inside empty attribute - remove it.\n\t\tif ( positionParent.is( 'attributeElement' ) && positionParent.childCount === 0 ) {\n\t\t\tconst parent = positionParent.parent;\n\t\t\tconst offset = positionParent.index;\n\n\t\t\tpositionParent._remove();\n\t\t\tthis._removeFromClonedElementsGroup( positionParent );\n\n\t\t\treturn this.mergeAttributes( new Position( parent, offset ) );\n\t\t}\n\n\t\tconst nodeBefore = positionParent.getChild( positionOffset - 1 );\n\t\tconst nodeAfter = positionParent.getChild( positionOffset );\n\n\t\t// Position should be placed between two nodes.\n\t\tif ( !nodeBefore || !nodeAfter ) {\n\t\t\treturn position;\n\t\t}\n\n\t\t// When position is between two text nodes.\n\t\tif ( nodeBefore.is( '$text' ) && nodeAfter.is( '$text' ) ) {\n\t\t\treturn mergeTextNodes( nodeBefore, nodeAfter );\n\t\t}\n\t\t// When position is between two same attribute elements.\n\t\telse if ( nodeBefore.is( 'attributeElement' ) && nodeAfter.is( 'attributeElement' ) && nodeBefore.isSimilar( nodeAfter ) ) {\n\t\t\t// Move all children nodes from node placed after selection and remove that node.\n\t\t\tconst count = nodeBefore.childCount;\n\t\t\tnodeBefore._appendChild( nodeAfter.getChildren() );\n\n\t\t\tnodeAfter._remove();\n\t\t\tthis._removeFromClonedElementsGroup( nodeAfter );\n\n\t\t\t// New position is located inside the first node, before new nodes.\n\t\t\t// Call this method recursively to merge again if needed.\n\t\t\treturn this.mergeAttributes( new Position( nodeBefore, count ) );\n\t\t}\n\n\t\treturn position;\n\t}\n\n\t/**\n\t * Merges two {@link module:engine/view/containerelement~ContainerElement container elements} that are before and after given position.\n\t * Precisely, the element after the position is removed and it's contents are moved to element before the position.\n\t *\n\t *\t\t

foo

^

bar

->

foo^bar

\n\t *\t\t
foo
^

bar

->
foo^bar
\n\t *\n\t * **Note:** Difference between {@link module:engine/view/downcastwriter~DowncastWriter#mergeAttributes mergeAttributes} and\n\t * {@link module:engine/view/downcastwriter~DowncastWriter#mergeContainers mergeContainers} is that `mergeAttributes` merges two\n\t * {@link module:engine/view/attributeelement~AttributeElement attribute elements} or {@link module:engine/view/text~Text text nodes}\n\t * while `mergeContainer` merges two {@link module:engine/view/containerelement~ContainerElement container elements}.\n\t *\n\t * @see module:engine/view/attributeelement~AttributeElement\n\t * @see module:engine/view/containerelement~ContainerElement\n\t * @see module:engine/view/downcastwriter~DowncastWriter#mergeAttributes\n\t * @param {module:engine/view/position~Position} position Merge position.\n\t * @returns {module:engine/view/position~Position} Position after merge.\n\t */\n\tmergeContainers( position ) {\n\t\tconst prev = position.nodeBefore;\n\t\tconst next = position.nodeAfter;\n\n\t\tif ( !prev || !next || !prev.is( 'containerElement' ) || !next.is( 'containerElement' ) ) {\n\t\t\t/**\n\t\t\t * Element before and after given position cannot be merged.\n\t\t\t *\n\t\t\t * @error view-writer-merge-containers-invalid-position\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-writer-merge-containers-invalid-position', this.document );\n\t\t}\n\n\t\tconst lastChild = prev.getChild( prev.childCount - 1 );\n\t\tconst newPosition = lastChild instanceof Text ? Position._createAt( lastChild, 'end' ) : Position._createAt( prev, 'end' );\n\n\t\tthis.move( Range._createIn( next ), Position._createAt( prev, 'end' ) );\n\t\tthis.remove( Range._createOn( next ) );\n\n\t\treturn newPosition;\n\t}\n\n\t/**\n\t * Inserts a node or nodes at specified position. Takes care about breaking attributes before insertion\n\t * and merging them afterwards.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-insert-invalid-node` when nodes to insert\n\t * contains instances that are not {@link module:engine/view/text~Text Texts},\n\t * {@link module:engine/view/attributeelement~AttributeElement AttributeElements},\n\t * {@link module:engine/view/containerelement~ContainerElement ContainerElements},\n\t * {@link module:engine/view/emptyelement~EmptyElement EmptyElements},\n\t * {@link module:engine/view/rawelement~RawElement RawElements} or\n\t * {@link module:engine/view/uielement~UIElement UIElements}.\n\t *\n\t * @param {module:engine/view/position~Position} position Insertion position.\n\t * @param {module:engine/view/text~Text|module:engine/view/attributeelement~AttributeElement|\n\t * module:engine/view/containerelement~ContainerElement|module:engine/view/emptyelement~EmptyElement|\n\t * module:engine/view/rawelement~RawElement|module:engine/view/uielement~UIElement|\n\t * Iterable.} nodes Node or nodes to insert.\n\t * @returns {module:engine/view/range~Range} Range around inserted nodes.\n\t */\n\tinsert( position, nodes ) {\n\t\tnodes = isIterable( nodes ) ? [ ...nodes ] : [ nodes ];\n\n\t\t// Check if nodes to insert are instances of AttributeElements, ContainerElements, EmptyElements, UIElements or Text.\n\t\tvalidateNodesToInsert( nodes, this.document );\n\n\t\t// Group nodes in batches of nodes that require or do not require breaking an AttributeElements.\n\t\tconst nodeGroups = nodes.reduce( ( groups, node ) => {\n\t\t\tconst lastGroup = groups[ groups.length - 1 ];\n\n\t\t\t// Break attributes on nodes that do exist in the model tree so they can have attributes, other elements\n\t\t\t// can't have an attribute in model and won't get wrapped with an AttributeElement while down-casted.\n\t\t\tconst breakAttributes = !( node.is( 'uiElement' ) && node.isAllowedInsideAttributeElement );\n\n\t\t\tif ( !lastGroup || lastGroup.breakAttributes != breakAttributes ) {\n\t\t\t\tgroups.push( {\n\t\t\t\t\tbreakAttributes,\n\t\t\t\t\tnodes: [ node ]\n\t\t\t\t} );\n\t\t\t} else {\n\t\t\t\tlastGroup.nodes.push( node );\n\t\t\t}\n\n\t\t\treturn groups;\n\t\t}, [] );\n\n\t\t// Insert nodes in batches.\n\t\tlet start = null;\n\t\tlet end = position;\n\n\t\tfor ( const { nodes, breakAttributes } of nodeGroups ) {\n\t\t\tconst range = this._insertNodes( end, nodes, breakAttributes );\n\n\t\t\tif ( !start ) {\n\t\t\t\tstart = range.start;\n\t\t\t}\n\n\t\t\tend = range.end;\n\t\t}\n\n\t\t// When no nodes were inserted - return collapsed range.\n\t\tif ( !start ) {\n\t\t\treturn new Range( position );\n\t\t}\n\n\t\treturn new Range( start, end );\n\t}\n\n\t/**\n\t * Removes provided range from the container.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-invalid-range-container` when\n\t * {@link module:engine/view/range~Range#start start} and {@link module:engine/view/range~Range#end end} positions are not placed inside\n\t * same parent container.\n\t *\n\t * @param {module:engine/view/range~Range|module:engine/view/item~Item} rangeOrItem Range to remove from container\n\t * or an {@link module:engine/view/item~Item item} to remove. If range is provided, after removing, it will be updated\n\t * to a collapsed range showing the new position.\n\t * @returns {module:engine/view/documentfragment~DocumentFragment} Document fragment containing removed nodes.\n\t */\n\tremove( rangeOrItem ) {\n\t\tconst range = rangeOrItem instanceof Range ? rangeOrItem : Range._createOn( rangeOrItem );\n\n\t\tvalidateRangeContainer( range, this.document );\n\n\t\t// If range is collapsed - nothing to remove.\n\t\tif ( range.isCollapsed ) {\n\t\t\treturn new DocumentFragment( this.document );\n\t\t}\n\n\t\t// Break attributes at range start and end.\n\t\tconst { start: breakStart, end: breakEnd } = this._breakAttributesRange( range, true );\n\t\tconst parentContainer = breakStart.parent;\n\n\t\tconst count = breakEnd.offset - breakStart.offset;\n\n\t\t// Remove nodes in range.\n\t\tconst removed = parentContainer._removeChildren( breakStart.offset, count );\n\n\t\tfor ( const node of removed ) {\n\t\t\tthis._removeFromClonedElementsGroup( node );\n\t\t}\n\n\t\t// Merge after removing.\n\t\tconst mergePosition = this.mergeAttributes( breakStart );\n\t\trange.start = mergePosition;\n\t\trange.end = mergePosition.clone();\n\n\t\t// Return removed nodes.\n\t\treturn new DocumentFragment( this.document, removed );\n\t}\n\n\t/**\n\t * Removes matching elements from given range.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-invalid-range-container` when\n\t * {@link module:engine/view/range~Range#start start} and {@link module:engine/view/range~Range#end end} positions are not placed inside\n\t * same parent container.\n\t *\n\t * @param {module:engine/view/range~Range} range Range to clear.\n\t * @param {module:engine/view/element~Element} element Element to remove.\n\t */\n\tclear( range, element ) {\n\t\tvalidateRangeContainer( range, this.document );\n\n\t\t// Create walker on given range.\n\t\t// We walk backward because when we remove element during walk it modifies range end position.\n\t\tconst walker = range.getWalker( {\n\t\t\tdirection: 'backward',\n\t\t\tignoreElementEnd: true\n\t\t} );\n\n\t\t// Let's walk.\n\t\tfor ( const current of walker ) {\n\t\t\tconst item = current.item;\n\t\t\tlet rangeToRemove;\n\n\t\t\t// When current item matches to the given element.\n\t\t\tif ( item.is( 'element' ) && element.isSimilar( item ) ) {\n\t\t\t\t// Create range on this element.\n\t\t\t\trangeToRemove = Range._createOn( item );\n\t\t\t\t// When range starts inside Text or TextProxy element.\n\t\t\t} else if ( !current.nextPosition.isAfter( range.start ) && item.is( '$textProxy' ) ) {\n\t\t\t\t// We need to check if parent of this text matches to given element.\n\t\t\t\tconst parentElement = item.getAncestors().find( ancestor => {\n\t\t\t\t\treturn ancestor.is( 'element' ) && element.isSimilar( ancestor );\n\t\t\t\t} );\n\n\t\t\t\t// If it is then create range inside this element.\n\t\t\t\tif ( parentElement ) {\n\t\t\t\t\trangeToRemove = Range._createIn( parentElement );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// If we have found element to remove.\n\t\t\tif ( rangeToRemove ) {\n\t\t\t\t// We need to check if element range stick out of the given range and truncate if it is.\n\t\t\t\tif ( rangeToRemove.end.isAfter( range.end ) ) {\n\t\t\t\t\trangeToRemove.end = range.end;\n\t\t\t\t}\n\n\t\t\t\tif ( rangeToRemove.start.isBefore( range.start ) ) {\n\t\t\t\t\trangeToRemove.start = range.start;\n\t\t\t\t}\n\n\t\t\t\t// At the end we remove range with found element.\n\t\t\t\tthis.remove( rangeToRemove );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Moves nodes from provided range to target position.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-invalid-range-container` when\n\t * {@link module:engine/view/range~Range#start start} and {@link module:engine/view/range~Range#end end} positions are not placed inside\n\t * same parent container.\n\t *\n\t * @param {module:engine/view/range~Range} sourceRange Range containing nodes to move.\n\t * @param {module:engine/view/position~Position} targetPosition Position to insert.\n\t * @returns {module:engine/view/range~Range} Range in target container. Inserted nodes are placed between\n\t * {@link module:engine/view/range~Range#start start} and {@link module:engine/view/range~Range#end end} positions.\n\t */\n\tmove( sourceRange, targetPosition ) {\n\t\tlet nodes;\n\n\t\tif ( targetPosition.isAfter( sourceRange.end ) ) {\n\t\t\ttargetPosition = this._breakAttributes( targetPosition, true );\n\n\t\t\tconst parent = targetPosition.parent;\n\t\t\tconst countBefore = parent.childCount;\n\n\t\t\tsourceRange = this._breakAttributesRange( sourceRange, true );\n\n\t\t\tnodes = this.remove( sourceRange );\n\n\t\t\ttargetPosition.offset += ( parent.childCount - countBefore );\n\t\t} else {\n\t\t\tnodes = this.remove( sourceRange );\n\t\t}\n\n\t\treturn this.insert( targetPosition, nodes );\n\t}\n\n\t/**\n\t * Wraps elements within range with provided {@link module:engine/view/attributeelement~AttributeElement AttributeElement}.\n\t * If a collapsed range is provided, it will be wrapped only if it is equal to view selection.\n\t *\n\t * If a collapsed range was passed and is same as selection, the selection\n\t * will be moved to the inside of the wrapped attribute element.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError} `view-writer-invalid-range-container`\n\t * when {@link module:engine/view/range~Range#start}\n\t * and {@link module:engine/view/range~Range#end} positions are not placed inside same parent container.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError} `view-writer-wrap-invalid-attribute` when passed attribute element is not\n\t * an instance of {@link module:engine/view/attributeelement~AttributeElement AttributeElement}.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError} `view-writer-wrap-nonselection-collapsed-range` when passed range\n\t * is collapsed and different than view selection.\n\t *\n\t * **Note:** Attribute elements by default can wrap {@link module:engine/view/text~Text},\n\t * {@link module:engine/view/emptyelement~EmptyElement}, {@link module:engine/view/uielement~UIElement},\n\t * {@link module:engine/view/rawelement~RawElement} and other attribute elements with higher priority. Other elements while placed\n\t * inside an attribute element will split it (or nest it in case of an `AttributeElement`). This behavior can be modified by changing\n\t * the `isAllowedInsideAttributeElement` option while using\n\t * {@link module:engine/view/downcastwriter~DowncastWriter#createContainerElement},\n\t * {@link module:engine/view/downcastwriter~DowncastWriter#createEmptyElement},\n\t * {@link module:engine/view/downcastwriter~DowncastWriter#createUIElement} or\n\t * {@link module:engine/view/downcastwriter~DowncastWriter#createRawElement}.\n\t *\n\t * @param {module:engine/view/range~Range} range Range to wrap.\n\t * @param {module:engine/view/attributeelement~AttributeElement} attribute Attribute element to use as wrapper.\n\t * @returns {module:engine/view/range~Range} range Range after wrapping, spanning over wrapping attribute element.\n\t */\n\twrap( range, attribute ) {\n\t\tif ( !( attribute instanceof AttributeElement ) ) {\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'view-writer-wrap-invalid-attribute',\n\t\t\t\tthis.document\n\t\t\t);\n\t\t}\n\n\t\tvalidateRangeContainer( range, this.document );\n\n\t\tif ( !range.isCollapsed ) {\n\t\t\t// Non-collapsed range. Wrap it with the attribute element.\n\t\t\treturn this._wrapRange( range, attribute );\n\t\t} else {\n\t\t\t// Collapsed range. Wrap position.\n\t\t\tlet position = range.start;\n\n\t\t\tif ( position.parent.is( 'element' ) && !_hasNonUiChildren( position.parent ) ) {\n\t\t\t\tposition = position.getLastMatchingPosition( value => value.item.is( 'uiElement' ) );\n\t\t\t}\n\n\t\t\tposition = this._wrapPosition( position, attribute );\n\t\t\tconst viewSelection = this.document.selection;\n\n\t\t\t// If wrapping position is equal to view selection, move view selection inside wrapping attribute element.\n\t\t\tif ( viewSelection.isCollapsed && viewSelection.getFirstPosition().isEqual( range.start ) ) {\n\t\t\t\tthis.setSelection( position );\n\t\t\t}\n\n\t\t\treturn new Range( position );\n\t\t}\n\t}\n\n\t/**\n\t * Unwraps nodes within provided range from attribute element.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-invalid-range-container` when\n\t * {@link module:engine/view/range~Range#start start} and {@link module:engine/view/range~Range#end end} positions are not placed inside\n\t * same parent container.\n\t *\n\t * @param {module:engine/view/range~Range} range\n\t * @param {module:engine/view/attributeelement~AttributeElement} attribute\n\t */\n\tunwrap( range, attribute ) {\n\t\tif ( !( attribute instanceof AttributeElement ) ) {\n\t\t\t/**\n\t\t\t * The `attribute` passed to {@link module:engine/view/downcastwriter~DowncastWriter#unwrap `DowncastWriter#unwrap()`}\n\t\t\t * must be an instance of {@link module:engine/view/attributeelement~AttributeElement `AttributeElement`}.\n\t\t\t *\n\t\t\t * @error view-writer-unwrap-invalid-attribute\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'view-writer-unwrap-invalid-attribute',\n\t\t\t\tthis.document\n\t\t\t);\n\t\t}\n\n\t\tvalidateRangeContainer( range, this.document );\n\n\t\t// If range is collapsed - nothing to unwrap.\n\t\tif ( range.isCollapsed ) {\n\t\t\treturn range;\n\t\t}\n\n\t\t// Break attributes at range start and end.\n\t\tconst { start: breakStart, end: breakEnd } = this._breakAttributesRange( range, true );\n\t\tconst parentContainer = breakStart.parent;\n\n\t\t// Unwrap children located between break points.\n\t\tconst newRange = this._unwrapChildren( parentContainer, breakStart.offset, breakEnd.offset, attribute );\n\n\t\t// Merge attributes at the both ends and return a new range.\n\t\tconst start = this.mergeAttributes( newRange.start );\n\n\t\t// If start position was merged - move end position back.\n\t\tif ( !start.isEqual( newRange.start ) ) {\n\t\t\tnewRange.end.offset--;\n\t\t}\n\n\t\tconst end = this.mergeAttributes( newRange.end );\n\n\t\treturn new Range( start, end );\n\t}\n\n\t/**\n\t * Renames element by creating a copy of renamed element but with changed name and then moving contents of the\n\t * old element to the new one. Keep in mind that this will invalidate all {@link module:engine/view/position~Position positions} which\n\t * has renamed element as {@link module:engine/view/position~Position#parent a parent}.\n\t *\n\t * New element has to be created because `Element#tagName` property in DOM is readonly.\n\t *\n\t * Since this function creates a new element and removes the given one, the new element is returned to keep reference.\n\t *\n\t * @param {String} newName New name for element.\n\t * @param {module:engine/view/containerelement~ContainerElement} viewElement Element to be renamed.\n\t * @returns {module:engine/view/containerelement~ContainerElement} Element created due to rename.\n\t */\n\trename( newName, viewElement ) {\n\t\tconst newElement = new ContainerElement( this.document, newName, viewElement.getAttributes() );\n\n\t\tthis.insert( Position._createAfter( viewElement ), newElement );\n\t\tthis.move( Range._createIn( viewElement ), Position._createAt( newElement, 0 ) );\n\t\tthis.remove( Range._createOn( viewElement ) );\n\n\t\treturn newElement;\n\t}\n\n\t/**\n\t * Cleans up memory by removing obsolete cloned elements group from the writer.\n\t *\n\t * Should be used whenever all {@link module:engine/view/attributeelement~AttributeElement attribute elements}\n\t * with the same {@link module:engine/view/attributeelement~AttributeElement#id id} are going to be removed from the view and\n\t * the group will no longer be needed.\n\t *\n\t * Cloned elements group are not removed automatically in case if the group is still needed after all its elements\n\t * were removed from the view.\n\t *\n\t * Keep in mind that group names are equal to the `id` property of the attribute element.\n\t *\n\t * @param {String} groupName Name of the group to clear.\n\t */\n\tclearClonedElementsGroup( groupName ) {\n\t\tthis._cloneGroups.delete( groupName );\n\t}\n\n\t/**\n\t * Creates position at the given location. The location can be specified as:\n\t *\n\t * * a {@link module:engine/view/position~Position position},\n\t * * parent element and offset (offset defaults to `0`),\n\t * * parent element and `'end'` (sets position at the end of that element),\n\t * * {@link module:engine/view/item~Item view item} and `'before'` or `'after'` (sets position before or after given view item).\n\t *\n\t * This method is a shortcut to other constructors such as:\n\t *\n\t * * {@link #createPositionBefore},\n\t * * {@link #createPositionAfter},\n\t *\n\t * @param {module:engine/view/item~Item|module:engine/model/position~Position} itemOrPosition\n\t * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when\n\t * first parameter is a {@link module:engine/view/item~Item view item}.\n\t */\n\tcreatePositionAt( itemOrPosition, offset ) {\n\t\treturn Position._createAt( itemOrPosition, offset );\n\t}\n\n\t/**\n\t * Creates a new position after given view item.\n\t *\n\t * @param {module:engine/view/item~Item} item View item after which the position should be located.\n\t * @returns {module:engine/view/position~Position}\n\t */\n\tcreatePositionAfter( item ) {\n\t\treturn Position._createAfter( item );\n\t}\n\n\t/**\n\t * Creates a new position before given view item.\n\t *\n\t * @param {module:engine/view/item~Item} item View item before which the position should be located.\n\t * @returns {module:engine/view/position~Position}\n\t */\n\tcreatePositionBefore( item ) {\n\t\treturn Position._createBefore( item );\n\t}\n\n\t/**\n\t * Creates a range spanning from `start` position to `end` position.\n\t *\n\t * **Note:** This factory method creates its own {@link module:engine/view/position~Position} instances basing on passed values.\n\t *\n\t * @param {module:engine/view/position~Position} start Start position.\n\t * @param {module:engine/view/position~Position} [end] End position. If not set, range will be collapsed at `start` position.\n\t * @returns {module:engine/view/range~Range}\n\t */\n\tcreateRange( start, end ) {\n\t\treturn new Range( start, end );\n\t}\n\n\t/**\n\t * Creates a range that starts before given {@link module:engine/view/item~Item view item} and ends after it.\n\t *\n\t * @param {module:engine/view/item~Item} item\n\t * @returns {module:engine/view/range~Range}\n\t */\n\tcreateRangeOn( item ) {\n\t\treturn Range._createOn( item );\n\t}\n\n\t/**\n\t * Creates a range inside an {@link module:engine/view/element~Element element} which starts before the first child of\n\t * that element and ends after the last child of that element.\n\t *\n\t * @param {module:engine/view/element~Element} element Element which is a parent for the range.\n\t * @returns {module:engine/view/range~Range}\n\t */\n\tcreateRangeIn( element ) {\n\t\treturn Range._createIn( element );\n\t}\n\n\t/**\n\t Creates new {@link module:engine/view/selection~Selection} instance.\n\t *\n\t * \t\t// Creates empty selection without ranges.\n\t *\t\tconst selection = writer.createSelection();\n\t *\n\t *\t\t// Creates selection at the given range.\n\t *\t\tconst range = writer.createRange( start, end );\n\t *\t\tconst selection = writer.createSelection( range );\n\t *\n\t *\t\t// Creates selection at the given ranges\n\t * \t\tconst ranges = [ writer.createRange( start1, end2 ), writer.createRange( star2, end2 ) ];\n\t *\t\tconst selection = writer.createSelection( ranges );\n\t *\n\t *\t\t// Creates selection from the other selection.\n\t *\t\tconst otherSelection = writer.createSelection();\n\t *\t\tconst selection = writer.createSelection( otherSelection );\n\t *\n\t *\t\t// Creates selection from the document selection.\n\t *\t\tconst selection = writer.createSelection( editor.editing.view.document.selection );\n\t *\n\t * \t\t// Creates selection at the given position.\n\t *\t\tconst position = writer.createPositionFromPath( root, path );\n\t *\t\tconst selection = writer.createSelection( position );\n\t *\n\t *\t\t// Creates collapsed selection at the position of given item and offset.\n\t *\t\tconst paragraph = writer.createContainerElement( 'p' );\n\t *\t\tconst selection = writer.createSelection( paragraph, offset );\n\t *\n\t *\t\t// Creates a range inside an {@link module:engine/view/element~Element element} which starts before the\n\t *\t\t// first child of that element and ends after the last child of that element.\n\t *\t\tconst selection = writer.createSelection( paragraph, 'in' );\n\t *\n\t *\t\t// Creates a range on an {@link module:engine/view/item~Item item} which starts before the item and ends\n\t *\t\t// just after the item.\n\t *\t\tconst selection = writer.createSelection( paragraph, 'on' );\n\t *\n\t * `Selection`'s constructor allow passing additional options (`backward`, `fake` and `label`) as the last argument.\n\t *\n\t *\t\t// Creates backward selection.\n\t *\t\tconst selection = writer.createSelection( range, { backward: true } );\n\t *\n\t * Fake selection does not render as browser native selection over selected elements and is hidden to the user.\n\t * This way, no native selection UI artifacts are displayed to the user and selection over elements can be\n\t * represented in other way, for example by applying proper CSS class.\n\t *\n\t * Additionally fake's selection label can be provided. It will be used to describe fake selection in DOM\n\t * (and be properly handled by screen readers).\n\t *\n\t *\t\t// Creates fake selection with label.\n\t *\t\tconst selection = writer.createSelection( range, { fake: true, label: 'foo' } );\n\t *\n\t * @param {module:engine/view/selection~Selectable} [selectable=null]\n\t * @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] Offset or place when selectable is an `Item`.\n\t * @param {Object} [options]\n\t * @param {Boolean} [options.backward] Sets this selection instance to be backward.\n\t * @param {Boolean} [options.fake] Sets this selection instance to be marked as `fake`.\n\t * @param {String} [options.label] Label for the fake selection.\n\t * @returns {module:engine/view/selection~Selection}\n\t */\n\tcreateSelection( selectable, placeOrOffset, options ) {\n\t\treturn new Selection( selectable, placeOrOffset, options );\n\t}\n\n\t/**\n\t * Inserts a node or nodes at the specified position. Takes care of breaking attributes before insertion\n\t * and merging them afterwards if requested by the breakAttributes param.\n\t *\n\t * @private\n\t * @param {module:engine/view/position~Position} position Insertion position.\n\t * @param {module:engine/view/text~Text|module:engine/view/attributeelement~AttributeElement|\n\t * module:engine/view/containerelement~ContainerElement|module:engine/view/emptyelement~EmptyElement|\n\t * module:engine/view/rawelement~RawElement|module:engine/view/uielement~UIElement|\n\t * Iterable.} nodes Node or nodes to insert.\n\t * @param {Boolean} breakAttributes Whether attributes should be broken.\n\t * @returns {module:engine/view/range~Range} Range around inserted nodes.\n\t */\n\t_insertNodes( position, nodes, breakAttributes ) {\n\t\tlet parentElement;\n\n\t\t// Break attributes on nodes that do exist in the model tree so they can have attributes, other elements\n\t\t// can't have an attribute in model and won't get wrapped with an AttributeElement while down-casted.\n\t\tif ( breakAttributes ) {\n\t\t\tparentElement = getParentContainer( position );\n\t\t} else {\n\t\t\tparentElement = position.parent.is( '$text' ) ? position.parent.parent : position.parent;\n\t\t}\n\n\t\tif ( !parentElement ) {\n\t\t\t/**\n\t\t\t * Position's parent container cannot be found.\n\t\t\t *\n\t\t\t * @error view-writer-invalid-position-container\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'view-writer-invalid-position-container',\n\t\t\t\tthis.document\n\t\t\t);\n\t\t}\n\n\t\tlet insertionPosition;\n\n\t\tif ( breakAttributes ) {\n\t\t\tinsertionPosition = this._breakAttributes( position, true );\n\t\t} else {\n\t\t\tinsertionPosition = position.parent.is( '$text' ) ? breakTextNode( position ) : position;\n\t\t}\n\n\t\tconst length = parentElement._insertChild( insertionPosition.offset, nodes );\n\n\t\tfor ( const node of nodes ) {\n\t\t\tthis._addToClonedElementsGroup( node );\n\t\t}\n\n\t\tconst endPosition = insertionPosition.getShiftedBy( length );\n\t\tconst start = this.mergeAttributes( insertionPosition );\n\n\t\t// If start position was merged - move end position.\n\t\tif ( !start.isEqual( insertionPosition ) ) {\n\t\t\tendPosition.offset--;\n\t\t}\n\n\t\tconst end = this.mergeAttributes( endPosition );\n\n\t\treturn new Range( start, end );\n\t}\n\n\t/**\n\t * Wraps children with provided `wrapElement`. Only children contained in `parent` element between\n\t * `startOffset` and `endOffset` will be wrapped.\n\t *\n\t * @private\n\t * @param {module:engine/view/element~Element} parent\n\t * @param {Number} startOffset\n\t * @param {Number} endOffset\n\t * @param {module:engine/view/element~Element} wrapElement\n\t */\n\t_wrapChildren( parent, startOffset, endOffset, wrapElement ) {\n\t\tlet i = startOffset;\n\t\tconst wrapPositions = [];\n\n\t\twhile ( i < endOffset ) {\n\t\t\tconst child = parent.getChild( i );\n\t\t\tconst isText = child.is( '$text' );\n\t\t\tconst isAttribute = child.is( 'attributeElement' );\n\t\t\tconst isAllowedInsideAttributeElement = child.isAllowedInsideAttributeElement;\n\n\t\t\t//\n\t\t\t// (In all examples, assume that `wrapElement` is `` element.)\n\t\t\t//\n\t\t\t// Check if `wrapElement` can be joined with the wrapped element. One of requirements is having same name.\n\t\t\t// If possible, join elements.\n\t\t\t//\n\t\t\t//

abc

-->

abc

\n\t\t\t//\n\t\t\tif ( isAttribute && this._wrapAttributeElement( wrapElement, child ) ) {\n\t\t\t\twrapPositions.push( new Position( parent, i ) );\n\t\t\t}\n\t\t\t//\n\t\t\t// Wrap the child if it is not an attribute element or if it is an attribute element that should be inside\n\t\t\t// `wrapElement` (due to priority).\n\t\t\t//\n\t\t\t//

abc

-->

abc

\n\t\t\t//

abc

-->

abc

\n\t\t\telse if ( isText || isAllowedInsideAttributeElement || ( isAttribute && shouldABeOutsideB( wrapElement, child ) ) ) {\n\t\t\t\t// Clone attribute.\n\t\t\t\tconst newAttribute = wrapElement._clone();\n\n\t\t\t\t// Wrap current node with new attribute.\n\t\t\t\tchild._remove();\n\t\t\t\tnewAttribute._appendChild( child );\n\n\t\t\t\tparent._insertChild( i, newAttribute );\n\t\t\t\tthis._addToClonedElementsGroup( newAttribute );\n\n\t\t\t\twrapPositions.push( new Position( parent, i ) );\n\t\t\t}\n\t\t\t//\n\t\t\t// If other nested attribute is found and it wasn't wrapped (see above), continue wrapping inside it.\n\t\t\t//\n\t\t\t//
-->

abc

\n\t\t\t//\n\t\t\telse if ( isAttribute ) {\n\t\t\t\tthis._wrapChildren( child, 0, child.childCount, wrapElement );\n\t\t\t}\n\n\t\t\ti++;\n\t\t}\n\n\t\t// Merge at each wrap.\n\t\tlet offsetChange = 0;\n\n\t\tfor ( const position of wrapPositions ) {\n\t\t\tposition.offset -= offsetChange;\n\n\t\t\t// Do not merge with elements outside selected children.\n\t\t\tif ( position.offset == startOffset ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst newPosition = this.mergeAttributes( position );\n\n\t\t\t// If nodes were merged - other merge offsets will change.\n\t\t\tif ( !newPosition.isEqual( position ) ) {\n\t\t\t\toffsetChange++;\n\t\t\t\tendOffset--;\n\t\t\t}\n\t\t}\n\n\t\treturn Range._createFromParentsAndOffsets( parent, startOffset, parent, endOffset );\n\t}\n\n\t/**\n\t * Unwraps children from provided `unwrapElement`. Only children contained in `parent` element between\n\t * `startOffset` and `endOffset` will be unwrapped.\n\t *\n\t * @private\n\t * @param {module:engine/view/element~Element} parent\n\t * @param {Number} startOffset\n\t * @param {Number} endOffset\n\t * @param {module:engine/view/element~Element} unwrapElement\n\t */\n\t_unwrapChildren( parent, startOffset, endOffset, unwrapElement ) {\n\t\tlet i = startOffset;\n\t\tconst unwrapPositions = [];\n\n\t\t// Iterate over each element between provided offsets inside parent.\n\t\t// We don't use tree walker or range iterator because we will be removing and merging potentially multiple nodes,\n\t\t// so it could get messy. It is safer to it manually in this case.\n\t\twhile ( i < endOffset ) {\n\t\t\tconst child = parent.getChild( i );\n\n\t\t\t// Skip all text nodes. There should be no container element's here either.\n\t\t\tif ( !child.is( 'attributeElement' ) ) {\n\t\t\t\ti++;\n\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t//\n\t\t\t// (In all examples, assume that `unwrapElement` is `` element.)\n\t\t\t//\n\t\t\t// If the child is similar to the given attribute element, unwrap it - it will be completely removed.\n\t\t\t//\n\t\t\t//

abcxyz

-->

abcxyz

\n\t\t\t//\n\t\t\tif ( child.isSimilar( unwrapElement ) ) {\n\t\t\t\tconst unwrapped = child.getChildren();\n\t\t\t\tconst count = child.childCount;\n\n\t\t\t\t// Replace wrapper element with its children\n\t\t\t\tchild._remove();\n\t\t\t\tparent._insertChild( i, unwrapped );\n\n\t\t\t\tthis._removeFromClonedElementsGroup( child );\n\n\t\t\t\t// Save start and end position of moved items.\n\t\t\t\tunwrapPositions.push(\n\t\t\t\t\tnew Position( parent, i ),\n\t\t\t\t\tnew Position( parent, i + count )\n\t\t\t\t);\n\n\t\t\t\t// Skip elements that were unwrapped. Assuming there won't be another element to unwrap in child elements.\n\t\t\t\ti += count;\n\t\t\t\tendOffset += count - 1;\n\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t//\n\t\t\t// If the child is not similar but is an attribute element, try partial unwrapping - remove the same attributes/styles/classes.\n\t\t\t// Partial unwrapping will happen only if the elements have the same name.\n\t\t\t//\n\t\t\t//

abcxyz

-->

abcxyz

\n\t\t\t//

abcxyz

-->

abcxyz

\n\t\t\t//\n\t\t\tif ( this._unwrapAttributeElement( unwrapElement, child ) ) {\n\t\t\t\tunwrapPositions.push(\n\t\t\t\t\tnew Position( parent, i ),\n\t\t\t\t\tnew Position( parent, i + 1 )\n\t\t\t\t);\n\n\t\t\t\ti++;\n\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t//\n\t\t\t// If other nested attribute is found, look through it's children for elements to unwrap.\n\t\t\t//\n\t\t\t//

abc

-->

abc

\n\t\t\t//\n\t\t\tthis._unwrapChildren( child, 0, child.childCount, unwrapElement );\n\n\t\t\ti++;\n\t\t}\n\n\t\t// Merge at each unwrap.\n\t\tlet offsetChange = 0;\n\n\t\tfor ( const position of unwrapPositions ) {\n\t\t\tposition.offset -= offsetChange;\n\n\t\t\t// Do not merge with elements outside selected children.\n\t\t\tif ( position.offset == startOffset || position.offset == endOffset ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst newPosition = this.mergeAttributes( position );\n\n\t\t\t// If nodes were merged - other merge offsets will change.\n\t\t\tif ( !newPosition.isEqual( position ) ) {\n\t\t\t\toffsetChange++;\n\t\t\t\tendOffset--;\n\t\t\t}\n\t\t}\n\n\t\treturn Range._createFromParentsAndOffsets( parent, startOffset, parent, endOffset );\n\t}\n\n\t/**\n\t * Helper function for `view.writer.wrap`. Wraps range with provided attribute element.\n\t * This method will also merge newly added attribute element with its siblings whenever possible.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError} `view-writer-wrap-invalid-attribute` when passed attribute element is not\n\t * an instance of {@link module:engine/view/attributeelement~AttributeElement AttributeElement}.\n\t *\n\t * @private\n\t * @param {module:engine/view/range~Range} range\n\t * @param {module:engine/view/attributeelement~AttributeElement} attribute\n\t * @returns {module:engine/view/range~Range} New range after wrapping, spanning over wrapping attribute element.\n\t */\n\t_wrapRange( range, attribute ) {\n\t\t// Break attributes at range start and end.\n\t\tconst { start: breakStart, end: breakEnd } = this._breakAttributesRange( range, true );\n\t\tconst parentContainer = breakStart.parent;\n\n\t\t// Wrap all children with attribute.\n\t\tconst newRange = this._wrapChildren( parentContainer, breakStart.offset, breakEnd.offset, attribute );\n\n\t\t// Merge attributes at the both ends and return a new range.\n\t\tconst start = this.mergeAttributes( newRange.start );\n\n\t\t// If start position was merged - move end position back.\n\t\tif ( !start.isEqual( newRange.start ) ) {\n\t\t\tnewRange.end.offset--;\n\t\t}\n\t\tconst end = this.mergeAttributes( newRange.end );\n\n\t\treturn new Range( start, end );\n\t}\n\n\t/**\n\t * Helper function for {@link #wrap}. Wraps position with provided attribute element.\n\t * This method will also merge newly added attribute element with its siblings whenever possible.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError} `view-writer-wrap-invalid-attribute` when passed attribute element is not\n\t * an instance of {@link module:engine/view/attributeelement~AttributeElement AttributeElement}.\n\t *\n\t * @private\n\t * @param {module:engine/view/position~Position} position\n\t * @param {module:engine/view/attributeelement~AttributeElement} attribute\n\t * @returns {module:engine/view/position~Position} New position after wrapping.\n\t */\n\t_wrapPosition( position, attribute ) {\n\t\t// Return same position when trying to wrap with attribute similar to position parent.\n\t\tif ( attribute.isSimilar( position.parent ) ) {\n\t\t\treturn movePositionToTextNode( position.clone() );\n\t\t}\n\n\t\t// When position is inside text node - break it and place new position between two text nodes.\n\t\tif ( position.parent.is( '$text' ) ) {\n\t\t\tposition = breakTextNode( position );\n\t\t}\n\n\t\t// Create fake element that will represent position, and will not be merged with other attributes.\n\t\tconst fakePosition = this.createAttributeElement();\n\t\tfakePosition._priority = Number.POSITIVE_INFINITY;\n\t\tfakePosition.isSimilar = () => false;\n\n\t\t// Insert fake element in position location.\n\t\tposition.parent._insertChild( position.offset, fakePosition );\n\n\t\t// Range around inserted fake attribute element.\n\t\tconst wrapRange = new Range( position, position.getShiftedBy( 1 ) );\n\n\t\t// Wrap fake element with attribute (it will also merge if possible).\n\t\tthis.wrap( wrapRange, attribute );\n\n\t\t// Remove fake element and place new position there.\n\t\tconst newPosition = new Position( fakePosition.parent, fakePosition.index );\n\t\tfakePosition._remove();\n\n\t\t// If position is placed between text nodes - merge them and return position inside.\n\t\tconst nodeBefore = newPosition.nodeBefore;\n\t\tconst nodeAfter = newPosition.nodeAfter;\n\n\t\tif ( nodeBefore instanceof Text && nodeAfter instanceof Text ) {\n\t\t\treturn mergeTextNodes( nodeBefore, nodeAfter );\n\t\t}\n\n\t\t// If position is next to text node - move position inside.\n\t\treturn movePositionToTextNode( newPosition );\n\t}\n\n\t/**\n\t * \tWraps one {@link module:engine/view/attributeelement~AttributeElement AttributeElement} into another by\n\t * \tmerging them if possible. When merging is possible - all attributes, styles and classes are moved from wrapper\n\t * \telement to element being wrapped.\n\t *\n\t * \t@private\n\t * \t@param {module:engine/view/attributeelement~AttributeElement} wrapper Wrapper AttributeElement.\n\t * \t@param {module:engine/view/attributeelement~AttributeElement} toWrap AttributeElement to wrap using wrapper element.\n\t * \t@returns {Boolean} Returns `true` if elements are merged.\n\t */\n\t_wrapAttributeElement( wrapper, toWrap ) {\n\t\tif ( !canBeJoined( wrapper, toWrap ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Can't merge if name or priority differs.\n\t\tif ( wrapper.name !== toWrap.name || wrapper.priority !== toWrap.priority ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Check if attributes can be merged.\n\t\tfor ( const key of wrapper.getAttributeKeys() ) {\n\t\t\t// Classes and styles should be checked separately.\n\t\t\tif ( key === 'class' || key === 'style' ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// If some attributes are different we cannot wrap.\n\t\t\tif ( toWrap.hasAttribute( key ) && toWrap.getAttribute( key ) !== wrapper.getAttribute( key ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\t// Check if styles can be merged.\n\t\tfor ( const key of wrapper.getStyleNames() ) {\n\t\t\tif ( toWrap.hasStyle( key ) && toWrap.getStyle( key ) !== wrapper.getStyle( key ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\t// Move all attributes/classes/styles from wrapper to wrapped AttributeElement.\n\t\tfor ( const key of wrapper.getAttributeKeys() ) {\n\t\t\t// Classes and styles should be checked separately.\n\t\t\tif ( key === 'class' || key === 'style' ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Move only these attributes that are not present - other are similar.\n\t\t\tif ( !toWrap.hasAttribute( key ) ) {\n\t\t\t\tthis.setAttribute( key, wrapper.getAttribute( key ), toWrap );\n\t\t\t}\n\t\t}\n\n\t\tfor ( const key of wrapper.getStyleNames() ) {\n\t\t\tif ( !toWrap.hasStyle( key ) ) {\n\t\t\t\tthis.setStyle( key, wrapper.getStyle( key ), toWrap );\n\t\t\t}\n\t\t}\n\n\t\tfor ( const key of wrapper.getClassNames() ) {\n\t\t\tif ( !toWrap.hasClass( key ) ) {\n\t\t\t\tthis.addClass( key, toWrap );\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Unwraps {@link module:engine/view/attributeelement~AttributeElement AttributeElement} from another by removing\n\t * corresponding attributes, classes and styles. All attributes, classes and styles from wrapper should be present\n\t * inside element being unwrapped.\n\t *\n\t * @private\n\t * @param {module:engine/view/attributeelement~AttributeElement} wrapper Wrapper AttributeElement.\n\t * @param {module:engine/view/attributeelement~AttributeElement} toUnwrap AttributeElement to unwrap using wrapper element.\n\t * @returns {Boolean} Returns `true` if elements are unwrapped.\n\t **/\n\t_unwrapAttributeElement( wrapper, toUnwrap ) {\n\t\tif ( !canBeJoined( wrapper, toUnwrap ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Can't unwrap if name or priority differs.\n\t\tif ( wrapper.name !== toUnwrap.name || wrapper.priority !== toUnwrap.priority ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Check if AttributeElement has all wrapper attributes.\n\t\tfor ( const key of wrapper.getAttributeKeys() ) {\n\t\t\t// Classes and styles should be checked separately.\n\t\t\tif ( key === 'class' || key === 'style' ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// If some attributes are missing or different we cannot unwrap.\n\t\t\tif ( !toUnwrap.hasAttribute( key ) || toUnwrap.getAttribute( key ) !== wrapper.getAttribute( key ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\t// Check if AttributeElement has all wrapper classes.\n\t\tif ( !toUnwrap.hasClass( ...wrapper.getClassNames() ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Check if AttributeElement has all wrapper styles.\n\t\tfor ( const key of wrapper.getStyleNames() ) {\n\t\t\t// If some styles are missing or different we cannot unwrap.\n\t\t\tif ( !toUnwrap.hasStyle( key ) || toUnwrap.getStyle( key ) !== wrapper.getStyle( key ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\t// Remove all wrapper's attributes from unwrapped element.\n\t\tfor ( const key of wrapper.getAttributeKeys() ) {\n\t\t\t// Classes and styles should be checked separately.\n\t\t\tif ( key === 'class' || key === 'style' ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tthis.removeAttribute( key, toUnwrap );\n\t\t}\n\n\t\t// Remove all wrapper's classes from unwrapped element.\n\t\tthis.removeClass( Array.from( wrapper.getClassNames() ), toUnwrap );\n\n\t\t// Remove all wrapper's styles from unwrapped element.\n\t\tthis.removeStyle( Array.from( wrapper.getStyleNames() ), toUnwrap );\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Helper function used by other `DowncastWriter` methods. Breaks attribute elements at the boundaries of given range.\n\t *\n\t * @private\n\t * @param {module:engine/view/range~Range} range Range which `start` and `end` positions will be used to break attributes.\n\t * @param {Boolean} [forceSplitText=false] If set to `true`, will break text nodes even if they are directly in container element.\n\t * This behavior will result in incorrect view state, but is needed by other view writing methods which then fixes view state.\n\t * @returns {module:engine/view/range~Range} New range with located at break positions.\n\t */\n\t_breakAttributesRange( range, forceSplitText = false ) {\n\t\tconst rangeStart = range.start;\n\t\tconst rangeEnd = range.end;\n\n\t\tvalidateRangeContainer( range, this.document );\n\n\t\t// Break at the collapsed position. Return new collapsed range.\n\t\tif ( range.isCollapsed ) {\n\t\t\tconst position = this._breakAttributes( range.start, forceSplitText );\n\n\t\t\treturn new Range( position, position );\n\t\t}\n\n\t\tconst breakEnd = this._breakAttributes( rangeEnd, forceSplitText );\n\t\tconst count = breakEnd.parent.childCount;\n\t\tconst breakStart = this._breakAttributes( rangeStart, forceSplitText );\n\n\t\t// Calculate new break end offset.\n\t\tbreakEnd.offset += breakEnd.parent.childCount - count;\n\n\t\treturn new Range( breakStart, breakEnd );\n\t}\n\n\t/**\n\t * Helper function used by other `DowncastWriter` methods. Breaks attribute elements at given position.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-cannot-break-empty-element` when break position\n\t * is placed inside {@link module:engine/view/emptyelement~EmptyElement EmptyElement}.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-cannot-break-ui-element` when break position\n\t * is placed inside {@link module:engine/view/uielement~UIElement UIElement}.\n\t *\n\t * @private\n\t * @param {module:engine/view/position~Position} position Position where to break attributes.\n\t * @param {Boolean} [forceSplitText=false] If set to `true`, will break text nodes even if they are directly in container element.\n\t * This behavior will result in incorrect view state, but is needed by other view writing methods which then fixes view state.\n\t * @returns {module:engine/view/position~Position} New position after breaking the attributes.\n\t */\n\t_breakAttributes( position, forceSplitText = false ) {\n\t\tconst positionOffset = position.offset;\n\t\tconst positionParent = position.parent;\n\n\t\t// If position is placed inside EmptyElement - throw an exception as we cannot break inside.\n\t\tif ( position.parent.is( 'emptyElement' ) ) {\n\t\t\t/**\n\t\t\t * Cannot break an `EmptyElement` instance.\n\t\t\t *\n\t\t\t * This error is thrown if\n\t\t\t * {@link module:engine/view/downcastwriter~DowncastWriter#breakAttributes `DowncastWriter#breakAttributes()`}\n\t\t\t * was executed in an incorrect position.\n\t\t\t *\n\t\t\t * @error view-writer-cannot-break-empty-element\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-writer-cannot-break-empty-element', this.document );\n\t\t}\n\n\t\t// If position is placed inside UIElement - throw an exception as we cannot break inside.\n\t\tif ( position.parent.is( 'uiElement' ) ) {\n\t\t\t/**\n\t\t\t * Cannot break a `UIElement` instance.\n\t\t\t *\n\t\t\t * This error is thrown if\n\t\t\t * {@link module:engine/view/downcastwriter~DowncastWriter#breakAttributes `DowncastWriter#breakAttributes()`}\n\t\t\t * was executed in an incorrect position.\n\t\t\t *\n\t\t\t * @error view-writer-cannot-break-ui-element\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-writer-cannot-break-ui-element', this.document );\n\t\t}\n\n\t\t// If position is placed inside RawElement - throw an exception as we cannot break inside.\n\t\tif ( position.parent.is( 'rawElement' ) ) {\n\t\t\t/**\n\t\t\t * Cannot break a `RawElement` instance.\n\t\t\t *\n\t\t\t * This error is thrown if\n\t\t\t * {@link module:engine/view/downcastwriter~DowncastWriter#breakAttributes `DowncastWriter#breakAttributes()`}\n\t\t\t * was executed in an incorrect position.\n\t\t\t *\n\t\t\t * @error view-writer-cannot-break-raw-element\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-writer-cannot-break-raw-element', this.document );\n\t\t}\n\n\t\t// There are no attributes to break and text nodes breaking is not forced.\n\t\tif ( !forceSplitText && positionParent.is( '$text' ) && isContainerOrFragment( positionParent.parent ) ) {\n\t\t\treturn position.clone();\n\t\t}\n\n\t\t// Position's parent is container, so no attributes to break.\n\t\tif ( isContainerOrFragment( positionParent ) ) {\n\t\t\treturn position.clone();\n\t\t}\n\n\t\t// Break text and start again in new position.\n\t\tif ( positionParent.is( '$text' ) ) {\n\t\t\treturn this._breakAttributes( breakTextNode( position ), forceSplitText );\n\t\t}\n\n\t\tconst length = positionParent.childCount;\n\n\t\t//

foobar{}

\n\t\t//

foobar[]

\n\t\t//

foobar[]

\n\t\tif ( positionOffset == length ) {\n\t\t\tconst newPosition = new Position( positionParent.parent, positionParent.index + 1 );\n\n\t\t\treturn this._breakAttributes( newPosition, forceSplitText );\n\t\t} else {\n\t\t\t//

foo{}bar

\n\t\t\t//

foo[]bar

\n\t\t\t//

foo{}bar

\n\t\t\tif ( positionOffset === 0 ) {\n\t\t\t\tconst newPosition = new Position( positionParent.parent, positionParent.index );\n\n\t\t\t\treturn this._breakAttributes( newPosition, forceSplitText );\n\t\t\t}\n\t\t\t//

foob{}ar

\n\t\t\t//

foob[]ar

\n\t\t\t//

foob[]ar

\n\t\t\t//

foob[]ar

\n\t\t\telse {\n\t\t\t\tconst offsetAfter = positionParent.index + 1;\n\n\t\t\t\t// Break element.\n\t\t\t\tconst clonedNode = positionParent._clone();\n\n\t\t\t\t// Insert cloned node to position's parent node.\n\t\t\t\tpositionParent.parent._insertChild( offsetAfter, clonedNode );\n\t\t\t\tthis._addToClonedElementsGroup( clonedNode );\n\n\t\t\t\t// Get nodes to move.\n\t\t\t\tconst count = positionParent.childCount - positionOffset;\n\t\t\t\tconst nodesToMove = positionParent._removeChildren( positionOffset, count );\n\n\t\t\t\t// Move nodes to cloned node.\n\t\t\t\tclonedNode._appendChild( nodesToMove );\n\n\t\t\t\t// Create new position to work on.\n\t\t\t\tconst newPosition = new Position( positionParent.parent, offsetAfter );\n\n\t\t\t\treturn this._breakAttributes( newPosition, forceSplitText );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Stores the information that an {@link module:engine/view/attributeelement~AttributeElement attribute element} was\n\t * added to the tree. Saves the reference to the group in the given element and updates the group, so other elements\n\t * from the group now keep a reference to the given attribute element.\n\t *\n\t * The clones group can be obtained using {@link module:engine/view/attributeelement~AttributeElement#getElementsWithSameId}.\n\t *\n\t * Does nothing if added element has no {@link module:engine/view/attributeelement~AttributeElement#id id}.\n\t *\n\t * @private\n\t * @param {module:engine/view/attributeelement~AttributeElement} element Attribute element to save.\n\t */\n\t_addToClonedElementsGroup( element ) {\n\t\t// Add only if the element is in document tree.\n\t\tif ( !element.root.is( 'rootElement' ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Traverse the element's children recursively to find other attribute elements that also might got inserted.\n\t\t// The loop is at the beginning so we can make fast returns later in the code.\n\t\tif ( element.is( 'element' ) ) {\n\t\t\tfor ( const child of element.getChildren() ) {\n\t\t\t\tthis._addToClonedElementsGroup( child );\n\t\t\t}\n\t\t}\n\n\t\tconst id = element.id;\n\n\t\tif ( !id ) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet group = this._cloneGroups.get( id );\n\n\t\tif ( !group ) {\n\t\t\tgroup = new Set();\n\t\t\tthis._cloneGroups.set( id, group );\n\t\t}\n\n\t\tgroup.add( element );\n\t\telement._clonesGroup = group;\n\t}\n\n\t/**\n\t * Removes all the information about the given {@link module:engine/view/attributeelement~AttributeElement attribute element}\n\t * from its clones group.\n\t *\n\t * Keep in mind, that the element will still keep a reference to the group (but the group will not keep a reference to it).\n\t * This allows to reference the whole group even if the element was already removed from the tree.\n\t *\n\t * Does nothing if the element has no {@link module:engine/view/attributeelement~AttributeElement#id id}.\n\t *\n\t * @private\n\t * @param {module:engine/view/attributeelement~AttributeElement} element Attribute element to remove.\n\t */\n\t_removeFromClonedElementsGroup( element ) {\n\t\t// Traverse the element's children recursively to find other attribute elements that also got removed.\n\t\t// The loop is at the beginning so we can make fast returns later in the code.\n\t\tif ( element.is( 'element' ) ) {\n\t\t\tfor ( const child of element.getChildren() ) {\n\t\t\t\tthis._removeFromClonedElementsGroup( child );\n\t\t\t}\n\t\t}\n\n\t\tconst id = element.id;\n\n\t\tif ( !id ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst group = this._cloneGroups.get( id );\n\n\t\tif ( !group ) {\n\t\t\treturn;\n\t\t}\n\n\t\tgroup.delete( element );\n\t\t// Not removing group from element on purpose!\n\t\t// If other parts of code have reference to this element, they will be able to get references to other elements from the group.\n\t}\n}\n\n// Helper function for `view.writer.wrap`. Checks if given element has any children that are not ui elements.\nfunction _hasNonUiChildren( parent ) {\n\treturn Array.from( parent.getChildren() ).some( child => !child.is( 'uiElement' ) );\n}\n\n/**\n * The `attribute` passed to {@link module:engine/view/downcastwriter~DowncastWriter#wrap `DowncastWriter#wrap()`}\n * must be an instance of {@link module:engine/view/attributeelement~AttributeElement `AttributeElement`}.\n *\n * @error view-writer-wrap-invalid-attribute\n */\n\n// Returns first parent container of specified {@link module:engine/view/position~Position Position}.\n// Position's parent node is checked as first, then next parents are checked.\n// Note that {@link module:engine/view/documentfragment~DocumentFragment DocumentFragment} is treated like a container.\n//\n// @param {module:engine/view/position~Position} position Position used as a start point to locate parent container.\n// @returns {module:engine/view/containerelement~ContainerElement|module:engine/view/documentfragment~DocumentFragment|undefined}\n// Parent container element or `undefined` if container is not found.\nfunction getParentContainer( position ) {\n\tlet parent = position.parent;\n\n\twhile ( !isContainerOrFragment( parent ) ) {\n\t\tif ( !parent ) {\n\t\t\treturn undefined;\n\t\t}\n\t\tparent = parent.parent;\n\t}\n\n\treturn parent;\n}\n\n// Checks if first {@link module:engine/view/attributeelement~AttributeElement AttributeElement} provided to the function\n// can be wrapped outside second element. It is done by comparing elements'\n// {@link module:engine/view/attributeelement~AttributeElement#priority priorities}, if both have same priority\n// {@link module:engine/view/element~Element#getIdentity identities} are compared.\n//\n// @param {module:engine/view/attributeelement~AttributeElement} a\n// @param {module:engine/view/attributeelement~AttributeElement} b\n// @returns {Boolean}\nfunction shouldABeOutsideB( a, b ) {\n\tif ( a.priority < b.priority ) {\n\t\treturn true;\n\t} else if ( a.priority > b.priority ) {\n\t\treturn false;\n\t}\n\n\t// When priorities are equal and names are different - use identities.\n\treturn a.getIdentity() < b.getIdentity();\n}\n\n// Returns new position that is moved to near text node. Returns same position if there is no text node before of after\n// specified position.\n//\n//\t\t

foo[]

->

foo{}

\n//\t\t

[]foo

->

{}foo

\n//\n// @param {module:engine/view/position~Position} position\n// @returns {module:engine/view/position~Position} Position located inside text node or same position if there is no text nodes\n// before or after position location.\nfunction movePositionToTextNode( position ) {\n\tconst nodeBefore = position.nodeBefore;\n\n\tif ( nodeBefore && nodeBefore.is( '$text' ) ) {\n\t\treturn new Position( nodeBefore, nodeBefore.data.length );\n\t}\n\n\tconst nodeAfter = position.nodeAfter;\n\n\tif ( nodeAfter && nodeAfter.is( '$text' ) ) {\n\t\treturn new Position( nodeAfter, 0 );\n\t}\n\n\treturn position;\n}\n\n// Breaks text node into two text nodes when possible.\n//\n//\t\t

foo{}bar

->

foo[]bar

\n//\t\t

{}foobar

->

[]foobar

\n//\t\t

foobar{}

->

foobar[]

\n//\n// @param {module:engine/view/position~Position} position Position that need to be placed inside text node.\n// @returns {module:engine/view/position~Position} New position after breaking text node.\nfunction breakTextNode( position ) {\n\tif ( position.offset == position.parent.data.length ) {\n\t\treturn new Position( position.parent.parent, position.parent.index + 1 );\n\t}\n\n\tif ( position.offset === 0 ) {\n\t\treturn new Position( position.parent.parent, position.parent.index );\n\t}\n\n\t// Get part of the text that need to be moved.\n\tconst textToMove = position.parent.data.slice( position.offset );\n\n\t// Leave rest of the text in position's parent.\n\tposition.parent._data = position.parent.data.slice( 0, position.offset );\n\n\t// Insert new text node after position's parent text node.\n\tposition.parent.parent._insertChild( position.parent.index + 1, new Text( position.root.document, textToMove ) );\n\n\t// Return new position between two newly created text nodes.\n\treturn new Position( position.parent.parent, position.parent.index + 1 );\n}\n\n// Merges two text nodes into first node. Removes second node and returns merge position.\n//\n// @param {module:engine/view/text~Text} t1 First text node to merge. Data from second text node will be moved at the end of\n// this text node.\n// @param {module:engine/view/text~Text} t2 Second text node to merge. This node will be removed after merging.\n// @returns {module:engine/view/position~Position} Position after merging text nodes.\nfunction mergeTextNodes( t1, t2 ) {\n\t// Merge text data into first text node and remove second one.\n\tconst nodeBeforeLength = t1.data.length;\n\tt1._data += t2.data;\n\tt2._remove();\n\n\treturn new Position( t1, nodeBeforeLength );\n}\n\n// Checks if provided nodes are valid to insert.\n//\n// Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-insert-invalid-node` when nodes to insert\n// contains instances that are not supported ones (see error description for valid ones.\n//\n// @param Iterable. nodes\n// @param {Object} errorContext\nfunction validateNodesToInsert( nodes, errorContext ) {\n\tfor ( const node of nodes ) {\n\t\tif ( !validNodesToInsert.some( ( validNode => node instanceof validNode ) ) ) { // eslint-disable-line no-use-before-define\n\t\t\t/**\n\t\t\t * One of the nodes to be inserted is of an invalid type.\n\t\t\t *\n\t\t\t * Nodes to be inserted with {@link module:engine/view/downcastwriter~DowncastWriter#insert `DowncastWriter#insert()`} should be\n\t\t\t * of the following types:\n\t\t\t *\n\t\t\t * * {@link module:engine/view/attributeelement~AttributeElement AttributeElement},\n\t\t\t * * {@link module:engine/view/containerelement~ContainerElement ContainerElement},\n\t\t\t * * {@link module:engine/view/emptyelement~EmptyElement EmptyElement},\n\t\t\t * * {@link module:engine/view/uielement~UIElement UIElement},\n\t\t\t * * {@link module:engine/view/rawelement~RawElement RawElement},\n\t\t\t * * {@link module:engine/view/text~Text Text}.\n\t\t\t *\n\t\t\t * @error view-writer-insert-invalid-node-type\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-writer-insert-invalid-node-type', errorContext );\n\t\t}\n\n\t\tif ( !node.is( '$text' ) ) {\n\t\t\tvalidateNodesToInsert( node.getChildren(), errorContext );\n\t\t}\n\t}\n}\n\nconst validNodesToInsert = [ Text, AttributeElement, ContainerElement, EmptyElement, RawElement, UIElement ];\n\n// Checks if node is ContainerElement or DocumentFragment, because in most cases they should be treated the same way.\n//\n// @param {module:engine/view/node~Node} node\n// @returns {Boolean} Returns `true` if node is instance of ContainerElement or DocumentFragment.\nfunction isContainerOrFragment( node ) {\n\treturn node && ( node.is( 'containerElement' ) || node.is( 'documentFragment' ) );\n}\n\n// Checks if {@link module:engine/view/range~Range#start range start} and {@link module:engine/view/range~Range#end range end} are placed\n// inside same {@link module:engine/view/containerelement~ContainerElement container element}.\n// Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-invalid-range-container` when validation fails.\n//\n// @param {module:engine/view/range~Range} range\n// @param {Object} errorContext\nfunction validateRangeContainer( range, errorContext ) {\n\tconst startContainer = getParentContainer( range.start );\n\tconst endContainer = getParentContainer( range.end );\n\n\tif ( !startContainer || !endContainer || startContainer !== endContainer ) {\n\t\t/**\n\t\t * The container of the given range is invalid.\n\t\t *\n\t\t * This may happen if {@link module:engine/view/range~Range#start range start} and\n\t\t * {@link module:engine/view/range~Range#end range end} positions are not placed inside the same container element or\n\t\t * a parent container for these positions cannot be found.\n\t\t *\n\t\t * Methods like {@link module:engine/view/downcastwriter~DowncastWriter#wrap `DowncastWriter#remove()`},\n\t\t * {@link module:engine/view/downcastwriter~DowncastWriter#wrap `DowncastWriter#clean()`},\n\t\t * {@link module:engine/view/downcastwriter~DowncastWriter#wrap `DowncastWriter#wrap()`},\n\t\t * {@link module:engine/view/downcastwriter~DowncastWriter#wrap `DowncastWriter#unwrap()`} need to be called\n\t\t * on a range that has its start and end positions located in the same container element. Both positions can be\n\t\t * nested within other elements (e.g. an attribute element) but the closest container ancestor must be the same.\n\t\t *\n\t\t * @error view-writer-invalid-range-container\n\t\t */\n\t\tthrow new CKEditorError( 'view-writer-invalid-range-container', errorContext );\n\t}\n}\n\n// Checks if two attribute elements can be joined together. Elements can be joined together if, and only if\n// they do not have ids specified.\n//\n// @private\n// @param {module:engine/view/element~Element} a\n// @param {module:engine/view/element~Element} b\n// @returns {Boolean}\nfunction canBeJoined( a, b ) {\n\treturn a.id === null && b.id === null;\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/view/domconverter\n */\n\n/* globals document, Node, NodeFilter, Text */\n\nimport ViewText from './text';\nimport ViewElement from './element';\nimport ViewPosition from './position';\nimport ViewRange from './range';\nimport ViewSelection from './selection';\nimport ViewDocumentFragment from './documentfragment';\nimport ViewTreeWalker from './treewalker';\nimport Matcher from './matcher';\nimport { BR_FILLER, getDataWithoutFiller, INLINE_FILLER_LENGTH, isInlineFiller, NBSP_FILLER, startsWithFiller } from './filler';\n\nimport global from '@ckeditor/ckeditor5-utils/src/dom/global';\nimport indexOf from '@ckeditor/ckeditor5-utils/src/dom/indexof';\nimport getAncestors from '@ckeditor/ckeditor5-utils/src/dom/getancestors';\nimport getCommonAncestor from '@ckeditor/ckeditor5-utils/src/dom/getcommonancestor';\nimport isText from '@ckeditor/ckeditor5-utils/src/dom/istext';\nimport { isElement } from 'lodash-es';\n\n// eslint-disable-next-line new-cap\nconst BR_FILLER_REF = BR_FILLER( document );\n\n/**\n * `DomConverter` is a set of tools to do transformations between DOM nodes and view nodes. It also handles\n * {@link module:engine/view/domconverter~DomConverter#bindElements bindings} between these nodes.\n *\n * An instance of the DOM converter is available under\n * {@link module:engine/view/view~View#domConverter `editor.editing.view.domConverter`}.\n *\n * The DOM converter does not check which nodes should be rendered (use {@link module:engine/view/renderer~Renderer}), does not keep the\n * state of a tree nor keeps the synchronization between the tree view and the DOM tree (use {@link module:engine/view/document~Document}).\n *\n * The DOM converter keeps DOM elements to view element bindings, so when the converter gets destroyed, the bindings are lost.\n * Two converters will keep separate binding maps, so one tree view can be bound with two DOM trees.\n */\nexport default class DomConverter {\n\t/**\n\t * Creates a DOM converter.\n\t *\n\t * @param {module:engine/view/document~Document} document The view document instance.\n\t * @param {Object} options An object with configuration options.\n\t * @param {module:engine/view/filler~BlockFillerMode} [options.blockFillerMode='br'] The type of the block filler to use.\n\t */\n\tconstructor( document, options = {} ) {\n\t\t/**\n\t\t * @readonly\n\t\t * @type {module:engine/view/document~Document}\n\t\t */\n\t\tthis.document = document;\n\n\t\t/**\n\t\t * The mode of a block filler used by the DOM converter.\n\t\t *\n\t\t * @readonly\n\t\t * @member {'br'|'nbsp'} module:engine/view/domconverter~DomConverter#blockFillerMode\n\t\t */\n\t\tthis.blockFillerMode = options.blockFillerMode || 'br';\n\n\t\t/**\n\t\t * Elements which are considered pre-formatted elements.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Array.} module:engine/view/domconverter~DomConverter#preElements\n\t\t */\n\t\tthis.preElements = [ 'pre' ];\n\n\t\t/**\n\t\t * Elements which are considered block elements (and hence should be filled with a\n\t\t * {@link #isBlockFiller block filler}).\n\t\t *\n\t\t * Whether an element is considered a block element also affects handling of trailing whitespaces.\n\t\t *\n\t\t * You can extend this array if you introduce support for block elements which are not yet recognized here.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Array.} module:engine/view/domconverter~DomConverter#blockElements\n\t\t */\n\t\tthis.blockElements = [ 'p', 'div', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'li', 'dd', 'dt', 'figcaption', 'td', 'th' ];\n\n\t\t/**\n\t\t * Block {@link module:engine/view/filler filler} creator, which is used to create all block fillers during the\n\t\t * view-to-DOM conversion and to recognize block fillers during the DOM-to-view conversion.\n\t\t *\n\t\t * @readonly\n\t\t * @private\n\t\t * @member {Function} module:engine/view/domconverter~DomConverter#_blockFiller\n\t\t */\n\t\tthis._blockFiller = this.blockFillerMode == 'br' ? BR_FILLER : NBSP_FILLER;\n\n\t\t/**\n\t\t * The DOM-to-view mapping.\n\t\t *\n\t\t * @private\n\t\t * @member {WeakMap} module:engine/view/domconverter~DomConverter#_domToViewMapping\n\t\t */\n\t\tthis._domToViewMapping = new WeakMap();\n\n\t\t/**\n\t\t * The view-to-DOM mapping.\n\t\t *\n\t\t * @private\n\t\t * @member {WeakMap} module:engine/view/domconverter~DomConverter#_viewToDomMapping\n\t\t */\n\t\tthis._viewToDomMapping = new WeakMap();\n\n\t\t/**\n\t\t * Holds the mapping between fake selection containers and corresponding view selections.\n\t\t *\n\t\t * @private\n\t\t * @member {WeakMap} module:engine/view/domconverter~DomConverter#_fakeSelectionMapping\n\t\t */\n\t\tthis._fakeSelectionMapping = new WeakMap();\n\n\t\t/**\n\t\t * Matcher for view elements whose content should be treated as raw data\n\t\t * and not processed during the conversion from DOM nodes to view elements.\n\t\t *\n\t\t * @private\n\t\t * @type {module:engine/view/matcher~Matcher}\n\t\t */\n\t\tthis._rawContentElementMatcher = new Matcher();\n\n\t\t/**\n\t\t * A set of encountered raw content DOM nodes. It is used for preventing left trimming of the following text node.\n\t\t *\n\t\t * @private\n\t\t * @type {WeakSet.}\n\t\t */\n\t\tthis._encounteredRawContentDomNodes = new WeakSet();\n\t}\n\n\t/**\n\t * Binds a given DOM element that represents fake selection to a **position** of a\n\t * {@link module:engine/view/documentselection~DocumentSelection document selection}.\n\t * Document selection copy is stored and can be retrieved by the\n\t * {@link module:engine/view/domconverter~DomConverter#fakeSelectionToView} method.\n\t *\n\t * @param {HTMLElement} domElement\n\t * @param {module:engine/view/documentselection~DocumentSelection} viewDocumentSelection\n\t */\n\tbindFakeSelection( domElement, viewDocumentSelection ) {\n\t\tthis._fakeSelectionMapping.set( domElement, new ViewSelection( viewDocumentSelection ) );\n\t}\n\n\t/**\n\t * Returns a {@link module:engine/view/selection~Selection view selection} instance corresponding to a given\n\t * DOM element that represents fake selection. Returns `undefined` if binding to the given DOM element does not exist.\n\t *\n\t * @param {HTMLElement} domElement\n\t * @returns {module:engine/view/selection~Selection|undefined}\n\t */\n\tfakeSelectionToView( domElement ) {\n\t\treturn this._fakeSelectionMapping.get( domElement );\n\t}\n\n\t/**\n\t * Binds DOM and view elements, so it will be possible to get corresponding elements using\n\t * {@link module:engine/view/domconverter~DomConverter#mapDomToView} and\n\t * {@link module:engine/view/domconverter~DomConverter#mapViewToDom}.\n\t *\n\t * @param {HTMLElement} domElement The DOM element to bind.\n\t * @param {module:engine/view/element~Element} viewElement The view element to bind.\n\t */\n\tbindElements( domElement, viewElement ) {\n\t\tthis._domToViewMapping.set( domElement, viewElement );\n\t\tthis._viewToDomMapping.set( viewElement, domElement );\n\t}\n\n\t/**\n\t * Unbinds a given DOM element from the view element it was bound to. Unbinding is deep, meaning that all children of\n\t * the DOM element will be unbound too.\n\t *\n\t * @param {HTMLElement} domElement The DOM element to unbind.\n\t */\n\tunbindDomElement( domElement ) {\n\t\tconst viewElement = this._domToViewMapping.get( domElement );\n\n\t\tif ( viewElement ) {\n\t\t\tthis._domToViewMapping.delete( domElement );\n\t\t\tthis._viewToDomMapping.delete( viewElement );\n\n\t\t\tfor ( const child of domElement.childNodes ) {\n\t\t\t\tthis.unbindDomElement( child );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Binds DOM and view document fragments, so it will be possible to get corresponding document fragments using\n\t * {@link module:engine/view/domconverter~DomConverter#mapDomToView} and\n\t * {@link module:engine/view/domconverter~DomConverter#mapViewToDom}.\n\t *\n\t * @param {DocumentFragment} domFragment The DOM document fragment to bind.\n\t * @param {module:engine/view/documentfragment~DocumentFragment} viewFragment The view document fragment to bind.\n\t */\n\tbindDocumentFragments( domFragment, viewFragment ) {\n\t\tthis._domToViewMapping.set( domFragment, viewFragment );\n\t\tthis._viewToDomMapping.set( viewFragment, domFragment );\n\t}\n\n\t/**\n\t * Converts the view to the DOM. For all text nodes, not bound elements and document fragments new items will\n\t * be created. For bound elements and document fragments the method will return corresponding items.\n\t *\n\t * @param {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment} viewNode\n\t * View node or document fragment to transform.\n\t * @param {Document} domDocument Document which will be used to create DOM nodes.\n\t * @param {Object} [options] Conversion options.\n\t * @param {Boolean} [options.bind=false] Determines whether new elements will be bound.\n\t * @param {Boolean} [options.withChildren=true] If `true`, node's and document fragment's children will be converted too.\n\t * @returns {Node|DocumentFragment} Converted node or DocumentFragment.\n\t */\n\tviewToDom( viewNode, domDocument, options = {} ) {\n\t\tif ( viewNode.is( '$text' ) ) {\n\t\t\tconst textData = this._processDataFromViewText( viewNode );\n\n\t\t\treturn domDocument.createTextNode( textData );\n\t\t} else {\n\t\t\tif ( this.mapViewToDom( viewNode ) ) {\n\t\t\t\treturn this.mapViewToDom( viewNode );\n\t\t\t}\n\n\t\t\tlet domElement;\n\n\t\t\tif ( viewNode.is( 'documentFragment' ) ) {\n\t\t\t\t// Create DOM document fragment.\n\t\t\t\tdomElement = domDocument.createDocumentFragment();\n\n\t\t\t\tif ( options.bind ) {\n\t\t\t\t\tthis.bindDocumentFragments( domElement, viewNode );\n\t\t\t\t}\n\t\t\t} else if ( viewNode.is( 'uiElement' ) ) {\n\t\t\t\t// UIElement has its own render() method (see #799).\n\t\t\t\tdomElement = viewNode.render( domDocument );\n\n\t\t\t\tif ( options.bind ) {\n\t\t\t\t\tthis.bindElements( domElement, viewNode );\n\t\t\t\t}\n\n\t\t\t\treturn domElement;\n\t\t\t} else {\n\t\t\t\t// Create DOM element.\n\t\t\t\tif ( viewNode.hasAttribute( 'xmlns' ) ) {\n\t\t\t\t\tdomElement = domDocument.createElementNS( viewNode.getAttribute( 'xmlns' ), viewNode.name );\n\t\t\t\t} else {\n\t\t\t\t\tdomElement = domDocument.createElement( viewNode.name );\n\t\t\t\t}\n\n\t\t\t\t// RawElement take care of their children in RawElement#render() method which can be customized\n\t\t\t\t// (see https://github.com/ckeditor/ckeditor5/issues/4469).\n\t\t\t\tif ( viewNode.is( 'rawElement' ) ) {\n\t\t\t\t\tviewNode.render( domElement );\n\t\t\t\t}\n\n\t\t\t\tif ( options.bind ) {\n\t\t\t\t\tthis.bindElements( domElement, viewNode );\n\t\t\t\t}\n\n\t\t\t\t// Copy element's attributes.\n\t\t\t\tfor ( const key of viewNode.getAttributeKeys() ) {\n\t\t\t\t\tdomElement.setAttribute( key, viewNode.getAttribute( key ) );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( options.withChildren !== false ) {\n\t\t\t\tfor ( const child of this.viewChildrenToDom( viewNode, domDocument, options ) ) {\n\t\t\t\t\tdomElement.appendChild( child );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn domElement;\n\t\t}\n\t}\n\n\t/**\n\t * Converts children of the view element to DOM using the\n\t * {@link module:engine/view/domconverter~DomConverter#viewToDom} method.\n\t * Additionally, this method adds block {@link module:engine/view/filler filler} to the list of children, if needed.\n\t *\n\t * @param {module:engine/view/element~Element|module:engine/view/documentfragment~DocumentFragment} viewElement Parent view element.\n\t * @param {Document} domDocument Document which will be used to create DOM nodes.\n\t * @param {Object} options See {@link module:engine/view/domconverter~DomConverter#viewToDom} options parameter.\n\t * @returns {Iterable.} DOM nodes.\n\t */\n\t* viewChildrenToDom( viewElement, domDocument, options = {} ) {\n\t\tconst fillerPositionOffset = viewElement.getFillerOffset && viewElement.getFillerOffset();\n\t\tlet offset = 0;\n\n\t\tfor ( const childView of viewElement.getChildren() ) {\n\t\t\tif ( fillerPositionOffset === offset ) {\n\t\t\t\tyield this._blockFiller( domDocument );\n\t\t\t}\n\n\t\t\tyield this.viewToDom( childView, domDocument, options );\n\n\t\t\toffset++;\n\t\t}\n\n\t\tif ( fillerPositionOffset === offset ) {\n\t\t\tyield this._blockFiller( domDocument );\n\t\t}\n\t}\n\n\t/**\n\t * Converts view {@link module:engine/view/range~Range} to DOM range.\n\t * Inline and block {@link module:engine/view/filler fillers} are handled during the conversion.\n\t *\n\t * @param {module:engine/view/range~Range} viewRange View range.\n\t * @returns {Range} DOM range.\n\t */\n\tviewRangeToDom( viewRange ) {\n\t\tconst domStart = this.viewPositionToDom( viewRange.start );\n\t\tconst domEnd = this.viewPositionToDom( viewRange.end );\n\n\t\tconst domRange = document.createRange();\n\t\tdomRange.setStart( domStart.parent, domStart.offset );\n\t\tdomRange.setEnd( domEnd.parent, domEnd.offset );\n\n\t\treturn domRange;\n\t}\n\n\t/**\n\t * Converts view {@link module:engine/view/position~Position} to DOM parent and offset.\n\t *\n\t * Inline and block {@link module:engine/view/filler fillers} are handled during the conversion.\n\t * If the converted position is directly before inline filler it is moved inside the filler.\n\t *\n\t * @param {module:engine/view/position~Position} viewPosition View position.\n\t * @returns {Object|null} position DOM position or `null` if view position could not be converted to DOM.\n\t * @returns {Node} position.parent DOM position parent.\n\t * @returns {Number} position.offset DOM position offset.\n\t */\n\tviewPositionToDom( viewPosition ) {\n\t\tconst viewParent = viewPosition.parent;\n\n\t\tif ( viewParent.is( '$text' ) ) {\n\t\t\tconst domParent = this.findCorrespondingDomText( viewParent );\n\n\t\t\tif ( !domParent ) {\n\t\t\t\t// Position is in a view text node that has not been rendered to DOM yet.\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tlet offset = viewPosition.offset;\n\n\t\t\tif ( startsWithFiller( domParent ) ) {\n\t\t\t\toffset += INLINE_FILLER_LENGTH;\n\t\t\t}\n\n\t\t\treturn { parent: domParent, offset };\n\t\t} else {\n\t\t\t// viewParent is instance of ViewElement.\n\t\t\tlet domParent, domBefore, domAfter;\n\n\t\t\tif ( viewPosition.offset === 0 ) {\n\t\t\t\tdomParent = this.mapViewToDom( viewParent );\n\n\t\t\t\tif ( !domParent ) {\n\t\t\t\t\t// Position is in a view element that has not been rendered to DOM yet.\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\tdomAfter = domParent.childNodes[ 0 ];\n\t\t\t} else {\n\t\t\t\tconst nodeBefore = viewPosition.nodeBefore;\n\n\t\t\t\tdomBefore = nodeBefore.is( '$text' ) ?\n\t\t\t\t\tthis.findCorrespondingDomText( nodeBefore ) :\n\t\t\t\t\tthis.mapViewToDom( viewPosition.nodeBefore );\n\n\t\t\t\tif ( !domBefore ) {\n\t\t\t\t\t// Position is after a view element that has not been rendered to DOM yet.\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\tdomParent = domBefore.parentNode;\n\t\t\t\tdomAfter = domBefore.nextSibling;\n\t\t\t}\n\n\t\t\t// If there is an inline filler at position return position inside the filler. We should never return\n\t\t\t// the position before the inline filler.\n\t\t\tif ( isText( domAfter ) && startsWithFiller( domAfter ) ) {\n\t\t\t\treturn { parent: domAfter, offset: INLINE_FILLER_LENGTH };\n\t\t\t}\n\n\t\t\tconst offset = domBefore ? indexOf( domBefore ) + 1 : 0;\n\n\t\t\treturn { parent: domParent, offset };\n\t\t}\n\t}\n\n\t/**\n\t * Converts DOM to view. For all text nodes, not bound elements and document fragments new items will\n\t * be created. For bound elements and document fragments function will return corresponding items. For\n\t * {@link module:engine/view/filler fillers} `null` will be returned.\n\t * For all DOM elements rendered by {@link module:engine/view/uielement~UIElement} that UIElement will be returned.\n\t *\n\t * @param {Node|DocumentFragment} domNode DOM node or document fragment to transform.\n\t * @param {Object} [options] Conversion options.\n\t * @param {Boolean} [options.bind=false] Determines whether new elements will be bound.\n\t * @param {Boolean} [options.withChildren=true] If `true`, node's and document fragment's children will be converted too.\n\t * @param {Boolean} [options.keepOriginalCase=false] If `false`, node's tag name will be converter to lower case.\n\t * @returns {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment|null} Converted node or document fragment\n\t * or `null` if DOM node is a {@link module:engine/view/filler filler} or the given node is an empty text node.\n\t */\n\tdomToView( domNode, options = {} ) {\n\t\tif ( this.isBlockFiller( domNode, this.blockFillerMode ) ) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// When node is inside a UIElement or a RawElement return that parent as it's view representation.\n\t\tconst hostElement = this.getHostViewElement( domNode );\n\n\t\tif ( hostElement ) {\n\t\t\treturn hostElement;\n\t\t}\n\n\t\tif ( isText( domNode ) ) {\n\t\t\tif ( isInlineFiller( domNode ) ) {\n\t\t\t\treturn null;\n\t\t\t} else {\n\t\t\t\tconst textData = this._processDataFromDomText( domNode );\n\n\t\t\t\treturn textData === '' ? null : new ViewText( this.document, textData );\n\t\t\t}\n\t\t} else if ( this.isComment( domNode ) ) {\n\t\t\treturn null;\n\t\t} else {\n\t\t\tif ( this.mapDomToView( domNode ) ) {\n\t\t\t\treturn this.mapDomToView( domNode );\n\t\t\t}\n\n\t\t\tlet viewElement;\n\n\t\t\tif ( this.isDocumentFragment( domNode ) ) {\n\t\t\t\t// Create view document fragment.\n\t\t\t\tviewElement = new ViewDocumentFragment( this.document );\n\n\t\t\t\tif ( options.bind ) {\n\t\t\t\t\tthis.bindDocumentFragments( domNode, viewElement );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Create view element.\n\t\t\t\tconst viewName = options.keepOriginalCase ? domNode.tagName : domNode.tagName.toLowerCase();\n\t\t\t\tviewElement = new ViewElement( this.document, viewName );\n\n\t\t\t\tif ( options.bind ) {\n\t\t\t\t\tthis.bindElements( domNode, viewElement );\n\t\t\t\t}\n\n\t\t\t\t// Copy element's attributes.\n\t\t\t\tconst attrs = domNode.attributes;\n\n\t\t\t\tfor ( let i = attrs.length - 1; i >= 0; i-- ) {\n\t\t\t\t\tviewElement._setAttribute( attrs[ i ].name, attrs[ i ].value );\n\t\t\t\t}\n\n\t\t\t\t// Treat this element's content as a raw data if it was registered as such.\n\t\t\t\tif ( options.withChildren !== false && this._rawContentElementMatcher.match( viewElement ) ) {\n\t\t\t\t\tviewElement._setCustomProperty( '$rawContent', domNode.innerHTML );\n\n\t\t\t\t\t// Store a DOM node to prevent left trimming of the following text node.\n\t\t\t\t\tthis._encounteredRawContentDomNodes.add( domNode );\n\n\t\t\t\t\treturn viewElement;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( options.withChildren !== false ) {\n\t\t\t\tfor ( const child of this.domChildrenToView( domNode, options ) ) {\n\t\t\t\t\tviewElement._appendChild( child );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn viewElement;\n\t\t}\n\t}\n\n\t/**\n\t * Converts children of the DOM element to view nodes using\n\t * the {@link module:engine/view/domconverter~DomConverter#domToView} method.\n\t * Additionally this method omits block {@link module:engine/view/filler filler}, if it exists in the DOM parent.\n\t *\n\t * @param {HTMLElement} domElement Parent DOM element.\n\t * @param {Object} options See {@link module:engine/view/domconverter~DomConverter#domToView} options parameter.\n\t * @returns {Iterable.} View nodes.\n\t */\n\t* domChildrenToView( domElement, options = {} ) {\n\t\tfor ( let i = 0; i < domElement.childNodes.length; i++ ) {\n\t\t\tconst domChild = domElement.childNodes[ i ];\n\t\t\tconst viewChild = this.domToView( domChild, options );\n\n\t\t\tif ( viewChild !== null ) {\n\t\t\t\tyield viewChild;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Converts DOM selection to view {@link module:engine/view/selection~Selection}.\n\t * Ranges which cannot be converted will be omitted.\n\t *\n\t * @param {Selection} domSelection DOM selection.\n\t * @returns {module:engine/view/selection~Selection} View selection.\n\t */\n\tdomSelectionToView( domSelection ) {\n\t\t// DOM selection might be placed in fake selection container.\n\t\t// If container contains fake selection - return corresponding view selection.\n\t\tif ( domSelection.rangeCount === 1 ) {\n\t\t\tlet container = domSelection.getRangeAt( 0 ).startContainer;\n\n\t\t\t// The DOM selection might be moved to the text node inside the fake selection container.\n\t\t\tif ( isText( container ) ) {\n\t\t\t\tcontainer = container.parentNode;\n\t\t\t}\n\n\t\t\tconst viewSelection = this.fakeSelectionToView( container );\n\n\t\t\tif ( viewSelection ) {\n\t\t\t\treturn viewSelection;\n\t\t\t}\n\t\t}\n\n\t\tconst isBackward = this.isDomSelectionBackward( domSelection );\n\n\t\tconst viewRanges = [];\n\n\t\tfor ( let i = 0; i < domSelection.rangeCount; i++ ) {\n\t\t\t// DOM Range have correct start and end, no matter what is the DOM Selection direction. So we don't have to fix anything.\n\t\t\tconst domRange = domSelection.getRangeAt( i );\n\t\t\tconst viewRange = this.domRangeToView( domRange );\n\n\t\t\tif ( viewRange ) {\n\t\t\t\tviewRanges.push( viewRange );\n\t\t\t}\n\t\t}\n\n\t\treturn new ViewSelection( viewRanges, { backward: isBackward } );\n\t}\n\n\t/**\n\t * Converts DOM Range to view {@link module:engine/view/range~Range}.\n\t * If the start or end position can not be converted `null` is returned.\n\t *\n\t * @param {Range} domRange DOM range.\n\t * @returns {module:engine/view/range~Range|null} View range.\n\t */\n\tdomRangeToView( domRange ) {\n\t\tconst viewStart = this.domPositionToView( domRange.startContainer, domRange.startOffset );\n\t\tconst viewEnd = this.domPositionToView( domRange.endContainer, domRange.endOffset );\n\n\t\tif ( viewStart && viewEnd ) {\n\t\t\treturn new ViewRange( viewStart, viewEnd );\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Converts DOM parent and offset to view {@link module:engine/view/position~Position}.\n\t *\n\t * If the position is inside a {@link module:engine/view/filler filler} which has no corresponding view node,\n\t * position of the filler will be converted and returned.\n\t *\n\t * If the position is inside DOM element rendered by {@link module:engine/view/uielement~UIElement}\n\t * that position will be converted to view position before that UIElement.\n\t *\n\t * If structures are too different and it is not possible to find corresponding position then `null` will be returned.\n\t *\n\t * @param {Node} domParent DOM position parent.\n\t * @param {Number} domOffset DOM position offset.\n\t * @returns {module:engine/view/position~Position} viewPosition View position.\n\t */\n\tdomPositionToView( domParent, domOffset ) {\n\t\tif ( this.isBlockFiller( domParent, this.blockFillerMode ) ) {\n\t\t\treturn this.domPositionToView( domParent.parentNode, indexOf( domParent ) );\n\t\t}\n\n\t\t// If position is somewhere inside UIElement or a RawElement - return position before that element.\n\t\tconst viewElement = this.mapDomToView( domParent );\n\n\t\tif ( viewElement && ( viewElement.is( 'uiElement' ) || viewElement.is( 'rawElement' ) ) ) {\n\t\t\treturn ViewPosition._createBefore( viewElement );\n\t\t}\n\n\t\tif ( isText( domParent ) ) {\n\t\t\tif ( isInlineFiller( domParent ) ) {\n\t\t\t\treturn this.domPositionToView( domParent.parentNode, indexOf( domParent ) );\n\t\t\t}\n\n\t\t\tconst viewParent = this.findCorrespondingViewText( domParent );\n\t\t\tlet offset = domOffset;\n\n\t\t\tif ( !viewParent ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tif ( startsWithFiller( domParent ) ) {\n\t\t\t\toffset -= INLINE_FILLER_LENGTH;\n\t\t\t\toffset = offset < 0 ? 0 : offset;\n\t\t\t}\n\n\t\t\treturn new ViewPosition( viewParent, offset );\n\t\t}\n\t\t// domParent instanceof HTMLElement.\n\t\telse {\n\t\t\tif ( domOffset === 0 ) {\n\t\t\t\tconst viewParent = this.mapDomToView( domParent );\n\n\t\t\t\tif ( viewParent ) {\n\t\t\t\t\treturn new ViewPosition( viewParent, 0 );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst domBefore = domParent.childNodes[ domOffset - 1 ];\n\t\t\t\tconst viewBefore = isText( domBefore ) ?\n\t\t\t\t\tthis.findCorrespondingViewText( domBefore ) :\n\t\t\t\t\tthis.mapDomToView( domBefore );\n\n\t\t\t\t// TODO #663\n\t\t\t\tif ( viewBefore && viewBefore.parent ) {\n\t\t\t\t\treturn new ViewPosition( viewBefore.parent, viewBefore.index + 1 );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t/**\n\t * Returns corresponding view {@link module:engine/view/element~Element Element} or\n\t * {@link module:engine/view/documentfragment~DocumentFragment} for provided DOM element or\n\t * document fragment. If there is no view item {@link module:engine/view/domconverter~DomConverter#bindElements bound}\n\t * to the given DOM - `undefined` is returned.\n\t *\n\t * For all DOM elements rendered by a {@link module:engine/view/uielement~UIElement} or\n\t * a {@link module:engine/view/rawelement~RawElement}, the parent `UIElement` or `RawElement` will be returned.\n\t *\n\t * @param {DocumentFragment|Element} domElementOrDocumentFragment DOM element or document fragment.\n\t * @returns {module:engine/view/element~Element|module:engine/view/documentfragment~DocumentFragment|undefined}\n\t * Corresponding view element, document fragment or `undefined` if no element was bound.\n\t */\n\tmapDomToView( domElementOrDocumentFragment ) {\n\t\tconst hostElement = this.getHostViewElement( domElementOrDocumentFragment );\n\n\t\treturn hostElement || this._domToViewMapping.get( domElementOrDocumentFragment );\n\t}\n\n\t/**\n\t * Finds corresponding text node. Text nodes are not {@link module:engine/view/domconverter~DomConverter#bindElements bound},\n\t * corresponding text node is returned based on the sibling or parent.\n\t *\n\t * If the directly previous sibling is a {@link module:engine/view/domconverter~DomConverter#bindElements bound} element, it is used\n\t * to find the corresponding text node.\n\t *\n\t * If this is a first child in the parent and the parent is a {@link module:engine/view/domconverter~DomConverter#bindElements bound}\n\t * element, it is used to find the corresponding text node.\n\t *\n\t * For all text nodes rendered by a {@link module:engine/view/uielement~UIElement} or\n\t * a {@link module:engine/view/rawelement~RawElement}, the parent `UIElement` or `RawElement` will be returned.\n\t *\n\t * Otherwise `null` is returned.\n\t *\n\t * Note that for the block or inline {@link module:engine/view/filler filler} this method returns `null`.\n\t *\n\t * @param {Text} domText DOM text node.\n\t * @returns {module:engine/view/text~Text|null} Corresponding view text node or `null`, if it was not possible to find a\n\t * corresponding node.\n\t */\n\tfindCorrespondingViewText( domText ) {\n\t\tif ( isInlineFiller( domText ) ) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// If DOM text was rendered by a UIElement or a RawElement - return this parent element.\n\t\tconst hostElement = this.getHostViewElement( domText );\n\n\t\tif ( hostElement ) {\n\t\t\treturn hostElement;\n\t\t}\n\n\t\tconst previousSibling = domText.previousSibling;\n\n\t\t// Try to use previous sibling to find the corresponding text node.\n\t\tif ( previousSibling ) {\n\t\t\tif ( !( this.isElement( previousSibling ) ) ) {\n\t\t\t\t// The previous is text or comment.\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst viewElement = this.mapDomToView( previousSibling );\n\n\t\t\tif ( viewElement ) {\n\t\t\t\tconst nextSibling = viewElement.nextSibling;\n\n\t\t\t\t// It might be filler which has no corresponding view node.\n\t\t\t\tif ( nextSibling instanceof ViewText ) {\n\t\t\t\t\treturn viewElement.nextSibling;\n\t\t\t\t} else {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// Try to use parent to find the corresponding text node.\n\t\telse {\n\t\t\tconst viewElement = this.mapDomToView( domText.parentNode );\n\n\t\t\tif ( viewElement ) {\n\t\t\t\tconst firstChild = viewElement.getChild( 0 );\n\n\t\t\t\t// It might be filler which has no corresponding view node.\n\t\t\t\tif ( firstChild instanceof ViewText ) {\n\t\t\t\t\treturn firstChild;\n\t\t\t\t} else {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Returns corresponding DOM item for provided {@link module:engine/view/element~Element Element} or\n\t * {@link module:engine/view/documentfragment~DocumentFragment DocumentFragment}.\n\t * To find a corresponding text for {@link module:engine/view/text~Text view Text instance}\n\t * use {@link #findCorrespondingDomText}.\n\t *\n\t * @param {module:engine/view/element~Element|module:engine/view/documentfragment~DocumentFragment} viewNode\n\t * View element or document fragment.\n\t * @returns {Node|DocumentFragment|undefined} Corresponding DOM node or document fragment.\n\t */\n\tmapViewToDom( documentFragmentOrElement ) {\n\t\treturn this._viewToDomMapping.get( documentFragmentOrElement );\n\t}\n\n\t/**\n\t * Finds corresponding text node. Text nodes are not {@link module:engine/view/domconverter~DomConverter#bindElements bound},\n\t * corresponding text node is returned based on the sibling or parent.\n\t *\n\t * If the directly previous sibling is a {@link module:engine/view/domconverter~DomConverter#bindElements bound} element, it is used\n\t * to find the corresponding text node.\n\t *\n\t * If this is a first child in the parent and the parent is a {@link module:engine/view/domconverter~DomConverter#bindElements bound}\n\t * element, it is used to find the corresponding text node.\n\t *\n\t * Otherwise `null` is returned.\n\t *\n\t * @param {module:engine/view/text~Text} viewText View text node.\n\t * @returns {Text|null} Corresponding DOM text node or `null`, if it was not possible to find a corresponding node.\n\t */\n\tfindCorrespondingDomText( viewText ) {\n\t\tconst previousSibling = viewText.previousSibling;\n\n\t\t// Try to use previous sibling to find the corresponding text node.\n\t\tif ( previousSibling && this.mapViewToDom( previousSibling ) ) {\n\t\t\treturn this.mapViewToDom( previousSibling ).nextSibling;\n\t\t}\n\n\t\t// If this is a first node, try to use parent to find the corresponding text node.\n\t\tif ( !previousSibling && viewText.parent && this.mapViewToDom( viewText.parent ) ) {\n\t\t\treturn this.mapViewToDom( viewText.parent ).childNodes[ 0 ];\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Focuses DOM editable that is corresponding to provided {@link module:engine/view/editableelement~EditableElement}.\n\t *\n\t * @param {module:engine/view/editableelement~EditableElement} viewEditable\n\t */\n\tfocus( viewEditable ) {\n\t\tconst domEditable = this.mapViewToDom( viewEditable );\n\n\t\tif ( domEditable && domEditable.ownerDocument.activeElement !== domEditable ) {\n\t\t\t// Save the scrollX and scrollY positions before the focus.\n\t\t\tconst { scrollX, scrollY } = global.window;\n\t\t\tconst scrollPositions = [];\n\n\t\t\t// Save all scrollLeft and scrollTop values starting from domEditable up to\n\t\t\t// document#documentElement.\n\t\t\tforEachDomNodeAncestor( domEditable, node => {\n\t\t\t\tconst { scrollLeft, scrollTop } = node;\n\n\t\t\t\tscrollPositions.push( [ scrollLeft, scrollTop ] );\n\t\t\t} );\n\n\t\t\tdomEditable.focus();\n\n\t\t\t// Restore scrollLeft and scrollTop values starting from domEditable up to\n\t\t\t// document#documentElement.\n\t\t\t// https://github.com/ckeditor/ckeditor5-engine/issues/951\n\t\t\t// https://github.com/ckeditor/ckeditor5-engine/issues/957\n\t\t\tforEachDomNodeAncestor( domEditable, node => {\n\t\t\t\tconst [ scrollLeft, scrollTop ] = scrollPositions.shift();\n\n\t\t\t\tnode.scrollLeft = scrollLeft;\n\t\t\t\tnode.scrollTop = scrollTop;\n\t\t\t} );\n\n\t\t\t// Restore the scrollX and scrollY positions after the focus.\n\t\t\t// https://github.com/ckeditor/ckeditor5-engine/issues/951\n\t\t\tglobal.window.scrollTo( scrollX, scrollY );\n\t\t}\n\t}\n\n\t/**\n\t * Returns `true` when `node.nodeType` equals `Node.ELEMENT_NODE`.\n\t *\n\t * @param {Node} node Node to check.\n\t * @returns {Boolean}\n\t */\n\tisElement( node ) {\n\t\treturn node && node.nodeType == Node.ELEMENT_NODE;\n\t}\n\n\t/**\n\t * Returns `true` when `node.nodeType` equals `Node.DOCUMENT_FRAGMENT_NODE`.\n\t *\n\t * @param {Node} node Node to check.\n\t * @returns {Boolean}\n\t */\n\tisDocumentFragment( node ) {\n\t\treturn node && node.nodeType == Node.DOCUMENT_FRAGMENT_NODE;\n\t}\n\n\t/**\n\t * Returns `true` when `node.nodeType` equals `Node.COMMENT_NODE`.\n\t *\n\t * @param {Node} node Node to check.\n\t * @returns {Boolean}\n\t */\n\tisComment( node ) {\n\t\treturn node && node.nodeType == Node.COMMENT_NODE;\n\t}\n\n\t/**\n\t * Checks if the node is an instance of the block filler for this DOM converter.\n\t *\n\t *\t\tconst converter = new DomConverter( viewDocument, { blockFillerMode: 'br' } );\n\t *\n\t *\t\tconverter.isBlockFiller( BR_FILLER( document ) ); // true\n\t *\t\tconverter.isBlockFiller( NBSP_FILLER( document ) ); // false\n\t *\n\t * **Note:**: For the `'nbsp'` mode the method also checks context of a node so it cannot be a detached node.\n\t *\n\t * **Note:** A special case in the `'nbsp'` mode exists where the `
` in `


` is treated as a block filler.\n\t *\n\t * @param {Node} domNode DOM node to check.\n\t * @returns {Boolean} True if a node is considered a block filler for given mode.\n\t */\n\tisBlockFiller( domNode ) {\n\t\tif ( this.blockFillerMode == 'br' ) {\n\t\t\treturn domNode.isEqualNode( BR_FILLER_REF );\n\t\t}\n\n\t\t// Special case for


in which case the
should be treated as filler even\n\t\t// when we're in the 'nbsp' mode. See ckeditor5#5564.\n\t\tif ( domNode.tagName === 'BR' && hasBlockParent( domNode, this.blockElements ) && domNode.parentNode.childNodes.length === 1 ) {\n\t\t\treturn true;\n\t\t}\n\n\t\treturn isNbspBlockFiller( domNode, this.blockElements );\n\t}\n\n\t/**\n\t * Returns `true` if given selection is a backward selection, that is, if it's `focus` is before `anchor`.\n\t *\n\t * @param {Selection} DOM Selection instance to check.\n\t * @returns {Boolean}\n\t */\n\tisDomSelectionBackward( selection ) {\n\t\tif ( selection.isCollapsed ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Since it takes multiple lines of code to check whether a \"DOM Position\" is before/after another \"DOM Position\",\n\t\t// we will use the fact that range will collapse if it's end is before it's start.\n\t\tconst range = document.createRange();\n\n\t\trange.setStart( selection.anchorNode, selection.anchorOffset );\n\t\trange.setEnd( selection.focusNode, selection.focusOffset );\n\n\t\tconst backward = range.collapsed;\n\n\t\trange.detach();\n\n\t\treturn backward;\n\t}\n\n\t/**\n\t * Returns a parent {@link module:engine/view/uielement~UIElement} or {@link module:engine/view/rawelement~RawElement}\n\t * that hosts the provided DOM node. Returns `null` if there is no such parent.\n\t *\n\t * @param {Node} domNode\n\t * @returns {module:engine/view/uielement~UIElement|module:engine/view/rawelement~RawElement|null}\n\t */\n\tgetHostViewElement( domNode ) {\n\t\tconst ancestors = getAncestors( domNode );\n\n\t\t// Remove domNode from the list.\n\t\tancestors.pop();\n\n\t\twhile ( ancestors.length ) {\n\t\t\tconst domNode = ancestors.pop();\n\t\t\tconst viewNode = this._domToViewMapping.get( domNode );\n\n\t\t\tif ( viewNode && ( viewNode.is( 'uiElement' ) || viewNode.is( 'rawElement' ) ) ) {\n\t\t\t\treturn viewNode;\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Checks if the given selection's boundaries are at correct places.\n\t *\n\t * The following places are considered as incorrect for selection boundaries:\n\t *\n\t * * before or in the middle of an inline filler sequence,\n\t * * inside a DOM element which represents {@link module:engine/view/uielement~UIElement a view UI element},\n\t * * inside a DOM element which represents {@link module:engine/view/rawelement~RawElement a view raw element}.\n\t *\n\t * @param {Selection} domSelection The DOM selection object to be checked.\n\t * @returns {Boolean} `true` if the given selection is at a correct place, `false` otherwise.\n\t */\n\tisDomSelectionCorrect( domSelection ) {\n\t\treturn this._isDomSelectionPositionCorrect( domSelection.anchorNode, domSelection.anchorOffset ) &&\n\t\t\tthis._isDomSelectionPositionCorrect( domSelection.focusNode, domSelection.focusOffset );\n\t}\n\n\t/**\n\t * Registers a {@link module:engine/view/matcher~MatcherPattern} for view elements whose content should be treated as raw data\n\t * and not processed during the conversion from DOM nodes to view elements.\n\t *\n\t * This is affecting how {@link module:engine/view/domconverter~DomConverter#domToView} and\n\t * {@link module:engine/view/domconverter~DomConverter#domChildrenToView} process DOM nodes.\n\t *\n\t * The raw data can be later accessed by a\n\t * {@link module:engine/view/element~Element#getCustomProperty custom property of a view element} called `\"$rawContent\"`.\n\t *\n\t * @param {module:engine/view/matcher~MatcherPattern} pattern Pattern matching a view element whose content should\n\t * be treated as raw data.\n\t */\n\tregisterRawContentMatcher( pattern ) {\n\t\tthis._rawContentElementMatcher.add( pattern );\n\t}\n\n\t/**\n\t * Checks if the given DOM position is a correct place for selection boundary. See {@link #isDomSelectionCorrect}.\n\t *\n\t * @private\n\t * @param {Element} domParent Position parent.\n\t * @param {Number} offset Position offset.\n\t * @returns {Boolean} `true` if given position is at a correct place for selection boundary, `false` otherwise.\n\t */\n\t_isDomSelectionPositionCorrect( domParent, offset ) {\n\t\t// If selection is before or in the middle of inline filler string, it is incorrect.\n\t\tif ( isText( domParent ) && startsWithFiller( domParent ) && offset < INLINE_FILLER_LENGTH ) {\n\t\t\t// Selection in a text node, at wrong position (before or in the middle of filler).\n\t\t\treturn false;\n\t\t}\n\n\t\tif ( this.isElement( domParent ) && startsWithFiller( domParent.childNodes[ offset ] ) ) {\n\t\t\t// Selection in an element node, before filler text node.\n\t\t\treturn false;\n\t\t}\n\n\t\tconst viewParent = this.mapDomToView( domParent );\n\n\t\t// The position is incorrect when anchored inside a UIElement or a RawElement.\n\t\t// Note: In case of UIElement and RawElement, mapDomToView() returns a parent element for any DOM child\n\t\t// so there's no need to perform any additional checks.\n\t\tif ( viewParent && ( viewParent.is( 'uiElement' ) || viewParent.is( 'rawElement' ) ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Takes text data from a given {@link module:engine/view/text~Text#data} and processes it so\n\t * it is correctly displayed in the DOM.\n\t *\n\t * Following changes are done:\n\t *\n\t * * a space at the beginning is changed to ` ` if this is the first text node in its container\n\t * element or if a previous text node ends with a space character,\n\t * * space at the end of the text node is changed to ` ` if there are two spaces at the end of a node or if next node\n\t * starts with a space or if it is the last text node in its container,\n\t * * remaining spaces are replaced to a chain of spaces and ` ` (e.g. `'x x'` becomes `'x   x'`).\n\t *\n\t * Content of {@link #preElements} is not processed.\n\t *\n\t * @private\n\t * @param {module:engine/view/text~Text} node View text node to process.\n\t * @returns {String} Processed text data.\n\t */\n\t_processDataFromViewText( node ) {\n\t\tlet data = node.data;\n\n\t\t// If any of node ancestors has a name which is in `preElements` array, then currently processed\n\t\t// view text node is (will be) in preformatted element. We should not change whitespaces then.\n\t\tif ( node.getAncestors().some( parent => this.preElements.includes( parent.name ) ) ) {\n\t\t\treturn data;\n\t\t}\n\n\t\t// 1. Replace the first space with a nbsp if the previous node ends with a space or there is no previous node\n\t\t// (container element boundary).\n\t\tif ( data.charAt( 0 ) == ' ' ) {\n\t\t\tconst prevNode = this._getTouchingViewTextNode( node, false );\n\t\t\tconst prevEndsWithSpace = prevNode && this._nodeEndsWithSpace( prevNode );\n\n\t\t\tif ( prevEndsWithSpace || !prevNode ) {\n\t\t\t\tdata = '\\u00A0' + data.substr( 1 );\n\t\t\t}\n\t\t}\n\n\t\t// 2. Replace the last space with nbsp if there are two spaces at the end or if the next node starts with space or there is no\n\t\t// next node (container element boundary).\n\t\t//\n\t\t// Keep in mind that Firefox prefers $nbsp; before tag, not inside it:\n\t\t//\n\t\t// Foo  bar <-- bad.\n\t\t// Foo  bar <-- good.\n\t\t//\n\t\t// More here: https://github.com/ckeditor/ckeditor5-engine/issues/1747.\n\t\tif ( data.charAt( data.length - 1 ) == ' ' ) {\n\t\t\tconst nextNode = this._getTouchingViewTextNode( node, true );\n\n\t\t\tif ( data.charAt( data.length - 2 ) == ' ' || !nextNode || nextNode.data.charAt( 0 ) == ' ' ) {\n\t\t\t\tdata = data.substr( 0, data.length - 1 ) + '\\u00A0';\n\t\t\t}\n\t\t}\n\n\t\t// 3. Create space+nbsp pairs.\n\t\treturn data.replace( / {2}/g, ' \\u00A0' );\n\t}\n\n\t/**\n\t * Checks whether given node ends with a space character after changing appropriate space characters to ` `s.\n\t *\n\t * @private\n\t * @param {module:engine/view/text~Text} node Node to check.\n\t * @returns {Boolean} `true` if given `node` ends with space, `false` otherwise.\n\t */\n\t_nodeEndsWithSpace( node ) {\n\t\tif ( node.getAncestors().some( parent => this.preElements.includes( parent.name ) ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst data = this._processDataFromViewText( node );\n\n\t\treturn data.charAt( data.length - 1 ) == ' ';\n\t}\n\n\t/**\n\t * Takes text data from native `Text` node and processes it to a correct {@link module:engine/view/text~Text view text node} data.\n\t *\n\t * Following changes are done:\n\t *\n\t * * multiple whitespaces are replaced to a single space,\n\t * * space at the beginning of a text node is removed if it is the first text node in its container\n\t * element or if the previous text node ends with a space character,\n\t * * space at the end of the text node is removed if there are two spaces at the end of a node or if next node\n\t * starts with a space or if it is the last text node in its container\n\t * * nbsps are converted to spaces.\n\t *\n\t * @param {Node} node DOM text node to process.\n\t * @returns {String} Processed data.\n\t * @private\n\t */\n\t_processDataFromDomText( node ) {\n\t\tlet data = node.data;\n\n\t\tif ( _hasDomParentOfType( node, this.preElements ) ) {\n\t\t\treturn getDataWithoutFiller( node );\n\t\t}\n\n\t\t// Change all consecutive whitespace characters (from the [ \\n\\t\\r] set –\n\t\t// see https://github.com/ckeditor/ckeditor5-engine/issues/822#issuecomment-311670249) to a single space character.\n\t\t// That's how multiple whitespaces are treated when rendered, so we normalize those whitespaces.\n\t\t// We're replacing 1+ (and not 2+) to also normalize singular \\n\\t\\r characters (#822).\n\t\tdata = data.replace( /[ \\n\\t\\r]{1,}/g, ' ' );\n\n\t\tconst prevNode = this._getTouchingInlineDomNode( node, false );\n\t\tconst nextNode = this._getTouchingInlineDomNode( node, true );\n\n\t\tconst shouldLeftTrim = this._checkShouldLeftTrimDomText( node, prevNode );\n\t\tconst shouldRightTrim = this._checkShouldRightTrimDomText( node, nextNode );\n\n\t\t// If the previous dom text node does not exist or it ends by whitespace character, remove space character from the beginning\n\t\t// of this text node. Such space character is treated as a whitespace.\n\t\tif ( shouldLeftTrim ) {\n\t\t\tdata = data.replace( /^ /, '' );\n\t\t}\n\n\t\t// If the next text node does not exist remove space character from the end of this text node.\n\t\tif ( shouldRightTrim ) {\n\t\t\tdata = data.replace( / $/, '' );\n\t\t}\n\n\t\t// At the beginning and end of a block element, Firefox inserts normal space +
instead of non-breaking space.\n\t\t// This means that the text node starts/end with normal space instead of non-breaking space.\n\t\t// This causes a problem because the normal space would be removed in `.replace` calls above. To prevent that,\n\t\t// the inline filler is removed only after the data is initially processed (by the `.replace` above). See ckeditor5#692.\n\t\tdata = getDataWithoutFiller( new Text( data ) );\n\n\t\t// At this point we should have removed all whitespaces from DOM text data.\n\t\t//\n\t\t// Now, We will reverse the process that happens in `_processDataFromViewText`.\n\t\t//\n\t\t// We have to change   chars, that were in DOM text data because of rendering reasons, to spaces.\n\t\t// First, change all ` \\u00A0` pairs (space +  ) to two spaces. DOM converter changes two spaces from model/view to\n\t\t// ` \\u00A0` to ensure proper rendering. Since here we convert back, we recognize those pairs and change them back to ` `.\n\t\tdata = data.replace( / \\u00A0/g, ' ' );\n\n\t\t// Then, let's change the last nbsp to a space.\n\t\tif ( /( |\\u00A0)\\u00A0$/.test( data ) || !nextNode || ( nextNode.data && nextNode.data.charAt( 0 ) == ' ' ) ) {\n\t\t\tdata = data.replace( /\\u00A0$/, ' ' );\n\t\t}\n\n\t\t// Then, change   character that is at the beginning of the text node to space character.\n\t\t// We do that replacement only if this is the first node or the previous node ends on whitespace character.\n\t\tif ( shouldLeftTrim ) {\n\t\t\tdata = data.replace( /^\\u00A0/, ' ' );\n\t\t}\n\n\t\t// At this point, all whitespaces should be removed and all   created for rendering reasons should be\n\t\t// changed to normal space. All left   are   inserted intentionally.\n\t\treturn data;\n\t}\n\n\t/**\n\t * Helper function which checks if a DOM text node, preceded by the given `prevNode` should\n\t * be trimmed from the left side.\n\t *\n\t * @private\n\t * @param {Node} node\n\t * @param {Node} prevNode\n\t */\n\t_checkShouldLeftTrimDomText( node, prevNode ) {\n\t\tif ( !prevNode ) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif ( isElement( prevNode ) ) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Shouldn't left trim if previous node is a node that was encountered as a raw content node.\n\t\tif ( this._encounteredRawContentDomNodes.has( node.previousSibling ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn /[^\\S\\u00A0]/.test( prevNode.data.charAt( prevNode.data.length - 1 ) );\n\t}\n\n\t/**\n\t * Helper function which checks if a DOM text node, succeeded by the given `nextNode` should\n\t * be trimmed from the right side.\n\t *\n\t * @private\n\t * @param {Node} node\n\t * @param {Node} nextNode\n\t */\n\t_checkShouldRightTrimDomText( node, nextNode ) {\n\t\tif ( nextNode ) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn !startsWithFiller( node );\n\t}\n\n\t/**\n\t * Helper function. For given {@link module:engine/view/text~Text view text node}, it finds previous or next sibling\n\t * that is contained in the same container element. If there is no such sibling, `null` is returned.\n\t *\n\t * @private\n\t * @param {module:engine/view/text~Text} node Reference node.\n\t * @param {Boolean} getNext\n\t * @returns {module:engine/view/text~Text|null} Touching text node or `null` if there is no next or previous touching text node.\n\t */\n\t_getTouchingViewTextNode( node, getNext ) {\n\t\tconst treeWalker = new ViewTreeWalker( {\n\t\t\tstartPosition: getNext ? ViewPosition._createAfter( node ) : ViewPosition._createBefore( node ),\n\t\t\tdirection: getNext ? 'forward' : 'backward'\n\t\t} );\n\n\t\tfor ( const value of treeWalker ) {\n\t\t\t// ViewContainerElement is found on a way to next ViewText node, so given `node` was first/last\n\t\t\t// text node in its container element.\n\t\t\tif ( value.item.is( 'containerElement' ) ) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\t//
found – it works like a block boundary, so do not scan further.\n\t\t\telse if ( value.item.is( 'element', 'br' ) ) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\t// Found a text node in the same container element.\n\t\t\telse if ( value.item.is( '$textProxy' ) ) {\n\t\t\t\treturn value.item;\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Helper function. For the given text node, it finds the closest touching node which is either\n\t * a text node or a `
`. The search is terminated at block element boundaries and if a matching node\n\t * wasn't found so far, `null` is returned.\n\t *\n\t * In the following DOM structure:\n\t *\n\t *\t\t

foobar
bom

\n\t *\n\t * * `foo` doesn't have its previous touching inline node (`null` is returned),\n\t * * `foo`'s next touching inline node is `bar`\n\t * * `bar`'s next touching inline node is `
`\n\t *\n\t * This method returns text nodes and `
` elements because these types of nodes affect how\n\t * spaces in the given text node need to be converted.\n\t *\n\t * @private\n\t * @param {Text} node\n\t * @param {Boolean} getNext\n\t * @returns {Text|Element|null}\n\t */\n\t_getTouchingInlineDomNode( node, getNext ) {\n\t\tif ( !node.parentNode ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst direction = getNext ? 'nextNode' : 'previousNode';\n\t\tconst document = node.ownerDocument;\n\t\tconst topmostParent = getAncestors( node )[ 0 ];\n\n\t\tconst treeWalker = document.createTreeWalker( topmostParent, NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT, {\n\t\t\tacceptNode( node ) {\n\t\t\t\tif ( isText( node ) ) {\n\t\t\t\t\treturn NodeFilter.FILTER_ACCEPT;\n\t\t\t\t}\n\n\t\t\t\tif ( node.tagName == 'BR' ) {\n\t\t\t\t\treturn NodeFilter.FILTER_ACCEPT;\n\t\t\t\t}\n\n\t\t\t\treturn NodeFilter.FILTER_SKIP;\n\t\t\t}\n\t\t} );\n\n\t\ttreeWalker.currentNode = node;\n\n\t\tconst touchingNode = treeWalker[ direction ]();\n\n\t\tif ( touchingNode !== null ) {\n\t\t\tconst lca = getCommonAncestor( node, touchingNode );\n\n\t\t\t// If there is common ancestor between the text node and next/prev text node,\n\t\t\t// and there are no block elements on a way from the text node to that ancestor,\n\t\t\t// and there are no block elements on a way from next/prev text node to that ancestor...\n\t\t\tif (\n\t\t\t\tlca &&\n\t\t\t\t!_hasDomParentOfType( node, this.blockElements, lca ) &&\n\t\t\t\t!_hasDomParentOfType( touchingNode, this.blockElements, lca )\n\t\t\t) {\n\t\t\t\t// Then they are in the same container element.\n\t\t\t\treturn touchingNode;\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n}\n\n// Helper function.\n// Used to check if given native `Element` or `Text` node has parent with tag name from `types` array.\n//\n// @param {Node} node\n// @param {Array.} types\n// @param {Boolean} [boundaryParent] Can be given if parents should be checked up to a given element (excluding that element).\n// @returns {Boolean} `true` if such parent exists or `false` if it does not.\nfunction _hasDomParentOfType( node, types, boundaryParent ) {\n\tlet parents = getAncestors( node );\n\n\tif ( boundaryParent ) {\n\t\tparents = parents.slice( parents.indexOf( boundaryParent ) + 1 );\n\t}\n\n\treturn parents.some( parent => parent.tagName && types.includes( parent.tagName.toLowerCase() ) );\n}\n\n// A helper that executes given callback for each DOM node's ancestor, starting from the given node\n// and ending in document#documentElement.\n//\n// @param {Node} node\n// @param {Function} callback A callback to be executed for each ancestor.\nfunction forEachDomNodeAncestor( node, callback ) {\n\twhile ( node && node != global.document ) {\n\t\tcallback( node );\n\t\tnode = node.parentNode;\n\t}\n}\n\n// Checks if given node is a nbsp block filler.\n//\n// A   is a block filler only if it is a single child of a block element.\n//\n// @param {Node} domNode DOM node.\n// @returns {Boolean}\nfunction isNbspBlockFiller( domNode, blockElements ) {\n\tconst isNBSP = isText( domNode ) && domNode.data == '\\u00A0';\n\n\treturn isNBSP && hasBlockParent( domNode, blockElements ) && domNode.parentNode.childNodes.length === 1;\n}\n\n// Checks if domNode has block parent.\n//\n// @param {Node} domNode DOM node.\n// @returns {Boolean}\nfunction hasBlockParent( domNode, blockElements ) {\n\tconst parent = domNode.parentNode;\n\n\treturn parent && parent.tagName && blockElements.includes( parent.tagName.toLowerCase() );\n}\n\n/**\n * Enum representing type of the block filler.\n *\n * Possible values:\n *\n * * `br` - for `
` block filler used in editing view,\n * * `nbsp` - for ` ` block fillers used in the data.\n *\n * @typedef {String} module:engine/view/filler~BlockFillerMode\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/view/document\n */\n\nimport DocumentSelection from './documentselection';\nimport Collection from '@ckeditor/ckeditor5-utils/src/collection';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\n\n// @if CK_DEBUG_ENGINE // const { logDocument } = require( '../dev-utils/utils' );\n\n/**\n * Document class creates an abstract layer over the content editable area, contains a tree of view elements and\n * {@link module:engine/view/documentselection~DocumentSelection view selection} associated with this document.\n *\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class Document {\n\t/**\n\t * Creates a Document instance.\n\t *\n\t * @param {module:engine/view/stylesmap~StylesProcessor} stylesProcessor The styles processor instance.\n\t */\n\tconstructor( stylesProcessor ) {\n\t\t/**\n\t\t * Selection done on this document.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/documentselection~DocumentSelection} module:engine/view/document~Document#selection\n\t\t */\n\t\tthis.selection = new DocumentSelection();\n\n\t\t/**\n\t\t * Roots of the view tree. Collection of the {@link module:engine/view/element~Element view elements}.\n\t\t *\n\t\t * View roots are created as a result of binding between {@link module:engine/view/document~Document#roots} and\n\t\t * {@link module:engine/model/document~Document#roots} and this is handled by\n\t\t * {@link module:engine/controller/editingcontroller~EditingController}, so to create view root we need to create\n\t\t * model root using {@link module:engine/model/document~Document#createRoot}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/collection~Collection} module:engine/view/document~Document#roots\n\t\t */\n\t\tthis.roots = new Collection( { idProperty: 'rootName' } );\n\n\t\t/**\n\t\t * The styles processor instance used by this document when normalizing styles.\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 * Defines whether document is in read-only mode.\n\t\t *\n\t\t * When document is read-ony then all roots are read-only as well and caret placed inside this root is hidden.\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} #isReadOnly\n\t\t */\n\t\tthis.set( 'isReadOnly', false );\n\n\t\t/**\n\t\t * True if document is focused.\n\t\t *\n\t\t * This property is updated by the {@link module:engine/view/observer/focusobserver~FocusObserver}.\n\t\t * If the {@link module:engine/view/observer/focusobserver~FocusObserver} is disabled this property will not change.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Boolean} module:engine/view/document~Document#isFocused\n\t\t */\n\t\tthis.set( 'isFocused', false );\n\n\t\t/**\n\t\t * True if composition is in progress inside the document.\n\t\t *\n\t\t * This property is updated by the {@link module:engine/view/observer/compositionobserver~CompositionObserver}.\n\t\t * If the {@link module:engine/view/observer/compositionobserver~CompositionObserver} is disabled this property will not change.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Boolean} module:engine/view/document~Document#isComposing\n\t\t */\n\t\tthis.set( 'isComposing', false );\n\n\t\t/**\n\t\t * Post-fixer callbacks registered to the view document.\n\t\t *\n\t\t * @private\n\t\t * @member {Set}\n\t\t */\n\t\tthis._postFixers = new Set();\n\t}\n\n\t/**\n\t * Gets a {@link module:engine/view/document~Document#roots view root element} with the specified name. If the name is not\n\t * specific \"main\" root is returned.\n\t *\n\t * @param {String} [name='main'] Name of the root.\n\t * @returns {module:engine/view/rooteditableelement~RootEditableElement|null} The view root element with the specified name\n\t * or null when there is no root of given name.\n\t */\n\tgetRoot( name = 'main' ) {\n\t\treturn this.roots.get( name );\n\t}\n\n\t/**\n\t * Allows registering post-fixer callbacks. A post-fixers mechanism allows to update the view tree just before it is rendered\n\t * to the DOM.\n\t *\n\t * Post-fixers are executed right after all changes from the outermost change block were applied but\n\t * before the {@link module:engine/view/view~View#event:render render event} is fired. If a post-fixer callback made\n\t * a change, it should return `true`. When this happens, all post-fixers are fired again to check if something else should\n\t * not be fixed in the new document tree state.\n\t *\n\t * View post-fixers are useful when you want to apply some fixes whenever the view structure changes. Keep in mind that\n\t * changes executed in a view post-fixer should not break model-view mapping.\n\t *\n\t * The types of changes which should be safe:\n\t *\n\t * * adding or removing attribute from elements,\n\t * * changes inside of {@link module:engine/view/uielement~UIElement UI elements},\n\t * * {@link module:engine/model/differ~Differ#refreshItem marking some of the model elements to be re-converted}.\n\t *\n\t * Try to avoid changes which touch view structure:\n\t *\n\t * * you should not add or remove nor wrap or unwrap any view elements,\n\t * * you should not change the editor data model in a view post-fixer.\n\t *\n\t * As a parameter, a post-fixer callback receives a {@link module:engine/view/downcastwriter~DowncastWriter downcast writer}.\n\t *\n\t * Typically, a post-fixer will look like this:\n\t *\n\t *\t\teditor.editing.view.document.registerPostFixer( writer => {\n\t *\t\t\tif ( checkSomeCondition() ) {\n\t *\t\t\t\twriter.doSomething();\n\t *\n\t *\t\t\t\t// Let other post-fixers know that something changed.\n\t *\t\t\t\treturn true;\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * Note that nothing happens right after you register a post-fixer (e.g. execute such a code in the console).\n\t * That is because adding a post-fixer does not execute it.\n\t * The post-fixer will be executed as soon as any change in the document needs to cause its rendering.\n\t * If you want to re-render the editor's view after registering the post-fixer then you should do it manually by calling\n\t * {@link module:engine/view/view~View#forceRender `view.forceRender()`}.\n\t *\n\t * If you need to register a callback which is executed when DOM elements are already updated,\n\t * use {@link module:engine/view/view~View#event:render render event}.\n\t *\n\t * @param {Function} postFixer\n\t */\n\tregisterPostFixer( postFixer ) {\n\t\tthis._postFixers.add( postFixer );\n\t}\n\n\t/**\n\t * Destroys this instance. Makes sure that all observers are destroyed and listeners removed.\n\t */\n\tdestroy() {\n\t\tthis.roots.map( root => root.destroy() );\n\t\tthis.stopListening();\n\t}\n\n\t/**\n\t * Performs post-fixer loops. Executes post-fixer callbacks as long as none of them has done any changes to the model.\n\t *\n\t * @protected\n\t * @param {module:engine/view/downcastwriter~DowncastWriter} writer\n\t */\n\t_callPostFixers( writer ) {\n\t\tlet wasFixed = false;\n\n\t\tdo {\n\t\t\tfor ( const callback of this._postFixers ) {\n\t\t\t\twasFixed = callback( writer );\n\n\t\t\t\tif ( wasFixed ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t} while ( wasFixed );\n\t}\n\n\t/**\n\t * Event fired whenever document content layout changes. It is fired whenever content is\n\t * {@link module:engine/view/view~View#event:render rendered}, but should be also fired by observers in case of\n\t * other actions which may change layout, for instance when image loads.\n\t *\n\t * @event layoutChanged\n\t */\n\n\t// @if CK_DEBUG_ENGINE // log( version ) {\n\t// @if CK_DEBUG_ENGINE //\tlogDocument( this, version );\n\t// @if CK_DEBUG_ENGINE // }\n}\n\nmix( Document, ObservableMixin );\n\n/**\n * Enum representing type of the change.\n *\n * Possible values:\n *\n * * `children` - for child list changes,\n * * `attributes` - for element attributes changes,\n * * `text` - for text nodes changes.\n *\n * @typedef {String} module:engine/view/document~ChangeType\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/view/documentfragment\n */\n\nimport Text from './text';\nimport TextProxy from './textproxy';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport isIterable from '@ckeditor/ckeditor5-utils/src/isiterable';\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\n\n/**\n * Document fragment.\n *\n * To create a new document fragment instance use the\n * {@link module:engine/view/upcastwriter~UpcastWriter#createDocumentFragment `UpcastWriter#createDocumentFragment()`}\n * method.\n */\nexport default class DocumentFragment {\n\t/**\n\t * Creates new DocumentFragment instance.\n\t *\n\t * @protected\n\t * @param {module:engine/view/document~Document} document The document to which this document fragment belongs.\n\t * @param {module:engine/view/node~Node|Iterable.} [children]\n\t * A list of nodes to be inserted into the created document fragment.\n\t */\n\tconstructor( document, children ) {\n\t\t/**\n\t\t * The document to which this document fragment belongs.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/document~Document}\n\t\t */\n\t\tthis.document = document;\n\n\t\t/**\n\t\t * Array of child nodes.\n\t\t *\n\t\t * @protected\n\t\t * @member {Array.} module:engine/view/documentfragment~DocumentFragment#_children\n\t\t */\n\t\tthis._children = [];\n\n\t\tif ( children ) {\n\t\t\tthis._insertChild( 0, children );\n\t\t}\n\t}\n\n\t/**\n\t * Iterable interface.\n\t *\n\t * Iterates over nodes added to this document fragment.\n\t *\n\t * @returns {Iterable.}\n\t */\n\t[ Symbol.iterator ]() {\n\t\treturn this._children[ Symbol.iterator ]();\n\t}\n\n\t/**\n\t * Number of child nodes in this document fragment.\n\t *\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget childCount() {\n\t\treturn this._children.length;\n\t}\n\n\t/**\n\t * Is `true` if there are no nodes inside this document fragment, `false` otherwise.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget isEmpty() {\n\t\treturn this.childCount === 0;\n\t}\n\n\t/**\n\t * Artificial root of `DocumentFragment`. Returns itself. Added for compatibility reasons.\n\t *\n\t * @readonly\n\t * @type {module:engine/model/documentfragment~DocumentFragment}\n\t */\n\tget root() {\n\t\treturn this;\n\t}\n\n\t/**\n\t * Artificial parent of `DocumentFragment`. Returns `null`. Added for compatibility reasons.\n\t *\n\t * @readonly\n\t * @type {null}\n\t */\n\tget parent() {\n\t\treturn null;\n\t}\n\n\t/**\n\t * Checks whether this object is of the given type.\n\t *\n\t *\t\tdocFrag.is( 'documentFragment' ); // -> true\n\t *\t\tdocFrag.is( 'view:documentFragment' ); // -> true\n\t *\n\t *\t\tdocFrag.is( 'model:documentFragment' ); // -> false\n\t *\t\tdocFrag.is( 'element' ); // -> false\n\t *\t\tdocFrag.is( 'node' ); // -> false\n\t *\n\t * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.\n\t *\n\t * @param {String} type\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type === 'documentFragment' || type === 'view:documentFragment';\n\t}\n\n\t/**\n\t * {@link module:engine/view/documentfragment~DocumentFragment#_insertChild Insert} a child node or a list of child nodes at the end\n\t * and sets the parent of these nodes to this fragment.\n\t *\n\t * @param {module:engine/view/item~Item|Iterable.} items Items to be inserted.\n\t * @returns {Number} Number of appended nodes.\n\t */\n\t_appendChild( items ) {\n\t\treturn this._insertChild( this.childCount, items );\n\t}\n\n\t/**\n\t * Gets child at the given index.\n\t *\n\t * @param {Number} index Index of child.\n\t * @returns {module:engine/view/node~Node} Child node.\n\t */\n\tgetChild( index ) {\n\t\treturn this._children[ index ];\n\t}\n\n\t/**\n\t * Gets index of the given child node. Returns `-1` if child node is not found.\n\t *\n\t * @param {module:engine/view/node~Node} node Child node.\n\t * @returns {Number} Index of the child node.\n\t */\n\tgetChildIndex( node ) {\n\t\treturn this._children.indexOf( node );\n\t}\n\n\t/**\n\t * Gets child nodes iterator.\n\t *\n\t * @returns {Iterable.} Child nodes iterator.\n\t */\n\tgetChildren() {\n\t\treturn this._children[ Symbol.iterator ]();\n\t}\n\n\t/**\n\t * Inserts a child node or a list of child nodes on the given index and sets the parent of these nodes to\n\t * this fragment.\n\t *\n\t * @param {Number} index Position where nodes should be inserted.\n\t * @param {module:engine/view/item~Item|Iterable.} items Items to be inserted.\n\t * @returns {Number} Number of inserted nodes.\n\t */\n\t_insertChild( index, items ) {\n\t\tthis._fireChange( 'children', this );\n\t\tlet count = 0;\n\n\t\tconst nodes = normalize( this.document, items );\n\n\t\tfor ( const node of nodes ) {\n\t\t\t// If node that is being added to this element is already inside another element, first remove it from the old parent.\n\t\t\tif ( node.parent !== null ) {\n\t\t\t\tnode._remove();\n\t\t\t}\n\n\t\t\tnode.parent = this;\n\n\t\t\tthis._children.splice( index, 0, node );\n\t\t\tindex++;\n\t\t\tcount++;\n\t\t}\n\n\t\treturn count;\n\t}\n\n\t/**\n\t * Removes number of child nodes starting at the given index and set the parent of these nodes to `null`.\n\t *\n\t * @param {Number} index Number of the first node to remove.\n\t * @param {Number} [howMany=1] Number of nodes to remove.\n\t * @returns {Array.} The array of removed nodes.\n\t */\n\t_removeChildren( index, howMany = 1 ) {\n\t\tthis._fireChange( 'children', this );\n\n\t\tfor ( let i = index; i < index + howMany; i++ ) {\n\t\t\tthis._children[ i ].parent = null;\n\t\t}\n\n\t\treturn this._children.splice( index, howMany );\n\t}\n\n\t/**\n\t * Fires `change` event with given type of the change.\n\t *\n\t * @private\n\t * @param {module:engine/view/document~ChangeType} type Type of the change.\n\t * @param {module:engine/view/node~Node} node Changed node.\n\t * @fires module:engine/view/node~Node#change\n\t */\n\t_fireChange( type, node ) {\n\t\tthis.fire( 'change:' + type, node );\n\t}\n\n\t// @if CK_DEBUG_ENGINE // printTree() {\n\t// @if CK_DEBUG_ENGINE //\tlet string = 'ViewDocumentFragment: [';\n\n\t// @if CK_DEBUG_ENGINE //\tfor ( const child of this.getChildren() ) {\n\t// @if CK_DEBUG_ENGINE //\t\tif ( child.is( '$text' ) ) {\n\t// @if CK_DEBUG_ENGINE //\t\t\tstring += '\\n' + '\\t'.repeat( 1 ) + child.data;\n\t// @if CK_DEBUG_ENGINE //\t\t} else {\n\t// @if CK_DEBUG_ENGINE //\t\t\tstring += '\\n' + child.printTree( 1 );\n\t// @if CK_DEBUG_ENGINE //\t\t}\n\t// @if CK_DEBUG_ENGINE //\t}\n\n\t// @if CK_DEBUG_ENGINE //\tstring += '\\n]';\n\n\t// @if CK_DEBUG_ENGINE //\treturn string;\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // logTree() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( this.printTree() );\n\t// @if CK_DEBUG_ENGINE // }\n}\n\nmix( DocumentFragment, EmitterMixin );\n\n// Converts strings to Text and non-iterables to arrays.\n//\n// @param {String|module:engine/view/item~Item|Iterable.}\n// @returns {Iterable.}\nfunction normalize( document, nodes ) {\n\t// Separate condition because string is iterable.\n\tif ( typeof nodes == 'string' ) {\n\t\treturn [ new Text( document, nodes ) ];\n\t}\n\n\tif ( !isIterable( nodes ) ) {\n\t\tnodes = [ nodes ];\n\t}\n\n\t// Array.from to enable .map() on non-arrays.\n\treturn Array.from( nodes )\n\t\t.map( node => {\n\t\t\tif ( typeof node == 'string' ) {\n\t\t\t\treturn new Text( document, node );\n\t\t\t}\n\n\t\t\tif ( node instanceof TextProxy ) {\n\t\t\t\treturn new Text( document, node.data );\n\t\t\t}\n\n\t\t\treturn node;\n\t\t} );\n}\n"],"sourceRoot":""}

abc