{"version":3,"sources":["webpack:///./node_modules/@ckeditor/ckeditor5-widget/src/widgettypearound/widgettypearound.js","webpack:///./node_modules/@ckeditor/ckeditor5-widget/src/widgettypearound/utils.js"],"names":["POSSIBLE_INSERTION_POSITIONS","RETURN_ARROW_ICON_ELEMENT","DOMParser","parseFromString","returnIcon","firstChild","PLUGIN_DISABLED_EDITING_ROOT_CLASS","WidgetTypeAround","editor","_this","Object","D_Projects_UA_repo_Source_Client_UA_User_Web_node_modules_babel_runtime_helpers_esm_classCallCheck_js__WEBPACK_IMPORTED_MODULE_10__","this","_super","call","_currentFakeCaretModelElement","editingView","editing","view","on","evt","data","isEnabled","change","writer","_step","_iterator","_createForOfIteratorHelper","document","roots","s","n","done","root","value","removeClass","addClass","err","e","f","model","removeSelectionAttribute","TYPE_AROUND_SELECTION_ATTRIBUTE","_enableTypeAroundUIInjection","_enableInsertingParagraphsOnButtonClick","_enableInsertingParagraphsOnEnterKeypress","_enableInsertingParagraphsOnTypingKeystroke","_enableTypeAroundFakeCaretActivationUsingKeyboardArrows","_enableDeleteIntegration","_enableInsertContentIntegration","_enableDeleteContentIntegration","widgetModelElement","position","execute","createPositionAt","focus","scrollToTheSelection","emitter","event","callback","options","_this2","listenTo","apply","arguments","modelSelection","selection","typeAroundFakeCaretPosition","getTypeAroundFakeCaretPosition","selectedModelElement","getSelectedElement","_insertParagraph","schema","t","locale","buttonTitles","before","after","downcastDispatcher","conversionApi","viewElement","mapper","toViewElement","item","isTypeAroundWidget","injectUIIntoWidget","priority","_this3","positionToWidgetCssClass","concat","_listenToIfEnabled","domEventData","_handleArrowKeyPress","context","isWidget","directChange","selectedViewElement","map","ui","focusTracker","name","isFocused","shouldStopAndPreventDefault","keyCode","isForward","isForwardArrowKeyCode","contentLanguageDirection","toModelElement","_handleArrowKeyPressOnSelectedWidget","isCollapsed","_handleArrowKeyPressWhenSelectionNextToAWidget","preventDefault","stop","setSelectionAttribute","isLeavingWidget","widgetPlugin","plugins","get","modelElementNextToSelection","_getObjectElementNextToSelection","viewElementNextToSelection","_setSelectionOverElement","_this4","button","getClosestTypeAroundDomButton","domTarget","buttonPosition","getTypeAroundButtonPosition","widgetViewElement","getClosestWidgetViewElement","domConverter","_this5","eventPhase","wasHandled","_insertParagraphAccordingToFakeCaretPosition","isSoft","_this6","keyCodesHandledSomewhereElse","keyCodes","enter","delete","backspace","includes","isNonTypingKeystroke","direction","selectedModelWidget","isFakeCaretBefore","isDeleteForward","shouldDeleteEntireWidget","createSelection","range","getNearestSelectionRange","probe","start","modifySelection","isEqual","deepestEmptyRangeAncestor","getDeepestEmptyElementAncestor","parent","deleteContent","doNotAutoparagraph","setSelection","documentSelection","_ref","_ref2","D_Projects_UA_repo_Source_Client_UA_User_Web_node_modules_babel_runtime_helpers_esm_slicedToArray_js__WEBPACK_IMPORTED_MODULE_7__","content","selectable","is","selectedElement","result","insertContent","_ref3","_ref4","Enter","Delete","Plugin","viewWriter","typeAroundWrapper","createUIElement","class","domDocument","wrapperDomElement","toDomElement","injectButtons","injectFakeCaret","insert","_step2","_iterator2","buttonTemplate","Template","tag","attributes","title","children","ownerDocument","importNode","appendChild","render","caretTemplate","element","_step3","deepestEmptyAncestor","_iterator3","getAncestors","parentFirst","ancestor","childCount","isLimit","__webpack_require__","d","__webpack_exports__","_utils__WEBPACK_IMPORTED_MODULE_0__","modelElement","isInline","domElement","closest","classList","contains","widgetDomElement","mapDomToView","getAttribute"],"mappings":"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","file":"js/chunk-459d0d46.dbfcc542.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/* global DOMParser */\n\n/**\n * @module widget/widgettypearound\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport Template from '@ckeditor/ckeditor5-ui/src/template';\nimport Enter from '@ckeditor/ckeditor5-enter/src/enter';\nimport Delete from '@ckeditor/ckeditor5-typing/src/delete';\nimport {\n\tisForwardArrowKeyCode,\n\tkeyCodes\n} from '@ckeditor/ckeditor5-utils/src/keyboard';\n\nimport {\n\tisTypeAroundWidget,\n\tgetClosestTypeAroundDomButton,\n\tgetTypeAroundButtonPosition,\n\tgetClosestWidgetViewElement,\n\tgetTypeAroundFakeCaretPosition,\n\tTYPE_AROUND_SELECTION_ATTRIBUTE\n} from './utils';\n\nimport {\n\tisNonTypingKeystroke\n} from '@ckeditor/ckeditor5-typing/src/utils/injectunsafekeystrokeshandling';\n\nimport { isWidget } from '../utils';\n\nimport returnIcon from '../../theme/icons/return-arrow.svg';\nimport '../../theme/widgettypearound.css';\n\nconst POSSIBLE_INSERTION_POSITIONS = [ 'before', 'after' ];\n\n// Do the SVG parsing once and then clone the result DOM element for each new button.\nconst RETURN_ARROW_ICON_ELEMENT = new DOMParser().parseFromString( returnIcon, 'image/svg+xml' ).firstChild;\n\nconst PLUGIN_DISABLED_EDITING_ROOT_CLASS = 'ck-widget__type-around_disabled';\n\n/**\n * A plugin that allows users to type around widgets where normally it is impossible to place the caret due\n * to limitations of web browsers. These \"tight spots\" occur, for instance, before (or after) a widget being\n * the first (or last) child of its parent or between two block widgets.\n *\n * This plugin extends the {@link module:widget/widget~Widget `Widget`} plugin and injects the user interface\n * with two buttons into each widget instance in the editor. Each of the buttons can be clicked by the\n * user if the widget is next to the \"tight spot\". Once clicked, a paragraph is created with the selection anchored\n * in it so that users can type (or insert content, paste, etc.) straight away.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class WidgetTypeAround extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'WidgetTypeAround';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ Enter, Delete ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * A reference to the model widget element that has the fake caret active\n\t\t * on either side of it. It is later used to remove CSS classes associated with the fake caret\n\t\t * when the widget no longer needs it.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/model/element~Element|null}\n\t\t */\n\t\tthis._currentFakeCaretModelElement = null;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst editingView = editor.editing.view;\n\n\t\t// Set a CSS class on the view editing root when the plugin is disabled so all the buttons\n\t\t// and lines visually disappear. All the interactions are disabled in individual plugin methods.\n\t\tthis.on( 'change:isEnabled', ( evt, data, isEnabled ) => {\n\t\t\teditingView.change( writer => {\n\t\t\t\tfor ( const root of editingView.document.roots ) {\n\t\t\t\t\tif ( isEnabled ) {\n\t\t\t\t\t\twriter.removeClass( PLUGIN_DISABLED_EDITING_ROOT_CLASS, root );\n\t\t\t\t\t} else {\n\t\t\t\t\t\twriter.addClass( PLUGIN_DISABLED_EDITING_ROOT_CLASS, root );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} );\n\n\t\t\tif ( !isEnabled ) {\n\t\t\t\teditor.model.change( writer => {\n\t\t\t\t\twriter.removeSelectionAttribute( TYPE_AROUND_SELECTION_ATTRIBUTE );\n\t\t\t\t} );\n\t\t\t}\n\t\t} );\n\n\t\tthis._enableTypeAroundUIInjection();\n\t\tthis._enableInsertingParagraphsOnButtonClick();\n\t\tthis._enableInsertingParagraphsOnEnterKeypress();\n\t\tthis._enableInsertingParagraphsOnTypingKeystroke();\n\t\tthis._enableTypeAroundFakeCaretActivationUsingKeyboardArrows();\n\t\tthis._enableDeleteIntegration();\n\t\tthis._enableInsertContentIntegration();\n\t\tthis._enableDeleteContentIntegration();\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tthis._currentFakeCaretModelElement = null;\n\t}\n\n\t/**\n\t * Inserts a new paragraph next to a widget element with the selection anchored in it.\n\t *\n\t * **Note**: This method is heavily user-oriented and will both focus the editing view and scroll\n\t * the viewport to the selection in the inserted paragraph.\n\t *\n\t * @protected\n\t * @param {module:engine/model/element~Element} widgetModelElement The model widget element next to which a paragraph is inserted.\n\t * @param {'before'|'after'} position The position where the paragraph is inserted. Either `'before'` or `'after'` the widget.\n\t */\n\t_insertParagraph( widgetModelElement, position ) {\n\t\tconst editor = this.editor;\n\t\tconst editingView = editor.editing.view;\n\n\t\teditor.execute( 'insertParagraph', {\n\t\t\tposition: editor.model.createPositionAt( widgetModelElement, position )\n\t\t} );\n\n\t\teditingView.focus();\n\t\teditingView.scrollToTheSelection();\n\t}\n\n\t/**\n\t * A wrapper for the {@link module:utils/emittermixin~EmitterMixin#listenTo} method that executes the callbacks only\n\t * when the plugin {@link #isEnabled is enabled}.\n\t *\n\t * @private\n\t * @param {module:utils/emittermixin~Emitter} emitter The object that fires the event.\n\t * @param {String} event The name of the event.\n\t * @param {Function} callback The function to be called on event.\n\t * @param {Object} [options={}] Additional options.\n\t * @param {module:utils/priorities~PriorityString|Number} [options.priority='normal'] The priority of this event callback. The higher\n\t * the priority value the sooner the callback will be fired. Events having the same priority are called in the\n\t * order they were added.\n\t */\n\t_listenToIfEnabled( emitter, event, callback, options ) {\n\t\tthis.listenTo( emitter, event, ( ...args ) => {\n\t\t\t// Do not respond if the plugin is disabled.\n\t\t\tif ( this.isEnabled ) {\n\t\t\t\tcallback( ...args );\n\t\t\t}\n\t\t}, options );\n\t}\n\n\t/**\n\t * Similar to {@link #_insertParagraph}, this method inserts a paragraph except that it\n\t * does not expect a position. Instead, it performs the insertion next to a selected widget\n\t * according to the `widget-type-around` model selection attribute value (fake caret position).\n\t *\n\t * Because this method requires the `widget-type-around` attribute to be set,\n\t * the insertion can only happen when the widget's fake caret is active (e.g. activated\n\t * using the keyboard).\n\t *\n\t * @private\n\t * @returns {Boolean} Returns `true` when the paragraph was inserted (the attribute was present) and `false` otherwise.\n\t */\n\t_insertParagraphAccordingToFakeCaretPosition() {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\t\tconst modelSelection = model.document.selection;\n\t\tconst typeAroundFakeCaretPosition = getTypeAroundFakeCaretPosition( modelSelection );\n\n\t\tif ( !typeAroundFakeCaretPosition ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst selectedModelElement = modelSelection.getSelectedElement();\n\n\t\tthis._insertParagraph( selectedModelElement, typeAroundFakeCaretPosition );\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Creates a listener in the editing conversion pipeline that injects the widget type around\n\t * UI into every single widget instance created in the editor.\n\t *\n\t * The UI is delivered as a {@link module:engine/view/uielement~UIElement}\n\t * wrapper which renders DOM buttons that users can use to insert paragraphs.\n\t *\n\t * @private\n\t */\n\t_enableTypeAroundUIInjection() {\n\t\tconst editor = this.editor;\n\t\tconst schema = editor.model.schema;\n\t\tconst t = editor.locale.t;\n\t\tconst buttonTitles = {\n\t\t\tbefore: t( 'Insert paragraph before block' ),\n\t\t\tafter: t( 'Insert paragraph after block' )\n\t\t};\n\n\t\teditor.editing.downcastDispatcher.on( 'insert', ( evt, data, conversionApi ) => {\n\t\t\tconst viewElement = conversionApi.mapper.toViewElement( data.item );\n\n\t\t\t// Filter out non-widgets and inline widgets.\n\t\t\tif ( isTypeAroundWidget( viewElement, data.item, schema ) ) {\n\t\t\t\tinjectUIIntoWidget( conversionApi.writer, buttonTitles, viewElement );\n\t\t\t}\n\t\t}, { priority: 'low' } );\n\t}\n\n\t/**\n\t * Brings support for the fake caret that appears when either:\n\t *\n\t * * the selection moves to a widget from a position next to it using arrow keys,\n\t * * the arrow key is pressed when the widget is already selected.\n\t *\n\t * The fake caret lets the user know that they can start typing or just press\n\t * Enter to insert a paragraph at the position next to a widget as suggested by the fake caret.\n\t *\n\t * The fake caret disappears when the user changes the selection or the editor\n\t * gets blurred.\n\t *\n\t * The whole idea is as follows:\n\t *\n\t * 1. A user does one of the 2 scenarios described at the beginning.\n\t * 2. The \"keydown\" listener is executed and the decision is made whether to show or hide the fake caret.\n\t * 3. If it should show up, the `widget-type-around` model selection attribute is set indicating\n\t * on which side of the widget it should appear.\n\t * 4. The selection dispatcher reacts to the selection attribute and sets CSS classes responsible for the\n\t * fake caret on the view widget.\n\t * 5. If the fake caret should disappear, the selection attribute is removed and the dispatcher\n\t * does the CSS class clean-up in the view.\n\t * 6. Additionally, `change:range` and `FocusTracker#isFocused` listeners also remove the selection\n\t * attribute (the former also removes widget CSS classes).\n\t *\n\t * @private\n\t */\n\t_enableTypeAroundFakeCaretActivationUsingKeyboardArrows() {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\t\tconst modelSelection = model.document.selection;\n\t\tconst schema = model.schema;\n\t\tconst editingView = editor.editing.view;\n\n\t\t// This is the main listener responsible for the fake caret.\n\t\t// Note: The priority must precede the default Widget class keydown handler (\"high\").\n\t\tthis._listenToIfEnabled( editingView.document, 'arrowKey', ( evt, domEventData ) => {\n\t\t\tthis._handleArrowKeyPress( evt, domEventData );\n\t\t}, { context: [ isWidget, '$text' ], priority: 'high' } );\n\n\t\t// This listener makes sure the widget type around selection attribute will be gone from the model\n\t\t// selection as soon as the model range changes. This attribute only makes sense when a widget is selected\n\t\t// (and the \"fake horizontal caret\" is visible) so whenever the range changes (e.g. selection moved somewhere else),\n\t\t// let's get rid of the attribute so that the selection downcast dispatcher isn't even bothered.\n\t\tthis._listenToIfEnabled( modelSelection, 'change:range', ( evt, data ) => {\n\t\t\t// Do not reset the selection attribute when the change was indirect.\n\t\t\tif ( !data.directChange ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Get rid of the widget type around attribute of the selection on every change:range.\n\t\t\t// If the range changes, it means for sure, the user is no longer in the active (\"fake horizontal caret\") mode.\n\t\t\teditor.model.change( writer => {\n\t\t\t\twriter.removeSelectionAttribute( TYPE_AROUND_SELECTION_ATTRIBUTE );\n\t\t\t} );\n\t\t} );\n\n\t\t// Get rid of the widget type around attribute of the selection on every document change\n\t\t// that makes widget not selected any more (i.e. widget was removed).\n\t\tthis._listenToIfEnabled( model.document, 'change:data', () => {\n\t\t\tconst selectedModelElement = modelSelection.getSelectedElement();\n\n\t\t\tif ( selectedModelElement ) {\n\t\t\t\tconst selectedViewElement = editor.editing.mapper.toViewElement( selectedModelElement );\n\n\t\t\t\tif ( isTypeAroundWidget( selectedViewElement, selectedModelElement, schema ) ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\teditor.model.change( writer => {\n\t\t\t\twriter.removeSelectionAttribute( TYPE_AROUND_SELECTION_ATTRIBUTE );\n\t\t\t} );\n\t\t} );\n\n\t\t// React to changes of the model selection attribute made by the arrow keys listener.\n\t\t// If the block widget is selected and the attribute changes, downcast the attribute to special\n\t\t// CSS classes associated with the active (\"fake horizontal caret\") mode of the widget.\n\t\tthis._listenToIfEnabled( editor.editing.downcastDispatcher, 'selection', ( evt, data, conversionApi ) => {\n\t\t\tconst writer = conversionApi.writer;\n\n\t\t\tif ( this._currentFakeCaretModelElement ) {\n\t\t\t\tconst selectedViewElement = conversionApi.mapper.toViewElement( this._currentFakeCaretModelElement );\n\n\t\t\t\tif ( selectedViewElement ) {\n\t\t\t\t\t// Get rid of CSS classes associated with the active (\"fake horizontal caret\") mode from the view widget.\n\t\t\t\t\twriter.removeClass( POSSIBLE_INSERTION_POSITIONS.map( positionToWidgetCssClass ), selectedViewElement );\n\n\t\t\t\t\tthis._currentFakeCaretModelElement = null;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst selectedModelElement = data.selection.getSelectedElement();\n\n\t\t\tif ( !selectedModelElement ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst selectedViewElement = conversionApi.mapper.toViewElement( selectedModelElement );\n\n\t\t\tif ( !isTypeAroundWidget( selectedViewElement, selectedModelElement, schema ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst typeAroundFakeCaretPosition = getTypeAroundFakeCaretPosition( data.selection );\n\n\t\t\tif ( !typeAroundFakeCaretPosition ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\twriter.addClass( positionToWidgetCssClass( typeAroundFakeCaretPosition ), selectedViewElement );\n\n\t\t\t// Remember the view widget that got the \"fake-caret\" CSS class. This class should be removed ASAP when the\n\t\t\t// selection changes\n\t\t\tthis._currentFakeCaretModelElement = selectedModelElement;\n\t\t} );\n\n\t\tthis._listenToIfEnabled( editor.ui.focusTracker, 'change:isFocused', ( evt, name, isFocused ) => {\n\t\t\tif ( !isFocused ) {\n\t\t\t\teditor.model.change( writer => {\n\t\t\t\t\twriter.removeSelectionAttribute( TYPE_AROUND_SELECTION_ATTRIBUTE );\n\t\t\t\t} );\n\t\t\t}\n\t\t} );\n\n\t\tfunction positionToWidgetCssClass( position ) {\n\t\t\treturn `ck-widget_type-around_show-fake-caret_${ position }`;\n\t\t}\n\t}\n\n\t/**\n\t * A listener executed on each \"keydown\" in the view document, a part of\n\t * {@link #_enableTypeAroundFakeCaretActivationUsingKeyboardArrows}.\n\t *\n\t * It decides whether the arrow keypress should activate the fake caret or not (also whether it should\n\t * be deactivated).\n\t *\n\t * The fake caret activation is done by setting the `widget-type-around` model selection attribute\n\t * in this listener, and stopping and preventing the event that would normally be handled by the widget\n\t * plugin that is responsible for the regular keyboard navigation near/across all widgets (that\n\t * includes inline widgets, which are ignored by the widget type around plugin).\n\t *\n\t * @private\n\t */\n\t_handleArrowKeyPress( evt, domEventData ) {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\t\tconst modelSelection = model.document.selection;\n\t\tconst schema = model.schema;\n\t\tconst editingView = editor.editing.view;\n\n\t\tconst keyCode = domEventData.keyCode;\n\t\tconst isForward = isForwardArrowKeyCode( keyCode, editor.locale.contentLanguageDirection );\n\t\tconst selectedViewElement = editingView.document.selection.getSelectedElement();\n\t\tconst selectedModelElement = editor.editing.mapper.toModelElement( selectedViewElement );\n\t\tlet shouldStopAndPreventDefault;\n\n\t\t// Handle keyboard navigation when a type-around-compatible widget is currently selected.\n\t\tif ( isTypeAroundWidget( selectedViewElement, selectedModelElement, schema ) ) {\n\t\t\tshouldStopAndPreventDefault = this._handleArrowKeyPressOnSelectedWidget( isForward );\n\t\t}\n\t\t// Handle keyboard arrow navigation when the selection is next to a type-around-compatible widget\n\t\t// and the widget is about to be selected.\n\t\telse if ( modelSelection.isCollapsed ) {\n\t\t\tshouldStopAndPreventDefault = this._handleArrowKeyPressWhenSelectionNextToAWidget( isForward );\n\t\t}\n\n\t\tif ( shouldStopAndPreventDefault ) {\n\t\t\tdomEventData.preventDefault();\n\t\t\tevt.stop();\n\t\t}\n\t}\n\n\t/**\n\t * Handles the keyboard navigation on \"keydown\" when a widget is currently selected and activates or deactivates\n\t * the fake caret for that widget, depending on the current value of the `widget-type-around` model\n\t * selection attribute and the direction of the pressed arrow key.\n\t *\n\t * @private\n\t * @param {Boolean} isForward `true` when the pressed arrow key was responsible for the forward model selection movement\n\t * as in {@link module:utils/keyboard~isForwardArrowKeyCode}.\n\t * @returns {Boolean} Returns `true` when the keypress was handled and no other keydown listener of the editor should\n\t * process the event any further. Returns `false` otherwise.\n\t */\n\t_handleArrowKeyPressOnSelectedWidget( isForward ) {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\t\tconst modelSelection = model.document.selection;\n\t\tconst typeAroundFakeCaretPosition = getTypeAroundFakeCaretPosition( modelSelection );\n\n\t\treturn model.change( writer => {\n\t\t\t// If the fake caret is displayed...\n\t\t\tif ( typeAroundFakeCaretPosition ) {\n\t\t\t\tconst isLeavingWidget = typeAroundFakeCaretPosition === ( isForward ? 'after' : 'before' );\n\n\t\t\t\t// If the keyboard arrow works against the value of the selection attribute...\n\t\t\t\t// then remove the selection attribute but prevent default DOM actions\n\t\t\t\t// and do not let the Widget plugin listener move the selection. This brings\n\t\t\t\t// the widget back to the state, for instance, like if was selected using the mouse.\n\t\t\t\t//\n\t\t\t\t// **Note**: If leaving the widget when the fake caret is active, then the default\n\t\t\t\t// Widget handler will change the selection and, in turn, this will automatically discard\n\t\t\t\t// the selection attribute.\n\t\t\t\tif ( !isLeavingWidget ) {\n\t\t\t\t\twriter.removeSelectionAttribute( TYPE_AROUND_SELECTION_ATTRIBUTE );\n\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// If the fake caret wasn't displayed, let's set it now according to the direction of the arrow\n\t\t\t// key press. This also means we cannot let the Widget plugin listener move the selection.\n\t\t\telse {\n\t\t\t\twriter.setSelectionAttribute( TYPE_AROUND_SELECTION_ATTRIBUTE, isForward ? 'after' : 'before' );\n\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\treturn false;\n\t\t} );\n\t}\n\n\t/**\n\t * Handles the keyboard navigation on \"keydown\" when **no** widget is selected but the selection is **directly** next\n\t * to one and upon the fake caret should become active for this widget upon arrow keypress\n\t * (AKA entering/selecting the widget).\n\t *\n\t * **Note**: This code mirrors the implementation from the widget plugin but also adds the selection attribute.\n\t * Unfortunately, there is no safe way to let the widget plugin do the selection part first and then just set the\n\t * selection attribute here in the widget type around plugin. This is why this code must duplicate some from the widget plugin.\n\t *\n\t * @private\n\t * @param {Boolean} isForward `true` when the pressed arrow key was responsible for the forward model selection movement\n\t * as in {@link module:utils/keyboard~isForwardArrowKeyCode}.\n\t * @returns {Boolean} Returns `true` when the keypress was handled and no other keydown listener of the editor should\n\t * process the event any further. Returns `false` otherwise.\n\t */\n\t_handleArrowKeyPressWhenSelectionNextToAWidget( isForward ) {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\t\tconst schema = model.schema;\n\t\tconst widgetPlugin = editor.plugins.get( 'Widget' );\n\n\t\t// This is the widget the selection is about to be set on.\n\t\tconst modelElementNextToSelection = widgetPlugin._getObjectElementNextToSelection( isForward );\n\t\tconst viewElementNextToSelection = editor.editing.mapper.toViewElement( modelElementNextToSelection );\n\n\t\tif ( isTypeAroundWidget( viewElementNextToSelection, modelElementNextToSelection, schema ) ) {\n\t\t\tmodel.change( writer => {\n\t\t\t\twidgetPlugin._setSelectionOverElement( modelElementNextToSelection );\n\t\t\t\twriter.setSelectionAttribute( TYPE_AROUND_SELECTION_ATTRIBUTE, isForward ? 'before' : 'after' );\n\t\t\t} );\n\n\t\t\t// The change() block above does the same job as the Widget plugin. The event can\n\t\t\t// be safely canceled.\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Registers a `mousedown` listener for the view document which intercepts events\n\t * coming from the widget type around UI, which happens when a user clicks one of the buttons\n\t * that insert a paragraph next to a widget.\n\t *\n\t * @private\n\t */\n\t_enableInsertingParagraphsOnButtonClick() {\n\t\tconst editor = this.editor;\n\t\tconst editingView = editor.editing.view;\n\n\t\tthis._listenToIfEnabled( editingView.document, 'mousedown', ( evt, domEventData ) => {\n\t\t\tconst button = getClosestTypeAroundDomButton( domEventData.domTarget );\n\n\t\t\tif ( !button ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst buttonPosition = getTypeAroundButtonPosition( button );\n\t\t\tconst widgetViewElement = getClosestWidgetViewElement( button, editingView.domConverter );\n\t\t\tconst widgetModelElement = editor.editing.mapper.toModelElement( widgetViewElement );\n\n\t\t\tthis._insertParagraph( widgetModelElement, buttonPosition );\n\n\t\t\tdomEventData.preventDefault();\n\t\t\tevt.stop();\n\t\t} );\n\t}\n\n\t/**\n\t * Creates the Enter key listener on the view document that allows the user to insert a paragraph\n\t * near the widget when either:\n\t *\n\t * * The fake caret was first activated using the arrow keys,\n\t * * The entire widget is selected in the model.\n\t *\n\t * In the first case, the new paragraph is inserted according to the `widget-type-around` selection\n\t * attribute (see {@link #_handleArrowKeyPress}).\n\t *\n\t * In the second case, the new paragraph is inserted based on whether a soft (Shift+Enter) keystroke\n\t * was pressed or not.\n\t *\n\t * @private\n\t */\n\t_enableInsertingParagraphsOnEnterKeypress() {\n\t\tconst editor = this.editor;\n\t\tconst selection = editor.model.document.selection;\n\t\tconst editingView = editor.editing.view;\n\n\t\tthis._listenToIfEnabled( editingView.document, 'enter', ( evt, domEventData ) => {\n\t\t\t// This event could be triggered from inside the widget but we are interested\n\t\t\t// only when the widget is selected itself.\n\t\t\tif ( evt.eventPhase != 'atTarget' ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst selectedModelElement = selection.getSelectedElement();\n\t\t\tconst selectedViewElement = editor.editing.mapper.toViewElement( selectedModelElement );\n\n\t\t\tconst schema = editor.model.schema;\n\t\t\tlet wasHandled;\n\n\t\t\t// First check if the widget is selected and there's a type around selection attribute associated\n\t\t\t// with the fake caret that would tell where to insert a new paragraph.\n\t\t\tif ( this._insertParagraphAccordingToFakeCaretPosition() ) {\n\t\t\t\twasHandled = true;\n\t\t\t}\n\t\t\t// Then, if there is no selection attribute associated with the fake caret, check if the widget\n\t\t\t// simply is selected and create a new paragraph according to the keystroke (Shift+)Enter.\n\t\t\telse if ( isTypeAroundWidget( selectedViewElement, selectedModelElement, schema ) ) {\n\t\t\t\tthis._insertParagraph( selectedModelElement, domEventData.isSoft ? 'before' : 'after' );\n\n\t\t\t\twasHandled = true;\n\t\t\t}\n\n\t\t\tif ( wasHandled ) {\n\t\t\t\tdomEventData.preventDefault();\n\t\t\t\tevt.stop();\n\t\t\t}\n\t\t}, { context: isWidget } );\n\t}\n\n\t/**\n\t * Similar to the {@link #_enableInsertingParagraphsOnEnterKeypress}, it allows the user\n\t * to insert a paragraph next to a widget when the fake caret was activated using arrow\n\t * keys but it responds to typing keystrokes instead of Enter.\n\t *\n\t * \"Typing keystrokes\" are keystrokes that insert new content into the document,\n\t * for instance, letters (\"a\") or numbers (\"4\"). The \"keydown\" listener enabled by this method\n\t * will insert a new paragraph according to the `widget-type-around` model selection attribute\n\t * as the user simply starts typing, which creates the impression that the fake caret\n\t * behaves like a real one rendered by the browser (AKA your text appears where the caret was).\n\t *\n\t * **Note**: At the moment this listener creates 2 undo steps: one for the `insertParagraph` command\n\t * and another one for actual typing. It is not a disaster but this may need to be fixed\n\t * sooner or later.\n\t *\n\t * Learn more in {@link module:typing/utils/injectunsafekeystrokeshandling}.\n\t *\n\t * @private\n\t */\n\t_enableInsertingParagraphsOnTypingKeystroke() {\n\t\tconst editor = this.editor;\n\t\tconst editingView = editor.editing.view;\n\t\tconst keyCodesHandledSomewhereElse = [\n\t\t\tkeyCodes.enter,\n\t\t\tkeyCodes.delete,\n\t\t\tkeyCodes.backspace\n\t\t];\n\n\t\t// Note: The priority must precede the default observers.\n\t\tthis._listenToIfEnabled( editingView.document, 'keydown', ( evt, domEventData ) => {\n\t\t\t// Don't handle enter/backspace/delete here. They are handled in dedicated listeners.\n\t\t\tif ( !keyCodesHandledSomewhereElse.includes( domEventData.keyCode ) && !isNonTypingKeystroke( domEventData ) ) {\n\t\t\t\tthis._insertParagraphAccordingToFakeCaretPosition();\n\t\t\t}\n\t\t}, { priority: 'high' } );\n\t}\n\n\t/**\n\t * It creates a \"delete\" event listener on the view document to handle cases when the Delete or Backspace\n\t * is pressed and the fake caret is currently active.\n\t *\n\t * The fake caret should create an illusion of a real browser caret so that when it appears before or after\n\t * a widget, pressing Delete or Backspace should remove a widget or delete the content\n\t * before or after a widget (depending on the content surrounding the widget).\n\t *\n\t * @private\n\t */\n\t_enableDeleteIntegration() {\n\t\tconst editor = this.editor;\n\t\tconst editingView = editor.editing.view;\n\t\tconst model = editor.model;\n\t\tconst schema = model.schema;\n\n\t\tthis._listenToIfEnabled( editingView.document, 'delete', ( evt, domEventData ) => {\n\t\t\t// This event could be triggered from inside the widget but we are interested\n\t\t\t// only when the widget is selected itself.\n\t\t\tif ( evt.eventPhase != 'atTarget' ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst typeAroundFakeCaretPosition = getTypeAroundFakeCaretPosition( model.document.selection );\n\n\t\t\t// This listener handles only these cases when the fake caret is active.\n\t\t\tif ( !typeAroundFakeCaretPosition ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst direction = domEventData.direction;\n\t\t\tconst selectedModelWidget = model.document.selection.getSelectedElement();\n\n\t\t\tconst isFakeCaretBefore = typeAroundFakeCaretPosition === 'before';\n\t\t\tconst isDeleteForward = direction == 'forward';\n\t\t\tconst shouldDeleteEntireWidget = isFakeCaretBefore === isDeleteForward;\n\n\t\t\tif ( shouldDeleteEntireWidget ) {\n\t\t\t\teditor.execute( 'delete', {\n\t\t\t\t\tselection: model.createSelection( selectedModelWidget, 'on' )\n\t\t\t\t} );\n\t\t\t} else {\n\t\t\t\tconst range = schema.getNearestSelectionRange(\n\t\t\t\t\tmodel.createPositionAt( selectedModelWidget, typeAroundFakeCaretPosition ),\n\t\t\t\t\tdirection\n\t\t\t\t);\n\n\t\t\t\t// If there is somewhere to move selection to, then there will be something to delete.\n\t\t\t\tif ( range ) {\n\t\t\t\t\t// If the range is NOT collapsed, then we know that the range contains an object (see getNearestSelectionRange() docs).\n\t\t\t\t\tif ( !range.isCollapsed ) {\n\t\t\t\t\t\tmodel.change( writer => {\n\t\t\t\t\t\t\twriter.setSelection( range );\n\t\t\t\t\t\t\teditor.execute( isDeleteForward ? 'deleteForward' : 'delete' );\n\t\t\t\t\t\t} );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconst probe = model.createSelection( range.start );\n\t\t\t\t\t\tmodel.modifySelection( probe, { direction } );\n\n\t\t\t\t\t\t// If the range is collapsed, let's see if a non-collapsed range exists that can could be deleted.\n\t\t\t\t\t\t// If such range exists, use the editor command because it it safe for collaboration (it merges where it can).\n\t\t\t\t\t\tif ( !probe.focus.isEqual( range.start ) ) {\n\t\t\t\t\t\t\tmodel.change( writer => {\n\t\t\t\t\t\t\t\twriter.setSelection( range );\n\t\t\t\t\t\t\t\teditor.execute( isDeleteForward ? 'deleteForward' : 'delete' );\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// If there is no non-collapsed range to be deleted then we are sure that there is an empty element\n\t\t\t\t\t\t// next to a widget that should be removed. \"delete\" and \"deleteForward\" commands cannot get rid of it\n\t\t\t\t\t\t// so calling Model#deleteContent here manually.\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tconst deepestEmptyRangeAncestor = getDeepestEmptyElementAncestor( schema, range.start.parent );\n\n\t\t\t\t\t\t\tmodel.deleteContent( model.createSelection( deepestEmptyRangeAncestor, 'on' ), {\n\t\t\t\t\t\t\t\tdoNotAutoparagraph: true\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// If some content was deleted, don't let the handler from the Widget plugin kick in.\n\t\t\t// If nothing was deleted, then the default handler will have nothing to do anyway.\n\t\t\tdomEventData.preventDefault();\n\t\t\tevt.stop();\n\t\t}, { context: isWidget } );\n\t}\n\n\t/**\n\t * Attaches the {@link module:engine/model/model~Model#event:insertContent} event listener that, for instance, allows the user to paste\n\t * content near a widget when the fake caret is first activated using the arrow keys.\n\t *\n\t * The content is inserted according to the `widget-type-around` selection attribute (see {@link #_handleArrowKeyPress}).\n\t *\n\t * @private\n\t */\n\t_enableInsertContentIntegration() {\n\t\tconst editor = this.editor;\n\t\tconst model = this.editor.model;\n\t\tconst documentSelection = model.document.selection;\n\n\t\tthis._listenToIfEnabled( editor.model, 'insertContent', ( evt, [ content, selectable ] ) => {\n\t\t\tif ( selectable && !selectable.is( 'documentSelection' ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst typeAroundFakeCaretPosition = getTypeAroundFakeCaretPosition( documentSelection );\n\n\t\t\tif ( !typeAroundFakeCaretPosition ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tevt.stop();\n\n\t\t\treturn model.change( writer => {\n\t\t\t\tconst selectedElement = documentSelection.getSelectedElement();\n\t\t\t\tconst position = model.createPositionAt( selectedElement, typeAroundFakeCaretPosition );\n\t\t\t\tconst selection = writer.createSelection( position );\n\n\t\t\t\tconst result = model.insertContent( content, selection );\n\n\t\t\t\twriter.setSelection( selection );\n\n\t\t\t\treturn result;\n\t\t\t} );\n\t\t}, { priority: 'high' } );\n\t}\n\n\t/**\n\t * Attaches the {@link module:engine/model/model~Model#event:deleteContent} event listener to block the event when the fake\n\t * caret is active.\n\t *\n\t * This is required for cases that trigger {@link module:engine/model/model~Model#deleteContent `model.deleteContent()`}\n\t * before calling {@link module:engine/model/model~Model#insertContent `model.insertContent()`} like, for instance,\n\t * plain text pasting.\n\t *\n\t * @private\n\t */\n\t_enableDeleteContentIntegration() {\n\t\tconst editor = this.editor;\n\t\tconst model = this.editor.model;\n\t\tconst documentSelection = model.document.selection;\n\n\t\tthis._listenToIfEnabled( editor.model, 'deleteContent', ( evt, [ selection ] ) => {\n\t\t\tif ( selection && !selection.is( 'documentSelection' ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst typeAroundFakeCaretPosition = getTypeAroundFakeCaretPosition( documentSelection );\n\n\t\t\t// Disable removing the selection content while pasting plain text.\n\t\t\tif ( typeAroundFakeCaretPosition ) {\n\t\t\t\tevt.stop();\n\t\t\t}\n\t\t}, { priority: 'high' } );\n\t}\n}\n\n// Injects the type around UI into a view widget instance.\n//\n// @param {module:engine/view/downcastwriter~DowncastWriter} viewWriter\n// @param {Object.} buttonTitles\n// @param {module:engine/view/element~Element} widgetViewElement\nfunction injectUIIntoWidget( viewWriter, buttonTitles, widgetViewElement ) {\n\tconst typeAroundWrapper = viewWriter.createUIElement( 'div', {\n\t\tclass: 'ck ck-reset_all ck-widget__type-around'\n\t}, function( domDocument ) {\n\t\tconst wrapperDomElement = this.toDomElement( domDocument );\n\n\t\tinjectButtons( wrapperDomElement, buttonTitles );\n\t\tinjectFakeCaret( wrapperDomElement );\n\n\t\treturn wrapperDomElement;\n\t} );\n\n\t// Inject the type around wrapper into the widget's wrapper.\n\tviewWriter.insert( viewWriter.createPositionAt( widgetViewElement, 'end' ), typeAroundWrapper );\n}\n\n// FYI: Not using the IconView class because each instance would need to be destroyed to avoid memory leaks\n// and it's pretty hard to figure out when a view (widget) is gone for good so it's cheaper to use raw\n// here.\n//\n// @param {HTMLElement} wrapperDomElement\n// @param {Object.} buttonTitles\nfunction injectButtons( wrapperDomElement, buttonTitles ) {\n\tfor ( const position of POSSIBLE_INSERTION_POSITIONS ) {\n\t\tconst buttonTemplate = new Template( {\n\t\t\ttag: 'div',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-widget__type-around__button',\n\t\t\t\t\t`ck-widget__type-around__button_${ position }`\n\t\t\t\t],\n\t\t\t\ttitle: buttonTitles[ position ]\n\t\t\t},\n\t\t\tchildren: [\n\t\t\t\twrapperDomElement.ownerDocument.importNode( RETURN_ARROW_ICON_ELEMENT, true )\n\t\t\t]\n\t\t} );\n\n\t\twrapperDomElement.appendChild( buttonTemplate.render() );\n\t}\n}\n\n// @param {HTMLElement} wrapperDomElement\nfunction injectFakeCaret( wrapperDomElement ) {\n\tconst caretTemplate = new Template( {\n\t\ttag: 'div',\n\t\tattributes: {\n\t\t\tclass: [\n\t\t\t\t'ck',\n\t\t\t\t'ck-widget__type-around__fake-caret'\n\t\t\t]\n\t\t}\n\t} );\n\n\twrapperDomElement.appendChild( caretTemplate.render() );\n}\n\n// Returns the ancestor of an element closest to the root which is empty. For instance,\n// for ``:\n//\n//\t\tabc\n//\n// it returns ``.\n//\n// @param {module:engine/model/schema~Schema} schema\n// @param {module:engine/model/element~Element} element\n// @returns {module:engine/model/element~Element|null}\nfunction getDeepestEmptyElementAncestor( schema, element ) {\n\tlet deepestEmptyAncestor = element;\n\n\tfor ( const ancestor of element.getAncestors( { parentFirst: true } ) ) {\n\t\tif ( ancestor.childCount > 1 || schema.isLimit( ancestor ) ) {\n\t\t\tbreak;\n\t\t}\n\n\t\tdeepestEmptyAncestor = ancestor;\n\t}\n\n\treturn deepestEmptyAncestor;\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 widget/widgettypearound/utils\n */\n\nimport { isWidget } from '../utils';\n\n/**\n * The name of the type around model selection attribute responsible for\n * displaying a fake caret next to a selected widget.\n */\nexport const TYPE_AROUND_SELECTION_ATTRIBUTE = 'widget-type-around';\n\n/**\n * Checks if an element is a widget that qualifies to get the widget type around UI.\n *\n * @param {module:engine/view/element~Element} viewElement\n * @param {module:engine/model/element~Element} modelElement\n * @param {module:engine/model/schema~Schema} schema\n * @returns {Boolean}\n */\nexport function isTypeAroundWidget( viewElement, modelElement, schema ) {\n\treturn viewElement && isWidget( viewElement ) && !schema.isInline( modelElement );\n}\n\n/**\n * For the passed HTML element, this helper finds the closest widget type around button ancestor.\n *\n * @param {HTMLElement} domElement\n * @returns {HTMLElement|null}\n */\nexport function getClosestTypeAroundDomButton( domElement ) {\n\treturn domElement.closest( '.ck-widget__type-around__button' );\n}\n\n/**\n * For the passed widget type around button element, this helper determines at which position\n * the paragraph would be inserted into the content if, for instance, the button was\n * clicked by the user.\n *\n * @param {HTMLElement} domElement\n * @returns {'before'|'after'} The position of the button.\n */\nexport function getTypeAroundButtonPosition( domElement ) {\n\treturn domElement.classList.contains( 'ck-widget__type-around__button_before' ) ? 'before' : 'after';\n}\n\n/**\n * For the passed HTML element, this helper returns the closest view widget ancestor.\n *\n * @param {HTMLElement} domElement\n * @param {module:engine/view/domconverter~DomConverter} domConverter\n * @returns {module:engine/view/element~Element}\n */\nexport function getClosestWidgetViewElement( domElement, domConverter ) {\n\tconst widgetDomElement = domElement.closest( '.ck-widget' );\n\n\treturn domConverter.mapDomToView( widgetDomElement );\n}\n\n/**\n * For the passed selection instance, it returns the position of the fake caret displayed next to a widget.\n *\n * **Note**: If the fake caret is not currently displayed, `null` is returned.\n *\n * @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection\n * @returns {'before'|'after'|null} The position of the fake caret or `null` when none is present.\n */\nexport function getTypeAroundFakeCaretPosition( selection ) {\n\treturn selection.getAttribute( TYPE_AROUND_SELECTION_ATTRIBUTE );\n}\n"],"sourceRoot":""}