Show: Inherited Protected Private Deprecated

# File `src/core/link.js`

                                (function() {
                                    'use strict';

                                    var REGEX_EMAIL_SCHEME = /^[a-z0-9\u0430-\u044F\._-]+@/i;
                                    var REGEX_URI_SCHEME = /^(?:[a-z][a-z0-9+\-.]*)\:|^\//i;

                                    /**
                                     * Link class utility. Provides methods for create, delete and update links.
                                     *
                                     * @class CKEDITOR.Link
                                     * @constructor
                                     * @param {Object} editor The CKEditor instance.
                                     */

                                    function Link(editor, config) {
                                        this._editor = editor;
                                        this.appendProtocol = config && config.appendProtocol === false ? false : true;
                                    }

                                    Link.prototype = {
                                        constructor: Link,

                                        /**
                                         * Advances the editor selection to the next available position after a
                                         * given link or the one in the current selection.
                                         *
                                         * @param {CKEDITOR.dom.element} link The link element which link style should be removed.
                                         * @method advanceSelection
                                         */
                                        advanceSelection: function(link) {
                                            link = link || this.getFromSelection();

                                            var range = this._editor.getSelection().getRanges()[0];

                                            if (link) {
                                                range.moveToElementEditEnd(link);

                                                var nextNode = range.getNextEditableNode();

                                                if (nextNode && !this._editor.element.equals(nextNode.getCommonAncestor(link))) {
                                                    var whitespace = /\s/.exec(nextNode.getText());

                                                    var offset = whitespace ? whitespace.index + 1 : 0;

                                                    range.setStart(nextNode, offset);
                                                    range.setEnd(nextNode, offset);
                                                }
                                            }

                                            this._editor.getSelection().selectRanges([range]);
                                        },

                                        /**
                                         * Create a link with given URI as href.
                                         *
                                         * @method create
                                         * @param {String} URI The URI of the link.
                                         * @param {Object} attrs A config object with link attributes. These might be arbitrary DOM attributes.
                                         * @param {Object} modifySelection A config object with an advance attribute to indicate if the selection should be moved after the link creation.
                                         */
                                        create: function(URI, attrs, modifySelection) {
                                            var selection = this._editor.getSelection();

                                            var range = selection.getRanges()[0];

                                            if (range.collapsed) {
                                                var text = new CKEDITOR.dom.text(URI, this._editor.document);
                                                range.insertNode(text);
                                                range.selectNodeContents(text);
                                            }

                                            URI = this._getCompleteURI(URI);

                                            var linkAttrs = CKEDITOR.tools.merge({
                                                'data-cke-saved-href': URI,
                                                href: URI
                                            }, attrs);

                                            var style = new CKEDITOR.style({
                                                attributes: linkAttrs,
                                                element: 'a'
                                            });

                                            style.type = CKEDITOR.STYLE_INLINE;
                                            style.applyToRange(range, this._editor);

                                            if (modifySelection && modifySelection.advance) {
                                                this.advanceSelection();
                                            } else {
                                                range.select();
                                            }
                                        },

                                        /**
                                         * Retrieves a link from the current selection.
                                         *
                                         * @method getFromSelection
                                         * @return {CKEDITOR.dom.element} The retrieved link or null if not found.
                                         */
                                        getFromSelection: function() {
                                            var selection = this._editor.getSelection();

                                            var selectedElement = selection.getSelectedElement();

                                            if (selectedElement && selectedElement.is('a')) {
                                                return selectedElement;
                                            }

                                            var range = selection.getRanges()[0];

                                            if (range) {
                                                range.shrink(CKEDITOR.SHRINK_TEXT);

                                                return this._editor.elementPath(range.getCommonAncestor()).contains('a', 1);
                                            }

                                            return null;
                                        },

                                        /**
                                         * Removes a link from the editor.
                                         *
                                         * @param {CKEDITOR.dom.element} link The link element which link style should be removed.
                                         * @param {Object} modifySelection A config object with an advance attribute to indicate if the selection should be moved after the link creation.
                                         * @method remove
                                         */
                                        remove: function(link, modifySelection) {
                                            var editor = this._editor;

                                            if (link) {
                                                if (modifySelection && modifySelection.advance) {
                                                    this.advanceSelection();
                                                }

                                                link.remove(editor);
                                            } else {
                                                var style = new CKEDITOR.style({
                                                    alwaysRemoveElement: 1,
                                                    element: 'a',
                                                    type: CKEDITOR.STYLE_INLINE
                                                });

                                                // 'removeStyle()' removes the style from the editor's current selection.
                                                //  We need to force the selection to be the whole link element
                                                //  to remove it properly.

                                                var selection = editor.getSelection();
                                                selection.selectElement(selection.getStartElement());

                                                editor.removeStyle(style);
                                            }
                                        },

                                        /**
                                         * Updates the href of an already existing link.
                                         *
                                         * @method update
                                         * @param {Object|String} attrs The attributes to update or remove. Attributes with null values will be removed.
                                         * @param {CKEDITOR.dom.element} link The link element which href should be removed.
                                         * @param {Object} modifySelection A config object with an advance attribute to indicate if the selection should be moved after the link creation.
                                         */
                                        update: function(attrs, link, modifySelection) {
                                            link = link || this.getFromSelection();

                                            if (typeof attrs === 'string') {
                                                link.setAttributes({
                                                    'data-cke-saved-href': attrs,
                                                    href: attrs
                                                });
                                            } else if (typeof attrs === 'object') {
                                                var removeAttrs = [];
                                                var setAttrs = {};

                                                Object.keys(attrs).forEach(function(key) {
                                                    if (attrs[key] === null) {
                                                        if (key === 'href') {
                                                            removeAttrs.push('data-cke-saved-href');
                                                        }

                                                        removeAttrs.push(key);
                                                    } else {
                                                        if (key === 'href') {
                                                            setAttrs['data-cke-saved-href'] = attrs[key];
                                                        }

                                                        setAttrs[key] = attrs[key];
                                                    }
                                                });

                                                link.removeAttributes(removeAttrs);
                                                link.setAttributes(setAttrs);
                                            }

                                            if (modifySelection && modifySelection.advance) {
                                                this.advanceSelection(link);
                                            }
                                        },

                                        /**
                                         * Checks if the URI has an '@' symbol. If it does and the URI looks like an email
                                         * and doesn't have 'mailto:', 'mailto:' is added to the URI.
                                         * If it doesn't and the URI doesn't have a scheme, the default 'http' scheme with
                                         * hierarchical path '//' is added to the URI.
                                         *
                                         * @protected
                                         * @method _getCompleteURI
                                         * @param {String} URI The URI of the link.
                                         * @return {String} The URI updated with the protocol.
                                         */
                                        _getCompleteURI: function(URI) {
                                            if (REGEX_EMAIL_SCHEME.test(URI)) {
                                                URI = 'mailto:' + URI;
                                            } else if (!REGEX_URI_SCHEME.test(URI)) {
                                                URI = this.appendProtocol ? 'http://' + URI : URI;
                                            }

                                            return URI;
                                        }
                                    };

                                    CKEDITOR.Link = CKEDITOR.Link || Link;
                                }());