Source: widget/help/view2/TileHotspot.js

(function() {
    /**
     * @typedef {Object} Help4.widget.help.view2.TileHotspot.ControlParams
     * @property {string} animationType
     * @property {Help4.control2.SizeWidthHeight} delta
     * @property {string} hotspotType
     * @property {string} icon
     * @property {?number} number
     * @property {Help4.control2.PositionXY} point
     * @property {string} pos
     * @property {Help4.control2.AreaXYWH} rect
     * @property {string} size
     * @property {boolean} spotlight
     * @property {number} spotlightBlur
     * @property {number} spotlightOffset
     * @property {number} spotlightOpacity
     * @property {?string} title
     * @property {boolean} active
     * @property {boolean} visible
     * @property {Object} _metadata
     * @property {string} _metadata.tileId
     * @property {string} _metadata.hotspotId
     * @property {string} _metadata.controlStyle
     * @property {string} [controlType]
     * @property {string} [ariaLabel]
     */

    /** hotspot helper for {@link Help4.widget.help.view2.Tile} */
    Help4.widget.help.view2.TileHotspot = class {
        /**
         * @param {Help4.widget.help.view2.Tile} tile
         * @returns {boolean}
         */
        static updateHotspotControl(tile) {
            const {hotspotControlId, stealth, __contentView} = tile;

            const removeHotspotControl = () => {
                __contentView.remove(hotspotControlId);
                tile.hotspotControlId = null;
            }

            if (stealth) {
                removeHotspotControl();
                return false;
            }

            const {view2} = Help4.widget.help;
            const {__widget, projectTile, hotspotStatus} = tile;

            const hasHotspot = view2.hasHotspot(__widget, projectTile);
            const status = hasHotspot && hotspotStatus || {visible: false};
            const params = _getHotspotParams(tile, projectTile, status);

            if (params) {
                // check whether controlStyle are still the same
                const control = hotspotControlId && __contentView.get(hotspotControlId);
                const cs1 = control?.getMetadata('controlStyle');
                const cs2 = projectTile.hotspotStyle;

                if (cs1 === cs2) {
                    // update existing hotspot control
                    const skip = {_metadata: 1, hotspotType: 1, controlType: 1, contentLanguage: 1};
                    for (const [key, value] of Object.entries(params)) {
                        if (!skip[key]) control[key] = value;
                    }
                } else {
                    // add new hotspot control
                    tile.hotspotControlId = __contentView.add(params).id;
                }
            } else if (hotspotControlId) {
                removeHotspotControl();
            }

            return !hasHotspot || status.visible;
        }

        /** @param {Help4.widget.help.view2.Tile} tile */
        static selectHotspot(tile) {
            const {_selected, _hovered, hotspotControlId, __contentView} = tile;

            const control = __contentView.get(hotspotControlId);
            if (control) control.active = _selected || _hovered;
        }

        /** @param {Help4.widget.help.view2.Tile} tile */
        static wmHover(tile) {
            const {hotspotControlId, __contentView} = tile;

            const control = __contentView.get(hotspotControlId);
            control?.addCss('hover');
        }

        /** @param {Help4.widget.help.view2.Tile} tile */
        static wmLeave(tile) {
            const {hotspotControlId, __contentView} = tile;

            const control = __contentView.get(hotspotControlId);
            control?.removeCss('hover');
        }

        /**
         * @param {Help4.widget.help.view2.Tile} tile
         * @returns {boolean}
         */
        static stopHotspotAnimation(tile) {
            const {hotspot} = Help4.control2;
            const {Connected} = hotspot;
            const {__contentView, hotspotControlId} = tile;
            const control = hotspotControlId && __contentView.get(hotspotControlId);

            if (control instanceof Connected) {
                const {ANIMATION_TYPES: {none}} = hotspot;
                const {hotspotType, animationType} = control;

                if (hotspotType === 'icon' && animationType !== none) {
                    control.animationType = none;
                    return true;
                }
            }

            return false;
        }

        /**
         * @param {Help4.widget.help.view2.Tile} tile
         * @returns {Promise<void>}
         */
        static async scrollHotspotIntoView(tile) {
            const {hotspotStatus, stealth} = tile;
            const status = !stealth && hotspotStatus || {visible: false};
            const {visible, scrolled, topmost} = status;

            if (visible && (scrolled || !topmost)) {
                const {Core} = Help4.widget.companionCore;
                const {__widget, projectTile} = tile;
                const hotspotData = Core.projectTileToHotspotData(projectTile, status);

                const {/** @type {Help4.service.recording.PlaybackService} */ playbackService} = __widget.getContext().service;
                await playbackService.scrollIntoView(hotspotData);
            }
        }
    }

    /**
     * @private
     * @param {Help4.widget.help.view2.Tile} tile
     * @param {Help4.widget.help.ProjectTile} projectTile
     * @param {Object} hotspotStatus
     * @returns {?Help4.widget.help.view2.TileHotspot.ControlParams}
     */
    function _getHotspotParams(tile, projectTile, hotspotStatus) {
        const {
            data: {HotspotData},
            widget: {
                companionCore: {Core},
                help: {view2}
            },
            control2: {hotspot: {ANIMATION_TYPES}}
        } = Help4;

        const {__widget} = tile;
        const {configuration} = __widget.getContext();

        const hotspot = Core.projectTileToHotspotData(projectTile, hotspotStatus);
        const hotspotData = new HotspotData(hotspot);
        const params = /** @type {?Help4.widget.help.view2.TileHotspot.ControlParams} */ hotspotData.toControlParams(configuration);
        hotspotData.destroy();

        if (params) {
            const {__view, descriptor, _selected, _hovered} = tile;
            const {language} = projectTile;
            params._metadata = {
                ...params._metadata,
                type: 'hotspot',
                descriptor
            };
            params.controlType = 'hotspot.Connected';
            params.contentLanguage = language;
            params.ariaLabel = params.title;
            params.title = null;  // XRAY-5028 - hotspot tooltip - hide in playback

            // disable animation for controls where stopAnimation has been called for
            const seenAnimations = /** @type {Help4.widget.help.TileDescriptor[]} */ __view.getSeenAnimations();
            if (view2.containsTileDescriptor(seenAnimations, descriptor)) {
                params.animationType = ANIMATION_TYPES.none;
            }

            // activate hotspots; if hovered or selected
            params.active = _selected || _hovered;
        }

        return params;
    }
})();