mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 16:02:26 +00:00
chore(ai): document js/ui/components/VideoModal.js
Co-authored-by: PR0M3TH3AN <[email protected]>
This commit is contained in:
1 parent
05d575d187
commit
d2c6f0a32e
5 files changed
+168
No files matched your search
@@ -0,0 +1,21 @@
|
||||
# Context for Documentation: js/ui/components/VideoModal.js
|
||||
|
||||
- **Agent:** docs-code-investigator (daily scheduler)
|
||||
- **Date:** 2026-02-13
|
||||
- **Target File:** `js/ui/components/VideoModal.js`
|
||||
- **Line Count:** 6284 lines
|
||||
- **Reason for Selection:**
|
||||
- Identified as one of the largest source files in the codebase (ranking #2 after `profileModalController.js`).
|
||||
- No existing overview documentation found (`docs/VideoModal-overview.md` is missing).
|
||||
- Contains critical UI logic for video playback, menu rendering, and interaction handling.
|
||||
- High complexity with multiple imported controllers (`CommentsController`, `ReactionsController`, etc.).
|
||||
|
||||
## Plan
|
||||
1. Analyze the file structure to understand the `VideoModal` class and its main execution flows.
|
||||
2. Create `docs/VideoModal-overview.md` to document the high-level architecture, public API, and key invariants.
|
||||
3. Add JSDoc to the exported `VideoModal` class and its primary methods (`constructor`, `open`, `close`).
|
||||
4. Add inline comments for complex logic blocks (e.g., rendering, data fetching).
|
||||
5. Verify changes with `npm run lint` and `npm run test:unit` (to ensure no regressions).
|
||||
|
||||
## Goal
|
||||
Improve maintainability and developer understanding of this critical UI component by providing clear documentation and entry points.
|
||||
@@ -0,0 +1,82 @@
|
||||
# VideoModal Component Overview
|
||||
|
||||
The `VideoModal` (`js/ui/components/VideoModal.js`) is the primary UI controller for the full-screen video playback experience in bitvid. It manages the modal lifecycle, orchestrates playback, and coordinates sub-controllers for social interactions (comments, reactions, moderation).
|
||||
|
||||
## Core Responsibilities
|
||||
|
||||
1. **Lifecycle Management**: Handles lazy-loading of the modal HTML, DOM injection, and visibility toggling.
|
||||
2. **Playback Orchestration**: Connects the video metadata to the underlying media player (via `mediaLoader` or direct video element manipulation).
|
||||
3. **Social Coordination**: Instantiates and manages `CommentsController`, `ReactionsController`, `SimilarContentController`, and `ModerationController`.
|
||||
4. **Accessibility**: Enforces focus trapping and ARIA attributes via `ModalAccessibility`.
|
||||
5. **Global State Integration**: Updates the application's modal state (`setGlobalModalState`) to pause background feeds and handle back-button navigation.
|
||||
|
||||
## Public API
|
||||
|
||||
The `VideoModal` exposes a minimal public interface for the application orchestrator (`ModalManager` or `App`):
|
||||
|
||||
| Method | Description |
|
||||
|--------|-------------|
|
||||
| `constructor(deps)` | Initializes the controller with dependencies (DOM, logger, state helpers). Does *not* touch the DOM. |
|
||||
| `async load()` | Fetches `components/video-modal.html`, injects it into the DOM, and hydrates references. Safe to call multiple times (idempotent). |
|
||||
| `open(video, options)` | Resets state, populates the modal with the given `video` object, and makes it visible. |
|
||||
| `close()` | Hides the modal, pauses playback, clears state, and returns focus to the trigger element. |
|
||||
|
||||
### Dependencies
|
||||
The constructor requires a robust dependency injection object:
|
||||
- `document`: The DOM document.
|
||||
- `setGlobalModalState`: Function to notify the app of modal visibility changes.
|
||||
- `logger`: Logging utility.
|
||||
- `mediaLoader`: Service for handling media source resolution.
|
||||
- `assets`, `state`, `helpers`: Configuration objects.
|
||||
|
||||
## internal Architecture
|
||||
|
||||
### Lazy Loading & Hydration
|
||||
To improve initial page load performance, `VideoModal` does not render its markup until `load()` is called (typically on the first user interaction).
|
||||
1. **Fetch**: Retrieves `components/video-modal.html`.
|
||||
2. **Inject**: Appends the HTML to the `#modalContainer`.
|
||||
3. **Hydrate**: Queries for all necessary DOM elements (buttons, containers, inputs) and binds event listeners.
|
||||
4. **Sub-Controller Init**: Initializes `CommentsController`, `ReactionsController`, etc., passing them the fresh DOM references.
|
||||
|
||||
### Sub-Controllers
|
||||
The `VideoModal` acts as a parent controller, delegating specific logic to specialized classes:
|
||||
- **`CommentsController`**: Manages the comment thread, composer, and fetching.
|
||||
- **`ReactionsController`**: Handles likes/dislikes and reaction counts.
|
||||
- **`SimilarContentController`**: Fetches and renders related videos.
|
||||
- **`ModerationController`**: Manages content warnings, blurring, and reporting flows.
|
||||
|
||||
## Usage Example
|
||||
|
||||
```javascript
|
||||
// Instantiation (usually in ModalManager)
|
||||
const videoModal = new VideoModal({
|
||||
document: document,
|
||||
setGlobalModalState: (key, active) => app.setModalState(key, active),
|
||||
logger: logger,
|
||||
mediaLoader: mediaLoader
|
||||
});
|
||||
|
||||
// Initialization (lazy)
|
||||
await videoModal.load();
|
||||
|
||||
// Opening
|
||||
const video = {
|
||||
id: "...",
|
||||
title: "My Video",
|
||||
pubkey: "...",
|
||||
// ... other metadata
|
||||
};
|
||||
videoModal.open(video, { triggerElement: clickedCard });
|
||||
```
|
||||
|
||||
## Key Invariants
|
||||
|
||||
1. **Single Active Instance**: Only one video modal exists in the DOM at a time. Opening a new video replaces the content of the existing modal.
|
||||
2. **Focus Management**: When open, the modal traps focus. When closed, it restores focus to the element that triggered it (via `options.triggerElement`).
|
||||
3. **State Synchronization**: The `setGlobalModalState` callback MUST be called on open/close to ensure the back button works correctly and background videos pause.
|
||||
|
||||
## When to Change
|
||||
|
||||
- **Refactoring**: This file is extremely large (>6000 LOC). Consider extracting more logic into sub-controllers (e.g., a `MetadataController` for title/description/tags).
|
||||
- **Styling**: Changes to the modal layout should be mirrored in `components/video-modal.html` and tested for responsiveness.
|
||||
- **Playback Logic**: Changes to how videos load or play should likely be done in `mediaLoader` or `PlaybackService` rather than here, unless it's strictly UI-related (e.g., custom controls).
|
||||
@@ -0,0 +1,8 @@
|
||||
# Agent Task Log Entry
|
||||
|
||||
- **Date:** 2026-02-13
|
||||
- **Agent:** docs-code-investigator
|
||||
- **Prompt:** bitvid-docs-code-investigator.md
|
||||
- **Status:** completed
|
||||
- **Branch:** ai/doc-video-modal-20260213
|
||||
- **Summary:** Documented `js/ui/components/VideoModal.js` with JSDoc and `docs/VideoModal-overview.md`.
|
||||
@@ -0,0 +1,8 @@
|
||||
# Agent Task Log Entry
|
||||
|
||||
- **Date:** 2026-02-13
|
||||
- **Agent:** docs-code-investigator
|
||||
- **Prompt:** bitvid-docs-code-investigator.md
|
||||
- **Status:** started
|
||||
- **Branch:** ai/doc-video-modal-20260213
|
||||
- **Summary:** Task claimed — execution beginning
|
||||
@@ -52,7 +52,29 @@ import { UI_FEEDBACK_DELAY_MS } from "../../constants.js";
|
||||
|
||||
const SIMILAR_CONTENT_LIMIT = 10;
|
||||
|
||||
/**
|
||||
* Main UI controller for the full-screen video playback modal.
|
||||
* Manages the modal lifecycle (load, open, close), orchestrates playback,
|
||||
* and coordinates sub-controllers for comments, reactions, and moderation.
|
||||
*
|
||||
* @see {@link docs/VideoModal-overview.md} for architectural details.
|
||||
*/
|
||||
export class VideoModal {
|
||||
/**
|
||||
* Initializes the video modal controller.
|
||||
* Note: Does not touch the DOM or load HTML until `load()` is called.
|
||||
*
|
||||
* @param {Object} options - Configuration options
|
||||
* @param {Function} [options.removeTrackingScripts] - Helper to sanitize HTML
|
||||
* @param {Function} options.setGlobalModalState - Callback to update app-wide modal state
|
||||
* @param {Document} options.document - The document instance (for DOM access)
|
||||
* @param {Object} [options.logger] - Logger instance (defaults to devLogger)
|
||||
* @param {Object} [options.mediaLoader] - Service for media resolution
|
||||
* @param {Object} [options.assets] - Asset configuration (e.g., fallback thumbnails)
|
||||
* @param {Object} [options.state] - Initial state (e.g., thumbnail cache)
|
||||
* @param {Object} [options.helpers] - Utility helpers (e.g., npub encoding)
|
||||
* @throws {Error} If document or setGlobalModalState is missing
|
||||
*/
|
||||
constructor({
|
||||
removeTrackingScripts,
|
||||
setGlobalModalState,
|
||||
@@ -475,6 +497,13 @@ export class VideoModal {
|
||||
return this.modalVideo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lazy-loads the video modal HTML and injects it into the DOM.
|
||||
* Ensures idempotency: if already loaded and connected, returns immediately.
|
||||
*
|
||||
* @returns {Promise<HTMLElement>} The root element of the video modal
|
||||
* @throws {Error} If fetching the template fails or container is missing
|
||||
*/
|
||||
async load() {
|
||||
if (this.loaded) {
|
||||
const root = this.playerModal;
|
||||
@@ -546,12 +575,20 @@ export class VideoModal {
|
||||
return this.playerModal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds the controller to the DOM elements within the modal.
|
||||
* Initializes sub-controllers and sets up event listeners.
|
||||
*
|
||||
* @param {HTMLElement} playerModal - The root modal element
|
||||
*/
|
||||
hydrate(playerModal) {
|
||||
// 1. Cleanup existing accessibility traps and sub-controllers
|
||||
if (this.modalAccessibility?.destroy) {
|
||||
this.modalAccessibility.destroy();
|
||||
}
|
||||
this.modalAccessibility = null;
|
||||
|
||||
// 2. Cleanup existing popovers (Zap, More Menu)
|
||||
if (this.modalZapPopover?.destroy) {
|
||||
this.modalZapPopover.destroy();
|
||||
}
|
||||
@@ -3021,6 +3058,14 @@ export class VideoModal {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the modal state, populates it with the provided video data, and makes it visible.
|
||||
* Also initializes moderation, comments, and accessibility traps.
|
||||
*
|
||||
* @param {Object} video - The video object to display (title, description, tags, etc.)
|
||||
* @param {Object} [options] - Display options
|
||||
* @param {HTMLElement} [options.triggerElement] - The element that triggered the modal (for focus restoration)
|
||||
*/
|
||||
open(video, options = {}) {
|
||||
this.activeVideo = video || null;
|
||||
this.moderationBadgeId = "";
|
||||
@@ -3069,6 +3114,10 @@ export class VideoModal {
|
||||
this.refreshActiveVideoModeration({ video: this.activeVideo });
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the modal, pauses playback, clears active state, and restores focus.
|
||||
* This is the primary cleanup method when dismissing the modal.
|
||||
*/
|
||||
close() {
|
||||
this.activeVideo = null;
|
||||
this.applyModerationOverlay(null);
|
||||
|
||||
Reference in new issue
Block a user