} module:core/plugin~LoadedPlugins\n */\n","/**\n * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md.\n */\n\n/**\n * @module ui/viewcollection\n */\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport Collection from '@ckeditor/ckeditor5-utils/src/collection';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\n\n/**\n * Collects {@link module:ui/view~View} instances.\n *\n *\t\tconst parentView = new ParentView( locale );\n *\t\tconst collection = new ViewCollection( locale );\n *\n *\t\tcollection.setParent( parentView.element );\n *\n *\t\tconst viewA = new ChildView( locale );\n *\t\tconst viewB = new ChildView( locale );\n *\n * View collection renders and manages view {@link module:ui/view~View#element elements}:\n *\n *\t\tcollection.add( viewA );\n *\t\tcollection.add( viewB );\n *\n *\t\tconsole.log( parentView.element.firsChild ); // -> viewA.element\n *\t\tconsole.log( parentView.element.lastChild ); // -> viewB.element\n *\n * It {@link module:ui/viewcollection~ViewCollection#delegate propagates} DOM events too:\n *\n *\t\t// Delegate #click and #keydown events from viewA and viewB to the parentView.\n *\t\tcollection.delegate( 'click' ).to( parentView );\n *\n *\t\tparentView.on( 'click', ( evt ) => {\n *\t\t\tconsole.log( `${ evt.source } has been clicked.` );\n *\t\t} );\n *\n *\t\t// This event will be delegated to the parentView.\n *\t\tviewB.fire( 'click' );\n *\n * **Note**: A view collection can be used directly in the {@link module:ui/template~TemplateDefinition definition}\n * of a {@link module:ui/template~Template template}.\n *\n * @extends module:utils/collection~Collection\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class ViewCollection extends Collection {\n\t/**\n\t * Creates a new instance of the {@link module:ui/viewcollection~ViewCollection}.\n\t *\n\t * @param {module:utils/locale~Locale} [locale] The {@link module:core/editor/editor~Editor editor's locale} instance.\n\t */\n\tconstructor( locale ) {\n\t\tsuper( {\n\t\t\t// An #id Number attribute should be legal and not break the `ViewCollection` instance.\n\t\t\t// https://github.com/ckeditor/ckeditor5-ui/issues/93\n\t\t\tidProperty: 'viewUid'\n\t\t} );\n\n\t\t// Handle {@link module:ui/view~View#element} in DOM when a new view is added to the collection.\n\t\tthis.on( 'add', ( evt, view, index ) => {\n\t\t\tif ( !view.isRendered ) {\n\t\t\t\tview.render();\n\t\t\t}\n\n\t\t\tif ( view.element && this._parentElement ) {\n\t\t\t\tthis._parentElement.insertBefore( view.element, this._parentElement.children[ index ] );\n\t\t\t}\n\t\t} );\n\n\t\t// Handle {@link module:ui/view~View#element} in DOM when a view is removed from the collection.\n\t\tthis.on( 'remove', ( evt, view ) => {\n\t\t\tif ( view.element && this._parentElement ) {\n\t\t\t\tview.element.remove();\n\t\t\t}\n\t\t} );\n\n\t\t/**\n\t\t * The {@link module:core/editor/editor~Editor#locale editor's locale} instance.\n\t\t * See the view {@link module:ui/view~View#locale locale} property.\n\t\t *\n\t\t * @member {module:utils/locale~Locale}\n\t\t */\n\t\tthis.locale = locale;\n\n\t\t/**\n\t\t * A parent element within which child views are rendered and managed in DOM.\n\t\t *\n\t\t * @protected\n\t\t * @member {HTMLElement}\n\t\t */\n\t\tthis._parentElement = null;\n\t}\n\n\t/**\n\t * Destroys the view collection along with child views.\n\t * See the view {@link module:ui/view~View#destroy} method.\n\t */\n\tdestroy() {\n\t\tthis.map( view => view.destroy() );\n\t}\n\n\t/**\n\t * Sets the parent HTML element of this collection. When parent is set, {@link #add adding} and\n\t * {@link #remove removing} views in the collection synchronizes their\n\t * {@link module:ui/view~View#element elements} in the parent element.\n\t *\n\t * @param {HTMLElement} element A new parent element.\n\t */\n\tsetParent( elementOrDocFragment ) {\n\t\tthis._parentElement = elementOrDocFragment;\n\t}\n\n\t/**\n\t * Delegates selected events coming from within views in the collection to any\n\t * {@link module:utils/emittermixin~Emitter}.\n\t *\n\t * For the following views and collection:\n\t *\n\t *\t\tconst viewA = new View();\n\t *\t\tconst viewB = new View();\n\t *\t\tconst viewC = new View();\n\t *\n\t *\t\tconst views = parentView.createCollection();\n\t *\n\t *\t\tviews.delegate( 'eventX' ).to( viewB );\n\t *\t\tviews.delegate( 'eventX', 'eventY' ).to( viewC );\n\t *\n\t *\t\tviews.add( viewA );\n\t *\n\t * the `eventX` is delegated (fired by) `viewB` and `viewC` along with `customData`:\n\t *\n\t *\t\tviewA.fire( 'eventX', customData );\n\t *\n\t * and `eventY` is delegated (fired by) `viewC` along with `customData`:\n\t *\n\t *\t\tviewA.fire( 'eventY', customData );\n\t *\n\t * See {@link module:utils/emittermixin~EmitterMixin#delegate}.\n\t *\n\t * @param {...String} events {@link module:ui/view~View} event names to be delegated to another\n\t * {@link module:utils/emittermixin~Emitter}.\n\t * @returns {Object}\n\t * @returns {Function} return.to A function which accepts the destination of\n\t * {@link module:utils/emittermixin~EmitterMixin#delegate delegated} events.\n\t */\n\tdelegate( ...events ) {\n\t\tif ( !events.length || !isStringArray( events ) ) {\n\t\t\t/**\n\t\t\t * All event names must be strings.\n\t\t\t *\n\t\t\t * @error ui-viewcollection-delegate-wrong-events\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'ui-viewcollection-delegate-wrong-events: All event names must be strings.' );\n\t\t}\n\n\t\treturn {\n\t\t\t/**\n\t\t\t * Selects destination for {@link module:utils/emittermixin~EmitterMixin#delegate} events.\n\t\t\t *\n\t\t\t * @memberOf module:ui/viewcollection~ViewCollection#delegate\n\t\t\t * @function module:ui/viewcollection~ViewCollection#delegate.to\n\t\t\t * @param {module:utils/emittermixin~EmitterMixin} dest An `EmitterMixin` instance which is\n\t\t\t * the destination for delegated events.\n\t\t\t */\n\t\t\tto: dest => {\n\t\t\t\t// Activate delegating on existing views in this collection.\n\t\t\t\tfor ( const view of this ) {\n\t\t\t\t\tfor ( const evtName of events ) {\n\t\t\t\t\t\tview.delegate( evtName ).to( dest );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Activate delegating on future views in this collection.\n\t\t\t\tthis.on( 'add', ( evt, view ) => {\n\t\t\t\t\tfor ( const evtName of events ) {\n\t\t\t\t\t\tview.delegate( evtName ).to( dest );\n\t\t\t\t\t}\n\t\t\t\t} );\n\n\t\t\t\t// Deactivate delegating when view is removed from this collection.\n\t\t\t\tthis.on( 'remove', ( evt, view ) => {\n\t\t\t\t\tfor ( const evtName of events ) {\n\t\t\t\t\t\tview.stopDelegating( evtName, dest );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t}\n\t\t};\n\t}\n\n\t/**\n\t * Removes a child view from the collection. If the {@link #setParent parent element} of the\n\t * collection has been set, the {@link module:ui/view~View#element element} of the view is also removed\n\t * in DOM, reflecting the order of the collection.\n\t *\n\t * See the {@link #add} method.\n\t *\n\t * @method #remove\n\t * @param {module:ui/view~View|Number|String} subject The view to remove, its id or index in the collection.\n\t * @returns {Object} The removed view.\n\t */\n}\n\nmix( Collection, ObservableMixin );\n\n// Check if all entries of the array are of `String` type.\n//\n// @private\n// @param {Array} arr An array to be checked.\n// @returns {Boolean}\nfunction isStringArray( arr ) {\n\treturn arr.every( a => typeof a == 'string' );\n}\n","/**\n * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md.\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 log from '@ckeditor/ckeditor5-utils/src/log';\nimport { isObject, cloneDeepWith } from 'lodash-es';\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\tA 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 * {@link module:ui/template~TemplateDefinition attributes} and\n\t * {@link module:ui/template~TemplateDefinition event listeners} 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 bind = Template.bind( observable, emitter );\n\t *\n\t *\t\tnew Template( {\n\t *\t\t\tattrs: {\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\telement.outerHTML == \"Div text.
\"\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( 'ui-template-revert-not-applied: Attempting to revert a template which has not been applied yet.' );\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\tattrs: {\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\tlog.warn( 'template-extend-render: Attempting to extend a template which has already been rendered.' );\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: Node definition must have either \"tag\" or \"text\" when rendering a new Node.'\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 {module:ui/template~RenderData#revertData} revertData Stores information about\n\t * what changes have been made by {@link #apply} to the node.\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} attrs\nfunction normalizeAttributes( attrs ) {\n\tfor ( const a in attrs ) {\n\t\tif ( attrs[ a ].value ) {\n\t\t\tattrs[ a ].value = [].concat( attrs[ a ].value );\n\t\t}\n\n\t\tarrayify( attrs, 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\tif ( !Array.isArray( def.text ) ) {\n\t\tdef.text = [ def.text ];\n\t}\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\tif ( !Array.isArray( obj[ key ] ) ) {\n\t\tobj[ key ] = [ obj[ key ] ];\n\t}\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.\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: The number of children in extended definition does not match.'\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-2019, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md.\n */\n\n/**\n * @module ui/view\n */\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport ViewCollection from './viewcollection';\nimport Template from './template';\nimport DomEmitterMixin from '@ckeditor/ckeditor5-utils/src/dom/emittermixin';\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport Collection from '@ckeditor/ckeditor5-utils/src/collection';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport isIterable from '@ckeditor/ckeditor5-utils/src/isiterable';\n\nimport '../theme/globals/globals.css';\n\n/**\n * The basic view class, which represents an HTML element created out of a\n * {@link module:ui/view~View#template}. Views are building blocks of the user interface and handle\n * interaction\n *\n * Views {@link module:ui/view~View#registerChild aggregate} children in\n * {@link module:ui/view~View#createCollection collections} and manage the life cycle of DOM\n * listeners e.g. by handling rendering and destruction.\n *\n * See the {@link module:ui/template~TemplateDefinition} syntax to learn more about shaping view\n * elements, attributes and listeners.\n *\n *\t\tclass SampleView extends View {\n *\t\t\tconstructor( locale ) {\n *\t\t\t\tsuper( locale );\n *\n *\t\t\t\tconst bind = this.bindTemplate;\n *\n *\t\t\t\t// Views define their interface (state) using observable attributes.\n *\t\t\t\tthis.set( 'elementClass', 'bar' );\n *\n *\t\t\t\tthis.setTemplate( {\n *\t\t\t\t\ttag: 'p',\n *\n *\t\t\t\t\t// The element of the view can be defined with its children.\n *\t\t\t\t\tchildren: [\n *\t\t\t\t\t\t'Hello',\n *\t\t\t\t\t\t{\n *\t\t\t\t\t\t\ttag: 'b',\n *\t\t\t\t\t\t\tchildren: [ 'world!' ]\n *\t\t\t\t\t\t}\n *\t\t\t\t\t],\n *\t\t\t\t\tattributes: {\n *\t\t\t\t\t\tclass: [\n *\t\t\t\t\t\t\t'foo',\n *\n *\t\t\t\t\t\t\t// Observable attributes control the state of the view in DOM.\n *\t\t\t\t\t\t\tbind.to( 'elementClass' )\n *\t\t\t\t\t\t]\n *\t\t\t\t\t},\n *\t\t\t\t\ton: {\n *\t\t\t\t\t\t// Views listen to DOM events and propagate them.\n *\t\t\t\t\t\tclick: bind.to( 'clicked' )\n *\t\t\t\t\t}\n *\t\t\t\t} );\n *\t\t\t}\n *\t\t}\n *\n *\t\tconst view = new SampleView( locale );\n *\n *\t\tview.render();\n *\n *\t\t// Append Helloworld
to the \n *\t\tdocument.body.appendChild( view.element );\n *\n *\t\t// Change the class attribute to Helloworld
\n *\t\tview.elementClass = 'baz';\n *\n *\t\t// Respond to the \"click\" event in DOM by executing a custom action.\n *\t\tview.on( 'clicked', () => {\n *\t\t\tconsole.log( 'The view has been clicked!' );\n *\t\t} );\n *\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class View {\n\t/**\n\t * Creates an instance of the {@link module:ui/view~View} 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 */\n\tconstructor( locale ) {\n\t\t/**\n\t\t * An HTML element of the view. `null` until {@link #render rendered}\n\t\t * from the {@link #template}.\n\t\t *\n\t\t *\t\tclass SampleView extends View {\n\t\t *\t\t\tconstructor() {\n\t\t *\t\t\t\tsuper();\n\t\t *\n\t\t *\t\t\t\t// A template instance the #element will be created from.\n\t\t *\t\t\t\tthis.setTemplate( {\n\t\t *\t\t\t\t\ttag: 'p'\n\t\t *\n\t\t *\t\t\t\t\t// ...\n\t\t *\t\t\t\t} );\n\t\t *\t\t\t}\n\t\t *\t\t}\n\t\t *\n\t\t *\t\tconst view = new SampleView();\n\t\t *\n\t\t *\t\t// Renders the #template.\n\t\t *\t\tview.render();\n\t\t *\n\t\t *\t\t// Append the HTML element of the view to .\n\t\t *\t\tdocument.body.appendChild( view.element );\n\t\t *\n\t\t * **Note**: The element of the view can also be assigned directly:\n\t\t *\n\t\t *\t\tview.element = document.querySelector( '#my-container' );\n\t\t *\n\t\t * @member {HTMLElement}\n\t\t */\n\t\tthis.element = null;\n\n\t\t/**\n\t\t * Set `true` when the view has already been {@link module:ui/view~View#render rendered}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean} #isRendered\n\t\t */\n\t\tthis.isRendered = false;\n\n\t\t/**\n\t\t * A set of tools to localize the user interface.\n\t\t *\n\t\t * Also see {@link module:core/editor/editor~Editor#locale}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/locale~Locale}\n\t\t */\n\t\tthis.locale = locale;\n\n\t\t/**\n\t\t * Shorthand for {@link module:utils/locale~Locale#t}.\n\t\t *\n\t\t * Note: If {@link #locale} instance hasn't been passed to the view this method may not\n\t\t * be available.\n\t\t *\n\t\t * @see module:utils/locale~Locale#t\n\t\t * @method\n\t\t */\n\t\tthis.t = locale && locale.t;\n\n\t\t/**\n\t\t * Collections registered with {@link #createCollection}.\n\t\t *\n\t\t * @protected\n\t\t * @member {Set.}\n\t\t */\n\t\tthis._viewCollections = new Collection();\n\n\t\t/**\n\t\t * A collection of view instances, which have been added directly\n\t\t * into the {@link module:ui/template~Template#children}.\n\t\t *\n\t\t * @protected\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis._unboundChildren = this.createCollection();\n\n\t\t// Pass parent locale to its children.\n\t\tthis._viewCollections.on( 'add', ( evt, collection ) => {\n\t\t\tcollection.locale = locale;\n\t\t} );\n\n\t\t/**\n\t\t * Template of this view. It provides the {@link #element} representing\n\t\t * the view in DOM, which is {@link #render rendered}.\n\t\t *\n\t\t * @member {module:ui/template~Template} #template\n\t\t */\n\n\t\t/**\n\t\t * Cached {@link module:ui/template~BindChain bind chain} object created by the\n\t\t * {@link #template}. See {@link #bindTemplate}.\n\t\t *\n\t\t * @private\n\t\t * @member {Object} #_bindTemplate\n\t\t */\n\n\t\tthis.decorate( 'render' );\n\t}\n\n\t/**\n\t * Shorthand for {@link module:ui/template~Template.bind}, a binding\n\t * {@link module:ui/template~BindChain interface} pre–configured for the view instance.\n\t *\n\t * It provides {@link module:ui/template~BindChain#to `to()`} and\n\t * {@link module:ui/template~BindChain#if `if()`} methods that initialize bindings with\n\t * observable attributes and attach DOM listeners.\n\t *\n\t *\t\tclass SampleView extends View {\n\t *\t\t\tconstructor( locale ) {\n\t *\t\t\t\tsuper( locale );\n\t *\n\t *\t\t\t\tconst bind = this.bindTemplate;\n\t *\n\t *\t\t\t\t// These {@link module:utils/observablemixin~Observable observable} attributes will control\n\t *\t\t\t\t// the state of the view in DOM.\n\t *\t\t\t\tthis.set( {\n\t *\t\t\t\t\telementClass: 'foo',\n\t *\t\t\t\t \tisEnabled: true\n\t *\t\t\t\t } );\n\t *\n\t *\t\t\t\tthis.setTemplate( {\n\t *\t\t\t\t\ttag: 'p',\n\t *\n\t *\t\t\t\t\tattributes: {\n\t *\t\t\t\t\t\t// The class HTML attribute will follow elementClass\n\t *\t\t\t\t\t\t// and isEnabled view attributes.\n\t *\t\t\t\t\t\tclass: [\n\t *\t\t\t\t\t\t\tbind.to( 'elementClass' )\n\t *\t\t\t\t\t\t\tbind.if( 'isEnabled', 'present-when-enabled' )\n\t *\t\t\t\t\t\t]\n\t *\t\t\t\t\t},\n\t *\n\t *\t\t\t\t\ton: {\n\t *\t\t\t\t\t\t// The view will fire the \"clicked\" event upon clicking in DOM.\n\t *\t\t\t\t\t\tclick: bind.to( 'clicked' )\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 * @method #bindTemplate\n\t */\n\tget bindTemplate() {\n\t\tif ( this._bindTemplate ) {\n\t\t\treturn this._bindTemplate;\n\t\t}\n\n\t\treturn ( this._bindTemplate = Template.bind( this, this ) );\n\t}\n\n\t/**\n\t * Creates a new collection of views, which can be used as\n\t * {@link module:ui/template~Template#children} of this view.\n\t *\n\t *\t\tclass SampleView extends View {\n\t *\t\t\tconstructor( locale ) {\n\t *\t\t\t\tsuper( locale );\n\t *\n\t *\t\t\t\tthis.items = this.createCollection();\n \t *\n\t *\t\t\t\tthis.setTemplate( {\n\t *\t\t\t\t\ttag: 'p',\n\t *\n\t *\t\t\t\t\t// `items` collection will render here.\n\t *\t\t\t\t\tchildren: this.items\n\t *\t\t\t\t} );\n\t *\t\t\t}\n\t *\t\t}\n\t *\n\t *\t\tconst view = new SampleView( locale );\n\t *\t\tconst child = new ChildView( locale );\n\t *\n\t *\t\tview.render();\n\t *\n\t *\t\t// It will append
to the .\n\t *\t\tdocument.body.appendChild( view.element );\n\t *\n\t *\t\t// From now on the child is nested under its parent, which is also reflected in DOM.\n\t *\t\t//
\n\t *\t\tview.items.add( child );\n\t *\n\t * @returns {module:ui/viewcollection~ViewCollection} A new collection of view instances.\n\t */\n\tcreateCollection() {\n\t\tconst collection = new ViewCollection();\n\n\t\tthis._viewCollections.add( collection );\n\n\t\treturn collection;\n\t}\n\n\t/**\n\t * Registers a new child view under the view instance. Once registered, a child\n\t * view is managed by its parent, including {@link #render rendering}\n\t * and {@link #destroy destruction}.\n\t *\n\t * To revert this, use {@link #deregisterChild}.\n\t *\n\t *\t\tclass SampleView extends View {\n\t *\t\t\tconstructor( locale ) {\n\t *\t\t\t\tsuper( locale );\n\t *\n\t *\t\t\t\tthis.childA = new SomeChildView( locale );\n\t *\t\t\t\tthis.childB = new SomeChildView( locale );\n\t *\n\t *\t\t\t\tthis.setTemplate( { tag: 'p' } );\n\t *\n\t *\t\t\t\t// Register the children.\n\t *\t\t\t\tthis.registerChild( [ this.childA, this.childB ] );\n\t *\t\t\t}\n\t *\n\t *\t\t\trender() {\n\t *\t\t\t\tsuper.render();\n\t *\n\t *\t\t\t\tthis.element.appendChild( this.childA.element );\n\t *\t\t\t\tthis.element.appendChild( this.childB.element );\n\t *\t\t\t}\n\t *\t\t}\n\t *\n\t *\t\tconst view = new SampleView( locale );\n\t *\n\t *\t\tview.render();\n\t *\n\t *\t\t// Will append
.\n\t *\t\tdocument.body.appendChild( view.element );\n\t *\n\t * **Note**: There's no need to add child views if they're already referenced in the\n\t * {@link #template}:\n\t *\n\t *\t\tclass SampleView extends View {\n\t *\t\t\tconstructor( locale ) {\n\t *\t\t\t\tsuper( locale );\n\t *\n\t *\t\t\t\tthis.childA = new SomeChildView( locale );\n\t *\t\t\t\tthis.childB = new SomeChildView( locale );\n\t *\n\t *\t\t\t\tthis.setTemplate( {\n\t *\t\t\t\t\ttag: 'p',\n\t *\n \t *\t\t\t\t\t// These children will be added automatically. There's no\n \t *\t\t\t\t\t// need to call {@link #registerChild} for any of them.\n\t *\t\t\t\t\tchildren: [ this.childA, this.childB ]\n\t *\t\t\t\t} );\n\t *\t\t\t}\n\t *\n\t *\t\t\t// ...\n\t *\t\t}\n\t *\n\t * @param {module:ui/view~View|Iterable.} children Children views to be registered.\n\t */\n\tregisterChild( children ) {\n\t\tif ( !isIterable( children ) ) {\n\t\t\tchildren = [ children ];\n\t\t}\n\n\t\tfor ( const child of children ) {\n\t\t\tthis._unboundChildren.add( child );\n\t\t}\n\t}\n\n\t/**\n\t * The opposite of {@link #registerChild}. Removes a child view from this view instance.\n\t * Once removed, the child is no longer managed by its parent, e.g. it can safely\n\t * become a child of another parent view.\n\t *\n\t * @see #registerChild\n\t * @param {module:ui/view~View|Iterable.} children Child views to be removed.\n\t */\n\tderegisterChild( children ) {\n\t\tif ( !isIterable( children ) ) {\n\t\t\tchildren = [ children ];\n\t\t}\n\n\t\tfor ( const child of children ) {\n\t\t\tthis._unboundChildren.remove( child );\n\t\t}\n\t}\n\n\t/**\n\t * Sets the {@link #template} of the view with with given definition.\n\t *\n\t * A shorthand for:\n\t *\n\t *\t\tview.setTemplate( definition );\n\t *\n\t * @param {module:ui/template~TemplateDefinition} definition Definition of view's template.\n\t */\n\tsetTemplate( definition ) {\n\t\tthis.template = new Template( definition );\n\t}\n\n\t/**\n\t * {@link module:ui/template~Template.extend Extends} the {@link #template} of the view with\n\t * with given definition.\n\t *\n\t * A shorthand for:\n\t *\n\t *\t\tTemplate.extend( view.template, definition );\n\t *\n\t * **Note**: Is requires the {@link #template} to be already set. See {@link #setTemplate}.\n\t *\n\t * @param {module:ui/template~TemplateDefinition} definition Definition which\n\t * extends the {@link #template}.\n\t */\n\textendTemplate( definition ) {\n\t\tTemplate.extend( this.template, definition );\n\t}\n\n\t/**\n\t * Recursively renders the view.\n\t *\n\t * Once the view is rendered:\n\t * * the {@link #element} becomes an HTML element out of {@link #template},\n\t * * the {@link #isRendered} flag is set `true`.\n\t *\n\t * **Note**: The children of the view:\n\t * * defined directly in the {@link #template}\n\t * * residing in collections created by the {@link #createCollection} method,\n\t * * and added by {@link #registerChild}\n\t * are also rendered in the process.\n\t *\n\t * In general, `render()` method is the right place to keep the code which refers to the\n\t * {@link #element} and should be executed at the very beginning of the view's life cycle.\n\t *\n\t * It is possible to {@link module:ui/template~Template.extend} the {@link #template} before\n\t * the view is rendered. To allow an early customization of the view (e.g. by its parent),\n\t * such references should be done in `render()`.\n\t *\n\t *\t\tclass SampleView extends View {\n\t *\t\t\tconstructor() {\n\t *\t\t\t\tthis.setTemplate( {\n\t *\t\t\t\t\t// ...\n\t *\t\t\t\t} );\n\t *\t\t\t},\n\t *\n\t *\t\t\trender() {\n\t *\t\t\t\t// View#element becomes available.\n\t *\t\t\t\tsuper.render();\n\t *\n\t *\t\t\t\t// The \"scroll\" listener depends on #element.\n\t *\t\t\t\tthis.listenTo( window, 'scroll', () => {\n\t *\t\t\t\t\t// A reference to #element would render the #template and make it non-extendable.\n\t *\t\t\t\t\tif ( window.scrollY > 0 ) {\n\t *\t\t\t\t\t\tthis.element.scrollLeft = 100;\n\t *\t\t\t\t\t} else {\n\t *\t\t\t\t\t\tthis.element.scrollLeft = 0;\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\tconst view = new SampleView();\n\t *\n\t *\t\t// Let's customize the view before it gets rendered.\n\t *\t\tview.extendTemplate( {\n\t *\t\t\tattributes: {\n\t *\t\t\t\tclass: [\n\t *\t\t\t\t\t'additional-class'\n\t *\t\t\t\t]\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t *\t\t// Late rendering allows customization of the view.\n\t *\t\tview.render();\n\t */\n\trender() {\n\t\tif ( this.isRendered ) {\n\t\t\t/**\n\t\t\t * This View has already been rendered.\n\t\t\t *\n\t\t\t * @error ui-view-render-rendered\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'ui-view-render-already-rendered: This View has already been rendered.' );\n\t\t}\n\n\t\t// Render #element of the view.\n\t\tif ( this.template ) {\n\t\t\tthis.element = this.template.render();\n\n\t\t\t// Auto–register view children from #template.\n\t\t\tthis.registerChild( this.template.getViews() );\n\t\t}\n\n\t\tthis.isRendered = true;\n\t}\n\n\t/**\n\t * Recursively destroys the view instance and child views added by {@link #registerChild} and\n\t * residing in collections created by the {@link #createCollection}.\n\t *\n\t * Destruction disables all event listeners:\n\t * * created on the view, e.g. `view.on( 'event', () => {} )`,\n\t * * defined in the {@link #template} for DOM events.\n\t */\n\tdestroy() {\n\t\tthis.stopListening();\n\n\t\tthis._viewCollections.map( c => c.destroy() );\n\n\t\t// Template isn't obligatory for views.\n\t\tif ( this.template && this.template._revertData ) {\n\t\t\tthis.template.revert( this.element );\n\t\t}\n\t}\n\n\t/**\n\t * Event fired by the {@link #render} method. Actual rendering is executed as a listener to\n\t * this event with the default priority.\n\t *\n\t * See {@link module:utils/observablemixin~ObservableMixin#decorate} for more information and samples.\n\t *\n\t * @event render\n\t */\n}\n\nmix( View, DomEmitterMixin );\nmix( View, ObservableMixin );\n","/**\n * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md.\n */\n\n/**\n * @module utils/dom/position\n */\n\nimport global from './global';\nimport Rect from './rect';\nimport getPositionedAncestor from './getpositionedancestor';\nimport getBorderWidths from './getborderwidths';\nimport { isFunction } from 'lodash-es';\n\n/**\n * Calculates the `position: absolute` coordinates of a given element so it can be positioned with respect to the\n * target in the visually most efficient way, taking various restrictions like viewport or limiter geometry\n * into consideration.\n *\n *\t\t// The element which is to be positioned.\n *\t\tconst element = document.body.querySelector( '#toolbar' );\n *\n *\t\t// A target to which the element is positioned relatively.\n *\t\tconst target = document.body.querySelector( '#container' );\n *\n *\t\t// Finding the optimal coordinates for the positioning.\n *\t\tconst { left, top, name } = getOptimalPosition( {\n *\t\t\telement: element,\n *\t\t\ttarget: target,\n *\n * \t\t\t// The algorithm will chose among these positions to meet the requirements such\n * \t\t\t// as \"limiter\" element or \"fitInViewport\", set below. The positions are considered\n * \t\t\t// in the order of the array.\n *\t\t\tpositions: [\n *\t\t\t\t//\n *\t\t\t \t//\t[ Target ]\n *\t\t\t\t//\t+-----------------+\n *\t\t\t\t//\t| Element |\n *\t\t\t\t//\t+-----------------+\n *\t\t\t\t//\n *\t\t\t\ttargetRect => ( {\n *\t\t\t\t\ttop: targetRect.bottom,\n *\t\t\t\t\tleft: targetRect.left,\n *\t\t\t\t\tname: 'mySouthEastPosition'\n *\t\t\t\t} ),\n *\n *\t\t\t\t//\n *\t\t\t\t//\t+-----------------+\n *\t\t\t\t//\t| Element |\n *\t\t\t\t//\t+-----------------+\n *\t\t\t\t//\t[ Target ]\n *\t\t\t\t//\n *\t\t\t\t( targetRect, elementRect ) => ( {\n *\t\t\t\t\ttop: targetRect.top - elementRect.height,\n *\t\t\t\t\tleft: targetRect.left,\n *\t\t\t\t\tname: 'myNorthEastPosition'\n *\t\t\t\t} )\n *\t\t\t],\n *\n *\t\t\t// Find a position such guarantees the element remains within visible boundaries of .\n *\t\t\tlimiter: document.body,\n *\n *\t\t\t// Find a position such guarantees the element remains within visible boundaries of the browser viewport.\n *\t\t\tfitInViewport: true\n *\t\t} );\n *\n *\t\t// The best position which fits into document.body and the viewport. May be useful\n *\t\t// to set proper class on the `element`.\n *\t\tconsole.log( name ); // -> \"myNorthEastPosition\"\n *\n *\t\t// Using the absolute coordinates which has been found to position the element\n *\t\t// as in the diagram depicting the \"myNorthEastPosition\" position.\n *\t\telement.style.top = top;\n *\t\telement.style.left = left;\n *\n * @param {module:utils/dom/position~Options} options Positioning options object.\n * @returns {module:utils/dom/position~Position}\n */\nexport function getOptimalPosition( { element, target, positions, limiter, fitInViewport } ) {\n\t// If the {@link module:utils/dom/position~Options#target} is a function, use what it returns.\n\t// https://github.com/ckeditor/ckeditor5-utils/issues/157\n\tif ( isFunction( target ) ) {\n\t\ttarget = target();\n\t}\n\n\t// If the {@link module:utils/dom/position~Options#limiter} is a function, use what it returns.\n\t// https://github.com/ckeditor/ckeditor5-ui/issues/260\n\tif ( isFunction( limiter ) ) {\n\t\tlimiter = limiter();\n\t}\n\n\tconst positionedElementAncestor = getPositionedAncestor( element.parentElement );\n\tconst elementRect = new Rect( element );\n\tconst targetRect = new Rect( target );\n\n\tlet bestPosition;\n\tlet name;\n\n\t// If there are no limits, just grab the very first position and be done with that drama.\n\tif ( !limiter && !fitInViewport ) {\n\t\t[ name, bestPosition ] = getPosition( positions[ 0 ], targetRect, elementRect );\n\t} else {\n\t\tconst limiterRect = limiter && new Rect( limiter ).getVisible();\n\t\tconst viewportRect = fitInViewport && new Rect( global.window );\n\n\t\t[ name, bestPosition ] =\n\t\t\tgetBestPosition( positions, targetRect, elementRect, limiterRect, viewportRect ) ||\n\t\t\t// If there's no best position found, i.e. when all intersections have no area because\n\t\t\t// rects have no width or height, then just use the first available position.\n\t\t\tgetPosition( positions[ 0 ], targetRect, elementRect );\n\t}\n\n\tlet { left, top } = getAbsoluteRectCoordinates( bestPosition );\n\n\tif ( positionedElementAncestor ) {\n\t\tconst ancestorPosition = getAbsoluteRectCoordinates( new Rect( positionedElementAncestor ) );\n\t\tconst ancestorBorderWidths = getBorderWidths( positionedElementAncestor );\n\n\t\t// (https://github.com/ckeditor/ckeditor5-ui-default/issues/126)\n\t\t// If there's some positioned ancestor of the panel, then its `Rect` must be taken into\n\t\t// consideration. `Rect` is always relative to the viewport while `position: absolute` works\n\t\t// with respect to that positioned ancestor.\n\t\tleft -= ancestorPosition.left;\n\t\ttop -= ancestorPosition.top;\n\n\t\t// (https://github.com/ckeditor/ckeditor5-utils/issues/139)\n\t\t// If there's some positioned ancestor of the panel, not only its position must be taken into\n\t\t// consideration (see above) but also its internal scrolls. Scroll have an impact here because `Rect`\n\t\t// is relative to the viewport (it doesn't care about scrolling), while `position: absolute`\n\t\t// must compensate that scrolling.\n\t\tleft += positionedElementAncestor.scrollLeft;\n\t\ttop += positionedElementAncestor.scrollTop;\n\n\t\t// (https://github.com/ckeditor/ckeditor5-utils/issues/139)\n\t\t// If there's some positioned ancestor of the panel, then its `Rect` includes its CSS `borderWidth`\n\t\t// while `position: absolute` positioning does not consider it.\n\t\t// E.g. `{ position: absolute, top: 0, left: 0 }` means upper left corner of the element,\n\t\t// not upper-left corner of its border.\n\t\tleft -= ancestorBorderWidths.left;\n\t\ttop -= ancestorBorderWidths.top;\n\t}\n\n\treturn { left, top, name };\n}\n\n// For given position function, returns a corresponding `Rect` instance.\n//\n// @private\n// @param {Function} position A function returning {@link module:utils/dom/position~Position}.\n// @param {utils/dom/rect~Rect} targetRect A rect of the target.\n// @param {utils/dom/rect~Rect} elementRect A rect of positioned element.\n// @returns {Array} An array containing position name and its Rect.\nfunction getPosition( position, targetRect, elementRect ) {\n\tconst { left, top, name } = position( targetRect, elementRect );\n\n\treturn [ name, elementRect.clone().moveTo( left, top ) ];\n}\n\n// For a given array of positioning functions, returns such that provides the best\n// fit of the `elementRect` into the `limiterRect` and `viewportRect`.\n//\n// @private\n// @param {module:utils/dom/position~Options#positions} positions Functions returning\n// {@link module:utils/dom/position~Position} to be checked, in the order of preference.\n// @param {utils/dom/rect~Rect} targetRect A rect of the {@link module:utils/dom/position~Options#target}.\n// @param {utils/dom/rect~Rect} elementRect A rect of positioned {@link module:utils/dom/position~Options#element}.\n// @param {utils/dom/rect~Rect} limiterRect A rect of the {@link module:utils/dom/position~Options#limiter}.\n// @param {utils/dom/rect~Rect} viewportRect A rect of the viewport.\n// @returns {Array} An array containing the name of the position and it's rect.\nfunction getBestPosition( positions, targetRect, elementRect, limiterRect, viewportRect ) {\n\tlet maxLimiterIntersectArea = 0;\n\tlet maxViewportIntersectArea = 0;\n\tlet bestPositionRect;\n\tlet bestPositionName;\n\n\t// This is when element is fully visible.\n\tconst elementRectArea = elementRect.getArea();\n\n\tpositions.some( position => {\n\t\tconst [ positionName, positionRect ] = getPosition( position, targetRect, elementRect );\n\t\tlet limiterIntersectArea;\n\t\tlet viewportIntersectArea;\n\n\t\tif ( limiterRect ) {\n\t\t\tif ( viewportRect ) {\n\t\t\t\t// Consider only the part of the limiter which is visible in the viewport. So the limiter is getting limited.\n\t\t\t\tconst limiterViewportIntersectRect = limiterRect.getIntersection( viewportRect );\n\n\t\t\t\tif ( limiterViewportIntersectRect ) {\n\t\t\t\t\t// If the limiter is within the viewport, then check the intersection between that part of the\n\t\t\t\t\t// limiter and actual position.\n\t\t\t\t\tlimiterIntersectArea = limiterViewportIntersectRect.getIntersectionArea( positionRect );\n\t\t\t\t} else {\n\t\t\t\t\tlimiterIntersectArea = 0;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tlimiterIntersectArea = limiterRect.getIntersectionArea( positionRect );\n\t\t\t}\n\t\t}\n\n\t\tif ( viewportRect ) {\n\t\t\tviewportIntersectArea = viewportRect.getIntersectionArea( positionRect );\n\t\t}\n\n\t\t// The only criterion: intersection with the viewport.\n\t\tif ( viewportRect && !limiterRect ) {\n\t\t\tif ( viewportIntersectArea > maxViewportIntersectArea ) {\n\t\t\t\tsetBestPosition();\n\t\t\t}\n\t\t}\n\t\t// The only criterion: intersection with the limiter.\n\t\telse if ( !viewportRect && limiterRect ) {\n\t\t\tif ( limiterIntersectArea > maxLimiterIntersectArea ) {\n\t\t\t\tsetBestPosition();\n\t\t\t}\n\t\t}\n\t\t// Two criteria: intersection with the viewport and the limiter visible in the viewport.\n\t\telse {\n\t\t\tif ( viewportIntersectArea > maxViewportIntersectArea && limiterIntersectArea >= maxLimiterIntersectArea ) {\n\t\t\t\tsetBestPosition();\n\t\t\t} else if ( viewportIntersectArea >= maxViewportIntersectArea && limiterIntersectArea > maxLimiterIntersectArea ) {\n\t\t\t\tsetBestPosition();\n\t\t\t}\n\t\t}\n\n\t\tfunction setBestPosition() {\n\t\t\tmaxViewportIntersectArea = viewportIntersectArea;\n\t\t\tmaxLimiterIntersectArea = limiterIntersectArea;\n\t\t\tbestPositionRect = positionRect;\n\t\t\tbestPositionName = positionName;\n\t\t}\n\n\t\t// If a such position is found that element is fully container by the limiter then, obviously,\n\t\t// there will be no better one, so finishing.\n\t\treturn limiterIntersectArea === elementRectArea;\n\t} );\n\n\treturn bestPositionRect ? [ bestPositionName, bestPositionRect ] : null;\n}\n\n// DOMRect (also Rect) works in a scroll–independent geometry but `position: absolute` doesn't.\n// This function converts Rect to `position: absolute` coordinates.\n//\n// @private\n// @param {utils/dom/rect~Rect} rect A rect to be converted.\n// @returns {Object} Object containing `left` and `top` properties, in absolute coordinates.\nfunction getAbsoluteRectCoordinates( { left, top } ) {\n\tconst { scrollX, scrollY } = global.window;\n\n\treturn {\n\t\tleft: left + scrollX,\n\t\ttop: top + scrollY,\n\t};\n}\n\n/**\n * The `getOptimalPosition` helper options.\n *\n * @interface module:utils/dom/position~Options\n */\n\n/**\n * Element that is to be positioned.\n *\n * @member {HTMLElement} #element\n */\n\n/**\n * Target with respect to which the `element` is to be positioned.\n *\n * @member {HTMLElement|Range|ClientRect|Rect|Function} #target\n */\n\n/**\n * An array of functions which return {@link module:utils/dom/position~Position} relative\n * to the `target`, in the order of preference.\n *\n * @member {Array.} #positions\n */\n\n/**\n * When set, the algorithm will chose position which fits the most in the\n * limiter's bounding rect.\n *\n * @member {HTMLElement|Range|ClientRect|Rect|Function} #limiter\n */\n\n/**\n * When set, the algorithm will chose such a position which fits `element`\n * the most inside visible viewport.\n *\n * @member {Boolean} #fitInViewport\n */\n\n/**\n * An object describing a position in `position: absolute` coordinate\n * system, along with position name.\n *\n * @typedef {Object} module:utils/dom/position~Position\n *\n * @property {Number} top Top position offset.\n * @property {Number} left Left position offset.\n * @property {String} name Name of the position.\n */\n","/**\n * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md.\n */\n\n/**\n * @module utils/dom/getpositionedancestor\n */\n\nimport global from './global';\n\n/**\n * For a given element, returns the nearest ancestor element which CSS position is not \"static\".\n *\n * @param {HTMLElement} element The native DOM element to be checked.\n * @returns {HTMLElement|null}\n */\nexport default function getPositionedAncestor( element ) {\n\twhile ( element && element.tagName.toLowerCase() != 'html' ) {\n\t\tif ( global.window.getComputedStyle( element ).position != 'static' ) {\n\t\t\treturn element;\n\t\t}\n\n\t\telement = element.parentElement;\n\t}\n\n\treturn null;\n}\n","/**\n * @license Copyright (c) 2003-2019, 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 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 * 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 \"arrow_nw\" position. The class\n\t\t * controls the minor aspects of the balloon's visual appearance like 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 `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 pining 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 * 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\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 choses 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 chose 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 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.southArrowNorthWest,\n\t\t\t\tdefaultPositions.southArrowNorthEast,\n\t\t\t\tdefaultPositions.northArrowSouth,\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 { top, left, name: position } = BalloonPanelView._getOptimalPosition( positionOptions );\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 * 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's none,\n// e.g. when 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 {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView#attachTo} method.\n *\n * The available positioning functions are as follow:\n *\n * **North**\n *\n * * `northArrowSouth`\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 * * `northArrowSouthWest`\n *\n * \t\t +-----------------+\n * \t\t | Balloon |\n * \t\t +-----------------+\n * \t\t V\n * \t\t[ Target ]\n *\n * **North west**\n *\n * * `northWestArrowSouth`\n *\n * \t\t+-----------------+\n * \t\t| Balloon |\n * \t\t+-----------------+\n * \t\t V\n * \t\t [ Target ]\n *\n * * `northWestArrowSouthWest`\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 * **North east**\n *\n * * `northEastArrowSouth`\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 * * `northEastArrowSouthWest`\n *\n * \t\t +-----------------+\n * \t\t | Balloon |\n * \t\t +-----------------+\n * \t\t V\n * \t\t[ Target ]\n *\n * **South**\n *\n * * `southArrowNorth`\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 * * `southArrowNorthWest`\n *\n *\t\t[ Target ]\n *\t\t ^\n *\t\t +-----------------+\n *\t\t | Balloon |\n *\t\t +-----------------+\n *\n * **South west**\n *\n * * `southWestArrowNorth`\n *\n *\t\t [ Target ]\n *\t\t ^\n *\t\t+-----------------+\n *\t\t| Balloon |\n *\t\t+-----------------+\n *\n * * `southWestArrowNorthWest`\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 * **South east**\n *\n * * `southEastArrowNorth`\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 * * `southEastArrowNorthWest`\n *\n *\t\t[ Target ]\n *\t\t ^\n *\t\t +-----------------+\n *\t\t | Balloon |\n *\t\t +-----------------+\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 position function returns will be reflected in 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\t// ------- North\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\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\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\t// ------- North west\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\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\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 east\n\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\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\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\t// ------- South\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\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\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\n\t// ------- South west\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\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\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 east\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\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\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\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","/**\n * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md.\n */\n\n/**\n * @module utils/dom/tounit\n */\n\n/**\n * Returns a helper function, which adds a desired trailing\n * `unit` to the passed value.\n *\n * @param {String} unit An unit like \"px\" or \"em\".\n * @returns {module:utils/dom/tounit~helper}\n */\nexport default function toUnit( unit ) {\n\t/**\n\t * A function, which adds a pre–defined trailing `unit`\n\t * to the passed `value`.\n\t *\n\t * @function helper\n \t * @param {*} value A value to be given the unit.\n \t * @returns {String} A value with the trailing unit.\n\t */\n\treturn value => value + unit;\n}\n","/**\n * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md.\n */\n\n/**\n * @module ui/panel/balloon/contextualballoon\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport BalloonPanelView from './balloonpanelview';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * Provides the common contextual balloon panel for the editor.\n *\n * This plugin allows reusing a single {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView} instance\n * to display multiple contextual balloon panels in the editor.\n *\n * Child views of such a panel are stored in the stack and the last one in the stack is visible. When the\n * visible view is removed from the stack, the previous view becomes visible, etc. If there are no more\n * views in the stack, the balloon panel will hide.\n *\n * It simplifies managing the views and helps\n * avoid the unnecessary complexity of handling multiple {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView}\n * instances in the editor.\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\tinit() {\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();\n\n\t\t/**\n\t\t * The {@link module:utils/dom/position~Options#limiter position limiter}\n\t\t * for the {@link #view}, 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, which 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 * Stack of the views injected into the balloon. Last one in the stack is displayed\n\t\t * as a content of {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon#view}.\n\t\t *\n\t\t * @private\n\t\t * @member {Map} #_stack\n\t\t */\n\t\tthis._stack = new Map();\n\n\t\t// Add balloon panel view to editor `body` collection and wait until view will be ready.\n\t\tthis.editor.ui.view.body.add( this.view );\n\n\t\t// Editor should be focused when contextual balloon is focused.\n\t\tthis.editor.ui.focusTracker.add( this.view.element );\n\t}\n\n\t/**\n\t * Returns the currently visible view or `null` when there are no\n\t * views in the stack.\n\t *\n\t * @returns {module:ui/view~View|null}\n\t */\n\tget visibleView() {\n\t\tconst item = this._stack.get( this.view.content.get( 0 ) );\n\n\t\treturn item ? item.view : null;\n\t}\n\n\t/**\n\t * Returns `true` when the given view is in the stack. 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 this._stack.has( view );\n\t}\n\n\t/**\n\t * Adds a new view to the stack and makes it visible.\n\t *\n\t * @param {Object} data Configuration of the view.\n\t * @param {module:ui/view~View} [data.view] Content of the balloon.\n\t * @param {module:utils/dom/position~Options} [data.position] Positioning options.\n\t * @param {String} [data.balloonClassName] Additional css class for {@link #view} added when given view is visible.\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( 'contextualballoon-add-view-exist: Cannot add configuration of the same view twice.' );\n\t\t}\n\n\t\t// When adding view to the not empty balloon.\n\t\tif ( this.visibleView ) {\n\t\t\t// Remove displayed content from the view.\n\t\t\tthis.view.content.remove( this.visibleView );\n\t\t}\n\n\t\t// Add new view to the stack.\n\t\tthis._stack.set( data.view, data );\n\n\t\t// And display it.\n\t\tthis._show( data );\n\t}\n\n\t/**\n\t * Removes the given view from the stack. If the removed view was visible,\n\t * then the view preceding it in the stack will become visible instead.\n\t * When there is no view in the stack then 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 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( 'contextualballoon-remove-view-not-exist: Cannot remove configuration of not existing view.' );\n\t\t}\n\n\t\t// When visible view is being removed.\n\t\tif ( this.visibleView === view ) {\n\t\t\t// We need to remove it from the view content.\n\t\t\tthis.view.content.remove( view );\n\n\t\t\t// And then remove from the stack.\n\t\t\tthis._stack.delete( view );\n\n\t\t\t// Next we need to check if there is other view in stack to show.\n\t\t\tconst last = Array.from( this._stack.values() ).pop();\n\n\t\t\t// If it is some other view.\n\t\t\tif ( last ) {\n\t\t\t\t// Just show it.\n\t\t\t\tthis._show( last );\n\t\t\t} else {\n\t\t\t\t// Hide the balloon panel.\n\t\t\t\tthis.view.hide();\n\t\t\t}\n\t\t} else {\n\t\t\t// Just remove given view from the stack.\n\t\t\tthis._stack.delete( view );\n\t\t}\n\t}\n\n\t/**\n\t * Updates the position of the balloon using position data of the first visible view in the stack.\n\t * When new position data is given then position data of currently visible panel 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._stack.get( this.visibleView ).position = position;\n\t\t}\n\n\t\tthis.view.pin( this._getBalloonPosition() );\n\t}\n\n\t/**\n\t * Sets the view as a content of the balloon and attaches 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] View to show in the balloon.\n\t * @param {String} [data.balloonClassName=''] Additional class name which will added to the {#_balloon} view.\n\t */\n\t_show( { view, balloonClassName = '' } ) {\n\t\tthis.view.class = balloonClassName;\n\n\t\tthis.view.content.add( view );\n\t\tthis.view.pin( this._getBalloonPosition() );\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 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._stack.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 * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md.\n */\n\n/* global setTimeout, clearTimeout */\n\n/**\n * @module utils/focustracker\n */\n\nimport DomEmitterMixin from './dom/emittermixin';\nimport ObservableMixin from './observablemixin';\nimport CKEditorError from './ckeditorerror';\nimport mix from './mix';\n\n/**\n * Allows observing a group of `HTMLElement`s whether at least one of them is focused.\n *\n * Used by the {@link module:core/editor/editor~Editor} in order to track whether the focus is still within the application,\n * or were used outside of its UI.\n *\n * **Note** `focus` and `blur` listeners use event capturing, so it is only needed to register wrapper `HTMLElement`\n * which contain other `focusable` elements. But note that this wrapper element has to be focusable too\n * (have e.g. `tabindex=\"-1\"`).\n *\n * @mixes module:utils/dom/emittermixin~EmitterMixin\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class FocusTracker {\n\tconstructor() {\n\t\t/**\n\t\t * True when one of the registered elements is focused.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Boolean} #isFocused\n\t\t */\n\t\tthis.set( 'isFocused', false );\n\n\t\t/**\n\t\t * Currently focused element.\n\t\t *\n\t\t * @readonly\n\t\t * @member {HTMLElement}\n\t\t */\n\t\tthis.focusedElement = null;\n\n\t\t/**\n\t\t * List of registered elements.\n\t\t *\n\t\t * @private\n\t\t * @member {Set.}\n\t\t */\n\t\tthis._elements = new Set();\n\n\t\t/**\n\t\t * Event loop timeout.\n\t\t *\n\t\t * @private\n\t\t * @member {Number}\n\t\t */\n\t\tthis._nextEventLoopTimeout = null;\n\t}\n\n\t/**\n\t * Starts tracking the specified element.\n\t *\n\t * @param {HTMLElement} element\n\t */\n\tadd( element ) {\n\t\tif ( this._elements.has( element ) ) {\n\t\t\tthrow new CKEditorError( 'focusTracker-add-element-already-exist' );\n\t\t}\n\n\t\tthis.listenTo( element, 'focus', () => this._focus( element ), { useCapture: true } );\n\t\tthis.listenTo( element, 'blur', () => this._blur(), { useCapture: true } );\n\t\tthis._elements.add( element );\n\t}\n\n\t/**\n\t * Stops tracking the specified element and stops listening on this element.\n\t *\n\t * @param {HTMLElement} element\n\t */\n\tremove( element ) {\n\t\tif ( element === this.focusedElement ) {\n\t\t\tthis._blur( element );\n\t\t}\n\n\t\tif ( this._elements.has( element ) ) {\n\t\t\tthis.stopListening( element );\n\t\t\tthis._elements.delete( element );\n\t\t}\n\t}\n\n\t/**\n\t * Destroys the focus tracker by:\n\t * - Disabling all event listeners attached to tracked elements.\n\t * - Removing all tracked elements that were previously added.\n\t */\n\tdestroy() {\n\t\tthis.stopListening();\n\t}\n\n\t/**\n\t * Stores currently focused element and set {#isFocused} as `true`.\n\t *\n\t * @private\n\t * @param {HTMLElement} element Element which has been focused.\n\t */\n\t_focus( element ) {\n\t\tclearTimeout( this._nextEventLoopTimeout );\n\n\t\tthis.focusedElement = element;\n\t\tthis.isFocused = true;\n\t}\n\n\t/**\n\t * Clears currently focused element and set {@link #isFocused} as `false`.\n\t * This method uses `setTimeout` to change order of fires `blur` and `focus` events.\n\t *\n\t * @private\n\t * @fires blur\n\t */\n\t_blur() {\n\t\tclearTimeout( this._nextEventLoopTimeout );\n\n\t\tthis._nextEventLoopTimeout = setTimeout( () => {\n\t\t\tthis.focusedElement = null;\n\t\t\tthis.isFocused = false;\n\t\t}, 0 );\n\t}\n\n\t/**\n\t * @event focus\n\t */\n\n\t/**\n\t * @event blur\n\t */\n}\n\nmix( FocusTracker, DomEmitterMixin );\nmix( FocusTracker, ObservableMixin );\n","/**\n * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md.\n */\n\n/**\n * @module ui/focuscycler\n */\n\nimport global from '@ckeditor/ckeditor5-utils/src/dom/global';\n\n/**\n * A utility class that helps cycling over focusable {@link module:ui/view~View views} in a\n * {@link module:ui/viewcollection~ViewCollection} when the focus is tracked by the\n * {@link module:utils/focustracker~FocusTracker} instance. It helps implementing keyboard\n * navigation in HTML forms, toolbars, lists and the like.\n *\n * To work properly it requires:\n * * a collection of focusable (HTML `tabindex` attribute) views that implement the `focus()` method,\n * * an associated focus tracker to determine which view is focused.\n *\n * A simple cycler setup can look like this:\n *\n *\t\tconst focusables = new ViewCollection();\n *\t\tconst focusTracker = new FocusTracker();\n *\n *\t\t// Add focusable views to the focus tracker.\n *\t\tfocusTracker.add( ... );\n *\n * Then, the cycler can be used manually:\n *\n *\t\tconst cycler = new FocusCycler( { focusables, focusTracker } );\n *\n *\t\t// Will focus the first focusable view in #focusables.\n *\t\tcycler.focusFirst();\n *\n *\t\t// Will log the next focusable item in #focusables.\n *\t\tconsole.log( cycler.next );\n *\n * Alternatively, it can work side by side with the {@link module:utils/keystrokehandler~KeystrokeHandler}:\n *\n *\t\tconst keystrokeHandler = new KeystrokeHandler();\n *\n *\t\t// Activate the keystroke handler.\n *\t\tkeystrokeHandler.listenTo( sourceOfEvents );\n *\n *\t\tconst cycler = new FocusCycler( {\n *\t\t\tfocusables, focusTracker, keystrokeHandler,\n *\t\t\tactions: {\n *\t\t\t\t// When arrowup of arrowleft is detected by the #keystrokeHandler,\n *\t\t\t\t// focusPrevious() will be called on the cycler.\n *\t\t\t\tfocusPrevious: [ 'arrowup', 'arrowleft' ],\n *\t\t\t}\n *\t\t} );\n */\nexport default class FocusCycler {\n\t/**\n\t * Creates an instance of the focus cycler utility.\n\t *\n\t * @param {Object} options Configuration options.\n\t * @param {module:utils/collection~Collection|Object} options.focusables\n\t * @param {module:utils/focustracker~FocusTracker} options.focusTracker\n\t * @param {module:utils/keystrokehandler~KeystrokeHandler} [options.keystrokeHandler]\n\t * @param {Object} [options.actions]\n\t */\n\tconstructor( options ) {\n\t\tObject.assign( this, options );\n\n\t\t/**\n\t\t * A {@link module:ui/view~View view} collection that the cycler operates on.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/collection~Collection} #focusables\n\t\t */\n\n\t\t/**\n\t\t * A focus tracker instance that the cycler uses to determine the current focus\n\t\t * state in {@link #focusables}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/focustracker~FocusTracker} #focusTracker\n\t\t */\n\n\t\t/**\n\t\t * An instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}\n\t\t * which can respond to certain keystrokes and cycle the focus.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/keystrokehandler~KeystrokeHandler} #keystrokeHandler\n\t\t */\n\n\t\t/**\n\t\t * Actions that the cycler can take when a keystroke is pressed. Requires\n\t\t * `options.keystrokeHandler` to be passed and working. When an action is\n\t\t * performed, `preventDefault` and `stopPropagation` will be called on the event\n\t\t * the keystroke fired in the DOM.\n\t\t *\n\t\t *\t\tactions: {\n\t\t *\t\t\t// Will call #focusPrevious() when arrowleft or arrowup is pressed.\n\t\t *\t\t\tfocusPrevious: [ 'arrowleft', 'arrowup' ],\n\t\t *\n\t\t *\t\t\t// Will call #focusNext() when arrowdown is pressed.\n\t\t *\t\t\tfocusNext: 'arrowdown'\n\t\t *\t\t}\n\t\t *\n\t\t * @readonly\n\t\t * @member {Object} #actions\n\t\t */\n\n\t\tif ( options.actions && options.keystrokeHandler ) {\n\t\t\tfor ( const methodName in options.actions ) {\n\t\t\t\tlet actions = options.actions[ methodName ];\n\n\t\t\t\tif ( typeof actions == 'string' ) {\n\t\t\t\t\tactions = [ actions ];\n\t\t\t\t}\n\n\t\t\t\tfor ( const keystroke of actions ) {\n\t\t\t\t\toptions.keystrokeHandler.set( keystroke, ( data, cancel ) => {\n\t\t\t\t\t\tthis[ methodName ]();\n\t\t\t\t\t\tcancel();\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Returns the first focusable view in {@link #focusables}.\n\t * Returns `null` if there is none.\n\t *\n\t * @readonly\n\t * @member {module:ui/view~View|null} #first\n\t */\n\tget first() {\n\t\treturn this.focusables.find( isFocusable ) || null;\n\t}\n\n\t/**\n\t * Returns the last focusable view in {@link #focusables}.\n\t * Returns `null` if there is none.\n\t *\n\t * @readonly\n\t * @member {module:ui/view~View|null} #last\n\t */\n\tget last() {\n\t\treturn this.focusables.filter( isFocusable ).slice( -1 )[ 0 ] || null;\n\t}\n\n\t/**\n\t * Returns the next focusable view in {@link #focusables} based on {@link #current}.\n\t * Returns `null` if there is none.\n\t *\n\t * @readonly\n\t * @member {module:ui/view~View|null} #next\n\t */\n\tget next() {\n\t\treturn this._getFocusableItem( 1 );\n\t}\n\n\t/**\n\t * Returns the previous focusable view in {@link #focusables} based on {@link #current}.\n\t * Returns `null` if there is none.\n\t *\n\t * @readonly\n\t * @member {module:ui/view~View|null} #previous\n\t */\n\tget previous() {\n\t\treturn this._getFocusableItem( -1 );\n\t}\n\n\t/**\n\t * An index of the view in the {@link #focusables} which is focused according\n\t * to {@link #focusTracker}. Returns `null` when there is no such view.\n\t *\n\t * @readonly\n\t * @member {Number|null} #current\n\t */\n\tget current() {\n\t\tlet index = null;\n\n\t\t// There's no focused view in the focusables.\n\t\tif ( this.focusTracker.focusedElement === null ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tthis.focusables.find( ( view, viewIndex ) => {\n\t\t\tconst focused = view.element === this.focusTracker.focusedElement;\n\n\t\t\tif ( focused ) {\n\t\t\t\tindex = viewIndex;\n\t\t\t}\n\n\t\t\treturn focused;\n\t\t} );\n\n\t\treturn index;\n\t}\n\n\t/**\n\t * Focuses the {@link #first} item in {@link #focusables}.\n\t */\n\tfocusFirst() {\n\t\tthis._focus( this.first );\n\t}\n\n\t/**\n\t * Focuses the {@link #last} item in {@link #focusables}.\n\t */\n\tfocusLast() {\n\t\tthis._focus( this.last );\n\t}\n\n\t/**\n\t * Focuses the {@link #next} item in {@link #focusables}.\n\t */\n\tfocusNext() {\n\t\tthis._focus( this.next );\n\t}\n\n\t/**\n\t * Focuses the {@link #previous} item in {@link #focusables}.\n\t */\n\tfocusPrevious() {\n\t\tthis._focus( this.previous );\n\t}\n\n\t/**\n\t * Focuses the given view if it exists.\n\t *\n\t * @protected\n\t * @param {module:ui/view~View} view\n\t */\n\t_focus( view ) {\n\t\tif ( view ) {\n\t\t\tview.focus();\n\t\t}\n\t}\n\n\t/**\n\t * Returns the next or previous focusable view in {@link #focusables} with respect\n\t * to {@link #current}.\n\t *\n\t * @protected\n\t * @param {Number} step Either `1` for checking forward from {@link #current} or\n\t * `-1` for checking backwards.\n\t * @returns {module:ui/view~View|null}\n\t */\n\t_getFocusableItem( step ) {\n\t\t// Cache for speed.\n\t\tconst current = this.current;\n\t\tconst collectionLength = this.focusables.length;\n\n\t\tif ( !collectionLength ) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Start from the beginning if no view is focused.\n\t\t// https://github.com/ckeditor/ckeditor5-ui/issues/206\n\t\tif ( current === null ) {\n\t\t\treturn this[ step === 1 ? 'first' : 'last' ];\n\t\t}\n\n\t\t// Cycle in both directions.\n\t\tlet index = ( current + collectionLength + step ) % collectionLength;\n\n\t\tdo {\n\t\t\tconst view = this.focusables.get( index );\n\n\t\t\t// TODO: Check if view is visible.\n\t\t\tif ( isFocusable( view ) ) {\n\t\t\t\treturn view;\n\t\t\t}\n\n\t\t\t// Cycle in both directions.\n\t\t\tindex = ( index + collectionLength + step ) % collectionLength;\n\t\t} while ( index !== current );\n\n\t\treturn null;\n\t}\n}\n\n// Checks whether a view is focusable.\n//\n// @private\n// @param {module:ui/view~View} view A view to be checked.\n// @returns {Boolean}\nfunction isFocusable( view ) {\n\treturn !!( view.focus && global.window.getComputedStyle( view.element ).display != 'none' );\n}\n","/**\n * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md.\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-2019, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md.\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 preventDefault from '../bindings/preventdefault.js';\nimport log from '@ckeditor/ckeditor5-utils/src/log';\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 * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\tconst bind = this.bindTemplate;\n\n\t\t/**\n\t\t * Collection of the toolbar items (like buttons).\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 DOM focus in the list.\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 * Instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}.\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 * Controls the orientation of toolbar items.\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} #isVertical\n\t\t */\n\t\tthis.set( 'isVertical', false );\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 * Helps cycling over focusable {@link #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.items,\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\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',\n\t\t\t\t\tbind.if( 'isVertical', 'ck-toolbar_vertical' ),\n\t\t\t\t\tbind.to( 'class' )\n\t\t\t\t]\n\t\t\t},\n\n\t\t\tchildren: this.items,\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\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\t// Items 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\t}\n\n\t/**\n\t * Focuses the first focusable in {@link #items}.\n\t */\n\tfocus() {\n\t\tthis._focusCycler.focusFirst();\n\t}\n\n\t/**\n\t * Focuses the last focusable in {@link #items}.\n\t */\n\tfocusLast() {\n\t\tthis._focusCycler.focusLast();\n\t}\n\n\t/**\n\t * A utility which expands a plain toolbar configuration into\n\t * {@link module:ui/toolbar/toolbarview~ToolbarView#items} using a given component factory.\n\t *\n\t * @param {Array.} config The toolbar items config.\n\t * @param {module:ui/componentfactory~ComponentFactory} factory A factory producing toolbar items.\n\t */\n\tfillFromConfig( config, factory ) {\n\t\tconfig.map( name => {\n\t\t\tif ( name == '|' ) {\n\t\t\t\tthis.items.add( new ToolbarSeparatorView() );\n\t\t\t} else if ( factory.has( name ) ) {\n\t\t\t\tthis.items.add( factory.create( name ) );\n\t\t\t} else {\n\t\t\t\t/**\n\t\t\t\t * There was a problem processing the configuration of the toolbar. The item with the given\n\t\t\t\t * name does not exist so it was omitted when rendering the toolbar.\n\t\t\t\t *\n\t\t\t\t * This warning usually shows up when the {@link module:core/plugin~Plugin} which is supposed\n\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 *\n\t\t\t\t * Make sure the plugin responsible for this toolbar item is loaded and the toolbar configuration\n\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 *\n\t\t\t\t * You can use the following snippet to retrieve all available toolbar items:\n\t\t\t\t *\n\t\t\t\t *\t\tArray.from( editor.ui.componentFactory.names() );\n\t\t\t\t *\n\t\t\t\t * @error toolbarview-item-unavailable\n\t\t\t\t * @param {String} name The name of the component.\n\t\t\t\t */\n\t\t\t\tlog.warn(\n\t\t\t\t\t'toolbarview-item-unavailable: The requested toolbar item is unavailable.',\n\t\t\t\t\t{ name }\n\t\t\t\t);\n\t\t\t}\n\t\t} );\n\t}\n}\n\n","/**\n * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md.\n */\n\n/**\n * @module ui/bindings/preventdefault\n */\n\n/**\n * A helper which executes a native `Event.preventDefault()` if the target of an event equals the\n * {@link module:ui/view~View#element element of the view}. It shortens the definition of a\n * {@link module:ui/view~View#template template}.\n *\n *\t\t// In a class extending View.\n *\t\timport preventDefault from '@ckeditor/ckeditor5-ui/src/bindings/preventdefault';\n *\n *\t\t// ...\n *\n *\t\tthis.setTemplate( {\n *\t\t\ttag: 'div',\n *\n *\t\t\ton: {\n *\t\t\t\t// Prevent the default mousedown action on this view.\n *\t\t\t\tmousedown: preventDefault( this )\n *\t\t\t}\n *\t\t} );\n *\n * @param {module:ui/view~View} view View instance that defines the template.\n * @returns {module:ui/template~TemplateToBinding}\n */\nexport default function preventDefault( view ) {\n\treturn view.bindTemplate.to( evt => {\n\t\tif ( evt.target === view.element ) {\n\t\t\tevt.preventDefault();\n\t\t}\n\t} );\n}\n","/**\n * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md.\n */\n\n/**\n * @module ui/toolbar/balloon/balloontoolbar\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\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';\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 * 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 * 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\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 config = normalizeToolbarConfig( this.editor.config.get( 'balloonToolbar' ) );\n\t\tconst factory = this.editor.ui.componentFactory;\n\n\t\tthis.toolbarView.fillFromConfig( config.items, 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 toolbarView = new ToolbarView( this.editor.locale );\n\n\t\ttoolbarView.extendTemplate( {\n\t\t\tattributes: {\n\t\t\t\tclass: [ 'ck-toolbar_floating' ]\n\t\t\t}\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\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 ( editor.model.document.selection.isCollapsed ) {\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._balloon.updatePosition( this._getBalloonPositionData() );\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 * @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\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.southWestArrowNorth,\n\t\tdefaultPositions.southWestArrowNorthWest,\n\t\tdefaultPositions.southWestArrowNorthEast\n\t] : [\n\t\tdefaultPositions.southEastArrowNorth,\n\t\tdefaultPositions.southEastArrowNorthEast,\n\t\tdefaultPositions.southEastArrowNorthWest,\n\t\tdefaultPositions.northEastArrowSouth,\n\t\tdefaultPositions.northEastArrowSouthEast,\n\t\tdefaultPositions.northEastArrowSouthWest\n\t];\n}\n\n/**\n * Contextual toolbar configuration. Used by the {@link module:ui/toolbar/balloon/balloontoolbar~BalloonToolbar}\n * feature.\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 * @member {Array.|Object} module:core/editor/editorconfig~EditorConfig#balloonToolbar\n */\n","/**\n * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md.\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\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};\n\t}\n\n\tif ( !config ) {\n\t\treturn {\n\t\t\titems: []\n\t\t};\n\t}\n\n\treturn Object.assign( {\n\t\titems: []\n\t}, config );\n}\n","/**\n * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md.\n */\n\n/**\n * @module ui/componentfactory\n */\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * A helper class implementing the UI component ({@link module:ui/view~View view}) factory.\n *\n * It allows functions producing specific UI components to be registered under their unique names\n * in the factory. A registered component can be then instantiated by providing its name.\n * Note that names are case insensitive.\n *\n *\t\t// The editor provides localization tools for the factory.\n *\t\tconst factory = new ComponentFactory( editor );\n *\n *\t\tfactory.add( 'foo', locale => new FooView( locale ) );\n *\t\tfactory.add( 'bar', locale => new BarView( locale ) );\n *\n *\t\t// An instance of FooView.\n *\t\tconst fooInstance = factory.create( 'foo' );\n *\n *\t\t// Names are case insensitive so this is also allowed:\n *\t\tconst barInstance = factory.create( 'Bar' );\n *\n * The {@link module:core/editor/editor~Editor#locale editor locale} is passed to the factory\n * function when {@link module:ui/componentfactory~ComponentFactory#create} is called.\n */\nexport default class ComponentFactory {\n\t/**\n\t * Creates an instance of the factory.\n\t *\n\t * @constructor\n\t * @param {module:core/editor/editor~Editor} editor The editor instance.\n\t */\n\tconstructor( editor ) {\n\t\t/**\n\t\t * The editor instance that the factory belongs to.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:core/editor/editor~Editor}\n\t\t */\n\t\tthis.editor = editor;\n\n\t\t/**\n\t\t * Registered component factories.\n\t\t *\n\t\t * @private\n\t\t * @member {Map}\n\t\t */\n\t\tthis._components = new Map();\n\t}\n\n\t/**\n\t * Returns an iterator of registered component names. Names are returned in lower case.\n\t *\n\t * @returns {Iterable.}\n\t */\n\t* names() {\n\t\tfor ( const value of this._components.values() ) {\n\t\t\tyield value.originalName;\n\t\t}\n\t}\n\n\t/**\n\t * Registers a component factory function that will be used by the\n\t * {@link #create create} method and called with the\n\t * {@link module:core/editor/editor~Editor#locale editor locale} as an argument,\n\t * allowing localization of the {@link module:ui/view~View view}.\n\t *\n\t * @param {String} name The name of the component.\n\t * @param {Function} callback The callback that returns the component.\n\t */\n\tadd( name, callback ) {\n\t\tif ( this.has( name ) ) {\n\t\t\t/**\n\t\t\t * The item already exists in the component factory.\n\t\t\t *\n\t\t\t * @error componentfactory-item-exists\n\t\t\t * @param {String} name The name of the component.\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'componentfactory-item-exists: The item already exists in the component factory.', { name }\n\t\t\t);\n\t\t}\n\n\t\tthis._components.set( getNormalized( name ), { callback, originalName: name } );\n\t}\n\n\t/**\n\t * Creates an instance of a component registered in the factory under a specific name.\n\t *\n\t * When called, the {@link module:core/editor/editor~Editor#locale editor locale} is passed to\n\t * the previously {@link #add added} factory function, allowing localization of the\n\t * {@link module:ui/view~View view}.\n\t *\n\t * @param {String} name The name of the component.\n\t * @returns {module:ui/view~View} The instantiated component view.\n\t */\n\tcreate( name ) {\n\t\tif ( !this.has( name ) ) {\n\t\t\t/**\n\t\t\t * The required component is not registered in the component factory. Please make sure\n\t\t\t * the provided name is correct and the component has been correctly\n\t\t\t * {@link #add added} to the factory.\n\t\t\t *\n\t\t\t * @error componentfactory-item-missing\n\t\t\t * @param {String} name The name of the missing component.\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'componentfactory-item-missing: The required component is not registered in the factory.', { name }\n\t\t\t);\n\t\t}\n\n\t\treturn this._components.get( getNormalized( name ) ).callback( this.editor.locale );\n\t}\n\n\t/**\n\t * Checks if a component of a given name is registered in the factory.\n\t *\n\t * @param {String} name The name of the component.\n\t * @returns {Boolean}\n\t */\n\thas( name ) {\n\t\treturn this._components.has( getNormalized( name ) );\n\t}\n}\n\n//\n// Ensures that the component name used as the key in the internal map is in lower case.\n//\n// @private\n// @param {String} name\n// @returns {String}\nfunction getNormalized( name ) {\n\treturn String( name ).toLowerCase();\n}\n","/**\n * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md.\n */\n\n/**\n * @module core/editor/editorui\n */\n\nimport ComponentFactory from '@ckeditor/ckeditor5-ui/src/componentfactory';\nimport FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker';\n\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\n\n/**\n * A class providing the minimal interface that is required to successfully bootstrap any editor UI.\n *\n * @mixes module:utils/emittermixin~EmitterMixin\n */\nexport default class EditorUI {\n\t/**\n\t * Creates an instance of the editor UI class.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor The editor instance.\n\t */\n\tconstructor( editor ) {\n\t\t/**\n\t\t * The editor that the UI belongs to.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:core/editor/editor~Editor} #editor\n\t\t */\n\t\tthis.editor = editor;\n\n\t\t/**\n\t\t * An instance of the {@link module:ui/componentfactory~ComponentFactory}, a registry used by plugins\n\t\t * to register factories of specific UI components.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/componentfactory~ComponentFactory} #componentFactory\n\t\t */\n\t\tthis.componentFactory = new ComponentFactory( editor );\n\n\t\t/**\n\t\t * Stores the information about the editor UI focus and propagates it so various plugins and components\n\t\t * are unified as a focus group.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/focustracker~FocusTracker} #focusTracker\n\t\t */\n\t\tthis.focusTracker = new FocusTracker();\n\n\t\t/**\n\t\t * Stores all editable elements used by the editor instance.\n\t\t *\n\t\t * @protected\n\t\t * @member {Map.}\n\t\t */\n\t\tthis._editableElements = new Map();\n\n\t\t// Informs UI components that should be refreshed after layout change.\n\t\tthis.listenTo( editor.editing.view.document, 'layoutChanged', () => this.update() );\n\t}\n\n\t/**\n\t * The main (outermost) DOM element of the editor UI.\n\t *\n\t * For example, in {@link module:editor-classic/classiceditor~ClassicEditor} it is a `` which\n\t * wraps the editable element and the toolbar. In {@link module:editor-inline/inlineeditor~InlineEditor}\n\t * it is the editable element itself (as there is no other wrapper). However, in\n\t * {@link module:editor-decoupled/decouplededitor~DecoupledEditor} it is set to `null` because this editor does not\n\t * come with a single \"main\" HTML element (its editable element and toolbar are separate).\n\t *\n\t * This property can be understood as a shorthand for retrieving the element that a specific editor integration\n\t * considers to be its main DOM element.\n\t *\n\t * @readonly\n\t * @member {HTMLElement|null} #element\n\t */\n\tget element() {\n\t\treturn null;\n\t}\n\n\t/**\n\t * Fires the {@link module:core/editor/editorui~EditorUI#event:update `update`} event.\n\t *\n\t * This method should be called when the editor UI (e.g. positions of its balloons) needs to be updated due to\n\t * some environmental change which CKEditor 5 is not aware of (e.g. resize of a container in which it is used).\n\t */\n\tupdate() {\n\t\tthis.fire( 'update' );\n\t}\n\n\t/**\n\t * Destroys the UI.\n\t */\n\tdestroy() {\n\t\tthis.stopListening();\n\n\t\tthis.focusTracker.destroy();\n\n\t\tthis._editableElements = new Map();\n\t}\n\n\t/**\n\t * Returns the editable editor element with the given name or null if editable does not exist.\n\t *\n\t * @param {String} [rootName=main] The editable name.\n\t * @returns {HTMLElement|undefined}\n\t */\n\tgetEditableElement( rootName = 'main' ) {\n\t\treturn this._editableElements.get( rootName );\n\t}\n\n\t/**\n\t * Returns array of names of all editor editable elements.\n\t *\n\t * @returns {Iterable.
}\n\t */\n\tgetEditableElementsNames() {\n\t\treturn this._editableElements.keys();\n\t}\n\n\t/**\n\t * Fired when the editor UI is ready.\n\t *\n\t * Fired before {@link module:engine/controller/datacontroller~DataController#event:ready}.\n\t *\n\t * @event ready\n\t */\n\n\t/**\n\t * Fired whenever the UI (all related components) should be refreshed.\n\t *\n\t * **Note:**: The event is fired after each {@link module:engine/view/document~Document#event:layoutChanged}.\n\t * It can also be fired manually via the {@link module:core/editor/editorui~EditorUI#update} method.\n\t *\n\t * @event update\n\t */\n}\n\nmix( EditorUI, EmitterMixin );\n","/**\n * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md.\n */\n\n/**\n * @module engine/view/placeholder\n */\n\nimport '../../theme/placeholder.css';\n\n// Each document stores information about its placeholder elements and check functions.\nconst documentPlaceholders = new WeakMap();\n\n/**\n * A helper that enables a placeholder on the provided view element (also updates its visibility).\n * The placeholder is a CSS pseudo–element (with a text content) attached to the element.\n *\n * To change the placeholder text, simply call this method again with new options.\n *\n * To disable the placeholder, use {@link module:engine/view/placeholder~disablePlaceholder `disablePlaceholder()`} helper.\n *\n * @param {Object} [options] Configuration options of the placeholder.\n * @param {module:engine/view/view~View} options.view Editing view instance.\n * @param {module:engine/view/element~Element} options.element Element that will gain a placeholder.\n * See `options.isDirectHost` to learn more.\n * @param {String} options.text Placeholder text.\n * @param {Boolean} [options.isDirectHost=true] If set `false`, the placeholder will not be enabled directly\n * in the passed `element` but in one of its children (selected automatically, i.e. a first empty child element).\n * Useful when attaching placeholders to elements that can host other elements (not just text), for instance,\n * editable root elements.\n */\nexport function enablePlaceholder( options ) {\n\tconst { view, element, text, isDirectHost = true } = options;\n\tconst doc = view.document;\n\n\t// Use a single a single post fixer per—document to update all placeholders.\n\tif ( !documentPlaceholders.has( doc ) ) {\n\t\tdocumentPlaceholders.set( doc, new Map() );\n\n\t\t// If a post-fixer callback makes a change, it should return `true` so other post–fixers\n\t\t// can re–evaluate the document again.\n\t\tdoc.registerPostFixer( writer => updateDocumentPlaceholders( doc, writer ) );\n\t}\n\n\t// Store information about the element placeholder under its document.\n\tdocumentPlaceholders.get( doc ).set( element, {\n\t\ttext,\n\t\tisDirectHost\n\t} );\n\n\t// Update the placeholders right away.\n\tview.change( writer => updateDocumentPlaceholders( doc, writer ) );\n}\n\n/**\n * Disables the placeholder functionality from a given element.\n *\n * See {@link module:engine/view/placeholder~enablePlaceholder `enablePlaceholder()`} to learn more.\n *\n * @param {module:engine/view/view~View} view\n * @param {module:engine/view/element~Element} element\n */\nexport function disablePlaceholder( view, element ) {\n\tconst doc = element.document;\n\n\tview.change( writer => {\n\t\tif ( !documentPlaceholders.has( doc ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst placeholders = documentPlaceholders.get( doc );\n\t\tconst config = placeholders.get( element );\n\n\t\twriter.removeAttribute( 'data-placeholder', config.hostElement );\n\t\thidePlaceholder( writer, config.hostElement );\n\n\t\tplaceholders.delete( element );\n\t} );\n}\n\n/**\n * Shows a placeholder in the provided element by changing related attributes and CSS classes.\n *\n * **Note**: This helper will not update the placeholder visibility nor manage the\n * it in any way in the future. What it does is a one–time state change of an element. Use\n * {@link module:engine/view/placeholder~enablePlaceholder `enablePlaceholder()`} and\n * {@link module:engine/view/placeholder~disablePlaceholder `disablePlaceholder()`} for full\n * placeholder functionality.\n *\n * **Note**: This helper will blindly show the placeholder directly in the root editable element if\n * one is passed, which could result in a visual clash if the editable element has some children\n * (for instance, an empty paragraph). Use {@link module:engine/view/placeholder~enablePlaceholder `enablePlaceholder()`}\n * in that case or make sure the correct element is passed to the helper.\n *\n * @param {module:engine/view/downcastwriter~DowncastWriter} writer\n * @param {module:engine/view/element~Element} element\n * @returns {Boolean} `true`, if any changes were made to the `element`.\n */\nexport function showPlaceholder( writer, element ) {\n\tif ( !element.hasClass( 'ck-placeholder' ) ) {\n\t\twriter.addClass( 'ck-placeholder', element );\n\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\n/**\n * Hides a placeholder in the element by changing related attributes and CSS classes.\n *\n * **Note**: This helper will not update the placeholder visibility nor manage the\n * it in any way in the future. What it does is a one–time state change of an element. Use\n * {@link module:engine/view/placeholder~enablePlaceholder `enablePlaceholder()`} and\n * {@link module:engine/view/placeholder~disablePlaceholder `disablePlaceholder()`} for full\n * placeholder functionality.\n *\n * @param {module:engine/view/downcastwriter~DowncastWriter} writer\n * @param {module:engine/view/element~Element} element\n * @returns {Boolean} `true`, if any changes were made to the `element`.\n */\nexport function hidePlaceholder( writer, element ) {\n\tif ( element.hasClass( 'ck-placeholder' ) ) {\n\t\twriter.removeClass( 'ck-placeholder', element );\n\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\n/**\n * Checks if a placeholder should be displayed in the element.\n *\n * **Note**: This helper will blindly check the possibility of showing a placeholder directly in the\n * root editable element if one is passed, which may not be the expected result. If an element can\n * host other elements (not just text), most likely one of its children should be checked instead\n * because it will be the final host for the placeholder. Use\n * {@link module:engine/view/placeholder~enablePlaceholder `enablePlaceholder()`} in that case or make\n * sure the correct element is passed to the helper.\n *\n * @param {module:engine/view/downcastwriter~DowncastWriter} writer\n * @param {module:engine/view/element~Element} element\n * @param {String} text\n * @returns {Boolean}\n */\nexport function needsPlaceholder( element ) {\n\tconst doc = element.document;\n\n\t// The element was removed from document.\n\tif ( !doc ) {\n\t\treturn false;\n\t}\n\n\t// The element is empty only as long as it contains nothing but uiElements.\n\tconst isEmptyish = !Array.from( element.getChildren() )\n\t\t.some( element => !element.is( 'uiElement' ) );\n\n\t// If the element is empty and the document is blurred.\n\tif ( !doc.isFocused && isEmptyish ) {\n\t\treturn true;\n\t}\n\n\tconst viewSelection = doc.selection;\n\tconst selectionAnchor = viewSelection.anchor;\n\n\t// If document is focused and the element is empty but the selection is not anchored inside it.\n\tif ( isEmptyish && selectionAnchor && selectionAnchor.parent !== element ) {\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\n// Updates all placeholders associated with a document in a post–fixer callback.\n//\n// @private\n// @param { module:engine/model/document~Document} doc\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer\n// @returns {Boolean} True if any changes were made to the view document.\nfunction updateDocumentPlaceholders( doc, writer ) {\n\tconst placeholders = documentPlaceholders.get( doc );\n\tlet wasViewModified = false;\n\n\tfor ( const [ element, config ] of placeholders ) {\n\t\tif ( updatePlaceholder( writer, element, config ) ) {\n\t\t\twasViewModified = true;\n\t\t}\n\t}\n\n\treturn wasViewModified;\n}\n\n// Updates a single placeholder in a post–fixer callback.\n//\n// @private\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer\n// @param {module:engine/view/element~Element} element\n// @param {Object} config Configuration of the placeholder\n// @param {String} config.text\n// @param {Boolean} config.isDirectHost\n// @returns {Boolean} True if any changes were made to the view document.\nfunction updatePlaceholder( writer, element, config ) {\n\tconst { text, isDirectHost } = config;\n\tconst hostElement = isDirectHost ? element : getChildPlaceholderHostSubstitute( element );\n\tlet wasViewModified = false;\n\n\t// When not a direct host, it could happen that there is no child element\n\t// capable of displaying a placeholder.\n\tif ( !hostElement ) {\n\t\treturn false;\n\t}\n\n\t// Cache the host element. It will be necessary for disablePlaceholder() to know\n\t// which element should have class and attribute removed because, depending on\n\t// the config.isDirectHost value, it could be the element or one of its descendants.\n\tconfig.hostElement = hostElement;\n\n\t// This may be necessary when updating the placeholder text to something else.\n\tif ( hostElement.getAttribute( 'data-placeholder' ) !== text ) {\n\t\twriter.setAttribute( 'data-placeholder', text, hostElement );\n\t\twasViewModified = true;\n\t}\n\n\tif ( needsPlaceholder( hostElement ) ) {\n\t\tif ( showPlaceholder( writer, hostElement ) ) {\n\t\t\twasViewModified = true;\n\t\t}\n\t} else if ( hidePlaceholder( writer, hostElement ) ) {\n\t\twasViewModified = true;\n\t}\n\n\treturn wasViewModified;\n}\n\n// Gets a child element capable of displaying a placeholder if a parent element can host more\n// than just text (for instance, when it is a root editable element). The child element\n// can then be used in other placeholder helpers as a substitute of its parent.\n//\n// @private\n// @param {module:engine/view/element~Element} parent\n// @returns {module:engine/view/element~Element|null}\nfunction getChildPlaceholderHostSubstitute( parent ) {\n\tif ( parent.childCount === 1 ) {\n\t\tconst firstChild = parent.getChild( 0 );\n\n\t\tif ( firstChild.is( 'element' ) && !firstChild.is( 'uiElement' ) ) {\n\t\t\treturn firstChild;\n\t\t}\n\t}\n\n\treturn null;\n}\n","/**\n * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md.\n */\n\n/**\n * @module editor-balloon/ballooneditorui\n */\n\nimport EditorUI from '@ckeditor/ckeditor5-core/src/editor/editorui';\nimport enableToolbarKeyboardFocus from '@ckeditor/ckeditor5-ui/src/toolbar/enabletoolbarkeyboardfocus';\nimport { enablePlaceholder } from '@ckeditor/ckeditor5-engine/src/view/placeholder';\n\n/**\n * The balloon editor UI class.\n *\n * @extends module:core/editor/editorui~EditorUI\n */\nexport default class BalloonEditorUI extends EditorUI {\n\t/**\n\t * Creates an instance of the balloon editor UI class.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor The editor instance.\n\t * @param {module:ui/editorui/editoruiview~EditorUIView} view The view of the UI.\n\t */\n\tconstructor( editor, view ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * The main (top–most) view of the editor UI.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/editorui/editoruiview~EditorUIView} #view\n\t\t */\n\t\tthis.view = view;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tget element() {\n\t\treturn this.view.editable.element;\n\t}\n\n\t/**\n\t * Initializes the UI.\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst view = this.view;\n\t\tconst balloonToolbar = editor.plugins.get( 'BalloonToolbar' );\n\t\tconst editingView = editor.editing.view;\n\t\tconst editable = view.editable;\n\t\tconst editingRoot = editingView.document.getRoot();\n\n\t\t// The editable UI and editing root should share the same name. Then name is used\n\t\t// to recognize the particular editable, for instance in ARIA attributes.\n\t\teditable.name = editingRoot.rootName;\n\n\t\tview.render();\n\n\t\t// The editable UI element in DOM is available for sure only after the editor UI view has been rendered.\n\t\t// But it can be available earlier if a DOM element has been passed to BalloonEditor.create().\n\t\tconst editableElement = editable.element;\n\n\t\t// Register the editable UI view in the editor. A single editor instance can aggregate multiple\n\t\t// editable areas (roots) but the balloon editor has only one.\n\t\tthis._editableElements.set( editable.name, editableElement );\n\n\t\t// Let the global focus tracker know that the editable UI element is focusable and\n\t\t// belongs to the editor. From now on, the focus tracker will sustain the editor focus\n\t\t// as long as the editable is focused (e.g. the user is typing).\n\t\tthis.focusTracker.add( editableElement );\n\n\t\t// Let the editable UI element respond to the changes in the global editor focus\n\t\t// tracker. It has been added to the same tracker a few lines above but, in reality, there are\n\t\t// many focusable areas in the editor, like balloons, toolbars or dropdowns and as long\n\t\t// as they have focus, the editable should act like it is focused too (although technically\n\t\t// it isn't), e.g. by setting the proper CSS class, visually announcing focus to the user.\n\t\t// Doing otherwise will result in editable focus styles disappearing, once e.g. the\n\t\t// toolbar gets focused.\n\t\teditable.bind( 'isFocused' ).to( this.focusTracker );\n\n\t\t// Bind the editable UI element to the editing view, making it an end– and entry–point\n\t\t// of the editor's engine. This is where the engine meets the UI.\n\t\teditingView.attachDomRoot( editableElement );\n\n\t\tenableToolbarKeyboardFocus( {\n\t\t\torigin: editingView,\n\t\t\toriginFocusTracker: this.focusTracker,\n\t\t\toriginKeystrokeHandler: editor.keystrokes,\n\t\t\ttoolbar: balloonToolbar.toolbarView,\n\t\t\tbeforeFocus() {\n\t\t\t\tballoonToolbar.show();\n\t\t\t},\n\t\t\tafterBlur() {\n\t\t\t\tballoonToolbar.hide();\n\t\t\t}\n\t\t} );\n\n\t\tthis._initPlaceholder();\n\t\tthis.fire( 'ready' );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tconst view = this.view;\n\t\tconst editingView = this.editor.editing.view;\n\n\t\teditingView.detachDomRoot( view.editable.name );\n\t\tview.destroy();\n\n\t\tsuper.destroy();\n\t}\n\n\t/**\n\t * Enable the placeholder text on the editing root, if any was configured.\n\t *\n\t * @private\n\t */\n\t_initPlaceholder() {\n\t\tconst editor = this.editor;\n\t\tconst editingView = editor.editing.view;\n\t\tconst editingRoot = editingView.document.getRoot();\n\t\tconst sourceElement = editor.sourceElement;\n\n\t\tconst placeholderText = editor.config.get( 'placeholder' ) ||\n\t\t\tsourceElement && sourceElement.tagName.toLowerCase() === 'textarea' && sourceElement.getAttribute( 'placeholder' );\n\n\t\tif ( placeholderText ) {\n\t\t\tenablePlaceholder( {\n\t\t\t\tview: editingView,\n\t\t\t\telement: editingRoot,\n\t\t\t\ttext: placeholderText,\n\t\t\t\tisDirectHost: false\n\t\t\t} );\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md.\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-2019, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md.\n */\n\n/**\n * @module ui/editorui/editoruiview\n */\n\n/* globals document */\n\nimport View from '../view';\nimport Template from '../template';\n\nimport '../../theme/components/editorui/editorui.css';\n\n/**\n * The editor UI view class. Base class for the editor main views.\n *\n * @extends module:ui/view~View\n */\nexport default class EditorUIView extends View {\n\t/**\n\t * Creates an instance of the editor UI view class.\n\t *\n\t * @param {module:utils/locale~Locale} [locale] The locale instance.\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\t/**\n\t\t * Collection of the child views, detached from the DOM\n\t\t * structure of the editor, like panels, icons etc.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection} #body\n\t\t */\n\t\tthis.body = this.createCollection();\n\n\t\t/**\n\t\t * The element holding elements of the 'body' region.\n\t\t *\n\t\t * @private\n\t\t * @member {HTMLElement} #_bodyCollectionContainer\n\t\t */\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\tthis._renderBodyCollection();\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tthis._bodyCollectionContainer.remove();\n\n\t\treturn super.destroy();\n\t}\n\n\t/**\n\t * Creates and appends to `` the {@link #body} collection container.\n\t *\n\t * @private\n\t */\n\t_renderBodyCollection() {\n\t\tconst bodyElement = this._bodyCollectionContainer = 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-reset_all',\n\t\t\t\t\t'ck-body',\n\t\t\t\t\t'ck-rounded-corners'\n\t\t\t\t]\n\t\t\t},\n\t\t\tchildren: this.body\n\t\t} ).render();\n\n\t\tdocument.body.appendChild( bodyElement );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md.\n */\n\n/**\n * @module ui/editableui/editableuiview\n */\n\nimport View from '../view';\n\n/**\n * The editable UI view class.\n *\n * @extends module:ui/view~View\n */\nexport default class EditableUIView extends View {\n\t/**\n\t * Creates an instance of EditableUIView class.\n\t *\n\t * @param {module:utils/locale~Locale} [locale] The locale instance.\n\t * @param {module:engine/view/view~View} editingView The editing view instance the editable is related to.\n\t * @param {HTMLElement} [editableElement] The editable element. If not specified, this view\n\t * should create it. Otherwise, the existing element should be used.\n\t */\n\tconstructor( locale, editingView, editableElement ) {\n\t\tsuper( locale );\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-content',\n\t\t\t\t\t'ck-editor__editable',\n\t\t\t\t\t'ck-rounded-corners'\n\t\t\t\t]\n\t\t\t}\n\t\t} );\n\n\t\t/**\n\t\t * The name of the editable UI view.\n\t\t *\n\t\t * @member {String} #name\n\t\t */\n\t\tthis.name = null;\n\n\t\t/**\n\t\t * Controls whether the editable is focused, i.e. the user is typing in it.\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} #isFocused\n\t\t */\n\t\tthis.set( 'isFocused', false );\n\n\t\t/**\n\t\t * The element which is the main editable element (usually the one with `contentEditable=\"true\"`).\n\t\t *\n\t\t * @private\n\t\t * @member {HTMLElement} #_editableElement\n\t\t */\n\t\tthis._editableElement = editableElement;\n\n\t\t/**\n\t\t * Whether an external {@link #_editableElement} was passed into the constructor, which also means\n\t\t * the view will not render its {@link #template}.\n\t\t *\n\t\t * @private\n\t\t * @member {Boolean} #_hasExternalElement\n\t\t */\n\t\tthis._hasExternalElement = !!this._editableElement;\n\n\t\t/**\n\t\t * The editing view instance the editable is related to. Editable uses the editing\n\t\t * view to dynamically modify its certain DOM attributes after {@link #render rendering}.\n\t\t *\n\t\t * **Note**: The DOM attributes are performed by the editing view and not UI\n\t\t * {@link module:ui/view~View#bindTemplate template bindings} because once rendered,\n\t\t * the editable DOM element must remain under the full control of the engine to work properly.\n\t\t *\n\t\t * @protected\n\t\t * @member {module:engine/view/view~View} #isFocused\n\t\t */\n\t\tthis._editingView = editingView;\n\t}\n\n\t/**\n\t * Renders the view by either applying the {@link #template} to the existing\n\t * {@link #_editableElement} or assigning {@link #element} as {@link #_editableElement}.\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\tif ( this._hasExternalElement ) {\n\t\t\tthis.template.apply( this.element = this._editableElement );\n\t\t} else {\n\t\t\tthis._editableElement = this.element;\n\t\t}\n\n\t\tthis.on( 'change:isFocused', () => this._updateIsFocusedClasses() );\n\t\tthis._updateIsFocusedClasses();\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tif ( this._hasExternalElement ) {\n\t\t\tthis.template.revert( this._editableElement );\n\t\t}\n\n\t\tsuper.destroy();\n\t}\n\n\t/**\n\t * Updates the `ck-focused` and `ck-blurred` CSS classes on the {@link #element} according to\n\t * the {@link #isFocused} property value using the {@link #_editingView editing view} API.\n\t *\n\t * @private\n\t */\n\t_updateIsFocusedClasses() {\n\t\tconst editingView = this._editingView;\n\n\t\tif ( editingView.isRenderingInProgress ) {\n\t\t\teditingView.once( 'change:isRenderingInProgress', () => update( this ) );\n\t\t} else {\n\t\t\tupdate( this );\n\t\t}\n\n\t\tfunction update( view ) {\n\t\t\teditingView.change( writer => {\n\t\t\t\tconst viewRoot = editingView.document.getRoot( view.name );\n\n\t\t\t\twriter.addClass( view.isFocused ? 'ck-focused' : 'ck-blurred', viewRoot );\n\t\t\t\twriter.removeClass( view.isFocused ? 'ck-blurred' : 'ck-focused', viewRoot );\n\t\t\t} );\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md.\n */\n/**\n * @module ui/editableui/inline/inlineeditableuiview\n */\nimport EditableUIView from '../../editableui/editableuiview';\n/**\n * The inline editable UI class implementing an inline {@link module:ui/editableui/editableuiview~EditableUIView}.\n *\n * @extends module:ui/editableui/editableuiview~EditableUIView\n */\nexport default class InlineEditableUIView extends EditableUIView {\n /**\n\t * Creates an instance of the InlineEditableUIView class.\n\t *\n\t * @param {module:utils/locale~Locale} [locale] The locale instance.\n\t * @param {module:engine/view/view~View} editingView The editing view instance the editable is related to.\n\t * @param {HTMLElement} [editableElement] The editable element. If not specified, the\n\t * {@link module:ui/editableui/editableuiview~EditableUIView}\n\t * will create it. Otherwise, the existing element will be used.\n\t */\n constructor(locale, editingView, editableElement) {\n super(locale, editingView, editableElement);\n this.extendTemplate({\n attributes: {\n role: 'textbox',\n class: 'ck-editor__editable_inline'\n }\n });\n }\n /**\n\t * @inheritDoc\n\t */\n render() {\n super.render();\n const editingView = this._editingView;\n const t = this.t;\n editingView.change(writer => {\n const viewRoot = editingView.document.getRoot(this.name);\n writer.setAttribute('aria-label', t('ba', [this.name]), viewRoot);\n });\n }\n}","/**\n * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md.\n */\n\n/**\n * @module editor-balloon/ballooneditoruiview\n */\n\nimport EditorUIView from '@ckeditor/ckeditor5-ui/src/editorui/editoruiview';\nimport InlineEditableUIView from '@ckeditor/ckeditor5-ui/src/editableui/inline/inlineeditableuiview';\n\n/**\n * Contextual editor UI view. Uses the {@link module:ui/editableui/inline/inlineeditableuiview~InlineEditableUIView}.\n *\n * @extends module:ui/editorui/editoruiview~EditorUIView\n */\nexport default class BalloonEditorUIView extends EditorUIView {\n\t/**\n\t * Creates an instance of the balloon editor UI view.\n\t *\n\t * @param {module:utils/locale~Locale} locale The {@link module:core/editor/editor~Editor#locale} instance.\n\t * @param {module:engine/view/view~View} editingView The editing view instance this view is related to.\n\t * @param {HTMLElement} [editableElement] The editable element. If not specified, it will be automatically created by\n\t * {@link module:ui/editableui/editableuiview~EditableUIView}. Otherwise, the given element will be used.\n\t */\n\tconstructor( locale, editingView, editableElement ) {\n\t\tsuper( locale );\n\n\t\t/**\n\t\t * The editable UI view.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/editableui/inline/inlineeditableuiview~InlineEditableUIView}\n\t\t */\n\t\tthis.editable = new InlineEditableUIView( locale, editingView, editableElement );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\tthis.registerChild( this.editable );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md.\n */\n\n/**\n * @module utils/dom/setdatainelement\n */\n\n/* globals HTMLTextAreaElement */\n\n/**\n * Sets data in a given element.\n *\n * @param {HTMLElement} el The element in which the data will be set.\n * @param {String} data The data string.\n */\nexport default function setDataInElement( el, data ) {\n\tif ( el instanceof HTMLTextAreaElement ) {\n\t\tel.value = data;\n\t}\n\n\tel.innerHTML = data;\n}\n","/**\n * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md.\n */\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport setDataInElement from '@ckeditor/ckeditor5-utils/src/dom/setdatainelement';\n\n/**\n * @module core/editor/utils/elementapimixin\n */\n\n/**\n * Implementation of the {@link module:core/editor/utils/elementapimixin~ElementApi}.\n *\n * @mixin ElementApiMixin\n * @implements module:core/editor/utils/elementapimixin~ElementApi\n */\nconst ElementApiMixin = {\n\t/**\n\t * @inheritDoc\n\t */\n\tupdateSourceElement() {\n\t\tif ( !this.sourceElement ) {\n\t\t\t/**\n\t\t\t * Cannot update the source element of a detached editor.\n\t\t\t *\n\t\t\t * The {@link ~ElementApi#updateSourceElement `updateSourceElement()`} method cannot be called if you did not\n\t\t\t * pass an element to `Editor.create()`.\n\t\t\t *\n\t\t\t * @error editor-missing-sourceelement\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'editor-missing-sourceelement: Cannot update the source element of a detached editor.' );\n\t\t}\n\n\t\tsetDataInElement( this.sourceElement, this.data.get() );\n\t}\n};\n\nexport default ElementApiMixin;\n\n/**\n * Interface describing an editor that replaced a DOM element (was \"initialized on an element\").\n *\n * Such an editor should provide a method to\n * {@link module:core/editor/utils/elementapimixin~ElementApi#updateSourceElement update the replaced element with the current data}.\n *\n * @interface ElementApi\n */\n\n/**\n * The element on which the editor has been initialized.\n *\n * @readonly\n * @member {HTMLElement} #sourceElement\n */\n\n/**\n * Updates the {@link #sourceElement editor source element}'s content with the data.\n *\n * @method #updateSourceElement\n */\n","/**\n * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md.\n */\n\n/**\n * @module editor-balloon/ballooneditor\n */\n\nimport Editor from '@ckeditor/ckeditor5-core/src/editor/editor';\nimport HtmlDataProcessor from '@ckeditor/ckeditor5-engine/src/dataprocessor/htmldataprocessor';\nimport BalloonToolbar from '@ckeditor/ckeditor5-ui/src/toolbar/balloon/balloontoolbar';\nimport BalloonEditorUI from './ballooneditorui';\nimport BalloonEditorUIView from './ballooneditoruiview';\nimport setDataInElement from '@ckeditor/ckeditor5-utils/src/dom/setdatainelement';\nimport getDataFromElement from '@ckeditor/ckeditor5-utils/src/dom/getdatafromelement';\nimport DataApiMixin from '@ckeditor/ckeditor5-core/src/editor/utils/dataapimixin';\nimport ElementApiMixin from '@ckeditor/ckeditor5-core/src/editor/utils/elementapimixin';\nimport attachToForm from '@ckeditor/ckeditor5-core/src/editor/utils/attachtoform';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport { isElement } from 'lodash-es';\n\n/**\n * The {@glink builds/guides/overview#balloon-editor balloon editor} implementation (Medium-like editor).\n * It uses an inline editable and a toolbar based on the {@link module:ui/toolbar/balloon/balloontoolbar~BalloonToolbar}.\n * See the {@glink examples/builds/balloon-editor demo}.\n *\n * In order to create a balloon editor instance, use the static\n * {@link module:editor-balloon/ballooneditor~BalloonEditor.create `BalloonEditor.create()`} method.\n *\n * # Balloon editor and balloon build\n *\n * The balloon editor can be used directly from source (if you installed the\n * [`@ckeditor/ckeditor5-editor-balloon`](https://www.npmjs.com/package/@ckeditor/ckeditor5-editor-balloon) package)\n * but it is also available in the {@glink builds/guides/overview#balloon-editor balloon build}.\n *\n * {@glink builds/guides/overview Builds} are ready-to-use editors with plugins bundled in. When using the editor from\n * source you need to take care of loading all plugins by yourself\n * (through the {@link module:core/editor/editorconfig~EditorConfig#plugins `config.plugins`} option).\n * Using the editor from source gives much better flexibility and allows easier customization.\n *\n * Read more about initializing the editor from source or as a build in\n * {@link module:editor-balloon/ballooneditor~BalloonEditor.create `BalloonEditor.create()`}.\n *\n * @mixes module:core/editor/utils/dataapimixin~DataApiMixin\n * @mixes module:core/editor/utils/elementapimixin~ElementApiMixin\n * @implements module:core/editor/editorwithui~EditorWithUI\n * @extends module:core/editor/editor~Editor\n */\nexport default class BalloonEditor extends Editor {\n\t/**\n\t * Creates an instance of the balloon editor.\n\t *\n\t * **Note:** do not use the constructor to create editor instances. Use the static\n\t * {@link module:editor-balloon/ballooneditor~BalloonEditor.create `BalloonEditor.create()`} method instead.\n\t *\n\t * @protected\n\t * @param {HTMLElement|String} sourceElementOrData The DOM element that will be the source for the created editor\n\t * (on which the editor will be initialized) or initial data for the editor. For more information see\n\t * {@link module:editor-balloon/ballooneditor~BalloonEditor.create `BalloonEditor.create()`}.\n\t * @param {module:core/editor/editorconfig~EditorConfig} config The editor configuration.\n\t */\n\tconstructor( sourceElementOrData, config ) {\n\t\tsuper( config );\n\n\t\tif ( isElement( sourceElementOrData ) ) {\n\t\t\tthis.sourceElement = sourceElementOrData;\n\t\t}\n\n\t\tconst plugins = this.config.get( 'plugins' );\n\t\tplugins.push( BalloonToolbar );\n\t\tthis.config.set( 'plugins', plugins );\n\n\t\tthis.config.define( 'balloonToolbar', this.config.get( 'toolbar' ) );\n\n\t\tthis.data.processor = new HtmlDataProcessor();\n\n\t\tthis.model.document.createRoot();\n\n\t\tconst view = new BalloonEditorUIView( this.locale, this.editing.view, this.sourceElement );\n\t\tthis.ui = new BalloonEditorUI( this, view );\n\n\t\tattachToForm( this );\n\t}\n\n\t/**\n\t * Destroys the editor instance, releasing all resources used by it.\n\t *\n\t * Updates the original editor element with the data.\n\t *\n\t * @returns {Promise}\n\t */\n\tdestroy() {\n\t\t// Cache the data, then destroy.\n\t\t// It's safe to assume that the model->view conversion will not work after super.destroy().\n\t\tconst data = this.getData();\n\n\t\tthis.ui.destroy();\n\n\t\treturn super.destroy()\n\t\t\t.then( () => {\n\t\t\t\tif ( this.sourceElement ) {\n\t\t\t\t\tsetDataInElement( this.sourceElement, data );\n\t\t\t\t}\n\t\t\t} );\n\t}\n\n\t/**\n\t * Creates a balloon editor instance.\n\t *\n\t * Creating an instance when using a {@glink builds/index CKEditor build}:\n\t *\n\t *\t\tBalloonEditor\n\t *\t\t\t.create( document.querySelector( '#editor' ) )\n\t *\t\t\t.then( editor => {\n\t *\t\t\t\tconsole.log( 'Editor was initialized', editor );\n\t *\t\t\t} )\n\t *\t\t\t.catch( err => {\n\t *\t\t\t\tconsole.error( err.stack );\n\t *\t\t\t} );\n\t *\n\t * Creating an instance when using CKEditor from source (make sure to specify the list of plugins to load and the toolbar):\n\t *\n\t *\t\timport BalloonEditor from '@ckeditor/ckeditor5-editor-balloon/src/ballooneditor';\n\t *\t\timport Essentials from '@ckeditor/ckeditor5-essentials/src/essentials';\n\t *\t\timport Bold from '@ckeditor/ckeditor5-basic-styles/src/bold';\n\t *\t\timport Italic from '@ckeditor/ckeditor5-basic-styles/src/italic';\n\t *\t\timport ...\n\t *\n\t *\t\tBalloonEditor\n\t *\t\t\t.create( document.querySelector( '#editor' ), {\n\t *\t\t\t\tplugins: [ Essentials, Bold, Italic, ... ],\n\t *\t\t\t\ttoolbar: [ 'bold', 'italic', ... ]\n\t *\t\t\t} )\n\t *\t\t\t.then( editor => {\n\t *\t\t\t\tconsole.log( 'Editor was initialized', editor );\n\t *\t\t\t} )\n\t *\t\t\t.catch( err => {\n\t *\t\t\t\tconsole.error( err.stack );\n\t *\t\t\t} );\n\t *\n\t * Creating an instance when using initial data instead of a DOM element:\n\t *\n\t *\t\timport BalloonEditor from '@ckeditor/ckeditor5-editor-balloon/src/ballooneditor';\n\t *\t\timport Essentials from '@ckeditor/ckeditor5-essentials/src/essentials';\n\t *\t\timport Bold from '@ckeditor/ckeditor5-basic-styles/src/bold';\n\t *\t\timport Italic from '@ckeditor/ckeditor5-basic-styles/src/italic';\n\t *\t\timport ...\n\t *\n\t *\t\tBalloonEditor\n\t *\t\t\t.create( 'Hello world!
', {\n\t *\t\t\t\tplugins: [ Essentials, Bold, Italic, ... ],\n\t *\t\t\t\ttoolbar: [ 'bold', 'italic', ... ]\n\t *\t\t\t} )\n\t *\t\t\t.then( editor => {\n\t *\t\t\t\tconsole.log( 'Editor was initialized', editor );\n\t *\n\t *\t\t\t\t// Initial data was provided so `editor.element` needs to be added manually to the DOM.\n\t *\t\t\t\tdocument.body.appendChild( editor.element );\n\t *\t\t\t} )\n\t *\t\t\t.catch( err => {\n\t *\t\t\t\tconsole.error( err.stack );\n\t *\t\t\t} );\n\t *\n\t * @param {HTMLElement|String} sourceElementOrData The DOM element that will be the source for the created editor\n\t * (on which the editor will be initialized) or initial data for the editor.\n\t *\n\t * If a source element is passed, then its contents will be automatically\n\t * {@link module:editor-balloon/ballooneditor~BalloonEditor#setData loaded} to the editor on startup and the element\n\t * itself will be used as the editor's editable element.\n\t *\n\t * If data is provided, then `editor.element` will be created automatically and needs to be added\n\t * to the DOM manually.\n\t * @param {module:core/editor/editorconfig~EditorConfig} config The editor configuration.\n\t * @returns {Promise} A promise resolved once the editor is ready.\n\t * The promise returns the created {@link module:editor-balloon/ballooneditor~BalloonEditor} instance.\n\t */\n\tstatic create( sourceElementOrData, config ) {\n\t\treturn new Promise( resolve => {\n\t\t\tconst editor = new this( sourceElementOrData, config );\n\n\t\t\tresolve(\n\t\t\t\teditor.initPlugins()\n\t\t\t\t\t.then( () => {\n\t\t\t\t\t\teditor.ui.init();\n\t\t\t\t\t} )\n\t\t\t\t\t.then( () => {\n\t\t\t\t\t\tconst initialData = isElement( sourceElementOrData ) ?\n\t\t\t\t\t\t\tgetDataFromElement( sourceElementOrData ) :\n\t\t\t\t\t\t\tsourceElementOrData;\n\n\t\t\t\t\t\treturn editor.data.init( initialData );\n\t\t\t\t\t} )\n\t\t\t\t\t.then( () => editor.fire( 'ready' ) )\n\t\t\t\t\t.then( () => editor )\n\t\t\t);\n\t\t} );\n\t}\n}\n\nmix( BalloonEditor, DataApiMixin );\nmix( BalloonEditor, ElementApiMixin );\n","/**\n * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md.\n */\n\nimport { isFunction } from 'lodash-es';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * @module core/editor/utils/attachtoform\n */\n\n/**\n * Checks if the editor is initialized on a `