{"version":3,"sources":["webpack:///./node_modules/@ckeditor/ckeditor5-engine/src/model/rootelement.js","webpack:///./node_modules/@ckeditor/ckeditor5-engine/src/model/schema.js","webpack:///./node_modules/@ckeditor/ckeditor5-engine/src/model/range.js","webpack:///./node_modules/@ckeditor/ckeditor5-engine/src/model/selection.js"],"names":["RootElement","document","name","rootName","_document","type","this","Element","combineWalkers","convertToMinimalFlatRanges","Schema","_sourceDefinitions","_attributeProperties","decorate","on","evt","args","SchemaContext","priority","getDefinition","itemName","definition","CKEditorError","Object","assign","_clearCache","push","_compiledDefinitions","_compile","item","is","getDefinitions","def","isBlock","isLimit","isObject","isSelectable","isContent","isInline","context","_checkContextMatch","attributeName","last","allowAttributes","includes","positionOrBaseElement","elementToMerge","Position","nodeBefore","nodeAfter","checkMerge","getChildren","child","checkChild","callback","ctx","childDef","retValue","stop","return","properties","getAttributeProperties","selectionOrRangeOrPosition","element","parent","ranges","Range","Array","from","getRanges","reduce","range","rangeCommonAncestor","getCommonAncestor","includeSelf","selection","attribute","isCollapsed","firstPosition","getFirstPosition","getAncestors","Text","getAttributes","checkAttribute","value","_getValidRangesForRange","position","backwardWalker","forwardWalker","direction","limitElement","reverse","find","root","TreeWalker","boundaries","_createIn","startPosition","data","walker","_createOn","nextPosition","node","nodes","writer","removeDisallowedAttributeFromNode","rangeInNode","positionsInRange","getPositions","compiledDefinitions","sourceRules","itemNames","keys","compileBaseItemRule","compileAllowContentOf","compileAllowWhere","compileAllowAttributesOf","compileInheritPropertiesFrom","cleanUpAllowIn","cleanUpAllowAttributes","contextItemIndex","length","contextItem","getItem","allowIn","parentRule","start","end","getItems","shallow","isEqual","_createAfter","mix","ObservableMixin","isArray","shift","_items","map","mapContextItem","Symbol","iterator","index","query","getNames","join","endsWith","startsWith","sourceItemRules","itemRule","allowContentOf","allowWhere","allowAttributesOf","inheritTypesFrom","copyTypes","copyProperty","makeInheritAllWork","allowContentOfItemName","allowedChildren","getAllowedChildren","forEach","allowedItem","allowWhereItemName","inheritFrom","allowedIn","allowAttributeOfItem","inheritAttributes","inheritPropertiesOfItem","typeNames","filter","existingItems","itemToCheck","Set","sourceItemRule","propertyName","inheritAllFrom","getValues","obj","key","ctxItem","getAttributeKeys","getAttribute","backward","forward","done","step","next","getMinimalFlatRanges","schema","removeAttribute","_createAt","stickiness","ignoreElementEnd","isAfter","isBefore","otherRange","loose","containsStart","containsPosition","containsEnd","pos","_createBefore","isIntersecting","commonRangeStart","commonRangeEnd","shouldJoin","isTouching","endPosition","diffAt","getCommonPath","posParent","path","howMany","maxOffset","offset","getShiftedBy","slice","options","treeWalker","operation","_getTransformedByInsertOperation","_getTransformedByMoveOperation","_getTransformedBySplitOperation","_getTransformedByMergeOperation","operations","i","result","getTransformedByOperation","splice","j","containsRange","nodeAfterStart","nodeBeforeEnd","toJSON","constructor","spread","_getTransformedByInsertion","sourcePosition","targetPosition","_getTransformedByMove","insertionPosition","deletionPosition","insertPosition","newPos","moveRange","_createFromPositionAndShift","_getTransformedByDeletion","differenceSet","getDifference","difference","common","getIntersection","transformedCommon","_getCombined","deletePosition","newStart","newEnd","startParentPath","getParentPath","endParentPath","compareArrays","offsetSize","clone","ref","sort","a","b","refIndex","indexOf","json","doc","fromJSON","Selection","selectable","placeOrOffset","_lastRangeBackward","_ranges","_attrs","Map","setTo","otherSelection","rangeCount","anchor","focus","thisRange","found","first","getFirstRange","lastRange","getLastRange","_setRanges","isBackward","Node","undefined","isIterable","newRanges","isLastBackward","anyNewRange","some","newRange","every","oldRange","_removeAllRanges","_pushRange","fire","directChange","itemOrPosition","newFocus","compareWith","_popRange","get","entries","has","hasAttribute","delete","attributeKeys","set","getContainedElement","visited","WeakSet","startBlock","getParentBlock","isTopBlockInRange","getWalker","block","isUnvisitedTopBlock","endBlock","limitStartPosition","limitEndPosition","getLastPosition","_checkRange","addedRange","intersectingRange","pop","isUnvisitedBlock","add","model","ancestors","parentFirst","hasParentLimit","parentBlock","findAncestorBlock","isParentInRange","EmitterMixin"],"mappings":"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","file":"js/chunk-vendors~5e92cc9a.f3551852.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/model/rootelement\n */\n\nimport Element from './element';\n\n/**\n * Type of {@link module:engine/model/element~Element} that is a root of a model tree.\n * @extends module:engine/model/element~Element\n */\nexport default class RootElement extends Element {\n\t/**\n\t * Creates root element.\n\t *\n\t * @param {module:engine/model/document~Document} document Document that is an owner of this root.\n\t * @param {String} name Node name.\n\t * @param {String} [rootName='main'] Unique root name used to identify this root\n\t * element by {@link module:engine/model/document~Document}.\n\t */\n\tconstructor( document, name, rootName = 'main' ) {\n\t\tsuper( name );\n\n\t\t/**\n\t\t * Document that is an owner of this root.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/model/document~Document}\n\t\t */\n\t\tthis._document = document;\n\n\t\t/**\n\t\t * Unique root name used to identify this root element by {@link module:engine/model/document~Document}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String}\n\t\t */\n\t\tthis.rootName = rootName;\n\t}\n\n\t/**\n\t * {@link module:engine/model/document~Document Document} that owns this root element.\n\t *\n\t * @readonly\n\t * @type {module:engine/model/document~Document|null}\n\t */\n\tget document() {\n\t\treturn this._document;\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\trootElement.is( 'rootElement' ); // -> true\n\t *\t\trootElement.is( 'element' ); // -> true\n\t *\t\trootElement.is( 'node' ); // -> true\n\t *\t\trootElement.is( 'model:rootElement' ); // -> true\n\t *\t\trootElement.is( 'model:element' ); // -> true\n\t *\t\trootElement.is( 'model:node' ); // -> true\n\t *\n\t *\t\trootElement.is( 'view:element' ); // -> false\n\t *\t\trootElement.is( 'documentFragment' ); // -> false\n\t *\n\t * Assuming that the object being checked is an element, you can also check its\n\t * {@link module:engine/model/element~Element#name name}:\n\t *\n\t *\t\trootElement.is( 'rootElement', '$root' ); // -> same as above\n\t *\n\t * {@link module:engine/model/node~Node#is Check the entire list of model 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 ) {\n\t\tif ( !name ) {\n\t\t\treturn type === 'rootElement' || type === 'model:rootElement' ||\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 === 'model:element' ||\n\t\t\t\ttype === 'node' || type === 'model:node';\n\t\t}\n\n\t\treturn name === this.name && (\n\t\t\ttype === 'rootElement' || type === 'model:rootElement' ||\n\t\t\t// From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.\n\t\t\ttype === 'element' || type === 'model:element'\n\t\t);\n\t}\n\n\t/**\n\t * Converts `RootElement` instance to `String` containing it's name.\n\t *\n\t * @returns {String} `RootElement` instance converted to `String`.\n\t */\n\ttoJSON() {\n\t\treturn this.rootName;\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn this.rootName;\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // log() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( 'ModelRootElement: ' + this );\n\t// @if CK_DEBUG_ENGINE // }\n}\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/model/schema\n */\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\n\nimport Range from './range';\nimport Position from './position';\nimport Element from './element';\nimport Text from './text';\nimport TreeWalker from './treewalker';\n\n/**\n * The model's schema. It defines allowed and disallowed structures of nodes as well as nodes' attributes.\n * The schema is usually defined by features and based on them the editing framework and features\n * make decisions how to change and process the model.\n *\n * The instance of schema is available in {@link module:engine/model/model~Model#schema `editor.model.schema`}.\n *\n * Read more about the schema in:\n *\n * * {@glink framework/guides/architecture/editing-engine#schema Schema} section of the\n * {@glink framework/guides/architecture/editing-engine Introduction to the Editing engine architecture}.\n * * {@glink framework/guides/deep-dive/schema Schema deep dive} guide.\n *\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class Schema {\n\t/**\n\t * Creates schema instance.\n\t */\n\tconstructor() {\n\t\tthis._sourceDefinitions = {};\n\n\t\t/**\n\t\t * A dictionary containing attribute properties.\n\t\t *\n\t\t * @private\n\t\t * @member {Object.}\n\t\t */\n\t\tthis._attributeProperties = {};\n\n\t\tthis.decorate( 'checkChild' );\n\t\tthis.decorate( 'checkAttribute' );\n\n\t\tthis.on( 'checkAttribute', ( evt, args ) => {\n\t\t\targs[ 0 ] = new SchemaContext( args[ 0 ] );\n\t\t}, { priority: 'highest' } );\n\n\t\tthis.on( 'checkChild', ( evt, args ) => {\n\t\t\targs[ 0 ] = new SchemaContext( args[ 0 ] );\n\t\t\targs[ 1 ] = this.getDefinition( args[ 1 ] );\n\t\t}, { priority: 'highest' } );\n\t}\n\n\t/**\n\t * Registers schema item. Can only be called once for every item name.\n\t *\n\t *\t\tschema.register( 'paragraph', {\n\t *\t\t\tinheritAllFrom: '$block'\n\t *\t\t} );\n\t *\n\t * @param {String} itemName\n\t * @param {module:engine/model/schema~SchemaItemDefinition} definition\n\t */\n\tregister( itemName, definition ) {\n\t\tif ( this._sourceDefinitions[ itemName ] ) {\n\t\t\t/**\n\t\t\t * A single item cannot be registered twice in the schema.\n\t\t\t *\n\t\t\t * This situation may happen when:\n\t\t\t *\n\t\t\t * * Two or more plugins called {@link #register `register()`} with the same name. This will usually mean that\n\t\t\t * there is a collision between plugins which try to use the same element in the model. Unfortunately,\n\t\t\t * the only way to solve this is by modifying one of these plugins to use a unique model element name.\n\t\t\t * * A single plugin was loaded twice. This happens when it is installed by npm/yarn in two versions\n\t\t\t * and usually means one or more of the following issues:\n\t\t\t * * a version mismatch (two of your dependencies require two different versions of this plugin),\n\t\t\t * * incorrect imports (this plugin is somehow imported twice in a way which confuses webpack),\n\t\t\t * * mess in `node_modules/` (`rm -rf node_modules/` may help).\n\t\t\t *\n\t\t\t * **Note:** Check the logged `itemName` to better understand which plugin was duplicated/conflicting.\n\t\t\t *\n\t\t\t * @param itemName The name of the model element that is being registered twice.\n\t\t\t * @error schema-cannot-register-item-twice\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'schema-cannot-register-item-twice',\n\t\t\t\tthis,\n\t\t\t\t{\n\t\t\t\t\titemName\n\t\t\t\t}\n\t\t\t);\n\t\t}\n\n\t\tthis._sourceDefinitions[ itemName ] = [\n\t\t\tObject.assign( {}, definition )\n\t\t];\n\n\t\tthis._clearCache();\n\t}\n\n\t/**\n\t * Extends a {@link #register registered} item's definition.\n\t *\n\t * Extending properties such as `allowIn` will add more items to the existing properties,\n\t * while redefining properties such as `isBlock` will override the previously defined ones.\n\t *\n\t *\t\tschema.register( 'foo', {\n\t *\t\t\tallowIn: '$root',\n\t *\t\t\tisBlock: true;\n\t *\t\t} );\n\t *\t\tschema.extend( 'foo', {\n\t *\t\t\tallowIn: 'blockQuote',\n\t *\t\t\tisBlock: false\n\t *\t\t} );\n\t *\n\t *\t\tschema.getDefinition( 'foo' );\n\t *\t\t//\t{\n\t *\t\t//\t\tallowIn: [ '$root', 'blockQuote' ],\n\t *\t\t// \t\tisBlock: false\n\t *\t\t//\t}\n\t *\n\t * @param {String} itemName\n\t * @param {module:engine/model/schema~SchemaItemDefinition} definition\n\t */\n\textend( itemName, definition ) {\n\t\tif ( !this._sourceDefinitions[ itemName ] ) {\n\t\t\t/**\n\t\t\t * Cannot extend an item which was not registered yet.\n\t\t\t *\n\t\t\t * This error happens when a plugin tries to extend the schema definition of an item which was not\n\t\t\t * {@link #register registered} yet.\n\t\t\t *\n\t\t\t * @param itemName The name of the model element which is being extended.\n\t\t\t * @error schema-cannot-extend-missing-item\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'schema-cannot-extend-missing-item', this, {\n\t\t\t\titemName\n\t\t\t} );\n\t\t}\n\n\t\tthis._sourceDefinitions[ itemName ].push( Object.assign( {}, definition ) );\n\n\t\tthis._clearCache();\n\t}\n\n\t/**\n\t * Returns data of all registered items.\n\t *\n\t * This method should normally be used for reflection purposes (e.g. defining a clone of a certain element,\n\t * checking a list of all block elements, etc).\n\t * Use specific methods (such as {@link #checkChild `checkChild()`} or {@link #isLimit `isLimit()`})\n\t * in other cases.\n\t *\n\t * @returns {Object.}\n\t */\n\tgetDefinitions() {\n\t\tif ( !this._compiledDefinitions ) {\n\t\t\tthis._compile();\n\t\t}\n\n\t\treturn this._compiledDefinitions;\n\t}\n\n\t/**\n\t * Returns a definition of the given item or `undefined` if an item is not registered.\n\t *\n\t * This method should normally be used for reflection purposes (e.g. defining a clone of a certain element,\n\t * checking a list of all block elements, etc).\n\t * Use specific methods (such as {@link #checkChild `checkChild()`} or {@link #isLimit `isLimit()`})\n\t * in other cases.\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/schema~SchemaContextItem|String} item\n\t * @returns {module:engine/model/schema~SchemaCompiledItemDefinition}\n\t */\n\tgetDefinition( item ) {\n\t\tlet itemName;\n\n\t\tif ( typeof item == 'string' ) {\n\t\t\titemName = item;\n\t\t} else if ( item.is && ( item.is( '$text' ) || item.is( '$textProxy' ) ) ) {\n\t\t\titemName = '$text';\n\t\t}\n\t\t// Element or module:engine/model/schema~SchemaContextItem.\n\t\telse {\n\t\t\titemName = item.name;\n\t\t}\n\n\t\treturn this.getDefinitions()[ itemName ];\n\t}\n\n\t/**\n\t * Returns `true` if the given item is registered in the schema.\n\t *\n\t *\t\tschema.isRegistered( 'paragraph' ); // -> true\n\t *\t\tschema.isRegistered( editor.model.document.getRoot() ); // -> true\n\t *\t\tschema.isRegistered( 'foo' ); // -> false\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/schema~SchemaContextItem|String} item\n\t */\n\tisRegistered( item ) {\n\t\treturn !!this.getDefinition( item );\n\t}\n\n\t/**\n\t * Returns `true` if the given item is defined to be\n\t * a block by the {@link module:engine/model/schema~SchemaItemDefinition}'s `isBlock` property.\n\t *\n\t *\t\tschema.isBlock( 'paragraph' ); // -> true\n\t *\t\tschema.isBlock( '$root' ); // -> false\n\t *\n\t *\t\tconst paragraphElement = writer.createElement( 'paragraph' );\n\t *\t\tschema.isBlock( paragraphElement ); // -> true\n\t *\n\t * See the {@glink framework/guides/deep-dive/schema#block-elements Block elements} section of the Schema deep dive\n\t * guide for more details.\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/schema~SchemaContextItem|String} item\n\t */\n\tisBlock( item ) {\n\t\tconst def = this.getDefinition( item );\n\n\t\treturn !!( def && def.isBlock );\n\t}\n\n\t/**\n\t * Returns `true` if the given item should be treated as a limit element.\n\t *\n\t * It considers an item to be a limit element if its\n\t * {@link module:engine/model/schema~SchemaItemDefinition}'s\n\t * {@link module:engine/model/schema~SchemaItemDefinition#isLimit `isLimit`} or\n\t * {@link module:engine/model/schema~SchemaItemDefinition#isObject `isObject`} property\n\t * was set to `true`.\n\t *\n\t *\t\tschema.isLimit( 'paragraph' ); // -> false\n\t *\t\tschema.isLimit( '$root' ); // -> true\n\t *\t\tschema.isLimit( editor.model.document.getRoot() ); // -> true\n\t *\t\tschema.isLimit( 'image' ); // -> true\n\t *\n\t * See the {@glink framework/guides/deep-dive/schema#limit-elements Limit elements} section of the Schema deep dive\n\t * guide for more details.\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/schema~SchemaContextItem|String} item\n\t */\n\tisLimit( item ) {\n\t\tconst def = this.getDefinition( item );\n\n\t\tif ( !def ) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn !!( def.isLimit || def.isObject );\n\t}\n\n\t/**\n\t * Returns `true` if the given item should be treated as an object element.\n\t *\n\t * It considers an item to be an object element if its\n\t * {@link module:engine/model/schema~SchemaItemDefinition}'s\n\t * {@link module:engine/model/schema~SchemaItemDefinition#isObject `isObject`} property\n\t * was set to `true`.\n\t *\n\t *\t\tschema.isObject( 'paragraph' ); // -> false\n\t *\t\tschema.isObject( 'image' ); // -> true\n\t *\n\t *\t\tconst imageElement = writer.createElement( 'image' );\n\t *\t\tschema.isObject( imageElement ); // -> true\n\t *\n\t * See the {@glink framework/guides/deep-dive/schema#object-elements Object elements} section of the Schema deep dive\n\t * guide for more details.\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/schema~SchemaContextItem|String} item\n\t */\n\tisObject( item ) {\n\t\tconst def = this.getDefinition( item );\n\n\t\tif ( !def ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Note: Check out the implementation of #isLimit(), #isSelectable(), and #isContent()\n\t\t// to understand why these three constitute an object.\n\t\treturn !!( def.isObject || ( def.isLimit && def.isSelectable && def.isContent ) );\n\t}\n\n\t/**\n\t * Returns `true` if the given item is defined to be\n\t * an inline element by the {@link module:engine/model/schema~SchemaItemDefinition}'s `isInline` property.\n\t *\n\t *\t\tschema.isInline( 'paragraph' ); // -> false\n\t *\t\tschema.isInline( 'softBreak' ); // -> true\n\t *\n\t *\t\tconst text = writer.createText( 'foo' );\n\t *\t\tschema.isInline( text ); // -> true\n\t *\n\t * See the {@glink framework/guides/deep-dive/schema#inline-elements Inline elements} section of the Schema deep dive\n\t * guide for more details.\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/schema~SchemaContextItem|String} item\n\t */\n\tisInline( item ) {\n\t\tconst def = this.getDefinition( item );\n\n\t\treturn !!( def && def.isInline );\n\t}\n\n\t/**\n\t * Returns `true` if the given item is defined to be\n\t * a selectable element by the {@link module:engine/model/schema~SchemaItemDefinition}'s `isSelectable` property.\n\t *\n\t *\t\tschema.isSelectable( 'paragraph' ); // -> false\n\t *\t\tschema.isSelectable( 'heading1' ); // -> false\n\t *\t\tschema.isSelectable( 'image' ); // -> true\n\t *\t\tschema.isSelectable( 'tableCell' ); // -> true\n\t *\n\t *\t\tconst text = writer.createText( 'foo' );\n\t *\t\tschema.isSelectable( text ); // -> false\n\t *\n\t * See the {@glink framework/guides/deep-dive/schema#selectable-elements Selectable elements} section of the Schema deep dive}\n\t * guide for more details.\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/schema~SchemaContextItem|String} item\n\t */\n\tisSelectable( item ) {\n\t\tconst def = this.getDefinition( item );\n\n\t\tif ( !def ) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn !!( def.isSelectable || def.isObject );\n\t}\n\n\t/**\n\t * Returns `true` if the given item is defined to be\n\t * a content by the {@link module:engine/model/schema~SchemaItemDefinition}'s `isContent` property.\n\t *\n\t *\t\tschema.isContent( 'paragraph' ); // -> false\n\t *\t\tschema.isContent( 'heading1' ); // -> false\n\t *\t\tschema.isContent( 'image' ); // -> true\n\t *\t\tschema.isContent( 'horizontalLine' ); // -> true\n\t *\n\t *\t\tconst text = writer.createText( 'foo' );\n\t *\t\tschema.isContent( text ); // -> true\n\t *\n\t * See the {@glink framework/guides/deep-dive/schema#content-elements Content elements} section of the Schema deep dive}\n\t * guide for more details.\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/schema~SchemaContextItem|String} item\n\t */\n\tisContent( item ) {\n\t\tconst def = this.getDefinition( item );\n\n\t\tif ( !def ) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn !!( def.isContent || def.isObject );\n\t}\n\n\t/**\n\t * Checks whether the given node (`child`) can be a child of the given context.\n\t *\n\t *\t\tschema.checkChild( model.document.getRoot(), paragraph ); // -> false\n\t *\n\t *\t\tschema.register( 'paragraph', {\n\t *\t\t\tallowIn: '$root'\n\t *\t\t} );\n\t *\t\tschema.checkChild( model.document.getRoot(), paragraph ); // -> true\n\t *\n\t * Note: When verifying whether the given node can be a child of the given context, the\n\t * schema also verifies the entire context — from its root to its last element. Therefore, it is possible\n\t * for `checkChild()` to return `false` even though the context's last element can contain the checked child.\n\t * It happens if one of the context's elements does not allow its child.\n\t *\n\t * @fires checkChild\n\t * @param {module:engine/model/schema~SchemaContextDefinition} context The context in which the child will be checked.\n\t * @param {module:engine/model/node~Node|String} def The child to check.\n\t */\n\tcheckChild( context, def ) {\n\t\t// Note: context and child are already normalized here to a SchemaContext and SchemaCompiledItemDefinition.\n\t\tif ( !def ) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn this._checkContextMatch( def, context );\n\t}\n\n\t/**\n\t * Checks whether the given attribute can be applied in the given context (on the last\n\t * item of the context).\n\t *\n\t *\t\tschema.checkAttribute( textNode, 'bold' ); // -> false\n\t *\n\t *\t\tschema.extend( '$text', {\n\t *\t\t\tallowAttributes: 'bold'\n\t *\t\t} );\n\t *\t\tschema.checkAttribute( textNode, 'bold' ); // -> true\n\t *\n\t * @fires checkAttribute\n\t * @param {module:engine/model/schema~SchemaContextDefinition} context The context in which the attribute will be checked.\n\t * @param {String} attributeName\n\t */\n\tcheckAttribute( context, attributeName ) {\n\t\tconst def = this.getDefinition( context.last );\n\n\t\tif ( !def ) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn def.allowAttributes.includes( attributeName );\n\t}\n\n\t/**\n\t * Checks whether the given element (`elementToMerge`) can be merged with the specified base element (`positionOrBaseElement`).\n\t *\n\t * In other words — whether `elementToMerge`'s children {@link #checkChild are allowed} in the `positionOrBaseElement`.\n\t *\n\t * This check ensures that elements merged with {@link module:engine/model/writer~Writer#merge `Writer#merge()`}\n\t * will be valid.\n\t *\n\t * Instead of elements, you can pass the instance of the {@link module:engine/model/position~Position} class as the\n\t * `positionOrBaseElement`. It means that the elements before and after the position will be checked whether they can be merged.\n\t *\n\t * @param {module:engine/model/position~Position|module:engine/model/element~Element} positionOrBaseElement The position or base\n\t * element to which the `elementToMerge` will be merged.\n\t * @param {module:engine/model/element~Element} elementToMerge The element to merge. Required if `positionOrBaseElement` is an element.\n\t * @returns {Boolean}\n\t */\n\tcheckMerge( positionOrBaseElement, elementToMerge = null ) {\n\t\tif ( positionOrBaseElement instanceof Position ) {\n\t\t\tconst nodeBefore = positionOrBaseElement.nodeBefore;\n\t\t\tconst nodeAfter = positionOrBaseElement.nodeAfter;\n\n\t\t\tif ( !( nodeBefore instanceof Element ) ) {\n\t\t\t\t/**\n\t\t\t\t * The node before the merge position must be an element.\n\t\t\t\t *\n\t\t\t\t * @error schema-check-merge-no-element-before\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t'schema-check-merge-no-element-before',\n\t\t\t\t\tthis\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif ( !( nodeAfter instanceof Element ) ) {\n\t\t\t\t/**\n\t\t\t\t * The node after the merge position must be an element.\n\t\t\t\t *\n\t\t\t\t * @error schema-check-merge-no-element-after\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t'schema-check-merge-no-element-after',\n\t\t\t\t\tthis\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn this.checkMerge( nodeBefore, nodeAfter );\n\t\t}\n\n\t\tfor ( const child of elementToMerge.getChildren() ) {\n\t\t\tif ( !this.checkChild( positionOrBaseElement, child ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Allows registering a callback to the {@link #checkChild} method calls.\n\t *\n\t * Callbacks allow you to implement rules which are not otherwise possible to achieve\n\t * by using the declarative API of {@link module:engine/model/schema~SchemaItemDefinition}.\n\t * For example, by using this method you can disallow elements in specific contexts.\n\t *\n\t * This method is a shorthand for using the {@link #event:checkChild} event. For even better control,\n\t * you can use that event instead.\n\t *\n\t * Example:\n\t *\n\t *\t\t// Disallow heading1 directly inside a blockQuote.\n\t *\t\tschema.addChildCheck( ( context, childDefinition ) => {\n\t *\t\t\tif ( context.endsWith( 'blockQuote' ) && childDefinition.name == 'heading1' ) {\n\t *\t\t\t\treturn false;\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * Which translates to:\n\t *\n\t *\t\tschema.on( 'checkChild', ( evt, args ) => {\n\t *\t\t\tconst context = args[ 0 ];\n\t *\t\t\tconst childDefinition = args[ 1 ];\n\t *\n\t *\t\t\tif ( context.endsWith( 'blockQuote' ) && childDefinition && childDefinition.name == 'heading1' ) {\n\t *\t\t\t\t// Prevent next listeners from being called.\n\t *\t\t\t\tevt.stop();\n\t *\t\t\t\t// Set the checkChild()'s return value.\n\t *\t\t\t\tevt.return = false;\n\t *\t\t\t}\n\t *\t\t}, { priority: 'high' } );\n\t *\n\t * @param {Function} callback The callback to be called. It is called with two parameters:\n\t * {@link module:engine/model/schema~SchemaContext} (context) instance and\n\t * {@link module:engine/model/schema~SchemaCompiledItemDefinition} (child-to-check definition).\n\t * The callback may return `true/false` to override `checkChild()`'s return value. If it does not return\n\t * a boolean value, the default algorithm (or other callbacks) will define `checkChild()`'s return value.\n\t */\n\taddChildCheck( callback ) {\n\t\tthis.on( 'checkChild', ( evt, [ ctx, childDef ] ) => {\n\t\t\t// checkChild() was called with a non-registered child.\n\t\t\t// In 99% cases such check should return false, so not to overcomplicate all callbacks\n\t\t\t// don't even execute them.\n\t\t\tif ( !childDef ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst retValue = callback( ctx, childDef );\n\n\t\t\tif ( typeof retValue == 'boolean' ) {\n\t\t\t\tevt.stop();\n\t\t\t\tevt.return = retValue;\n\t\t\t}\n\t\t}, { priority: 'high' } );\n\t}\n\n\t/**\n\t * Allows registering a callback to the {@link #checkAttribute} method calls.\n\t *\n\t * Callbacks allow you to implement rules which are not otherwise possible to achieve\n\t * by using the declarative API of {@link module:engine/model/schema~SchemaItemDefinition}.\n\t * For example, by using this method you can disallow attribute if node to which it is applied\n\t * is contained within some other element (e.g. you want to disallow `bold` on `$text` within `heading1`).\n\t *\n\t * This method is a shorthand for using the {@link #event:checkAttribute} event. For even better control,\n\t * you can use that event instead.\n\t *\n\t * Example:\n\t *\n\t *\t\t// Disallow bold on $text inside heading1.\n\t *\t\tschema.addAttributeCheck( ( context, attributeName ) => {\n\t *\t\t\tif ( context.endsWith( 'heading1 $text' ) && attributeName == 'bold' ) {\n\t *\t\t\t\treturn false;\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * Which translates to:\n\t *\n\t *\t\tschema.on( 'checkAttribute', ( evt, args ) => {\n\t *\t\t\tconst context = args[ 0 ];\n\t *\t\t\tconst attributeName = args[ 1 ];\n\t *\n\t *\t\t\tif ( context.endsWith( 'heading1 $text' ) && attributeName == 'bold' ) {\n\t *\t\t\t\t// Prevent next listeners from being called.\n\t *\t\t\t\tevt.stop();\n\t *\t\t\t\t// Set the checkAttribute()'s return value.\n\t *\t\t\t\tevt.return = false;\n\t *\t\t\t}\n\t *\t\t}, { priority: 'high' } );\n\t *\n\t * @param {Function} callback The callback to be called. It is called with two parameters:\n\t * {@link module:engine/model/schema~SchemaContext} (context) instance and attribute name.\n\t * The callback may return `true/false` to override `checkAttribute()`'s return value. If it does not return\n\t * a boolean value, the default algorithm (or other callbacks) will define `checkAttribute()`'s return value.\n\t */\n\taddAttributeCheck( callback ) {\n\t\tthis.on( 'checkAttribute', ( evt, [ ctx, attributeName ] ) => {\n\t\t\tconst retValue = callback( ctx, attributeName );\n\n\t\t\tif ( typeof retValue == 'boolean' ) {\n\t\t\t\tevt.stop();\n\t\t\t\tevt.return = retValue;\n\t\t\t}\n\t\t}, { priority: 'high' } );\n\t}\n\n\t/**\n\t * This method allows assigning additional metadata to the model attributes. For example,\n\t * {@link module:engine/model/schema~AttributeProperties `AttributeProperties#isFormatting` property} is\n\t * used to mark formatting attributes (like `bold` or `italic`).\n\t *\n\t *\t\t// Mark bold as a formatting attribute.\n\t *\t\tschema.setAttributeProperties( 'bold', {\n\t *\t\t\tisFormatting: true\n\t *\t\t} );\n\t *\n\t *\t\t// Override code not to be considered a formatting markup.\n\t *\t\tschema.setAttributeProperties( 'code', {\n\t *\t\t\tisFormatting: false\n\t *\t\t} );\n\t *\n\t * Properties are not limited to members defined in the\n\t * {@link module:engine/model/schema~AttributeProperties `AttributeProperties` type} and you can also use custom properties:\n\t *\n\t *\t\tschema.setAttributeProperties( 'blockQuote', {\n\t *\t\t\tcustomProperty: 'value'\n\t *\t\t} );\n\t *\n\t * Subsequent calls with the same attribute will extend its custom properties:\n\t *\n\t *\t\tschema.setAttributeProperties( 'blockQuote', {\n\t *\t\t\tone: 1\n\t *\t\t} );\n\t *\n\t *\t\tschema.setAttributeProperties( 'blockQuote', {\n\t *\t\t\ttwo: 2\n\t *\t\t} );\n\t *\n\t *\t\tconsole.log( schema.getAttributeProperties( 'blockQuote' ) );\n\t *\t\t// Logs: { one: 1, two: 2 }\n\t *\n\t * @param {String} attributeName A name of the attribute to receive the properties.\n\t * @param {module:engine/model/schema~AttributeProperties} properties A dictionary of properties.\n\t */\n\tsetAttributeProperties( attributeName, properties ) {\n\t\tthis._attributeProperties[ attributeName ] = Object.assign( this.getAttributeProperties( attributeName ), properties );\n\t}\n\n\t/**\n\t * Returns properties associated with a given model attribute. See {@link #setAttributeProperties `setAttributeProperties()`}.\n\t *\n\t * @param {String} attributeName A name of the attribute.\n\t * @returns {module:engine/model/schema~AttributeProperties}\n\t */\n\tgetAttributeProperties( attributeName ) {\n\t\treturn this._attributeProperties[ attributeName ] || {};\n\t}\n\n\t/**\n\t * Returns the lowest {@link module:engine/model/schema~Schema#isLimit limit element} containing the entire\n\t * selection/range/position or the root otherwise.\n\t *\n\t * @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection|\n\t * module:engine/model/range~Range|module:engine/model/position~Position} selectionOrRangeOrPosition\n\t * The selection/range/position to check.\n\t * @returns {module:engine/model/element~Element} The lowest limit element containing\n\t * the entire `selectionOrRangeOrPosition`.\n\t */\n\tgetLimitElement( selectionOrRangeOrPosition ) {\n\t\tlet element;\n\n\t\tif ( selectionOrRangeOrPosition instanceof Position ) {\n\t\t\telement = selectionOrRangeOrPosition.parent;\n\t\t} else {\n\t\t\tconst ranges = selectionOrRangeOrPosition instanceof Range ?\n\t\t\t\t[ selectionOrRangeOrPosition ] :\n\t\t\t\tArray.from( selectionOrRangeOrPosition.getRanges() );\n\n\t\t\t// Find the common ancestor for all selection's ranges.\n\t\t\telement = ranges\n\t\t\t\t.reduce( ( element, range ) => {\n\t\t\t\t\tconst rangeCommonAncestor = range.getCommonAncestor();\n\n\t\t\t\t\tif ( !element ) {\n\t\t\t\t\t\treturn rangeCommonAncestor;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn element.getCommonAncestor( rangeCommonAncestor, { includeSelf: true } );\n\t\t\t\t}, null );\n\t\t}\n\n\t\twhile ( !this.isLimit( element ) ) {\n\t\t\tif ( element.parent ) {\n\t\t\t\telement = element.parent;\n\t\t\t} else {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn element;\n\t}\n\n\t/**\n\t * Checks whether the attribute is allowed in selection:\n\t *\n\t * * if the selection is not collapsed, then checks if the attribute is allowed on any of nodes in that range,\n\t * * if the selection is collapsed, then checks if on the selection position there's a text with the\n\t * specified attribute allowed.\n\t *\n\t * @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection\n\t * Selection which will be checked.\n\t * @param {String} attribute The name of the attribute to check.\n\t * @returns {Boolean}\n\t */\n\tcheckAttributeInSelection( selection, attribute ) {\n\t\tif ( selection.isCollapsed ) {\n\t\t\tconst firstPosition = selection.getFirstPosition();\n\t\t\tconst context = [\n\t\t\t\t...firstPosition.getAncestors(),\n\t\t\t\tnew Text( '', selection.getAttributes() )\n\t\t\t];\n\n\t\t\t// Check whether schema allows for a text with the attribute in the selection.\n\t\t\treturn this.checkAttribute( context, attribute );\n\t\t} else {\n\t\t\tconst ranges = selection.getRanges();\n\n\t\t\t// For all ranges, check nodes in them until you find a node that is allowed to have the attribute.\n\t\t\tfor ( const range of ranges ) {\n\t\t\t\tfor ( const value of range ) {\n\t\t\t\t\tif ( this.checkAttribute( value.item, attribute ) ) {\n\t\t\t\t\t\t// If we found a node that is allowed to have the attribute, return true.\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// If we haven't found such node, return false.\n\t\treturn false;\n\t}\n\n\t/**\n\t * Transforms the given set of ranges into a set of ranges where the given attribute is allowed (and can be applied).\n\t *\n\t * @param {Array.} ranges Ranges to be validated.\n\t * @param {String} attribute The name of the attribute to check.\n\t * @returns {Iterable.} Ranges in which the attribute is allowed.\n\t */\n\t* getValidRanges( ranges, attribute ) {\n\t\tranges = convertToMinimalFlatRanges( ranges );\n\n\t\tfor ( const range of ranges ) {\n\t\t\tyield* this._getValidRangesForRange( range, attribute );\n\t\t}\n\t}\n\n\t/**\n\t * Basing on given `position`, finds and returns a {@link module:engine/model/range~Range range} which is\n\t * nearest to that `position` and is a correct range for selection.\n\t *\n\t * The correct selection range might be collapsed when it is located in a position where the text node can be placed.\n\t * Non-collapsed range is returned when selection can be placed around element marked as an \"object\" in\n\t * the {@link module:engine/model/schema~Schema schema}.\n\t *\n\t * Direction of searching for the nearest correct selection range can be specified as:\n\t *\n\t * * `both` - searching will be performed in both ways,\n\t * * `forward` - searching will be performed only forward,\n\t * * `backward` - searching will be performed only backward.\n\t *\n\t * When valid selection range cannot be found, `null` is returned.\n\t *\n\t * @param {module:engine/model/position~Position} position Reference position where new selection range should be looked for.\n\t * @param {'both'|'forward'|'backward'} [direction='both'] Search direction.\n\t * @returns {module:engine/model/range~Range|null} Nearest selection range or `null` if one cannot be found.\n\t */\n\tgetNearestSelectionRange( position, direction = 'both' ) {\n\t\t// Return collapsed range if provided position is valid.\n\t\tif ( this.checkChild( position, '$text' ) ) {\n\t\t\treturn new Range( position );\n\t\t}\n\n\t\tlet backwardWalker, forwardWalker;\n\n\t\t// Never leave a limit element.\n\t\tconst limitElement = position.getAncestors().reverse().find( item => this.isLimit( item ) ) || position.root;\n\n\t\tif ( direction == 'both' || direction == 'backward' ) {\n\t\t\tbackwardWalker = new TreeWalker( {\n\t\t\t\tboundaries: Range._createIn( limitElement ),\n\t\t\t\tstartPosition: position,\n\t\t\t\tdirection: 'backward'\n\t\t\t} );\n\t\t}\n\n\t\tif ( direction == 'both' || direction == 'forward' ) {\n\t\t\tforwardWalker = new TreeWalker( {\n\t\t\t\tboundaries: Range._createIn( limitElement ),\n\t\t\t\tstartPosition: position\n\t\t\t} );\n\t\t}\n\n\t\tfor ( const data of combineWalkers( backwardWalker, forwardWalker ) ) {\n\t\t\tconst type = ( data.walker == backwardWalker ? 'elementEnd' : 'elementStart' );\n\t\t\tconst value = data.value;\n\n\t\t\tif ( value.type == type && this.isObject( value.item ) ) {\n\t\t\t\treturn Range._createOn( value.item );\n\t\t\t}\n\n\t\t\tif ( this.checkChild( value.nextPosition, '$text' ) ) {\n\t\t\t\treturn new Range( value.nextPosition );\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Tries to find position ancestors that allow to insert a given node.\n\t * It starts searching from the given position and goes node by node to the top of the model tree\n\t * as long as a {@link module:engine/model/schema~Schema#isLimit limit element}, an\n\t * {@link module:engine/model/schema~Schema#isObject object element} or a topmost ancestor is not reached.\n\t *\n\t * @param {module:engine/model/position~Position} position The position that the search will start from.\n\t * @param {module:engine/model/node~Node|String} node The node for which an allowed parent should be found or its name.\n\t * @returns {module:engine/model/element~Element|null} element Allowed parent or null if nothing was found.\n\t */\n\tfindAllowedParent( position, node ) {\n\t\tlet parent = position.parent;\n\n\t\twhile ( parent ) {\n\t\t\tif ( this.checkChild( parent, node ) ) {\n\t\t\t\treturn parent;\n\t\t\t}\n\n\t\t\t// Do not split limit elements.\n\t\t\tif ( this.isLimit( parent ) ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tparent = parent.parent;\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Removes attributes disallowed by the schema.\n\t *\n\t * @param {Iterable.} nodes Nodes that will be filtered.\n\t * @param {module:engine/model/writer~Writer} writer\n\t */\n\tremoveDisallowedAttributes( nodes, writer ) {\n\t\tfor ( const node of nodes ) {\n\t\t\t// When node is a `Text` it has no children, so just filter it out.\n\t\t\tif ( node.is( '$text' ) ) {\n\t\t\t\tremoveDisallowedAttributeFromNode( this, node, writer );\n\t\t\t}\n\t\t\t// In a case of `Element` iterates through positions between nodes inside this element\n\t\t\t// and filter out node before the current position, or position parent when position\n\t\t\t// is at start of an element. Using positions prevent from omitting merged nodes\n\t\t\t// see https://github.com/ckeditor/ckeditor5-engine/issues/1789.\n\t\t\telse {\n\t\t\t\tconst rangeInNode = Range._createIn( node );\n\t\t\t\tconst positionsInRange = rangeInNode.getPositions();\n\n\t\t\t\tfor ( const position of positionsInRange ) {\n\t\t\t\t\tconst item = position.nodeBefore || position.parent;\n\n\t\t\t\t\tremoveDisallowedAttributeFromNode( this, item, writer );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Creates an instance of the schema context.\n\t *\n\t * @param {module:engine/model/schema~SchemaContextDefinition} context\n\t * @returns {module:engine/model/schema~SchemaContext}\n\t */\n\tcreateContext( context ) {\n\t\treturn new SchemaContext( context );\n\t}\n\n\t/**\n\t * @private\n\t */\n\t_clearCache() {\n\t\tthis._compiledDefinitions = null;\n\t}\n\n\t/**\n\t * @private\n\t */\n\t_compile() {\n\t\tconst compiledDefinitions = {};\n\t\tconst sourceRules = this._sourceDefinitions;\n\t\tconst itemNames = Object.keys( sourceRules );\n\n\t\tfor ( const itemName of itemNames ) {\n\t\t\tcompiledDefinitions[ itemName ] = compileBaseItemRule( sourceRules[ itemName ], itemName );\n\t\t}\n\n\t\tfor ( const itemName of itemNames ) {\n\t\t\tcompileAllowContentOf( compiledDefinitions, itemName );\n\t\t}\n\n\t\tfor ( const itemName of itemNames ) {\n\t\t\tcompileAllowWhere( compiledDefinitions, itemName );\n\t\t}\n\n\t\tfor ( const itemName of itemNames ) {\n\t\t\tcompileAllowAttributesOf( compiledDefinitions, itemName );\n\t\t\tcompileInheritPropertiesFrom( compiledDefinitions, itemName );\n\t\t}\n\n\t\tfor ( const itemName of itemNames ) {\n\t\t\tcleanUpAllowIn( compiledDefinitions, itemName );\n\t\t\tcleanUpAllowAttributes( compiledDefinitions, itemName );\n\t\t}\n\n\t\tthis._compiledDefinitions = compiledDefinitions;\n\t}\n\n\t/**\n\t * @private\n\t * @param {module:engine/model/schema~SchemaCompiledItemDefinition} def\n\t * @param {module:engine/model/schema~SchemaContext} context\n\t * @param {Number} contextItemIndex\n\t */\n\t_checkContextMatch( def, context, contextItemIndex = context.length - 1 ) {\n\t\tconst contextItem = context.getItem( contextItemIndex );\n\n\t\tif ( def.allowIn.includes( contextItem.name ) ) {\n\t\t\tif ( contextItemIndex == 0 ) {\n\t\t\t\treturn true;\n\t\t\t} else {\n\t\t\t\tconst parentRule = this.getDefinition( contextItem );\n\n\t\t\t\treturn this._checkContextMatch( parentRule, context, contextItemIndex - 1 );\n\t\t\t}\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Takes a flat range and an attribute name. Traverses the range recursively and deeply to find and return all ranges\n\t * inside the given range on which the attribute can be applied.\n\t *\n\t * This is a helper function for {@link ~Schema#getValidRanges}.\n\t *\n\t * @private\n\t * @param {module:engine/model/range~Range} range The range to process.\n\t * @param {String} attribute The name of the attribute to check.\n\t * @returns {Iterable.} Ranges in which the attribute is allowed.\n\t */\n\t* _getValidRangesForRange( range, attribute ) {\n\t\tlet start = range.start;\n\t\tlet end = range.start;\n\n\t\tfor ( const item of range.getItems( { shallow: true } ) ) {\n\t\t\tif ( item.is( 'element' ) ) {\n\t\t\t\tyield* this._getValidRangesForRange( Range._createIn( item ), attribute );\n\t\t\t}\n\n\t\t\tif ( !this.checkAttribute( item, attribute ) ) {\n\t\t\t\tif ( !start.isEqual( end ) ) {\n\t\t\t\t\tyield new Range( start, end );\n\t\t\t\t}\n\n\t\t\t\tstart = Position._createAfter( item );\n\t\t\t}\n\n\t\t\tend = Position._createAfter( item );\n\t\t}\n\n\t\tif ( !start.isEqual( end ) ) {\n\t\t\tyield new Range( start, end );\n\t\t}\n\t}\n}\n\nmix( Schema, ObservableMixin );\n\n/**\n * Event fired when the {@link #checkChild} method is called. It allows plugging in\n * additional behavior, for example implementing rules which cannot be defined using the declarative\n * {@link module:engine/model/schema~SchemaItemDefinition} interface.\n *\n * **Note:** The {@link #addChildCheck} method is a more handy way to register callbacks. Internally,\n * it registers a listener to this event but comes with a simpler API and it is the recommended choice\n * in most of the cases.\n *\n * The {@link #checkChild} method fires an event because it is\n * {@link module:utils/observablemixin~ObservableMixin#decorate decorated} with it. Thanks to that you can\n * use this event in various ways, but the most important use case is overriding standard behavior of the\n * `checkChild()` method. Let's see a typical listener template:\n *\n *\t\tschema.on( 'checkChild', ( evt, args ) => {\n *\t\t\tconst context = args[ 0 ];\n *\t\t\tconst childDefinition = args[ 1 ];\n *\t\t}, { priority: 'high' } );\n *\n * The listener is added with a `high` priority to be executed before the default method is really called. The `args` callback\n * parameter contains arguments passed to `checkChild( context, child )`. However, the `context` parameter is already\n * normalized to a {@link module:engine/model/schema~SchemaContext} instance and `child` to a\n * {@link module:engine/model/schema~SchemaCompiledItemDefinition} instance, so you do not have to worry about\n * the various ways how `context` and `child` may be passed to `checkChild()`.\n *\n * **Note:** `childDefinition` may be `undefined` if `checkChild()` was called with a non-registered element.\n *\n * So, in order to implement a rule \"disallow `heading1` in `blockQuote`\", you can add such a listener:\n *\n *\t\tschema.on( 'checkChild', ( evt, args ) => {\n *\t\t\tconst context = args[ 0 ];\n *\t\t\tconst childDefinition = args[ 1 ];\n *\n *\t\t\tif ( context.endsWith( 'blockQuote' ) && childDefinition && childDefinition.name == 'heading1' ) {\n *\t\t\t\t// Prevent next listeners from being called.\n *\t\t\t\tevt.stop();\n *\t\t\t\t// Set the checkChild()'s return value.\n *\t\t\t\tevt.return = false;\n *\t\t\t}\n *\t\t}, { priority: 'high' } );\n *\n * Allowing elements in specific contexts will be a far less common use case, because it is normally handled by the\n * `allowIn` rule from {@link module:engine/model/schema~SchemaItemDefinition}. But if you have a complex scenario\n * where `listItem` should be allowed only in element `foo` which must be in element `bar`, then this would be the way:\n *\n *\t\tschema.on( 'checkChild', ( evt, args ) => {\n *\t\t\tconst context = args[ 0 ];\n *\t\t\tconst childDefinition = args[ 1 ];\n *\n *\t\t\tif ( context.endsWith( 'bar foo' ) && childDefinition.name == 'listItem' ) {\n *\t\t\t\t// Prevent next listeners from being called.\n *\t\t\t\tevt.stop();\n *\t\t\t\t// Set the checkChild()'s return value.\n *\t\t\t\tevt.return = true;\n *\t\t\t}\n *\t\t}, { priority: 'high' } );\n *\n * @event checkChild\n * @param {Array} args The `checkChild()`'s arguments.\n */\n\n/**\n * Event fired when the {@link #checkAttribute} method is called. It allows plugging in\n * additional behavior, for example implementing rules which cannot be defined using the declarative\n * {@link module:engine/model/schema~SchemaItemDefinition} interface.\n *\n * **Note:** The {@link #addAttributeCheck} method is a more handy way to register callbacks. Internally,\n * it registers a listener to this event but comes with a simpler API and it is the recommended choice\n * in most of the cases.\n *\n * The {@link #checkAttribute} method fires an event because it is\n * {@link module:utils/observablemixin~ObservableMixin#decorate decorated} with it. Thanks to that you can\n * use this event in various ways, but the most important use case is overriding the standard behavior of the\n * `checkAttribute()` method. Let's see a typical listener template:\n *\n *\t\tschema.on( 'checkAttribute', ( evt, args ) => {\n *\t\t\tconst context = args[ 0 ];\n *\t\t\tconst attributeName = args[ 1 ];\n *\t\t}, { priority: 'high' } );\n *\n * The listener is added with a `high` priority to be executed before the default method is really called. The `args` callback\n * parameter contains arguments passed to `checkAttribute( context, attributeName )`. However, the `context` parameter is already\n * normalized to a {@link module:engine/model/schema~SchemaContext} instance, so you do not have to worry about\n * the various ways how `context` may be passed to `checkAttribute()`.\n *\n * So, in order to implement a rule \"disallow `bold` in a text which is in a `heading1`, you can add such a listener:\n *\n *\t\tschema.on( 'checkAttribute', ( evt, args ) => {\n *\t\t\tconst context = args[ 0 ];\n *\t\t\tconst attributeName = args[ 1 ];\n *\n *\t\t\tif ( context.endsWith( 'heading1 $text' ) && attributeName == 'bold' ) {\n *\t\t\t\t// Prevent next listeners from being called.\n *\t\t\t\tevt.stop();\n *\t\t\t\t// Set the checkAttribute()'s return value.\n *\t\t\t\tevt.return = false;\n *\t\t\t}\n *\t\t}, { priority: 'high' } );\n *\n * Allowing attributes in specific contexts will be a far less common use case, because it is normally handled by the\n * `allowAttributes` rule from {@link module:engine/model/schema~SchemaItemDefinition}. But if you have a complex scenario\n * where `bold` should be allowed only in element `foo` which must be in element `bar`, then this would be the way:\n *\n *\t\tschema.on( 'checkAttribute', ( evt, args ) => {\n *\t\t\tconst context = args[ 0 ];\n *\t\t\tconst attributeName = args[ 1 ];\n *\n *\t\t\tif ( context.endsWith( 'bar foo $text' ) && attributeName == 'bold' ) {\n *\t\t\t\t// Prevent next listeners from being called.\n *\t\t\t\tevt.stop();\n *\t\t\t\t// Set the checkAttribute()'s return value.\n *\t\t\t\tevt.return = true;\n *\t\t\t}\n *\t\t}, { priority: 'high' } );\n *\n * @event checkAttribute\n * @param {Array} args The `checkAttribute()`'s arguments.\n */\n\n/**\n * A definition of a {@link module:engine/model/schema~Schema schema} item.\n *\n * You can define the following rules:\n *\n * * {@link ~SchemaItemDefinition#allowIn `allowIn`} – Defines in which other items this item will be allowed.\n * * {@link ~SchemaItemDefinition#allowAttributes `allowAttributes`} – Defines allowed attributes of the given item.\n * * {@link ~SchemaItemDefinition#allowContentOf `allowContentOf`} – Inherits \"allowed children\" from other items.\n * * {@link ~SchemaItemDefinition#allowWhere `allowWhere`} – Inherits \"allowed in\" from other items.\n * * {@link ~SchemaItemDefinition#allowAttributesOf `allowAttributesOf`} – Inherits attributes from other items.\n * * {@link ~SchemaItemDefinition#inheritTypesFrom `inheritTypesFrom`} – Inherits `is*` properties of other items.\n * * {@link ~SchemaItemDefinition#inheritAllFrom `inheritAllFrom`} –\n * A shorthand for `allowContentOf`, `allowWhere`, `allowAttributesOf`, `inheritTypesFrom`.\n *\n * # The `is*` properties\n *\n * There are a couple commonly used `is*` properties. Their role is to assign additional semantics to schema items.\n * You can define more properties but you will also need to implement support for them in the existing editor features.\n *\n * * {@link ~SchemaItemDefinition#isBlock `isBlock`} – Whether this item is paragraph-like.\n * Generally speaking, content is usually made out of blocks like paragraphs, list items, images, headings, etc.\n * * {@link ~SchemaItemDefinition#isInline `isInline`} – Whether an item is \"text-like\" and should be treated as an inline node.\n * Examples of inline elements: `$text`, `softBreak` (`
`), etc.\n * * {@link ~SchemaItemDefinition#isLimit `isLimit`} – It can be understood as whether this element\n * should not be split by Enter. Examples of limit elements: `$root`, table cell, image caption, etc.\n * In other words, all actions that happen inside a limit element are limited to its content.\n * All objects are treated as limit elements, too.\n * * {@link ~SchemaItemDefinition#isObject `isObject`} – Whether an item is \"self-contained\" and should be treated as a whole.\n * Examples of object elements: `image`, `table`, `video`, etc. An object is also a limit, so\n * {@link module:engine/model/schema~Schema#isLimit `isLimit()`} returns `true` for object elements automatically.\n *\n * Read more about the meaning of these types in the\n * {@glink framework/guides/deep-dive/schema#defining-additional-semantics dedicated section of the Schema deep dive} guide.\n *\n * # Generic items\n *\n * There are three basic generic items: `$root`, `$block` and `$text`.\n * They are defined as follows:\n *\n *\t\tthis.schema.register( '$root', {\n *\t\t\tisLimit: true\n *\t\t} );\n *\t\tthis.schema.register( '$block', {\n *\t\t\tallowIn: '$root',\n *\t\t\tisBlock: true\n *\t\t} );\n *\t\tthis.schema.register( '$text', {\n *\t\t\tallowIn: '$block',\n *\t\t\tisInline: true\n *\t\t} );\n *\n * They reflect typical editor content that is contained within one root, consists of several blocks\n * (paragraphs, lists items, headings, images) which, in turn, may contain text inside.\n *\n * By inheriting from the generic items you can define new items which will get extended by other editor features.\n * Read more about generic types in the {@glink framework/guides/deep-dive/schema Schema deep dive} guide.\n *\n * # Example definitions\n *\n * Allow `paragraph` in roots and block quotes:\n *\n *\t\tschema.register( 'paragraph', {\n *\t\t\tallowIn: [ '$root', 'blockQuote' ],\n *\t\t\tisBlock: true\n *\t\t} );\n *\n * Allow `paragraph` everywhere where `$block` is allowed (i.e. in `$root`):\n *\n *\t\tschema.register( 'paragraph', {\n *\t\t\tallowWhere: '$block',\n *\t\t\tisBlock: true\n *\t\t} );\n *\n * Make `image` a block object, which is allowed everywhere where `$block` is.\n * Also, allow `src` and `alt` attributes in it:\n *\n *\t\tschema.register( 'image', {\n *\t\t\tallowWhere: '$block',\n *\t\t\tallowAttributes: [ 'src', 'alt' ],\n *\t\t\tisBlock: true,\n *\t\t\tisObject: true\n *\t\t} );\n *\n * Make `caption` allowed in `image` and make it allow all the content of `$block`s (usually, `$text`).\n * Also, mark it as a limit element so it cannot be split:\n *\n *\t\tschema.register( 'caption', {\n *\t\t\tallowIn: 'image',\n *\t\t\tallowContentOf: '$block',\n *\t\t\tisLimit: true\n *\t\t} );\n *\n * Make `listItem` inherit all from `$block` but also allow additional attributes:\n *\n *\t\tschema.register( 'listItem', {\n *\t\t\tinheritAllFrom: '$block',\n *\t\t\tallowAttributes: [ 'listType', 'listIndent' ]\n *\t\t} );\n *\n * Which translates to:\n *\n *\t\tschema.register( 'listItem', {\n *\t\t\tallowWhere: '$block',\n *\t\t\tallowContentOf: '$block',\n *\t\t\tallowAttributesOf: '$block',\n *\t\t\tinheritTypesFrom: '$block',\n *\t\t\tallowAttributes: [ 'listType', 'listIndent' ]\n *\t\t} );\n *\n * # Tips\n *\n * * Check schema definitions of existing features to see how they are defined.\n * * If you want to publish your feature so other developers can use it, try to use\n * generic items as much as possible.\n * * Keep your model clean. Limit it to the actual data and store information in a normalized way.\n * * Remember about defining the `is*` properties. They do not affect the allowed structures, but they can\n * affect how the editor features treat your elements.\n *\n * @typedef {Object} module:engine/model/schema~SchemaItemDefinition\n *\n * @property {String|Array.} allowIn Defines in which other items this item will be allowed.\n * @property {String|Array.} allowAttributes Defines allowed attributes of the given item.\n * @property {String|Array.} allowContentOf Inherits \"allowed children\" from other items.\n * @property {String|Array.} allowWhere Inherits \"allowed in\" from other items.\n * @property {String|Array.} allowAttributesOf Inherits attributes from other items.\n * @property {String|Array.} inheritTypesFrom Inherits `is*` properties of other items.\n * @property {String} inheritAllFrom A shorthand for `allowContentOf`, `allowWhere`, `allowAttributesOf`, `inheritTypesFrom`.\n *\n * @property {Boolean} isBlock\n * Whether this item is paragraph-like. Generally speaking, content is usually made out of blocks\n * like paragraphs, list items, images, headings, etc. All these elements are marked as blocks. A block\n * should not allow another block inside. Note: There is also the `$block` generic item which has `isBlock` set to `true`.\n * Most block type items will inherit from `$block` (through `inheritAllFrom`).\n *\n * Read more about the block elements in the\n * {@glink framework/guides/deep-dive/schema#block-elements Block elements} section of the Schema deep dive} guide.\n *\n * @property {Boolean} isInline\n * Whether an item is \"text-like\" and should be treated as an inline node. Examples of inline elements:\n * `$text`, `softBreak` (`
`), etc.\n *\n * Read more about the inline elements in the\n * {@glink framework/guides/deep-dive/schema#inline-elements Inline elements} section of the Schema deep dive} guide.\n *\n * @property {Boolean} isLimit\n * It can be understood as whether this element should not be split by Enter.\n * Examples of limit elements: `$root`, table cell, image caption, etc. In other words, all actions that happen inside\n * a limit element are limited to its content.\n *\n * Read more about the limit elements in the\n * {@glink framework/guides/deep-dive/schema#limit-elements Limit elements} section of the Schema deep dive} guide.\n *\n * @property {Boolean} isObject\n * Whether an item is \"self-contained\" and should be treated as a whole. Examples of object elements:\n * `image`, `table`, `video`, etc.\n *\n * **Note:** An object is also a limit, so\n * {@link module:engine/model/schema~Schema#isLimit `isLimit()`} returns `true` for object elements automatically.\n *\n * Read more about the object elements in the\n * {@glink framework/guides/deep-dive/schema#object-elements Object elements} section of the Schema deep dive} guide.\n *\n * @property {Boolean} isSelectable\n * `true` when an element should be selectable as a whole by the user. Examples of selectable elements: `image`, `table`, `tableCell`, etc.\n *\n * **Note:** An object is also a selectable element, so\n * {@link module:engine/model/schema~Schema#isSelectable `isSelectable()`} returns `true` for object elements automatically.\n *\n * Read more about selectable elements in the\n * {@glink framework/guides/deep-dive/schema#selectable-elements Selectable elements} section of the Schema deep dive} guide.\n *\n * @property {Boolean} isContent\n * An item is a content when it always finds its way to the editor data output regardless of the number and type of its descendants.\n * Examples of content elements: `$text`, `image`, `table`, etc. (but not `paragraph`, `heading1` or `tableCell`).\n *\n * **Note:** An object is also a content element, so\n * {@link module:engine/model/schema~Schema#isContent `isContent()`} returns `true` for object elements automatically.\n *\n * Read more about content elements in the\n * {@glink framework/guides/deep-dive/schema#content-elements Content elements} section of the Schema deep dive} guide.\n */\n\n/**\n * A simplified version of {@link module:engine/model/schema~SchemaItemDefinition} after\n * compilation by the {@link module:engine/model/schema~Schema schema}.\n * Rules fed to the schema by {@link module:engine/model/schema~Schema#register}\n * and {@link module:engine/model/schema~Schema#extend} methods are defined in the\n * {@link module:engine/model/schema~SchemaItemDefinition} format.\n * Later on, they are compiled to `SchemaCompiledItemDefinition` so when you use e.g.\n * the {@link module:engine/model/schema~Schema#getDefinition} method you get the compiled version.\n *\n * The compiled version contains only the following properties:\n *\n * * The `name` property,\n * * The `is*` properties,\n * * The `allowIn` array,\n * * The `allowAttributes` array.\n *\n * @typedef {Object} module:engine/model/schema~SchemaCompiledItemDefinition\n */\n\n/**\n * A schema context — a list of ancestors of a given position in the document.\n *\n * Considering such position:\n *\n *\t\t<$root>\n *\t\t\t
\n *\t\t\t\t\n *\t\t\t\t\t^\n *\t\t\t\t\n *\t\t\t
\n *\t\t\n *\n * The context of this position is its {@link module:engine/model/position~Position#getAncestors lists of ancestors}:\n *\n *\t\t[ rootElement, blockQuoteElement, paragraphElement ]\n *\n * Contexts are used in the {@link module:engine/model/schema~Schema#event:checkChild `Schema#checkChild`} and\n * {@link module:engine/model/schema~Schema#event:checkAttribute `Schema#checkAttribute`} events as a definition\n * of a place in the document where the check occurs. The context instances are created based on the first arguments\n * of the {@link module:engine/model/schema~Schema#checkChild `Schema#checkChild()`} and\n * {@link module:engine/model/schema~Schema#checkAttribute `Schema#checkAttribute()`} methods so when\n * using these methods you need to use {@link module:engine/model/schema~SchemaContextDefinition}s.\n */\nexport class SchemaContext {\n\t/**\n\t * Creates an instance of the context.\n\t *\n\t * @param {module:engine/model/schema~SchemaContextDefinition} context\n\t */\n\tconstructor( context ) {\n\t\tif ( context instanceof SchemaContext ) {\n\t\t\treturn context;\n\t\t}\n\n\t\tif ( typeof context == 'string' ) {\n\t\t\tcontext = [ context ];\n\t\t} else if ( !Array.isArray( context ) ) {\n\t\t\t// `context` is item or position.\n\t\t\t// Position#getAncestors() doesn't accept any parameters but it works just fine here.\n\t\t\tcontext = context.getAncestors( { includeSelf: true } );\n\t\t}\n\n\t\tif ( context[ 0 ] && typeof context[ 0 ] != 'string' && context[ 0 ].is( 'documentFragment' ) ) {\n\t\t\tcontext.shift();\n\t\t}\n\n\t\tthis._items = context.map( mapContextItem );\n\t}\n\n\t/**\n\t * The number of items.\n\t *\n\t * @type {Number}\n\t */\n\tget length() {\n\t\treturn this._items.length;\n\t}\n\n\t/**\n\t * The last item (the lowest node).\n\t *\n\t * @type {module:engine/model/schema~SchemaContextItem}\n\t */\n\tget last() {\n\t\treturn this._items[ this._items.length - 1 ];\n\t}\n\n\t/**\n\t * Iterable interface.\n\t *\n\t * Iterates over all context items.\n\t *\n\t * @returns {Iterable.}\n\t */\n\t[ Symbol.iterator ]() {\n\t\treturn this._items[ Symbol.iterator ]();\n\t}\n\n\t/**\n\t * Returns a new schema context instance with an additional item.\n\t *\n\t * Item can be added as:\n\t *\n\t * \t\tconst context = new SchemaContext( [ '$root' ] );\n\t *\n\t * \t\t// An element.\n\t * \t\tconst fooElement = writer.createElement( 'fooElement' );\n\t * \t\tconst newContext = context.push( fooElement ); // [ '$root', 'fooElement' ]\n\t *\n\t * \t\t// A text node.\n\t * \t\tconst text = writer.createText( 'foobar' );\n\t * \t\tconst newContext = context.push( text ); // [ '$root', '$text' ]\n\t *\n\t * \t\t// A string (element name).\n\t * \t\tconst newContext = context.push( 'barElement' ); // [ '$root', 'barElement' ]\n\t *\n\t * **Note** {@link module:engine/model/node~Node} that is already in the model tree will be added as the only item\n\t * (without ancestors).\n\t *\n\t * @param {String|module:engine/model/node~Node|Array} item An item that will be added\n\t * to the current context.\n\t * @returns {module:engine/model/schema~SchemaContext} A new schema context instance with an additional item.\n\t */\n\tpush( item ) {\n\t\tconst ctx = new SchemaContext( [ item ] );\n\n\t\tctx._items = [ ...this._items, ...ctx._items ];\n\n\t\treturn ctx;\n\t}\n\n\t/**\n\t * Gets an item on the given index.\n\t *\n\t * @returns {module:engine/model/schema~SchemaContextItem}\n\t */\n\tgetItem( index ) {\n\t\treturn this._items[ index ];\n\t}\n\n\t/**\n\t * Returns the names of items.\n\t *\n\t * @returns {Iterable.}\n\t */\n\t* getNames() {\n\t\tyield* this._items.map( item => item.name );\n\t}\n\n\t/**\n\t * Checks whether the context ends with the given nodes.\n\t *\n\t *\t\tconst ctx = new SchemaContext( [ rootElement, paragraphElement, textNode ] );\n\t *\n\t *\t\tctx.endsWith( '$text' ); // -> true\n\t *\t\tctx.endsWith( 'paragraph $text' ); // -> true\n\t *\t\tctx.endsWith( '$root' ); // -> false\n\t *\t\tctx.endsWith( 'paragraph' ); // -> false\n\t *\n\t * @param {String} query\n\t * @returns {Boolean}\n\t */\n\tendsWith( query ) {\n\t\treturn Array.from( this.getNames() ).join( ' ' ).endsWith( query );\n\t}\n\n\t/**\n\t * Checks whether the context starts with the given nodes.\n\t *\n\t *\t\tconst ctx = new SchemaContext( [ rootElement, paragraphElement, textNode ] );\n\t *\n\t *\t\tctx.endsWith( '$root' ); // -> true\n\t *\t\tctx.endsWith( '$root paragraph' ); // -> true\n\t *\t\tctx.endsWith( '$text' ); // -> false\n\t *\t\tctx.endsWith( 'paragraph' ); // -> false\n\t *\n\t * @param {String} query\n\t * @returns {Boolean}\n\t */\n\tstartsWith( query ) {\n\t\treturn Array.from( this.getNames() ).join( ' ' ).startsWith( query );\n\t}\n}\n\n/**\n * The definition of a {@link module:engine/model/schema~SchemaContext schema context}.\n *\n * Contexts can be created in multiple ways:\n *\n * * By defining a **node** – in this cases this node and all its ancestors will be used.\n * * By defining a **position** in the document – in this case all its ancestors will be used.\n * * By defining an **array of nodes** – in this case this array defines the entire context.\n * * By defining a **name of node** - in this case node will be \"mocked\". It is not recommended because context\n * will be unrealistic (e.g. attributes of these nodes are not specified). However, at times this may be the only\n * way to define the context (e.g. when checking some hypothetical situation).\n * * By defining an **array of node names** (potentially, mixed with real nodes) – The same as **name of node**\n * but it is possible to create a path.\n * * By defining a {@link module:engine/model/schema~SchemaContext} instance - in this case the same instance as provided\n * will be return.\n *\n * Examples of context definitions passed to the {@link module:engine/model/schema~Schema#checkChild `Schema#checkChild()`}\n * method:\n *\n *\t\t// Assuming that we have a $root > blockQuote > paragraph structure, the following code\n *\t\t// will check node 'foo' in the following context:\n *\t\t// [ rootElement, blockQuoteElement, paragraphElement ]\n *\t\tconst contextDefinition = paragraphElement;\n * \t\tconst childToCheck = 'foo';\n *\t\tschema.checkChild( contextDefinition, childToCheck );\n *\n *\t\t// Also check in [ rootElement, blockQuoteElement, paragraphElement ].\n *\t\tschema.checkChild( model.createPositionAt( paragraphElement, 0 ), 'foo' );\n *\n *\t\t// Check in [ rootElement, paragraphElement ].\n *\t\tschema.checkChild( [ rootElement, paragraphElement ], 'foo' );\n *\n *\t\t// Check only fakeParagraphElement.\n *\t\tschema.checkChild( 'paragraph', 'foo' );\n *\n *\t\t// Check in [ fakeRootElement, fakeBarElement, paragraphElement ].\n *\t\tschema.checkChild( [ '$root', 'bar', paragraphElement ], 'foo' );\n *\n * All these `checkChild()` calls will fire {@link module:engine/model/schema~Schema#event:checkChild `Schema#checkChild`}\n * events in which `args[ 0 ]` is an instance of the context. Therefore, you can write a listener like this:\n *\n *\t\tschema.on( 'checkChild', ( evt, args ) => {\n *\t\t\tconst ctx = args[ 0 ];\n *\n *\t\t\tconsole.log( Array.from( ctx.getNames() ) );\n *\t\t} );\n *\n * Which will log the following:\n *\n *\t\t[ '$root', 'blockQuote', 'paragraph' ]\n *\t\t[ '$root', 'paragraph' ]\n *\t\t[ '$root', 'bar', 'paragraph' ]\n *\n * Note: When using the {@link module:engine/model/schema~Schema#checkAttribute `Schema#checkAttribute()`} method\n * you may want to check whether a text node may have an attribute. A {@link module:engine/model/text~Text} is a\n * correct way to define a context so you can do this:\n *\n *\t\tschema.checkAttribute( textNode, 'bold' );\n *\n * But sometimes you want to check whether a text at a given position might've had some attribute,\n * in which case you can create a context by mixing in an array of elements with a `'$text'` string:\n *\n *\t\t// Check in [ rootElement, paragraphElement, textNode ].\n *\t\tschema.checkChild( [ ...positionInParagraph.getAncestors(), '$text' ], 'bold' );\n *\n * @typedef {module:engine/model/node~Node|module:engine/model/position~Position|module:engine/model/schema~SchemaContext|\n * String|Array.} module:engine/model/schema~SchemaContextDefinition\n */\n\n/**\n * An item of the {@link module:engine/model/schema~SchemaContext schema context}.\n *\n * It contains 3 properties:\n *\n * * `name` – the name of this item,\n * * `* getAttributeKeys()` – a generator of keys of item attributes,\n * * `getAttribute( keyName )` – a method to get attribute values.\n *\n * The context item interface is a highly simplified version of {@link module:engine/model/node~Node} and its role\n * is to expose only the information which schema checks are able to provide (which is the name of the node and\n * node's attributes).\n *\n *\t\tschema.on( 'checkChild', ( evt, args ) => {\n *\t\t\tconst ctx = args[ 0 ];\n *\t\t\tconst firstItem = ctx.getItem( 0 );\n *\n *\t\t\tconsole.log( firstItem.name ); // -> '$root'\n *\t\t\tconsole.log( firstItem.getAttribute( 'foo' ) ); // -> 'bar'\n *\t\t\tconsole.log( Array.from( firstItem.getAttributeKeys() ) ); // -> [ 'foo', 'faa' ]\n *\t\t} );\n *\n * @typedef {Object} module:engine/model/schema~SchemaContextItem\n */\n\n/**\n * A structure containing additional metadata describing the attribute.\n *\n * See {@link module:engine/model/schema~Schema#setAttributeProperties `Schema#setAttributeProperties()`} for usage examples.\n *\n * @typedef {Object} module:engine/model/schema~AttributeProperties\n * @property {Boolean} [isFormatting] Indicates that the attribute should be considered as a visual formatting, like `bold`, `italic` or\n * `fontSize` rather than semantic attribute (such as `src`, `listType`, etc.). For example, it is used by the \"Remove format\" feature.\n * @property {Boolean} [copyOnEnter] Indicates that given text attribute should be copied to the next block when enter is pressed.\n */\n\nfunction compileBaseItemRule( sourceItemRules, itemName ) {\n\tconst itemRule = {\n\t\tname: itemName,\n\n\t\tallowIn: [],\n\t\tallowContentOf: [],\n\t\tallowWhere: [],\n\n\t\tallowAttributes: [],\n\t\tallowAttributesOf: [],\n\n\t\tinheritTypesFrom: []\n\t};\n\n\tcopyTypes( sourceItemRules, itemRule );\n\n\tcopyProperty( sourceItemRules, itemRule, 'allowIn' );\n\tcopyProperty( sourceItemRules, itemRule, 'allowContentOf' );\n\tcopyProperty( sourceItemRules, itemRule, 'allowWhere' );\n\n\tcopyProperty( sourceItemRules, itemRule, 'allowAttributes' );\n\tcopyProperty( sourceItemRules, itemRule, 'allowAttributesOf' );\n\n\tcopyProperty( sourceItemRules, itemRule, 'inheritTypesFrom' );\n\n\tmakeInheritAllWork( sourceItemRules, itemRule );\n\n\treturn itemRule;\n}\n\nfunction compileAllowContentOf( compiledDefinitions, itemName ) {\n\tfor ( const allowContentOfItemName of compiledDefinitions[ itemName ].allowContentOf ) {\n\t\t// The allowContentOf property may point to an unregistered element.\n\t\tif ( compiledDefinitions[ allowContentOfItemName ] ) {\n\t\t\tconst allowedChildren = getAllowedChildren( compiledDefinitions, allowContentOfItemName );\n\n\t\t\tallowedChildren.forEach( allowedItem => {\n\t\t\t\tallowedItem.allowIn.push( itemName );\n\t\t\t} );\n\t\t}\n\t}\n\n\tdelete compiledDefinitions[ itemName ].allowContentOf;\n}\n\nfunction compileAllowWhere( compiledDefinitions, itemName ) {\n\tfor ( const allowWhereItemName of compiledDefinitions[ itemName ].allowWhere ) {\n\t\tconst inheritFrom = compiledDefinitions[ allowWhereItemName ];\n\n\t\t// The allowWhere property may point to an unregistered element.\n\t\tif ( inheritFrom ) {\n\t\t\tconst allowedIn = inheritFrom.allowIn;\n\n\t\t\tcompiledDefinitions[ itemName ].allowIn.push( ...allowedIn );\n\t\t}\n\t}\n\n\tdelete compiledDefinitions[ itemName ].allowWhere;\n}\n\nfunction compileAllowAttributesOf( compiledDefinitions, itemName ) {\n\tfor ( const allowAttributeOfItem of compiledDefinitions[ itemName ].allowAttributesOf ) {\n\t\tconst inheritFrom = compiledDefinitions[ allowAttributeOfItem ];\n\n\t\tif ( inheritFrom ) {\n\t\t\tconst inheritAttributes = inheritFrom.allowAttributes;\n\n\t\t\tcompiledDefinitions[ itemName ].allowAttributes.push( ...inheritAttributes );\n\t\t}\n\t}\n\n\tdelete compiledDefinitions[ itemName ].allowAttributesOf;\n}\n\nfunction compileInheritPropertiesFrom( compiledDefinitions, itemName ) {\n\tconst item = compiledDefinitions[ itemName ];\n\n\tfor ( const inheritPropertiesOfItem of item.inheritTypesFrom ) {\n\t\tconst inheritFrom = compiledDefinitions[ inheritPropertiesOfItem ];\n\n\t\tif ( inheritFrom ) {\n\t\t\tconst typeNames = Object.keys( inheritFrom ).filter( name => name.startsWith( 'is' ) );\n\n\t\t\tfor ( const name of typeNames ) {\n\t\t\t\tif ( !( name in item ) ) {\n\t\t\t\t\titem[ name ] = inheritFrom[ name ];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tdelete item.inheritTypesFrom;\n}\n\n// Remove items which weren't registered (because it may break some checks or we'd need to complicate them).\n// Make sure allowIn doesn't contain repeated values.\nfunction cleanUpAllowIn( compiledDefinitions, itemName ) {\n\tconst itemRule = compiledDefinitions[ itemName ];\n\tconst existingItems = itemRule.allowIn.filter( itemToCheck => compiledDefinitions[ itemToCheck ] );\n\n\titemRule.allowIn = Array.from( new Set( existingItems ) );\n}\n\nfunction cleanUpAllowAttributes( compiledDefinitions, itemName ) {\n\tconst itemRule = compiledDefinitions[ itemName ];\n\n\titemRule.allowAttributes = Array.from( new Set( itemRule.allowAttributes ) );\n}\n\nfunction copyTypes( sourceItemRules, itemRule ) {\n\tfor ( const sourceItemRule of sourceItemRules ) {\n\t\tconst typeNames = Object.keys( sourceItemRule ).filter( name => name.startsWith( 'is' ) );\n\n\t\tfor ( const name of typeNames ) {\n\t\t\titemRule[ name ] = sourceItemRule[ name ];\n\t\t}\n\t}\n}\n\nfunction copyProperty( sourceItemRules, itemRule, propertyName ) {\n\tfor ( const sourceItemRule of sourceItemRules ) {\n\t\tif ( typeof sourceItemRule[ propertyName ] == 'string' ) {\n\t\t\titemRule[ propertyName ].push( sourceItemRule[ propertyName ] );\n\t\t} else if ( Array.isArray( sourceItemRule[ propertyName ] ) ) {\n\t\t\titemRule[ propertyName ].push( ...sourceItemRule[ propertyName ] );\n\t\t}\n\t}\n}\n\nfunction makeInheritAllWork( sourceItemRules, itemRule ) {\n\tfor ( const sourceItemRule of sourceItemRules ) {\n\t\tconst inheritFrom = sourceItemRule.inheritAllFrom;\n\n\t\tif ( inheritFrom ) {\n\t\t\titemRule.allowContentOf.push( inheritFrom );\n\t\t\titemRule.allowWhere.push( inheritFrom );\n\t\t\titemRule.allowAttributesOf.push( inheritFrom );\n\t\t\titemRule.inheritTypesFrom.push( inheritFrom );\n\t\t}\n\t}\n}\n\nfunction getAllowedChildren( compiledDefinitions, itemName ) {\n\tconst itemRule = compiledDefinitions[ itemName ];\n\n\treturn getValues( compiledDefinitions ).filter( def => def.allowIn.includes( itemRule.name ) );\n}\n\nfunction getValues( obj ) {\n\treturn Object.keys( obj ).map( key => obj[ key ] );\n}\n\nfunction mapContextItem( ctxItem ) {\n\tif ( typeof ctxItem == 'string' ) {\n\t\treturn {\n\t\t\tname: ctxItem,\n\n\t\t\t* getAttributeKeys() {},\n\n\t\t\tgetAttribute() {}\n\t\t};\n\t} else {\n\t\treturn {\n\t\t\t// '$text' means text nodes and text proxies.\n\t\t\tname: ctxItem.is( 'element' ) ? ctxItem.name : '$text',\n\n\t\t\t* getAttributeKeys() {\n\t\t\t\tyield* ctxItem.getAttributeKeys();\n\t\t\t},\n\n\t\t\tgetAttribute( key ) {\n\t\t\t\treturn ctxItem.getAttribute( key );\n\t\t\t}\n\t\t};\n\t}\n}\n\n// Generator function returning values from provided walkers, switching between them at each iteration. If only one walker\n// is provided it will return data only from that walker.\n//\n// @param {module:engine/module/treewalker~TreeWalker} [backward] Walker iterating in backward direction.\n// @param {module:engine/module/treewalker~TreeWalker} [forward] Walker iterating in forward direction.\n// @returns {Iterable.} Object returned at each iteration contains `value` and `walker` (informing which walker returned\n// given value) fields.\nfunction* combineWalkers( backward, forward ) {\n\tlet done = false;\n\n\twhile ( !done ) {\n\t\tdone = true;\n\n\t\tif ( backward ) {\n\t\t\tconst step = backward.next();\n\n\t\t\tif ( !step.done ) {\n\t\t\t\tdone = false;\n\t\t\t\tyield {\n\t\t\t\t\twalker: backward,\n\t\t\t\t\tvalue: step.value\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\tif ( forward ) {\n\t\t\tconst step = forward.next();\n\n\t\t\tif ( !step.done ) {\n\t\t\t\tdone = false;\n\t\t\t\tyield {\n\t\t\t\t\twalker: forward,\n\t\t\t\t\tvalue: step.value\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t}\n}\n\n// Takes an array of non-intersecting ranges. For each of them gets minimal flat ranges covering that range and returns\n// all those minimal flat ranges.\n//\n// @param {Array.} ranges Ranges to process.\n// @returns {Iterable.} Minimal flat ranges of given `ranges`.\nfunction* convertToMinimalFlatRanges( ranges ) {\n\tfor ( const range of ranges ) {\n\t\tyield* range.getMinimalFlatRanges();\n\t}\n}\n\nfunction removeDisallowedAttributeFromNode( schema, node, writer ) {\n\tfor ( const attribute of node.getAttributeKeys() ) {\n\t\tif ( !schema.checkAttribute( node, attribute ) ) {\n\t\t\twriter.removeAttribute( attribute, node );\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/range\n */\n\nimport Position from './position';\nimport TreeWalker from './treewalker';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport compareArrays from '@ckeditor/ckeditor5-utils/src/comparearrays';\n\n/**\n * Represents a range in the model tree.\n *\n * A range is defined by its {@link module:engine/model/range~Range#start} and {@link module:engine/model/range~Range#end}\n * positions.\n *\n * You can create range instances via its constructor or the `createRange*()` factory methods of\n * {@link module:engine/model/model~Model} and {@link module:engine/model/writer~Writer}.\n */\nexport default class Range {\n\t/**\n\t * Creates a range spanning from `start` position to `end` position.\n\t *\n\t * @param {module:engine/model/position~Position} start Start position.\n\t * @param {module:engine/model/position~Position} [end] End position. If not set, range will be collapsed at `start` position.\n\t */\n\tconstructor( start, end = null ) {\n\t\t/**\n\t\t * Start position.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/position~Position}\n\t\t */\n\t\tthis.start = Position._createAt( start );\n\n\t\t/**\n\t\t * End position.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/position~Position}\n\t\t */\n\t\tthis.end = end ? Position._createAt( end ) : Position._createAt( start );\n\n\t\t// If the range is collapsed, treat in a similar way as a position and set its boundaries stickiness to 'toNone'.\n\t\t// In other case, make the boundaries stick to the \"inside\" of the range.\n\t\tthis.start.stickiness = this.isCollapsed ? 'toNone' : 'toNext';\n\t\tthis.end.stickiness = this.isCollapsed ? 'toNone' : 'toPrevious';\n\t}\n\n\t/**\n\t * Iterable interface.\n\t *\n\t * Iterates over all {@link module:engine/model/item~Item items} that are in this range and returns\n\t * them together with additional information like length or {@link module:engine/model/position~Position positions},\n\t * grouped as {@link module:engine/model/treewalker~TreeWalkerValue}.\n\t * It iterates over all {@link module:engine/model/textproxy~TextProxy text contents} that are inside the range\n\t * and all the {@link module:engine/model/element~Element}s that are entered into when iterating over this range.\n\t *\n\t * This iterator uses {@link module:engine/model/treewalker~TreeWalker} with `boundaries` set to this range\n\t * and `ignoreElementEnd` option set to `true`.\n\t *\n\t * @returns {Iterable.}\n\t */\n\t* [ Symbol.iterator ]() {\n\t\tyield* new TreeWalker( { boundaries: this, ignoreElementEnd: true } );\n\t}\n\n\t/**\n\t * Returns whether the range is collapsed, that is if {@link #start} and\n\t * {@link #end} positions are equal.\n\t *\n\t * @type {Boolean}\n\t */\n\tget isCollapsed() {\n\t\treturn this.start.isEqual( this.end );\n\t}\n\n\t/**\n\t * Returns whether this range is flat, that is if {@link #start} position and\n\t * {@link #end} position are in the same {@link module:engine/model/position~Position#parent}.\n\t *\n\t * @type {Boolean}\n\t */\n\tget isFlat() {\n\t\tconst startParentPath = this.start.getParentPath();\n\t\tconst endParentPath = this.end.getParentPath();\n\n\t\treturn compareArrays( startParentPath, endParentPath ) == 'same';\n\t}\n\n\t/**\n\t * Range root element.\n\t *\n\t * @type {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment}\n\t */\n\tget root() {\n\t\treturn this.start.root;\n\t}\n\n\t/**\n\t * Checks whether this range contains given {@link module:engine/model/position~Position position}.\n\t *\n\t * @param {module:engine/model/position~Position} position Position to check.\n\t * @returns {Boolean} `true` if given {@link module:engine/model/position~Position position} is contained\n\t * in this range,`false` otherwise.\n\t */\n\tcontainsPosition( position ) {\n\t\treturn position.isAfter( this.start ) && position.isBefore( this.end );\n\t}\n\n\t/**\n\t * Checks whether this range contains given {@link ~Range range}.\n\t *\n\t * @param {module:engine/model/range~Range} otherRange Range to check.\n\t * @param {Boolean} [loose=false] Whether the check is loose or strict. If the check is strict (`false`), compared range cannot\n\t * start or end at the same position as this range boundaries. If the check is loose (`true`), compared range can start, end or\n\t * even be equal to this range. Note that collapsed ranges are always compared in strict mode.\n\t * @returns {Boolean} `true` if given {@link ~Range range} boundaries are contained by this range, `false` otherwise.\n\t */\n\tcontainsRange( otherRange, loose = false ) {\n\t\tif ( otherRange.isCollapsed ) {\n\t\t\tloose = false;\n\t\t}\n\n\t\tconst containsStart = this.containsPosition( otherRange.start ) || ( loose && this.start.isEqual( otherRange.start ) );\n\t\tconst containsEnd = this.containsPosition( otherRange.end ) || ( loose && this.end.isEqual( otherRange.end ) );\n\n\t\treturn containsStart && containsEnd;\n\t}\n\n\t/**\n\t * Checks whether given {@link module:engine/model/item~Item} is inside this range.\n\t *\n\t * @param {module:engine/model/item~Item} item Model item to check.\n\t */\n\tcontainsItem( item ) {\n\t\tconst pos = Position._createBefore( item );\n\n\t\treturn this.containsPosition( pos ) || this.start.isEqual( pos );\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\trange.is( 'range' ); // -> true\n\t *\t\trange.is( 'model:range' ); // -> true\n\t *\n\t *\t\trange.is( 'view:range' ); // -> false\n\t *\t\trange.is( 'documentSelection' ); // -> false\n\t *\n\t * {@link module:engine/model/node~Node#is Check the entire list of model 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 === 'range' || type === 'model:range';\n\t}\n\n\t/**\n\t * Two ranges are equal if their {@link #start} and {@link #end} positions are equal.\n\t *\n\t * @param {module:engine/model/range~Range} otherRange Range to compare with.\n\t * @returns {Boolean} `true` if ranges are equal, `false` otherwise.\n\t */\n\tisEqual( otherRange ) {\n\t\treturn this.start.isEqual( otherRange.start ) && this.end.isEqual( otherRange.end );\n\t}\n\n\t/**\n\t * Checks and returns whether this range intersects with given range.\n\t *\n\t * @param {module:engine/model/range~Range} otherRange Range to compare with.\n\t * @returns {Boolean} `true` if ranges intersect, `false` otherwise.\n\t */\n\tisIntersecting( otherRange ) {\n\t\treturn this.start.isBefore( otherRange.end ) && this.end.isAfter( otherRange.start );\n\t}\n\n\t/**\n\t * Computes which part(s) of this {@link ~Range range} is not a part of given {@link ~Range range}.\n\t * Returned array contains zero, one or two {@link ~Range ranges}.\n\t *\n\t * Examples:\n\t *\n\t *\t\tlet range = model.createRange(\n\t *\t\t\tmodel.createPositionFromPath( root, [ 2, 7 ] ),\n\t *\t\t\tmodel.createPositionFromPath( root, [ 4, 0, 1 ] )\n\t *\t\t);\n\t *\t\tlet otherRange = model.createRange( model.createPositionFromPath( root, [ 1 ] ), model.createPositionFromPath( root, [ 5 ] ) );\n\t *\t\tlet transformed = range.getDifference( otherRange );\n\t *\t\t// transformed array has no ranges because `otherRange` contains `range`\n\t *\n\t *\t\totherRange = model.createRange( model.createPositionFromPath( root, [ 1 ] ), model.createPositionFromPath( root, [ 3 ] ) );\n\t *\t\ttransformed = range.getDifference( otherRange );\n\t *\t\t// transformed array has one range: from [ 3 ] to [ 4, 0, 1 ]\n\t *\n\t *\t\totherRange = model.createRange( model.createPositionFromPath( root, [ 3 ] ), model.createPositionFromPath( root, [ 4 ] ) );\n\t *\t\ttransformed = range.getDifference( otherRange );\n\t *\t\t// transformed array has two ranges: from [ 2, 7 ] to [ 3 ] and from [ 4 ] to [ 4, 0, 1 ]\n\t *\n\t * @param {module:engine/model/range~Range} otherRange Range to differentiate against.\n\t * @returns {Array.} The difference between ranges.\n\t */\n\tgetDifference( otherRange ) {\n\t\tconst ranges = [];\n\n\t\tif ( this.isIntersecting( otherRange ) ) {\n\t\t\t// Ranges intersect.\n\n\t\t\tif ( this.containsPosition( otherRange.start ) ) {\n\t\t\t\t// Given range start is inside this range. This means that we have to\n\t\t\t\t// add shrunken range - from the start to the middle of this range.\n\t\t\t\tranges.push( new Range( this.start, otherRange.start ) );\n\t\t\t}\n\n\t\t\tif ( this.containsPosition( otherRange.end ) ) {\n\t\t\t\t// Given range end is inside this range. This means that we have to\n\t\t\t\t// add shrunken range - from the middle of this range to the end.\n\t\t\t\tranges.push( new Range( otherRange.end, this.end ) );\n\t\t\t}\n\t\t} else {\n\t\t\t// Ranges do not intersect, return the original range.\n\t\t\tranges.push( new Range( this.start, this.end ) );\n\t\t}\n\n\t\treturn ranges;\n\t}\n\n\t/**\n\t * Returns an intersection of this {@link ~Range range} and given {@link ~Range range}.\n\t * Intersection is a common part of both of those ranges. If ranges has no common part, returns `null`.\n\t *\n\t * Examples:\n\t *\n\t *\t\tlet range = model.createRange(\n\t *\t\t\tmodel.createPositionFromPath( root, [ 2, 7 ] ),\n\t *\t\t\tmodel.createPositionFromPath( root, [ 4, 0, 1 ] )\n\t *\t\t);\n\t *\t\tlet otherRange = model.createRange( model.createPositionFromPath( root, [ 1 ] ), model.createPositionFromPath( root, [ 2 ] ) );\n\t *\t\tlet transformed = range.getIntersection( otherRange ); // null - ranges have no common part\n\t *\n\t *\t\totherRange = model.createRange( model.createPositionFromPath( root, [ 3 ] ), model.createPositionFromPath( root, [ 5 ] ) );\n\t *\t\ttransformed = range.getIntersection( otherRange ); // range from [ 3 ] to [ 4, 0, 1 ]\n\t *\n\t * @param {module:engine/model/range~Range} otherRange Range to check for intersection.\n\t * @returns {module:engine/model/range~Range|null} A common part of given ranges or `null` if ranges have no common part.\n\t */\n\tgetIntersection( otherRange ) {\n\t\tif ( this.isIntersecting( otherRange ) ) {\n\t\t\t// Ranges intersect, so a common range will be returned.\n\t\t\t// At most, it will be same as this range.\n\t\t\tlet commonRangeStart = this.start;\n\t\t\tlet commonRangeEnd = this.end;\n\n\t\t\tif ( this.containsPosition( otherRange.start ) ) {\n\t\t\t\t// Given range start is inside this range. This means thaNt we have to\n\t\t\t\t// shrink common range to the given range start.\n\t\t\t\tcommonRangeStart = otherRange.start;\n\t\t\t}\n\n\t\t\tif ( this.containsPosition( otherRange.end ) ) {\n\t\t\t\t// Given range end is inside this range. This means that we have to\n\t\t\t\t// shrink common range to the given range end.\n\t\t\t\tcommonRangeEnd = otherRange.end;\n\t\t\t}\n\n\t\t\treturn new Range( commonRangeStart, commonRangeEnd );\n\t\t}\n\n\t\t// Ranges do not intersect, so they do not have common part.\n\t\treturn null;\n\t}\n\n\t/**\n\t * Returns a range created by joining this {@link ~Range range} with the given {@link ~Range range}.\n\t * If ranges have no common part, returns `null`.\n\t *\n\t * Examples:\n\t *\n\t *\t\tlet range = model.createRange(\n\t *\t\t\tmodel.createPositionFromPath( root, [ 2, 7 ] ),\n\t *\t\t\tmodel.createPositionFromPath( root, [ 4, 0, 1 ] )\n\t *\t\t);\n\t *\t\tlet otherRange = model.createRange(\n\t *\t\t\tmodel.createPositionFromPath( root, [ 1 ] ),\n\t *\t\t\tmodel.createPositionFromPath( root, [ 2 ] )\n \t *\t\t);\n\t *\t\tlet transformed = range.getJoined( otherRange ); // null - ranges have no common part\n\t *\n\t *\t\totherRange = model.createRange(\n\t *\t\t\tmodel.createPositionFromPath( root, [ 3 ] ),\n\t *\t\t\tmodel.createPositionFromPath( root, [ 5 ] )\n\t *\t\t);\n\t *\t\ttransformed = range.getJoined( otherRange ); // range from [ 2, 7 ] to [ 5 ]\n\t *\n\t * @param {module:engine/model/range~Range} otherRange Range to be joined.\n\t * @param {Boolean} [loose=false] Whether the intersection check is loose or strict. If the check is strict (`false`),\n\t * ranges are tested for intersection or whether start/end positions are equal. If the check is loose (`true`),\n\t * compared range is also checked if it's {@link module:engine/model/position~Position#isTouching touching} current range.\n\t * @returns {module:engine/model/range~Range|null} A sum of given ranges or `null` if ranges have no common part.\n\t */\n\tgetJoined( otherRange, loose = false ) {\n\t\tlet shouldJoin = this.isIntersecting( otherRange );\n\n\t\tif ( !shouldJoin ) {\n\t\t\tif ( this.start.isBefore( otherRange.start ) ) {\n\t\t\t\tshouldJoin = loose ? this.end.isTouching( otherRange.start ) : this.end.isEqual( otherRange.start );\n\t\t\t} else {\n\t\t\t\tshouldJoin = loose ? otherRange.end.isTouching( this.start ) : otherRange.end.isEqual( this.start );\n\t\t\t}\n\t\t}\n\n\t\tif ( !shouldJoin ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tlet startPosition = this.start;\n\t\tlet endPosition = this.end;\n\n\t\tif ( otherRange.start.isBefore( startPosition ) ) {\n\t\t\tstartPosition = otherRange.start;\n\t\t}\n\n\t\tif ( otherRange.end.isAfter( endPosition ) ) {\n\t\t\tendPosition = otherRange.end;\n\t\t}\n\n\t\treturn new Range( startPosition, endPosition );\n\t}\n\n\t/**\n\t * Computes and returns the smallest set of {@link #isFlat flat} ranges, that covers this range in whole.\n\t *\n\t * See an example of a model structure (`[` and `]` are range boundaries):\n\t *\n\t *\t\troot root\n\t *\t\t |- element DIV DIV P2 P3 DIV\n\t *\t\t | |- element H H P1 f o o b a r H P4\n\t *\t\t | | |- \"fir[st\" fir[st lorem se]cond ipsum\n\t *\t\t | |- element P1\n\t *\t\t | | |- \"lorem\" ||\n\t *\t\t |- element P2 ||\n\t *\t\t | |- \"foo\" VV\n\t *\t\t |- element P3\n\t *\t\t | |- \"bar\" root\n\t *\t\t |- element DIV DIV [P2 P3] DIV\n\t *\t\t | |- element H H [P1] f o o b a r H P4\n\t *\t\t | | |- \"se]cond\" fir[st] lorem [se]cond ipsum\n\t *\t\t | |- element P4\n\t *\t\t | | |- \"ipsum\"\n\t *\n\t * As it can be seen, letters contained in the range are: `stloremfoobarse`, spread across different parents.\n\t * We are looking for minimal set of flat ranges that contains the same nodes.\n\t *\n\t * Minimal flat ranges for above range `( [ 0, 0, 3 ], [ 3, 0, 2 ] )` will be:\n\t *\n\t *\t\t( [ 0, 0, 3 ], [ 0, 0, 5 ] ) = \"st\"\n\t *\t\t( [ 0, 1 ], [ 0, 2 ] ) = element P1 (\"lorem\")\n\t *\t\t( [ 1 ], [ 3 ] ) = element P2, element P3 (\"foobar\")\n\t *\t\t( [ 3, 0, 0 ], [ 3, 0, 2 ] ) = \"se\"\n\t *\n\t * **Note:** if an {@link module:engine/model/element~Element element} is not wholly contained in this range, it won't be returned\n\t * in any of the returned flat ranges. See in the example how `H` elements at the beginning and at the end of the range\n\t * were omitted. Only their parts that were wholly in the range were returned.\n\t *\n\t * **Note:** this method is not returning flat ranges that contain no nodes.\n\t *\n\t * @returns {Array.} Array of flat ranges covering this range.\n\t */\n\tgetMinimalFlatRanges() {\n\t\tconst ranges = [];\n\t\tconst diffAt = this.start.getCommonPath( this.end ).length;\n\n\t\tconst pos = Position._createAt( this.start );\n\t\tlet posParent = pos.parent;\n\n\t\t// Go up.\n\t\twhile ( pos.path.length > diffAt + 1 ) {\n\t\t\tconst howMany = posParent.maxOffset - pos.offset;\n\n\t\t\tif ( howMany !== 0 ) {\n\t\t\t\tranges.push( new Range( pos, pos.getShiftedBy( howMany ) ) );\n\t\t\t}\n\n\t\t\tpos.path = pos.path.slice( 0, -1 );\n\t\t\tpos.offset++;\n\t\t\tposParent = posParent.parent;\n\t\t}\n\n\t\t// Go down.\n\t\twhile ( pos.path.length <= this.end.path.length ) {\n\t\t\tconst offset = this.end.path[ pos.path.length - 1 ];\n\t\t\tconst howMany = offset - pos.offset;\n\n\t\t\tif ( howMany !== 0 ) {\n\t\t\t\tranges.push( new Range( pos, pos.getShiftedBy( howMany ) ) );\n\t\t\t}\n\n\t\t\tpos.offset = offset;\n\t\t\tpos.path.push( 0 );\n\t\t}\n\n\t\treturn ranges;\n\t}\n\n\t/**\n\t * Creates a {@link module:engine/model/treewalker~TreeWalker TreeWalker} instance with this range as a boundary.\n\t *\n\t * For example, to iterate over all items in the entire document root:\n\t *\n\t *\t\t// Create a range spanning over the entire root content:\n\t *\t\tconst range = editor.model.createRangeIn( editor.model.document.getRoot() );\n\t *\n\t *\t\t// Iterate over all items in this range:\n\t *\t\tfor ( const value of range.getWalker() ) {\n\t *\t\t\tconsole.log( value.item );\n\t *\t\t}\n\t *\n\t * @param {Object} options Object with configuration options. See {@link module:engine/model/treewalker~TreeWalker}.\n\t * @param {module:engine/model/position~Position} [options.startPosition]\n\t * @param {Boolean} [options.singleCharacters=false]\n\t * @param {Boolean} [options.shallow=false]\n\t * @param {Boolean} [options.ignoreElementEnd=false]\n\t */\n\tgetWalker( options = {} ) {\n\t\toptions.boundaries = this;\n\n\t\treturn new TreeWalker( options );\n\t}\n\n\t/**\n\t * Returns an iterator that iterates over all {@link module:engine/model/item~Item items} that are in this range and returns\n\t * them.\n\t *\n\t * This method uses {@link module:engine/model/treewalker~TreeWalker} with `boundaries` set to this range and `ignoreElementEnd` option\n\t * set to `true`. However it returns only {@link module:engine/model/item~Item model items},\n\t * not {@link module:engine/model/treewalker~TreeWalkerValue}.\n\t *\n\t * You may specify additional options for the tree walker. See {@link module:engine/model/treewalker~TreeWalker} for\n\t * a full list of available options.\n\t *\n\t * @param {Object} options Object with configuration options. See {@link module:engine/model/treewalker~TreeWalker}.\n\t * @returns {Iterable.}\n\t */\n\t* getItems( options = {} ) {\n\t\toptions.boundaries = this;\n\t\toptions.ignoreElementEnd = true;\n\n\t\tconst treeWalker = new TreeWalker( options );\n\n\t\tfor ( const value of treeWalker ) {\n\t\t\tyield value.item;\n\t\t}\n\t}\n\n\t/**\n\t * Returns an iterator that iterates over all {@link module:engine/model/position~Position positions} that are boundaries or\n\t * contained in this range.\n\t *\n\t * This method uses {@link module:engine/model/treewalker~TreeWalker} with `boundaries` set to this range. However it returns only\n\t * {@link module:engine/model/position~Position positions}, not {@link module:engine/model/treewalker~TreeWalkerValue}.\n\t *\n\t * You may specify additional options for the tree walker. See {@link module:engine/model/treewalker~TreeWalker} for\n\t * a full list of available options.\n\t *\n\t * @param {Object} options Object with configuration options. See {@link module:engine/model/treewalker~TreeWalker}.\n\t * @returns {Iterable.}\n\t */\n\t* getPositions( options = {} ) {\n\t\toptions.boundaries = this;\n\n\t\tconst treeWalker = new TreeWalker( options );\n\n\t\tyield treeWalker.position;\n\n\t\tfor ( const value of treeWalker ) {\n\t\t\tyield value.nextPosition;\n\t\t}\n\t}\n\n\t/**\n\t * Returns a range that is a result of transforming this range by given `operation`.\n\t *\n\t * **Note:** transformation may break one range into multiple ranges (for example, when a part of the range is\n\t * moved to a different part of document tree). For this reason, an array is returned by this method and it\n\t * may contain one or more `Range` instances.\n\t *\n\t * @param {module:engine/model/operation/operation~Operation} operation Operation to transform range by.\n\t * @returns {Array.} Range which is the result of transformation.\n\t */\n\tgetTransformedByOperation( operation ) {\n\t\tswitch ( operation.type ) {\n\t\t\tcase 'insert':\n\t\t\t\treturn this._getTransformedByInsertOperation( operation );\n\t\t\tcase 'move':\n\t\t\tcase 'remove':\n\t\t\tcase 'reinsert':\n\t\t\t\treturn this._getTransformedByMoveOperation( operation );\n\t\t\tcase 'split':\n\t\t\t\treturn [ this._getTransformedBySplitOperation( operation ) ];\n\t\t\tcase 'merge':\n\t\t\t\treturn [ this._getTransformedByMergeOperation( operation ) ];\n\t\t}\n\n\t\treturn [ new Range( this.start, this.end ) ];\n\t}\n\n\t/**\n\t * Returns a range that is a result of transforming this range by multiple `operations`.\n\t *\n\t * @see ~Range#getTransformedByOperation\n\t * @param {Iterable.} operations Operations to transform the range by.\n\t * @returns {Array.} Range which is the result of transformation.\n\t */\n\tgetTransformedByOperations( operations ) {\n\t\tconst ranges = [ new Range( this.start, this.end ) ];\n\n\t\tfor ( const operation of operations ) {\n\t\t\tfor ( let i = 0; i < ranges.length; i++ ) {\n\t\t\t\tconst result = ranges[ i ].getTransformedByOperation( operation );\n\n\t\t\t\tranges.splice( i, 1, ...result );\n\t\t\t\ti += result.length - 1;\n\t\t\t}\n\t\t}\n\n\t\t// It may happen that a range is split into two, and then the part of second \"piece\" is moved into first\n\t\t// \"piece\". In this case we will have incorrect third range, which should not be included in the result --\n\t\t// because it is already included in the first \"piece\". In this loop we are looking for all such ranges that\n\t\t// are inside other ranges and we simply remove them.\n\t\tfor ( let i = 0; i < ranges.length; i++ ) {\n\t\t\tconst range = ranges[ i ];\n\n\t\t\tfor ( let j = i + 1; j < ranges.length; j++ ) {\n\t\t\t\tconst next = ranges[ j ];\n\n\t\t\t\tif ( range.containsRange( next ) || next.containsRange( range ) || range.isEqual( next ) ) {\n\t\t\t\t\tranges.splice( j, 1 );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn ranges;\n\t}\n\n\t/**\n\t * Returns an {@link module:engine/model/element~Element} or {@link module:engine/model/documentfragment~DocumentFragment}\n\t * which is a common ancestor of the range's both ends (in which the entire range is contained).\n\t *\n\t * @returns {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment|null}\n\t */\n\tgetCommonAncestor() {\n\t\treturn this.start.getCommonAncestor( this.end );\n\t}\n\n\t/**\n\t * Returns an {@link module:engine/model/element~Element Element} contained by the range.\n\t * The element will be returned when it is the **only** node within the range and **fully–contained**\n\t * at the same time.\n\t *\n\t * @returns {module:engine/model/element~Element|null}\n\t */\n\tgetContainedElement() {\n\t\tif ( this.isCollapsed ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst nodeAfterStart = this.start.nodeAfter;\n\t\tconst nodeBeforeEnd = this.end.nodeBefore;\n\n\t\tif ( nodeAfterStart && nodeAfterStart.is( 'element' ) && nodeAfterStart === nodeBeforeEnd ) {\n\t\t\treturn nodeAfterStart;\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Converts `Range` to plain object and returns it.\n\t *\n\t * @returns {Object} `Node` converted to plain object.\n\t */\n\ttoJSON() {\n\t\treturn {\n\t\t\tstart: this.start.toJSON(),\n\t\t\tend: this.end.toJSON()\n\t\t};\n\t}\n\n\t/**\n\t * Returns a new range that is equal to current range.\n\t *\n\t * @returns {module:engine/model/range~Range}\n\t */\n\tclone() {\n\t\treturn new this.constructor( this.start, this.end );\n\t}\n\n\t/**\n\t * Returns a result of transforming a copy of this range by insert operation.\n\t *\n\t * One or more ranges may be returned as a result of this transformation.\n\t *\n\t * @protected\n\t * @param {module:engine/model/operation/insertoperation~InsertOperation} operation\n\t * @returns {Array.}\n\t */\n\t_getTransformedByInsertOperation( operation, spread = false ) {\n\t\treturn this._getTransformedByInsertion( operation.position, operation.howMany, spread );\n\t}\n\n\t/**\n\t * Returns a result of transforming a copy of this range by move operation.\n\t *\n\t * One or more ranges may be returned as a result of this transformation.\n\t *\n\t * @protected\n\t * @param {module:engine/model/operation/moveoperation~MoveOperation} operation\n\t * @returns {Array.}\n\t */\n\t_getTransformedByMoveOperation( operation, spread = false ) {\n\t\tconst sourcePosition = operation.sourcePosition;\n\t\tconst howMany = operation.howMany;\n\t\tconst targetPosition = operation.targetPosition;\n\n\t\treturn this._getTransformedByMove( sourcePosition, targetPosition, howMany, spread );\n\t}\n\n\t/**\n\t * Returns a result of transforming a copy of this range by split operation.\n\t *\n\t * Always one range is returned. The transformation is done in a way to not break the range.\n\t *\n\t * @protected\n\t * @param {module:engine/model/operation/splitoperation~SplitOperation} operation\n\t * @returns {module:engine/model/range~Range}\n\t */\n\t_getTransformedBySplitOperation( operation ) {\n\t\tconst start = this.start._getTransformedBySplitOperation( operation );\n\t\tlet end = this.end._getTransformedBySplitOperation( operation );\n\n\t\tif ( this.end.isEqual( operation.insertionPosition ) ) {\n\t\t\tend = this.end.getShiftedBy( 1 );\n\t\t}\n\n\t\t// Below may happen when range contains graveyard element used by split operation.\n\t\tif ( start.root != end.root ) {\n\t\t\t// End position was next to the moved graveyard element and was moved with it.\n\t\t\t// Fix it by using old `end` which has proper `root`.\n\t\t\tend = this.end.getShiftedBy( -1 );\n\t\t}\n\n\t\treturn new Range( start, end );\n\t}\n\n\t/**\n\t * Returns a result of transforming a copy of this range by merge operation.\n\t *\n\t * Always one range is returned. The transformation is done in a way to not break the range.\n\t *\n\t * @protected\n\t * @param {module:engine/model/operation/mergeoperation~MergeOperation} operation\n\t * @returns {module:engine/model/range~Range}\n\t */\n\t_getTransformedByMergeOperation( operation ) {\n\t\t// Special case when the marker is set on \"the closing tag\" of an element. Marker can be set like that during\n\t\t// transformations, especially when a content of a few block elements were removed. For example:\n\t\t//\n\t\t// {} is the transformed range, [] is the removed range.\n\t\t//

F[o{o

B}ar

Xy]z

\n\t\t//\n\t\t//

Fo{o

B}ar

z

\n\t\t//

F{

B}ar

z

\n\t\t//

F{

}

z

\n\t\t//

F{}z

\n\t\t//\n\t\tif ( this.start.isEqual( operation.targetPosition ) && this.end.isEqual( operation.deletionPosition ) ) {\n\t\t\treturn new Range( this.start );\n\t\t}\n\n\t\tlet start = this.start._getTransformedByMergeOperation( operation );\n\t\tlet end = this.end._getTransformedByMergeOperation( operation );\n\n\t\tif ( start.root != end.root ) {\n\t\t\t// This happens when the end position was next to the merged (deleted) element.\n\t\t\t// Then, the end position was moved to the graveyard root. In this case we need to fix\n\t\t\t// the range cause its boundaries would be in different roots.\n\t\t\tend = this.end.getShiftedBy( -1 );\n\t\t}\n\n\t\tif ( start.isAfter( end ) ) {\n\t\t\t// This happens in three following cases:\n\t\t\t//\n\t\t\t// Case 1: Merge operation source position is before the target position (due to some transformations, OT, etc.)\n\t\t\t// This means that start can be moved before the end of the range.\n\t\t\t//\n\t\t\t// Before:

a{a

b}b

cc

\n\t\t\t// Merge:

b}b

