import {h, Component, createRef} from 'preact'; import {LayoutHotspot, shallowCompareHotspots} from '../utils/hotspot'; import Hotspot from './Hotspot'; import {AnalyticsEvents} from '../utils/analyticsEvents'; const { withPlayer } = KalturaPlayer.ui.components; const { withText, Text } = KalturaPlayer.ui.preacti18n; const translates = { hotspotRemoved: ( {`{hotspotLabel} hotspot removed`} ), hotspotAdded: ( {`{hotspotLabel} hotspot added`} ) }; const hotspotsContainerStyles = { position: 'absolute', display: 'block', overflow: 'visible', top: 0, left: 0, width: 0, height: 0 }; export interface Props { hotspots: LayoutHotspot[]; pauseVideo(): void; seekTo(time: number): void; sendAnalytics(event: AnalyticsEvents): void; dispatcher(name: string, payload?: any): void; hotspotRemoved?: string; hotspotAdded?: string; player?: any; } @withPlayer @withText(translates) export default class HotspotWrapper extends Component { private liveRegionRef = createRef(); private previousHotspotMap: Map = new Map(); shouldComponentUpdate(nextProps: Props) { return !shallowCompareHotspots(this.props.hotspots, nextProps.hotspots); } componentDidUpdate() { const currentMap = new Map( this.props.hotspots .filter(h => typeof h.label === 'string') .map(h => [h.id, h.label!]) ); let announced = false; // Announce removed hotspots this.previousHotspotMap.forEach((label, id) => { if (!currentMap.has(id) && !announced) { if (this.props.hotspotRemoved) { const message = this.props.hotspotRemoved.replace('{hotspotLabel}', label); this.announceHotspotChange(message); } announced = true; } }); // Announce added hotspots if (!announced) { currentMap.forEach((label, id) => { if (!this.previousHotspotMap.has(id) && !announced) { if (this.props.hotspotAdded) { const message = this.props.hotspotAdded.replace('{hotspotLabel}', label); this.announceHotspotChange(message); } announced = true; } }); } this.previousHotspotMap = currentMap; } private announceHotspotChange(message: string) { const liveRegion = this.liveRegionRef.current; if (!liveRegion) return; liveRegion.textContent = ''; //setTimeout ensures the DOM change happens in two separate cycles // which solves the issue that the hotspot removal is announced only the first time. setTimeout(() => { liveRegion.textContent = message; }); } private renderHotspots = (visualHotspot: LayoutHotspot[]) => { if (!visualHotspot) { return null; } const {seekTo, pauseVideo, sendAnalytics, dispatcher} = this.props; return visualHotspot.map(hotspotData => ( )); }; render() { const {hotspots} = this.props; const hotspotsElements = this.renderHotspots(hotspots); const targetId = this.props.player?.config?.targetId; const liveRegionId = `hotspot-liveRegion-${targetId}`; return (
{hotspotsElements}
); } }