Show: Inherited Protected Private Deprecated

# File `src/core/selection-region.js`

                                (function() {
                                    'use strict';

                                    if (CKEDITOR.plugins.get('ae_selectionregion')) {
                                        return;
                                    }

                                    CKEDITOR.SELECTION_TOP_TO_BOTTOM = 0;
                                    CKEDITOR.SELECTION_BOTTOM_TO_TOP = 1;
                                    CKEDITOR.SELECTION_LEFT_TO_RIGHT = 2;
                                    CKEDITOR.SELECTION_RIGHT_TO_LEFT = 3;

                                    /**
                                     * SelectionRegion utility class which provides metadata about the selection. The metadata may be the start and end
                                     * rectangles, caret region, etc. **This class is not intended to be used standalone. Its functions will
                                     * be merged into each editor instance, so the developer may use them directly via the editor, without making
                                     * an instance of this class**.
                                     *
                                     * @class CKEDITOR.plugins.ae_selectionregion
                                     * @constructor
                                     */
                                    function SelectionRegion() {}

                                    SelectionRegion.prototype = {
                                        constructor: SelectionRegion,

                                        /**
                                         * Creates selection from two points in page coordinates.
                                         *
                                         * @method createSelectionFromPoint
                                         * @param {Number} x X point in page coordinates.
                                         * @param {Number} y Y point in page coordinates.
                                         */
                                        createSelectionFromPoint: function(x, y) {
                                            this.createSelectionFromRange(x, y, x, y);
                                        },

                                        /**
                                         * Creates selection from range. A range consists from two points in page coordinates.
                                         *
                                         * @method createSelectionFromRange
                                         * @param {Number} startX X coordinate of the first point.
                                         * @param {Number} startY Y coordinate of the first point.
                                         * @param {Number} endX X coordinate of the second point.
                                         * @param {Number} endY Y coordinate of the second point.
                                         */
                                        createSelectionFromRange: function(startX, startY, endX, endY) {
                                            var end;
                                            var endContainer;
                                            var endOffset;
                                            var range;
                                            var start;
                                            var startContainer;
                                            var startOffset;

                                            if (typeof document.caretPositionFromPoint === 'function') {
                                                start = document.caretPositionFromPoint(startX, startY);
                                                end = document.caretPositionFromPoint(endX, endY);

                                                startContainer = start.offsetNode;
                                                endContainer = end.offsetNode;

                                                startOffset = start.offset;
                                                endOffset = end.offset;

                                                range = this.createRange();
                                            } else if (typeof document.caretRangeFromPoint === 'function') {
                                                start = document.caretRangeFromPoint(startX, startY);
                                                end = document.caretRangeFromPoint(endX, endY);

                                                startContainer = start.startContainer;
                                                endContainer = end.startContainer;

                                                startOffset = start.startOffset;
                                                endOffset = end.startOffset;

                                                range = this.createRange();
                                            }

                                            if (range && document.getSelection) {
                                                range.setStart(new CKEDITOR.dom.node(startContainer), startOffset);
                                                range.setEnd(new CKEDITOR.dom.node(endContainer), endOffset);

                                                this.getSelection().selectRanges([range]);
                                            } else if (typeof document.body.createTextRange === 'function') {
                                                var selection = this.getSelection();

                                                selection.unlock();

                                                range = document.body.createTextRange();
                                                range.moveToPoint(startX, startY);

                                                var endRange = range.duplicate();
                                                endRange.moveToPoint(endX, endY);

                                                range.setEndPoint('EndToEnd', endRange);
                                                range.select();

                                                this.getSelection().lock();
                                            }
                                        },

                                        /**
                                         * Returns the region of the current position of the caret. The points are in page coordinates.
                                         *
                                         * @method getCaretRegion
                                         * @return {Object} Returns object with the following properties:
                                         * - bottom
                                         * - left
                                         * - right
                                         * - top
                                         */
                                        getCaretRegion: function() {
                                            var selection = this.getSelection();

                                            var region = {
                                                bottom: 0,
                                                left: 0,
                                                right: 0,
                                                top: 0
                                            };

                                            var bookmarks = selection.createBookmarks();

                                            if (!bookmarks.length) {
                                                return region;
                                            }

                                            var bookmarkNodeEl = bookmarks[0].startNode.$;

                                            bookmarkNodeEl.style.display = 'inline-block';

                                            region = new CKEDITOR.dom.element(bookmarkNodeEl).getClientRect();

                                            bookmarkNodeEl.parentNode.removeChild(bookmarkNodeEl);

                                            var scrollPos = new CKEDITOR.dom.window(window).getScrollPosition();

                                            region.bottom = scrollPos.y + region.bottom;
                                            region.left = scrollPos.x + region.left;
                                            region.right = scrollPos.x + region.right;
                                            region.top = scrollPos.y + region.top;

                                            return region;
                                        },

                                        /**
                                         * Returns data for the current selection.
                                         *
                                         * @method getSelectionData
                                         * @return {Object|null} Returns an object with the following data:
                                         * - element - The currently selected element, if any
                                         * - text - The selected text
                                         * - region - The data, returned from {{#crossLink "CKEDITOR.plugins.ae_selectionregion/getSelectionRegion:method"}}{{/crossLink}}
                                         */
                                        getSelectionData: function() {
                                            var selection = this.getSelection();

                                            if (!selection.getNative()) {
                                                return null;
                                            }

                                            var result = {
                                                element: selection.getSelectedElement(),
                                                text: selection.getSelectedText()
                                            };

                                            result.region = this.getSelectionRegion(selection);

                                            return result;
                                        },

                                        /**
                                         * Returns the region of the current selection.
                                         *
                                         * @method getSelectionRegion
                                         * @return {Object} Returns object which is being returned from
                                         * {{#crossLink "CKEDITOR.plugins.ae_selectionregion/getClientRectsRegion:method"}}{{/crossLink}} with three more properties:
                                         * - direction - the direction of the selection. Can be one of these:
                                         *   1. CKEDITOR.SELECTION_TOP_TO_BOTTOM
                                         *   2. CKEDITOR.SELECTION_BOTTOM_TO_TOP
                                         * - height - The height of the selection region
                                         * - width - The width of the selection region
                                         */
                                        getSelectionRegion: function() {
                                            var region = this.getClientRectsRegion();

                                            region.direction = this.getSelectionDirection();

                                            region.height = region.bottom - region.top;
                                            region.width = region.right - region.left;

                                            return region;
                                        },

                                        /**
                                         * Returns true if the current selection is empty, false otherwise.
                                         *
                                         * @method isSelectionEmpty
                                         * @return {Boolean} Returns true if the current selection is empty, false otherwise.
                                         */
                                        isSelectionEmpty: function() {
                                            var ranges;

                                            var selection = this.getSelection();

                                            return (selection.getType() === CKEDITOR.SELECTION_NONE) ||
                                                ((ranges = selection.getRanges()) && ranges.length === 1 && ranges[0].collapsed);
                                        },

                                        /**
                                         * Returns object with data about the [client rectangles](https://developer.mozilla.org/en-US/docs/Web/API/Element.getClientRects) of the selection,
                                         * normalized across browses. All offsets below are in page coordinates.
                                         *
                                         * @method getClientRectsRegion
                                         * @return {Object} Returns object with the following data:
                                         * - bottom - bottom offset of all client rectangles
                                         * - left - left offset of all client rectangles
                                         * - right - right offset of all client rectangles
                                         * - top - top offset of all client rectangles
                                         * - startRect - An Object, which contains the following information:
                                         *     + bottom - bottom offset
                                         *     + height - the height of the rectangle
                                         *     + left - left offset of the selection
                                         *     + right - right offset of the selection
                                         *     + top - top offset of the selection
                                         *     + width - the width of the rectangle
                                         * - endRect - An Object, which contains the following information:
                                         *     + bottom - bottom offset
                                         *     + height - the height of the rectangle
                                         *     + left - left offset of the selection
                                         *     + right - right offset of the selection
                                         *     + top - top offset of the selection
                                         *     + width - the width of the rectangle
                                         *
                                         * If there is no native selection, the objects will be filled with 0.
                                         */
                                        getClientRectsRegion: function() {
                                            var selection = this.getSelection();
                                            var nativeSelection = selection.getNative();

                                            var defaultRect = {
                                                bottom: 0,
                                                height: 0,
                                                left: 0,
                                                right: 0,
                                                top: 0,
                                                width: 0
                                            };

                                            var region = {
                                                bottom: 0,
                                                endRect: defaultRect,
                                                left: 0,
                                                right: 0,
                                                top: 0,
                                                startRect: defaultRect
                                            };

                                            if (!nativeSelection) {
                                                return region;
                                            }

                                            var bottom = 0;
                                            var clientRects;
                                            var left = Infinity;
                                            var rangeCount;
                                            var right = -Infinity;
                                            var top = Infinity;

                                            if (nativeSelection.createRange) {
                                                clientRects = nativeSelection.createRange().getClientRects();
                                            } else {
                                                rangeCount = nativeSelection.rangeCount;
                                                clientRects = (nativeSelection.rangeCount > 0) ? nativeSelection.getRangeAt(0).getClientRects() : [];
                                            }

                                            if (clientRects.length === 0) {
                                                region = this.getCaretRegion();
                                            } else {
                                                for (var i = 0, length = clientRects.length; i < length; i++) {
                                                    var item = clientRects[i];

                                                    if (item.left < left) {
                                                        left = item.left;
                                                    }

                                                    if (item.right > right) {
                                                        right = item.right;
                                                    }

                                                    if (item.top < top) {
                                                        top = item.top;
                                                    }

                                                    if (item.bottom > bottom) {
                                                        bottom = item.bottom;
                                                    }
                                                }

                                                var scrollPos = new CKEDITOR.dom.window(window).getScrollPosition();

                                                region.bottom = scrollPos.y + bottom;
                                                region.left = scrollPos.x + left;
                                                region.right = scrollPos.x + right;
                                                region.top = scrollPos.y + top;

                                                if (clientRects.length) {
                                                    var endRect = clientRects[clientRects.length - 1];
                                                    var startRect = clientRects[0];

                                                    region.endRect = {
                                                        bottom: scrollPos.y + endRect.bottom,
                                                        height: endRect.height,
                                                        left: scrollPos.x + endRect.left,
                                                        right: scrollPos.x + endRect.right,
                                                        top: scrollPos.y + endRect.top,
                                                        width: endRect.width
                                                    };

                                                    region.startRect = {
                                                        bottom: scrollPos.y + startRect.bottom,
                                                        height: startRect.height,
                                                        left: scrollPos.x + startRect.left,
                                                        right: scrollPos.x + startRect.right,
                                                        top: scrollPos.y + startRect.top,
                                                        width: startRect.width
                                                    };
                                                }
                                            }

                                            return region;
                                        },

                                        /**
                                         * Retrieves the direction of the selection. The direction is from top to bottom or from bottom to top.
                                         * For IE < 9 it is not possible, so the direction for these browsers will be always CKEDITOR.SELECTION_TOP_TO_BOTTOM.
                                         *
                                         * @method getSelectionDirection
                                         * @return {Number} Returns a number which represents selection direction. It might be one of these:
                                         * - CKEDITOR.SELECTION_TOP_TO_BOTTOM;
                                         * - CKEDITOR.SELECTION_BOTTOM_TO_TOP;
                                         */
                                        getSelectionDirection: function() {
                                            var direction = CKEDITOR.SELECTION_TOP_TO_BOTTOM;
                                            var selection = this.getSelection();
                                            var nativeSelection = selection.getNative();

                                            if (!nativeSelection) {
                                                return direction;
                                            }

                                            var anchorNode;

                                            if ((anchorNode = nativeSelection.anchorNode) && anchorNode.compareDocumentPosition) {
                                                var position = anchorNode.compareDocumentPosition(nativeSelection.focusNode);

                                                if (!position && nativeSelection.anchorOffset > nativeSelection.focusOffset || position === Node.DOCUMENT_POSITION_PRECEDING) {
                                                    direction = CKEDITOR.SELECTION_BOTTOM_TO_TOP;
                                                }
                                            }

                                            return direction;
                                        }
                                    };

                                    CKEDITOR.plugins.add(
                                        'ae_selectionregion', {
                                            /**
                                             * Initializer lifecycle implementation for the SelectionRegion plugin.
                                             *
                                             * @method init
                                             * @protected
                                             * @param {Object} editor The current CKEditor instance.
                                             */
                                            init: function(editor) {
                                                var attr,
                                                    hasOwnProperty;

                                                hasOwnProperty = Object.prototype.hasOwnProperty;

                                                for (attr in SelectionRegion.prototype) {
                                                    if (hasOwnProperty.call(SelectionRegion.prototype, attr) && typeof editor[attr] === 'undefined') {
                                                        editor[attr] = SelectionRegion.prototype[attr];
                                                    }
                                                }
                                            }
                                        }
                                    );
                                }());