/** * Dailymotion Pro – Unified Preview Module * * Consolidates preview logic for both VideoEmbed and SetupWizard contexts. * This module is a thin adapter over the shared preview core in `src/Admin/Preview/PreviewCore.ts`. * * Provides backward-compatible APIs for: * - VideoEmbed: updatePreview(), initPreviewListeners() * - SetupWizard: updateManualPreviewSW(), updateContextualPreviewSW(), teardownPreviewsSW() */ import { getMode, qs } from '../../Libs/Utils'; import { initPreviewCore, ScopeConfig } from '../Preview/PreviewCore'; type ScopeId = 'embed' | 'manual' | 'contextual'; /** * Scope configuration for VideoEmbed context. * Uses dynamic selectors based on getMode() (contextual vs manual). */ const embedScopeConfig: ScopeConfig = { id: 'embed', selectors: { containerId: 'dm-preview-container', headingId: 'dm-preview-heading', titleId: 'dm-preview-title', playerId: 'dm-preview-player', playerSelectId: () => (getMode() === 'contextual' ? 'contextual-player-id' : 'manual-player-id'), headingToggleId: () => (getMode() === 'contextual' ? 'contextual-video-heading' : 'manual-video-heading'), headingTextId: () => (getMode() === 'contextual' ? 'contextual-video-heading-text' : 'manual-video-heading-text'), headingFontId: () => (getMode() === 'contextual' ? 'contextual-font-heading' : 'manual-font-heading'), headingSizeId: () => (getMode() === 'contextual' ? 'contextual-heading-size' : 'manual-heading-size'), titleToggleId: () => (getMode() === 'contextual' ? 'contextual-video-title' : 'manual-video-title'), titleFontId: () => (getMode() === 'contextual' ? 'contextual-font-title' : 'manual-font-title'), titleSizeId: () => (getMode() === 'contextual' ? 'contextual-title-size' : 'manual-title-size'), muteId: () => (getMode() === 'contextual' ? 'contextual-mute' : 'manual-mute'), activeLabelSelector: '.active__player-id', }, hooks: { isScopeEnabled: () => { const mode = getMode(); if (mode === 'contextual') { const globalToggle = qs('contextual_embed'); return !!globalToggle?.checked; } return true; }, getVideoId: () => { const videoIdInput = qs('dm-preview-video-id'); return videoIdInput?.value || 'x8mubmn'; }, }, }; /** * Scope configuration for SetupWizard Manual context. */ const manualScopeConfig: ScopeConfig = { id: 'manual', selectors: { containerId: 'dm-preview-container-manual', headingId: 'dm-preview-heading-manual', titleId: 'dm-preview-title-manual', playerId: 'dm-preview-player-manual', playerSelectId: 'manual-player-id', headingToggleId: 'manual-video-heading', headingTextId: 'manual-video-heading-text', headingFontId: 'manual-font-heading', headingSizeId: 'manual-heading-size', titleToggleId: 'manual-video-title', titleFontId: 'manual-font-title', titleSizeId: 'manual-title-size', muteId: 'manual-mute', activeLabelSelector: '.active__player-id', extraActiveLabelSelector: '.active__player-id-manual', }, hooks: { getVideoId: () => 'x8mubmn', }, }; /** * Scope configuration for SetupWizard Contextual context. */ const contextualScopeConfig: ScopeConfig = { id: 'contextual', selectors: { containerId: 'dm-preview-container-contextual', headingId: 'dm-preview-heading-contextual', titleId: 'dm-preview-title-contextual', playerId: 'dm-preview-player-contextual', playerSelectId: 'contextual-player-id', headingToggleId: 'contextual-video-heading', headingTextId: 'contextual-video-heading-text', headingFontId: 'contextual-font-heading', headingSizeId: 'contextual-heading-size', titleToggleId: 'contextual-video-title', titleFontId: 'contextual-font-title', titleSizeId: 'contextual-title-size', muteId: 'contextual-mute', activeLabelSelector: '.active__player-id', extraActiveLabelSelector: '.active__player-id-contextual', }, hooks: { isScopeEnabled: () => { const toggle = qs('contextual_embed'); return !!toggle?.checked; }, getVideoId: () => 'x8mubmn', }, }; // Initialize preview core with all scope configurations const previewApi = initPreviewCore([embedScopeConfig, manualScopeConfig, contextualScopeConfig]); // ============================================================================ // VideoEmbed API (backward compatible) // ============================================================================ /** * Updates the preview configuration for the VideoEmbed settings screen. * Public API remains identical; underlying logic is delegated to the shared core. */ export function updatePreview(): void { const scopeId: ScopeId = 'embed'; previewApi.updateScope(scopeId); } /** * Attach listeners to Video Embed Settings controls to keep preview in sync. * This should be called on initialization. */ export function initPreviewListeners(): void { const mode = getMode(); const prefix = mode === 'contextual' ? 'contextual' : 'manual'; const elementIds = [ `${prefix}-player-id`, `${prefix}-video-heading`, `${prefix}-video-heading-text`, `${prefix}-font-heading`, `${prefix}-heading-size`, `${prefix}-video-title`, `${prefix}-font-title`, `${prefix}-title-size`, `${prefix}-mute`, 'dm-preview-video-id' // Specific to video embed preview ]; previewApi.attachListeners('embed', elementIds); updatePreview(); } // ============================================================================ // SetupWizard API (backward compatible) // ============================================================================ /** * Update the Default Embed Settings preview in Setup Wizard. * Safe to call on any relevant input change. */ export function updateManualPreviewSW(): void { previewApi.updateScope('manual'); } /** * Update the Contextual Video Matching preview in Setup Wizard. * Honors the global contextual toggle; disables preview when off. */ export function updateContextualPreviewSW(): void { previewApi.updateScope('contextual'); } /** * Teardown helper to destroy preview players when navigating between steps. * * Called by the wizard before switching steps to ensure there is no leftover * player instance continuing playback or holding event listeners. */ export async function teardownPreviewsSW(scope: 'manual' | 'contextual' | 'all' = 'all'): Promise { await previewApi.teardown(scope === 'all' ? 'all' : scope); }