Show: Inherited Protected Private Deprecated

# File `src/ui/react/src/adapter/alloy-editor.js`

                                (function() {
                                    'use strict';

                                    /**
                                     * AlloyEditor main class. Creates instance of the editor and provides the user configuration
                                     * to the UI.
                                     *
                                     * @class Core
                                     * @constructor
                                     */
                                    function Core(config) {
                                        Core.superclass.constructor.call(this, config);
                                    }

                                    AlloyEditor.OOP.extend(Core, AlloyEditor.Base, {
                                        /**
                                         * Initializer lifecycle implementation for the AlloyEditor class. Creates a CKEditor
                                         * instance, passing it the provided configuration attributes.
                                         *
                                         * @protected
                                         * @method initializer
                                         * @param config {Object} Configuration object literal for the editor.
                                         */
                                        initializer: function(config) {
                                            var node = this.get('srcNode');

                                            if (this.get('enableContentEditable')) {
                                                node.setAttribute('contenteditable', 'true');
                                            }

                                            var editor = CKEDITOR.inline(node);

                                            editor.config.allowedContent = this.get('allowedContent');

                                            editor.config.toolbars = this.get('toolbars');

                                            editor.config.removePlugins = this.get('removePlugins');
                                            editor.config.extraPlugins = this.get('extraPlugins');
                                            editor.config.placeholderClass = this.get('placeholderClass');

                                            editor.config.pasteFromWordRemoveStyles = false;
                                            editor.config.pasteFromWordRemoveFontStyles = false;

                                            editor.config.selectionKeystrokes = this.get('selectionKeystrokes');

                                            if (CKEDITOR.env.ie) {
                                                editor.config.extraPlugins = editor.config.extraPlugins.replace('ae_dragresize', 'ae_dragresize_ie');
                                                editor.config.removePlugins = editor.config.removePlugins.replace('ae_dragresize', 'ae_dragresize_ie');
                                            }

                                            AlloyEditor.Lang.mix(editor.config, config);

                                            editor.once('contentDom', function() {

                                                this._addReadOnlyLinkClickListener(editor);

                                                var editable = editor.editable();

                                                editable.addClass('ae-editable');

                                            }.bind(this));

                                            AlloyEditor.loadLanguageResources(this._renderUI.bind(this));

                                            this._editor = editor;
                                        },

                                        /**
                                         * Destructor lifecycle implementation for the AlloyEdtor class. Destroys the CKEditor
                                         * instance and destroys all created toolbars.
                                         *
                                         * @protected
                                         * @method destructor
                                         */
                                        destructor: function() {
                                            this._destroyed = true;

                                            if (this._editorUIElement) {
                                                ReactDOM.unmountComponentAtNode(this._editorUIElement);
                                                this._editorUIElement.parentNode.removeChild(this._editorUIElement);
                                            }

                                            var nativeEditor = this.get('nativeEditor');

                                            if (nativeEditor) {
                                                var editable = nativeEditor.editable();

                                                if (editable) {
                                                    editable.removeClass('ae-editable');

                                                    if (this.get('enableContentEditable')) {
                                                        this.get('srcNode').setAttribute('contenteditable', 'false');
                                                    }
                                                }

                                                this._clearSelections();

                                                nativeEditor.destroy();
                                            }
                                        },

                                        /**
                                         * Clear selections from window object
                                         *
                                         * @protected
                                         * @method _clearSelections
                                         */
                                        _clearSelections: function() {
                                            var nativeEditor = this.get('nativeEditor');
                                            var isMSSelection = typeof window.getSelection != 'function';

                                            if (isMSSelection) {
                                                nativeEditor.document.$.selection.empty();
                                            } else {
                                                nativeEditor.document.getWindow().$.getSelection().removeAllRanges();
                                            }
                                        },

                                        /**
                                         * Method to set default link behavior
                                         *
                                         * @protected
                                         * @method _addReadOnlyLinkClickListener
                                         * @param {Object} editor
                                         */
                                        _addReadOnlyLinkClickListener: function(editor) {
                                            editor.editable().on('click', this._defaultReadOnlyClickFn, this, {
                                                editor: editor
                                            });
                                        },

                                        /**
                                         * Called on `click` event when the editor is in read only mode. Navigates to link's URL or opens
                                         * the link in a new window.
                                         *
                                         * @event readOnlyClick
                                         * @protected
                                         * @method _defaultReadOnlyClickFn
                                         * @param {Object} event The fired `click` event payload
                                         */
                                        _defaultReadOnlyClickFn: function(event) {
                                            var mouseEvent = event.data.$;
                                            var hasCtrlKey = mouseEvent.ctrlKey || mouseEvent.metaKey;
                                            var shouldOpen = this._editor.config.readOnly || hasCtrlKey;

                                            mouseEvent.preventDefault();

                                            if (!shouldOpen) {
                                                return;
                                            }

                                            if (event.listenerData.editor.editable().editor.fire('readOnlyClick', event.data) !== false) {
                                                var ckElement = new CKEDITOR.dom.elementPath(event.data.getTarget(), this);
                                                var link = ckElement.lastElement;

                                                if (link) {
                                                    var href = link.$.attributes.href ? link.$.attributes.href.value : null;
                                                    var target = hasCtrlKey ? '_blank' : link.$.attributes.target ? link.$.attributes.target.value : null;
                                                    this._redirectLink(href, target);
                                                }
                                            }
                                        },

                                        /**
                                         * Retrieves the native CKEditor instance. Having this, the developer may use the API of CKEditor OOTB.
                                         *
                                         * @protected
                                         * @method _getNativeEditor
                                         * @return {Object} The current instance of CKEditor.
                                         */
                                        _getNativeEditor: function() {
                                            return this._editor;
                                        },

                                        /**
                                         * Redirects the browser to a given link
                                         *
                                         * @protected
                                         * @method _redirectLink
                                         * @param {string} href The href to take the browser to
                                         * @param {string=} target Specifies where to display the link
                                         */
                                        _redirectLink: function(href, target) {
                                            if (target && href) {
                                                window.open(href, target);
                                            }
                                            else if (href) {
                                                window.location.href = href;
                                            }
                                        },

                                        /**
                                         * Renders the specified from the user toolbars.
                                         *
                                         * @protected
                                         * @method _renderUI
                                         */
                                        _renderUI: function() {
                                            if (!this._destroyed) {
                                                var editorUIElement = document.createElement('div');
                                                editorUIElement.className = 'ae-ui';

                                                var uiNode = this.get('uiNode') || document.body;

                                                uiNode.appendChild(editorUIElement);

                                                this._mainUI = ReactDOM.render(React.createElement(AlloyEditor.UI, {
                                                    editor: this,
                                                    eventsDelay: this.get('eventsDelay'),
                                                    toolbars: this.get('toolbars')
                                                }), editorUIElement);

                                                this._editorUIElement = editorUIElement;

                                                this.get('nativeEditor').fire('uiReady');
                                            }
                                        },

                                        /**
                                         * The function returns an HTML element from the passed value. If the passed value is a string, it should be
                                         * the Id of the element which have to be retrieved from the DOM.
                                         * If an HTML Element is passed, the element itself will be returned.
                                         *
                                         * @method _toElement
                                         * @protected
                                         * @param {!(String|HTMLElement)} value String, which have to correspond to an HTML element from the DOM,
                                         * or the HTML element itself. If Id is passed, the HTML element will be retrieved from the DOM.
                                         * @return {HTMLElement} An HTML element.
                                         */
                                        _toElement: function(value) {
                                            if (AlloyEditor.Lang.isString(value)) {
                                                value = document.getElementById(value);
                                            }

                                            return value;
                                        },

                                        /**
                                         * Validates the allowed content attribute. Look
                                         * [here](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-allowedContent) for more information about the
                                         * supported values.
                                         *
                                         * @protected
                                         * @method _validateAllowedContent
                                         * @param {Any} The value to be checked
                                         * @return {Boolean} True if the current value is valid configuration, false otherwise
                                         */
                                        _validateAllowedContent: function(value) {
                                            return AlloyEditor.Lang.isString(value) || AlloyEditor.Lang.isObject(value) || AlloyEditor.Lang.isBoolean(value);
                                        },

                                        /**
                                         * Validates the value of toolbars attribute
                                         *
                                         * @protected
                                         * @method _validateToolbars
                                         * @param {Any} The value to be checked
                                         * @return {Boolean} True if the current value is valid toolbars configuration, false otherwise
                                         */
                                        _validateToolbars: function(value) {
                                            return AlloyEditor.Lang.isObject(value) || AlloyEditor.Lang.isNull(value);
                                        }
                                    }, {
                                        ATTRS: {
                                            /**
                                             * Configures the allowed content for the current instance of AlloyEditor.
                                             * Look on the [official CKEditor API](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-allowedContent)
                                             * for more information about the valid values.
                                             *
                                             * @property allowedContent
                                             * @default true
                                             * @writeOnce
                                             * @type {Boolean, String, Object}
                                             */
                                            allowedContent: {
                                                validator: '_validateAllowedContent',
                                                value: true,
                                                writeOnce: true
                                            },

                                            /**
                                             * Specifies whether AlloyEditor set the contenteditable attribute
                                             * to "true" on its srcNode.
                                             *
                                             * @property enableContentEditable
                                             * @type Boolean
                                             * @default true
                                             * @writeOnce
                                             */
                                            enableContentEditable: {
                                                validator: AlloyEditor.Lang.isBoolean,
                                                value: true,
                                                writeOnce: true
                                            },

                                            /**
                                             * The delay (timeout), in ms, after which events such like key or mouse events will be processed.
                                             *
                                             * @property eventsDelay
                                             * @type {Number}
                                             */
                                            eventsDelay: {
                                                validator: AlloyEditor.Lang.isNumber,
                                                value: 100
                                            },

                                            /**
                                             * Specifies the extra plugins which have to be loaded to the current CKEditor instance in order to
                                             * make AlloyEditor to work properly.
                                             *
                                             * @property extraPlugins
                                             * @default 'uicore,selectionregion,dragresize,addimages,placeholder,tabletools,tableresize,autolink'
                                             * @writeOnce
                                             * @type {String}
                                             */
                                            extraPlugins: {
                                                validator: AlloyEditor.Lang.isString,
                                                value: 'ae_uicore,ae_selectionregion,ae_selectionkeystrokes,ae_imagealignment,ae_addimages,ae_placeholder,ae_tabletools,ae_tableresize,ae_autolink,ae_embed,ae_autolist,ae_dragresize',
                                                writeOnce: true
                                            },

                                            /**
                                             * Retrieves the native CKEditor instance. Having this, the developer may use the full API of CKEditor.
                                             *
                                             * @property nativeEditor
                                             * @readOnly
                                             * @type {Object}
                                             */
                                            nativeEditor: {
                                                getter: '_getNativeEditor',
                                                readOnly: true
                                            },

                                            /**
                                             * Specifies the class, which should be added by Placeholder plugin
                                             * {{#crossLink "CKEDITOR.plugins.ae_placeholder}}{{/crossLink}}
                                             * when editor is not focused.
                                             *
                                             * @property placeholderClass
                                             * @default 'ae-placeholder'
                                             * @writeOnce
                                             * @type {String}
                                             */
                                            placeholderClass: {
                                                validator: AlloyEditor.Lang.isString,
                                                value: 'ae-placeholder',
                                                writeOnce: true
                                            },

                                            /**
                                             * Specifies the plugins, which come by default with CKEditor, but which are not needed by AlloyEditor.
                                             * These plugins add the default UI for CKeditor, which is no more needed. Please note that AlloyEdtor
                                             * comes with its own highly optimized copy of CKEditor (just customized via their official download page).
                                             * This version does not come with the unneeded plugins, so the value of this property won't be needed.
                                             * However, if you decide to go with the OOTB version of CKEditor, you will have to remove some of the
                                             * plugins if you decide to use AlloyEditor. Keep in mind that removing these plugins doesn't remove them
                                             * entirely from CKEditor. It just removes them from its current instance, in which you will use different
                                             * UI - those of AlloyEditor. You will be fully able to use both OOTB CKEditor and AlloyEditor on the same
                                             * page!
                                             *
                                             * @property removePlugins
                                             * @default 'contextmenu,toolbar,elementspath,resize,liststyle,link'
                                             * @writeOnce
                                             * @type {String}
                                             */
                                            removePlugins: {
                                                validator: AlloyEditor.Lang.isString,
                                                value: 'contextmenu,toolbar,elementspath,resize,liststyle,link',
                                                writeOnce: true
                                            },

                                            /**
                                             * Array of manual selection triggers. They can be configured to manually show a specific selection toolbar
                                             * by forcing the selection type. A selectionKeystroke item consists of a keys property with a [CKEditor keystroke
                                             * definition](http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-keystrokes) and a selection property with
                                             * the selection name to trigger.
                                             *
                                             * @property selectionKeystrokes
                                             * @type {Array}
                                             */
                                            selectionKeystrokes: {
                                                validator: AlloyEditor.Lang.isArray,
                                                value: [{
                                                    keys: CKEDITOR.CTRL + 76 /*L*/,
                                                    selection: 'link'
                                                }, {
                                                    keys: CKEDITOR.CTRL + CKEDITOR.SHIFT + 76 /*L*/,
                                                    selection: 'embed'
                                                }]
                                            },

                                            /**
                                             * The Node ID or HTMl node, which AlloyEditor should use as an editable area.
                                             *
                                             * @property srcNode
                                             * @type String | Node
                                             * @writeOnce
                                             */
                                            srcNode: {
                                                setter: '_toElement',
                                                writeOnce: true
                                            },

                                            /**
                                             * The toolbars configuration for this editor instance
                                             *
                                             * @property {Object} toolbars
                                             */
                                            toolbars: {
                                                validator: '_validateToolbars',
                                                value: {
                                                    add: {
                                                        buttons: ['image', 'embed', 'camera', 'hline', 'table'],
                                                        tabIndex: 2
                                                    },
                                                    styles: {
                                                        selections: AlloyEditor.Selections,
                                                        tabIndex: 1
                                                    }
                                                }
                                            },

                                            /**
                                             * The Node ID or HTMl node, where AlloyEditor's UI should be rendered.
                                             *
                                             * @property uiNode
                                             * @type String | Node
                                             * @writeOnce
                                             */
                                            uiNode: {
                                                setter: '_toElement',
                                                writeOnce: true
                                            }
                                        }
                                    });

                                    CKEDITOR.event.implementOn(Core);

                                    AlloyEditor.Core = Core;
                                }());