Source: engine/ConditionEngine.js

(function() {
    /**
     * @typedef {Help4.engine.StateEngine.Params} Help4.engine.ConditionEngine.Params
     * @property {Help4.controller.ControllerBase} controller
     * @property {Help4.service.ConditionService} conditionService
     * @property {Help4.engine.DomRefreshEngine} domRefreshEngine
     * @property {Help4.engine.hotspotManager.HotspotManagerEngine} hotspotManager
     */

    /**
     * ConditionEngine class.
     * @augments Help4.engine.StateEngine
     */
    Help4.engine.ConditionEngine = class extends Help4.engine.StateEngine {
        /**
         * @override
         * @param {Help4.engine.ConditionEngine.Params} params
         */
        constructor(params) {
            super(params, {
                controller: null,
                hotspotManager: null,
                domRefreshEngine: null,
                conditionService: null
            });

            this.onChange = new Help4.EmbeddedEvent();
            this._execJob = () => this.execJob.call(this);
        }

        /** @override */
        destroy() {
            this.stop();
            delete this._status;
            delete this._execJob;

            this.onChange?.destroy();
            delete this.onChange;

            super.destroy();
        }

        /** @override */
        start() {
            if (this._started) return;
            super.start();

            const {_execJob} = this;
            this._status = {};
            this._params.domRefreshEngine.addExecutor(_execJob);  // watch DOM UI Elements
            window.addEventListener('popstate', _execJob);  // watch URL changes
        }

        /** @override */
        stop() {
            if (!this._started) return;
            super.stop();

            const {_execJob} = this;
            this._params.domRefreshEngine.removeExecutor(_execJob);
            window.removeEventListener('popstate', _execJob);
            this._status = {};
        }

        /** @override */
        clean() {
            this._status = {};
        }

        /**
         * @param {string} tileId
         * @return {boolean}
         */
        getStatus(tileId) {
            return this._status?.[tileId] ?? true;
        }

        execJob() {
            if (!this._started) return;

            const {_params: {controller, conditionService}, _status} = this;
            const {isEditMode = true, isTourMode = true} = controller?.getConfiguration() || {};
            if (isEditMode || isTourMode) return;

            const model = controller.getService('model');
            const carousel = controller.getHandler()?.getCarousel();

            const tiles = [];
            const promises = [];
            for (const carouselTile of carousel?.getTile() || []) {
                const tileId = carouselTile.getMetadata('tileId');
                const tourId = carouselTile.getMetadata('tourId');
                const tile = tileId
                    ? model.getTile(tileId)
                    : (tourId ? model.getProject({id: tourId}) : null);

                if (tile?.conditions?.length) {
                    const {id, conditions, hotspotAnchor} = tile;
                    tiles.push(id);
                    promises.push(conditionService.checkConditions({conditions, hotspotAnchor}));
                }
            }

            Help4.Promise.all(promises)
            .then(result => {
                /**
                 * @param {boolean|null} fulfilled
                 * @param {number} index
                 */
                result.forEach((fulfilled, index) => {
                    const id = tiles[index];
                    if (typeof fulfilled === 'boolean' && _status[id] !== fulfilled) {
                        _status[id] = fulfilled;
                        this.onChange.onEvent({id, fulfilled});
                    }
                });
            });
        }
    }
})();