src/provider/CursorProvider.js

goog.module('gep.provider.CursorProvider');

const {listen,unlisten,Event,EventType,EventTarget} = goog.require('goog.events');
const classlist = goog.require('goog.dom.classlist');
const {setStyle} = goog.require('goog.style');

/**
 * This provider (singleton) manages the display of a custom cursor object if a corresponding element with the `class="custom-cursor"` exists in the dom.
 * @extends {EventTarget}
 */
class CursorProvider extends EventTarget
{
    constructor()
    {
        super();

        /**
         * List of elements to be perceived for hovering.
         * @type {NodeList}
         * @private
         */
        this.hoverElements_ = null;

        /**
         * List of elements that should use the default cursor for themselves again.
         * @type {NodeList}
         * @private
         */
        this.leaveElements_ = null;

        /**
         * Element in the dom which is used as a grafic replacement of the cursor.
         * @type {Element}
         * @private
         */
        this.cursor_ = document.documentElement.querySelector('.custom-cursor');

        /**
         * Specifies whether the display of the custom cursor should be prevented.
         * @type {boolean}
         * @private
         */
        this.preventShow_ = false;

        if(this.cursor_)
        {
            listen(window, EventType.MOUSEMOVE, this.move_, false, this);
            listen(window, EventType.MOUSEOUT, this.hide, false, this);
        }
    }

    /**
     * Trigger manual check to display custom mouse cursor after changing the list of hover or leave elements.
     */
    update()
    {
        if(!this.cursor_)
            return;

        if(this.hoverElements_)
            this.hoverElements_.forEach((element) => {
                unlisten(element, EventType.MOUSEOVER, this.over, false, this);
                unlisten(element, EventType.MOUSEOUT, this.out, false, this);
            });
        if(this.leaveElements_)
            this.leaveElements_.forEach((element) => {
                unlisten(element, EventType.MOUSEOVER, this.handleLeaveOver_, false, this);
                unlisten(element, EventType.MOUSEOUT, this.handleLeaveOut_, false, this);
            });

        this.hoverElements_ = document.body.querySelectorAll('button,a');
        this.hoverElements_.forEach((element) => {
            listen(element, EventType.MOUSEOVER, this.over, false, this);
            listen(element, EventType.MOUSEOUT, this.out, false, this);
        });

        this.leaveElements_ = document.body.querySelectorAll('.layer-media-vimeo,.layer.installation-frame .layer-content-wrapper');
        this.leaveElements_.forEach((element) => {
            listen(element, EventType.MOUSEOVER, this.handleLeaveOver_, false, this);
            listen(element, EventType.MOUSEOUT, this.handleLeaveOut_, false, this);
        });
    }

    /**
     * Handle mouse move event for updating the position of the custom cursor
     * @param {Event} event
     * @private
     */
    move_(event)
    {
        if(!this.preventShow_) this.show();
        setStyle(this.cursor_, {'left': event.getBrowserEvent().clientX+'px', 'top': event.getBrowserEvent().clientY+'px'})
    }

    /**
     * Handle mouse over an element which is defined in the leave element list and should display the default cursor
     * @param {Event} event
     * @private
     */
    handleLeaveOver_(event)
    {
        this.preventShow_ = true;
        this.hide();
    }

    /**
     * Handle mouse out an element which is defined in the leave element list and should display the default cursor
     * @private
     */
    handleLeaveOut_()
    {
        this.preventShow_ = false;
    }

    /**
     * Handle mouse over event of an element which is defined in the hover elements list
     */
    over()
    {
        classlist.add(document.documentElement, 'is-mouse-over');
    }

    /**
     * Handle mouse out event of an element which is defined in the hover elements list
     */
    out()
    {
        classlist.remove(document.documentElement, 'is-mouse-over');
    }

    /**
     * Make the custom cursor visible
     */
    show()
    {
        if(!this.preventShow_)
            classlist.add(document.documentElement, 'has-custom-cursor');
    }

    /**
     * Hide the custom cursor
     */
    hide()
    {
        classlist.remove(document.documentElement, 'has-custom-cursor');
    }
}

goog.addSingletonGetter(CursorProvider);

exports = CursorProvider;