Source: observer/EventObserver.js

(function() {
    /**
     * observes DOM events
     * @augments Help4.observer.Observer
     */
    Help4.observer.EventObserver = class extends Help4.observer.Observer {
        /**
         * @override
         * @param {Help4.observer.Callback} callback
         * @param {Window} [win = window] - the to-be-observed window
         * @param {Object} [derived]
         */
        constructor(callback, win, derived) {
            const onEvent = event => {
                const {_callback} = this;

                // Help4.Event.stopObserving sometimes fails; therefore check this._callback
                if (_callback && (event = Help4.Event.normalize(event))) {
                    const retVal = _callback(event);
                    if (typeof retVal === 'boolean') return retVal;
                }
                return true;
            };

            super(callback, {
                statics: {
                    _window:  {init: win || window, destroy: false},
                    _onEvent: {init: onEvent, destroy: false}
                },
                derived
            });
        }

        /**
         * observes DOM events in the window specified by target
         * @override
         * @param {Window} target - the to be observed window
         * @param {Object} options - options for the DOM event observation
         * @returns {Help4.observer.EventObserver}
         */
        observe(target, options) {
            if (!Help4.isArray(options.type)) options.type = [options.type];

            super.observe(target, options);

            const {_window} = this;
            const {type: types, capture} = options;

            for (const type of types) {
                Help4.Event.observe(target, {
                    manual: true,
                    type,
                    window: _window,
                    capture,
                    callback: this._onEvent
                });
            }

            return this;
        }

        /**
         * @override
         * @returns {Help4.observer.EventObserver}
         */
        disconnect() {
            const {_window, _connections} = this;

            for (const {target, options: {type: types, capture}} of _connections) {
                for (const type of types) {
                    Help4.Event.stopObserving(target, {
                        manual: true,
                        type,
                        window: _window,
                        capture,
                        callback: this._onEvent
                    });
                }
            }

            super.disconnect();
            return this;
        }
    }
})();