{"version":3,"sources":["webpack:///./node_modules/@ckeditor/ckeditor5-engine/src/view/placeholder.js","webpack:///./node_modules/@ckeditor/ckeditor5-engine/src/view/position.js"],"names":["documentPlaceholders","WeakMap","enablePlaceholder","options","view","element","text","_options$isDirectHost","isDirectHost","_options$keepOnFocus","keepOnFocus","doc","document","has","set","Map","registerPostFixer","writer","updateDocumentPlaceholders","get","hostElement","change","showPlaceholder","hasClass","addClass","hidePlaceholder","removeClass","needsPlaceholder","isAttached","hasContent","Array","from","getChildren","some","is","isFocused","viewSelection","selection","selectionAnchor","anchor","parent","_step","placeholders","directHostElements","wasViewModified","_iterator","_createForOfIteratorHelper","s","n","done","_step$value","Object","D_Projects_UA_repo_Source_Client_UA_User_Web_node_modules_babel_runtime_helpers_esm_slicedToArray_js__WEBPACK_IMPORTED_MODULE_5__","value","config","push","updatePlaceholder","err","e","f","_step2","_iterator2","_step2$value","getChildPlaceholderHostSubstitute","includes","getAttribute","setAttribute","isOnlyChild","childCount","firstChild","getChild","Position","offset","D_Projects_UA_repo_Source_Client_UA_User_Web_node_modules_babel_runtime_helpers_esm_classCallCheck_js__WEBPACK_IMPORTED_MODULE_0__","this","endOffset","data","length","root","editable","EditableElement","shift","shifted","_createAt","skip","arguments","undefined","startPosition","treeWalker","TreeWalker","position","getAncestors","includeSelf","ancestorsA","ancestorsB","i","type","otherPosition","compareWith","isEqual","thisPath","getPath","otherPath","result","compareArrays","itemOrPosition","node","_createBefore","_createAfter","CKEditorError","item","textNode","offsetInText","index"],"mappings":"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","file":"js/chunk-4538cddb.7c78936c.js","sourcesContent":["/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/view/placeholder\n */\n\nimport '../../theme/placeholder.css';\n\n// Each document stores information about its placeholder elements and check functions.\nconst documentPlaceholders = new WeakMap();\n\n/**\n * A helper that enables a placeholder on the provided view element (also updates its visibility).\n * The placeholder is a CSS pseudo–element (with a text content) attached to the element.\n *\n * To change the placeholder text, simply call this method again with new options.\n *\n * To disable the placeholder, use {@link module:engine/view/placeholder~disablePlaceholder `disablePlaceholder()`} helper.\n *\n * @param {Object} [options] Configuration options of the placeholder.\n * @param {module:engine/view/view~View} options.view Editing view instance.\n * @param {module:engine/view/element~Element} options.element Element that will gain a placeholder.\n * See `options.isDirectHost` to learn more.\n * @param {String} options.text Placeholder text.\n * @param {Boolean} [options.isDirectHost=true] If set `false`, the placeholder will not be enabled directly\n * in the passed `element` but in one of its children (selected automatically, i.e. a first empty child element).\n * Useful when attaching placeholders to elements that can host other elements (not just text), for instance,\n * editable root elements.\n * @param {Boolean} [options.keepOnFocus=false] If set `true`, the placeholder stay visible when the host element is focused.\n */\nexport function enablePlaceholder( options ) {\n\tconst { view, element, text, isDirectHost = true, keepOnFocus = false } = options;\n\tconst doc = view.document;\n\n\t// Use a single a single post fixer per—document to update all placeholders.\n\tif ( !documentPlaceholders.has( doc ) ) {\n\t\tdocumentPlaceholders.set( doc, new Map() );\n\n\t\t// If a post-fixer callback makes a change, it should return `true` so other post–fixers\n\t\t// can re–evaluate the document again.\n\t\tdoc.registerPostFixer( writer => updateDocumentPlaceholders( doc, writer ) );\n\t}\n\n\t// Store information about the element placeholder under its document.\n\tdocumentPlaceholders.get( doc ).set( element, {\n\t\ttext,\n\t\tisDirectHost,\n\t\tkeepOnFocus,\n\t\thostElement: isDirectHost ? element : null\n\t} );\n\n\t// Update the placeholders right away.\n\tview.change( writer => updateDocumentPlaceholders( doc, writer ) );\n}\n\n/**\n * Disables the placeholder functionality from a given element.\n *\n * See {@link module:engine/view/placeholder~enablePlaceholder `enablePlaceholder()`} to learn more.\n *\n * @param {module:engine/view/view~View} view\n * @param {module:engine/view/element~Element} element\n */\nexport function disablePlaceholder( view, element ) {\n\tconst doc = element.document;\n\n\tview.change( writer => {\n\t\tif ( !documentPlaceholders.has( doc ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst placeholders = documentPlaceholders.get( doc );\n\t\tconst config = placeholders.get( element );\n\n\t\twriter.removeAttribute( 'data-placeholder', config.hostElement );\n\t\thidePlaceholder( writer, config.hostElement );\n\n\t\tplaceholders.delete( element );\n\t} );\n}\n\n/**\n * Shows a placeholder in the provided element by changing related attributes and CSS classes.\n *\n * **Note**: This helper will not update the placeholder visibility nor manage the\n * it in any way in the future. What it does is a one–time state change of an element. Use\n * {@link module:engine/view/placeholder~enablePlaceholder `enablePlaceholder()`} and\n * {@link module:engine/view/placeholder~disablePlaceholder `disablePlaceholder()`} for full\n * placeholder functionality.\n *\n * **Note**: This helper will blindly show the placeholder directly in the root editable element if\n * one is passed, which could result in a visual clash if the editable element has some children\n * (for instance, an empty paragraph). Use {@link module:engine/view/placeholder~enablePlaceholder `enablePlaceholder()`}\n * in that case or make sure the correct element is passed to the helper.\n *\n * @param {module:engine/view/downcastwriter~DowncastWriter} writer\n * @param {module:engine/view/element~Element} element\n * @returns {Boolean} `true`, if any changes were made to the `element`.\n */\nexport function showPlaceholder( writer, element ) {\n\tif ( !element.hasClass( 'ck-placeholder' ) ) {\n\t\twriter.addClass( 'ck-placeholder', element );\n\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\n/**\n * Hides a placeholder in the element by changing related attributes and CSS classes.\n *\n * **Note**: This helper will not update the placeholder visibility nor manage the\n * it in any way in the future. What it does is a one–time state change of an element. Use\n * {@link module:engine/view/placeholder~enablePlaceholder `enablePlaceholder()`} and\n * {@link module:engine/view/placeholder~disablePlaceholder `disablePlaceholder()`} for full\n * placeholder functionality.\n *\n * @param {module:engine/view/downcastwriter~DowncastWriter} writer\n * @param {module:engine/view/element~Element} element\n * @returns {Boolean} `true`, if any changes were made to the `element`.\n */\nexport function hidePlaceholder( writer, element ) {\n\tif ( element.hasClass( 'ck-placeholder' ) ) {\n\t\twriter.removeClass( 'ck-placeholder', element );\n\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\n/**\n * Checks if a placeholder should be displayed in the element.\n *\n * **Note**: This helper will blindly check the possibility of showing a placeholder directly in the\n * root editable element if one is passed, which may not be the expected result. If an element can\n * host other elements (not just text), most likely one of its children should be checked instead\n * because it will be the final host for the placeholder. Use\n * {@link module:engine/view/placeholder~enablePlaceholder `enablePlaceholder()`} in that case or make\n * sure the correct element is passed to the helper.\n *\n * @param {module:engine/view/element~Element} element Element that holds the placeholder.\n * @param {Boolean} keepOnFocus Focusing the element will keep the placeholder visible.\n * @returns {Boolean}\n */\nexport function needsPlaceholder( element, keepOnFocus ) {\n\tif ( !element.isAttached() ) {\n\t\treturn false;\n\t}\n\n\t// Anything but uiElement(s) counts as content.\n\tconst hasContent = Array.from( element.getChildren() )\n\t\t.some( element => !element.is( 'uiElement' ) );\n\n\tif ( hasContent ) {\n\t\treturn false;\n\t}\n\n\t// Skip the focus check and make the placeholder visible already regardless of document focus state.\n\tif ( keepOnFocus ) {\n\t\treturn true;\n\t}\n\n\tconst doc = element.document;\n\n\t// If the document is blurred.\n\tif ( !doc.isFocused ) {\n\t\treturn true;\n\t}\n\n\tconst viewSelection = doc.selection;\n\tconst selectionAnchor = viewSelection.anchor;\n\n\t// If document is focused and the element is empty but the selection is not anchored inside it.\n\treturn selectionAnchor && selectionAnchor.parent !== element;\n}\n\n// Updates all placeholders associated with a document in a post–fixer callback.\n//\n// @private\n// @param { module:engine/view/document~Document} doc\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer\n// @returns {Boolean} True if any changes were made to the view document.\nfunction updateDocumentPlaceholders( doc, writer ) {\n\tconst placeholders = documentPlaceholders.get( doc );\n\tconst directHostElements = [];\n\tlet wasViewModified = false;\n\n\t// First set placeholders on the direct hosts.\n\tfor ( const [ element, config ] of placeholders ) {\n\t\tif ( config.isDirectHost ) {\n\t\t\tdirectHostElements.push( element );\n\n\t\t\tif ( updatePlaceholder( writer, element, config ) ) {\n\t\t\t\twasViewModified = true;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Then set placeholders on the indirect hosts but only on those that does not already have an direct host placeholder.\n\tfor ( const [ element, config ] of placeholders ) {\n\t\tif ( config.isDirectHost ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst hostElement = getChildPlaceholderHostSubstitute( element );\n\n\t\t// When not a direct host, it could happen that there is no child element\n\t\t// capable of displaying a placeholder.\n\t\tif ( !hostElement ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Don't override placeholder if the host element already has some direct placeholder.\n\t\tif ( directHostElements.includes( hostElement ) ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Update the host element (used for setting and removing the placeholder).\n\t\tconfig.hostElement = hostElement;\n\n\t\tif ( updatePlaceholder( writer, element, config ) ) {\n\t\t\twasViewModified = true;\n\t\t}\n\t}\n\n\treturn wasViewModified;\n}\n\n// Updates a single placeholder in a post–fixer callback.\n//\n// @private\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer\n// @param {module:engine/view/element~Element} element\n// @param {Object} config Configuration of the placeholder\n// @param {String} config.text\n// @param {Boolean} config.isDirectHost\n// @returns {Boolean} True if any changes were made to the view document.\nfunction updatePlaceholder( writer, element, config ) {\n\tconst { text, isDirectHost, hostElement } = config;\n\n\tlet wasViewModified = false;\n\n\t// This may be necessary when updating the placeholder text to something else.\n\tif ( hostElement.getAttribute( 'data-placeholder' ) !== text ) {\n\t\twriter.setAttribute( 'data-placeholder', text, hostElement );\n\t\twasViewModified = true;\n\t}\n\n\t// If the host element is not a direct host then placeholder is needed only when there is only one element.\n\tconst isOnlyChild = isDirectHost || element.childCount == 1;\n\n\tif ( isOnlyChild && needsPlaceholder( hostElement, config.keepOnFocus ) ) {\n\t\tif ( showPlaceholder( writer, hostElement ) ) {\n\t\t\twasViewModified = true;\n\t\t}\n\t} else if ( hidePlaceholder( writer, hostElement ) ) {\n\t\twasViewModified = true;\n\t}\n\n\treturn wasViewModified;\n}\n\n// Gets a child element capable of displaying a placeholder if a parent element can host more\n// than just text (for instance, when it is a root editable element). The child element\n// can then be used in other placeholder helpers as a substitute of its parent.\n//\n// @private\n// @param {module:engine/view/element~Element} parent\n// @returns {module:engine/view/element~Element|null}\nfunction getChildPlaceholderHostSubstitute( parent ) {\n\tif ( parent.childCount ) {\n\t\tconst firstChild = parent.getChild( 0 );\n\n\t\tif ( firstChild.is( 'element' ) && !firstChild.is( 'uiElement' ) ) {\n\t\t\treturn firstChild;\n\t\t}\n\t}\n\n\treturn null;\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/view/position\n */\n\nimport TreeWalker from './treewalker';\n\nimport compareArrays from '@ckeditor/ckeditor5-utils/src/comparearrays';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport EditableElement from './editableelement';\n\n// To check if component is loaded more than once.\nimport '@ckeditor/ckeditor5-utils/src/version';\n\n/**\n * Position in the view tree. Position is represented by its parent node and an offset in this parent.\n *\n * In order to create a new position instance use the `createPosition*()` factory methods available in:\n *\n * * {@link module:engine/view/view~View}\n * * {@link module:engine/view/downcastwriter~DowncastWriter}\n * * {@link module:engine/view/upcastwriter~UpcastWriter}\n */\nexport default class Position {\n\t/**\n\t * Creates a position.\n\t *\n\t * @param {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment} parent Position parent.\n\t * @param {Number} offset Position offset.\n\t */\n\tconstructor( parent, offset ) {\n\t\t/**\n\t\t * Position parent.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment}\n\t\t * module:engine/view/position~Position#parent\n\t\t */\n\t\tthis.parent = parent;\n\n\t\t/**\n\t\t * Position offset.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number} module:engine/view/position~Position#offset\n\t\t */\n\t\tthis.offset = offset;\n\t}\n\n\t/**\n\t * Node directly after the position. Equals `null` when there is no node after position or position is located\n\t * inside text node.\n\t *\n\t * @readonly\n\t * @type {module:engine/view/node~Node|null}\n\t */\n\tget nodeAfter() {\n\t\tif ( this.parent.is( '$text' ) ) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn this.parent.getChild( this.offset ) || null;\n\t}\n\n\t/**\n\t * Node directly before the position. Equals `null` when there is no node before position or position is located\n\t * inside text node.\n\t *\n\t * @readonly\n\t * @type {module:engine/view/node~Node|null}\n\t */\n\tget nodeBefore() {\n\t\tif ( this.parent.is( '$text' ) ) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn this.parent.getChild( this.offset - 1 ) || null;\n\t}\n\n\t/**\n\t * Is `true` if position is at the beginning of its {@link module:engine/view/position~Position#parent parent}, `false` otherwise.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget isAtStart() {\n\t\treturn this.offset === 0;\n\t}\n\n\t/**\n\t * Is `true` if position is at the end of its {@link module:engine/view/position~Position#parent parent}, `false` otherwise.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget isAtEnd() {\n\t\tconst endOffset = this.parent.is( '$text' ) ? this.parent.data.length : this.parent.childCount;\n\n\t\treturn this.offset === endOffset;\n\t}\n\n\t/**\n\t * Position's root, that is the root of the position's parent element.\n\t *\n\t * @readonly\n\t * @type {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment}\n\t */\n\tget root() {\n\t\treturn this.parent.root;\n\t}\n\n\t/**\n\t * {@link module:engine/view/editableelement~EditableElement EditableElement} instance that contains this position, or `null` if\n\t * position is not inside an editable element.\n\t *\n\t * @type {module:engine/view/editableelement~EditableElement|null}\n\t */\n\tget editableElement() {\n\t\tlet editable = this.parent;\n\n\t\twhile ( !( editable instanceof EditableElement ) ) {\n\t\t\tif ( editable.parent ) {\n\t\t\t\teditable = editable.parent;\n\t\t\t} else {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\n\t\treturn editable;\n\t}\n\n\t/**\n\t * Returns a new instance of Position with offset incremented by `shift` value.\n\t *\n\t * @param {Number} shift How position offset should get changed. Accepts negative values.\n\t * @returns {module:engine/view/position~Position} Shifted position.\n\t */\n\tgetShiftedBy( shift ) {\n\t\tconst shifted = Position._createAt( this );\n\n\t\tconst offset = shifted.offset + shift;\n\t\tshifted.offset = offset < 0 ? 0 : offset;\n\n\t\treturn shifted;\n\t}\n\n\t/**\n\t * Gets the farthest position which matches the callback using\n\t * {@link module:engine/view/treewalker~TreeWalker TreeWalker}.\n\t *\n\t * For example:\n\t *\n\t * \t\tgetLastMatchingPosition( value => value.type == 'text' ); //
{}foo
->foo[]
\n\t * \t\tgetLastMatchingPosition( value => value.type == 'text', { direction: 'backward' } ); //foo[]
->{}foo
\n\t * \t\tgetLastMatchingPosition( value => false ); // Do not move the position.\n\t *\n\t * @param {Function} skip Callback function. Gets {@link module:engine/view/treewalker~TreeWalkerValue} and should\n\t * return `true` if the value should be skipped or `false` if not.\n\t * @param {Object} options Object with configuration options. See {@link module:engine/view/treewalker~TreeWalker}.\n\t *\n\t * @returns {module:engine/view/position~Position} The position after the last item which matches the `skip` callback test.\n\t */\n\tgetLastMatchingPosition( skip, options = {} ) {\n\t\toptions.startPosition = this;\n\n\t\tconst treeWalker = new TreeWalker( options );\n\t\ttreeWalker.skip( skip );\n\n\t\treturn treeWalker.position;\n\t}\n\n\t/**\n\t * Returns ancestors array of this position, that is this position's parent and it's ancestors.\n\t *\n\t * @returns {Array} Array with ancestors.\n\t */\n\tgetAncestors() {\n\t\tif ( this.parent.is( 'documentFragment' ) ) {\n\t\t\treturn [ this.parent ];\n\t\t} else {\n\t\t\treturn this.parent.getAncestors( { includeSelf: true } );\n\t\t}\n\t}\n\n\t/**\n\t * Returns a {@link module:engine/view/node~Node} or {@link module:engine/view/documentfragment~DocumentFragment}\n\t * which is a common ancestor of both positions.\n\t *\n\t * @param {module:engine/view/position~Position} position\n\t * @returns {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment|null}\n\t */\n\tgetCommonAncestor( position ) {\n\t\tconst ancestorsA = this.getAncestors();\n\t\tconst ancestorsB = position.getAncestors();\n\n\t\tlet i = 0;\n\n\t\twhile ( ancestorsA[ i ] == ancestorsB[ i ] && ancestorsA[ i ] ) {\n\t\t\ti++;\n\t\t}\n\n\t\treturn i === 0 ? null : ancestorsA[ i - 1 ];\n\t}\n\n\t/**\n\t * Checks whether this object is of the given type.\n\t *\n\t *\t\tposition.is( 'position' ); // -> true\n\t *\t\tposition.is( 'view:position' ); // -> true\n\t *\n\t *\t\tposition.is( 'model:position' ); // -> false\n\t *\t\tposition.is( 'element' ); // -> false\n\t *\t\tposition.is( 'range' ); // -> false\n\t *\n\t * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.\n\t *\n\t * @param {String} type\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type === 'position' || type === 'view:position';\n\t}\n\n\t/**\n\t * Checks whether this position equals given position.\n\t *\n\t * @param {module:engine/view/position~Position} otherPosition Position to compare with.\n\t * @returns {Boolean} True if positions are same.\n\t */\n\tisEqual( otherPosition ) {\n\t\treturn ( this.parent == otherPosition.parent && this.offset == otherPosition.offset );\n\t}\n\n\t/**\n\t * Checks whether this position is located before given position. When method returns `false` it does not mean that\n\t * this position is after give one. Two positions may be located inside separate roots and in that situation this\n\t * method will still return `false`.\n\t *\n\t * @see module:engine/view/position~Position#isAfter\n\t * @see module:engine/view/position~Position#compareWith\n\t * @param {module:engine/view/position~Position} otherPosition Position to compare with.\n\t * @returns {Boolean} Returns `true` if this position is before given position.\n\t */\n\tisBefore( otherPosition ) {\n\t\treturn this.compareWith( otherPosition ) == 'before';\n\t}\n\n\t/**\n\t * Checks whether this position is located after given position. When method returns `false` it does not mean that\n\t * this position is before give one. Two positions may be located inside separate roots and in that situation this\n\t * method will still return `false`.\n\t *\n\t * @see module:engine/view/position~Position#isBefore\n\t * @see module:engine/view/position~Position#compareWith\n\t * @param {module:engine/view/position~Position} otherPosition Position to compare with.\n\t * @returns {Boolean} Returns `true` if this position is after given position.\n\t */\n\tisAfter( otherPosition ) {\n\t\treturn this.compareWith( otherPosition ) == 'after';\n\t}\n\n\t/**\n\t * Checks whether this position is before, after or in same position that other position. Two positions may be also\n\t * different when they are located in separate roots.\n\t *\n\t * @param {module:engine/view/position~Position} otherPosition Position to compare with.\n\t * @returns {module:engine/view/position~PositionRelation}\n\t */\n\tcompareWith( otherPosition ) {\n\t\tif ( this.root !== otherPosition.root ) {\n\t\t\treturn 'different';\n\t\t}\n\n\t\tif ( this.isEqual( otherPosition ) ) {\n\t\t\treturn 'same';\n\t\t}\n\n\t\t// Get path from root to position's parent element.\n\t\tconst thisPath = this.parent.is( 'node' ) ? this.parent.getPath() : [];\n\t\tconst otherPath = otherPosition.parent.is( 'node' ) ? otherPosition.parent.getPath() : [];\n\n\t\t// Add the positions' offsets to the parents offsets.\n\t\tthisPath.push( this.offset );\n\t\totherPath.push( otherPosition.offset );\n\n\t\t// Compare both path arrays to find common ancestor.\n\t\tconst result = compareArrays( thisPath, otherPath );\n\n\t\tswitch ( result ) {\n\t\t\tcase 'prefix':\n\t\t\t\treturn 'before';\n\n\t\t\tcase 'extension':\n\t\t\t\treturn 'after';\n\n\t\t\tdefault:\n\t\t\t\treturn thisPath[ result ] < otherPath[ result ] ? 'before' : 'after';\n\t\t}\n\t}\n\n\t/**\n\t * Creates a {@link module:engine/view/treewalker~TreeWalker TreeWalker} instance with this positions as a start position.\n\t *\n\t * @param {Object} options Object with configuration options. See {@link module:engine/view/treewalker~TreeWalker}\n\t * @param {module:engine/view/range~Range} [options.boundaries=null] Range to define boundaries of the iterator.\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.startPosition = this;\n\n\t\treturn new TreeWalker( options );\n\t}\n\n\tclone() {\n\t\treturn new Position( this.parent, this.offset );\n\t}\n\n\t/**\n\t * Creates position at the given location. The location can be specified as:\n\t *\n\t * * a {@link module:engine/view/position~Position position},\n\t * * parent element and offset (offset defaults to `0`),\n\t * * parent element and `'end'` (sets position at the end of that element),\n\t * * {@link module:engine/view/item~Item view item} and `'before'` or `'after'` (sets position before or after given view item).\n\t *\n\t * This method is a shortcut to other constructors such as:\n\t *\n\t * * {@link module:engine/view/position~Position._createBefore},\n\t * * {@link module:engine/view/position~Position._createAfter}.\n\t *\n\t * @protected\n\t * @param {module:engine/view/item~Item|module:engine/view/position~Position} itemOrPosition\n\t * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when\n\t * first parameter is a {@link module:engine/view/item~Item view item}.\n\t */\n\tstatic _createAt( itemOrPosition, offset ) {\n\t\tif ( itemOrPosition instanceof Position ) {\n\t\t\treturn new this( itemOrPosition.parent, itemOrPosition.offset );\n\t\t} else {\n\t\t\tconst node = itemOrPosition;\n\n\t\t\tif ( offset == 'end' ) {\n\t\t\t\toffset = node.is( '$text' ) ? node.data.length : node.childCount;\n\t\t\t} else if ( offset == 'before' ) {\n\t\t\t\treturn this._createBefore( node );\n\t\t\t} else if ( offset == 'after' ) {\n\t\t\t\treturn this._createAfter( node );\n\t\t\t} else if ( offset !== 0 && !offset ) {\n\t\t\t\t/**\n\t\t\t\t * {@link module:engine/view/view~View#createPositionAt `View#createPositionAt()`}\n\t\t\t\t * requires the offset to be specified when the first parameter is a view item.\n\t\t\t\t *\n\t\t\t\t * @error view-createpositionat-offset-required\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError( 'view-createpositionat-offset-required', node );\n\t\t\t}\n\n\t\t\treturn new Position( node, offset );\n\t\t}\n\t}\n\n\t/**\n\t * Creates a new position after given view item.\n\t *\n\t * @protected\n\t * @param {module:engine/view/item~Item} item View item after which the position should be located.\n\t * @returns {module:engine/view/position~Position}\n\t */\n\tstatic _createAfter( item ) {\n\t\t// TextProxy is not a instance of Node so we need do handle it in specific way.\n\t\tif ( item.is( '$textProxy' ) ) {\n\t\t\treturn new Position( item.textNode, item.offsetInText + item.data.length );\n\t\t}\n\n\t\tif ( !item.parent ) {\n\t\t\t/**\n\t\t\t * You can not make a position after a root.\n\t\t\t *\n\t\t\t * @error view-position-after-root\n\t\t\t * @param {module:engine/view/node~Node} root\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-position-after-root', item, { root: item } );\n\t\t}\n\n\t\treturn new Position( item.parent, item.index + 1 );\n\t}\n\n\t/**\n\t * Creates a new position before given view item.\n\t *\n\t * @protected\n\t * @param {module:engine/view/item~Item} item View item before which the position should be located.\n\t * @returns {module:engine/view/position~Position}\n\t */\n\tstatic _createBefore( item ) {\n\t\t// TextProxy is not a instance of Node so we need do handle it in specific way.\n\t\tif ( item.is( '$textProxy' ) ) {\n\t\t\treturn new Position( item.textNode, item.offsetInText );\n\t\t}\n\n\t\tif ( !item.parent ) {\n\t\t\t/**\n\t\t\t * You cannot make a position before a root.\n\t\t\t *\n\t\t\t * @error view-position-before-root\n\t\t\t * @param {module:engine/view/node~Node} root\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-position-before-root', item, { root: item } );\n\t\t}\n\n\t\treturn new Position( item.parent, item.index );\n\t}\n}\n\n/**\n * A flag indicating whether this position is `'before'` or `'after'` or `'same'` as given position.\n * If positions are in different roots `'different'` flag is returned.\n *\n * @typedef {String} module:engine/view/position~PositionRelation\n */\n"],"sourceRoot":""}