cca{a

\n\t\t\t// Fix:

{b}b

ccaa

\n\t\t\t//\n\t\t\t// Case 2: Range start is before merged node but not directly.\n\t\t\t// Result should include all nodes that were in the original range.\n\t\t\t//\n\t\t\t// Before:

aa

{

cc

b}b

\n\t\t\t// Merge:

aab}b

{

cc

\n\t\t\t// Fix:

aa{bb

cc

}\n\t\t\t//\n\t\t\t// The range is expanded by an additional `b` letter but it is better than dropping the whole `cc` paragraph.\n\t\t\t//\n\t\t\t// Case 3: Range start is directly before merged node.\n\t\t\t// Resulting range should include only nodes from the merged element:\n\t\t\t//\n\t\t\t// Before:

aa

{

b}b

cc

\n\t\t\t// Merge:

aab}b

{

cc

\n\t\t\t// Fix:

aa{b}b

cc

\n\t\t\t//\n\n\t\t\tif ( operation.sourcePosition.isBefore( operation.targetPosition ) ) {\n\t\t\t\t// Case 1.\n\t\t\t\tstart = Position._createAt( end );\n\t\t\t\tstart.offset = 0;\n\t\t\t} else {\n\t\t\t\tif ( !operation.deletionPosition.isEqual( start ) ) {\n\t\t\t\t\t// Case 2.\n\t\t\t\t\tend = operation.deletionPosition;\n\t\t\t\t}\n\n\t\t\t\t// In both case 2 and 3 start is at the end of the merge-to element.\n\t\t\t\tstart = operation.targetPosition;\n\t\t\t}\n\n\t\t\treturn new Range( start, end );\n\t\t}\n\n\t\treturn new Range( start, end );\n\t}\n\n\t/**\n\t * Returns an array containing one or two {@link ~Range ranges} that are a result of transforming this\n\t * {@link ~Range range} by inserting `howMany` nodes at `insertPosition`. Two {@link ~Range ranges} are\n\t * returned if the insertion was inside this {@link ~Range range} and `spread` is set to `true`.\n\t *\n\t * Examples:\n\t *\n\t *\t\tlet range = model.createRange(\n\t *\t\t\tmodel.createPositionFromPath( root, [ 2, 7 ] ),\n\t *\t\t\tmodel.createPositionFromPath( root, [ 4, 0, 1 ] )\n\t *\t\t);\n\t *\t\tlet transformed = range._getTransformedByInsertion( model.createPositionFromPath( root, [ 1 ] ), 2 );\n\t *\t\t// transformed array has one range from [ 4, 7 ] to [ 6, 0, 1 ]\n\t *\n\t *\t\ttransformed = range._getTransformedByInsertion( model.createPositionFromPath( root, [ 4, 0, 0 ] ), 4 );\n\t *\t\t// transformed array has one range from [ 2, 7 ] to [ 4, 0, 5 ]\n\t *\n\t *\t\ttransformed = range._getTransformedByInsertion( model.createPositionFromPath( root, [ 3, 2 ] ), 4 );\n\t *\t\t// transformed array has one range, which is equal to original range\n\t *\n\t *\t\ttransformed = range._getTransformedByInsertion( model.createPositionFromPath( root, [ 3, 2 ] ), 4, true );\n\t *\t\t// transformed array has two ranges: from [ 2, 7 ] to [ 3, 2 ] and from [ 3, 6 ] to [ 4, 0, 1 ]\n\t *\n\t * @protected\n\t * @param {module:engine/model/position~Position} insertPosition Position where nodes are inserted.\n\t * @param {Number} howMany How many nodes are inserted.\n\t * @param {Boolean} [spread] Flag indicating whether this {~Range range} should be spread if insertion\n\t * was inside the range. Defaults to `false`.\n\t * @returns {Array.} Result of the transformation.\n\t */\n\t_getTransformedByInsertion( insertPosition, howMany, spread = false ) {\n\t\tif ( spread && this.containsPosition( insertPosition ) ) {\n\t\t\t// Range has to be spread. The first part is from original start to the spread point.\n\t\t\t// The other part is from spread point to the original end, but transformed by\n\t\t\t// insertion to reflect insertion changes.\n\n\t\t\treturn [\n\t\t\t\tnew Range( this.start, insertPosition ),\n\t\t\t\tnew Range(\n\t\t\t\t\tinsertPosition.getShiftedBy( howMany ),\n\t\t\t\t\tthis.end._getTransformedByInsertion( insertPosition, howMany )\n\t\t\t\t)\n\t\t\t];\n\t\t} else {\n\t\t\tconst range = new Range( this.start, this.end );\n\n\t\t\trange.start = range.start._getTransformedByInsertion( insertPosition, howMany );\n\t\t\trange.end = range.end._getTransformedByInsertion( insertPosition, howMany );\n\n\t\t\treturn [ range ];\n\t\t}\n\t}\n\n\t/**\n\t * Returns an array containing {@link ~Range ranges} that are a result of transforming this\n\t * {@link ~Range range} by moving `howMany` nodes from `sourcePosition` to `targetPosition`.\n\t *\n\t * @protected\n\t * @param {module:engine/model/position~Position} sourcePosition Position from which nodes are moved.\n\t * @param {module:engine/model/position~Position} targetPosition Position to where nodes are moved.\n\t * @param {Number} howMany How many nodes are moved.\n\t * @param {Boolean} [spread=false] Whether the range should be spread if the move points inside the range.\n\t * @returns {Array.} Result of the transformation.\n\t */\n\t_getTransformedByMove( sourcePosition, targetPosition, howMany, spread = false ) {\n\t\t// Special case for transforming a collapsed range. Just transform it like a position.\n\t\tif ( this.isCollapsed ) {\n\t\t\tconst newPos = this.start._getTransformedByMove( sourcePosition, targetPosition, howMany );\n\n\t\t\treturn [ new Range( newPos ) ];\n\t\t}\n\n\t\t// Special case for transformation when a part of the range is moved towards the range.\n\t\t//\n\t\t// Examples:\n\t\t//\n\t\t//

ab

c[d

e]f

-->

ab

c[d

e]f

\n\t\t//

e[f

a]b

cd

-->

e[f

a]b

cd

\n\t\t//\n\t\t// Without this special condition, the default algorithm leaves an \"artifact\" range from one of `differenceSet` parts:\n\t\t//\n\t\t//

ab

c[d

e]f

-->

ab

{
}

c[d

e]f

\n\t\t//\n\t\t// This special case is applied only if the range is to be kept together (not spread).\n\t\tconst moveRange = Range._createFromPositionAndShift( sourcePosition, howMany );\n\t\tconst insertPosition = targetPosition._getTransformedByDeletion( sourcePosition, howMany );\n\n\t\tif ( this.containsPosition( targetPosition ) && !spread ) {\n\t\t\tif ( moveRange.containsPosition( this.start ) || moveRange.containsPosition( this.end ) ) {\n\t\t\t\tconst start = this.start._getTransformedByMove( sourcePosition, targetPosition, howMany );\n\t\t\t\tconst end = this.end._getTransformedByMove( sourcePosition, targetPosition, howMany );\n\n\t\t\t\treturn [ new Range( start, end ) ];\n\t\t\t}\n\t\t}\n\n\t\t// Default algorithm.\n\t\tlet result;\n\n\t\tconst differenceSet = this.getDifference( moveRange );\n\t\tlet difference = null;\n\n\t\tconst common = this.getIntersection( moveRange );\n\n\t\tif ( differenceSet.length == 1 ) {\n\t\t\t// `moveRange` and this range may intersect but may be separate.\n\t\t\tdifference = new Range(\n\t\t\t\tdifferenceSet[ 0 ].start._getTransformedByDeletion( sourcePosition, howMany ),\n\t\t\t\tdifferenceSet[ 0 ].end._getTransformedByDeletion( sourcePosition, howMany )\n\t\t\t);\n\t\t} else if ( differenceSet.length == 2 ) {\n\t\t\t// `moveRange` is inside this range.\n\t\t\tdifference = new Range(\n\t\t\t\tthis.start,\n\t\t\t\tthis.end._getTransformedByDeletion( sourcePosition, howMany )\n\t\t\t);\n\t\t} // else, `moveRange` contains this range.\n\n\t\tif ( difference ) {\n\t\t\tresult = difference._getTransformedByInsertion( insertPosition, howMany, common !== null || spread );\n\t\t} else {\n\t\t\tresult = [];\n\t\t}\n\n\t\tif ( common ) {\n\t\t\tconst transformedCommon = new Range(\n\t\t\t\tcommon.start._getCombined( moveRange.start, insertPosition ),\n\t\t\t\tcommon.end._getCombined( moveRange.start, insertPosition )\n\t\t\t);\n\n\t\t\tif ( result.length == 2 ) {\n\t\t\t\tresult.splice( 1, 0, transformedCommon );\n\t\t\t} else {\n\t\t\t\tresult.push( transformedCommon );\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns a copy of this range that is transformed by deletion of `howMany` nodes from `deletePosition`.\n\t *\n\t * If the deleted range is intersecting with the transformed range, the transformed range will be shrank.\n\t *\n\t * If the deleted range contains transformed range, `null` will be returned.\n\t *\n\t * @protected\n\t * @param {module:engine/model/position~Position} deletionPosition Position from which nodes are removed.\n\t * @param {Number} howMany How many nodes are removed.\n\t * @returns {module:engine/model/range~Range|null} Result of the transformation.\n\t */\n\t_getTransformedByDeletion( deletePosition, howMany ) {\n\t\tlet newStart = this.start._getTransformedByDeletion( deletePosition, howMany );\n\t\tlet newEnd = this.end._getTransformedByDeletion( deletePosition, howMany );\n\n\t\tif ( newStart == null && newEnd == null ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif ( newStart == null ) {\n\t\t\tnewStart = deletePosition;\n\t\t}\n\n\t\tif ( newEnd == null ) {\n\t\t\tnewEnd = deletePosition;\n\t\t}\n\n\t\treturn new Range( newStart, newEnd );\n\t}\n\n\t/**\n\t * Creates a new range, spreading from specified {@link module:engine/model/position~Position position} to a position moved by\n\t * given `shift`. If `shift` is a negative value, shifted position is treated as the beginning of the range.\n\t *\n\t * @protected\n\t * @param {module:engine/model/position~Position} position Beginning of the range.\n\t * @param {Number} shift How long the range should be.\n\t * @returns {module:engine/model/range~Range}\n\t */\n\tstatic _createFromPositionAndShift( position, shift ) {\n\t\tconst start = position;\n\t\tconst end = position.getShiftedBy( shift );\n\n\t\treturn shift > 0 ? new this( start, end ) : new this( end, start );\n\t}\n\n\t/**\n\t * Creates a range inside an {@link module:engine/model/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 * @protected\n\t * @param {module:engine/model/element~Element} element Element which is a parent for the range.\n\t * @returns {module:engine/model/range~Range}\n\t */\n\tstatic _createIn( element ) {\n\t\treturn new this( Position._createAt( element, 0 ), Position._createAt( element, element.maxOffset ) );\n\t}\n\n\t/**\n\t * Creates a range that starts before given {@link module:engine/model/item~Item model item} and ends after it.\n\t *\n\t * @protected\n\t * @param {module:engine/model/item~Item} item\n\t * @returns {module:engine/model/range~Range}\n\t */\n\tstatic _createOn( item ) {\n\t\treturn this._createFromPositionAndShift( Position._createBefore( item ), item.offsetSize );\n\t}\n\n\t/**\n\t * Combines all ranges from the passed array into a one range. At least one range has to be passed.\n\t * Passed ranges must not have common parts.\n\t *\n\t * The first range from the array is a reference range. If other ranges start or end on the exactly same position where\n\t * the reference range, they get combined into one range.\n\t *\n\t *\t\t[ ][] [ ][ ][ ][ ][] [ ] // Passed ranges, shown sorted\n\t *\t\t[ ] // The result of the function if the first range was a reference range.\n\t *\t [ ] // The result of the function if the third-to-seventh range was a reference range.\n\t *\t [ ] // The result of the function if the last range was a reference range.\n\t *\n\t * @param {Array.} ranges Ranges to combine.\n\t * @returns {module:engine/model/range~Range} Combined range.\n\t */\n\tstatic _createFromRanges( ranges ) {\n\t\tif ( ranges.length === 0 ) {\n\t\t\t/**\n\t\t\t * At least one range has to be passed to\n\t\t\t * {@link module:engine/model/range~Range._createFromRanges `Range._createFromRanges()`}.\n\t\t\t *\n\t\t\t * @error range-create-from-ranges-empty-array\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'range-create-from-ranges-empty-array',\n\t\t\t\tnull\n\t\t\t);\n\t\t} else if ( ranges.length == 1 ) {\n\t\t\treturn ranges[ 0 ].clone();\n\t\t}\n\n\t\t// 1. Set the first range in `ranges` array as a reference range.\n\t\t// If we are going to return just a one range, one of the ranges need to be the reference one.\n\t\t// Other ranges will be stuck to that range, if possible.\n\t\tconst ref = ranges[ 0 ];\n\n\t\t// 2. Sort all the ranges so it's easier to process them.\n\t\tranges.sort( ( a, b ) => {\n\t\t\treturn a.start.isAfter( b.start ) ? 1 : -1;\n\t\t} );\n\n\t\t// 3. Check at which index the reference range is now.\n\t\tconst refIndex = ranges.indexOf( ref );\n\n\t\t// 4. At this moment we don't need the original range.\n\t\t// We are going to modify the result and we need to return a new instance of Range.\n\t\t// We have to create a copy of the reference range.\n\t\tconst result = new this( ref.start, ref.end );\n\n\t\t// 5. Ranges should be checked and glued starting from the range that is closest to the reference range.\n\t\t// Since ranges are sorted, start with the range with index that is closest to reference range index.\n\t\tif ( refIndex > 0 ) {\n\t\t\tfor ( let i = refIndex - 1; true; i++ ) {\n\t\t\t\tif ( ranges[ i ].end.isEqual( result.start ) ) {\n\t\t\t\t\tresult.start = Position._createAt( ranges[ i ].start );\n\t\t\t\t} else {\n\t\t\t\t\t// If ranges are not starting/ending at the same position there is no point in looking further.\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// 6. Ranges should be checked and glued starting from the range that is closest to the reference range.\n\t\t// Since ranges are sorted, start with the range with index that is closest to reference range index.\n\t\tfor ( let i = refIndex + 1; i < ranges.length; i++ ) {\n\t\t\tif ( ranges[ i ].start.isEqual( result.end ) ) {\n\t\t\t\tresult.end = Position._createAt( ranges[ i ].end );\n\t\t\t} else {\n\t\t\t\t// If ranges are not starting/ending at the same position there is no point in looking further.\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Creates a `Range` instance from given plain object (i.e. parsed JSON string).\n\t *\n\t * @param {Object} json Plain object to be converted to `Range`.\n\t * @param {module:engine/model/document~Document} doc Document object that will be range owner.\n\t * @returns {module:engine/model/element~Element} `Range` instance created using given plain object.\n\t */\n\tstatic fromJSON( json, doc ) {\n\t\treturn new this( Position.fromJSON( json.start, doc ), Position.fromJSON( json.end, doc ) );\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn `${ this.root } [ ${ this.start.path.join( ', ' ) } ] - [ ${ this.end.path.join( ', ' ) } ]`;\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // log() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( 'ModelPosition: ' + this );\n\t// @if CK_DEBUG_ENGINE // }\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/model/selection\n */\n\nimport Position from './position';\nimport Node from './node';\nimport Range from './range';\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport isIterable from '@ckeditor/ckeditor5-utils/src/isiterable';\n\n/**\n * Selection is a set of {@link module:engine/model/range~Range ranges}. It has a direction specified by its\n * {@link module:engine/model/selection~Selection#anchor anchor} and {@link module:engine/model/selection~Selection#focus focus}\n * (it can be {@link module:engine/model/selection~Selection#isBackward forward or backward}).\n * Additionally, selection may have its own attributes (think – whether text typed in in this selection\n * should have those attributes – e.g. whether you type a bolded text).\n *\n * @mixes module:utils/emittermixin~EmitterMixin\n */\nexport default class Selection {\n\t/**\n\t * Creates a new selection instance based on the given {@link module:engine/model/selection~Selectable selectable}\n\t * or creates an empty selection if no arguments were passed.\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\t// Note: It doesn't copies selection attributes.\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 given document selection.\n\t *\t\t// Note: It doesn't copies selection attributes.\n\t *\t\tconst documentSelection = model.document.selection;\n\t *\t\tconst selection = writer.createSelection( documentSelection );\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 selection at the given offset in the given element.\n\t *\t\tconst paragraph = writer.createElement( 'paragraph' );\n\t *\t\tconst selection = writer.createSelection( paragraph, offset );\n\t *\n\t *\t\t// Creates a range inside an {@link module:engine/model/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/model/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'`) 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 * @param {module:engine/model/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 */\n\tconstructor( selectable, placeOrOffset, options ) {\n\t\t/**\n\t\t * Specifies whether the last added range was added as a backward or forward range.\n\t\t *\n\t\t * @private\n\t\t * @type {Boolean}\n\t\t */\n\t\tthis._lastRangeBackward = false;\n\n\t\t/**\n\t\t * Stores selection ranges.\n\t\t *\n\t\t * @protected\n\t\t * @type {Array.}\n\t\t */\n\t\tthis._ranges = [];\n\n\t\t/**\n\t\t * List of attributes set on current selection.\n\t\t *\n\t\t * @protected\n\t\t * @type {Map.}\n\t\t */\n\t\tthis._attrs = new Map();\n\n\t\tif ( selectable ) {\n\t\t\tthis.setTo( selectable, placeOrOffset, options );\n\t\t}\n\t}\n\n\t/**\n\t * Selection anchor. Anchor is the position from which the selection was started. If a user is making a selection\n\t * by dragging the mouse, the anchor is where the user pressed the mouse button (the beginning of the selection).\n\t *\n\t * Anchor and {@link #focus} define the direction of the selection, which is important\n\t * when expanding/shrinking selection. The focus moves, while the anchor should remain in the same place.\n\t *\n\t * Anchor is always set to the {@link module:engine/model/range~Range#start start} or\n\t * {@link module:engine/model/range~Range#end end} position of the last of selection's ranges. Whether it is\n\t * the `start` or `end` depends on the specified `options.backward`. See the {@link #setTo `setTo()`} method.\n\t *\n\t * May be set to `null` if there are no ranges in the selection.\n\t *\n\t * @see #focus\n\t * @readonly\n\t * @type {module:engine/model/position~Position|null}\n\t */\n\tget anchor() {\n\t\tif ( this._ranges.length > 0 ) {\n\t\t\tconst range = this._ranges[ this._ranges.length - 1 ];\n\n\t\t\treturn this._lastRangeBackward ? range.end : range.start;\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Selection focus. Focus is the position where the selection ends. If a user is making a selection\n\t * by dragging the mouse, the focus is where the mouse cursor is.\n\t *\n\t * May be set to `null` if there are no ranges in the selection.\n\t *\n\t * @see #anchor\n\t * @readonly\n\t * @type {module:engine/model/position~Position|null}\n\t */\n\tget focus() {\n\t\tif ( this._ranges.length > 0 ) {\n\t\t\tconst range = this._ranges[ this._ranges.length - 1 ];\n\n\t\t\treturn this._lastRangeBackward ? range.start : range.end;\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Whether the selection is collapsed. Selection is collapsed when there is exactly one range in it\n\t * and it is collapsed.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget isCollapsed() {\n\t\tconst length = this._ranges.length;\n\n\t\tif ( length === 1 ) {\n\t\t\treturn this._ranges[ 0 ].isCollapsed;\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Returns the number of ranges in the selection.\n\t *\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget rangeCount() {\n\t\treturn this._ranges.length;\n\t}\n\n\t/**\n\t * Specifies whether the selection's {@link #focus} precedes the selection's {@link #anchor}.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget isBackward() {\n\t\treturn !this.isCollapsed && this._lastRangeBackward;\n\t}\n\n\t/**\n\t * Checks whether this selection is equal to the given selection. Selections are equal if they have the same directions,\n\t * the same number of ranges and all ranges from one selection equal to ranges from the another selection.\n\t *\n\t * @param {module:engine/model/selection~Selection|module:engine/model/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\tif ( this.rangeCount != otherSelection.rangeCount ) {\n\t\t\treturn false;\n\t\t} else if ( this.rangeCount === 0 ) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif ( !this.anchor.isEqual( otherSelection.anchor ) || !this.focus.isEqual( otherSelection.focus ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tfor ( const thisRange of this._ranges ) {\n\t\t\tlet found = false;\n\n\t\t\tfor ( const otherRange of otherSelection._ranges ) {\n\t\t\t\tif ( thisRange.isEqual( otherRange ) ) {\n\t\t\t\t\tfound = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( !found ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Returns an iterable object that iterates over copies of selection ranges.\n\t *\n\t * @returns {Iterable.}\n\t */\n\t* getRanges() {\n\t\tfor ( const range of this._ranges ) {\n\t\t\tyield new Range( range.start, range.end );\n\t\t}\n\t}\n\n\t/**\n\t * Returns a copy of the first range in the selection.\n\t * First range is the one which {@link module:engine/model/range~Range#start start} position\n\t * {@link module:engine/model/position~Position#isBefore is before} start position of all other ranges\n\t * (not to confuse with the first range added to the selection).\n\t *\n\t * Returns `null` if there are no ranges in selection.\n\t *\n\t * @returns {module:engine/model/range~Range|null}\n\t */\n\tgetFirstRange() {\n\t\tlet first = null;\n\n\t\tfor ( const range of this._ranges ) {\n\t\t\tif ( !first || range.start.isBefore( first.start ) ) {\n\t\t\t\tfirst = range;\n\t\t\t}\n\t\t}\n\n\t\treturn first ? new Range( first.start, first.end ) : null;\n\t}\n\n\t/**\n\t * Returns a copy of the last range in the selection.\n\t * Last range is the one which {@link module:engine/model/range~Range#end end} position\n\t * {@link module:engine/model/position~Position#isAfter is after} end position of all other ranges (not to confuse with the range most\n\t * recently added to the selection).\n\t *\n\t * Returns `null` if there are no ranges in selection.\n\t *\n\t * @returns {module:engine/model/range~Range|null}\n\t */\n\tgetLastRange() {\n\t\tlet last = null;\n\n\t\tfor ( const range of this._ranges ) {\n\t\t\tif ( !last || range.end.isAfter( last.end ) ) {\n\t\t\t\tlast = range;\n\t\t\t}\n\t\t}\n\n\t\treturn last ? new Range( last.start, last.end ) : null;\n\t}\n\n\t/**\n\t * Returns the first position in the selection.\n\t * First position is the position that {@link module:engine/model/position~Position#isBefore is before}\n\t * any other position in the selection.\n\t *\n\t * Returns `null` if there are no ranges in selection.\n\t *\n\t * @returns {module:engine/model/position~Position|null}\n\t */\n\tgetFirstPosition() {\n\t\tconst first = this.getFirstRange();\n\n\t\treturn first ? first.start.clone() : null;\n\t}\n\n\t/**\n\t * Returns the last position in the selection.\n\t * Last position is the position that {@link module:engine/model/position~Position#isAfter is after}\n\t * any other position in the selection.\n\t *\n\t * Returns `null` if there are no ranges in selection.\n\t *\n\t * @returns {module:engine/model/position~Position|null}\n\t */\n\tgetLastPosition() {\n\t\tconst lastRange = this.getLastRange();\n\n\t\treturn lastRange ? lastRange.end.clone() : null;\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/model/selection~Selectable selectable}.\n\t *\n\t *\t\t// Removes all selection's ranges.\n\t *\t\tselection.setTo( null );\n\t *\n\t *\t\t// Sets selection to the given range.\n\t *\t\tconst range = writer.createRange( start, end );\n\t *\t\tselection.setTo( range );\n\t *\n\t *\t\t// Sets selection to given ranges.\n\t *\t\tconst ranges = [ writer.createRange( start1, end2 ), writer.createRange( star2, end2 ) ];\n\t *\t\tselection.setTo( ranges );\n\t *\n\t *\t\t// Sets selection to other selection.\n\t *\t\t// Note: It doesn't copies selection attributes.\n\t *\t\tconst otherSelection = writer.createSelection();\n\t *\t\tselection.setTo( otherSelection );\n\t *\n\t *\t\t// Sets selection to the given document selection.\n\t *\t\t// Note: It doesn't copies selection attributes.\n\t *\t\tconst documentSelection = new DocumentSelection( doc );\n\t *\t\tselection.setTo( documentSelection );\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\tselection.setTo( position );\n\t *\n\t *\t\t// Sets collapsed selection at the position of the given node and an offset.\n\t *\t\tselection.setTo( paragraph, offset );\n\t *\n\t * Creates a range inside an {@link module:engine/model/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\tselection.setTo( paragraph, 'in' );\n\t *\n\t * Creates a range on an {@link module:engine/model/item~Item item} which starts before the item and ends just after the item.\n\t *\n\t *\t\tselection.setTo( paragraph, 'on' );\n\t *\n\t * `Selection#setTo()`' method allow passing additional options (`backward`) as the last argument.\n\t *\n\t *\t\t// Sets backward selection.\n\t *\t\tconst selection = writer.createSelection( range, { backward: true } );\n\t *\n\t * @param {module:engine/model/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 */\n\tsetTo( selectable, placeOrOffset, options ) {\n\t\tif ( selectable === null ) {\n\t\t\tthis._setRanges( [] );\n\t\t} else if ( selectable instanceof Selection ) {\n\t\t\tthis._setRanges( selectable.getRanges(), selectable.isBackward );\n\t\t} else if ( selectable && typeof selectable.getRanges == 'function' ) {\n\t\t\t// We assume that the selectable is a DocumentSelection.\n\t\t\t// It can't be imported here, because it would lead to circular imports.\n\t\t\tthis._setRanges( selectable.getRanges(), selectable.isBackward );\n\t\t} else if ( selectable instanceof Range ) {\n\t\t\tthis._setRanges( [ selectable ], !!placeOrOffset && !!placeOrOffset.backward );\n\t\t} else if ( selectable instanceof Position ) {\n\t\t\tthis._setRanges( [ new Range( selectable ) ] );\n\t\t} else if ( selectable instanceof Node ) {\n\t\t\tconst backward = !!options && !!options.backward;\n\t\t\tlet range;\n\n\t\t\tif ( placeOrOffset == 'in' ) {\n\t\t\t\trange = Range._createIn( selectable );\n\t\t\t} else if ( placeOrOffset == 'on' ) {\n\t\t\t\trange = Range._createOn( selectable );\n\t\t\t} else if ( placeOrOffset !== undefined ) {\n\t\t\t\trange = new Range( Position._createAt( selectable, placeOrOffset ) );\n\t\t\t} else {\n\t\t\t\t/**\n\t\t\t\t * selection.setTo requires the second parameter when the first parameter is a node.\n\t\t\t\t *\n\t\t\t\t * @error model-selection-setto-required-second-parameter\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError( 'model-selection-setto-required-second-parameter', [ this, selectable ] );\n\t\t\t}\n\n\t\t\tthis._setRanges( [ range ], backward );\n\t\t} else if ( isIterable( selectable ) ) {\n\t\t\t// We assume that the selectable is an iterable of ranges.\n\t\t\tthis._setRanges( selectable, placeOrOffset && !!placeOrOffset.backward );\n\t\t} else {\n\t\t\t/**\n\t\t\t * Cannot set the selection to the given place.\n\t\t\t *\n\t\t\t * Invalid parameters were specified when setting the selection. Common issues:\n\t\t\t *\n\t\t\t * * A {@link module:engine/model/textproxy~TextProxy} instance was passed instead of\n\t\t\t * a real {@link module:engine/model/text~Text}.\n\t\t\t * * View nodes were passed instead of model nodes.\n\t\t\t * * `null`/`undefined` was passed.\n\t\t\t *\n\t\t\t * @error model-selection-setto-not-selectable\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'model-selection-setto-not-selectable', [ this, selectable ] );\n\t\t}\n\t}\n\n\t/**\n\t * Replaces all ranges that were added to the selection with given array of ranges. Last range of the array\n\t * is treated like the last added range and is used to set {@link module:engine/model/selection~Selection#anchor} and\n\t * {@link module:engine/model/selection~Selection#focus}. Accepts a flag describing in which direction the selection is made.\n\t *\n\t * @protected\n\t * @fires change:range\n\t * @param {Iterable.} newRanges Ranges to set.\n\t * @param {Boolean} [isLastBackward=false] Flag describing if last added range was selected forward - from start to end (`false`)\n\t * or backward - from end to start (`true`).\n\t */\n\t_setRanges( newRanges, isLastBackward = false ) {\n\t\tnewRanges = Array.from( newRanges );\n\n\t\t// Check whether there is any range in new ranges set that is different than all already added ranges.\n\t\tconst anyNewRange = newRanges.some( newRange => {\n\t\t\tif ( !( newRange instanceof Range ) ) {\n\t\t\t\t/**\n\t\t\t\t * Selection range set to an object that is not an instance of {@link module:engine/model/range~Range}.\n\t\t\t\t *\n\t\t\t\t * Only {@link module:engine/model/range~Range} instances can be used to set a selection.\n\t\t\t\t * Common mistakes leading to this error are:\n\t\t\t\t *\n\t\t\t\t * * using DOM `Range` object,\n\t\t\t\t * * incorrect CKEditor 5 installation with multiple `ckeditor5-engine` packages having different versions.\n\t\t\t\t *\n\t\t\t\t * @error model-selection-set-ranges-not-range\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t'model-selection-set-ranges-not-range',\n\t\t\t\t\t[ this, newRanges ]\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn this._ranges.every( oldRange => {\n\t\t\t\treturn !oldRange.isEqual( newRange );\n\t\t\t} );\n\t\t} );\n\n\t\t// Don't do anything if nothing changed.\n\t\tif ( newRanges.length === this._ranges.length && !anyNewRange ) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._removeAllRanges();\n\n\t\tfor ( const range of newRanges ) {\n\t\t\tthis._pushRange( range );\n\t\t}\n\n\t\tthis._lastRangeBackward = !!isLastBackward;\n\n\t\tthis.fire( 'change:range', { directChange: true } );\n\t}\n\n\t/**\n\t * Moves {@link module:engine/model/selection~Selection#focus} to the specified location.\n\t *\n\t * The location can be specified in the same form as\n\t * {@link module:engine/model/writer~Writer#createPositionAt writer.createPositionAt()} parameters.\n\t *\n\t * @fires change:range\n\t * @param {module:engine/model/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/model/item~Item model item}.\n\t */\n\tsetFocus( itemOrPosition, offset ) {\n\t\tif ( this.anchor === null ) {\n\t\t\t/**\n\t\t\t * Cannot set selection focus if there are no ranges in selection.\n\t\t\t *\n\t\t\t * @error model-selection-setfocus-no-ranges\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'model-selection-setfocus-no-ranges', [ this, itemOrPosition ] );\n\t\t}\n\n\t\tconst newFocus = Position._createAt( itemOrPosition, offset );\n\n\t\tif ( newFocus.compareWith( this.focus ) == 'same' ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst anchor = this.anchor;\n\n\t\tif ( this._ranges.length ) {\n\t\t\tthis._popRange();\n\t\t}\n\n\t\tif ( newFocus.compareWith( anchor ) == 'before' ) {\n\t\t\tthis._pushRange( new Range( newFocus, anchor ) );\n\t\t\tthis._lastRangeBackward = true;\n\t\t} else {\n\t\t\tthis._pushRange( new Range( anchor, newFocus ) );\n\t\t\tthis._lastRangeBackward = false;\n\t\t}\n\n\t\tthis.fire( 'change:range', { directChange: true } );\n\t}\n\n\t/**\n\t * Gets an attribute value for given key or `undefined` if that attribute is not set on the selection.\n\t *\n\t * @param {String} key Key of attribute to look for.\n\t * @returns {*} Attribute value or `undefined`.\n\t */\n\tgetAttribute( key ) {\n\t\treturn this._attrs.get( key );\n\t}\n\n\t/**\n\t * Returns iterable that iterates over this selection's attributes.\n\t *\n\t * Attributes are returned as arrays containing two items. First one is attribute key and second is attribute value.\n\t * This format is accepted by native `Map` object and also can be passed in `Node` constructor.\n\t *\n\t * @returns {Iterable.<*>}\n\t */\n\tgetAttributes() {\n\t\treturn this._attrs.entries();\n\t}\n\n\t/**\n\t * Returns iterable that iterates over this selection's attribute keys.\n\t *\n\t * @returns {Iterable.}\n\t */\n\tgetAttributeKeys() {\n\t\treturn this._attrs.keys();\n\t}\n\n\t/**\n\t * Checks if the selection has an attribute for given key.\n\t *\n\t * @param {String} key Key of attribute to check.\n\t * @returns {Boolean} `true` if attribute with given key is set on selection, `false` otherwise.\n\t */\n\thasAttribute( key ) {\n\t\treturn this._attrs.has( key );\n\t}\n\n\t/**\n\t * Removes an attribute with given key from the selection.\n\t *\n\t * If given attribute was set on the selection, fires the {@link #event:change:range} event with\n\t * removed attribute key.\n\t *\n\t * @fires change:attribute\n\t * @param {String} key Key of attribute to remove.\n\t */\n\tremoveAttribute( key ) {\n\t\tif ( this.hasAttribute( key ) ) {\n\t\t\tthis._attrs.delete( key );\n\n\t\t\tthis.fire( 'change:attribute', { attributeKeys: [ key ], directChange: true } );\n\t\t}\n\t}\n\n\t/**\n\t * Sets attribute on the selection. If attribute with the same key already is set, it's value is overwritten.\n\t *\n\t * If the attribute value has changed, fires the {@link #event:change:range} event with\n\t * the attribute key.\n\t *\n\t * @fires change:attribute\n\t * @param {String} key Key of attribute to set.\n\t * @param {*} value Attribute value.\n\t */\n\tsetAttribute( key, value ) {\n\t\tif ( this.getAttribute( key ) !== value ) {\n\t\t\tthis._attrs.set( key, value );\n\n\t\t\tthis.fire( 'change:attribute', { attributeKeys: [ key ], directChange: true } );\n\t\t}\n\t}\n\n\t/**\n\t * Returns the selected element. {@link module:engine/model/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/model/element~Element|null}\n\t */\n\tgetSelectedElement() {\n\t\tif ( this.rangeCount !== 1 ) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn this.getFirstRange().getContainedElement();\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\tselection.is( 'selection' ); // -> true\n\t *\t\tselection.is( 'model:selection' ); // -> true\n\t *\n\t *\t\tselection.is( 'view:selection' ); // -> false\n\t *\t\tselection.is( 'range' ); // -> false\n\t *\n\t * {@link module:engine/model/node~Node#is Check the entire list of model 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' || type === 'model:selection';\n\t}\n\n\t/**\n\t * Gets elements of type {@link module:engine/model/schema~Schema#isBlock \"block\"} touched by the selection.\n\t *\n\t * This method's result can be used for example to apply block styling to all blocks covered by this selection.\n\t *\n\t * **Note:** `getSelectedBlocks()` returns blocks that are nested in other non-block elements\n\t * but will not return blocks nested in other blocks.\n\t *\n\t * In this case the function will return exactly all 3 paragraphs (note: `
` is not a block itself):\n\t *\n\t *\t\t[a\n\t *\t\t
\n\t *\t\t\tb\n\t *\t\t
\n\t *\t\tc]d\n\t *\n\t * In this case the paragraph will also be returned, despite the collapsed selection:\n\t *\n\t *\t\t[]a\n\t *\n\t * In such a scenario, however, only blocks A, B & E will be returned as blocks C & D are nested in block B:\n\t *\n\t *\t\t[\n\t *\t\t\n\t *\t\t\t\n\t *\t\t\t\n\t *\t\t\n\t *\t\t]\n\t *\n\t * If the selection is inside a block all the inner blocks (A & B) are returned:\n\t *\n\t * \t\t\n\t *\t\t\t[a\n\t * \t\t\tb]\n\t * \t\t\n\t *\n\t * **Special case**: If a selection ends at the beginning of a block, that block is not returned as from user perspective\n\t * this block wasn't selected. See [#984](https://github.com/ckeditor/ckeditor5-engine/issues/984) for more details.\n\t *\n\t *\t\t[a\n\t *\t\tb\n\t *\t\t]c // this block will not be returned\n\t *\n\t * @returns {Iterable.}\n\t */\n\t* getSelectedBlocks() {\n\t\tconst visited = new WeakSet();\n\n\t\tfor ( const range of this.getRanges() ) {\n\t\t\t// Get start block of range in case of a collapsed range.\n\t\t\tconst startBlock = getParentBlock( range.start, visited );\n\n\t\t\tif ( startBlock && isTopBlockInRange( startBlock, range ) ) {\n\t\t\t\tyield startBlock;\n\t\t\t}\n\n\t\t\tfor ( const value of range.getWalker() ) {\n\t\t\t\tconst block = value.item;\n\n\t\t\t\tif ( value.type == 'elementEnd' && isUnvisitedTopBlock( block, visited, range ) ) {\n\t\t\t\t\tyield block;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst endBlock = getParentBlock( range.end, visited );\n\n\t\t\t// #984. Don't return the end block if the range ends right at its beginning.\n\t\t\tif ( endBlock && !range.end.isTouching( Position._createAt( endBlock, 0 ) ) && isTopBlockInRange( endBlock, range ) ) {\n\t\t\t\tyield endBlock;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Checks whether the selection contains the entire content of the given element. This means that selection must start\n\t * at a position {@link module:engine/model/position~Position#isTouching touching} the element's start and ends at position\n\t * touching the element's end.\n\t *\n\t * By default, this method will check whether the entire content of the selection's current root is selected.\n\t * Useful to check if e.g. the user has just pressed Ctrl + A.\n\t *\n\t * @param {module:engine/model/element~Element} [element=this.anchor.root]\n\t * @returns {Boolean}\n\t */\n\tcontainsEntireContent( element = this.anchor.root ) {\n\t\tconst limitStartPosition = Position._createAt( element, 0 );\n\t\tconst limitEndPosition = Position._createAt( element, 'end' );\n\n\t\treturn limitStartPosition.isTouching( this.getFirstPosition() ) &&\n\t\t\tlimitEndPosition.isTouching( this.getLastPosition() );\n\t}\n\n\t/**\n\t * Adds given range to internal {@link #_ranges ranges array}. Throws an error\n\t * if given range is intersecting with any range that is already stored in this selection.\n\t *\n\t * @protected\n\t * @param {module:engine/model/range~Range} range Range to add.\n\t */\n\t_pushRange( range ) {\n\t\tthis._checkRange( range );\n\t\tthis._ranges.push( new Range( range.start, range.end ) );\n\t}\n\n\t/**\n\t * Checks if given range intersects with ranges that are already in the selection. Throws an error if it does.\n\t *\n\t * @protected\n\t * @param {module:engine/model/range~Range} range Range to check.\n\t */\n\t_checkRange( range ) {\n\t\tfor ( let i = 0; i < this._ranges.length; i++ ) {\n\t\t\tif ( range.isIntersecting( this._ranges[ i ] ) ) {\n\t\t\t\t/**\n\t\t\t\t * Trying to add a range that intersects with another range in the selection.\n\t\t\t\t *\n\t\t\t\t * @error model-selection-range-intersects\n\t\t\t\t * @param {module:engine/model/range~Range} addedRange Range that was added to the selection.\n\t\t\t\t * @param {module:engine/model/range~Range} intersectingRange Range in the selection that intersects with `addedRange`.\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t'model-selection-range-intersects',\n\t\t\t\t\t[ this, range ],\n\t\t\t\t\t{ addedRange: range, intersectingRange: this._ranges[ i ] }\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Deletes ranges from internal range array. Uses {@link #_popRange _popRange} to\n\t * ensure proper ranges removal.\n\t *\n\t * @protected\n\t */\n\t_removeAllRanges() {\n\t\twhile ( this._ranges.length > 0 ) {\n\t\t\tthis._popRange();\n\t\t}\n\t}\n\n\t/**\n\t * Removes most recently added range from the selection.\n\t *\n\t * @protected\n\t */\n\t_popRange() {\n\t\tthis._ranges.pop();\n\t}\n\n\t/**\n\t * Fired when selection range(s) changed.\n\t *\n\t * @event change:range\n\t * @param {Boolean} directChange In case of {@link module:engine/model/selection~Selection} class it is always set\n\t * to `true` which indicates that the selection change was caused by a direct use of selection's API.\n\t * The {@link module:engine/model/documentselection~DocumentSelection}, however, may change because its position\n\t * was directly changed through the {@link module:engine/model/writer~Writer writer} or because its position was\n\t * changed because the structure of the model has been changed (which means an indirect change).\n\t * The indirect change does not occur in case of normal (detached) selections because they are \"static\" (as \"not live\")\n\t * which mean that they are not updated once the document changes.\n\t */\n\n\t/**\n\t * Fired when selection attribute changed.\n\t *\n\t * @event change:attribute\n\t * @param {Boolean} directChange In case of {@link module:engine/model/selection~Selection} class it is always set\n\t * to `true` which indicates that the selection change was caused by a direct use of selection's API.\n\t * The {@link module:engine/model/documentselection~DocumentSelection}, however, may change because its attributes\n\t * were directly changed through the {@link module:engine/model/writer~Writer writer} or because its position was\n\t * changed in the model and its attributes were refreshed (which means an indirect change).\n\t * The indirect change does not occur in case of normal (detached) selections because they are \"static\" (as \"not live\")\n\t * which mean that they are not updated once the document changes.\n\t * @param {Array.} attributeKeys Array containing keys of attributes that changed.\n\t */\n}\n\nmix( Selection, EmitterMixin );\n\n// Checks whether the given element extends $block in the schema and has a parent (is not a root).\n// Marks it as already visited.\nfunction isUnvisitedBlock( element, visited ) {\n\tif ( visited.has( element ) ) {\n\t\treturn false;\n\t}\n\n\tvisited.add( element );\n\n\treturn element.root.document.model.schema.isBlock( element ) && element.parent;\n}\n\n// Checks if the given element is a $block was not previously visited and is a top block in a range.\nfunction isUnvisitedTopBlock( element, visited, range ) {\n\treturn isUnvisitedBlock( element, visited ) && isTopBlockInRange( element, range );\n}\n\n// Finds the lowest element in position's ancestors which is a block.\n// It will search until first ancestor that is a limit element.\n// Marks all ancestors as already visited to not include any of them later on.\nfunction getParentBlock( position, visited ) {\n\tconst element = position.parent;\n\tconst schema = element.root.document.model.schema;\n\n\tconst ancestors = position.parent.getAncestors( { parentFirst: true, includeSelf: true } );\n\n\tlet hasParentLimit = false;\n\n\tconst block = ancestors.find( element => {\n\t\t// Stop searching after first parent node that is limit element.\n\t\tif ( hasParentLimit ) {\n\t\t\treturn false;\n\t\t}\n\n\t\thasParentLimit = schema.isLimit( element );\n\n\t\treturn !hasParentLimit && isUnvisitedBlock( element, visited );\n\t} );\n\n\t// Mark all ancestors of this position's parent, because find() might've stopped early and\n\t// the found block may be a child of another block.\n\tancestors.forEach( element => visited.add( element ) );\n\n\treturn block;\n}\n\n// Checks if the blocks is not nested in other block inside a range.\n//\n// @param {module:engine/model/element~Element} block Block to check.\n// @param {module:engine/model/range~Range} range Range to check.\nfunction isTopBlockInRange( block, range ) {\n\tconst parentBlock = findAncestorBlock( block );\n\n\tif ( !parentBlock ) {\n\t\treturn true;\n\t}\n\n\t// Add loose flag to check as parentRange can be equal to range.\n\tconst isParentInRange = range.containsRange( Range._createOn( parentBlock ), true );\n\n\treturn !isParentInRange;\n}\n\n// Returns first ancestor block of a node.\n//\n// @param {module:engine/model/node~Node} node\n// @returns {module:engine/model/node~Node|undefined}\nfunction findAncestorBlock( node ) {\n\tconst schema = node.root.document.model.schema;\n\n\tlet parent = node.parent;\n\n\twhile ( parent ) {\n\t\tif ( schema.isBlock( parent ) ) {\n\t\t\treturn parent;\n\t\t}\n\n\t\tparent = parent.parent;\n\t}\n}\n\n/**\n * An entity that is used to set selection.\n *\n * See also {@link module:engine/model/selection~Selection#setTo}\n *\n * @typedef {\n * module:engine/model/selection~Selection|\n * module:engine/model/documentselection~DocumentSelection|\n * module:engine/model/position~Position|\n * module:engine/model/range~Range|\n * module:engine/model/node~Node|\n * Iterable.|\n * null\n * } module:engine/model/selection~Selectable\n */\n"],"sourceRoot":""}