Show:
                            (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;
                            }());