Show:
                            (function () {
                                'use strict';
                            
                                /**
                                 * The main editor UI class manages a hierarchy of widgets (toolbars and buttons).
                                 *
                                 * @uses WidgetExclusive
                                 * @uses WidgetFocusManager
                                 *
                                 * @class UI
                                 */
                                var UI = React.createClass({
                                    mixins: [AlloyEditor.WidgetExclusive, AlloyEditor.WidgetFocusManager],
                            
                                    // Allows validating props being passed to the component.
                                    propTypes: {
                                        /**
                                         * Localized messages for live aria updates. Should include the following messages:
                                         * - noToolbar: Notification for no available toolbar in the editor.
                                         * - oneToolbar: Notification for just one available toolbar in the editor.
                                         * - manyToolbars: Notification for more than one available toolbar in the editor.
                                         *
                                         * @property {Object} ariaUpdates
                                         */
                                        ariaUpdates: React.PropTypes.object,
                            
                                        /**
                                         * The editor instance where the component is being used.
                                         *
                                         * @property {Object} editor
                                         */
                                        editor: React.PropTypes.object.isRequired,
                            
                                        /**
                                         * The delay (ms), after which key or mouse events will be processed.
                                         *
                                         * @property {Number} eventsDelay
                                         */
                                        eventsDelay: React.PropTypes.number,
                            
                                        /**
                                         * The toolbars configuration for this editor instance
                                         *
                                         * @property {Object} toolbars
                                         */
                                        toolbars: React.PropTypes.object.isRequired
                                    },
                            
                                    /**
                                     * Lifecycle. Invoked once before the component is mounted.
                                     *
                                     * @method getInitialState
                                     */
                                    getInitialState: function() {
                                        return {
                                            hidden: false
                                        };
                                    },
                            
                                    /**
                                     * Lifecycle. Returns the default values of the properties used in the widget.
                                     *
                                     * @method getDefaultProps
                                     * @return {Object} The default properties.
                                     */
                                    getDefaultProps: function() {
                                        return {
                                            circular: true,
                                            descendants: '[class^=ae-toolbar-]',
                                            eventsDelay: 0,
                                            keys: {
                                                next: 9
                                            }
                                        };
                                    },
                            
                                    /**
                                     * Lifecycle. Invoked once, only on the client, immediately after the initial rendering occurs.
                                     *
                                     * @method componentDidMount
                                     */
                                    componentDidMount: function () {
                                        var editor = this.props.editor.get('nativeEditor');
                            
                                        editor.on('editorInteraction', this._onEditorInteraction, this);
                                        editor.on('actionPerformed', this._onActionPerformed, this);
                                        editor.on('key', this._onEditorKey, this);
                            
                                        // Set up events for hiding the UI when user stops interacting with the editor.
                                        // This may happen when he just clicks outside of the editor. However,
                                        // this does not include a situation when he clicks on some button, part of
                                        // editor's UI.
                            
                                        // It is not easy to debounce _setUIHidden on mousedown, because if we
                                        // debounce it, when the handler is being invoked, the target might be no more part
                                        // of the editor's UI - onActionPerformed causes re-render.
                                        this._mousedownListener = function (event) {
                                            this._setUIHidden(event.target);
                                        }.bind(this);
                            
                                        this._keyDownListener = CKEDITOR.tools.debounce(function(event) {
                                            this._setUIHidden(document.activeElement);
                                        }, this.props.eventsDelay, this);
                            
                                        document.addEventListener('mousedown', this._mousedownListener);
                                        document.addEventListener('keydown', this._keyDownListener);
                                    },
                            
                                    /**
                                     * Lifecycle. Invoked immediately after the component's updates are flushed to the DOM.
                                     * Fires `ariaUpdate` event passing ARIA related messages.
                                     * Fires `editorUpdate` event passing the previous and current properties and state.
                                     *
                                     * @method componentDidUpdate
                                     */
                                    componentDidUpdate: function (prevProps, prevState) {
                                        var domNode = ReactDOM.findDOMNode(this);
                            
                                        var editor = this.props.editor.get('nativeEditor');
                            
                                        if (domNode) {
                                            editor.fire('ariaUpdate', {
                                                message: this._getAvailableToolbarsMessage(domNode)
                                            });
                                        }
                            
                                        editor.fire('editorUpdate', {
                                            prevProps: prevProps,
                                            prevState: prevState,
                                            props: this.props,
                                            state: this.state
                                        });
                                    },
                            
                                    _getAriaUpdateTemplate: function(ariaUpdate) {
                                        if (!this._ariaUpdateTemplates) {
                                            this._ariaUpdateTemplates = {};
                                        }
                            
                                        if (!this._ariaUpdateTemplates[ariaUpdate]) {
                                            this._ariaUpdateTemplates[ariaUpdate] = new CKEDITOR.template(this._getAriaUpdates()[ariaUpdate]);
                                        }
                            
                                        return this._ariaUpdateTemplates[ariaUpdate];
                                    },
                            
                                    /**
                                     * Returns the templates for ARIA messages.
                                     *
                                     * @protected
                                     * @method _getAriaUpdates
                                     * @return {Object} ARIA relates messages. Default:
                                     * {
                                     *      noToolbar: AlloyEditor.Strings.ariaUpdateNoToolbar,
                                     *      oneToolbar: AlloyEditor.Strings.ariaUpdateOneToolbar,
                                     *      manyToolbars: AlloyEditor.Strings.ariaUpdateManyToolbars
                                     *  }
                                     */
                                    _getAriaUpdates: function() {
                                        return this.props.ariaUpdates || {
                                            noToolbar: AlloyEditor.Strings.ariaUpdateNoToolbar,
                                            oneToolbar: AlloyEditor.Strings.ariaUpdateOneToolbar,
                                            manyToolbars: AlloyEditor.Strings.ariaUpdateManyToolbars
                                        };
                                    },
                            
                                    /**
                                     * Returns an ARIA message which represents the number of currently available toolbars.
                                     *
                                     * @method _getAvailableToolbarsMessage
                                     * @protected
                                     * @param {CKEDITOR.dom.element} domNode The DOM node from which the available toolbars will be retrieved.
                                     * @return {String} The ARIA message for the number of available toolbars
                                     */
                                    _getAvailableToolbarsMessage: function(domNode) {
                                        var toolbarsNodeList = domNode.querySelectorAll('[role="toolbar"]');
                            
                                        if (!toolbarsNodeList.length) {
                                            return this._getAriaUpdates().noToolbar;
                                        } else {
                                            var toolbarNames = Array.prototype.slice.call(toolbarsNodeList).map(function(toolbar) {
                                                return toolbar.getAttribute('aria-label');
                                            });
                            
                                            var ariaUpdate = toolbarNames.length === 1 ? 'oneToolbar' : 'manyToolbars';
                            
                                            return this._getAriaUpdateTemplate(ariaUpdate).output({
                                                toolbars: toolbarNames.join(',').replace(/,([^,]*)$/, ' and ' + '$1')
                                            });
                                        }
                                    },
                            
                                    /**
                                     * Lifecycle. Invoked immediately before a component is unmounted from the DOM.
                                     *
                                     * @method componentWillUnmount
                                     */
                                    componentWillUnmount: function() {
                                        if (this._mousedownListener) {
                                            document.removeEventListener('mousedown', this._mousedownListener);
                                        }
                            
                                        if (this._keyDownListener) {
                                            this._keyDownListener.detach();
                                            document.removeEventListener('keydown', this._keyDownListener);
                                        }
                                    },
                            
                                    /**
                                     * Lifecycle. Renders the UI of the editor. This may include several toolbars and buttons.
                                     * The editor's UI also takes care of rendering the items in exclusive mode.
                                     *
                                     * @method render
                                     * @return {Object} The content which should be rendered.
                                     */
                                    render: function() {
                                        if (this.state.hidden) {
                                            return null;
                                        }
                            
                                        var toolbars = Object.keys(this.props.toolbars).map(function(toolbar) {
                                            return AlloyEditor.Toolbars[toolbar] || window[toolbar];
                                        });
                            
                                        toolbars = this.filterExclusive(toolbars).map(function(toolbar) {
                                            var props = this.mergeExclusiveProps({
                                                config: this.props.toolbars[toolbar.key],
                                                editor: this.props.editor,
                                                editorEvent: this.state.editorEvent,
                                                key: toolbar.key,
                                                onDismiss: this._onDismissToolbarFocus,
                                                selectionData: this.state.selectionData
                                            }, toolbar.key);
                            
                                            return React.createElement(toolbar, props);
                                        }.bind(this));
                            
                                        return (
                                            <div className="ae-toolbars" onKeyDown={this.handleKey}>
                                                {toolbars}
                                            </div>
                                        );
                                    },
                            
                                    /**
                                     * Listener to the editor's `actionPerformed` event. Sets state and redraws the UI of the editor.
                                     *
                                     * @protected
                                     * @method _onActionPerformed
                                     * @param {SynteticEvent} event The provided event
                                     */
                                    _onActionPerformed: function(event) {
                                        var editor = this.props.editor.get('nativeEditor');
                            
                                        editor.focus();
                            
                                        this.setState({
                                            itemExclusive: null,
                                            selectionData: editor.getSelectionData()
                                        });
                                    },
                            
                                    /**
                                     * Executed when a dismiss key is pressed over a toolbar to return the focus to the editor.
                                     *
                                     * @protected
                                     * @method _onDismissToolbarFocus
                                     */
                                    _onDismissToolbarFocus: function() {
                                        var editor = this.props.editor.get('nativeEditor');
                            
                                        editor.focus();
                                    },
                            
                                    /**
                                     * Listener to the editor's `userInteraction` event. Retrieves the data about the user selection and
                                     * provides it via component's state property.
                                     *
                                     * @protected
                                     * @method _onEditorInteraction
                                     * @param {SynteticEvent} event The provided event
                                     */
                                    _onEditorInteraction: function(event) {
                                        this.setState({
                                            editorEvent: event,
                                            hidden: false,
                                            itemExclusive: null,
                                            selectionData: event.data.selectionData
                                        });
                                    },
                            
                                    /**
                                     * Focuses on the active toolbar when the combination ALT+F10 is pressed inside the editor.
                                     *
                                     * @protected
                                     * @method _onEditorKey
                                     */
                                    _onEditorKey: function(event) {
                                        var nativeEvent = event.data.domEvent.$;
                            
                                        if (nativeEvent.altKey && nativeEvent.keyCode === 121) {
                                            this.focus();
                                        }
                                    },
                            
                                    /**
                                     * Checks if the target with which the user interacted is part of editor's UI or it is
                                     * the editable area. If none of these, sets the state of editor's UI to be hidden.
                                     *
                                     * @protected
                                     * @method _setUIHidden
                                     * @param {DOMElement} target The DOM element with which user interacted lastly.
                                     */
                                    _setUIHidden: function(target) {
                                        var domNode = ReactDOM.findDOMNode(this);
                            
                                        if (domNode) {
                                            var editable = this.props.editor.get('nativeEditor').editable();
                                            var targetNode = new CKEDITOR.dom.node(target);
                            
                                            var res = (editable.$ === target) || editable.contains(targetNode) ||
                                                (new CKEDITOR.dom.element(domNode)).contains(targetNode);
                            
                                            if (!res) {
                                                this.setState({
                                                    hidden: true
                                                });
                                            }
                                        }
                                    }
                                });
                            
                                /**
                                 * Fired when component updates and when it is rendered in the DOM.
                                 * The payload consists from a `message` property containing the ARIA message.
                                 *
                                 * @event ariaUpdate
                                 */
                            
                                /**
                                 * Fired when component updates. The payload consists from an object with the following
                                 * properties:
                                 * - prevProps - The previous properties of the component
                                 * - prevState - The previous state of the component
                                 * - props - The current properties of the component
                                 * - state - The current state of the component
                                 *
                                 * @event ariaUpdate
                                 */
                            
                                AlloyEditor.UI = UI;
                            }());