arrowsControl.js

define(['utils', 'IControl', 'errors'], function(Utils, IControl, Errors) {
    "use strict";

    /**
     * @class
     * Класс управления панелью с помощью стрелок, отображаемых по сторонам панели.
     * @param {JQuery} mainDiv - элемент, в котором располагается панель. Должен содержать класс rb-wrapper.
     * @param {function} actionFn - функция, определяющая действие при переходе в одну из сторон (Moving.prototype._moveByActionValue)
     * @param {Moving#afterRenderDispatcher} afterRender - Диспетчер, выполняющий зарегистрированные функции после рендеринга контента моделей на странице после перехода
     * @constructor ArrowsControl
     * @extends IControl
     */
    function ArrowsControl(mainDiv, actionFn, afterRender) {
        if (!(mainDiv instanceof $)) {
            throw new Errors.ArgumentError('mainDiv', mainDiv);
        }

        if (typeof actionFn !== 'function') {
            throw new Errors.ArgumentError('actionFn', actionFn);
        }
        this._isEnable = false;
        this._mainDiv = mainDiv.parent();
        this._actionFn = actionFn;
        this._afterRender = afterRender;
    }
    Utils.inherite(ArrowsControl, IControl);

    /**
     * Применить конфигурацию. Учитывает опции hideArrowsTime, showArrowsOutside, showArrowsOnHover, hideArrowsAfterTime.
     * @param {Moving~config} config
     * @memberOf ArrowsControl
     */
    ArrowsControl.prototype.configure = function(config) {
        if (typeof config === 'object') {
            if (config.hideArrowsTime !== undefined) {
                this._hideArrowsTime = config.hideArrowsTime;
            }
            if (config.showArrowsOutside !== undefined) {
                this._showArrowsOutside = config.showArrowsOutside;
            }
            if (config.showArrowsOnHover !== undefined) {
                this._showArrowsOnHover = config.showArrowsOnHover;
            }
            if (config.hideArrowsAfterTime !== undefined) {
                this._hideArrowsAfterTime = config.hideArrowsAfterTime;
            }
        }
        this._containerClass = (this._showArrowsOnHover ? 'rb__arrow-container-hover' : 'rb__arrow-container');
    };
    /**
     *
     * @returns {boolean}
     * @memberOf ArrowsControl
     */
    ArrowsControl.prototype.isEnable = function() {
        return this._isEnable;
    };
    /**
     *
     * @memberOf ArrowsControl
     */
    ArrowsControl.prototype.enable = function() {
        if (this._isEnable) return;

        var self = this;
        var mouseEnterHandler = function(e) {
            if (!self._hideArrowsAfterTime) return;

            var arrow = $(e.currentTarget),
                $body = $('body'),
                arrowOffset = arrow.offset(),
                arrowX = arrowOffset.left,
                arrowY = arrowOffset.top,
                arrowXX = arrowX + arrow.width(),
                arrowYY = arrowY + arrow.height();

            //var timeoutId;
            function mouseMoveHandler(e) {
                var x = e.clientX, y = e.clientY;

                if (!(arrowX < x && x < arrowXX && arrowY < y && y < arrowYY)) {
                    arrow.toggleClass('rb__arrow-none', false);
                    arrow.toggleClass('rb__arrow-cursor', true);
                    $body.off('mousemove', mouseMoveHandler);
                    //clearTimeout(timeoutId);
                }
            }
            function hideArrow() {
                arrow.toggleClass('rb__arrow-none', true);
                arrow.toggleClass('rb__arrow-cursor', false);

                $body.on('mousemove', mouseMoveHandler);
                //timeoutId = setTimeout(function() {
                //    arrow.toggleClass('rb__arrow-none', false);
                //    arrow.toggleClass('rb__arrow-cursor', true);
                //    $body.off('mousemove', mouseMoveHandler);
                //}, 10000);
                // todo если из iframe не всплывает mousemove с нормальными координатами, для iframe не будет работать
            }

            if (arrow.length) {
                arrow[0].hideArrowId = setTimeout(hideArrow, self._hideArrowsTime);
            }
        };
        var mouseLeaveHandler = function(e) {
            if (!self._hideArrowsAfterTime) return;

            var arrow = $(e.currentTarget);
            clearTimeout(arrow[0].hideArrowId);
        };
        var clickHandler = function(e) {
            var arrow = $(e.currentTarget);

            mouseLeaveHandler(e);
            self._afterRender.add(mouseEnterHandler.bind(undefined, e), true);

            self._actionFn(arrow, Utils.sides, function(container, defValue) {
                return container.is('.rb__arrow-container_' + defValue);
            });
        };

        var markup = '';
        Utils.sides.forEach(function(side) {
            markup += '<div class="' +
                self._containerClass +
                ' rb__arrow-cursor rb__arrow-container_' + side + '' +
                (self._showArrowsOutside ? (' rb__arrow-outside_' + side) : '') +
                '">' +
                '<div class="rb__arrow rb__arrow_' + side + '"></div>' +
                '</div>';
        });
        this._mainDiv.append($(markup));

        var $rbArrowContainer = this._mainDiv.find('>.' + this._containerClass);

        $rbArrowContainer.on('click', clickHandler);
        $rbArrowContainer.on('mouseenter', mouseEnterHandler);
        $rbArrowContainer.on('mouseleave', mouseLeaveHandler);
        this._clickHandler = clickHandler;
        this._mouseEnterHandler = mouseEnterHandler;
        this._mouseLeaveHandler = mouseLeaveHandler;

        this._isEnable = true;
    };
    /**
     *
     * @memberOf ArrowsControl
     */
    ArrowsControl.prototype.disable = function() {
        if (!this._isEnable) return;

        var $rbArrowContainer = this._mainDiv.find('>.' + this._containerClass);
        for (var i = 0; i < $rbArrowContainer.length; i++) {
            clearTimeout($rbArrowContainer[i].hideArrowId);
        }
        $rbArrowContainer.off('click', this._clickHandler);
        $rbArrowContainer.off('mouseenter', this._mouseEnterHandler);
        $rbArrowContainer.off('mouseleave', this._mouseLeaveHandler);
        this._clickHandler = null;
        this._mouseEnterHandler = null;
        this._mouseLeaveHandler = null;

        this._mainDiv.find('>.' + this._containerClass).remove();

        this._isEnable = false;
    };
    /**
     *
     * @memberOf ArrowsControl
     */
    ArrowsControl.prototype.destroy = function() {
        this.disable();
    };

    return ArrowsControl;
});