{"version":3,"sources":["webpack:///./node_modules/@ckeditor/ckeditor5-ui/src/toolbar/enabletoolbarkeyboardfocus.js","webpack:///./node_modules/@ckeditor/ckeditor5-ui/src/toolbar/toolbarseparatorview.js","webpack:///./node_modules/@ckeditor/ckeditor5-ui/src/panel/balloon/contextualballoon.js","webpack:///./node_modules/@ckeditor/ckeditor5-ui/src/toolbar/toolbarlinebreakview.js","webpack:///./node_modules/@ckeditor/ckeditor5-ui/src/toolbar/toolbarview.js","webpack:///./node_modules/@ckeditor/ckeditor5-ui/src/toolbar/normalizetoolbarconfig.js","webpack:///./node_modules/@ckeditor/ckeditor5-ui/src/panel/sticky/stickypanelview.js","webpack:///./node_modules/@ckeditor/ckeditor5-ui/src/tooltip/tooltipview.js","webpack:///./node_modules/@ckeditor/ckeditor5-ui/src/notification/notification.js","webpack:///./node_modules/@ckeditor/ckeditor5-ui/src/toolbar/block/blockbuttonview.js","webpack:///./node_modules/@ckeditor/ckeditor5-ui/src/toolbar/block/blocktoolbar.js","webpack:///./node_modules/@ckeditor/ckeditor5-ui/src/toolbar/balloon/balloontoolbar.js","webpack:///./node_modules/@ckeditor/ckeditor5-ui/src/template.js","webpack:///./node_modules/@ckeditor/ckeditor5-ui/src/panel/balloon/balloonpanelview.js"],"names":["enableToolbarKeyboardFocus","origin","originKeystrokeHandler","originFocusTracker","toolbar","beforeFocus","afterBlur","add","element","set","data","cancel","isFocused","focusTracker","focus","keystrokes","ToolbarSeparatorView","locale","setTemplate","tag","attributes","class","View","toPx","toUnit","ContextualBalloon","editor","positionLimiter","view","editing","viewDocument","document","editableElement","selection","domConverter","mapViewToDom","root","BalloonPanelView","ui","body","_viewToStack","Map","_idToStack","_rotatorView","_createRotatorView","_fakePanelsView","_createFakePanelsView","Array","from","this","keys","includes","hasView","CKEditorError","stackId","has","get","_numberOfStacks","size","_visibleStack","singleViewMode","showStack","stack","_showView","_singleViewMode","visibleView","_showNextStack","hide","hideView","values","delete","_getStackId","position","pin","_getBalloonPosition","updatePosition","id","visibleStack","pop","entry","entries","find","stacks","nextIndex","indexOf","length","RotatorView","t","content","bind","to","value","isSingleViewMode","on","priority","numberOfStacks","current","buttonNextView","buttonPrevView","_showPrevStack","FakePanelsView","number","showPanels","Math","min","listenTo","balloonClassName","withArrow","showView","limiter","Object","assign","Plugin","bindTemplate","FocusTracker","_createButtonView","prevIcon","nextIcon","createCollection","children","text","clear","label","icon","ButtonView","tooltip","balloonPanelView","_balloonPanelView","style","top","left","width","height","evt","name","next","prev","_addPanels","_removePanels","registerChild","last","remove","deregisterChild","destroy","numberOfPanels","Rect","ToolbarLineBreakView","ToolbarView","options","items","KeystrokeHandler","itemsView","ItemsView","focusables","_focusCycler","FocusCycler","keystrokeHandler","actions","focusPrevious","focusNext","classes","if","shouldGroupWhenFull","isFloating","push","role","maxWidth","mousedown","preventDefault","_behavior","DynamicGrouping","StaticLayout","item","render","focusFirst","focusLast","itemsOrConfig","factory","config","normalizeToolbarConfig","itemsToClean","filter","idx","removeItems","logWarning","itemsToAdd","_cleanSeparators","map","create","addMany","nonSeparatorPredicate","count","firstCommandItem","findIndex","lastCommandItem","slice","reverse","isDuplicated","bindTo","using","extendTemplate","viewChildren","viewFocusables","viewItemsView","viewFocusTracker","viewLocale","ungroupedItems","groupedItems","groupedItemsDropdown","_createGroupedItemsDropdown","resizeObserver","cachedPadding","shouldUpdateGroupingOnNextResize","_updateFocusCycleableItems","changeData","index","removed","removedItem","currentIndex","added","addedItem","_updateGrouping","viewElement","_enableGroupingOnResize","_enableGroupingOnMaxWidthChange","ownerDocument","contains","offsetParent","wereItemsGrouped","initialGroupedItemsCount","_areItemsOverflowing","_groupLastItem","_ungroupFirstItem","fire","previousWidth","ResizeObserver","contentRect","first","dropdown","createDropdown","panelPosition","uiLanguageDirection","addToolbarToDropdown","buttonView","tooltipPosition","icons","threeVerticalDots","toolbarView","lastChildRect","lastChild","toolbarRect","computedStyle","global","window","getComputedStyle","paddingProperty","Number","parseInt","right","isArray","TooltipView","trim","Notification","alert","message","_showNotification","type","namespace","title","event","ContextPlugin","BlockButtonView","isVisible","isToggleable","val","getBalloonPositions","isBackward","defaultPositions","northWestArrowSouth","northWestArrowSouthWest","northWestArrowSouthEast","northWestArrowSouthMiddleEast","northWestArrowSouthMiddleWest","southWestArrowNorth","southWestArrowNorthWest","southWestArrowNorthEast","southWestArrowNorthMiddleWest","southWestArrowNorthMiddleEast","southEastArrowNorth","southEastArrowNorthEast","southEastArrowNorthWest","southEastArrowNorthMiddleEast","southEastArrowNorthMiddleWest","northEastArrowSouth","northEastArrowSouthEast","northEastArrowSouthWest","northEastArrowSouthMiddleEast","northEastArrowSouthMiddleWest","selectionContainsOnlyMultipleSelectables","schema","rangeCount","getRanges","every","range","getContainedElement","isSelectable","xhtmlNs","Template","def","normalize","clone","_isRendered","_revertData","node","_renderNode","intoFragment","getEmptyRevertData","isApplying","revertData","_revertTemplateFromNode","search","child","isView","isTemplate","isInvalid","_renderText","_renderElement","createElementNS","ns","_renderAttributes","_renderElementChildren","_setUpListeners","textContent","createTextNode","hasTemplateBinding","_bindToObservable","updater","getTextUpdater","join","attrName","attrValue","domAttrValue","attrNs","getAttribute","isObject","valueToBind","shouldExtend","unshift","getAttributeUpdater","_renderStyleAttribute","reduce","concat","arrayValueReducer","isFalsy","setAttributeNS","styles","styleName","styleValue","getStyleUpdater","container","createDocumentFragment","childIndex","isViewCollection","setParent","appendChild","isRendered","isNode","childRevertData","childNodes","eventListeners","key","revertBindings","schemaItem","split","domEvtName","domSelector","activateDomEventListener","bindings","syncValueSchemaValue","observable","templateBinding","activateAttributeListener","binding","revertBinding","removeAttribute","setAttribute","i","emitter","eventNameOrFunctionOrAttribute","callback","TemplateToBinding","eventNameOrFunction","attribute","valueIfTrue","TemplateIfBinding","template","mix","EmitterMixin","TemplateBinding","stopListening","domEvt","target","matches","some","getValueSchemaValue","getValue","el","removeAttributeNS","cloneDeepWith","normalizePlainTextDefinition","normalizeTextDefinition","normalizeListeners","normalizeAttributes","a","toArray","arrayify","listeners","l","obj","cur","extendObjectValueArray","ext","childDef","ViewCollection","defaultLimiterElement","show","positionOptions","positions","southArrowNorth","southArrowNorthMiddleWest","southArrowNorthMiddleEast","southArrowNorthWest","southArrowNorthEast","northArrowSouth","northArrowSouthMiddleWest","northArrowSouthMiddleEast","northArrowSouthWest","northArrowSouthEast","fitInViewport","optimalPosition","_getOptimalPosition","unpin","_pinWhenIsVisibleCallback","_startPinning","_stopPinning","attachTo","targetElement","getDomElement","limiterElement","scrollTarget","isWithinScrollTarget","isLimiterWithinScrollTarget","useCapture","object","isElement","isRange","commonAncestorContainer","getNorthTop","targetRect","balloonRect","arrowVerticalOffset","getSouthTop","bottom","arrowHorizontalOffset","getOptimalPosition"],"mappings":"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","file":"js/chunk-vendors~51de861d.d1c2c751.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 ui/toolbar/enabletoolbarkeyboardfocus\n */\n\n/**\n * Enables focus/blur toolbar navigation using `Alt+F10` and `Esc` keystrokes.\n *\n * @param {Object} options Options of the utility.\n * @param {*} options.origin A view to which the focus will return when `Esc` is pressed and\n * `options.toolbar` is focused.\n * @param {module:utils/keystrokehandler~KeystrokeHandler} options.originKeystrokeHandler A keystroke\n * handler to register `Alt+F10` keystroke.\n * @param {module:utils/focustracker~FocusTracker} options.originFocusTracker A focus tracker\n * for `options.origin`.\n * @param {module:ui/toolbar/toolbarview~ToolbarView} options.toolbar A toolbar which is to gain\n * focus when `Alt+F10` is pressed.\n * @param {Function} [options.beforeFocus] A callback executed before the `options.toolbar` gains focus\n * upon the `Alt+F10` keystroke.\n * @param {Function} [options.afterBlur] A callback executed after `options.toolbar` loses focus upon\n * `Esc` keystroke but before the focus goes back to `options.origin`.\n */\nexport default function enableToolbarKeyboardFocus( {\n\torigin,\n\toriginKeystrokeHandler,\n\toriginFocusTracker,\n\ttoolbar,\n\tbeforeFocus,\n\tafterBlur\n} ) {\n\t// Because toolbar items can get focus, the overall state of the toolbar must\n\t// also be tracked.\n\toriginFocusTracker.add( toolbar.element );\n\n\t// Focus the toolbar on the keystroke, if not already focused.\n\toriginKeystrokeHandler.set( 'Alt+F10', ( data, cancel ) => {\n\t\tif ( originFocusTracker.isFocused && !toolbar.focusTracker.isFocused ) {\n\t\t\tif ( beforeFocus ) {\n\t\t\t\tbeforeFocus();\n\t\t\t}\n\n\t\t\ttoolbar.focus();\n\n\t\t\tcancel();\n\t\t}\n\t} );\n\n\t// Blur the toolbar and bring the focus back to origin.\n\ttoolbar.keystrokes.set( 'Esc', ( data, cancel ) => {\n\t\tif ( toolbar.focusTracker.isFocused ) {\n\t\t\torigin.focus();\n\n\t\t\tif ( afterBlur ) {\n\t\t\t\tafterBlur();\n\t\t\t}\n\n\t\t\tcancel();\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 ui/toolbar/toolbarseparatorview\n */\n\nimport View from '../view';\n\n/**\n * The toolbar separator view class.\n *\n * @extends module:ui/view~View\n */\nexport default class ToolbarSeparatorView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'span',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-toolbar__separator'\n\t\t\t\t]\n\t\t\t}\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 ui/panel/balloon/contextualballoon\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport BalloonPanelView from './balloonpanelview';\nimport View from '../../view';\nimport ButtonView from '../../button/buttonview';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker';\nimport toUnit from '@ckeditor/ckeditor5-utils/src/dom/tounit';\nimport Rect from '@ckeditor/ckeditor5-utils/src/dom/rect';\n\nimport prevIcon from '../../../theme/icons/previous-arrow.svg';\nimport nextIcon from '../../../theme/icons/next-arrow.svg';\n\nimport '../../../theme/components/panel/balloonrotator.css';\nimport '../../../theme/components/panel/fakepanel.css';\n\nconst toPx = toUnit( 'px' );\n\n/**\n * Provides the common contextual balloon for the editor.\n *\n * The role of this plugin is to unify the contextual balloons logic, simplify views management and help\n * avoid the unnecessary complexity of handling multiple {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView}\n * instances in the editor.\n *\n * This plugin allows for creating single or multiple panel stacks.\n *\n * Each stack may have multiple views, with the one on the top being visible. When the visible view is removed from the stack,\n * the previous view becomes visible.\n *\n * It might be useful to implement nested navigation in a balloon. For instance, a toolbar view may contain a link button.\n * When you click it, a link view (which lets you set the URL) is created and put on top of the toolbar view, so the link panel\n * is displayed. When you finish editing the link and close (remove) the link view, the toolbar view is visible again.\n *\n * However, there are cases when there are multiple independent balloons to be displayed, for instance, if the selection\n * is inside two inline comments at the same time. For such cases, you can create two independent panel stacks.\n * The contextual balloon plugin will create a navigation bar to let the users switch between these panel stacks using the \"Next\"\n * and \"Previous\" buttons.\n *\n * If there are no views in the current stack, the balloon panel will try to switch to the next stack. If there are no\n * panels in any stack, the balloon panel will be hidden.\n *\n * **Note**: To force the balloon panel to show only one view, even if there are other stacks, use the `singleViewMode=true` option\n * when {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon#add adding} a view to a panel.\n *\n * From the implementation point of view, the contextual ballon plugin is reusing a single\n * {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView} instance to display multiple contextual balloon\n * panels in the editor. It also creates a special {@link module:ui/panel/balloon/contextualballoon~RotatorView rotator view},\n * used to manage multiple panel stacks. Rotator view is a child of the balloon panel view and the parent of the specific\n * view you want to display. If there is more than one panel stack to be displayed, the rotator view will add a\n * navigation bar. If there is only one stack, the rotator view is transparent (it does not add any UI elements).\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ContextualBalloon extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'ContextualBalloon';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * The {@link module:utils/dom/position~Options#limiter position limiter}\n\t\t * for the {@link #view balloon}, used when no `limiter` has been passed into {@link #add}\n\t\t * or {@link #updatePosition}.\n\t\t *\n\t\t * By default, a function that obtains the farthest DOM\n\t\t * {@link module:engine/view/rooteditableelement~RootEditableElement}\n\t\t * of the {@link module:engine/view/document~Document#selection}.\n\t\t *\n\t\t * @member {module:utils/dom/position~Options#limiter} #positionLimiter\n\t\t */\n\t\tthis.positionLimiter = () => {\n\t\t\tconst view = this.editor.editing.view;\n\t\t\tconst viewDocument = view.document;\n\t\t\tconst editableElement = viewDocument.selection.editableElement;\n\n\t\t\tif ( editableElement ) {\n\t\t\t\treturn view.domConverter.mapViewToDom( editableElement.root );\n\t\t\t}\n\n\t\t\treturn null;\n\t\t};\n\n\t\t/**\n\t\t * The currently visible view or `null` when there are no views in any stack.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {module:ui/view~View|null} #visibleView\n\t\t */\n\t\tthis.set( 'visibleView', null );\n\n\t\t/**\n\t\t * The common balloon panel view.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/panel/balloon/balloonpanelview~BalloonPanelView} #view\n\t\t */\n\t\tthis.view = new BalloonPanelView( editor.locale );\n\t\teditor.ui.view.body.add( this.view );\n\t\teditor.ui.focusTracker.add( this.view.element );\n\n\t\t/**\n\t\t * The map of views and their stacks.\n\t\t *\n\t\t * @private\n\t\t * @type {Map.}\n\t\t */\n\t\tthis._viewToStack = new Map();\n\n\t\t/**\n\t\t * The map of IDs and stacks.\n\t\t *\n\t\t * @private\n\t\t * @type {Map.}\n\t\t */\n\t\tthis._idToStack = new Map();\n\n\t\t/**\n\t\t * A total number of all stacks in the balloon.\n\t\t *\n\t\t * @private\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Number} #_numberOfStacks\n\t\t */\n\t\tthis.set( '_numberOfStacks', 0 );\n\n\t\t/**\n\t\t * A flag that controls the single view mode.\n\t\t *\n\t\t * @private\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Boolean} #_singleViewMode\n\t\t */\n\t\tthis.set( '_singleViewMode', false );\n\n\t\t/**\n\t\t * Rotator view embedded in the contextual balloon.\n\t\t * Displays the currently visible view in the balloon and provides navigation for switching stacks.\n\t\t *\n\t\t * @private\n\t\t * @type {module:ui/panel/balloon/contextualballoon~RotatorView}\n\t\t */\n\t\tthis._rotatorView = this._createRotatorView();\n\n\t\t/**\n\t\t * Displays fake panels under the balloon panel view when multiple stacks are added to the balloon.\n\t\t *\n\t\t * @private\n\t\t * @type {module:ui/view~View}\n\t\t */\n\t\tthis._fakePanelsView = this._createFakePanelsView();\n\t}\n\n\t/**\n\t * Returns `true` when the given view is in one of the stacks. Otherwise returns `false`.\n\t *\n\t * @param {module:ui/view~View} view\n\t * @returns {Boolean}\n\t */\n\thasView( view ) {\n\t\treturn Array.from( this._viewToStack.keys() ).includes( view );\n\t}\n\n\t/**\n\t * Adds a new view to the stack and makes it visible if the current stack is visible\n\t * or it is the first view in the balloon.\n\t *\n\t * @param {Object} data The configuration of the view.\n\t * @param {String} [data.stackId='main'] The ID of the stack that the view is added to.\n\t * @param {module:ui/view~View} [data.view] The content of the balloon.\n\t * @param {module:utils/dom/position~Options} [data.position] Positioning options.\n\t * @param {String} [data.balloonClassName] An additional CSS class added to the {@link #view balloon} when visible.\n\t * @param {Boolean} [data.withArrow=true] Whether the {@link #view balloon} should be rendered with an arrow.\n\t * @param {Boolean} [data.singleViewMode=false] Whether the view should be the only visible view even if other stacks were added.\n\t */\n\tadd( data ) {\n\t\tif ( this.hasView( data.view ) ) {\n\t\t\t/**\n\t\t\t * Trying to add configuration of the same view more than once.\n\t\t\t *\n\t\t\t * @error contextualballoon-add-view-exist\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'contextualballoon-add-view-exist',\n\t\t\t\t[ this, data ]\n\t\t\t);\n\t\t}\n\n\t\tconst stackId = data.stackId || 'main';\n\n\t\t// If new stack is added, creates it and show view from this stack.\n\t\tif ( !this._idToStack.has( stackId ) ) {\n\t\t\tthis._idToStack.set( stackId, new Map( [ [ data.view, data ] ] ) );\n\t\t\tthis._viewToStack.set( data.view, this._idToStack.get( stackId ) );\n\t\t\tthis._numberOfStacks = this._idToStack.size;\n\n\t\t\tif ( !this._visibleStack || data.singleViewMode ) {\n\t\t\t\tthis.showStack( stackId );\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\tconst stack = this._idToStack.get( stackId );\n\n\t\tif ( data.singleViewMode ) {\n\t\t\tthis.showStack( stackId );\n\t\t}\n\n\t\t// Add new view to the stack.\n\t\tstack.set( data.view, data );\n\t\tthis._viewToStack.set( data.view, stack );\n\n\t\t// And display it if is added to the currently visible stack.\n\t\tif ( stack === this._visibleStack ) {\n\t\t\tthis._showView( data );\n\t\t}\n\t}\n\n\t/**\n\t * Removes the given view from the stack. If the removed view was visible,\n\t * the view preceding it in the stack will become visible instead.\n\t * When there is no view in the stack, the next stack will be displayed.\n\t * When there are no more stacks, the balloon will hide.\n\t *\n\t * @param {module:ui/view~View} view A view to be removed from the balloon.\n\t */\n\tremove( view ) {\n\t\tif ( !this.hasView( view ) ) {\n\t\t\t/**\n\t\t\t * Trying to remove the configuration of the view not defined in the stack.\n\t\t\t *\n\t\t\t * @error contextualballoon-remove-view-not-exist\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'contextualballoon-remove-view-not-exist',\n\t\t\t\t[ this, view ]\n\t\t\t);\n\t\t}\n\n\t\tconst stack = this._viewToStack.get( view );\n\n\t\tif ( this._singleViewMode && this.visibleView === view ) {\n\t\t\tthis._singleViewMode = false;\n\t\t}\n\n\t\t// When visible view will be removed we need to show a preceding view or next stack\n\t\t// if a view is the only view in the stack.\n\t\tif ( this.visibleView === view ) {\n\t\t\tif ( stack.size === 1 ) {\n\t\t\t\tif ( this._idToStack.size > 1 ) {\n\t\t\t\t\tthis._showNextStack();\n\t\t\t\t} else {\n\t\t\t\t\tthis.view.hide();\n\t\t\t\t\tthis.visibleView = null;\n\t\t\t\t\tthis._rotatorView.hideView();\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis._showView( Array.from( stack.values() )[ stack.size - 2 ] );\n\t\t\t}\n\t\t}\n\n\t\tif ( stack.size === 1 ) {\n\t\t\tthis._idToStack.delete( this._getStackId( stack ) );\n\t\t\tthis._numberOfStacks = this._idToStack.size;\n\t\t} else {\n\t\t\tstack.delete( view );\n\t\t}\n\n\t\tthis._viewToStack.delete( view );\n\t}\n\n\t/**\n\t * Updates the position of the balloon using the position data of the first visible view in the stack.\n\t * When new position data is given, the position data of the currently visible view will be updated.\n\t *\n\t * @param {module:utils/dom/position~Options} [position] position options.\n\t */\n\tupdatePosition( position ) {\n\t\tif ( position ) {\n\t\t\tthis._visibleStack.get( this.visibleView ).position = position;\n\t\t}\n\n\t\tthis.view.pin( this._getBalloonPosition() );\n\t\tthis._fakePanelsView.updatePosition();\n\t}\n\n\t/**\n\t * Shows the last view from the stack of a given ID.\n\t *\n\t * @param {String} id\n\t */\n\tshowStack( id ) {\n\t\tthis.visibleStack = id;\n\t\tconst stack = this._idToStack.get( id );\n\n\t\tif ( !stack ) {\n\t\t\t/**\n\t\t\t * Trying to show a stack that does not exist.\n\t\t\t *\n\t\t\t * @error contextualballoon-showstack-stack-not-exist\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'contextualballoon-showstack-stack-not-exist',\n\t\t\t\tthis\n\t\t\t);\n\t\t}\n\n\t\tif ( this._visibleStack === stack ) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._showView( Array.from( stack.values() ).pop() );\n\t}\n\n\t/**\n\t * Returns the stack of the currently visible view.\n\t *\n\t * @private\n\t * @type {Set}\n\t */\n\tget _visibleStack() {\n\t\treturn this._viewToStack.get( this.visibleView );\n\t}\n\n\t/**\n\t * Returns the ID of the given stack.\n\t *\n\t * @private\n\t * @param {Set} stack\n\t * @returns {String}\n\t */\n\t_getStackId( stack ) {\n\t\tconst entry = Array.from( this._idToStack.entries() ).find( entry => entry[ 1 ] === stack );\n\n\t\treturn entry[ 0 ];\n\t}\n\n\t/**\n\t * Shows the last view from the next stack.\n\t *\n\t * @private\n\t */\n\t_showNextStack() {\n\t\tconst stacks = Array.from( this._idToStack.values() );\n\n\t\tlet nextIndex = stacks.indexOf( this._visibleStack ) + 1;\n\n\t\tif ( !stacks[ nextIndex ] ) {\n\t\t\tnextIndex = 0;\n\t\t}\n\n\t\tthis.showStack( this._getStackId( stacks[ nextIndex ] ) );\n\t}\n\n\t/**\n\t * Shows the last view from the previous stack.\n\t *\n\t * @private\n\t */\n\t_showPrevStack() {\n\t\tconst stacks = Array.from( this._idToStack.values() );\n\n\t\tlet nextIndex = stacks.indexOf( this._visibleStack ) - 1;\n\n\t\tif ( !stacks[ nextIndex ] ) {\n\t\t\tnextIndex = stacks.length - 1;\n\t\t}\n\n\t\tthis.showStack( this._getStackId( stacks[ nextIndex ] ) );\n\t}\n\n\t/**\n\t * Creates a rotator view.\n\t *\n\t * @private\n\t * @returns {module:ui/panel/balloon/contextualballoon~RotatorView}\n\t */\n\t_createRotatorView() {\n\t\tconst view = new RotatorView( this.editor.locale );\n\t\tconst t = this.editor.locale.t;\n\n\t\tthis.view.content.add( view );\n\n\t\t// Hide navigation when there is only a one stack & not in single view mode.\n\t\tview.bind( 'isNavigationVisible' ).to( this, '_numberOfStacks', this, '_singleViewMode', ( value, isSingleViewMode ) => {\n\t\t\treturn !isSingleViewMode && value > 1;\n\t\t} );\n\n\t\t// Update balloon position after toggling navigation.\n\t\tview.on( 'change:isNavigationVisible', () => ( this.updatePosition() ), { priority: 'low' } );\n\n\t\t// Update stacks counter value.\n\t\tview.bind( 'counter' ).to( this, 'visibleView', this, '_numberOfStacks', ( visibleView, numberOfStacks ) => {\n\t\t\tif ( numberOfStacks < 2 ) {\n\t\t\t\treturn '';\n\t\t\t}\n\n\t\t\tconst current = Array.from( this._idToStack.values() ).indexOf( this._visibleStack ) + 1;\n\n\t\t\treturn t( '%0 of %1', [ current, numberOfStacks ] );\n\t\t} );\n\n\t\tview.buttonNextView.on( 'execute', () => {\n\t\t\t// When current view has a focus then move focus to the editable before removing it,\n\t\t\t// otherwise editor will lost focus.\n\t\t\tif ( view.focusTracker.isFocused ) {\n\t\t\t\tthis.editor.editing.view.focus();\n\t\t\t}\n\n\t\t\tthis._showNextStack();\n\t\t} );\n\n\t\tview.buttonPrevView.on( 'execute', () => {\n\t\t\t// When current view has a focus then move focus to the editable before removing it,\n\t\t\t// otherwise editor will lost focus.\n\t\t\tif ( view.focusTracker.isFocused ) {\n\t\t\t\tthis.editor.editing.view.focus();\n\t\t\t}\n\n\t\t\tthis._showPrevStack();\n\t\t} );\n\n\t\treturn view;\n\t}\n\n\t/**\n\t * @private\n\t * @returns {module:ui/view~View}\n\t */\n\t_createFakePanelsView() {\n\t\tconst view = new FakePanelsView( this.editor.locale, this.view );\n\n\t\tview.bind( 'numberOfPanels' ).to( this, '_numberOfStacks', this, '_singleViewMode', ( number, isSingleViewMode ) => {\n\t\t\tconst showPanels = !isSingleViewMode && number >= 2;\n\n\t\t\treturn showPanels ? Math.min( number - 1, 2 ) : 0;\n\t\t} );\n\n\t\tview.listenTo( this.view, 'change:top', () => view.updatePosition() );\n\t\tview.listenTo( this.view, 'change:left', () => view.updatePosition() );\n\n\t\tthis.editor.ui.view.body.add( view );\n\n\t\treturn view;\n\t}\n\n\t/**\n\t * Sets the view as the content of the balloon and attaches the balloon using position\n\t * options of the first view.\n\t *\n\t * @private\n\t * @param {Object} data Configuration.\n\t * @param {module:ui/view~View} [data.view] The view to show in the balloon.\n\t * @param {String} [data.balloonClassName=''] Additional class name which will be added to the {@link #view balloon}.\n\t * @param {Boolean} [data.withArrow=true] Whether the {@link #view balloon} should be rendered with an arrow.\n\t */\n\t_showView( { view, balloonClassName = '', withArrow = true, singleViewMode = false } ) {\n\t\tthis.view.class = balloonClassName;\n\t\tthis.view.withArrow = withArrow;\n\n\t\tthis._rotatorView.showView( view );\n\t\tthis.visibleView = view;\n\t\tthis.view.pin( this._getBalloonPosition() );\n\t\tthis._fakePanelsView.updatePosition();\n\n\t\tif ( singleViewMode ) {\n\t\t\tthis._singleViewMode = true;\n\t\t}\n\t}\n\n\t/**\n\t * Returns position options of the last view in the stack.\n\t * This keeps the balloon in the same position when the view is changed.\n\t *\n\t * @private\n\t * @returns {module:utils/dom/position~Options}\n\t */\n\t_getBalloonPosition() {\n\t\tlet position = Array.from( this._visibleStack.values() ).pop().position;\n\n\t\t// Use the default limiter if none has been specified.\n\t\tif ( position && !position.limiter ) {\n\t\t\t// Don't modify the original options object.\n\t\t\tposition = Object.assign( {}, position, {\n\t\t\t\tlimiter: this.positionLimiter\n\t\t\t} );\n\t\t}\n\n\t\treturn position;\n\t}\n}\n\n/**\n * Rotator view is a helper class for the {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon ContextualBalloon}.\n * It is used for displaying the last view from the current stack and providing navigation buttons for switching stacks.\n * See the {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon ContextualBalloon} documentation to learn more.\n *\n * @extends module:ui/view~View\n */\nclass RotatorView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\tconst t = locale.t;\n\t\tconst bind = this.bindTemplate;\n\n\t\t/**\n\t\t * Defines whether navigation is visible or not.\n\t\t *\n\t\t * @member {Boolean} #isNavigationVisible\n\t\t */\n\t\tthis.set( 'isNavigationVisible', true );\n\n\t\t/**\n\t\t * Used for checking if a view is focused or not.\n\t\t *\n\t\t * @type {module:utils/focustracker~FocusTracker}\n\t\t */\n\t\tthis.focusTracker = new FocusTracker();\n\n\t\t/**\n\t\t * Navigation button for switching the stack to the previous one.\n\t\t *\n\t\t * @type {module:ui/button/buttonview~ButtonView}\n\t\t */\n\t\tthis.buttonPrevView = this._createButtonView( t( 'Previous' ), prevIcon );\n\n\t\t/**\n\t\t * Navigation button for switching the stack to the next one.\n\t\t *\n\t\t * @type {module:ui/button/buttonview~ButtonView}\n\t\t */\n\t\tthis.buttonNextView = this._createButtonView( t( 'Next' ), nextIcon );\n\n\t\t/**\n\t\t * A collection of the child views that creates the rotator content.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.content = this.createCollection();\n\n\t\tthis.setTemplate( {\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-balloon-rotator'\n\t\t\t\t],\n\t\t\t\t'z-index': '-1'\n\t\t\t},\n\t\t\tchildren: [\n\t\t\t\t{\n\t\t\t\t\ttag: 'div',\n\t\t\t\t\tattributes: {\n\t\t\t\t\t\tclass: [\n\t\t\t\t\t\t\t'ck-balloon-rotator__navigation',\n\t\t\t\t\t\t\tbind.to( 'isNavigationVisible', value => value ? '' : 'ck-hidden' )\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\tchildren: [\n\t\t\t\t\t\tthis.buttonPrevView,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttag: 'span',\n\n\t\t\t\t\t\t\tattributes: {\n\t\t\t\t\t\t\t\tclass: [\n\t\t\t\t\t\t\t\t\t'ck-balloon-rotator__counter'\n\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t},\n\n\t\t\t\t\t\t\tchildren: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\ttext: bind.to( 'counter' )\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t},\n\t\t\t\t\t\tthis.buttonNextView\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttag: 'div',\n\t\t\t\t\tattributes: {\n\t\t\t\t\t\tclass: 'ck-balloon-rotator__content'\n\t\t\t\t\t},\n\t\t\t\t\tchildren: this.content\n\t\t\t\t}\n\t\t\t]\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\tthis.focusTracker.add( this.element );\n\t}\n\n\t/**\n\t * Shows a given view.\n\t *\n\t * @param {module:ui/view~View} view The view to show.\n\t */\n\tshowView( view ) {\n\t\tthis.hideView();\n\t\tthis.content.add( view );\n\t}\n\n\t/**\n\t * Hides the currently displayed view.\n\t */\n\thideView() {\n\t\tthis.content.clear();\n\t}\n\n\t/**\n\t * Creates a navigation button view.\n\t *\n\t * @private\n\t * @param {String} label The button label.\n\t * @param {String} icon The button icon.\n\t * @returns {module:ui/button/buttonview~ButtonView}\n\t */\n\t_createButtonView( label, icon ) {\n\t\tconst view = new ButtonView( this.locale );\n\n\t\tview.set( {\n\t\t\tlabel,\n\t\t\ticon,\n\t\t\ttooltip: true\n\t\t} );\n\n\t\treturn view;\n\t}\n}\n\n// Displays additional layers under the balloon when multiple stacks are added to the balloon.\n//\n// @private\n// @extends module:ui/view~View\nclass FakePanelsView extends View {\n\t// @inheritDoc\n\tconstructor( locale, balloonPanelView ) {\n\t\tsuper( locale );\n\n\t\tconst bind = this.bindTemplate;\n\n\t\t// Fake panels top offset.\n\t\t//\n\t\t// @observable\n\t\t// @member {Number} #top\n\t\tthis.set( 'top', 0 );\n\n\t\t// Fake panels left offset.\n\t\t//\n\t\t// @observable\n\t\t// @member {Number} #left\n\t\tthis.set( 'left', 0 );\n\n\t\t// Fake panels height.\n\t\t//\n\t\t// @observable\n\t\t// @member {Number} #height\n\t\tthis.set( 'height', 0 );\n\n\t\t// Fake panels width.\n\t\t//\n\t\t// @observable\n\t\t// @member {Number} #width\n\t\tthis.set( 'width', 0 );\n\n\t\t// Number of rendered fake panels.\n\t\t//\n\t\t// @observable\n\t\t// @member {Number} #numberOfPanels\n\t\tthis.set( 'numberOfPanels', 0 );\n\n\t\t// Collection of the child views which creates fake panel content.\n\t\t//\n\t\t// @readonly\n\t\t// @type {module:ui/viewcollection~ViewCollection}\n\t\tthis.content = this.createCollection();\n\n\t\t// Context.\n\t\t//\n\t\t// @private\n\t\t// @type {module:ui/panel/balloon/balloonpanelview~BalloonPanelView}\n\t\tthis._balloonPanelView = balloonPanelView;\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'div',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck-fake-panel',\n\t\t\t\t\tbind.to( 'numberOfPanels', number => number ? '' : 'ck-hidden' )\n\t\t\t\t],\n\t\t\t\tstyle: {\n\t\t\t\t\ttop: bind.to( 'top', toPx ),\n\t\t\t\t\tleft: bind.to( 'left', toPx ),\n\t\t\t\t\twidth: bind.to( 'width', toPx ),\n\t\t\t\t\theight: bind.to( 'height', toPx )\n\t\t\t\t}\n\t\t\t},\n\t\t\tchildren: this.content\n\t\t} );\n\n\t\tthis.on( 'change:numberOfPanels', ( evt, name, next, prev ) => {\n\t\t\tif ( next > prev ) {\n\t\t\t\tthis._addPanels( next - prev );\n\t\t\t} else {\n\t\t\t\tthis._removePanels( prev - next );\n\t\t\t}\n\n\t\t\tthis.updatePosition();\n\t\t} );\n\t}\n\n\t// @private\n\t// @param {Number} number\n\t_addPanels( number ) {\n\t\twhile ( number-- ) {\n\t\t\tconst view = new View();\n\n\t\t\tview.setTemplate( { tag: 'div' } );\n\n\t\t\tthis.content.add( view );\n\t\t\tthis.registerChild( view );\n\t\t}\n\t}\n\n\t// @private\n\t// @param {Number} number\n\t_removePanels( number ) {\n\t\twhile ( number-- ) {\n\t\t\tconst view = this.content.last;\n\n\t\t\tthis.content.remove( view );\n\t\t\tthis.deregisterChild( view );\n\t\t\tview.destroy();\n\t\t}\n\t}\n\n\t// Updates coordinates of fake panels.\n\tupdatePosition() {\n\t\tif ( this.numberOfPanels ) {\n\t\t\tconst { top, left } = this._balloonPanelView;\n\t\t\tconst { width, height } = new Rect( this._balloonPanelView.element );\n\n\t\t\tObject.assign( this, { top, left, width, height } );\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 ui/toolbar/toolbarlinebreakview\n */\n\nimport View from '../view';\n\n/**\n * The toolbar line break view class.\n *\n * @extends module:ui/view~View\n */\nexport default class ToolbarLineBreakView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'span',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-toolbar__line-break'\n\t\t\t\t]\n\t\t\t}\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 ui/toolbar/toolbarview\n */\n\nimport View from '../view';\nimport FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker';\nimport FocusCycler from '../focuscycler';\nimport KeystrokeHandler from '@ckeditor/ckeditor5-utils/src/keystrokehandler';\nimport ToolbarSeparatorView from './toolbarseparatorview';\nimport ToolbarLineBreakView from './toolbarlinebreakview';\nimport ResizeObserver from '@ckeditor/ckeditor5-utils/src/dom/resizeobserver';\nimport preventDefault from '../bindings/preventdefault.js';\nimport Rect from '@ckeditor/ckeditor5-utils/src/dom/rect';\nimport global from '@ckeditor/ckeditor5-utils/src/dom/global';\nimport { createDropdown, addToolbarToDropdown } from '../dropdown/utils';\nimport { logWarning } from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport normalizeToolbarConfig from './normalizetoolbarconfig';\nimport { icons } from 'ckeditor5/src/core';\n\nimport '../../theme/components/toolbar/toolbar.css';\n\n/**\n * The toolbar view class.\n *\n * @extends module:ui/view~View\n * @implements module:ui/dropdown/dropdownpanelfocusable~DropdownPanelFocusable\n */\nexport default class ToolbarView extends View {\n\t/**\n\t * Creates an instance of the {@link module:ui/toolbar/toolbarview~ToolbarView} class.\n\t *\n\t * Also see {@link #render}.\n\t *\n\t * @param {module:utils/locale~Locale} locale The localization services instance.\n\t * @param {module:ui/toolbar/toolbarview~ToolbarOptions} [options] Configuration options of the toolbar.\n\t */\n\tconstructor( locale, options ) {\n\t\tsuper( locale );\n\n\t\tconst bind = this.bindTemplate;\n\t\tconst t = this.t;\n\n\t\t/**\n\t\t * A reference to the options object passed to the constructor.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/toolbar/toolbarview~ToolbarOptions}\n\t\t */\n\t\tthis.options = options || {};\n\n\t\t/**\n\t\t * Label used by assistive technologies to describe this toolbar element.\n\t\t *\n\t\t * @default 'Editor toolbar'\n\t\t * @member {String} #ariaLabel\n\t\t */\n\t\tthis.set( 'ariaLabel', t( 'Editor toolbar' ) );\n\n\t\t/**\n\t\t * The maximum width of the toolbar element.\n\t\t *\n\t\t * **Note**: When set to a specific value (e.g. `'200px'`), the value will affect the behavior of the\n\t\t * {@link module:ui/toolbar/toolbarview~ToolbarOptions#shouldGroupWhenFull}\n\t\t * option by changing the number of {@link #items} that will be displayed in the toolbar at a time.\n\t\t *\n\t\t * @observable\n\t\t * @default 'auto'\n\t\t * @member {String} #maxWidth\n\t\t */\n\t\tthis.set( 'maxWidth', 'auto' );\n\n\t\t/**\n\t\t * A collection of toolbar items (buttons, dropdowns, etc.).\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.items = this.createCollection();\n\n\t\t/**\n\t\t * Tracks information about the DOM focus in the toolbar.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/focustracker~FocusTracker}\n\t\t */\n\t\tthis.focusTracker = new FocusTracker();\n\n\t\t/**\n\t\t * An instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}\n\t\t * to handle keyboard navigation in the toolbar.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/keystrokehandler~KeystrokeHandler}\n\t\t */\n\t\tthis.keystrokes = new KeystrokeHandler();\n\n\t\t/**\n\t\t * An additional CSS class added to the {@link #element}.\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #class\n\t\t */\n\t\tthis.set( 'class' );\n\n\t\t/**\n\t\t * When set true, makes the toolbar look compact with {@link #element}.\n\t\t *\n\t\t * @observable\n\t\t * @default false\n\t\t * @member {String} #isCompact\n\t\t */\n\t\tthis.set( 'isCompact', false );\n\n\t\t/**\n\t\t * A (child) view containing {@link #items toolbar items}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/toolbar/toolbarview~ItemsView}\n\t\t */\n\t\tthis.itemsView = new ItemsView( locale );\n\n\t\t/**\n\t\t * A top–level collection aggregating building blocks of the toolbar.\n\t\t *\n\t\t *\t┌───────────────── ToolbarView ─────────────────┐\n\t\t *\t| ┌──────────────── #children ────────────────┐ |\n\t\t *\t| | ┌──────────── #itemsView ───────────┐ | |\n\t\t *\t| | | [ item1 ] [ item2 ] ... [ itemN ] | | |\n\t\t *\t| | └──────────────────────────────────-┘ | |\n\t\t *\t| └───────────────────────────────────────────┘ |\n\t\t *\t└───────────────────────────────────────────────┘\n\t\t *\n\t\t * By default, it contains the {@link #itemsView} but it can be extended with additional\n\t\t * UI elements when necessary.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.children = this.createCollection();\n\t\tthis.children.add( this.itemsView );\n\n\t\t/**\n\t\t * A collection of {@link #items} that take part in the focus cycling\n\t\t * (i.e. navigation using the keyboard). Usually, it contains a subset of {@link #items} with\n\t\t * some optional UI elements that also belong to the toolbar and should be focusable\n\t\t * by the user.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.focusables = this.createCollection();\n\n\t\t/**\n\t\t * Controls the orientation of toolbar items. Only available when\n\t\t * {@link module:ui/toolbar/toolbarview~ToolbarOptions#shouldGroupWhenFull dynamic items grouping}\n\t\t * is **disabled**.\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} #isVertical\n\t\t */\n\n\t\t/**\n\t\t * Helps cycling over {@link #focusables focusable items} in the toolbar.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {module:ui/focuscycler~FocusCycler}\n\t\t */\n\t\tthis._focusCycler = new FocusCycler( {\n\t\t\tfocusables: this.focusables,\n\t\t\tfocusTracker: this.focusTracker,\n\t\t\tkeystrokeHandler: this.keystrokes,\n\t\t\tactions: {\n\t\t\t\t// Navigate toolbar items backwards using the arrow[left,up] keys.\n\t\t\t\tfocusPrevious: [ 'arrowleft', 'arrowup' ],\n\n\t\t\t\t// Navigate toolbar items forwards using the arrow[right,down] keys.\n\t\t\t\tfocusNext: [ 'arrowright', 'arrowdown' ]\n\t\t\t}\n\t\t} );\n\n\t\tconst classes = [\n\t\t\t'ck',\n\t\t\t'ck-toolbar',\n\t\t\tbind.to( 'class' ),\n\t\t\tbind.if( 'isCompact', 'ck-toolbar_compact' )\n\t\t];\n\n\t\tif ( this.options.shouldGroupWhenFull && this.options.isFloating ) {\n\t\t\tclasses.push( 'ck-toolbar_floating' );\n\t\t}\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'div',\n\t\t\tattributes: {\n\t\t\t\tclass: classes,\n\t\t\t\trole: 'toolbar',\n\t\t\t\t'aria-label': bind.to( 'ariaLabel' ),\n\t\t\t\tstyle: {\n\t\t\t\t\tmaxWidth: bind.to( 'maxWidth' )\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tchildren: this.children,\n\n\t\t\ton: {\n\t\t\t\t// https://github.com/ckeditor/ckeditor5-ui/issues/206\n\t\t\t\tmousedown: preventDefault( this )\n\t\t\t}\n\t\t} );\n\n\t\t/**\n\t\t * An instance of the active toolbar behavior that shapes its look and functionality.\n\t\t *\n\t\t * See {@link module:ui/toolbar/toolbarview~ToolbarBehavior} to learn more.\n\t\t *\n\t\t * @protected\n\t\t * @readonly\n\t\t * @member {module:ui/toolbar/toolbarview~ToolbarBehavior}\n\t\t */\n\t\tthis._behavior = this.options.shouldGroupWhenFull ? new DynamicGrouping( this ) : new StaticLayout( this );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\t// Children added before rendering should be known to the #focusTracker.\n\t\tfor ( const item of this.items ) {\n\t\t\tthis.focusTracker.add( item.element );\n\t\t}\n\n\t\tthis.items.on( 'add', ( evt, item ) => {\n\t\t\tthis.focusTracker.add( item.element );\n\t\t} );\n\n\t\tthis.items.on( 'remove', ( evt, item ) => {\n\t\t\tthis.focusTracker.remove( item.element );\n\t\t} );\n\n\t\t// Start listening for the keystrokes coming from #element.\n\t\tthis.keystrokes.listenTo( this.element );\n\n\t\tthis._behavior.render( this );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tthis._behavior.destroy();\n\n\t\treturn super.destroy();\n\t}\n\n\t/**\n\t * Focuses the first focusable in {@link #focusables}.\n\t */\n\tfocus() {\n\t\tthis._focusCycler.focusFirst();\n\t}\n\n\t/**\n\t * Focuses the last focusable in {@link #focusables}.\n\t */\n\tfocusLast() {\n\t\tthis._focusCycler.focusLast();\n\t}\n\n\t/**\n\t * A utility that expands the plain toolbar configuration into\n\t * {@link module:ui/toolbar/toolbarview~ToolbarView#items} using a given component factory.\n\t *\n\t * @param {Array.|Object} itemsOrConfig The toolbar items or the entire toolbar configuration object.\n\t * @param {module:ui/componentfactory~ComponentFactory} factory A factory producing toolbar items.\n\t */\n\tfillFromConfig( itemsOrConfig, factory ) {\n\t\tconst config = normalizeToolbarConfig( itemsOrConfig );\n\n\t\tconst itemsToClean = config.items\n\t\t\t.filter( ( name, idx, items ) => {\n\t\t\t\tif ( name === '|' ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\t// Items listed in `config.removeItems` should not be added to the toolbar.\n\t\t\t\tif ( config.removeItems.indexOf( name ) !== -1 ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tif ( name === '-' ) {\n\t\t\t\t\t// The toolbar line breaks must not be rendered when toolbar grouping is enabled.\n\t\t\t\t\t// (https://github.com/ckeditor/ckeditor5/issues/8582)\n\t\t\t\t\tif ( this.options.shouldGroupWhenFull ) {\n\t\t\t\t\t\t/**\n\t\t\t\t\t\t * The toolbar multiline breaks (`-` items) only work when the automatic button grouping\n\t\t\t\t\t\t * is disabled in the toolbar configuration.\n\t\t\t\t\t\t * To do this, set the `shouldNotGroupWhenFull` option to `true` in the editor configuration:\n\t\t\t\t\t\t *\n\t\t\t\t\t\t *\t\tconst config = {\n\t\t\t\t\t\t *\t\t\ttoolbar: {\n\t\t\t\t\t\t *\t\t\t\titems: [ ... ],\n\t\t\t\t\t\t *\t\t\t\tshouldNotGroupWhenFull: true\n\t\t\t\t\t\t *\t\t\t}\n\t\t\t\t\t\t *\t\t}\n\t\t\t\t\t\t *\n\t\t\t\t\t\t * Learn more about {@link module:core/editor/editorconfig~EditorConfig#toolbar toolbar configuration}.\n\t\t\t\t\t\t *\n\t\t\t\t\t\t * @error toolbarview-line-break-ignored-when-grouping-items\n\t\t\t\t\t\t */\n\t\t\t\t\t\tlogWarning( 'toolbarview-line-break-ignored-when-grouping-items', items );\n\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\t// For the items that cannot be instantiated we are sending warning message. We also filter them out.\n\t\t\t\tif ( !factory.has( name ) ) {\n\t\t\t\t\t/**\n\t\t\t\t\t * There was a problem processing the configuration of the toolbar. The item with the given\n\t\t\t\t\t * name does not exist so it was omitted when rendering the toolbar.\n\t\t\t\t\t *\n\t\t\t\t\t * This warning usually shows up when the {@link module:core/plugin~Plugin} which is supposed\n\t\t\t\t\t * to provide a toolbar item has not been loaded or there is a typo in the configuration.\n\t\t\t\t\t *\n\t\t\t\t\t * Make sure the plugin responsible for this toolbar item is loaded and the toolbar configuration\n\t\t\t\t\t * is correct, e.g. {@link module:basic-styles/bold~Bold} is loaded for the `'bold'` toolbar item.\n\t\t\t\t\t *\n\t\t\t\t\t * You can use the following snippet to retrieve all available toolbar items:\n\t\t\t\t\t *\n\t\t\t\t\t *\t\tArray.from( editor.ui.componentFactory.names() );\n\t\t\t\t\t *\n\t\t\t\t\t * @error toolbarview-item-unavailable\n\t\t\t\t\t * @param {String} name The name of the component.\n\t\t\t\t\t */\n\t\t\t\t\tlogWarning( 'toolbarview-item-unavailable', { name } );\n\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\treturn true;\n\t\t\t} );\n\n\t\tconst itemsToAdd = this._cleanSeparators( itemsToClean )\n\t\t\t// Instantiate toolbar items.\n\t\t\t.map( name => {\n\t\t\t\tif ( name === '|' ) {\n\t\t\t\t\treturn new ToolbarSeparatorView();\n\t\t\t\t} else if ( name === '-' ) {\n\t\t\t\t\treturn new ToolbarLineBreakView();\n\t\t\t\t}\n\n\t\t\t\treturn factory.create( name );\n\t\t\t} );\n\n\t\tthis.items.addMany( itemsToAdd );\n\t}\n\n\t/**\n\t * Remove leading, trailing, and duplicated separators (`-` and `|`).\n\t *\n\t * @private\n\t * @param {Array.} items\n\t */\n\t_cleanSeparators( items ) {\n\t\tconst nonSeparatorPredicate = item => ( item !== '-' && item !== '|' );\n\t\tconst count = items.length;\n\n\t\t// Find an index of the first item that is not a separator.\n\t\tconst firstCommandItem = items.findIndex( nonSeparatorPredicate );\n\n\t\t// Search from the end of the list, then convert found index back to the original direction.\n\t\tconst lastCommandItem = count - items\n\t\t\t.slice()\n\t\t\t.reverse()\n\t\t\t.findIndex( nonSeparatorPredicate );\n\n\t\treturn items\n\t\t\t// Return items without the leading and trailing separators.\n\t\t\t.slice( firstCommandItem, lastCommandItem )\n\t\t\t// Remove duplicated separators.\n\t\t\t.filter( ( name, idx, items ) => {\n\t\t\t\t// Filter only separators.\n\t\t\t\tif ( nonSeparatorPredicate( name ) ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tconst isDuplicated = idx > 0 && items[ idx - 1 ] === name;\n\n\t\t\t\treturn !isDuplicated;\n\t\t\t} );\n\t}\n\n\t/**\n\t * Fired when some toolbar {@link #items} were grouped or ungrouped as a result of some change\n\t * in the toolbar geometry.\n\t *\n\t * **Note**: This event is always fired **once** regardless of the number of items that were be\n\t * grouped or ungrouped at a time.\n\t *\n\t * **Note**: This event is fired only if the items grouping functionality was enabled in\n\t * the first place (see {@link module:ui/toolbar/toolbarview~ToolbarOptions#shouldGroupWhenFull}).\n\t *\n\t * @event groupedItemsUpdate\n\t */\n}\n\n/**\n * An inner block of the {@link module:ui/toolbar/toolbarview~ToolbarView} hosting its\n * {@link module:ui/toolbar/toolbarview~ToolbarView#items}.\n *\n * @private\n * @extends module:ui/view~View\n */\nclass ItemsView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\t/**\n\t\t * A collection of items (buttons, dropdowns, etc.).\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.children = this.createCollection();\n\n\t\tthis.setTemplate( {\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-toolbar__items'\n\t\t\t\t]\n\t\t\t},\n\t\t\tchildren: this.children\n\t\t} );\n\t}\n}\n\n/**\n * A toolbar behavior that makes it static and unresponsive to the changes of the environment.\n * At the same time, it also makes it possible to display a toolbar with a vertical layout\n * using the {@link module:ui/toolbar/toolbarview~ToolbarView#isVertical} property.\n *\n * @private\n * @implements module:ui/toolbar/toolbarview~ToolbarBehavior\n */\nclass StaticLayout {\n\t/**\n\t * Creates an instance of the {@link module:ui/toolbar/toolbarview~StaticLayout} toolbar\n\t * behavior.\n\t *\n\t * @param {module:ui/toolbar/toolbarview~ToolbarView} view An instance of the toolbar that this behavior\n\t * is added to.\n\t */\n\tconstructor( view ) {\n\t\tconst bind = view.bindTemplate;\n\n\t\t// Static toolbar can be vertical when needed.\n\t\tview.set( 'isVertical', false );\n\n\t\t// 1:1 pass–through binding, all ToolbarView#items are visible.\n\t\tview.itemsView.children.bindTo( view.items ).using( item => item );\n\n\t\t// 1:1 pass–through binding, all ToolbarView#items are focusable.\n\t\tview.focusables.bindTo( view.items ).using( item => item );\n\n\t\tview.extendTemplate( {\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t// When vertical, the toolbar has an additional CSS class.\n\t\t\t\t\tbind.if( 'isVertical', 'ck-toolbar_vertical' )\n\t\t\t\t]\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {}\n}\n\n/**\n * A toolbar behavior that makes the items respond to changes in the geometry.\n *\n * In a nutshell, it groups {@link module:ui/toolbar/toolbarview~ToolbarView#items}\n * that do not fit visually into a single row of the toolbar (due to limited space).\n * Items that do not fit are aggregated in a dropdown displayed at the end of the toolbar.\n *\n *\t┌──────────────────────────────────────── ToolbarView ──────────────────────────────────────────┐\n *\t| ┌─────────────────────────────────────── #children ─────────────────────────────────────────┐ |\n *\t| | ┌─────── #itemsView ────────┐ ┌──────────────────────┐ ┌── #groupedItemsDropdown ───┐ | |\n *\t| | | #ungroupedItems | | ToolbarSeparatorView | | #groupedItems | | |\n *\t| | └──────────────────────────-┘ └──────────────────────┘ └────────────────────────────┘ | |\n *\t| | \\---------- only when toolbar items overflow --------/ | |\n *\t| └───────────────────────────────────────────────────────────────────────────────────────────┘ |\n *\t└───────────────────────────────────────────────────────────────────────────────────────────────┘\n *\n * @private\n * @implements module:ui/toolbar/toolbarview~ToolbarBehavior\n */\nclass DynamicGrouping {\n\t/**\n\t * Creates an instance of the {@link module:ui/toolbar/toolbarview~DynamicGrouping} toolbar\n\t * behavior.\n\t *\n\t * @param {module:ui/toolbar/toolbarview~ToolbarView} view An instance of the toolbar that this behavior\n\t * is added to.\n\t */\n\tconstructor( view ) {\n\t\t/**\n\t\t * A toolbar view this behavior belongs to.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/toolbar~ToolbarView}\n\t\t */\n\t\tthis.view = view;\n\n\t\t/**\n\t\t * A collection of toolbar children.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.viewChildren = view.children;\n\n\t\t/**\n\t\t * A collection of focusable toolbar elements.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.viewFocusables = view.focusables;\n\n\t\t/**\n\t\t * A view containing toolbar items.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/toolbar/toolbarview~ItemsView}\n\t\t */\n\t\tthis.viewItemsView = view.itemsView;\n\n\t\t/**\n\t\t * Toolbar focus tracker.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/focustracker~FocusTracker}\n\t\t */\n\t\tthis.viewFocusTracker = view.focusTracker;\n\n\t\t/**\n\t\t * Toolbar locale.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/locale~Locale}\n\t\t */\n\t\tthis.viewLocale = view.locale;\n\n\t\t/**\n\t\t * Toolbar element.\n\t\t *\n\t\t * @readonly\n\t\t * @member {HTMLElement} #viewElement\n\t\t */\n\n\t\t/**\n\t\t * A subset of toolbar {@link module:ui/toolbar/toolbarview~ToolbarView#items}.\n\t\t * Aggregates items that fit into a single row of the toolbar and were not {@link #groupedItems grouped}\n\t\t * into a {@link #groupedItemsDropdown dropdown}. Items of this collection are displayed in the\n\t\t * {@link module:ui/toolbar/toolbarview~ToolbarView#itemsView}.\n\t\t *\n\t\t * When none of the {@link module:ui/toolbar/toolbarview~ToolbarView#items} were grouped, it\n\t\t * matches the {@link module:ui/toolbar/toolbarview~ToolbarView#items} collection in size and order.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.ungroupedItems = view.createCollection();\n\n\t\t/**\n\t\t * A subset of toolbar {@link module:ui/toolbar/toolbarview~ToolbarView#items}.\n\t\t * A collection of the toolbar items that do not fit into a single row of the toolbar.\n\t\t * Grouped items are displayed in a dedicated {@link #groupedItemsDropdown dropdown}.\n\t\t *\n\t\t * When none of the {@link module:ui/toolbar/toolbarview~ToolbarView#items} were grouped,\n\t\t * this collection is empty.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.groupedItems = view.createCollection();\n\n\t\t/**\n\t\t * The dropdown that aggregates {@link #groupedItems grouped items} that do not fit into a single\n\t\t * row of the toolbar. It is displayed on demand as the last of\n\t\t * {@link module:ui/toolbar/toolbarview~ToolbarView#children toolbar children} and offers another\n\t\t * (nested) toolbar which displays items that would normally overflow.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/dropdown/dropdownview~DropdownView}\n\t\t */\n\t\tthis.groupedItemsDropdown = this._createGroupedItemsDropdown();\n\n\t\t/**\n\t\t * An instance of the resize observer that helps dynamically determine the geometry of the toolbar\n\t\t * and manage items that do not fit into a single row.\n\t\t *\n\t\t * **Note:** Created in {@link #_enableGroupingOnResize}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/dom/resizeobserver~ResizeObserver}\n\t\t */\n\t\tthis.resizeObserver = null;\n\n\t\t/**\n\t\t * A cached value of the horizontal padding style used by {@link #_updateGrouping}\n\t\t * to manage the {@link module:ui/toolbar/toolbarview~ToolbarView#items} that do not fit into\n\t\t * a single toolbar line. This value can be reused between updates because it is unlikely that\n\t\t * the padding will change and re–using `Window.getComputedStyle()` is expensive.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number}\n\t\t */\n\t\tthis.cachedPadding = null;\n\n\t\t/**\n\t\t * A flag indicating that an items grouping update has been queued (e.g. due to the toolbar being visible)\n\t\t * and should be executed immediately the next time the toolbar shows up.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean}\n\t\t */\n\t\tthis.shouldUpdateGroupingOnNextResize = false;\n\n\t\t// Only those items that were not grouped are visible to the user.\n\t\tview.itemsView.children.bindTo( this.ungroupedItems ).using( item => item );\n\n\t\t// Make sure all #items visible in the main space of the toolbar are \"focuscycleable\".\n\t\tthis.ungroupedItems.on( 'add', this._updateFocusCycleableItems.bind( this ) );\n\t\tthis.ungroupedItems.on( 'remove', this._updateFocusCycleableItems.bind( this ) );\n\n\t\t// Make sure the #groupedItemsDropdown is also included in cycling when it appears.\n\t\tview.children.on( 'add', this._updateFocusCycleableItems.bind( this ) );\n\t\tview.children.on( 'remove', this._updateFocusCycleableItems.bind( this ) );\n\n\t\t// ToolbarView#items is dynamic. When an item is added or removed, it should be automatically\n\t\t// represented in either grouped or ungrouped items at the right index.\n\t\t// In other words #items == concat( #ungroupedItems, #groupedItems )\n\t\t// (in length and order).\n\t\tview.items.on( 'change', ( evt, changeData ) => {\n\t\t\tconst index = changeData.index;\n\n\t\t\t// Removing.\n\t\t\tfor ( const removedItem of changeData.removed ) {\n\t\t\t\tif ( index >= this.ungroupedItems.length ) {\n\t\t\t\t\tthis.groupedItems.remove( removedItem );\n\t\t\t\t} else {\n\t\t\t\t\tthis.ungroupedItems.remove( removedItem );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Adding.\n\t\t\tfor ( let currentIndex = index; currentIndex < index + changeData.added.length; currentIndex++ ) {\n\t\t\t\tconst addedItem = changeData.added[ currentIndex - index ];\n\n\t\t\t\tif ( currentIndex > this.ungroupedItems.length ) {\n\t\t\t\t\tthis.groupedItems.add( addedItem, currentIndex - this.ungroupedItems.length );\n\t\t\t\t} else {\n\t\t\t\t\tthis.ungroupedItems.add( addedItem, currentIndex );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// When new ungrouped items join in and land in #ungroupedItems, there's a chance it causes\n\t\t\t// the toolbar to overflow.\n\t\t\t// Consequently if removed from grouped or ungrouped items, there is a chance\n\t\t\t// some new space is available and we could do some ungrouping.\n\t\t\tthis._updateGrouping();\n\t\t} );\n\n\t\tview.extendTemplate( {\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t// To group items dynamically, the toolbar needs a dedicated CSS class.\n\t\t\t\t\t'ck-toolbar_grouping'\n\t\t\t\t]\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Enables dynamic items grouping based on the dimensions of the toolbar.\n\t *\n\t * @param {module:ui/toolbar/toolbarview~ToolbarView} view An instance of the toolbar that this behavior\n\t * is added to.\n\t */\n\trender( view ) {\n\t\tthis.viewElement = view.element;\n\n\t\tthis._enableGroupingOnResize();\n\t\tthis._enableGroupingOnMaxWidthChange( view );\n\t}\n\n\t/**\n\t * Cleans up the internals used by this behavior.\n\t */\n\tdestroy() {\n\t\t// The dropdown may not be in ToolbarView#children at the moment of toolbar destruction\n\t\t// so let's make sure it's actually destroyed along with the toolbar.\n\t\tthis.groupedItemsDropdown.destroy();\n\n\t\tthis.resizeObserver.destroy();\n\t}\n\n\t/**\n\t * When called, it will check if any of the {@link #ungroupedItems} do not fit into a single row of the toolbar,\n\t * and it will move them to the {@link #groupedItems} when it happens.\n\t *\n\t * At the same time, it will also check if there is enough space in the toolbar for the first of the\n\t * {@link #groupedItems} to be returned back to {@link #ungroupedItems} and still fit into a single row\n\t * without the toolbar wrapping.\n\t *\n\t * @protected\n\t */\n\t_updateGrouping() {\n\t\t// Do no grouping–related geometry analysis when the toolbar is detached from visible DOM,\n\t\t// for instance before #render(), or after render but without a parent or a parent detached\n\t\t// from DOM. DOMRects won't work anyway and there will be tons of warning in the console and\n\t\t// nothing else. This happens, for instance, when the toolbar is detached from DOM and\n\t\t// some logic adds or removes its #items.\n\t\tif ( !this.viewElement.ownerDocument.body.contains( this.viewElement ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Do not update grouping when the element is invisible. Such toolbar has DOMRect filled with zeros\n\t\t// and that would cause all items to be grouped. Instead, queue the grouping so it runs next time\n\t\t// the toolbar is visible (the next ResizeObserver callback execution). This is handy because\n\t\t// the grouping could be caused by increasing the #maxWidth when the toolbar was invisible and the next\n\t\t// time it shows up, some items could actually be ungrouped (https://github.com/ckeditor/ckeditor5/issues/6575).\n\t\tif ( !this.viewElement.offsetParent ) {\n\t\t\tthis.shouldUpdateGroupingOnNextResize = true;\n\n\t\t\treturn;\n\t\t}\n\n\t\t// Remember how many items were initially grouped so at the it is possible to figure out if the number\n\t\t// of grouped items has changed. If the number has changed, geometry of the toolbar has also changed.\n\t\tconst initialGroupedItemsCount = this.groupedItems.length;\n\t\tlet wereItemsGrouped;\n\n\t\t// Group #items as long as some wrap to the next row. This will happen, for instance,\n\t\t// when the toolbar is getting narrow and there is not enough space to display all items in\n\t\t// a single row.\n\t\twhile ( this._areItemsOverflowing ) {\n\t\t\tthis._groupLastItem();\n\n\t\t\twereItemsGrouped = true;\n\t\t}\n\n\t\t// If none were grouped now but there were some items already grouped before,\n\t\t// then, what the hell, maybe let's see if some of them can be ungrouped. This happens when,\n\t\t// for instance, the toolbar is stretching and there's more space in it than before.\n\t\tif ( !wereItemsGrouped && this.groupedItems.length ) {\n\t\t\t// Ungroup items as long as none are overflowing or there are none to ungroup left.\n\t\t\twhile ( this.groupedItems.length && !this._areItemsOverflowing ) {\n\t\t\t\tthis._ungroupFirstItem();\n\t\t\t}\n\n\t\t\t// If the ungrouping ended up with some item wrapping to the next row,\n\t\t\t// put it back to the group toolbar (\"undo the last ungroup\"). We don't know whether\n\t\t\t// an item will wrap or not until we ungroup it (that's a DOM/CSS thing) so this\n\t\t\t// clean–up is vital for the algorithm.\n\t\t\tif ( this._areItemsOverflowing ) {\n\t\t\t\tthis._groupLastItem();\n\t\t\t}\n\t\t}\n\n\t\tif ( this.groupedItems.length !== initialGroupedItemsCount ) {\n\t\t\tthis.view.fire( 'groupedItemsUpdate' );\n\t\t}\n\t}\n\n\t/**\n\t * Returns `true` when {@link module:ui/toolbar/toolbarview~ToolbarView#element} children visually overflow,\n\t * for instance if the toolbar is narrower than its members. Returns `false` otherwise.\n\t *\n\t * @private\n\t * @type {Boolean}\n\t */\n\tget _areItemsOverflowing() {\n\t\t// An empty toolbar cannot overflow.\n\t\tif ( !this.ungroupedItems.length ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst element = this.viewElement;\n\t\tconst uiLanguageDirection = this.viewLocale.uiLanguageDirection;\n\t\tconst lastChildRect = new Rect( element.lastChild );\n\t\tconst toolbarRect = new Rect( element );\n\n\t\tif ( !this.cachedPadding ) {\n\t\t\tconst computedStyle = global.window.getComputedStyle( element );\n\t\t\tconst paddingProperty = uiLanguageDirection === 'ltr' ? 'paddingRight' : 'paddingLeft';\n\n\t\t\t// parseInt() is essential because of quirky floating point numbers logic and DOM.\n\t\t\t// If the padding turned out too big because of that, the grouped items dropdown would\n\t\t\t// always look (from the Rect perspective) like it overflows (while it's not).\n\t\t\tthis.cachedPadding = Number.parseInt( computedStyle[ paddingProperty ] );\n\t\t}\n\n\t\tif ( uiLanguageDirection === 'ltr' ) {\n\t\t\treturn lastChildRect.right > toolbarRect.right - this.cachedPadding;\n\t\t} else {\n\t\t\treturn lastChildRect.left < toolbarRect.left + this.cachedPadding;\n\t\t}\n\t}\n\n\t/**\n\t * Enables the functionality that prevents {@link #ungroupedItems} from overflowing (wrapping to the next row)\n\t * upon resize when there is little space available. Instead, the toolbar items are moved to the\n\t * {@link #groupedItems} collection and displayed in a dropdown at the end of the row (which has its own nested toolbar).\n\t *\n\t * When called, the toolbar will automatically analyze the location of its {@link #ungroupedItems} and \"group\"\n\t * them in the dropdown if necessary. It will also observe the browser window for size changes in\n\t * the future and respond to them by grouping more items or reverting already grouped back, depending\n\t * on the visual space available.\n\t *\n\t * @private\n\t */\n\t_enableGroupingOnResize() {\n\t\tlet previousWidth;\n\n\t\t// TODO: Consider debounce.\n\t\tthis.resizeObserver = new ResizeObserver( this.viewElement, entry => {\n\t\t\tif ( !previousWidth || previousWidth !== entry.contentRect.width || this.shouldUpdateGroupingOnNextResize ) {\n\t\t\t\tthis.shouldUpdateGroupingOnNextResize = false;\n\n\t\t\t\tthis._updateGrouping();\n\n\t\t\t\tpreviousWidth = entry.contentRect.width;\n\t\t\t}\n\t\t} );\n\n\t\tthis._updateGrouping();\n\t}\n\n\t/**\n\t * Enables the grouping functionality, just like {@link #_enableGroupingOnResize} but the difference is that\n\t * it listens to the changes of {@link module:ui/toolbar/toolbarview~ToolbarView#maxWidth} instead.\n\t *\n\t * @private\n\t */\n\t_enableGroupingOnMaxWidthChange( view ) {\n\t\tview.on( 'change:maxWidth', () => {\n\t\t\tthis._updateGrouping();\n\t\t} );\n\t}\n\n\t/**\n\t * When called, it will remove the last item from {@link #ungroupedItems} and move it back\n\t * to the {@link #groupedItems} collection.\n\t *\n\t * The opposite of {@link #_ungroupFirstItem}.\n\t *\n\t * @private\n\t */\n\t_groupLastItem() {\n\t\tif ( !this.groupedItems.length ) {\n\t\t\tthis.viewChildren.add( new ToolbarSeparatorView() );\n\t\t\tthis.viewChildren.add( this.groupedItemsDropdown );\n\t\t\tthis.viewFocusTracker.add( this.groupedItemsDropdown.element );\n\t\t}\n\n\t\tthis.groupedItems.add( this.ungroupedItems.remove( this.ungroupedItems.last ), 0 );\n\t}\n\n\t/**\n\t * Moves the very first item belonging to {@link #groupedItems} back\n\t * to the {@link #ungroupedItems} collection.\n\t *\n\t * The opposite of {@link #_groupLastItem}.\n\t *\n\t * @private\n\t */\n\t_ungroupFirstItem() {\n\t\tthis.ungroupedItems.add( this.groupedItems.remove( this.groupedItems.first ) );\n\n\t\tif ( !this.groupedItems.length ) {\n\t\t\tthis.viewChildren.remove( this.groupedItemsDropdown );\n\t\t\tthis.viewChildren.remove( this.viewChildren.last );\n\t\t\tthis.viewFocusTracker.remove( this.groupedItemsDropdown.element );\n\t\t}\n\t}\n\n\t/**\n\t * Creates the {@link #groupedItemsDropdown} that hosts the members of the {@link #groupedItems}\n\t * collection when there is not enough space in the toolbar to display all items in a single row.\n\t *\n\t * @private\n\t * @returns {module:ui/dropdown/dropdownview~DropdownView}\n\t */\n\t_createGroupedItemsDropdown() {\n\t\tconst locale = this.viewLocale;\n\t\tconst t = locale.t;\n\t\tconst dropdown = createDropdown( locale );\n\n\t\tdropdown.class = 'ck-toolbar__grouped-dropdown';\n\n\t\t// Make sure the dropdown never sticks out to the left/right. It should be under the main toolbar.\n\t\t// (https://github.com/ckeditor/ckeditor5/issues/5608)\n\t\tdropdown.panelPosition = locale.uiLanguageDirection === 'ltr' ? 'sw' : 'se';\n\n\t\taddToolbarToDropdown( dropdown, [] );\n\n\t\tdropdown.buttonView.set( {\n\t\t\tlabel: t( 'Show more items' ),\n\t\t\ttooltip: true,\n\t\t\ttooltipPosition: locale.uiLanguageDirection === 'rtl' ? 'se' : 'sw',\n\t\t\ticon: icons.threeVerticalDots\n\t\t} );\n\n\t\t// 1:1 pass–through binding.\n\t\tdropdown.toolbarView.items.bindTo( this.groupedItems ).using( item => item );\n\n\t\treturn dropdown;\n\t}\n\n\t/**\n\t * Updates the {@link module:ui/toolbar/toolbarview~ToolbarView#focusables focus–cycleable items}\n\t * collection so it represents the up–to–date state of the UI from the perspective of the user.\n\t *\n\t * For instance, the {@link #groupedItemsDropdown} can show up and hide but when it is visible,\n\t * it must be subject to focus cycling in the toolbar.\n\t *\n\t * See the {@link module:ui/toolbar/toolbarview~ToolbarView#focusables collection} documentation\n\t * to learn more about the purpose of this method.\n\t *\n\t * @private\n\t */\n\t_updateFocusCycleableItems() {\n\t\tthis.viewFocusables.clear();\n\n\t\tthis.ungroupedItems.map( item => {\n\t\t\tthis.viewFocusables.add( item );\n\t\t} );\n\n\t\tif ( this.groupedItems.length ) {\n\t\t\tthis.viewFocusables.add( this.groupedItemsDropdown );\n\t\t}\n\t}\n}\n\n/**\n * Options passed to the {@link module:ui/toolbar/toolbarview~ToolbarView#constructor} of the toolbar.\n *\n * @interface module:ui/toolbar/toolbarview~ToolbarOptions\n */\n\n/**\n * When set to `true`, the toolbar will automatically group {@link module:ui/toolbar/toolbarview~ToolbarView#items} that\n * would normally wrap to the next line when there is not enough space to display them in a single row, for\n * instance, if the parent container of the toolbar is narrow. For toolbars in absolutely positioned containers\n * without width restrictions also the {@link module:ui/toolbar/toolbarview~ToolbarOptions#isFloating} option is required to be `true`.\n *\n * See also: {@link module:ui/toolbar/toolbarview~ToolbarView#maxWidth}.\n *\n * @member {Boolean} module:ui/toolbar/toolbarview~ToolbarOptions#shouldGroupWhenFull\n */\n\n/**\n * This option should be enabled for toolbars in absolutely positioned containers without width restrictions\n * to enable automatic {@link module:ui/toolbar/toolbarview~ToolbarView#items} grouping.\n * When this option is set to `true`, the items will stop wrapping to the next line\n * and together with {@link module:ui/toolbar/toolbarview~ToolbarOptions#shouldGroupWhenFull},\n * this will allow grouping them when there is not enough space in a single row.\n *\n * @member {Boolean} module:ui/toolbar/toolbarview~ToolbarOptions#isFloating\n */\n\n/**\n * A class interface defining the behavior of the {@link module:ui/toolbar/toolbarview~ToolbarView}.\n *\n * Toolbar behaviors extend its look and functionality and have an impact on the\n * {@link module:ui/toolbar/toolbarview~ToolbarView#element} template or\n * {@link module:ui/toolbar/toolbarview~ToolbarView#render rendering}. They can be enabled\n * conditionally, e.g. depending on the configuration of the toolbar.\n *\n * @private\n * @interface module:ui/toolbar/toolbarview~ToolbarBehavior\n */\n\n/**\n * Creates a new toolbar behavior instance.\n *\n * The instance is created in the {@link module:ui/toolbar/toolbarview~ToolbarView#constructor} of the toolbar.\n * This is the right place to extend the {@link module:ui/toolbar/toolbarview~ToolbarView#template} of\n * the toolbar, define extra toolbar properties, etc.\n *\n * @method #constructor\n * @param {module:ui/toolbar/toolbarview~ToolbarView} view An instance of the toolbar that this behavior is added to.\n */\n\n/**\n * A method called after the toolbar has been {@link module:ui/toolbar/toolbarview~ToolbarView#render rendered}.\n * It can be used to, for example, customize the behavior of the toolbar when its {@link module:ui/toolbar/toolbarview~ToolbarView#element}\n * is available.\n *\n * @readonly\n * @member {Function} #render\n * @param {module:ui/toolbar/toolbarview~ToolbarView} view An instance of the toolbar being rendered.\n */\n\n/**\n * A method called after the toolbar has been {@link module:ui/toolbar/toolbarview~ToolbarView#destroy destroyed}.\n * It allows cleaning up after the toolbar behavior, for instance, this is the right place to detach\n * event listeners, free up references, etc.\n *\n * @readonly\n * @member {Function} #destroy\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 ui/toolbar/normalizetoolbarconfig\n */\n\n/**\n * Normalizes the toolbar configuration (`config.toolbar`), which:\n *\n * * may be defined as an `Array`:\n *\n * \t\ttoolbar: [ 'heading', 'bold', 'italic', 'link', ... ]\n *\n * * or an `Object`:\n *\n *\t\ttoolbar: {\n *\t\t\titems: [ 'heading', 'bold', 'italic', 'link', ... ],\n *\t\t\tremoveItems: [ 'bold' ],\n *\t\t\t...\n *\t\t}\n *\n * * or may not be defined at all (`undefined`)\n *\n * and returns it in the object form.\n *\n * @param {Array|Object|undefined} config The value of `config.toolbar`.\n * @returns {Object} A normalized toolbar config object.\n */\nexport default function normalizeToolbarConfig( config ) {\n\tif ( Array.isArray( config ) ) {\n\t\treturn {\n\t\t\titems: config,\n\t\t\tremoveItems: []\n\t\t};\n\t}\n\n\tif ( !config ) {\n\t\treturn {\n\t\t\titems: [],\n\t\t\tremoveItems: []\n\t\t};\n\t}\n\n\treturn Object.assign( {\n\t\titems: [],\n\t\tremoveItems: []\n\t}, config );\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 ui/panel/sticky/stickypanelview\n */\n\nimport global from '@ckeditor/ckeditor5-utils/src/dom/global';\nimport View from '../../view';\nimport Template from '../../template';\nimport toUnit from '@ckeditor/ckeditor5-utils/src/dom/tounit';\n\nimport '../../../theme/components/panel/stickypanel.css';\n\nconst toPx = toUnit( 'px' );\n\n/**\n * The sticky panel view class.\n */\nexport default class StickyPanelView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\tconst bind = this.bindTemplate;\n\n\t\t/**\n\t\t * Controls whether the sticky panel should be active.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Boolean} #isActive\n\t\t */\n\t\tthis.set( 'isActive', false );\n\n\t\t/**\n\t\t * Controls whether the sticky panel is in the \"sticky\" state.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Boolean} #isSticky\n\t\t */\n\t\tthis.set( 'isSticky', false );\n\n\t\t/**\n\t\t * The limiter element for the sticky panel instance. Its bounding rect limits\n\t\t * the \"stickyness\" of the panel, i.e. when the panel reaches the bottom\n\t\t * edge of the limiter, it becomes sticky to that edge and does not float\n\t\t * off the limiter. It is mandatory for the panel to work properly and once\n\t\t * set, it cannot be changed.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {HTMLElement} #limiterElement\n\t\t */\n\t\tthis.set( 'limiterElement', null );\n\n\t\t/**\n\t\t * The offset from the bottom edge of {@link #limiterElement}\n\t\t * which stops the panel from stickying any further to prevent limiter's content\n\t\t * from being completely covered.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @default 50\n\t\t * @member {Number} #limiterBottomOffset\n\t\t */\n\t\tthis.set( 'limiterBottomOffset', 50 );\n\n\t\t/**\n\t\t * The offset from the top edge of the web browser's viewport which makes the\n\t\t * panel become sticky. The default value is `0`, which means the panel becomes\n\t\t * sticky when it's upper edge touches the top of the page viewport.\n\t\t *\n\t\t * This attribute is useful when the web page has UI elements positioned to the top\n\t\t * either using `position: fixed` or `position: sticky`, which would cover the\n\t\t * sticky panel or vice–versa (depending on the `z-index` hierarchy).\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @default 0\n\t\t * @member {Number} #viewportTopOffset\n\t\t */\n\t\tthis.set( 'viewportTopOffset', 0 );\n\n\t\t/**\n\t\t * Controls the `margin-left` CSS style of the panel.\n\t\t *\n\t\t * @protected\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {String} #_marginLeft\n\t\t */\n\t\tthis.set( '_marginLeft', null );\n\n\t\t/**\n\t\t * Set `true` if the sticky panel reached the bottom edge of the\n\t\t * {@link #limiterElement}.\n\t\t *\n\t\t * @protected\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Boolean} #_isStickyToTheLimiter\n\t\t */\n\t\tthis.set( '_isStickyToTheLimiter', false );\n\n\t\t/**\n\t\t * Set `true` if the sticky panel uses the {@link #viewportTopOffset},\n\t\t * i.e. not {@link #_isStickyToTheLimiter} and the {@link #viewportTopOffset}\n\t\t * is not `0`.\n\t\t *\n\t\t * @protected\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Boolean} #_hasViewportTopOffset\n\t\t */\n\t\tthis.set( '_hasViewportTopOffset', false );\n\n\t\t/**\n\t\t * Collection of the child views which creates balloon panel contents.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.content = this.createCollection();\n\n\t\t/**\n\t\t * The DOM bounding client rect of the {@link module:ui/view~View#element} of the panel.\n\t\t *\n\t\t * @protected\n\t\t * @member {Object} #_panelRect\n\t\t */\n\n\t\t/**\n\t\t * The DOM bounding client rect of the {@link #limiterElement}\n\t\t * of the panel.\n\t\t *\n\t\t * @protected\n\t\t * @member {Object} #_limiterRect\n\t\t */\n\n\t\t/**\n\t\t * A dummy element which visually fills the space as long as the\n\t\t * actual panel is sticky. It prevents flickering of the UI.\n\t\t *\n\t\t * @protected\n\t\t * @property {HTMLElement}\n\t\t */\n\t\tthis._contentPanelPlaceholder = 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-sticky-panel__placeholder'\n\t\t\t\t],\n\t\t\t\tstyle: {\n\t\t\t\t\tdisplay: bind.to( 'isSticky', isSticky => isSticky ? 'block' : 'none' ),\n\t\t\t\t\theight: bind.to( 'isSticky', isSticky => {\n\t\t\t\t\t\treturn isSticky ? toPx( this._panelRect.height ) : null;\n\t\t\t\t\t} )\n\t\t\t\t}\n\t\t\t}\n\t\t} ).render();\n\n\t\t/**\n\t\t * The panel which accepts children into {@link #content} collection.\n\t\t * Also an element which is positioned when {@link #isSticky}.\n\t\t *\n\t\t * @protected\n\t\t * @property {HTMLElement}\n\t\t */\n\t\tthis._contentPanel = new Template( {\n\t\t\ttag: 'div',\n\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-sticky-panel__content',\n\t\t\t\t\t// Toggle class of the panel when \"sticky\" state changes in the view.\n\t\t\t\t\tbind.if( 'isSticky', 'ck-sticky-panel__content_sticky' ),\n\t\t\t\t\tbind.if( '_isStickyToTheLimiter', 'ck-sticky-panel__content_sticky_bottom-limit' )\n\t\t\t\t],\n\t\t\t\tstyle: {\n\t\t\t\t\twidth: bind.to( 'isSticky', isSticky => {\n\t\t\t\t\t\treturn isSticky ? toPx( this._contentPanelPlaceholder.getBoundingClientRect().width ) : null;\n\t\t\t\t\t} ),\n\n\t\t\t\t\ttop: bind.to( '_hasViewportTopOffset', _hasViewportTopOffset => {\n\t\t\t\t\t\treturn _hasViewportTopOffset ? toPx( this.viewportTopOffset ) : null;\n\t\t\t\t\t} ),\n\n\t\t\t\t\tbottom: bind.to( '_isStickyToTheLimiter', _isStickyToTheLimiter => {\n\t\t\t\t\t\treturn _isStickyToTheLimiter ? toPx( this.limiterBottomOffset ) : null;\n\t\t\t\t\t} ),\n\n\t\t\t\t\tmarginLeft: bind.to( '_marginLeft' )\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tchildren: this.content\n\t\t} ).render();\n\n\t\tthis.setTemplate( {\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-sticky-panel'\n\t\t\t\t]\n\t\t\t},\n\t\t\tchildren: [\n\t\t\t\tthis._contentPanelPlaceholder,\n\t\t\t\tthis._contentPanel\n\t\t\t]\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\t// Check if the panel should go into the sticky state immediately.\n\t\tthis._checkIfShouldBeSticky();\n\n\t\t// Update sticky state of the panel as the window is being scrolled.\n\t\tthis.listenTo( global.window, 'scroll', () => {\n\t\t\tthis._checkIfShouldBeSticky();\n\t\t} );\n\n\t\t// Synchronize with `model.isActive` because sticking an inactive panel is pointless.\n\t\tthis.listenTo( this, 'change:isActive', () => {\n\t\t\tthis._checkIfShouldBeSticky();\n\t\t} );\n\t}\n\n\t/**\n\t * Analyzes the environment to decide whether the panel should\n\t * be sticky or not.\n\t *\n\t * @protected\n\t */\n\t_checkIfShouldBeSticky() {\n\t\tconst panelRect = this._panelRect = this._contentPanel.getBoundingClientRect();\n\t\tlet limiterRect;\n\n\t\tif ( !this.limiterElement ) {\n\t\t\tthis.isSticky = false;\n\t\t} else {\n\t\t\tlimiterRect = this._limiterRect = this.limiterElement.getBoundingClientRect();\n\n\t\t\t// The panel must be active to become sticky.\n\t\t\tthis.isSticky = this.isActive &&\n\t\t\t\t// The limiter's top edge must be beyond the upper edge of the visible viewport (+the viewportTopOffset).\n\t\t\t\tlimiterRect.top < this.viewportTopOffset &&\n\t\t\t\t// The model#limiterElement's height mustn't be smaller than the panel's height and model#limiterBottomOffset.\n\t\t\t\t// There's no point in entering the sticky mode if the model#limiterElement is very, very small, because\n\t\t\t\t// it would immediately set model#_isStickyToTheLimiter true and, given model#limiterBottomOffset, the panel\n\t\t\t\t// would be positioned before the model#limiterElement.\n\t\t\t\tthis._panelRect.height + this.limiterBottomOffset < limiterRect.height;\n\t\t}\n\n\t\t// Stick the panel to the top edge of the viewport simulating CSS position:sticky.\n\t\t// TODO: Possibly replaced by CSS in the future http://caniuse.com/#feat=css-sticky\n\t\tif ( this.isSticky ) {\n\t\t\tthis._isStickyToTheLimiter =\n\t\t\t\tlimiterRect.bottom < panelRect.height + this.limiterBottomOffset + this.viewportTopOffset;\n\t\t\tthis._hasViewportTopOffset = !this._isStickyToTheLimiter && !!this.viewportTopOffset;\n\t\t\tthis._marginLeft = this._isStickyToTheLimiter ? null : toPx( -global.window.scrollX );\n\t\t}\n\t\t// Detach the panel from the top edge of the viewport.\n\t\telse {\n\t\t\tthis._isStickyToTheLimiter = false;\n\t\t\tthis._hasViewportTopOffset = false;\n\t\t\tthis._marginLeft = null;\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 ui/tooltip/tooltipview\n */\n\nimport View from '../view';\n\nimport '../../theme/components/tooltip/tooltip.css';\n\n/**\n * The tooltip view class.\n *\n * @extends module:ui/view~View\n */\nexport default class TooltipView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\t/**\n\t\t * The text of the tooltip visible to the user.\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #text\n\t\t */\n\t\tthis.set( 'text', '' );\n\n\t\t/**\n\t\t * The position of the tooltip (south, south-west, south-east, or north).\n\t\t *\n\t\t *\t\t+-----------+\n\t\t *\t\t| north |\n\t\t *\t\t+-----------+\n\t\t *\t\t V\n\t\t *\t\t [element]\n\t\t *\n\t\t *\t\t [element]\n\t\t *\t\t ^\n\t\t *\t\t+-----------+\n\t\t *\t\t| south |\n\t\t *\t\t+-----------+\n\t\t *\n\t\t * +----------+\n\t\t * [element] < | east |\n\t\t * +----------+\n\t\t *\n\t\t * +----------+\n\t\t * | west | > [element]\n\t\t * +----------+\n\t\t *\n\t\t *\t\t [element]\n\t\t *\t\t ^\n\t\t *\t\t+--------------+\n\t\t *\t\t| south west |\n\t\t *\t\t+--------------+\n\t\t *\n\t\t *\t [element]\n\t\t *\t\t ^\n\t\t *\t\t+--------------+\n\t\t *\t\t| south east |\n\t\t *\t\t+--------------+\n\n\t\t * @observable\n\t\t * @default 's'\n\t\t * @member {'s'|'n'|'e'|'w'|'sw'|'se'} #position\n\t\t */\n\t\tthis.set( 'position', 's' );\n\n\t\tconst bind = this.bindTemplate;\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'span',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-tooltip',\n\t\t\t\t\tbind.to( 'position', position => 'ck-tooltip_' + position ),\n\t\t\t\t\tbind.if( 'text', 'ck-hidden', value => !value.trim() )\n\t\t\t\t]\n\t\t\t},\n\t\t\tchildren: [\n\t\t\t\t{\n\t\t\t\t\ttag: 'span',\n\n\t\t\t\t\tattributes: {\n\t\t\t\t\t\tclass: [\n\t\t\t\t\t\t\t'ck',\n\t\t\t\t\t\t\t'ck-tooltip__text'\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\n\t\t\t\t\tchildren: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttext: bind.to( 'text' )\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t]\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 ui/notification/notification\n */\n\n/* globals window */\n\nimport { ContextPlugin } from 'ckeditor5/src/core';\n\n/**\n * The Notification plugin.\n *\n * This plugin sends a few types of notifications: `success`, `info` and `warning`. The notifications need to be\n * handled and displayed by a plugin responsible for showing the UI of the notifications. Using this plugin for dispatching\n * notifications makes it possible to switch the notifications UI.\n *\n * Note that every unhandled and not stopped `warning` notification will be displayed as a system alert.\n * See {@link module:ui/notification/notification~Notification#showWarning}.\n *\n * @extends module:core/contextplugin~ContextPlugin\n */\nexport default class Notification extends ContextPlugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Notification';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\t// Each unhandled and not stopped `show:warning` event is displayed as a system alert.\n\t\tthis.on( 'show:warning', ( evt, data ) => {\n\t\t\twindow.alert( data.message ); // eslint-disable-line no-alert\n\t\t}, { priority: 'lowest' } );\n\t}\n\n\t/**\n\t * Shows a success notification.\n\t *\n\t * By default, it fires the {@link #event:show:success `show:success` event} with the given `data`. The event namespace can be extended\n\t * using the `data.namespace` option. For example:\n\t *\n\t * \t\tshowSuccess( 'Image is uploaded.', {\n\t * \t\t\tnamespace: 'upload:image'\n\t * \t\t} );\n\t *\n\t * will fire the `show:success:upload:image` event.\n\t *\n\t * You can provide the title of the notification:\n\t *\n\t *\t\tshowSuccess( 'Image is uploaded.', {\n\t *\t\t\ttitle: 'Image upload success'\n\t *\t\t} );\n\t *\n\t * @param {String} message The content of the notification.\n\t * @param {Object} [data={}] Additional data.\n\t * @param {String} [data.namespace] Additional event namespace.\n\t * @param {String} [data.title] The title of the notification.\n\t */\n\tshowSuccess( message, data = {} ) {\n\t\tthis._showNotification( {\n\t\t\tmessage,\n\t\t\ttype: 'success',\n\t\t\tnamespace: data.namespace,\n\t\t\ttitle: data.title\n\t\t} );\n\t}\n\n\t/**\n\t * Shows an information notification.\n\t *\n\t * By default, it fires the {@link #event:show:info `show:info` event} with the given `data`. The event namespace can be extended\n\t * using the `data.namespace` option. For example:\n\t *\n\t * \t\tshowInfo( 'Editor is offline.', {\n\t * \t\t\tnamespace: 'editor:status'\n\t * \t\t} );\n\t *\n\t * will fire the `show:info:editor:status` event.\n\t *\n\t * You can provide the title of the notification:\n\t *\n\t *\t\tshowInfo( 'Editor is offline.', {\n\t *\t\t\ttitle: 'Network information'\n\t *\t\t} );\n\t *\n\t * @param {String} message The content of the notification.\n\t * @param {Object} [data={}] Additional data.\n\t * @param {String} [data.namespace] Additional event namespace.\n\t * @param {String} [data.title] The title of the notification.\n\t */\n\tshowInfo( message, data = {} ) {\n\t\tthis._showNotification( {\n\t\t\tmessage,\n\t\t\ttype: 'info',\n\t\t\tnamespace: data.namespace,\n\t\t\ttitle: data.title\n\t\t} );\n\t}\n\n\t/**\n\t * Shows a warning notification.\n\t *\n\t * By default, it fires the {@link #event:show:warning `show:warning` event}\n\t * with the given `data`. The event namespace can be extended using the `data.namespace` option. For example:\n\t *\n\t * \t\tshowWarning( 'Image upload error.', {\n\t * \t\t\tnamespace: 'upload:image'\n\t * \t\t} );\n\t *\n\t * will fire the `show:warning:upload:image` event.\n\t *\n\t * You can provide the title of the notification:\n\t *\n\t *\t\tshowWarning( 'Image upload error.', {\n\t *\t\t\ttitle: 'Upload failed'\n\t *\t\t} );\n\t *\n\t * Note that each unhandled and not stopped `warning` notification will be displayed as a system alert.\n\t * The plugin responsible for displaying warnings should `stop()` the event to prevent displaying it as an alert:\n\t *\n\t * \t\tnotifications.on( 'show:warning', ( evt, data ) => {\n\t * \t\t\t// Do something with the data.\n\t *\n\t * \t\t\t// Stop this event to prevent displaying it as an alert.\n\t * \t\t\tevt.stop();\n\t * \t\t} );\n\t *\n\t * You can attach many listeners to the same event and `stop()` this event in a listener with a low priority:\n\t *\n\t * \t\tnotifications.on( 'show:warning', ( evt, data ) => {\n\t * \t\t\t// Show the warning in the UI, but do not stop it.\n\t * \t\t} );\n\t *\n\t * \t\tnotifications.on( 'show:warning', ( evt, data ) => {\n\t * \t\t\t// Log the warning to some error tracker.\n\t *\n\t * \t\t\t// Stop this event to prevent displaying it as an alert.\n\t * \t\t\tevt.stop();\n\t * \t\t}, { priority: 'low' } );\n\t *\n\t * @param {String} message The content of the notification.\n\t * @param {Object} [data={}] Additional data.\n\t * @param {String} [data.namespace] Additional event namespace.\n\t * @param {String} [data.title] The title of the notification.\n\t */\n\tshowWarning( message, data = {} ) {\n\t\tthis._showNotification( {\n\t\t\tmessage,\n\t\t\ttype: 'warning',\n\t\t\tnamespace: data.namespace,\n\t\t\ttitle: data.title\n\t\t} );\n\t}\n\n\t/**\n\t * Fires the `show` event with the specified type, namespace and message.\n\t *\n\t * @private\n\t * @param {Object} data The message data.\n\t * @param {String} data.message The content of the notification.\n\t * @param {'success'|'info'|'warning'} data.type The type of the message.\n\t * @param {String} [data.namespace] Additional event namespace.\n\t * @param {String} [data.title=''] The title of the notification.\n\t */\n\t_showNotification( data ) {\n\t\tconst event = `show:${ data.type }` + ( data.namespace ? `:${ data.namespace }` : '' );\n\n\t\tthis.fire( event, {\n\t\t\tmessage: data.message,\n\t\t\ttype: data.type,\n\t\t\ttitle: data.title || ''\n\t\t} );\n\t}\n\n\t/**\n\t * Fired when one of the `showSuccess()`, `showInfo()`, `showWarning()` methods is called.\n\t *\n\t * @event show\n\t * @param {Object} data The notification data.\n\t * @param {String} data.message The content of the notification.\n\t * @param {String} data.title The title of the notification.\n\t * @param {'success'|'info'|'warning'} data.type The type of the notification.\n\t */\n\n\t/**\n\t * Fired when the `showSuccess()` method is called.\n\t *\n\t * @event show:success\n\t * @param {Object} data The notification data.\n\t * @param {String} data.message The content of the notification.\n\t * @param {String} data.title The title of the notification.\n\t * @param {'success'} data.type The type of the notification.\n\t */\n\n\t/**\n\t * Fired when the `showInfo()` method is called.\n\t *\n\t * @event show:info\n\t * @param {Object} data The notification data.\n\t * @param {String} data.message The content of the notification.\n\t * @param {String} data.title The title of the notification.\n\t * @param {'info'} data.type The type of the notification.\n\t */\n\n\t/**\n\t * Fired when the `showWarning()` method is called.\n\t *\n\t * When this event is not handled or stopped by `event.stop()`, the `data.message` of this event will\n\t * be automatically displayed as a system alert.\n\t *\n\t * @event show:warning\n\t * @param {Object} data The notification data.\n\t * @param {String} data.message The content of the notification.\n\t * @param {String} data.title The title of the notification.\n\t * @param {'warning'} data.type The type of the notification.\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 ui/toolbar/block/blockbuttonview\n */\n\nimport ButtonView from '../../button/buttonview';\nimport toUnit from '@ckeditor/ckeditor5-utils/src/dom/tounit';\nimport '../../../theme/components/toolbar/blocktoolbar.css';\n\nconst toPx = toUnit( 'px' );\n\n/**\n * The block button view class.\n *\n * This view represents a button attached next to block element where the selection is anchored.\n *\n * See {@link module:ui/toolbar/block/blocktoolbar~BlockToolbar}.\n *\n * @extends {module:ui/button/buttonview~ButtonView}\n */\nexport default class BlockButtonView extends ButtonView {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\tconst bind = this.bindTemplate;\n\n\t\t// Hide button on init.\n\t\tthis.isVisible = false;\n\n\t\tthis.isToggleable = true;\n\n\t\t/**\n\t\t * Top offset.\n\t\t *\n\t\t * @member {Number} #top\n\t\t */\n\t\tthis.set( 'top', 0 );\n\n\t\t/**\n\t\t * Left offset.\n\t\t *\n\t\t * @member {Number} #left\n\t\t */\n\t\tthis.set( 'left', 0 );\n\n\t\tthis.extendTemplate( {\n\t\t\tattributes: {\n\t\t\t\tclass: 'ck-block-toolbar-button',\n\t\t\t\tstyle: {\n\t\t\t\t\ttop: bind.to( 'top', val => toPx( val ) ),\n\t\t\t\t\tleft: bind.to( 'left', val => toPx( val ) )\n\t\t\t\t}\n\t\t\t}\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 ui/toolbar/block/blocktoolbar\n */\n\n/* global window */\n\nimport { Plugin, icons } from 'ckeditor5/src/core';\n\nimport BlockButtonView from './blockbuttonview';\nimport BalloonPanelView from '../../panel/balloon/balloonpanelview';\nimport ToolbarView from '../toolbarview';\n\nimport clickOutsideHandler from '../../bindings/clickoutsidehandler';\n\nimport { getOptimalPosition } from '@ckeditor/ckeditor5-utils/src/dom/position';\nimport Rect from '@ckeditor/ckeditor5-utils/src/dom/rect';\nimport normalizeToolbarConfig from '../normalizetoolbarconfig';\n\nimport ResizeObserver from '@ckeditor/ckeditor5-utils/src/dom/resizeobserver';\n\nimport toUnit from '@ckeditor/ckeditor5-utils/src/dom/tounit';\n\nconst toPx = toUnit( 'px' );\n\n/**\n * The block toolbar plugin.\n *\n * This plugin provides a button positioned next to the block of content where the selection is anchored.\n * Upon clicking the button, a dropdown providing access to editor features shows up, as configured in\n * {@link module:core/editor/editorconfig~EditorConfig#blockToolbar}.\n *\n * By default, the button is displayed next to all elements marked in {@link module:engine/model/schema~Schema}\n * as `$block` for which the toolbar provides at least one option.\n *\n * By default, the button is attached so its right boundary is touching the\n * {@link module:engine/view/editableelement~EditableElement}:\n *\n * \t\t __ |\n * \t\t| || This is a block of content that the\n * \t\t ¯¯ | button is attached to. This is a\n * \t\t | block of content that the button is\n * \t\t | attached to.\n *\n * The position of the button can be adjusted using the CSS `transform` property:\n *\n * \t\t.ck-block-toolbar-button {\n * \t\t\ttransform: translateX( -10px );\n * \t\t}\n *\n * \t\t __ |\n * \t\t| | | This is a block of content that the\n * \t\t ¯¯ | button is attached to. This is a\n * \t\t | block of content that the button is\n * \t\t | attached to.\n *\n * **Note**: If you plan to run the editor in a right–to–left (RTL) language, keep in mind the button\n * will be attached to the **right** boundary of the editable area. In that case, make sure the\n * CSS position adjustment works properly by adding the following styles:\n *\n * \t\t.ck[dir=\"rtl\"] .ck-block-toolbar-button {\n * \t\t\ttransform: translateX( 10px );\n * \t\t}\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class BlockToolbar extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'BlockToolbar';\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 cached and normalized `config.blockToolbar` object.\n\t\t *\n\t\t * @type {module:core/editor/editorconfig~EditorConfig#blockToolbar}\n\t\t * @private\n\t\t */\n\t\tthis._blockToolbarConfig = normalizeToolbarConfig( this.editor.config.get( 'blockToolbar' ) );\n\n\t\t/**\n\t\t * The toolbar view.\n\t\t *\n\t\t * @type {module:ui/toolbar/toolbarview~ToolbarView}\n\t\t */\n\t\tthis.toolbarView = this._createToolbarView();\n\n\t\t/**\n\t\t * The balloon panel view, containing the {@link #toolbarView}.\n\t\t *\n\t\t * @type {module:ui/panel/balloon/balloonpanelview~BalloonPanelView}\n\t\t */\n\t\tthis.panelView = this._createPanelView();\n\n\t\t/**\n\t\t * The button view that opens the {@link #toolbarView}.\n\t\t *\n\t\t * @type {module:ui/toolbar/block/blockbuttonview~BlockButtonView}\n\t\t */\n\t\tthis.buttonView = this._createButtonView();\n\n\t\t/**\n\t\t * An instance of the resize observer that allows to respond to changes in editable's geometry\n\t\t * so the toolbar can stay within its boundaries (and group toolbar items that do not fit).\n\t\t *\n\t\t * **Note**: Used only when `shouldNotGroupWhenFull` was **not** set in the\n\t\t * {@link module:core/editor/editorconfig~EditorConfig#blockToolbar configuration}.\n\t\t *\n\t\t * **Note:** Created in {@link #afterInit}.\n\t\t *\n\t\t * @protected\n\t\t * @member {module:utils/dom/resizeobserver~ResizeObserver}\n\t\t */\n\t\tthis._resizeObserver = null;\n\n\t\t// Close the #panelView upon clicking outside of the plugin UI.\n\t\tclickOutsideHandler( {\n\t\t\temitter: this.panelView,\n\t\t\tcontextElements: [ this.panelView.element, this.buttonView.element ],\n\t\t\tactivator: () => this.panelView.isVisible,\n\t\t\tcallback: () => this._hidePanel()\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\n\t\t// Hides panel on a direct selection change.\n\t\tthis.listenTo( editor.model.document.selection, 'change:range', ( evt, data ) => {\n\t\t\tif ( data.directChange ) {\n\t\t\t\tthis._hidePanel();\n\t\t\t}\n\t\t} );\n\n\t\tthis.listenTo( editor.ui, 'update', () => this._updateButton() );\n\t\t// `low` priority is used because of https://github.com/ckeditor/ckeditor5-core/issues/133.\n\t\tthis.listenTo( editor, 'change:isReadOnly', () => this._updateButton(), { priority: 'low' } );\n\t\tthis.listenTo( editor.ui.focusTracker, 'change:isFocused', () => this._updateButton() );\n\n\t\t// Reposition button on resize.\n\t\tthis.listenTo( this.buttonView, 'change:isVisible', ( evt, name, isVisible ) => {\n\t\t\tif ( isVisible ) {\n\t\t\t\t// Keep correct position of button and panel on window#resize.\n\t\t\t\tthis.buttonView.listenTo( window, 'resize', () => this._updateButton() );\n\t\t\t} else {\n\t\t\t\t// Stop repositioning button when is hidden.\n\t\t\t\tthis.buttonView.stopListening( window, 'resize' );\n\n\t\t\t\t// Hide the panel when the button disappears.\n\t\t\t\tthis._hidePanel();\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Fills the toolbar with its items based on the configuration.\n\t *\n\t * **Note:** This needs to be done after all plugins are ready.\n\t *\n\t * @inheritDoc\n\t */\n\tafterInit() {\n\t\tconst factory = this.editor.ui.componentFactory;\n\t\tconst config = this._blockToolbarConfig;\n\n\t\tthis.toolbarView.fillFromConfig( config, factory );\n\n\t\t// Hide panel before executing each button in the panel.\n\t\tfor ( const item of this.toolbarView.items ) {\n\t\t\titem.on( 'execute', () => this._hidePanel( true ), { priority: 'high' } );\n\t\t}\n\n\t\tif ( !config.shouldNotGroupWhenFull ) {\n\t\t\tthis.listenTo( this.editor, 'ready', () => {\n\t\t\t\tconst editableElement = this.editor.ui.view.editable.element;\n\n\t\t\t\t// Set #toolbarView's max-width just after the initialization and update it on the editable resize.\n\t\t\t\tthis._resizeObserver = new ResizeObserver( editableElement, () => {\n\t\t\t\t\tthis.toolbarView.maxWidth = this._getToolbarMaxWidth();\n\t\t\t\t} );\n\t\t\t} );\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tsuper.destroy();\n\n\t\t// Destroy created UI components as they are not automatically destroyed (see ckeditor5#1341).\n\t\tthis.panelView.destroy();\n\t\tthis.buttonView.destroy();\n\t\tthis.toolbarView.destroy();\n\n\t\tif ( this._resizeObserver ) {\n\t\t\tthis._resizeObserver.destroy();\n\t\t}\n\t}\n\n\t/**\n\t * Creates the {@link #toolbarView}.\n\t *\n\t * @private\n\t * @returns {module:ui/toolbar/toolbarview~ToolbarView}\n\t */\n\t_createToolbarView() {\n\t\tconst shouldGroupWhenFull = !this._blockToolbarConfig.shouldNotGroupWhenFull;\n\t\tconst toolbarView = new ToolbarView( this.editor.locale, {\n\t\t\tshouldGroupWhenFull,\n\t\t\tisFloating: true\n\t\t} );\n\n\t\t// When toolbar lost focus then panel should hide.\n\t\ttoolbarView.focusTracker.on( 'change:isFocused', ( evt, name, is ) => {\n\t\t\tif ( !is ) {\n\t\t\t\tthis._hidePanel();\n\t\t\t}\n\t\t} );\n\n\t\treturn toolbarView;\n\t}\n\n\t/**\n\t * Creates the {@link #panelView}.\n\t *\n\t * @private\n\t * @returns {module:ui/panel/balloon/balloonpanelview~BalloonPanelView}\n\t */\n\t_createPanelView() {\n\t\tconst editor = this.editor;\n\t\tconst panelView = new BalloonPanelView( editor.locale );\n\n\t\tpanelView.content.add( this.toolbarView );\n\t\tpanelView.class = 'ck-toolbar-container';\n\t\teditor.ui.view.body.add( panelView );\n\t\teditor.ui.focusTracker.add( panelView.element );\n\n\t\t// Close #panelView on `Esc` press.\n\t\tthis.toolbarView.keystrokes.set( 'Esc', ( evt, cancel ) => {\n\t\t\tthis._hidePanel( true );\n\t\t\tcancel();\n\t\t} );\n\n\t\treturn panelView;\n\t}\n\n\t/**\n\t * Creates the {@link #buttonView}.\n\t *\n\t * @private\n\t * @returns {module:ui/toolbar/block/blockbuttonview~BlockButtonView}\n\t */\n\t_createButtonView() {\n\t\tconst editor = this.editor;\n\t\tconst t = editor.t;\n\t\tconst buttonView = new BlockButtonView( editor.locale );\n\n\t\tbuttonView.set( {\n\t\t\tlabel: t( 'Edit block' ),\n\t\t\ticon: icons.pilcrow,\n\t\t\twithText: false\n\t\t} );\n\n\t\t// Bind the panelView observable properties to the buttonView.\n\t\tbuttonView.bind( 'isOn' ).to( this.panelView, 'isVisible' );\n\t\tbuttonView.bind( 'tooltip' ).to( this.panelView, 'isVisible', isVisible => !isVisible );\n\n\t\t// Toggle the panelView upon buttonView#execute.\n\t\tthis.listenTo( buttonView, 'execute', () => {\n\t\t\tif ( !this.panelView.isVisible ) {\n\t\t\t\tthis._showPanel();\n\t\t\t} else {\n\t\t\t\tthis._hidePanel( true );\n\t\t\t}\n\t\t} );\n\n\t\teditor.ui.view.body.add( buttonView );\n\t\teditor.ui.focusTracker.add( buttonView.element );\n\n\t\treturn buttonView;\n\t}\n\n\t/**\n\t * Shows or hides the button.\n\t * When all the conditions for displaying the button are matched, it shows the button. Hides otherwise.\n\t *\n\t * @private\n\t */\n\t_updateButton() {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\t\tconst view = editor.editing.view;\n\n\t\t// Hides the button when the editor is not focused.\n\t\tif ( !editor.ui.focusTracker.isFocused ) {\n\t\t\tthis._hideButton();\n\n\t\t\treturn;\n\t\t}\n\n\t\t// Hides the button when the editor switches to the read-only mode.\n\t\tif ( editor.isReadOnly ) {\n\t\t\tthis._hideButton();\n\n\t\t\treturn;\n\t\t}\n\n\t\t// Get the first selected block, button will be attached to this element.\n\t\tconst modelTarget = Array.from( model.document.selection.getSelectedBlocks() )[ 0 ];\n\n\t\t// Hides the button when there is no enabled item in toolbar for the current block element.\n\t\tif ( !modelTarget || Array.from( this.toolbarView.items ).every( item => !item.isEnabled ) ) {\n\t\t\tthis._hideButton();\n\n\t\t\treturn;\n\t\t}\n\n\t\t// Get DOM target element.\n\t\tconst domTarget = view.domConverter.mapViewToDom( editor.editing.mapper.toViewElement( modelTarget ) );\n\n\t\t// Show block button.\n\t\tthis.buttonView.isVisible = true;\n\n\t\t// Attach block button to target DOM element.\n\t\tthis._attachButtonToElement( domTarget );\n\n\t\t// When panel is opened then refresh it position to be properly aligned with block button.\n\t\tif ( this.panelView.isVisible ) {\n\t\t\tthis._showPanel();\n\t\t}\n\t}\n\n\t/**\n\t * Hides the button.\n\t *\n\t * @private\n\t */\n\t_hideButton() {\n\t\tthis.buttonView.isVisible = false;\n\t}\n\n\t/**\n\t * Shows the {@link #toolbarView} attached to the {@link #buttonView}.\n\t * If the toolbar is already visible, then it simply repositions it.\n\t *\n\t * @private\n\t */\n\t_showPanel() {\n\t\tconst wasVisible = this.panelView.isVisible;\n\n\t\t// So here's the thing: If there was no initial panelView#show() or these two were in different order, the toolbar\n\t\t// positioning will break in RTL editors. Weird, right? What you show know is that the toolbar\n\t\t// grouping works thanks to:\n\t\t//\n\t\t// * the ResizeObserver, which kicks in as soon as the toolbar shows up in DOM (becomes visible again).\n\t\t// * the observable ToolbarView#maxWidth, which triggers re-grouping when changed.\n\t\t//\n\t\t// Here are the possible scenarios:\n\t\t//\n\t\t// 1. (WRONG ❌) If the #maxWidth is set when the toolbar is invisible, it won't affect item grouping (no DOMRects, no grouping).\n\t\t// Then, when panelView.pin() is called, the position of the toolbar will be calculated for the old\n\t\t// items grouping state, and when finally ResizeObserver kicks in (hey, the toolbar is visible now, right?)\n\t\t// it will group/ungroup some items and the length of the toolbar will change. But since in RTL the toolbar\n\t\t// is attached on the right side and the positioning uses CSS \"left\", it will result in the toolbar shifting\n\t\t// to the left and being displayed in the wrong place.\n\t\t// 2. (WRONG ❌) If the panelView.pin() is called first and #maxWidth set next, then basically the story repeats. The balloon\n\t\t// calculates the position for the old toolbar grouping state, then the toolbar re-groups items and because\n\t\t// it is positioned using CSS \"left\" it will move.\n\t\t// 3. (RIGHT ✅) We show the panel first (the toolbar does re-grouping but it does not matter), then the #maxWidth\n\t\t// is set allowing the toolbar to re-group again and finally panelView.pin() does the positioning when the\n\t\t// items grouping state is stable and final.\n\t\t//\n\t\t// https://github.com/ckeditor/ckeditor5/issues/6449, https://github.com/ckeditor/ckeditor5/issues/6575\n\t\tthis.panelView.show();\n\t\tthis.toolbarView.maxWidth = this._getToolbarMaxWidth();\n\n\t\tthis.panelView.pin( {\n\t\t\ttarget: this.buttonView.element,\n\t\t\tlimiter: this.editor.ui.getEditableElement()\n\t\t} );\n\n\t\tif ( !wasVisible ) {\n\t\t\tthis.toolbarView.items.get( 0 ).focus();\n\t\t}\n\t}\n\n\t/**\n\t * Hides the {@link #toolbarView}.\n\t *\n\t * @private\n\t * @param {Boolean} [focusEditable=false] When `true`, the editable will be focused after hiding the panel.\n\t */\n\t_hidePanel( focusEditable ) {\n\t\tthis.panelView.isVisible = false;\n\n\t\tif ( focusEditable ) {\n\t\t\tthis.editor.editing.view.focus();\n\t\t}\n\t}\n\n\t/**\n\t * Attaches the {@link #buttonView} to the target block of content.\n\t *\n\t * @protected\n\t * @param {HTMLElement} targetElement Target element.\n\t */\n\t_attachButtonToElement( targetElement ) {\n\t\tconst contentStyles = window.getComputedStyle( targetElement );\n\n\t\tconst editableRect = new Rect( this.editor.ui.getEditableElement() );\n\t\tconst contentPaddingTop = parseInt( contentStyles.paddingTop, 10 );\n\t\t// When line height is not an integer then thread it as \"normal\".\n\t\t// MDN says that 'normal' == ~1.2 on desktop browsers.\n\t\tconst contentLineHeight = parseInt( contentStyles.lineHeight, 10 ) || parseInt( contentStyles.fontSize, 10 ) * 1.2;\n\n\t\tconst position = getOptimalPosition( {\n\t\t\telement: this.buttonView.element,\n\t\t\ttarget: targetElement,\n\t\t\tpositions: [\n\t\t\t\t( contentRect, buttonRect ) => {\n\t\t\t\t\tlet left;\n\n\t\t\t\t\tif ( this.editor.locale.uiLanguageDirection === 'ltr' ) {\n\t\t\t\t\t\tleft = editableRect.left - buttonRect.width;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tleft = editableRect.right;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\ttop: contentRect.top + contentPaddingTop + ( contentLineHeight - buttonRect.height ) / 2,\n\t\t\t\t\t\tleft\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t]\n\t\t} );\n\n\t\tthis.buttonView.top = position.top;\n\t\tthis.buttonView.left = position.left;\n\t}\n\n\t/**\n\t * Gets the {@link #toolbarView} max-width, based on\n\t * editable width plus distance between farthest edge of the {@link #buttonView} and the editable.\n\t *\n\t * @private\n\t * @returns {String} maxWidth A maximum width that toolbar can have, in pixels.\n\t */\n\t_getToolbarMaxWidth() {\n\t\tconst editableElement = this.editor.ui.view.editable.element;\n\t\tconst editableRect = new Rect( editableElement );\n\t\tconst buttonRect = new Rect( this.buttonView.element );\n\t\tconst isRTL = this.editor.locale.uiLanguageDirection === 'rtl';\n\t\tconst offset = isRTL ? ( buttonRect.left - editableRect.right ) + buttonRect.width : editableRect.left - buttonRect.left;\n\n\t\treturn toPx( editableRect.width + offset );\n\t}\n}\n\n/**\n * The block toolbar configuration. Used by the {@link module:ui/toolbar/block/blocktoolbar~BlockToolbar}\n * feature.\n *\n *\t\tconst config = {\n *\t\t\tblockToolbar: [ 'paragraph', 'heading1', 'heading2', 'bulletedList', 'numberedList' ]\n *\t\t};\n *\n * You can also use `'|'` to create a separator between groups of items:\n *\n *\t\tconst config = {\n *\t\t\tblockToolbar: [ 'paragraph', 'heading1', 'heading2', '|', 'bulletedList', 'numberedList' ]\n *\t\t};\n *\n * ## Configuring items grouping\n *\n * You can prevent automatic items grouping by setting the `shouldNotGroupWhenFull` option:\n *\n *\t\tconst config = {\n *\t\t\tblockToolbar: {\n *\t\t\t\titems: [ 'paragraph', 'heading1', 'heading2', '|', 'bulletedList', 'numberedList' ],\n *\t\t\t\tshouldNotGroupWhenFull: true\n *\t\t\t},\n *\t\t};\n *\n * Read more about configuring the main editor toolbar in {@link module:core/editor/editorconfig~EditorConfig#toolbar}.\n *\n * @member {Array.|Object} module:core/editor/editorconfig~EditorConfig#blockToolbar\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 ui/toolbar/balloon/balloontoolbar\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport ContextualBalloon from '../../panel/balloon/contextualballoon';\nimport ToolbarView from '../toolbarview';\nimport BalloonPanelView from '../../panel/balloon/balloonpanelview.js';\nimport FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker';\nimport Rect from '@ckeditor/ckeditor5-utils/src/dom/rect';\nimport normalizeToolbarConfig from '../normalizetoolbarconfig';\nimport { debounce } from 'lodash-es';\nimport ResizeObserver from '@ckeditor/ckeditor5-utils/src/dom/resizeobserver';\nimport toUnit from '@ckeditor/ckeditor5-utils/src/dom/tounit';\n\nconst toPx = toUnit( 'px' );\n\n/**\n * The contextual toolbar.\n *\n * It uses the {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon contextual balloon plugin}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class BalloonToolbar extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'BalloonToolbar';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ ContextualBalloon ];\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 cached and normalized `config.balloonToolbar` object.\n\t\t *\n\t\t * @type {module:core/editor/editorconfig~EditorConfig#balloonToolbar}\n\t\t * @private\n\t\t */\n\t\tthis._balloonConfig = normalizeToolbarConfig( editor.config.get( 'balloonToolbar' ) );\n\n\t\t/**\n\t\t * The toolbar view displayed in the balloon.\n\t\t *\n\t\t * @type {module:ui/toolbar/toolbarview~ToolbarView}\n\t\t */\n\t\tthis.toolbarView = this._createToolbarView();\n\n\t\t/**\n\t\t * Tracks the focus of the {@link module:core/editor/editorui~EditorUI#getEditableElement editable element}\n\t\t * and the {@link #toolbarView}. When both are blurred then the toolbar should hide.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:utils:focustracker~FocusTracker}\n\t\t */\n\t\tthis.focusTracker = new FocusTracker();\n\n\t\t// Wait for the EditorUI#init. EditableElement is not available before.\n\t\teditor.ui.once( 'ready', () => {\n\t\t\tthis.focusTracker.add( editor.ui.getEditableElement() );\n\t\t\tthis.focusTracker.add( this.toolbarView.element );\n\t\t} );\n\n\t\t/**\n\t\t * An instance of the resize observer that allows to respond to changes in editable's geometry\n\t\t * so the toolbar can stay within its boundaries (and group toolbar items that do not fit).\n\t\t *\n\t\t * **Note**: Used only when `shouldNotGroupWhenFull` was **not** set in the\n\t\t * {@link module:core/editor/editorconfig~EditorConfig#balloonToolbar configuration}.\n\t\t *\n\t\t * **Note:** Created in {@link #init}.\n\t\t *\n\t\t * @protected\n\t\t * @member {module:utils/dom/resizeobserver~ResizeObserver}\n\t\t */\n\t\tthis._resizeObserver = null;\n\n\t\t/**\n\t\t * The contextual balloon plugin instance.\n\t\t *\n\t\t * @private\n\t\t * @type {module:ui/panel/balloon/contextualballoon~ContextualBalloon}\n\t\t */\n\t\tthis._balloon = editor.plugins.get( ContextualBalloon );\n\n\t\t/**\n\t\t * Fires {@link #event:_selectionChangeDebounced} event using `lodash#debounce`.\n\t\t *\n\t\t * This function is stored as a plugin property to make possible to cancel\n\t\t * trailing debounced invocation on destroy.\n\t\t *\n\t\t * @private\n\t\t * @type {Function}\n\t\t */\n\t\tthis._fireSelectionChangeDebounced = debounce( () => this.fire( '_selectionChangeDebounced' ), 200 );\n\n\t\t// The appearance of the BalloonToolbar method is event–driven.\n\t\t// It is possible to stop the #show event and this prevent the toolbar from showing up.\n\t\tthis.decorate( 'show' );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst selection = editor.model.document.selection;\n\n\t\t// Show/hide the toolbar on editable focus/blur.\n\t\tthis.listenTo( this.focusTracker, 'change:isFocused', ( evt, name, isFocused ) => {\n\t\t\tconst isToolbarVisible = this._balloon.visibleView === this.toolbarView;\n\n\t\t\tif ( !isFocused && isToolbarVisible ) {\n\t\t\t\tthis.hide();\n\t\t\t} else if ( isFocused ) {\n\t\t\t\tthis.show();\n\t\t\t}\n\t\t} );\n\n\t\t// Hide the toolbar when the selection is changed by a direct change or has changed to collapsed.\n\t\tthis.listenTo( selection, 'change:range', ( evt, data ) => {\n\t\t\tif ( data.directChange || selection.isCollapsed ) {\n\t\t\t\tthis.hide();\n\t\t\t}\n\n\t\t\t// Fire internal `_selectionChangeDebounced` event to use it for showing\n\t\t\t// the toolbar after the selection stops changing.\n\t\t\tthis._fireSelectionChangeDebounced();\n\t\t} );\n\n\t\t// Show the toolbar when the selection stops changing.\n\t\tthis.listenTo( this, '_selectionChangeDebounced', () => {\n\t\t\tif ( this.editor.editing.view.document.isFocused ) {\n\t\t\t\tthis.show();\n\t\t\t}\n\t\t} );\n\n\t\tif ( !this._balloonConfig.shouldNotGroupWhenFull ) {\n\t\t\tthis.listenTo( editor, 'ready', () => {\n\t\t\t\tconst editableElement = editor.ui.view.editable.element;\n\n\t\t\t\t// Set #toolbarView's max-width on the initialization and update it on the editable resize.\n\t\t\t\tthis._resizeObserver = new ResizeObserver( editableElement, () => {\n\t\t\t\t\t// The max-width equals 90% of the editable's width for the best user experience.\n\t\t\t\t\t// The value keeps the balloon very close to the boundaries of the editable and limits the cases\n\t\t\t\t\t// when the balloon juts out from the editable element it belongs to.\n\t\t\t\t\tthis.toolbarView.maxWidth = toPx( new Rect( editableElement ).width * .9 );\n\t\t\t\t} );\n\t\t\t} );\n\t\t}\n\n\t\t// Listen to the toolbar view and whenever it changes its geometry due to some items being\n\t\t// grouped or ungrouped, update the position of the balloon because a shorter/longer toolbar\n\t\t// means the balloon could be pointing at the wrong place. Once updated, the balloon will point\n\t\t// at the right selection in the content again.\n\t\t// https://github.com/ckeditor/ckeditor5/issues/6444\n\t\tthis.listenTo( this.toolbarView, 'groupedItemsUpdate', () => {\n\t\t\tthis._updatePosition();\n\t\t} );\n\t}\n\n\t/**\n\t * Creates toolbar components based on given configuration.\n\t * This needs to be done when all plugins are ready.\n\t *\n\t * @inheritDoc\n\t */\n\tafterInit() {\n\t\tconst factory = this.editor.ui.componentFactory;\n\n\t\tthis.toolbarView.fillFromConfig( this._balloonConfig, factory );\n\t}\n\n\t/**\n\t * Creates the toolbar view instance.\n\t *\n\t * @private\n\t * @returns {module:ui/toolbar/toolbarview~ToolbarView}\n\t */\n\t_createToolbarView() {\n\t\tconst shouldGroupWhenFull = !this._balloonConfig.shouldNotGroupWhenFull;\n\t\tconst toolbarView = new ToolbarView( this.editor.locale, {\n\t\t\tshouldGroupWhenFull,\n\t\t\tisFloating: true\n\t\t} );\n\n\t\ttoolbarView.render();\n\n\t\treturn toolbarView;\n\t}\n\n\t/**\n\t * Shows the toolbar and attaches it to the selection.\n\t *\n\t * Fires {@link #event:show} event which can be stopped to prevent the toolbar from showing up.\n\t */\n\tshow() {\n\t\tconst editor = this.editor;\n\t\tconst selection = editor.model.document.selection;\n\t\tconst schema = editor.model.schema;\n\n\t\t// Do not add the toolbar to the balloon stack twice.\n\t\tif ( this._balloon.hasView( this.toolbarView ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Do not show the toolbar when the selection is collapsed.\n\t\tif ( selection.isCollapsed ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Do not show the toolbar when there is more than one range in the selection and they fully contain selectable elements.\n\t\t// See https://github.com/ckeditor/ckeditor5/issues/6443.\n\t\tif ( selectionContainsOnlyMultipleSelectables( selection, schema ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Don not show the toolbar when all components inside are disabled\n\t\t// see https://github.com/ckeditor/ckeditor5-ui/issues/269.\n\t\tif ( Array.from( this.toolbarView.items ).every( item => item.isEnabled !== undefined && !item.isEnabled ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Update the toolbar position when the editor ui should be refreshed.\n\t\tthis.listenTo( this.editor.ui, 'update', () => {\n\t\t\tthis._updatePosition();\n\t\t} );\n\n\t\t// Add the toolbar to the common editor contextual balloon.\n\t\tthis._balloon.add( {\n\t\t\tview: this.toolbarView,\n\t\t\tposition: this._getBalloonPositionData(),\n\t\t\tballoonClassName: 'ck-toolbar-container'\n\t\t} );\n\t}\n\n\t/**\n\t * Hides the toolbar.\n\t */\n\thide() {\n\t\tif ( this._balloon.hasView( this.toolbarView ) ) {\n\t\t\tthis.stopListening( this.editor.ui, 'update' );\n\t\t\tthis._balloon.remove( this.toolbarView );\n\t\t}\n\t}\n\n\t/**\n\t * Returns positioning options for the {@link #_balloon}. They control the way balloon is attached\n\t * to the selection.\n\t *\n\t * @private\n\t * @returns {module:utils/dom/position~Options}\n\t */\n\t_getBalloonPositionData() {\n\t\tconst editor = this.editor;\n\t\tconst view = editor.editing.view;\n\t\tconst viewDocument = view.document;\n\t\tconst viewSelection = viewDocument.selection;\n\n\t\t// Get direction of the selection.\n\t\tconst isBackward = viewDocument.selection.isBackward;\n\n\t\treturn {\n\t\t\t// Because the target for BalloonPanelView is a Rect (not DOMRange), it's geometry will stay fixed\n\t\t\t// as the window scrolls. To let the BalloonPanelView follow such Rect, is must be continuously\n\t\t\t// computed and hence, the target is defined as a function instead of a static value.\n\t\t\t// https://github.com/ckeditor/ckeditor5-ui/issues/195\n\t\t\ttarget: () => {\n\t\t\t\tconst range = isBackward ? viewSelection.getFirstRange() : viewSelection.getLastRange();\n\t\t\t\tconst rangeRects = Rect.getDomRangeRects( view.domConverter.viewRangeToDom( range ) );\n\n\t\t\t\t// Select the proper range rect depending on the direction of the selection.\n\t\t\t\tif ( isBackward ) {\n\t\t\t\t\treturn rangeRects[ 0 ];\n\t\t\t\t} else {\n\t\t\t\t\t// Ditch the zero-width \"orphan\" rect in the next line for the forward selection if there's\n\t\t\t\t\t// another one preceding it. It is not rendered as a selection by the web browser anyway.\n\t\t\t\t\t// https://github.com/ckeditor/ckeditor5-ui/issues/308\n\t\t\t\t\tif ( rangeRects.length > 1 && rangeRects[ rangeRects.length - 1 ].width === 0 ) {\n\t\t\t\t\t\trangeRects.pop();\n\t\t\t\t\t}\n\n\t\t\t\t\treturn rangeRects[ rangeRects.length - 1 ];\n\t\t\t\t}\n\t\t\t},\n\t\t\tpositions: getBalloonPositions( isBackward )\n\t\t};\n\t}\n\n\t/**\n\t * Updates the position of the {@link #_balloon} to make up for changes:\n\t *\n\t * * in the geometry of the selection it is attached to (e.g. the selection moved in the viewport or expanded or shrunk),\n\t * * or the geometry of the balloon toolbar itself (e.g. the toolbar has grouped or ungrouped some items and it is shorter or longer).\n\t *\n\t * @private\n\t */\n\t_updatePosition() {\n\t\tthis._balloon.updatePosition( this._getBalloonPositionData() );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tsuper.destroy();\n\n\t\tthis.stopListening();\n\t\tthis._fireSelectionChangeDebounced.cancel();\n\t\tthis.toolbarView.destroy();\n\t\tthis.focusTracker.destroy();\n\n\t\tif ( this._resizeObserver ) {\n\t\t\tthis._resizeObserver.destroy();\n\t\t}\n\t}\n\n\t/**\n\t * This event is fired just before the toolbar shows up. Stopping this event will prevent this.\n\t *\n\t * @event show\n\t */\n\n\t/**\n\t * This is internal plugin event which is fired 200 ms after model selection last change.\n\t * This is to makes easy test debounced action without need to use `setTimeout`.\n\t *\n\t * @protected\n\t * @event _selectionChangeDebounced\n\t */\n}\n\n// Returns toolbar positions for the given direction of the selection.\n//\n// @private\n// @param {Boolean} isBackward\n// @returns {Array.}\nfunction getBalloonPositions( isBackward ) {\n\tconst defaultPositions = BalloonPanelView.defaultPositions;\n\n\treturn isBackward ? [\n\t\tdefaultPositions.northWestArrowSouth,\n\t\tdefaultPositions.northWestArrowSouthWest,\n\t\tdefaultPositions.northWestArrowSouthEast,\n\t\tdefaultPositions.northWestArrowSouthMiddleEast,\n\t\tdefaultPositions.northWestArrowSouthMiddleWest,\n\t\tdefaultPositions.southWestArrowNorth,\n\t\tdefaultPositions.southWestArrowNorthWest,\n\t\tdefaultPositions.southWestArrowNorthEast,\n\t\tdefaultPositions.southWestArrowNorthMiddleWest,\n\t\tdefaultPositions.southWestArrowNorthMiddleEast\n\t] : [\n\t\tdefaultPositions.southEastArrowNorth,\n\t\tdefaultPositions.southEastArrowNorthEast,\n\t\tdefaultPositions.southEastArrowNorthWest,\n\t\tdefaultPositions.southEastArrowNorthMiddleEast,\n\t\tdefaultPositions.southEastArrowNorthMiddleWest,\n\t\tdefaultPositions.northEastArrowSouth,\n\t\tdefaultPositions.northEastArrowSouthEast,\n\t\tdefaultPositions.northEastArrowSouthWest,\n\t\tdefaultPositions.northEastArrowSouthMiddleEast,\n\t\tdefaultPositions.northEastArrowSouthMiddleWest\n\t];\n}\n\n// Returns \"true\" when the selection has multiple ranges and each range contains a selectable element\n// and nothing else.\n//\n// @private\n// @param {module:engine/model/selection~Selection} selection\n// @param {module:engine/model/schema~Schema} schema\n// @returns {Boolean}\nfunction selectionContainsOnlyMultipleSelectables( selection, schema ) {\n\t// It doesn't contain multiple objects if there is only one range.\n\tif ( selection.rangeCount === 1 ) {\n\t\treturn false;\n\t}\n\n\treturn [ ...selection.getRanges() ].every( range => {\n\t\tconst element = range.getContainedElement();\n\n\t\treturn element && schema.isSelectable( element );\n\t} );\n}\n\n/**\n * Contextual toolbar configuration. Used by the {@link module:ui/toolbar/balloon/balloontoolbar~BalloonToolbar}\n * feature.\n *\n * ## Configuring toolbar items\n *\n *\t\tconst config = {\n *\t\t\tballoonToolbar: [ 'bold', 'italic', 'undo', 'redo' ]\n *\t\t};\n *\n * You can also use `'|'` to create a separator between groups of items:\n *\n *\t\tconst config = {\n *\t\t\tballoonToolbar: [ 'bold', 'italic', | 'undo', 'redo' ]\n *\t\t};\n *\n * Read also about configuring the main editor toolbar in {@link module:core/editor/editorconfig~EditorConfig#toolbar}.\n *\n * ## Configuring items grouping\n *\n * You can prevent automatic items grouping by setting the `shouldNotGroupWhenFull` option:\n *\n *\t\tconst config = {\n *\t\t\tballoonToolbar: {\n *\t\t\t\titems: [ 'bold', 'italic', 'undo', 'redo' ],\n *\t\t\t\tshouldNotGroupWhenFull: true\n *\t\t\t},\n *\t\t};\n *\n * @member {Array.|Object} module:core/editor/editorconfig~EditorConfig#balloonToolbar\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 ui/template\n */\n\n/* global document */\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\nimport View from './view';\nimport ViewCollection from './viewcollection';\nimport isNode from '@ckeditor/ckeditor5-utils/src/dom/isnode';\nimport { isObject, cloneDeepWith } from 'lodash-es';\nimport toArray from '@ckeditor/ckeditor5-utils/src/toarray';\n\nconst xhtmlNs = 'http://www.w3.org/1999/xhtml';\n\n/**\n * A basic Template class. It renders a DOM HTML element or text from a\n * {@link module:ui/template~TemplateDefinition definition} and supports element attributes, children,\n * bindings to {@link module:utils/observablemixin~Observable observables} and DOM event propagation.\n *\n * A simple template can look like this:\n *\n *\t\tconst bind = Template.bind( observable, emitter );\n *\n *\t\tnew Template( {\n *\t\t\ttag: 'p',\n *\t\t\tattributes: {\n *\t\t\t\tclass: 'foo',\n *\t\t\t\tstyle: {\n *\t\t\t\t\tbackgroundColor: 'yellow'\n *\t\t\t\t}\n *\t\t\t},\n *\t\t\ton: {\n *\t\t\t\tclick: bind.to( 'clicked' )\n *\t\t\t},\n *\t\t\tchildren: [\n *\t\t\t\t'A paragraph.'\n *\t\t\t]\n *\t\t} ).render();\n *\n * and it will render the following HTML element:\n *\n *\t\t

A paragraph.

\n *\n * Additionally, the `observable` will always fire `clicked` upon clicking `

` in the DOM.\n *\n * See {@link module:ui/template~TemplateDefinition} to know more about templates and complex\n * template definitions.\n *\n* @mixes module:utils/emittermixin~EmitterMixin\n */\nexport default class Template {\n\t/**\n\t * Creates an instance of the {@link ~Template} class.\n\t *\n\t * @param {module:ui/template~TemplateDefinition} def The definition of the template.\n\t */\n\tconstructor( def ) {\n\t\tObject.assign( this, normalize( clone( def ) ) );\n\n\t\t/**\n\t\t * Indicates whether this particular Template instance has been\n\t\t * {@link #render rendered}.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {Boolean}\n\t\t */\n\t\tthis._isRendered = false;\n\n\t\t/**\n\t\t * The tag (`tagName`) of this template, e.g. `div`. It also indicates that the template\n\t\t * renders to an HTML element.\n\t\t *\n\t\t * @member {String} #tag\n\t\t */\n\n\t\t/**\n\t\t * The text of the template. It also indicates that the template renders to a DOM text node.\n\t\t *\n\t\t * @member {Array.} #text\n\t\t */\n\n\t\t/**\n\t\t * The attributes of the template, e.g. `{ id: [ 'ck-id' ] }`, corresponding with\n\t\t * the attributes of an HTML element.\n\t\t *\n\t\t * **Note**: This property only makes sense when {@link #tag} is defined.\n\t\t *\n\t\t * @member {Object} #attributes\n\t\t */\n\n\t\t/**\n\t\t * The children of the template. They can be either:\n\t\t * * independent instances of {@link ~Template} (sub–templates),\n\t\t * * native DOM Nodes.\n\t\t *\n\t\t * **Note**: This property only makes sense when {@link #tag} is defined.\n\t\t *\n\t\t * @member {Array.} #children\n\t\t */\n\n\t\t/**\n\t\t * The DOM event listeners of the template.\n\t\t *\n\t\t * @member {Object} #eventListeners\n\t\t */\n\n\t\t/**\n\t\t * The data used by the {@link #revert} method to restore a node to its original state.\n\t\t *\n\t\t * See: {@link #apply}.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {module:ui/template~RenderData}\n\t\t */\n\t\tthis._revertData = null;\n\t}\n\n\t/**\n\t * Renders a DOM Node (an HTML element or text) out of the template.\n\t *\n\t *\t\tconst domNode = new Template( { ... } ).render();\n\t *\n\t * See: {@link #apply}.\n\t *\n\t * @returns {HTMLElement|Text}\n\t */\n\trender() {\n\t\tconst node = this._renderNode( {\n\t\t\tintoFragment: true\n\t\t} );\n\n\t\tthis._isRendered = true;\n\n\t\treturn node;\n\t}\n\n\t/**\n\t * Applies the template to an existing DOM Node, either HTML element or text.\n\t *\n\t * **Note:** No new DOM nodes will be created. Applying extends:\n\t *\n\t * {@link module:ui/template~TemplateDefinition attributes},\n\t * {@link module:ui/template~TemplateDefinition event listeners}, and\n\t * `textContent` of {@link module:ui/template~TemplateDefinition children} only.\n\t *\n\t * **Note:** Existing `class` and `style` attributes are extended when a template\n\t * is applied to an HTML element, while other attributes and `textContent` are overridden.\n\t *\n\t * **Note:** The process of applying a template can be easily reverted using the\n\t * {@link module:ui/template~Template#revert} method.\n\t *\n\t *\t\tconst element = document.createElement( 'div' );\n\t *\t\tconst observable = new Model( { divClass: 'my-div' } );\n\t *\t\tconst emitter = Object.create( EmitterMixin );\n\t *\t\tconst bind = Template.bind( observable, emitter );\n\t *\n\t *\t\tnew Template( {\n\t *\t\t\tattributes: {\n\t *\t\t\t\tid: 'first-div',\n\t *\t\t\t\tclass: bind.to( 'divClass' )\n\t *\t\t\t},\n\t *\t\t\ton: {\n\t *\t\t\t\tclick: bind( 'elementClicked' ) // Will be fired by the observable.\n\t *\t\t\t},\n\t *\t\t\tchildren: [\n\t *\t\t\t\t'Div text.'\n\t *\t\t\t]\n\t *\t\t} ).apply( element );\n\t *\n\t *\t\tconsole.log( element.outerHTML ); // -> '

'\n\t *\n\t * @see module:ui/template~Template#render\n\t * @see module:ui/template~Template#revert\n\t * @param {Node} node Root node for the template to apply.\n\t */\n\tapply( node ) {\n\t\tthis._revertData = getEmptyRevertData();\n\n\t\tthis._renderNode( {\n\t\t\tnode,\n\t\t\tisApplying: true,\n\t\t\trevertData: this._revertData\n\t\t} );\n\n\t\treturn node;\n\t}\n\n\t/**\n\t * Reverts a template {@link module:ui/template~Template#apply applied} to a DOM node.\n\t *\n\t * @param {Node} node The root node for the template to revert. In most of the cases, it is the\n\t * same node used by {@link module:ui/template~Template#apply}.\n\t */\n\trevert( node ) {\n\t\tif ( !this._revertData ) {\n\t\t\t/**\n\t\t\t * Attempting to revert a template which has not been applied yet.\n\t\t\t *\n\t\t\t * @error ui-template-revert-not-applied\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'ui-template-revert-not-applied',\n\t\t\t\t[ this, node ]\n\t\t\t);\n\t\t}\n\n\t\tthis._revertTemplateFromNode( node, this._revertData );\n\t}\n\n\t/**\n\t * Returns an iterator which traverses the template in search of {@link module:ui/view~View}\n\t * instances and returns them one by one.\n\t *\n\t *\t\tconst viewFoo = new View();\n\t *\t\tconst viewBar = new View();\n\t *\t\tconst viewBaz = new View();\n\t *\t\tconst template = new Template( {\n\t *\t\t\ttag: 'div',\n\t *\t\t\tchildren: [\n\t *\t\t\t\tviewFoo,\n\t *\t\t\t\t{\n\t *\t\t\t\t\ttag: 'div',\n\t *\t\t\t\t\tchildren: [\n\t *\t\t\t\t\t\tviewBar\n\t *\t\t\t\t\t]\n\t *\t\t\t\t},\n\t *\t\t\t\tviewBaz\n\t *\t\t\t]\n\t *\t\t} );\n\t *\n\t *\t\t// Logs: viewFoo, viewBar, viewBaz\n\t *\t\tfor ( const view of template.getViews() ) {\n\t *\t\t\tconsole.log( view );\n\t *\t\t}\n\t *\n\t * @returns {Iterable.}\n\t */\n\t* getViews() {\n\t\tfunction* search( def ) {\n\t\t\tif ( def.children ) {\n\t\t\t\tfor ( const child of def.children ) {\n\t\t\t\t\tif ( isView( child ) ) {\n\t\t\t\t\t\tyield child;\n\t\t\t\t\t} else if ( isTemplate( child ) ) {\n\t\t\t\t\t\tyield* search( child );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tyield* search( this );\n\t}\n\n\t/**\n\t * An entry point to the interface which binds DOM nodes to\n\t * {@link module:utils/observablemixin~Observable observables}.\n\t * There are two types of bindings:\n\t *\n\t * * HTML element attributes or text `textContent` synchronized with attributes of an\n\t * {@link module:utils/observablemixin~Observable}. Learn more about {@link module:ui/template~BindChain#to}\n\t * and {@link module:ui/template~BindChain#if}.\n\t *\n\t *\t\tconst bind = Template.bind( observable, emitter );\n\t *\n\t *\t\tnew Template( {\n\t *\t\t\tattributes: {\n\t *\t\t\t\t// Binds the element \"class\" attribute to observable#classAttribute.\n\t *\t\t\t\tclass: bind.to( 'classAttribute' )\n\t *\t\t\t}\n\t *\t\t} ).render();\n\t *\n\t * * DOM events fired on HTML element propagated through\n\t * {@link module:utils/observablemixin~Observable}. Learn more about {@link module:ui/template~BindChain#to}.\n\t *\n\t *\t\tconst bind = Template.bind( observable, emitter );\n\t *\n\t *\t\tnew Template( {\n\t *\t\t\ton: {\n\t *\t\t\t\t// Will be fired by the observable.\n\t *\t\t\t\tclick: bind( 'elementClicked' )\n\t *\t\t\t}\n\t *\t\t} ).render();\n\t *\n\t * Also see {@link module:ui/view~View#bindTemplate}.\n\t *\n\t * @param {module:utils/observablemixin~Observable} observable An observable which provides boundable attributes.\n\t * @param {module:utils/emittermixin~Emitter} emitter An emitter that listens to observable attribute\n\t * changes or DOM Events (depending on the kind of the binding). Usually, a {@link module:ui/view~View} instance.\n\t * @returns {module:ui/template~BindChain}\n\t */\n\tstatic bind( observable, emitter ) {\n\t\treturn {\n\t\t\tto( eventNameOrFunctionOrAttribute, callback ) {\n\t\t\t\treturn new TemplateToBinding( {\n\t\t\t\t\teventNameOrFunction: eventNameOrFunctionOrAttribute,\n\t\t\t\t\tattribute: eventNameOrFunctionOrAttribute,\n\t\t\t\t\tobservable, emitter, callback\n\t\t\t\t} );\n\t\t\t},\n\n\t\t\tif( attribute, valueIfTrue, callback ) {\n\t\t\t\treturn new TemplateIfBinding( {\n\t\t\t\t\tobservable, emitter, attribute, valueIfTrue, callback\n\t\t\t\t} );\n\t\t\t}\n\t\t};\n\t}\n\n\t/**\n\t * Extends an existing {@link module:ui/template~Template} instance with some additional content\n\t * from another {@link module:ui/template~TemplateDefinition}.\n\t *\n\t *\t\tconst bind = Template.bind( observable, emitter );\n\t *\n\t *\t\tconst template = new Template( {\n\t *\t\t\ttag: 'p',\n\t *\t\t\tattributes: {\n\t *\t\t\t\tclass: 'a',\n\t *\t\t\t\tdata-x: bind.to( 'foo' )\n\t *\t\t\t},\n\t *\t\t\tchildren: [\n\t *\t\t\t\t{\n\t *\t\t\t\t\ttag: 'span',\n\t *\t\t\t\t\tattributes: {\n\t *\t\t\t\t\t\tclass: 'b'\n\t *\t\t\t\t\t},\n\t *\t\t\t\t\tchildren: [\n\t *\t\t\t\t\t\t'Span'\n\t *\t\t\t\t\t]\n\t *\t\t\t\t}\n\t *\t\t\t]\n\t *\t\t } );\n\t *\n\t *\t\t// Instance-level extension.\n\t *\t\tTemplate.extend( template, {\n\t *\t\t\tattributes: {\n\t *\t\t\t\tclass: 'b',\n\t *\t\t\t\tdata-x: bind.to( 'bar' )\n\t *\t\t\t},\n\t *\t\t\tchildren: [\n\t *\t\t\t\t{\n\t *\t\t\t\t\tattributes: {\n\t *\t\t\t\t\t\tclass: 'c'\n\t *\t\t\t\t\t}\n\t *\t\t\t\t}\n\t *\t\t\t]\n\t *\t\t} );\n\t *\n\t *\t\t// Child extension.\n\t *\t\tTemplate.extend( template.children[ 0 ], {\n\t *\t\t\tattributes: {\n\t *\t\t\t\tclass: 'd'\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * the `outerHTML` of `template.render()` is:\n\t *\n\t *\t\t

\n\t *\t\t\tSpan\n\t *\t\t

\n\t *\n\t * @param {module:ui/template~Template} template An existing template instance to be extended.\n\t * @param {module:ui/template~TemplateDefinition} def Additional definition to be applied to a template.\n\t */\n\tstatic extend( template, def ) {\n\t\tif ( template._isRendered ) {\n\t\t\t/**\n\t\t\t * Extending a template after rendering may not work as expected. To make sure\n\t\t\t * the {@link module:ui/template~Template.extend extending} works for an element,\n\t\t\t * make sure it happens before {@link #render} is called.\n\t\t\t *\n\t\t\t * @error template-extend-render\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'template-extend-render',\n\t\t\t\t[ this, template ]\n\t\t\t);\n\t\t}\n\n\t\textendTemplate( template, normalize( clone( def ) ) );\n\t}\n\n\t/**\n\t * Renders a DOM Node (either an HTML element or text) out of the template.\n\t *\n\t * @protected\n\t * @param {module:ui/template~RenderData} data Rendering data.\n\t */\n\t_renderNode( data ) {\n\t\tlet isInvalid;\n\n\t\tif ( data.node ) {\n\t\t\t// When applying, a definition cannot have \"tag\" and \"text\" at the same time.\n\t\t\tisInvalid = this.tag && this.text;\n\t\t} else {\n\t\t\t// When rendering, a definition must have either \"tag\" or \"text\": XOR( this.tag, this.text ).\n\t\t\tisInvalid = this.tag ? this.text : !this.text;\n\t\t}\n\n\t\tif ( isInvalid ) {\n\t\t\t/**\n\t\t\t * Node definition cannot have the \"tag\" and \"text\" properties at the same time.\n\t\t\t * Node definition must have either \"tag\" or \"text\" when rendering a new Node.\n\t\t\t *\n\t\t\t * @error ui-template-wrong-syntax\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'ui-template-wrong-syntax',\n\t\t\t\tthis\n\t\t\t);\n\t\t}\n\n\t\tif ( this.text ) {\n\t\t\treturn this._renderText( data );\n\t\t} else {\n\t\t\treturn this._renderElement( data );\n\t\t}\n\t}\n\n\t/**\n\t * Renders an HTML element out of the template.\n\t *\n\t * @protected\n\t * @param {module:ui/template~RenderData} data Rendering data.\n\t */\n\t_renderElement( data ) {\n\t\tlet node = data.node;\n\n\t\tif ( !node ) {\n\t\t\tnode = data.node = document.createElementNS( this.ns || xhtmlNs, this.tag );\n\t\t}\n\n\t\tthis._renderAttributes( data );\n\t\tthis._renderElementChildren( data );\n\t\tthis._setUpListeners( data );\n\n\t\treturn node;\n\t}\n\n\t/**\n\t * Renders a text node out of {@link module:ui/template~Template#text}.\n\t *\n\t * @protected\n\t * @param {module:ui/template~RenderData} data Rendering data.\n\t */\n\t_renderText( data ) {\n\t\tlet node = data.node;\n\n\t\t// Save the original textContent to revert it in #revert().\n\t\tif ( node ) {\n\t\t\tdata.revertData.text = node.textContent;\n\t\t} else {\n\t\t\tnode = data.node = document.createTextNode( '' );\n\t\t}\n\n\t\t// Check if this Text Node is bound to Observable. Cases:\n\t\t//\n\t\t//\t\ttext: [ Template.bind( ... ).to( ... ) ]\n\t\t//\n\t\t//\t\ttext: [\n\t\t//\t\t\t'foo',\n\t\t//\t\t\tTemplate.bind( ... ).to( ... ),\n\t\t//\t\t\t...\n\t\t//\t\t]\n\t\t//\n\t\tif ( hasTemplateBinding( this.text ) ) {\n\t\t\tthis._bindToObservable( {\n\t\t\t\tschema: this.text,\n\t\t\t\tupdater: getTextUpdater( node ),\n\t\t\t\tdata\n\t\t\t} );\n\t\t}\n\t\t// Simply set text. Cases:\n\t\t//\n\t\t//\t\ttext: [ 'all', 'are', 'static' ]\n\t\t//\n\t\t//\t\ttext: [ 'foo' ]\n\t\t//\n\t\telse {\n\t\t\tnode.textContent = this.text.join( '' );\n\t\t}\n\n\t\treturn node;\n\t}\n\n\t/**\n\t * Renders HTML element attributes out of {@link module:ui/template~Template#attributes}.\n\t *\n\t * @protected\n\t * @param {module:ui/template~RenderData} data Rendering data.\n\t */\n\t_renderAttributes( data ) {\n\t\tlet attrName, attrValue, domAttrValue, attrNs;\n\n\t\tif ( !this.attributes ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst node = data.node;\n\t\tconst revertData = data.revertData;\n\n\t\tfor ( attrName in this.attributes ) {\n\t\t\t// Current attribute value in DOM.\n\t\t\tdomAttrValue = node.getAttribute( attrName );\n\n\t\t\t// The value to be set.\n\t\t\tattrValue = this.attributes[ attrName ];\n\n\t\t\t// Save revert data.\n\t\t\tif ( revertData ) {\n\t\t\t\trevertData.attributes[ attrName ] = domAttrValue;\n\t\t\t}\n\n\t\t\t// Detect custom namespace:\n\t\t\t//\n\t\t\t//\t\tclass: {\n\t\t\t//\t\t\tns: 'abc',\n\t\t\t//\t\t\tvalue: Template.bind( ... ).to( ... )\n\t\t\t//\t\t}\n\t\t\t//\n\t\t\tattrNs = ( isObject( attrValue[ 0 ] ) && attrValue[ 0 ].ns ) ? attrValue[ 0 ].ns : null;\n\n\t\t\t// Activate binding if one is found. Cases:\n\t\t\t//\n\t\t\t//\t\tclass: [\n\t\t\t//\t\t\tTemplate.bind( ... ).to( ... )\n\t\t\t//\t\t]\n\t\t\t//\n\t\t\t//\t\tclass: [\n\t\t\t//\t\t\t'bar',\n\t\t\t//\t\t\tTemplate.bind( ... ).to( ... ),\n\t\t\t//\t\t\t'baz'\n\t\t\t//\t\t]\n\t\t\t//\n\t\t\t//\t\tclass: {\n\t\t\t//\t\t\tns: 'abc',\n\t\t\t//\t\t\tvalue: Template.bind( ... ).to( ... )\n\t\t\t//\t\t}\n\t\t\t//\n\t\t\tif ( hasTemplateBinding( attrValue ) ) {\n\t\t\t\t// Normalize attributes with additional data like namespace:\n\t\t\t\t//\n\t\t\t\t//\t\tclass: {\n\t\t\t\t//\t\t\tns: 'abc',\n\t\t\t\t//\t\t\tvalue: [ ... ]\n\t\t\t\t//\t\t}\n\t\t\t\t//\n\t\t\t\tconst valueToBind = attrNs ? attrValue[ 0 ].value : attrValue;\n\n\t\t\t\t// Extend the original value of attributes like \"style\" and \"class\",\n\t\t\t\t// don't override them.\n\t\t\t\tif ( revertData && shouldExtend( attrName ) ) {\n\t\t\t\t\tvalueToBind.unshift( domAttrValue );\n\t\t\t\t}\n\n\t\t\t\tthis._bindToObservable( {\n\t\t\t\t\tschema: valueToBind,\n\t\t\t\t\tupdater: getAttributeUpdater( node, attrName, attrNs ),\n\t\t\t\t\tdata\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\t// Style attribute could be an Object so it needs to be parsed in a specific way.\n\t\t\t//\n\t\t\t//\t\tstyle: {\n\t\t\t//\t\t\twidth: '100px',\n\t\t\t//\t\t\theight: Template.bind( ... ).to( ... )\n\t\t\t//\t\t}\n\t\t\t//\n\t\t\telse if ( attrName == 'style' && typeof attrValue[ 0 ] !== 'string' ) {\n\t\t\t\tthis._renderStyleAttribute( attrValue[ 0 ], data );\n\t\t\t}\n\n\t\t\t// Otherwise simply set the static attribute:\n\t\t\t//\n\t\t\t//\t\tclass: [ 'foo' ]\n\t\t\t//\n\t\t\t//\t\tclass: [ 'all', 'are', 'static' ]\n\t\t\t//\n\t\t\t//\t\tclass: [\n\t\t\t//\t\t\t{\n\t\t\t//\t\t\t\tns: 'abc',\n\t\t\t//\t\t\t\tvalue: [ 'foo' ]\n\t\t\t//\t\t\t}\n\t\t\t//\t\t]\n\t\t\t//\n\t\t\telse {\n\t\t\t\t// Extend the original value of attributes like \"style\" and \"class\",\n\t\t\t\t// don't override them.\n\t\t\t\tif ( revertData && domAttrValue && shouldExtend( attrName ) ) {\n\t\t\t\t\tattrValue.unshift( domAttrValue );\n\t\t\t\t}\n\n\t\t\t\tattrValue = attrValue\n\t\t\t\t\t// Retrieve \"values\" from:\n\t\t\t\t\t//\n\t\t\t\t\t//\t\tclass: [\n\t\t\t\t\t//\t\t\t{\n\t\t\t\t\t//\t\t\t\tns: 'abc',\n\t\t\t\t\t//\t\t\t\tvalue: [ ... ]\n\t\t\t\t\t//\t\t\t}\n\t\t\t\t\t//\t\t]\n\t\t\t\t\t//\n\t\t\t\t\t.map( val => val ? ( val.value || val ) : val )\n\t\t\t\t\t// Flatten the array.\n\t\t\t\t\t.reduce( ( prev, next ) => prev.concat( next ), [] )\n\t\t\t\t\t// Convert into string.\n\t\t\t\t\t.reduce( arrayValueReducer, '' );\n\n\t\t\t\tif ( !isFalsy( attrValue ) ) {\n\t\t\t\t\tnode.setAttributeNS( attrNs, attrName, attrValue );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Renders the `style` attribute of an HTML element based on\n\t * {@link module:ui/template~Template#attributes}.\n\t *\n\t * A style attribute is an {Object} with static values:\n\t *\n\t *\t\tattributes: {\n\t *\t\t\tstyle: {\n\t *\t\t\t\tcolor: 'red'\n\t *\t\t\t}\n\t *\t\t}\n\t *\n\t * or values bound to {@link module:ui/model~Model} properties:\n\t *\n\t *\t\tattributes: {\n\t *\t\t\tstyle: {\n\t *\t\t\t\tcolor: bind.to( ... )\n\t *\t\t\t}\n\t *\t\t}\n\t *\n\t * Note: The `style` attribute is rendered without setting the namespace. It does not seem to be\n\t * needed.\n\t *\n\t * @private\n\t * @param {Object} styles Styles located in `attributes.style` of {@link module:ui/template~TemplateDefinition}.\n\t * @param {module:ui/template~RenderData} data Rendering data.\n\t */\n\t_renderStyleAttribute( styles, data ) {\n\t\tconst node = data.node;\n\n\t\tfor ( const styleName in styles ) {\n\t\t\tconst styleValue = styles[ styleName ];\n\n\t\t\t// Cases:\n\t\t\t//\n\t\t\t//\t\tstyle: {\n\t\t\t//\t\t\tcolor: bind.to( 'attribute' )\n\t\t\t//\t\t}\n\t\t\t//\n\t\t\tif ( hasTemplateBinding( styleValue ) ) {\n\t\t\t\tthis._bindToObservable( {\n\t\t\t\t\tschema: [ styleValue ],\n\t\t\t\t\tupdater: getStyleUpdater( node, styleName ),\n\t\t\t\t\tdata\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\t// Cases:\n\t\t\t//\n\t\t\t//\t\tstyle: {\n\t\t\t//\t\t\tcolor: 'red'\n\t\t\t//\t\t}\n\t\t\t//\n\t\t\telse {\n\t\t\t\tnode.style[ styleName ] = styleValue;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Recursively renders HTML element's children from {@link module:ui/template~Template#children}.\n\t *\n\t * @protected\n\t * @param {module:ui/template~RenderData} data Rendering data.\n\t */\n\t_renderElementChildren( data ) {\n\t\tconst node = data.node;\n\t\tconst container = data.intoFragment ? document.createDocumentFragment() : node;\n\t\tconst isApplying = data.isApplying;\n\t\tlet childIndex = 0;\n\n\t\tfor ( const child of this.children ) {\n\t\t\tif ( isViewCollection( child ) ) {\n\t\t\t\tif ( !isApplying ) {\n\t\t\t\t\tchild.setParent( node );\n\n\t\t\t\t\t// Note: ViewCollection renders its children.\n\t\t\t\t\tfor ( const view of child ) {\n\t\t\t\t\t\tcontainer.appendChild( view.element );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if ( isView( child ) ) {\n\t\t\t\tif ( !isApplying ) {\n\t\t\t\t\tif ( !child.isRendered ) {\n\t\t\t\t\t\tchild.render();\n\t\t\t\t\t}\n\n\t\t\t\t\tcontainer.appendChild( child.element );\n\t\t\t\t}\n\t\t\t} else if ( isNode( child ) ) {\n\t\t\t\tcontainer.appendChild( child );\n\t\t\t} else {\n\t\t\t\tif ( isApplying ) {\n\t\t\t\t\tconst revertData = data.revertData;\n\t\t\t\t\tconst childRevertData = getEmptyRevertData();\n\n\t\t\t\t\trevertData.children.push( childRevertData );\n\n\t\t\t\t\tchild._renderNode( {\n\t\t\t\t\t\tnode: container.childNodes[ childIndex++ ],\n\t\t\t\t\t\tisApplying: true,\n\t\t\t\t\t\trevertData: childRevertData\n\t\t\t\t\t} );\n\t\t\t\t} else {\n\t\t\t\t\tcontainer.appendChild( child.render() );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif ( data.intoFragment ) {\n\t\t\tnode.appendChild( container );\n\t\t}\n\t}\n\n\t/**\n\t * Activates `on` event listeners from the {@link module:ui/template~TemplateDefinition}\n\t * on an HTML element.\n\t *\n\t * @protected\n\t * @param {module:ui/template~RenderData} data Rendering data.\n\t */\n\t_setUpListeners( data ) {\n\t\tif ( !this.eventListeners ) {\n\t\t\treturn;\n\t\t}\n\n\t\tfor ( const key in this.eventListeners ) {\n\t\t\tconst revertBindings = this.eventListeners[ key ].map( schemaItem => {\n\t\t\t\tconst [ domEvtName, domSelector ] = key.split( '@' );\n\n\t\t\t\treturn schemaItem.activateDomEventListener( domEvtName, domSelector, data );\n\t\t\t} );\n\n\t\t\tif ( data.revertData ) {\n\t\t\t\tdata.revertData.bindings.push( revertBindings );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * For a given {@link module:ui/template~TemplateValueSchema} containing {@link module:ui/template~TemplateBinding}\n\t * activates the binding and sets its initial value.\n\t *\n\t * Note: {@link module:ui/template~TemplateValueSchema} can be for HTML element attributes or\n\t * text node `textContent`.\n\t *\n\t * @protected\n\t * @param {Object} options Binding options.\n\t * @param {module:ui/template~TemplateValueSchema} options.schema\n\t * @param {Function} options.updater A function which updates the DOM (like attribute or text).\n\t * @param {module:ui/template~RenderData} options.data Rendering data.\n\t */\n\t_bindToObservable( { schema, updater, data } ) {\n\t\tconst revertData = data.revertData;\n\n\t\t// Set initial values.\n\t\tsyncValueSchemaValue( schema, updater, data );\n\n\t\tconst revertBindings = schema\n\t\t\t// Filter \"falsy\" (false, undefined, null, '') value schema components out.\n\t\t\t.filter( item => !isFalsy( item ) )\n\t\t\t// Filter inactive bindings from schema, like static strings ('foo'), numbers (42), etc.\n\t\t\t.filter( item => item.observable )\n\t\t\t// Once only the actual binding are left, let the emitter listen to observable change:attribute event.\n\t\t\t// TODO: Reduce the number of listeners attached as many bindings may listen\n\t\t\t// to the same observable attribute.\n\t\t\t.map( templateBinding => templateBinding.activateAttributeListener( schema, updater, data ) );\n\n\t\tif ( revertData ) {\n\t\t\trevertData.bindings.push( revertBindings );\n\t\t}\n\t}\n\n\t/**\n\t * Reverts {@link module:ui/template~RenderData#revertData template data} from a node to\n\t * return it to the original state.\n\t *\n\t * @protected\n\t * @param {HTMLElement|Text} node A node to be reverted.\n\t * @param {Object} revertData An object that stores information about what changes have been made by\n\t * {@link #apply} to the node. See {@link module:ui/template~RenderData#revertData} for more information.\n\t */\n\t_revertTemplateFromNode( node, revertData ) {\n\t\tfor ( const binding of revertData.bindings ) {\n\t\t\t// Each binding may consist of several observable+observable#attribute.\n\t\t\t// like the following has 2:\n\t\t\t//\n\t\t\t//\t\tclass: [\n\t\t\t//\t\t\t'x',\n\t\t\t//\t\t\tbind.to( 'foo' ),\n\t\t\t//\t\t\t'y',\n\t\t\t//\t\t\tbind.to( 'bar' )\n\t\t\t//\t\t]\n\t\t\t//\n\t\t\tfor ( const revertBinding of binding ) {\n\t\t\t\trevertBinding();\n\t\t\t}\n\t\t}\n\n\t\tif ( revertData.text ) {\n\t\t\tnode.textContent = revertData.text;\n\n\t\t\treturn;\n\t\t}\n\n\t\tfor ( const attrName in revertData.attributes ) {\n\t\t\tconst attrValue = revertData.attributes[ attrName ];\n\n\t\t\t// When the attribute has **not** been set before #apply().\n\t\t\tif ( attrValue === null ) {\n\t\t\t\tnode.removeAttribute( attrName );\n\t\t\t} else {\n\t\t\t\tnode.setAttribute( attrName, attrValue );\n\t\t\t}\n\t\t}\n\n\t\tfor ( let i = 0; i < revertData.children.length; ++i ) {\n\t\t\tthis._revertTemplateFromNode( node.childNodes[ i ], revertData.children[ i ] );\n\t\t}\n\t}\n}\n\nmix( Template, EmitterMixin );\n\n/**\n * Describes a binding created by the {@link module:ui/template~Template.bind} interface.\n *\n * @protected\n */\nexport class TemplateBinding {\n\t/**\n\t * Creates an instance of the {@link module:ui/template~TemplateBinding} class.\n\t *\n\t * @param {module:ui/template~TemplateDefinition} def The definition of the binding.\n\t */\n\tconstructor( def ) {\n\t\tObject.assign( this, def );\n\n\t\t/**\n\t\t * An observable instance of the binding. It either:\n\t\t *\n\t\t * * provides the attribute with the value,\n\t\t * * or passes the event when a corresponding DOM event is fired.\n\t\t *\n\t\t * @member {module:utils/observablemixin~ObservableMixin} module:ui/template~TemplateBinding#observable\n\t\t */\n\n\t\t/**\n\t\t * An {@link module:utils/emittermixin~Emitter} used by the binding to:\n\t\t *\n\t\t * * listen to the attribute change in the {@link module:ui/template~TemplateBinding#observable},\n\t\t * * or listen to the event in the DOM.\n\t\t *\n\t\t * @member {module:utils/emittermixin~EmitterMixin} module:ui/template~TemplateBinding#emitter\n\t\t */\n\n\t\t/**\n\t\t * The name of the {@link module:ui/template~TemplateBinding#observable observed attribute}.\n\t\t *\n\t\t * @member {String} module:ui/template~TemplateBinding#attribute\n\t\t */\n\n\t\t/**\n\t\t * A custom function to process the value of the {@link module:ui/template~TemplateBinding#attribute}.\n\t\t *\n\t\t * @member {Function} [module:ui/template~TemplateBinding#callback]\n\t\t */\n\t}\n\n\t/**\n\t * Returns the value of the binding. It is the value of the {@link module:ui/template~TemplateBinding#attribute} in\n\t * {@link module:ui/template~TemplateBinding#observable}. The value may be processed by the\n\t * {@link module:ui/template~TemplateBinding#callback}, if such has been passed to the binding.\n\t *\n\t * @param {Node} [node] A native DOM node, passed to the custom {@link module:ui/template~TemplateBinding#callback}.\n\t * @returns {*} The value of {@link module:ui/template~TemplateBinding#attribute} in\n\t * {@link module:ui/template~TemplateBinding#observable}.\n\t */\n\tgetValue( node ) {\n\t\tconst value = this.observable[ this.attribute ];\n\n\t\treturn this.callback ? this.callback( value, node ) : value;\n\t}\n\n\t/**\n\t * Activates the listener which waits for changes of the {@link module:ui/template~TemplateBinding#attribute} in\n\t * {@link module:ui/template~TemplateBinding#observable}, then updates the DOM with the aggregated\n\t * value of {@link module:ui/template~TemplateValueSchema}.\n\t *\n\t * @param {module:ui/template~TemplateValueSchema} schema A full schema to generate an attribute or text in the DOM.\n\t * @param {Function} updater A DOM updater function used to update the native DOM attribute or text.\n\t * @param {module:ui/template~RenderData} data Rendering data.\n\t * @returns {Function} A function to sever the listener binding.\n\t */\n\tactivateAttributeListener( schema, updater, data ) {\n\t\tconst callback = () => syncValueSchemaValue( schema, updater, data );\n\n\t\tthis.emitter.listenTo( this.observable, 'change:' + this.attribute, callback );\n\n\t\t// Allows revert of the listener.\n\t\treturn () => {\n\t\t\tthis.emitter.stopListening( this.observable, 'change:' + this.attribute, callback );\n\t\t};\n\t}\n}\n\n/**\n * Describes either:\n *\n * * a binding to an {@link module:utils/observablemixin~Observable},\n * * or a native DOM event binding.\n *\n * It is created by the {@link module:ui/template~BindChain#to} method.\n *\n * @protected\n */\nexport class TemplateToBinding extends TemplateBinding {\n\t/**\n\t * Activates the listener for the native DOM event, which when fired, is propagated by\n\t * the {@link module:ui/template~TemplateBinding#emitter}.\n\t *\n\t * @param {String} domEvtName The name of the native DOM event.\n\t * @param {String} domSelector The selector in the DOM to filter delegated events.\n\t * @param {module:ui/template~RenderData} data Rendering data.\n\t * @returns {Function} A function to sever the listener binding.\n\t */\n\tactivateDomEventListener( domEvtName, domSelector, data ) {\n\t\tconst callback = ( evt, domEvt ) => {\n\t\t\tif ( !domSelector || domEvt.target.matches( domSelector ) ) {\n\t\t\t\tif ( typeof this.eventNameOrFunction == 'function' ) {\n\t\t\t\t\tthis.eventNameOrFunction( domEvt );\n\t\t\t\t} else {\n\t\t\t\t\tthis.observable.fire( this.eventNameOrFunction, domEvt );\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tthis.emitter.listenTo( data.node, domEvtName, callback );\n\n\t\t// Allows revert of the listener.\n\t\treturn () => {\n\t\t\tthis.emitter.stopListening( data.node, domEvtName, callback );\n\t\t};\n\t}\n}\n\n/**\n * Describes a binding to {@link module:utils/observablemixin~ObservableMixin} created by the {@link module:ui/template~BindChain#if}\n * method.\n *\n * @protected\n */\nexport class TemplateIfBinding extends TemplateBinding {\n\t/**\n\t * @inheritDoc\n\t */\n\tgetValue( node ) {\n\t\tconst value = super.getValue( node );\n\n\t\treturn isFalsy( value ) ? false : ( this.valueIfTrue || true );\n\t}\n\n\t/**\n\t * The value of the DOM attribute or text to be set if the {@link module:ui/template~TemplateBinding#attribute} in\n\t * {@link module:ui/template~TemplateBinding#observable} is `true`.\n\t *\n\t * @member {String} [module:ui/template~TemplateIfBinding#valueIfTrue]\n\t */\n}\n\n// Checks whether given {@link module:ui/template~TemplateValueSchema} contains a\n// {@link module:ui/template~TemplateBinding}.\n//\n// @param {module:ui/template~TemplateValueSchema} schema\n// @returns {Boolean}\nfunction hasTemplateBinding( schema ) {\n\tif ( !schema ) {\n\t\treturn false;\n\t}\n\n\t// Normalize attributes with additional data like namespace:\n\t//\n\t//\t\tclass: {\n\t//\t\t\tns: 'abc',\n\t//\t\t\tvalue: [ ... ]\n\t//\t\t}\n\t//\n\tif ( schema.value ) {\n\t\tschema = schema.value;\n\t}\n\n\tif ( Array.isArray( schema ) ) {\n\t\treturn schema.some( hasTemplateBinding );\n\t} else if ( schema instanceof TemplateBinding ) {\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\n// Assembles the value using {@link module:ui/template~TemplateValueSchema} and stores it in a form of\n// an Array. Each entry of the Array corresponds to one of {@link module:ui/template~TemplateValueSchema}\n// items.\n//\n// @param {module:ui/template~TemplateValueSchema} schema\n// @param {Node} node DOM Node updated when {@link module:utils/observablemixin~ObservableMixin} changes.\n// @returns {Array}\nfunction getValueSchemaValue( schema, node ) {\n\treturn schema.map( schemaItem => {\n\t\t// Process {@link module:ui/template~TemplateBinding} bindings.\n\t\tif ( schemaItem instanceof TemplateBinding ) {\n\t\t\treturn schemaItem.getValue( node );\n\t\t}\n\n\t\t// All static values like strings, numbers, and \"falsy\" values (false, null, undefined, '', etc.) just pass.\n\t\treturn schemaItem;\n\t} );\n}\n\n// A function executed each time the bound Observable attribute changes, which updates the DOM with a value\n// constructed from {@link module:ui/template~TemplateValueSchema}.\n//\n// @param {module:ui/template~TemplateValueSchema} schema\n// @param {Function} updater A function which updates the DOM (like attribute or text).\n// @param {Node} node DOM Node updated when {@link module:utils/observablemixin~ObservableMixin} changes.\nfunction syncValueSchemaValue( schema, updater, { node } ) {\n\tlet value = getValueSchemaValue( schema, node );\n\n\t// Check if schema is a single Template.bind.if, like:\n\t//\n\t//\t\tclass: Template.bind.if( 'foo' )\n\t//\n\tif ( schema.length == 1 && schema[ 0 ] instanceof TemplateIfBinding ) {\n\t\tvalue = value[ 0 ];\n\t} else {\n\t\tvalue = value.reduce( arrayValueReducer, '' );\n\t}\n\n\tif ( isFalsy( value ) ) {\n\t\tupdater.remove();\n\t} else {\n\t\tupdater.set( value );\n\t}\n}\n\n// Returns an object consisting of `set` and `remove` functions, which\n// can be used in the context of DOM Node to set or reset `textContent`.\n// @see module:ui/view~View#_bindToObservable\n//\n// @param {Node} node DOM Node to be modified.\n// @returns {Object}\nfunction getTextUpdater( node ) {\n\treturn {\n\t\tset( value ) {\n\t\t\tnode.textContent = value;\n\t\t},\n\n\t\tremove() {\n\t\t\tnode.textContent = '';\n\t\t}\n\t};\n}\n\n// Returns an object consisting of `set` and `remove` functions, which\n// can be used in the context of DOM Node to set or reset an attribute.\n// @see module:ui/view~View#_bindToObservable\n//\n// @param {Node} node DOM Node to be modified.\n// @param {String} attrName Name of the attribute to be modified.\n// @param {String} [ns=null] Namespace to use.\n// @returns {Object}\nfunction getAttributeUpdater( el, attrName, ns ) {\n\treturn {\n\t\tset( value ) {\n\t\t\tel.setAttributeNS( ns, attrName, value );\n\t\t},\n\n\t\tremove() {\n\t\t\tel.removeAttributeNS( ns, attrName );\n\t\t}\n\t};\n}\n\n// Returns an object consisting of `set` and `remove` functions, which\n// can be used in the context of CSSStyleDeclaration to set or remove a style.\n// @see module:ui/view~View#_bindToObservable\n//\n// @param {Node} node DOM Node to be modified.\n// @param {String} styleName Name of the style to be modified.\n// @returns {Object}\nfunction getStyleUpdater( el, styleName ) {\n\treturn {\n\t\tset( value ) {\n\t\t\tel.style[ styleName ] = value;\n\t\t},\n\n\t\tremove() {\n\t\t\tel.style[ styleName ] = null;\n\t\t}\n\t};\n}\n\n// Clones definition of the template.\n//\n// @param {module:ui/template~TemplateDefinition} def\n// @returns {module:ui/template~TemplateDefinition}\nfunction clone( def ) {\n\tconst clone = cloneDeepWith( def, value => {\n\t\t// Don't clone the `Template.bind`* bindings because of the references to Observable\n\t\t// and DomEmitterMixin instances inside, which would also be traversed and cloned by greedy\n\t\t// cloneDeepWith algorithm. There's no point in cloning Observable/DomEmitterMixins\n\t\t// along with the definition.\n\t\t//\n\t\t// Don't clone Template instances if provided as a child. They're simply #render()ed\n\t\t// and nothing should interfere.\n\t\t//\n\t\t// Also don't clone View instances if provided as a child of the Template. The template\n\t\t// instance will be extracted from the View during the normalization and there's no need\n\t\t// to clone it.\n\t\tif ( value && ( value instanceof TemplateBinding || isTemplate( value ) || isView( value ) || isViewCollection( value ) ) ) {\n\t\t\treturn value;\n\t\t}\n\t} );\n\n\treturn clone;\n}\n\n// Normalizes given {@link module:ui/template~TemplateDefinition}.\n//\n// See:\n// * {@link normalizeAttributes}\n// * {@link normalizeListeners}\n// * {@link normalizePlainTextDefinition}\n// * {@link normalizeTextDefinition}\n//\n// @param {module:ui/template~TemplateDefinition} def\n// @returns {module:ui/template~TemplateDefinition} Normalized definition.\nfunction normalize( def ) {\n\tif ( typeof def == 'string' ) {\n\t\tdef = normalizePlainTextDefinition( def );\n\t} else if ( def.text ) {\n\t\tnormalizeTextDefinition( def );\n\t}\n\n\tif ( def.on ) {\n\t\tdef.eventListeners = normalizeListeners( def.on );\n\n\t\t// Template mixes EmitterMixin, so delete #on to avoid collision.\n\t\tdelete def.on;\n\t}\n\n\tif ( !def.text ) {\n\t\tif ( def.attributes ) {\n\t\t\tnormalizeAttributes( def.attributes );\n\t\t}\n\n\t\tconst children = [];\n\n\t\tif ( def.children ) {\n\t\t\tif ( isViewCollection( def.children ) ) {\n\t\t\t\tchildren.push( def.children );\n\t\t\t} else {\n\t\t\t\tfor ( const child of def.children ) {\n\t\t\t\t\tif ( isTemplate( child ) || isView( child ) || isNode( child ) ) {\n\t\t\t\t\t\tchildren.push( child );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tchildren.push( new Template( child ) );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tdef.children = children;\n\t}\n\n\treturn def;\n}\n\n// Normalizes \"attributes\" section of {@link module:ui/template~TemplateDefinition}.\n//\n//\t\tattributes: {\n//\t\t\ta: 'bar',\n//\t\t\tb: {@link module:ui/template~TemplateBinding},\n//\t\t\tc: {\n//\t\t\t\tvalue: 'bar'\n//\t\t\t}\n//\t\t}\n//\n// becomes\n//\n//\t\tattributes: {\n//\t\t\ta: [ 'bar' ],\n//\t\t\tb: [ {@link module:ui/template~TemplateBinding} ],\n//\t\t\tc: {\n//\t\t\t\tvalue: [ 'bar' ]\n//\t\t\t}\n//\t\t}\n//\n// @param {Object} attributes\nfunction normalizeAttributes( attributes ) {\n\tfor ( const a in attributes ) {\n\t\tif ( attributes[ a ].value ) {\n\t\t\tattributes[ a ].value = toArray( attributes[ a ].value );\n\t\t}\n\n\t\tarrayify( attributes, a );\n\t}\n}\n\n// Normalizes \"on\" section of {@link module:ui/template~TemplateDefinition}.\n//\n//\t\ton: {\n//\t\t\ta: 'bar',\n//\t\t\tb: {@link module:ui/template~TemplateBinding},\n//\t\t\tc: [ {@link module:ui/template~TemplateBinding}, () => { ... } ]\n//\t\t}\n//\n// becomes\n//\n//\t\ton: {\n//\t\t\ta: [ 'bar' ],\n//\t\t\tb: [ {@link module:ui/template~TemplateBinding} ],\n//\t\t\tc: [ {@link module:ui/template~TemplateBinding}, () => { ... } ]\n//\t\t}\n//\n// @param {Object} listeners\n// @returns {Object} Object containing normalized listeners.\nfunction normalizeListeners( listeners ) {\n\tfor ( const l in listeners ) {\n\t\tarrayify( listeners, l );\n\t}\n\n\treturn listeners;\n}\n\n// Normalizes \"string\" {@link module:ui/template~TemplateDefinition}.\n//\n//\t\t\"foo\"\n//\n// becomes\n//\n//\t\t{ text: [ 'foo' ] },\n//\n// @param {String} def\n// @returns {module:ui/template~TemplateDefinition} Normalized template definition.\nfunction normalizePlainTextDefinition( def ) {\n\treturn {\n\t\ttext: [ def ]\n\t};\n}\n\n// Normalizes text {@link module:ui/template~TemplateDefinition}.\n//\n//\t\tchildren: [\n//\t\t\t{ text: 'def' },\n//\t\t\t{ text: {@link module:ui/template~TemplateBinding} }\n//\t\t]\n//\n// becomes\n//\n//\t\tchildren: [\n//\t\t\t{ text: [ 'def' ] },\n//\t\t\t{ text: [ {@link module:ui/template~TemplateBinding} ] }\n//\t\t]\n//\n// @param {module:ui/template~TemplateDefinition} def\nfunction normalizeTextDefinition( def ) {\n\tdef.text = toArray( def.text );\n}\n\n// Wraps an entry in Object in an Array, if not already one.\n//\n//\t\t{\n//\t\t\tx: 'y',\n//\t\t\ta: [ 'b' ]\n//\t\t}\n//\n// becomes\n//\n//\t\t{\n//\t\t\tx: [ 'y' ],\n//\t\t\ta: [ 'b' ]\n//\t\t}\n//\n// @param {Object} obj\n// @param {String} key\nfunction arrayify( obj, key ) {\n\tobj[ key ] = toArray( obj[ key ] );\n}\n\n// A helper which concatenates the value avoiding unwanted\n// leading white spaces.\n//\n// @param {String} prev\n// @param {String} cur\n// @returns {String}\nfunction arrayValueReducer( prev, cur ) {\n\tif ( isFalsy( cur ) ) {\n\t\treturn prev;\n\t} else if ( isFalsy( prev ) ) {\n\t\treturn cur;\n\t} else {\n\t\treturn `${ prev } ${ cur }`;\n\t}\n}\n\n// Extends one object defined in the following format:\n//\n//\t\t{\n//\t\t\tkey1: [Array1],\n//\t\t\tkey2: [Array2],\n//\t\t\t...\n//\t\t\tkeyN: [ArrayN]\n//\t\t}\n//\n// with another object of the same data format.\n//\n// @param {Object} obj Base object.\n// @param {Object} ext Object extending base.\n// @returns {String}\nfunction extendObjectValueArray( obj, ext ) {\n\tfor ( const a in ext ) {\n\t\tif ( obj[ a ] ) {\n\t\t\tobj[ a ].push( ...ext[ a ] );\n\t\t} else {\n\t\t\tobj[ a ] = ext[ a ];\n\t\t}\n\t}\n}\n\n// A helper for {@link module:ui/template~Template#extend}. Recursively extends {@link module:ui/template~Template} instance\n// with content from {@link module:ui/template~TemplateDefinition}. See {@link module:ui/template~Template#extend} to learn more.\n//\n// @param {module:ui/template~Template} def A template instance to be extended.\n// @param {module:ui/template~TemplateDefinition} def A definition which is to extend the template instance.\n// @param {Object} Error context.\nfunction extendTemplate( template, def ) {\n\tif ( def.attributes ) {\n\t\tif ( !template.attributes ) {\n\t\t\ttemplate.attributes = {};\n\t\t}\n\n\t\textendObjectValueArray( template.attributes, def.attributes );\n\t}\n\n\tif ( def.eventListeners ) {\n\t\tif ( !template.eventListeners ) {\n\t\t\ttemplate.eventListeners = {};\n\t\t}\n\n\t\textendObjectValueArray( template.eventListeners, def.eventListeners );\n\t}\n\n\tif ( def.text ) {\n\t\ttemplate.text.push( ...def.text );\n\t}\n\n\tif ( def.children && def.children.length ) {\n\t\tif ( template.children.length != def.children.length ) {\n\t\t\t/**\n\t\t\t * The number of children in extended definition does not match.\n\t\t\t *\n\t\t\t * @error ui-template-extend-children-mismatch\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'ui-template-extend-children-mismatch',\n\t\t\t\ttemplate\n\t\t\t);\n\t\t}\n\n\t\tlet childIndex = 0;\n\n\t\tfor ( const childDef of def.children ) {\n\t\t\textendTemplate( template.children[ childIndex++ ], childDef );\n\t\t}\n\t}\n}\n\n// Checks if value is \"falsy\".\n// Note: 0 (Number) is not \"falsy\" in this context.\n//\n// @private\n// @param {*} value Value to be checked.\nfunction isFalsy( value ) {\n\treturn !value && value !== 0;\n}\n\n// Checks if the item is an instance of {@link module:ui/view~View}\n//\n// @private\n// @param {*} value Value to be checked.\nfunction isView( item ) {\n\treturn item instanceof View;\n}\n\n// Checks if the item is an instance of {@link module:ui/template~Template}\n//\n// @private\n// @param {*} value Value to be checked.\nfunction isTemplate( item ) {\n\treturn item instanceof Template;\n}\n\n// Checks if the item is an instance of {@link module:ui/viewcollection~ViewCollection}\n//\n// @private\n// @param {*} value Value to be checked.\nfunction isViewCollection( item ) {\n\treturn item instanceof ViewCollection;\n}\n\n// Creates an empty skeleton for {@link module:ui/template~Template#revert}\n// data.\n//\n// @private\nfunction getEmptyRevertData() {\n\treturn {\n\t\tchildren: [],\n\t\tbindings: [],\n\t\tattributes: {}\n\t};\n}\n\n// Checks whether an attribute should be extended when\n// {@link module:ui/template~Template#apply} is called.\n//\n// @private\n// @param {String} attrName Attribute name to check.\nfunction shouldExtend( attrName ) {\n\treturn attrName == 'class' || attrName == 'style';\n}\n\n/**\n * A definition of the {@link module:ui/template~Template}. It describes what kind of\n * node a template will render (HTML element or text), attributes of an element, DOM event\n * listeners and children.\n *\n * Also see:\n * * {@link module:ui/template~TemplateValueSchema} to learn about HTML element attributes,\n * * {@link module:ui/template~TemplateListenerSchema} to learn about DOM event listeners.\n *\n * A sample definition on an HTML element can look like this:\n *\n *\t\tnew Template( {\n *\t\t\ttag: 'p',\n *\t\t\tchildren: [\n *\t\t\t\t{\n *\t\t\t\t\ttag: 'span',\n *\t\t\t\t\tattributes: { ... },\n *\t\t\t\t\tchildren: [ ... ],\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\ttext: 'static–text'\n *\t\t\t\t},\n *\t\t\t\t'also-static–text',\n *\t\t\t],\n *\t\t\tattributes: {\n *\t\t\t\tclass: {@link module:ui/template~TemplateValueSchema},\n *\t\t\t\tid: {@link module:ui/template~TemplateValueSchema},\n *\t\t\t\tstyle: {@link module:ui/template~TemplateValueSchema}\n *\n *\t\t\t\t// ...\n *\t\t\t},\n *\t\t\ton: {\n *\t\t\t\t'click': {@link module:ui/template~TemplateListenerSchema}\n *\n *\t\t\t\t// Document.querySelector format is also accepted.\n *\t\t\t\t'keyup@a.some-class': {@link module:ui/template~TemplateListenerSchema}\n *\n *\t\t\t\t// ...\n *\t\t\t}\n *\t\t} );\n *\n * A {@link module:ui/view~View}, another {@link module:ui/template~Template} or a native DOM node\n * can also become a child of a template. When a view is passed, its {@link module:ui/view~View#element} is used:\n *\n *\t\tconst view = new SomeView();\n *\t\tconst childTemplate = new Template( { ... } );\n *\t\tconst childNode = document.createElement( 'b' );\n *\n *\t\tnew Template( {\n *\t\t\ttag: 'p',\n *\n *\t\t\tchildren: [\n *\t\t\t\t// view#element will be added as a child of this

.\n *\t\t\t\tview,\n *\n * \t\t\t\t// The output of childTemplate.render() will be added here.\n *\t\t\t\tchildTemplate,\n *\n *\t\t\t\t// Native DOM nodes are included directly in the rendered output.\n *\t\t\t\tchildNode\n *\t\t\t]\n *\t\t} );\n *\n * An entire {@link module:ui/viewcollection~ViewCollection} can be used as a child in the definition:\n *\n *\t\tconst collection = new ViewCollection();\n *\t\tcollection.add( someView );\n *\n *\t\tnew Template( {\n *\t\t\ttag: 'p',\n *\n *\t\t\tchildren: collection\n *\t\t} );\n *\n * @typedef module:ui/template~TemplateDefinition\n * @type Object\n *\n * @property {String} tag See the template {@link module:ui/template~Template#tag} property.\n *\n * @property {Array.} [children]\n * See the template {@link module:ui/template~Template#children} property.\n *\n * @property {Object.} [attributes]\n * See the template {@link module:ui/template~Template#attributes} property.\n *\n * @property {String|module:ui/template~TemplateValueSchema|Array.} [text]\n * See the template {@link module:ui/template~Template#text} property.\n *\n * @property {Object.} [on]\n * See the template {@link module:ui/template~Template#eventListeners} property.\n */\n\n/**\n * Describes a value of an HTML element attribute or `textContent`. It allows combining multiple\n * data sources like static values and {@link module:utils/observablemixin~Observable} attributes.\n *\n * Also see:\n * * {@link module:ui/template~TemplateDefinition} to learn where to use it,\n * * {@link module:ui/template~Template.bind} to learn how to configure\n * {@link module:utils/observablemixin~Observable} attribute bindings,\n * * {@link module:ui/template~Template#render} to learn how to render a template,\n * * {@link module:ui/template~BindChain#to `to()`} and {@link module:ui/template~BindChain#if `if()`}\n * methods to learn more about bindings.\n *\n * Attribute values can be described in many different ways:\n *\n *\t\t// Bind helper will create bindings to attributes of the observable.\n *\t\tconst bind = Template.bind( observable, emitter );\n *\n *\t\tnew Template( {\n *\t\t\ttag: 'p',\n *\t\t\tattributes: {\n *\t\t\t\t// A plain string schema.\n *\t\t\t\t'class': 'static-text',\n *\n *\t\t\t\t// An object schema, binds to the \"foo\" attribute of the\n *\t\t\t\t// observable and follows its value.\n *\t\t\t\t'class': bind.to( 'foo' ),\n *\n *\t\t\t\t// An array schema, combines the above.\n *\t\t\t\t'class': [\n *\t\t\t\t\t'static-text',\n *\t\t\t\t\tbind.to( 'bar', () => { ... } ),\n *\n * \t\t\t\t\t// Bindings can also be conditional.\n *\t\t\t\t\tbind.if( 'baz', 'class-when-baz-is-true' )\n *\t\t\t\t],\n *\n *\t\t\t\t// An array schema, with a custom namespace, e.g. useful for creating SVGs.\n *\t\t\t\t'class': {\n *\t\t\t\t\tns: 'http://ns.url',\n *\t\t\t\t\tvalue: [\n *\t\t\t\t\t\tbind.if( 'baz', 'value-when-true' ),\n *\t\t\t\t\t\t'static-text'\n *\t\t\t\t\t]\n *\t\t\t\t},\n *\n *\t\t\t\t// An object schema, specific for styles.\n *\t\t\t\tstyle: {\n *\t\t\t\t\tcolor: 'red',\n *\t\t\t\t\tbackgroundColor: bind.to( 'qux', () => { ... } )\n *\t\t\t\t}\n *\t\t\t}\n *\t\t} );\n *\n * Text nodes can also have complex values:\n *\n *\t\tconst bind = Template.bind( observable, emitter );\n *\n *\t\t// Will render a \"foo\" text node.\n *\t\tnew Template( {\n *\t\t\ttext: 'foo'\n *\t\t} );\n *\n *\t\t// Will render a \"static text: {observable.foo}\" text node.\n *\t\t// The text of the node will be updated as the \"foo\" attribute changes.\n *\t\tnew Template( {\n *\t\t\ttext: [\n *\t\t\t\t'static text: ',\n *\t\t\t\tbind.to( 'foo', () => { ... } )\n *\t\t\t]\n *\t\t} );\n *\n * @typedef module:ui/template~TemplateValueSchema\n * @type {Object|String|Array}\n */\n\n/**\n * Describes an event listener attached to an HTML element. Such listener can propagate DOM events\n * through an {@link module:utils/observablemixin~Observable} instance, execute custom callbacks\n * or both, if necessary.\n *\n * Also see:\n * * {@link module:ui/template~TemplateDefinition} to learn more about template definitions,\n * * {@link module:ui/template~BindChain#to `to()`} method to learn more about bindings.\n *\n * Check out different ways of attaching event listeners below:\n *\n *\t\t// Bind helper will propagate events through the observable.\n *\t\tconst bind = Template.bind( observable, emitter );\n *\n *\t\tnew Template( {\n *\t\t\ttag: 'p',\n *\t\t\ton: {\n *\t\t\t\t// An object schema. The observable will fire the \"clicked\" event upon DOM \"click\".\n *\t\t\t\tclick: bind.to( 'clicked' )\n *\n *\t\t\t\t// An object schema. It will work for \"click\" event on \"a.foo\" children only.\n *\t\t\t\t'click@a.foo': bind.to( 'clicked' )\n *\n *\t\t\t\t// An array schema, makes the observable propagate multiple events.\n *\t\t\t\tclick: [\n *\t\t\t\t\tbind.to( 'clicked' ),\n *\t\t\t\t\tbind.to( 'executed' )\n *\t\t\t\t],\n *\n *\t\t\t\t// An array schema with a custom callback.\n *\t\t\t\t'click@a.foo': {\n *\t\t\t\t\tbind.to( 'clicked' ),\n *\t\t\t\t\tbind.to( evt => {\n *\t\t\t\t\t\tconsole.log( `${ evt.target } has been clicked!` );\n *\t\t\t\t\t} }\n *\t\t\t\t}\n *\t\t\t}\n *\t\t} );\n *\n * @typedef module:ui/template~TemplateListenerSchema\n * @type {Object|String|Array}\n */\n\n/**\n * The return value of {@link ~Template.bind `Template.bind()`}. It provides `to()` and `if()`\n * methods to create the {@link module:utils/observablemixin~Observable observable} attribute and event bindings.\n *\n * @interface module:ui/template~BindChain\n */\n\n/**\n * Binds an {@link module:utils/observablemixin~Observable observable} to either:\n *\n * * an HTML element attribute or a text node `textContent`, so it remains in sync with the observable\n * attribute as it changes,\n * * or an HTML element DOM event, so the DOM events are propagated through an observable.\n *\n * Some common use cases of `to()` bindings are presented below:\n *\n *\t\tconst bind = Template.bind( observable, emitter );\n *\n *\t\tnew Template( {\n *\t\t\ttag: 'p',\n *\t\t\tattributes: {\n *\t\t\t\t// class=\"...\" attribute gets bound to `observable#a`\n *\t\t\t\tclass: bind.to( 'a' )\n *\t\t\t},\n *\t\t\tchildren: [\n *\t\t\t\t//

...

gets bound to observable#b; always `toUpperCase()`.\n *\t\t\t\t{\n *\t\t\t\t\ttext: bind.to( 'b', ( value, node ) => value.toUpperCase() )\n *\t\t\t\t}\n *\t\t\t],\n *\t\t\ton: {\n *\t\t\t\tclick: [\n *\t\t\t\t\t// An observable will fire \"clicked\" upon \"click\" in the DOM.\n *\t\t\t\t\tbind.to( 'clicked' ),\n *\n *\t\t\t\t\t// A custom callback will be executed upon \"click\" in the DOM.\n *\t\t\t\t\tbind.to( () => {\n *\t\t\t\t\t\t...\n *\t\t\t\t\t} )\n *\t\t\t\t]\n *\t\t\t}\n *\t\t} ).render();\n *\n * Learn more about using `to()` in the {@link module:ui/template~TemplateValueSchema} and\n * {@link module:ui/template~TemplateListenerSchema}.\n *\n * @method #to\n * @param {String|Function} eventNameOrFunctionOrAttribute An attribute name of\n * {@link module:utils/observablemixin~Observable} or a DOM event name or an event callback.\n * @param {Function} [callback] Allows for processing of the value. Accepts `Node` and `value` as arguments.\n * @returns {module:ui/template~TemplateBinding}\n */\n\n/**\n * Binds an {@link module:utils/observablemixin~Observable observable} to an HTML element attribute or a text\n * node `textContent` so it remains in sync with the observable attribute as it changes.\n *\n * Unlike {@link module:ui/template~BindChain#to}, it controls the presence of the attribute or `textContent`\n * depending on the \"falseness\" of an {@link module:utils/observablemixin~Observable} attribute.\n *\n *\t\tconst bind = Template.bind( observable, emitter );\n *\n *\t\tnew Template( {\n *\t\t\ttag: 'input',\n *\t\t\tattributes: {\n *\t\t\t\t// when `observable#a` is not undefined/null/false/''\n *\t\t\t\t// when `observable#a` is undefined/null/false\n *\t\t\t\tchecked: bind.if( 'a' )\n *\t\t\t},\n *\t\t\tchildren: [\n *\t\t\t\t{\n *\t\t\t\t\t// \"b-is-not-set\" when `observable#b` is undefined/null/false/''\n *\t\t\t\t\t// when `observable#b` is not \"falsy\"\n *\t\t\t\t\ttext: bind.if( 'b', 'b-is-not-set', ( value, node ) => !value )\n *\t\t\t\t}\n *\t\t\t]\n *\t\t} ).render();\n *\n * Learn more about using `if()` in the {@link module:ui/template~TemplateValueSchema}.\n *\n * @method #if\n * @param {String} attribute An attribute name of {@link module:utils/observablemixin~Observable} used in the binding.\n * @param {String} [valueIfTrue] Value set when the {@link module:utils/observablemixin~Observable} attribute is not\n * undefined/null/false/'' (empty string).\n * @param {Function} [callback] Allows for processing of the value. Accepts `Node` and `value` as arguments.\n * @returns {module:ui/template~TemplateBinding}\n */\n\n/**\n * The {@link module:ui/template~Template#_renderNode} configuration.\n *\n * @private\n * @interface module:ui/template~RenderData\n */\n\n/**\n * Tells {@link module:ui/template~Template#_renderNode} to render\n * children into `DocumentFragment` first and then append the fragment\n * to the parent element. It is a speed optimization.\n *\n * @member {Boolean} #intoFragment\n */\n\n/**\n * A node which is being rendered.\n *\n * @member {HTMLElement|Text} #node\n */\n\n/**\n * Indicates whether the {@module:ui/template~RenderNodeOptions#node} has\n * been provided by {@module:ui/template~Template#apply}.\n *\n * @member {Boolean} #isApplying\n */\n\n/**\n * An object storing the data that helps {@module:ui/template~Template#revert}\n * bringing back an element to its initial state, i.e. before\n * {@module:ui/template~Template#apply} was called.\n *\n * @member {Object} #revertData\n */\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md.\n */\n\n/**\n * @module ui/panel/balloon/balloonpanelview\n */\n\nimport View from '../../view';\nimport { getOptimalPosition } from '@ckeditor/ckeditor5-utils/src/dom/position';\nimport isRange from '@ckeditor/ckeditor5-utils/src/dom/isrange';\nimport toUnit from '@ckeditor/ckeditor5-utils/src/dom/tounit';\nimport global from '@ckeditor/ckeditor5-utils/src/dom/global';\nimport { isElement } from 'lodash-es';\n\nimport '../../../theme/components/panel/balloonpanel.css';\n\nconst toPx = toUnit( 'px' );\nconst defaultLimiterElement = global.document.body;\n\n/**\n * The balloon panel view class.\n *\n * A floating container which can\n * {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView#pin pin} to any\n * {@link module:utils/dom/position~Options#target target} in the DOM and remain in that position\n * e.g. when the web page is scrolled.\n *\n * The balloon panel can be used to display contextual, non-blocking UI like forms, toolbars and\n * the like in its {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView#content} view\n * collection.\n *\n * There is a number of {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView.defaultPositions}\n * that the balloon can use, automatically switching from one to another when the viewport space becomes\n * scarce to keep the balloon visible to the user as long as it is possible. The balloon will also\n * accept any custom position set provided by the user compatible with the\n * {@link module:utils/dom/position~Options options}.\n *\n *\t\tconst panel = new BalloonPanelView( locale );\n *\t\tconst childView = new ChildView();\n *\t\tconst positions = BalloonPanelView.defaultPositions;\n *\n *\t\tpanel.render();\n *\n *\t\t// Add a child view to the panel's content collection.\n *\t\tpanel.content.add( childView );\n *\n *\t\t// Start pinning the panel to an element with the \"target\" id DOM.\n *\t\t// The balloon will remain pinned until unpin() is called.\n *\t\tpanel.pin( {\n *\t\t\ttarget: document.querySelector( '#target' ),\n *\t\t\tpositions: [\n *\t\t\t\tpositions.northArrowSouth,\n *\t\t\t\tpositions.southArrowNorth\n *\t\t\t]\n *\t\t} );\n *\n * @extends module:ui/view~View\n */\nexport default class BalloonPanelView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\tconst bind = this.bindTemplate;\n\n\t\t/**\n\t\t * The absolute top position of the balloon panel in pixels.\n\t\t *\n\t\t * @observable\n\t\t * @default 0\n\t\t * @member {Number} #top\n\t\t */\n\t\tthis.set( 'top', 0 );\n\n\t\t/**\n\t\t * The absolute left position of the balloon panel in pixels.\n\t\t *\n\t\t * @observable\n\t\t * @default 0\n\t\t * @member {Number} #left\n\t\t */\n\t\tthis.set( 'left', 0 );\n\n\t\t/**\n\t\t * The balloon panel's current position. The position name is reflected in the CSS class set\n\t\t * to the balloon, i.e. `.ck-balloon-panel_arrow_nw` for the \"arrow_nw\" position. The class\n\t\t * controls the minor aspects of the balloon's visual appearance like the placement\n\t\t * of an {@link #withArrow arrow}. To support a new position, an additional CSS must be created.\n\t\t *\n\t\t * Default position names correspond with\n\t\t * {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView.defaultPositions}.\n\t\t *\n\t\t * See the {@link #attachTo} and {@link #pin} methods to learn about custom balloon positions.\n\t\t *\n\t\t * @observable\n\t\t * @default 'arrow_nw'\n\t\t * @member {'arrow_nw'|'arrow_ne'|'arrow_sw'|'arrow_se'} #position\n\t\t */\n\t\tthis.set( 'position', 'arrow_nw' );\n\n\t\t/**\n\t\t * Controls whether the balloon panel is visible or not.\n\t\t *\n\t\t * @observable\n\t\t * @default false\n\t\t * @member {Boolean} #isVisible\n\t\t */\n\t\tthis.set( 'isVisible', false );\n\n\t\t/**\n\t\t * Controls whether the balloon panel has an arrow. The presence of the arrow\n\t\t * is reflected in the `ck-balloon-panel_with-arrow` CSS class.\n\t\t *\n\t\t * @observable\n\t\t * @default true\n\t\t * @member {Boolean} #withArrow\n\t\t */\n\t\tthis.set( 'withArrow', true );\n\n\t\t/**\n\t\t * An additional CSS class added to the {@link #element}.\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #class\n\t\t */\n\t\tthis.set( 'class' );\n\n\t\t/**\n\t\t * A callback that starts pinning the panel when {@link #isVisible} gets\n\t\t * `true`. Used by {@link #pin}.\n\t\t *\n\t\t * @private\n\t\t * @member {Function} #_pinWhenIsVisibleCallback\n\t\t */\n\n\t\t/**\n\t\t * A collection of the child views that creates the balloon panel contents.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.content = this.createCollection();\n\n\t\tthis.setTemplate( {\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-balloon-panel',\n\t\t\t\t\tbind.to( 'position', value => `ck-balloon-panel_${ value }` ),\n\t\t\t\t\tbind.if( 'isVisible', 'ck-balloon-panel_visible' ),\n\t\t\t\t\tbind.if( 'withArrow', 'ck-balloon-panel_with-arrow' ),\n\t\t\t\t\tbind.to( 'class' )\n\t\t\t\t],\n\n\t\t\t\tstyle: {\n\t\t\t\t\ttop: bind.to( 'top', toPx ),\n\t\t\t\t\tleft: bind.to( 'left', toPx )\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tchildren: this.content\n\t\t} );\n\t}\n\n\t/**\n\t * Shows the panel.\n\t *\n\t * See {@link #isVisible}.\n\t */\n\tshow() {\n\t\tthis.isVisible = true;\n\t}\n\n\t/**\n\t * Hides the panel.\n\t *\n\t * See {@link #isVisible}.\n\t */\n\thide() {\n\t\tthis.isVisible = false;\n\t}\n\n\t/**\n\t * Attaches the panel to a specified {@link module:utils/dom/position~Options#target} with a\n\t * smart positioning heuristics that chooses from available positions to make sure the panel\n\t * is visible to the user i.e. within the limits of the viewport.\n\t *\n\t * This method accepts configuration {@link module:utils/dom/position~Options options}\n\t * to set the `target`, optional `limiter` and `positions` the balloon should choose from.\n\t *\n\t *\t\tconst panel = new BalloonPanelView( locale );\n\t *\t\tconst positions = BalloonPanelView.defaultPositions;\n\t *\n\t *\t\tpanel.render();\n\t *\n\t *\t\t// Attach the panel to an element with the \"target\" id DOM.\n\t *\t\tpanel.attachTo( {\n\t *\t\t\ttarget: document.querySelector( '#target' ),\n\t *\t\t\tpositions: [\n\t *\t\t\t\tpositions.northArrowSouth,\n\t *\t\t\t\tpositions.southArrowNorth\n\t *\t\t\t]\n\t *\t\t} );\n\t *\n\t * **Note**: Attaching the panel will also automatically {@link #show} it.\n\t *\n\t * **Note**: An attached panel will not follow its target when the window is scrolled or resized.\n\t * See the {@link #pin} method for a more permanent positioning strategy.\n\t *\n\t * @param {module:utils/dom/position~Options} options Positioning options compatible with\n\t * {@link module:utils/dom/position~getOptimalPosition}. Default `positions` array is\n\t * {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView.defaultPositions}.\n\t */\n\tattachTo( options ) {\n\t\tthis.show();\n\n\t\tconst defaultPositions = BalloonPanelView.defaultPositions;\n\t\tconst positionOptions = Object.assign( {}, {\n\t\t\telement: this.element,\n\t\t\tpositions: [\n\t\t\t\tdefaultPositions.southArrowNorth,\n\t\t\t\tdefaultPositions.southArrowNorthMiddleWest,\n\t\t\t\tdefaultPositions.southArrowNorthMiddleEast,\n\t\t\t\tdefaultPositions.southArrowNorthWest,\n\t\t\t\tdefaultPositions.southArrowNorthEast,\n\t\t\t\tdefaultPositions.northArrowSouth,\n\t\t\t\tdefaultPositions.northArrowSouthMiddleWest,\n\t\t\t\tdefaultPositions.northArrowSouthMiddleEast,\n\t\t\t\tdefaultPositions.northArrowSouthWest,\n\t\t\t\tdefaultPositions.northArrowSouthEast\n\t\t\t],\n\t\t\tlimiter: defaultLimiterElement,\n\t\t\tfitInViewport: true\n\t\t}, options );\n\n\t\tconst optimalPosition = BalloonPanelView._getOptimalPosition( positionOptions );\n\n\t\t// Usually browsers make some problems with super accurate values like 104.345px\n\t\t// so it is better to use int values.\n\t\tconst left = parseInt( optimalPosition.left );\n\t\tconst top = parseInt( optimalPosition.top );\n\t\tconst position = optimalPosition.name;\n\n\t\tObject.assign( this, { top, left, position } );\n\t}\n\n\t/**\n\t * Works the same way as the {@link #attachTo} method except that the position of the panel is\n\t * continuously updated when:\n\t *\n\t * * any ancestor of the {@link module:utils/dom/position~Options#target}\n\t * or {@link module:utils/dom/position~Options#limiter} is scrolled,\n\t * * the browser window gets resized or scrolled.\n\t *\n\t * Thanks to that, the panel always sticks to the {@link module:utils/dom/position~Options#target}\n\t * and is immune to the changing environment.\n\t *\n\t *\t\tconst panel = new BalloonPanelView( locale );\n\t *\t\tconst positions = BalloonPanelView.defaultPositions;\n\t *\n\t *\t\tpanel.render();\n\t *\n\t *\t\t// Pin the panel to an element with the \"target\" id DOM.\n\t *\t\tpanel.pin( {\n\t *\t\t\ttarget: document.querySelector( '#target' ),\n\t *\t\t\tpositions: [\n\t *\t\t\t\tpositions.northArrowSouth,\n\t *\t\t\t\tpositions.southArrowNorth\n\t *\t\t\t]\n\t *\t\t} );\n\t *\n\t * To leave the pinned state, use the {@link #unpin} method.\n\t *\n\t * **Note**: Pinning the panel will also automatically {@link #show} it.\n\t *\n\t * @param {module:utils/dom/position~Options} options Positioning options compatible with\n\t * {@link module:utils/dom/position~getOptimalPosition}. Default `positions` array is\n\t * {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView.defaultPositions}.\n\t */\n\tpin( options ) {\n\t\tthis.unpin();\n\n\t\tthis._pinWhenIsVisibleCallback = () => {\n\t\t\tif ( this.isVisible ) {\n\t\t\t\tthis._startPinning( options );\n\t\t\t} else {\n\t\t\t\tthis._stopPinning();\n\t\t\t}\n\t\t};\n\n\t\tthis._startPinning( options );\n\n\t\t// Control the state of the listeners depending on whether the panel is visible\n\t\t// or not.\n\t\t// TODO: Use on() (https://github.com/ckeditor/ckeditor5-utils/issues/144).\n\t\tthis.listenTo( this, 'change:isVisible', this._pinWhenIsVisibleCallback );\n\t}\n\n\t/**\n\t * Stops pinning the panel, as set up by {@link #pin}.\n\t */\n\tunpin() {\n\t\tif ( this._pinWhenIsVisibleCallback ) {\n\t\t\t// Deactivate listeners attached by pin().\n\t\t\tthis._stopPinning();\n\n\t\t\t// Deactivate the panel pin() control logic.\n\t\t\t// TODO: Use off() (https://github.com/ckeditor/ckeditor5-utils/issues/144).\n\t\t\tthis.stopListening( this, 'change:isVisible', this._pinWhenIsVisibleCallback );\n\n\t\t\tthis._pinWhenIsVisibleCallback = null;\n\n\t\t\tthis.hide();\n\t\t}\n\t}\n\n\t/**\n\t * Starts managing the pinned state of the panel. See {@link #pin}.\n\t *\n\t * @private\n\t * @param {module:utils/dom/position~Options} options Positioning options compatible with\n\t * {@link module:utils/dom/position~getOptimalPosition}.\n\t */\n\t_startPinning( options ) {\n\t\tthis.attachTo( options );\n\n\t\tconst targetElement = getDomElement( options.target );\n\t\tconst limiterElement = options.limiter ? getDomElement( options.limiter ) : defaultLimiterElement;\n\n\t\t// Then we need to listen on scroll event of eny element in the document.\n\t\tthis.listenTo( global.document, 'scroll', ( evt, domEvt ) => {\n\t\t\tconst scrollTarget = domEvt.target;\n\n\t\t\t// The position needs to be updated if the positioning target is within the scrolled element.\n\t\t\tconst isWithinScrollTarget = targetElement && scrollTarget.contains( targetElement );\n\n\t\t\t// The position needs to be updated if the positioning limiter is within the scrolled element.\n\t\t\tconst isLimiterWithinScrollTarget = limiterElement && scrollTarget.contains( limiterElement );\n\n\t\t\t// The positioning target and/or limiter can be a Rect, object etc..\n\t\t\t// There's no way to optimize the listener then.\n\t\t\tif ( isWithinScrollTarget || isLimiterWithinScrollTarget || !targetElement || !limiterElement ) {\n\t\t\t\tthis.attachTo( options );\n\t\t\t}\n\t\t}, { useCapture: true } );\n\n\t\t// We need to listen on window resize event and update position.\n\t\tthis.listenTo( global.window, 'resize', () => {\n\t\t\tthis.attachTo( options );\n\t\t} );\n\t}\n\n\t/**\n\t * Stops managing the pinned state of the panel. See {@link #pin}.\n\t *\n\t * @private\n\t */\n\t_stopPinning() {\n\t\tthis.stopListening( global.document, 'scroll' );\n\t\tthis.stopListening( global.window, 'resize' );\n\t}\n}\n\n// Returns the DOM element for given object or null, if there is none,\n// e.g. when the passed object is a Rect instance or so.\n//\n// @private\n// @param {*} object\n// @returns {HTMLElement|null}\nfunction getDomElement( object ) {\n\tif ( isElement( object ) ) {\n\t\treturn object;\n\t}\n\n\tif ( isRange( object ) ) {\n\t\treturn object.commonAncestorContainer;\n\t}\n\n\tif ( typeof object == 'function' ) {\n\t\treturn getDomElement( object() );\n\t}\n\n\treturn null;\n}\n\n/**\n * A horizontal offset of the arrow tip from the edge of the balloon. Controlled by CSS.\n *\n *\t\t +-----|---------...\n *\t\t | |\n *\t\t | |\n *\t\t | |\n *\t\t | |\n *\t\t +--+ | +------...\n *\t\t \\ | /\n *\t\t \\|/\n *\t >|-----|<---------------- horizontal offset\n *\n * @default 30\n * @member {Number} module:ui/panel/balloon/balloonpanelview~BalloonPanelView.arrowHorizontalOffset\n */\nBalloonPanelView.arrowHorizontalOffset = 25;\n\n/**\n * A vertical offset of the arrow from the edge of the balloon. Controlled by CSS.\n *\n *\t\t +-------------...\n *\t\t |\n *\t\t |\n *\t\t | /-- vertical offset\n *\t\t | V\n *\t\t +--+ +-----... ---------\n *\t\t \\ / |\n *\t\t \\/ |\n *\t\t-------------------------------\n *\t\t ^\n *\n * @default 15\n * @member {Number} module:ui/panel/balloon/balloonpanelview~BalloonPanelView.arrowVerticalOffset\n */\nBalloonPanelView.arrowVerticalOffset = 10;\n\n/**\n * Function used to calculate the optimal position for the balloon.\n *\n * @protected\n * @member {Function} module:ui/panel/balloon/balloonpanelview~BalloonPanelView._getOptimalPosition\n */\nBalloonPanelView._getOptimalPosition = getOptimalPosition;\n\n/**\n * A default set of positioning functions used by the balloon panel view\n * when attaching using the {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView#attachTo} method.\n *\n * The available positioning functions are as follows:\n *\n *\n *\n * **North west**\n *\n * * `northWestArrowSouthWest`\n *\n *\t\t+-----------------+\n *\t\t| Balloon |\n *\t\t+-----------------+\n *\t\t V\n *\t\t [ Target ]\n *\n * * `northWestArrowSouthMiddleWest`\n *\n *\t\t+-----------------+\n *\t\t| Balloon |\n *\t\t+-----------------+\n *\t\t V\n *\t\t [ Target ]\n *\n * * `northWestArrowSouth`\n *\n *\t\t+-----------------+\n *\t\t| Balloon |\n *\t\t+-----------------+\n *\t\t V\n *\t\t [ Target ]\n *\n * * `northWestArrowSouthMiddleEast`\n *\n *\t\t+-----------------+\n *\t\t| Balloon |\n *\t\t+-----------------+\n *\t\t V\n *\t\t [ Target ]\n *\n * * `northWestArrowSouthEast`\n *\n *\t\t+-----------------+\n *\t\t| Balloon |\n *\t\t+-----------------+\n *\t\t V\n *\t\t [ Target ]\n *\n *\n *\n * **North**\n *\n * * `northArrowSouthWest`\n *\n *\t\t +-----------------+\n *\t\t | Balloon |\n *\t\t +-----------------+\n *\t\t V\n *\t\t[ Target ]\n *\n * * `northArrowSouthMiddleWest`\n *\n *\t\t +-----------------+\n *\t\t | Balloon |\n *\t\t +-----------------+\n *\t\t V\n *\t\t[ Target ]\n *\n * * `northArrowSouth`\n *\n *\t\t+-----------------+\n *\t\t| Balloon |\n *\t\t+-----------------+\n *\t\t V\n *\t\t [ Target ]\n *\n * * `northArrowSouthMiddleEast`\n *\n *\t\t+-----------------+\n *\t\t| Balloon |\n *\t\t+-----------------+\n *\t\t V\n *\t\t [ Target ]\n *\n * * `northArrowSouthEast`\n *\n *\t\t+-----------------+\n *\t\t| Balloon |\n *\t\t+-----------------+\n *\t\t V\n *\t\t [ Target ]\n *\n * **North east**\n *\n * * `northEastArrowSouthWest`\n *\n *\t\t +-----------------+\n *\t\t | Balloon |\n *\t\t +-----------------+\n *\t\t V\n *\t\t[ Target ]\n *\n *\n * * `northEastArrowSouthMiddleWest`\n *\n *\t\t +-----------------+\n *\t\t | Balloon |\n *\t\t +-----------------+\n *\t\t V\n *\t\t[ Target ]\n *\n * * `northEastArrowSouth`\n *\n *\t\t+-----------------+\n *\t\t| Balloon |\n *\t\t+-----------------+\n *\t\t V\n *\t\t[ Target ]\n *\n * * `northEastArrowSouthMiddleEast`\n *\n *\t\t+-----------------+\n *\t\t| Balloon |\n *\t\t+-----------------+\n *\t\t V\n *\t\t [ Target ]\n *\n * * `northEastArrowSouthEast`\n *\n *\t\t+-----------------+\n *\t\t| Balloon |\n *\t\t+-----------------+\n *\t\t V\n *\t\t [ Target ]\n *\n *\n *\n * **South**\n *\n *\n * * `southArrowNorthWest`\n *\n *\t\t[ Target ]\n *\t\t ^\n *\t\t +-----------------+\n *\t\t | Balloon |\n *\t\t +-----------------+\n *\n * * `southArrowNorthMiddleWest`\n *\n *\t\t [ Target ]\n *\t\t ^\n *\t\t +-----------------+\n *\t\t | Balloon |\n *\t\t +-----------------+\n *\n * * `southArrowNorth`\n *\n *\t\t [ Target ]\n *\t\t ^\n *\t\t+-----------------+\n *\t\t| Balloon |\n *\t\t+-----------------+\n *\n * * `southArrowNorthMiddleEast`\n *\n *\t\t [ Target ]\n *\t\t ^\n *\t\t +-----------------+\n *\t\t | Balloon |\n *\t\t +-----------------+\n *\n * * `southArrowNorthEast`\n *\n *\t\t [ Target ]\n *\t\t ^\n *\t\t+-----------------+\n *\t\t| Balloon |\n *\t\t+-----------------+\n *\n *\n *\n * **South west**\n *\n * * `southWestArrowNorthWest`\n *\n *\t\t [ Target ]\n *\t\t ^\n *\t\t+-----------------+\n *\t\t| Balloon |\n *\t\t+-----------------+\n *\n * * `southWestArrowNorthMiddleWest`\n *\n *\t\t [ Target ]\n *\t\t ^\n *\t\t +-----------------+\n *\t\t | Balloon |\n *\t\t +-----------------+\n *\n * * `southWestArrowNorth`\n *\n *\t\t [ Target ]\n *\t\t ^\n *\t\t+-----------------+\n *\t\t| Balloon |\n *\t\t+-----------------+\n *\n * * `southWestArrowNorthMiddleEast`\n *\n *\t\t [ Target ]\n *\t\t ^\n *\t\t+-----------------+\n *\t\t| Balloon |\n *\t\t+-----------------+\n *\n * * `southWestArrowNorthEast`\n *\n *\t\t [ Target ]\n *\t\t ^\n *\t\t+-----------------+\n *\t\t| Balloon |\n *\t\t+-----------------+\n *\n *\n *\n * **South east**\n *\n * * `southEastArrowNorthWest`\n *\n *\t\t[ Target ]\n *\t\t ^\n *\t\t +-----------------+\n *\t\t | Balloon |\n *\t\t +-----------------+\n* * `southEastArrowNorthMiddleWest`\n *\n *\t\t [ Target ]\n *\t\t ^\n *\t\t +-----------------+\n *\t\t | Balloon |\n *\t\t +-----------------+\n *\n * * `southEastArrowNorth`\n *\n *\t\t[ Target ]\n *\t\t ^\n *\t\t+-----------------+\n *\t\t| Balloon |\n *\t\t+-----------------+\n *\n * * `southEastArrowNorthMiddleEast`\n *\n *\t\t [ Target ]\n *\t\t ^\n *\t\t+-----------------+\n *\t\t| Balloon |\n *\t\t+-----------------+\n *\n * * `southEastArrowNorthEast`\n *\n *\t\t [ Target ]\n *\t\t ^\n *\t\t+-----------------+\n *\t\t| Balloon |\n *\t\t+-----------------+\n *\n *\n * See {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView#attachTo}.\n *\n * Positioning functions must be compatible with {@link module:utils/dom/position~Position}.\n *\n * The name that the position function returns will be reflected in the balloon panel's class that\n * controls the placement of the \"arrow\". See {@link #position} to learn more.\n *\n * @member {Object} module:ui/panel/balloon/balloonpanelview~BalloonPanelView.defaultPositions\n */\nBalloonPanelView.defaultPositions = {\n\n\t// ------- North west\n\n\tnorthWestArrowSouthWest: ( targetRect, balloonRect ) => ( {\n\t\ttop: getNorthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left - BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_sw'\n\t} ),\n\n\tnorthWestArrowSouthMiddleWest: ( targetRect, balloonRect ) => ( {\n\t\ttop: getNorthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left - ( balloonRect.width * .25 ) - BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_smw'\n\t} ),\n\n\tnorthWestArrowSouth: ( targetRect, balloonRect ) => ( {\n\t\ttop: getNorthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left - balloonRect.width / 2,\n\t\tname: 'arrow_s'\n\t} ),\n\n\tnorthWestArrowSouthMiddleEast: ( targetRect, balloonRect ) => ( {\n\t\ttop: getNorthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left - ( balloonRect.width * .75 ) + BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_sme'\n\t} ),\n\n\tnorthWestArrowSouthEast: ( targetRect, balloonRect ) => ( {\n\t\ttop: getNorthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left - balloonRect.width + BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_se'\n\t} ),\n\n\t// ------- North\n\n\tnorthArrowSouthWest: ( targetRect, balloonRect ) => ( {\n\t\ttop: getNorthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left + targetRect.width / 2 - BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_sw'\n\t} ),\n\n\tnorthArrowSouthMiddleWest: ( targetRect, balloonRect ) => ( {\n\t\ttop: getNorthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left + targetRect.width / 2 - ( balloonRect.width * .25 ) - BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_smw'\n\t} ),\n\n\tnorthArrowSouth: ( targetRect, balloonRect ) => ( {\n\t\ttop: getNorthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left + targetRect.width / 2 - balloonRect.width / 2,\n\t\tname: 'arrow_s'\n\t} ),\n\n\tnorthArrowSouthMiddleEast: ( targetRect, balloonRect ) => ( {\n\t\ttop: getNorthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left + targetRect.width / 2 - ( balloonRect.width * .75 ) + BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_sme'\n\t} ),\n\n\tnorthArrowSouthEast: ( targetRect, balloonRect ) => ( {\n\t\ttop: getNorthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left + targetRect.width / 2 - balloonRect.width + BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_se'\n\t} ),\n\n\t// ------- North east\n\n\tnorthEastArrowSouthWest: ( targetRect, balloonRect ) => ( {\n\t\ttop: getNorthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.right - BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_sw'\n\t} ),\n\n\tnorthEastArrowSouthMiddleWest: ( targetRect, balloonRect ) => ( {\n\t\ttop: getNorthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.right - ( balloonRect.width * .25 ) - BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_smw'\n\t} ),\n\tnorthEastArrowSouth: ( targetRect, balloonRect ) => ( {\n\t\ttop: getNorthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.right - balloonRect.width / 2,\n\t\tname: 'arrow_s'\n\t} ),\n\n\tnorthEastArrowSouthMiddleEast: ( targetRect, balloonRect ) => ( {\n\t\ttop: getNorthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.right - ( balloonRect.width * .75 ) + BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_sme'\n\t} ),\n\n\tnorthEastArrowSouthEast: ( targetRect, balloonRect ) => ( {\n\t\ttop: getNorthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.right - balloonRect.width + BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_se'\n\t} ),\n\t// ------- South west\n\n\tsouthWestArrowNorthWest: ( targetRect, balloonRect ) => ( {\n\t\ttop: getSouthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left - BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_nw'\n\t} ),\n\n\tsouthWestArrowNorthMiddleWest: ( targetRect, balloonRect ) => ( {\n\t\ttop: getSouthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left - ( balloonRect.width * .25 ) - BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_nmw'\n\t} ),\n\n\tsouthWestArrowNorth: ( targetRect, balloonRect ) => ( {\n\t\ttop: getSouthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left - balloonRect.width / 2,\n\t\tname: 'arrow_n'\n\t} ),\n\n\tsouthWestArrowNorthMiddleEast: ( targetRect, balloonRect ) => ( {\n\t\ttop: getSouthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left - ( balloonRect.width * .75 ) + BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_nme'\n\t} ),\n\n\tsouthWestArrowNorthEast: ( targetRect, balloonRect ) => ( {\n\t\ttop: getSouthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left - balloonRect.width + BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_ne'\n\t} ),\n\n\t// ------- South\n\n\tsouthArrowNorthWest: ( targetRect, balloonRect ) => ( {\n\t\ttop: getSouthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left + targetRect.width / 2 - BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_nw'\n\t} ),\n\tsouthArrowNorthMiddleWest: ( targetRect, balloonRect ) => ( {\n\t\ttop: getSouthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left + targetRect.width / 2 - ( balloonRect.width * 0.25 ) - BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_nmw'\n\t} ),\n\n\tsouthArrowNorth: ( targetRect, balloonRect ) => ( {\n\t\ttop: getSouthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left + targetRect.width / 2 - balloonRect.width / 2,\n\t\tname: 'arrow_n'\n\t} ),\n\n\tsouthArrowNorthMiddleEast: ( targetRect, balloonRect ) => ( {\n\t\ttop: getSouthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left + targetRect.width / 2 - ( balloonRect.width * 0.75 ) + BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_nme'\n\t} ),\n\n\tsouthArrowNorthEast: ( targetRect, balloonRect ) => ( {\n\t\ttop: getSouthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left + targetRect.width / 2 - balloonRect.width + BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_ne'\n\t} ),\n\n\t// ------- South east\n\n\tsouthEastArrowNorthWest: ( targetRect, balloonRect ) => ( {\n\t\ttop: getSouthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.right - BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_nw'\n\t} ),\n\n\tsouthEastArrowNorthMiddleWest: ( targetRect, balloonRect ) => ( {\n\t\ttop: getSouthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.right - ( balloonRect.width * .25 ) - BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_nmw'\n\t} ),\n\n\tsouthEastArrowNorth: ( targetRect, balloonRect ) => ( {\n\t\ttop: getSouthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.right - balloonRect.width / 2,\n\t\tname: 'arrow_n'\n\t} ),\n\n\tsouthEastArrowNorthMiddleEast: ( targetRect, balloonRect ) => ( {\n\t\ttop: getSouthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.right - ( balloonRect.width * .75 ) + BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_nme'\n\t} ),\n\n\tsouthEastArrowNorthEast: ( targetRect, balloonRect ) => ( {\n\t\ttop: getSouthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.right - balloonRect.width + BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_ne'\n\t} )\n\n};\n\n// Returns the top coordinate for positions starting with `north*`.\n//\n// @private\n// @param {utils/dom/rect~Rect} targetRect A rect of the target.\n// @param {utils/dom/rect~Rect} elementRect A rect of the balloon.\n// @returns {Number}\nfunction getNorthTop( targetRect, balloonRect ) {\n\treturn targetRect.top - balloonRect.height - BalloonPanelView.arrowVerticalOffset;\n}\n\n// Returns the top coordinate for positions starting with `south*`.\n//\n// @private\n// @param {utils/dom/rect~Rect} targetRect A rect of the target.\n// @param {utils/dom/rect~Rect} elementRect A rect of the balloon.\n// @returns {Number}\nfunction getSouthTop( targetRect ) {\n\treturn targetRect.bottom + BalloonPanelView.arrowVerticalOffset;\n}\n"],"sourceRoot":""}