@editframe/elements 0.30.1-beta.0 → 0.31.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/EF_FRAMEGEN.d.ts +5 -0
- package/dist/EF_FRAMEGEN.js +20 -4
- package/dist/EF_FRAMEGEN.js.map +1 -1
- package/dist/EF_INTERACTIVE.js.map +1 -1
- package/dist/_virtual/rolldown_runtime.js +27 -0
- package/dist/canvas/EFCanvas.d.ts +311 -0
- package/dist/canvas/EFCanvas.js +1089 -0
- package/dist/canvas/EFCanvas.js.map +1 -0
- package/dist/canvas/EFCanvasItem.d.ts +55 -0
- package/dist/canvas/EFCanvasItem.js +72 -0
- package/dist/canvas/EFCanvasItem.js.map +1 -0
- package/dist/canvas/api/CanvasAPI.d.ts +115 -0
- package/dist/canvas/api/CanvasAPI.js +182 -0
- package/dist/canvas/api/CanvasAPI.js.map +1 -0
- package/dist/canvas/api/types.d.ts +42 -0
- package/dist/canvas/coordinateTransform.js +90 -0
- package/dist/canvas/coordinateTransform.js.map +1 -0
- package/dist/canvas/getElementBounds.js +40 -0
- package/dist/canvas/getElementBounds.js.map +1 -0
- package/dist/canvas/overlays/SelectionOverlay.js +265 -0
- package/dist/canvas/overlays/SelectionOverlay.js.map +1 -0
- package/dist/canvas/overlays/overlayState.js +153 -0
- package/dist/canvas/overlays/overlayState.js.map +1 -0
- package/dist/canvas/selection/SelectionController.js +105 -0
- package/dist/canvas/selection/SelectionController.js.map +1 -0
- package/dist/canvas/selection/SelectionModel.d.ts +98 -0
- package/dist/canvas/selection/SelectionModel.js +229 -0
- package/dist/canvas/selection/SelectionModel.js.map +1 -0
- package/dist/canvas/selection/selectionContext.d.ts +31 -0
- package/dist/canvas/selection/selectionContext.js +12 -0
- package/dist/canvas/selection/selectionContext.js.map +1 -0
- package/dist/elements/ContainerInfo.d.ts +29 -0
- package/dist/elements/ContainerInfo.js +30 -0
- package/dist/elements/ContainerInfo.js.map +1 -0
- package/dist/elements/EFAudio.d.ts +13 -3
- package/dist/elements/EFAudio.js +64 -10
- package/dist/elements/EFAudio.js.map +1 -1
- package/dist/elements/EFCaptions.d.ts +18 -16
- package/dist/elements/EFCaptions.js +110 -19
- package/dist/elements/EFCaptions.js.map +1 -1
- package/dist/elements/EFImage.d.ts +16 -6
- package/dist/elements/EFImage.js +79 -9
- package/dist/elements/EFImage.js.map +1 -1
- package/dist/elements/EFMedia/AssetIdMediaEngine.js +51 -4
- package/dist/elements/EFMedia/AssetIdMediaEngine.js.map +1 -1
- package/dist/elements/EFMedia/AssetMediaEngine.js +125 -52
- package/dist/elements/EFMedia/AssetMediaEngine.js.map +1 -1
- package/dist/elements/EFMedia/BaseMediaEngine.js +24 -6
- package/dist/elements/EFMedia/BaseMediaEngine.js.map +1 -1
- package/dist/elements/EFMedia/JitMediaEngine.js +12 -8
- package/dist/elements/EFMedia/JitMediaEngine.js.map +1 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.js +46 -7
- package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.js.map +1 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.js +98 -73
- package/dist/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.js.map +1 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.js +28 -5
- package/dist/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.js.map +1 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioInputTask.js +18 -6
- package/dist/elements/EFMedia/audioTasks/makeAudioInputTask.js.map +1 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioSeekTask.js +8 -2
- package/dist/elements/EFMedia/audioTasks/makeAudioSeekTask.js.map +1 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.js +31 -6
- package/dist/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.js.map +1 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.js +28 -5
- package/dist/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.js.map +1 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.js +97 -72
- package/dist/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.js.map +1 -1
- package/dist/elements/EFMedia/shared/AudioSpanUtils.js +3 -1
- package/dist/elements/EFMedia/shared/AudioSpanUtils.js.map +1 -1
- package/dist/elements/EFMedia/shared/BufferUtils.js +1 -1
- package/dist/elements/EFMedia/shared/BufferUtils.js.map +1 -1
- package/dist/elements/EFMedia/shared/ThumbnailExtractor.js +25 -14
- package/dist/elements/EFMedia/shared/ThumbnailExtractor.js.map +1 -1
- package/dist/elements/EFMedia/tasks/makeMediaEngineTask.js +47 -16
- package/dist/elements/EFMedia/tasks/makeMediaEngineTask.js.map +1 -1
- package/dist/elements/EFMedia/videoTasks/MainVideoInputCache.js +37 -19
- package/dist/elements/EFMedia/videoTasks/MainVideoInputCache.js.map +1 -1
- package/dist/elements/EFMedia/videoTasks/ScrubInputCache.js +65 -21
- package/dist/elements/EFMedia/videoTasks/ScrubInputCache.js.map +1 -1
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoBufferTask.js +8 -3
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoBufferTask.js.map +1 -1
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoInitSegmentFetchTask.js +32 -9
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoInitSegmentFetchTask.js.map +1 -1
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoInputTask.js +33 -10
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoInputTask.js.map +1 -1
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoSeekTask.js +23 -8
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoSeekTask.js.map +1 -1
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoSegmentFetchTask.js +34 -10
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoSegmentFetchTask.js.map +1 -1
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoSegmentIdTask.js +31 -8
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoSegmentIdTask.js.map +1 -1
- package/dist/elements/EFMedia/videoTasks/makeUnifiedVideoSeekTask.js +31 -114
- package/dist/elements/EFMedia/videoTasks/makeUnifiedVideoSeekTask.js.map +1 -1
- package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.js +44 -8
- package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.js.map +1 -1
- package/dist/elements/EFMedia.d.ts +18 -7
- package/dist/elements/EFMedia.js +23 -3
- package/dist/elements/EFMedia.js.map +1 -1
- package/dist/elements/EFPanZoom.d.ts +96 -0
- package/dist/elements/EFPanZoom.js +290 -0
- package/dist/elements/EFPanZoom.js.map +1 -0
- package/dist/elements/EFSourceMixin.js +7 -6
- package/dist/elements/EFSourceMixin.js.map +1 -1
- package/dist/elements/EFSurface.d.ts +6 -6
- package/dist/elements/EFSurface.js +7 -2
- package/dist/elements/EFSurface.js.map +1 -1
- package/dist/elements/EFTemporal.d.ts +2 -1
- package/dist/elements/EFTemporal.js +192 -71
- package/dist/elements/EFTemporal.js.map +1 -1
- package/dist/elements/EFText.d.ts +5 -4
- package/dist/elements/EFText.js +102 -13
- package/dist/elements/EFText.js.map +1 -1
- package/dist/elements/EFTextSegment.d.ts +32 -6
- package/dist/elements/EFTextSegment.js +53 -15
- package/dist/elements/EFTextSegment.js.map +1 -1
- package/dist/elements/EFThumbnailStrip.d.ts +118 -56
- package/dist/elements/EFThumbnailStrip.js +522 -358
- package/dist/elements/EFThumbnailStrip.js.map +1 -1
- package/dist/elements/EFTimegroup.d.ts +223 -27
- package/dist/elements/EFTimegroup.js +851 -148
- package/dist/elements/EFTimegroup.js.map +1 -1
- package/dist/elements/EFVideo.d.ts +42 -5
- package/dist/elements/EFVideo.js +165 -11
- package/dist/elements/EFVideo.js.map +1 -1
- package/dist/elements/EFWaveform.d.ts +6 -6
- package/dist/elements/EFWaveform.js +2 -1
- package/dist/elements/EFWaveform.js.map +1 -1
- package/dist/elements/ElementPositionInfo.d.ts +35 -0
- package/dist/elements/ElementPositionInfo.js +49 -0
- package/dist/elements/ElementPositionInfo.js.map +1 -0
- package/dist/elements/FetchMixin.js +16 -1
- package/dist/elements/FetchMixin.js.map +1 -1
- package/dist/elements/SessionThumbnailCache.js +152 -0
- package/dist/elements/SessionThumbnailCache.js.map +1 -0
- package/dist/elements/TargetController.js +3 -1
- package/dist/elements/TargetController.js.map +1 -1
- package/dist/elements/TimegroupController.js +9 -3
- package/dist/elements/TimegroupController.js.map +1 -1
- package/dist/elements/findRootTemporal.js +30 -0
- package/dist/elements/findRootTemporal.js.map +1 -0
- package/dist/elements/renderTemporalAudio.js +18 -5
- package/dist/elements/renderTemporalAudio.js.map +1 -1
- package/dist/elements/updateAnimations.js +492 -109
- package/dist/elements/updateAnimations.js.map +1 -1
- package/dist/getRenderInfo.d.ts +2 -2
- package/dist/gui/ContextMixin.js +4 -2
- package/dist/gui/ContextMixin.js.map +1 -1
- package/dist/gui/Controllable.js +74 -1
- package/dist/gui/Controllable.js.map +1 -1
- package/dist/gui/EFActiveRootTemporal.d.ts +50 -0
- package/dist/gui/EFActiveRootTemporal.js +94 -0
- package/dist/gui/EFActiveRootTemporal.js.map +1 -0
- package/dist/gui/EFConfiguration.d.ts +11 -5
- package/dist/gui/EFConfiguration.js.map +1 -1
- package/dist/gui/EFControls.d.ts +2 -2
- package/dist/gui/EFControls.js +109 -13
- package/dist/gui/EFControls.js.map +1 -1
- package/dist/gui/EFDial.d.ts +4 -4
- package/dist/gui/EFFilmstrip.d.ts +11 -214
- package/dist/gui/EFFilmstrip.js +53 -1152
- package/dist/gui/EFFilmstrip.js.map +1 -1
- package/dist/gui/EFFitScale.d.ts +3 -3
- package/dist/gui/EFFitScale.js +39 -12
- package/dist/gui/EFFitScale.js.map +1 -1
- package/dist/gui/EFFocusOverlay.d.ts +4 -4
- package/dist/gui/EFOverlayItem.d.ts +48 -0
- package/dist/gui/EFOverlayItem.js +97 -0
- package/dist/gui/EFOverlayItem.js.map +1 -0
- package/dist/gui/EFOverlayLayer.d.ts +70 -0
- package/dist/gui/EFOverlayLayer.js +104 -0
- package/dist/gui/EFOverlayLayer.js.map +1 -0
- package/dist/gui/EFPause.d.ts +4 -4
- package/dist/gui/EFPlay.d.ts +4 -4
- package/dist/gui/EFPreview.d.ts +4 -4
- package/dist/gui/EFResizableBox.d.ts +12 -16
- package/dist/gui/EFResizableBox.js +109 -451
- package/dist/gui/EFResizableBox.js.map +1 -1
- package/dist/gui/EFScrubber.d.ts +30 -5
- package/dist/gui/EFScrubber.js +224 -31
- package/dist/gui/EFScrubber.js.map +1 -1
- package/dist/gui/EFTimeDisplay.d.ts +4 -4
- package/dist/gui/EFTimeDisplay.js +4 -1
- package/dist/gui/EFTimeDisplay.js.map +1 -1
- package/dist/gui/EFTimelineRuler.d.ts +71 -0
- package/dist/gui/EFTimelineRuler.js +320 -0
- package/dist/gui/EFTimelineRuler.js.map +1 -0
- package/dist/gui/EFToggleLoop.d.ts +4 -4
- package/dist/gui/EFTogglePlay.d.ts +4 -4
- package/dist/gui/EFTransformHandles.d.ts +91 -0
- package/dist/gui/EFTransformHandles.js +393 -0
- package/dist/gui/EFTransformHandles.js.map +1 -0
- package/dist/gui/EFWorkbench.d.ts +182 -4
- package/dist/gui/EFWorkbench.js +2067 -22
- package/dist/gui/EFWorkbench.js.map +1 -1
- package/dist/gui/FitScaleHelpers.d.ts +31 -0
- package/dist/gui/FitScaleHelpers.js +41 -0
- package/dist/gui/FitScaleHelpers.js.map +1 -0
- package/dist/gui/PlaybackController.d.ts +2 -1
- package/dist/gui/PlaybackController.js +46 -15
- package/dist/gui/PlaybackController.js.map +1 -1
- package/dist/gui/TWMixin.js +1 -1
- package/dist/gui/TWMixin.js.map +1 -1
- package/dist/gui/hierarchy/EFHierarchy.d.ts +65 -0
- package/dist/gui/hierarchy/EFHierarchy.js +338 -0
- package/dist/gui/hierarchy/EFHierarchy.js.map +1 -0
- package/dist/gui/hierarchy/EFHierarchyItem.d.ts +118 -0
- package/dist/gui/hierarchy/EFHierarchyItem.js +551 -0
- package/dist/gui/hierarchy/EFHierarchyItem.js.map +1 -0
- package/dist/gui/hierarchy/hierarchyContext.d.ts +38 -0
- package/dist/gui/hierarchy/hierarchyContext.js +8 -0
- package/dist/gui/hierarchy/hierarchyContext.js.map +1 -0
- package/dist/gui/icons.js +34 -0
- package/dist/gui/icons.js.map +1 -0
- package/dist/gui/panZoomTransformContext.js +12 -0
- package/dist/gui/panZoomTransformContext.js.map +1 -0
- package/dist/gui/previewSettingsContext.js +12 -0
- package/dist/gui/previewSettingsContext.js.map +1 -0
- package/dist/gui/timeline/EFTimeline.d.ts +270 -0
- package/dist/gui/timeline/EFTimeline.js +1369 -0
- package/dist/gui/timeline/EFTimeline.js.map +1 -0
- package/dist/gui/timeline/EFTimelineRow.js +374 -0
- package/dist/gui/timeline/EFTimelineRow.js.map +1 -0
- package/dist/gui/timeline/TrimHandles.d.ts +36 -0
- package/dist/gui/timeline/TrimHandles.js +204 -0
- package/dist/gui/timeline/TrimHandles.js.map +1 -0
- package/dist/gui/timeline/flattenHierarchy.js +31 -0
- package/dist/gui/timeline/flattenHierarchy.js.map +1 -0
- package/dist/gui/timeline/timelineStateContext.d.ts +26 -0
- package/dist/gui/timeline/timelineStateContext.js +42 -0
- package/dist/gui/timeline/timelineStateContext.js.map +1 -0
- package/dist/gui/timeline/tracks/AudioTrack.js +264 -0
- package/dist/gui/timeline/tracks/AudioTrack.js.map +1 -0
- package/dist/gui/timeline/tracks/CaptionsTrack.js +595 -0
- package/dist/gui/timeline/tracks/CaptionsTrack.js.map +1 -0
- package/dist/gui/timeline/tracks/HTMLTrack.js +19 -0
- package/dist/gui/timeline/tracks/HTMLTrack.js.map +1 -0
- package/dist/gui/timeline/tracks/ImageTrack.js +53 -0
- package/dist/gui/timeline/tracks/ImageTrack.js.map +1 -0
- package/dist/gui/timeline/tracks/TextTrack.js +250 -0
- package/dist/gui/timeline/tracks/TextTrack.js.map +1 -0
- package/dist/gui/timeline/tracks/TimegroupTrack.js +143 -0
- package/dist/gui/timeline/tracks/TimegroupTrack.js.map +1 -0
- package/dist/gui/timeline/tracks/TrackItem.js +269 -0
- package/dist/gui/timeline/tracks/TrackItem.js.map +1 -0
- package/dist/gui/timeline/tracks/VideoTrack.js +265 -0
- package/dist/gui/timeline/tracks/VideoTrack.js.map +1 -0
- package/dist/gui/timeline/tracks/WaveformTrack.js +19 -0
- package/dist/gui/timeline/tracks/WaveformTrack.js.map +1 -0
- package/dist/gui/timeline/tracks/ensureTrackItemInit.js +1 -0
- package/dist/gui/timeline/tracks/preloadTracks.js +9 -0
- package/dist/gui/timeline/tracks/renderTrackChildren.js +119 -0
- package/dist/gui/timeline/tracks/renderTrackChildren.js.map +1 -0
- package/dist/gui/timeline/tracks/waveformUtils.js +80 -0
- package/dist/gui/timeline/tracks/waveformUtils.js.map +1 -0
- package/dist/gui/transformCalculations.js +217 -0
- package/dist/gui/transformCalculations.js.map +1 -0
- package/dist/gui/transformUtils.d.ts +37 -0
- package/dist/gui/transformUtils.js +77 -0
- package/dist/gui/transformUtils.js.map +1 -0
- package/dist/gui/tree/EFTree.d.ts +59 -0
- package/dist/gui/tree/EFTree.js +174 -0
- package/dist/gui/tree/EFTree.js.map +1 -0
- package/dist/gui/tree/EFTreeItem.d.ts +38 -0
- package/dist/gui/tree/EFTreeItem.js +146 -0
- package/dist/gui/tree/EFTreeItem.js.map +1 -0
- package/dist/gui/tree/treeContext.d.ts +60 -0
- package/dist/gui/tree/treeContext.js +23 -0
- package/dist/gui/tree/treeContext.js.map +1 -0
- package/dist/index.d.ts +32 -8
- package/dist/index.js +30 -6
- package/dist/index.js.map +1 -1
- package/dist/node_modules/react/cjs/react-jsx-runtime.development.js +688 -0
- package/dist/node_modules/react/cjs/react-jsx-runtime.development.js.map +1 -0
- package/dist/node_modules/react/cjs/react.development.js +1521 -0
- package/dist/node_modules/react/cjs/react.development.js.map +1 -0
- package/dist/node_modules/react/index.js +13 -0
- package/dist/node_modules/react/index.js.map +1 -0
- package/dist/node_modules/react/jsx-runtime.js +13 -0
- package/dist/node_modules/react/jsx-runtime.js.map +1 -0
- package/dist/preview/AdaptiveResolutionTracker.js +228 -0
- package/dist/preview/AdaptiveResolutionTracker.js.map +1 -0
- package/dist/preview/RenderProfiler.js +135 -0
- package/dist/preview/RenderProfiler.js.map +1 -0
- package/dist/preview/previewSettings.js +131 -0
- package/dist/preview/previewSettings.js.map +1 -0
- package/dist/preview/previewTypes.js +64 -0
- package/dist/preview/previewTypes.js.map +1 -0
- package/dist/preview/renderTimegroupPreview.js +656 -0
- package/dist/preview/renderTimegroupPreview.js.map +1 -0
- package/dist/preview/renderTimegroupToCanvas.d.ts +37 -0
- package/dist/preview/renderTimegroupToCanvas.js +840 -0
- package/dist/preview/renderTimegroupToCanvas.js.map +1 -0
- package/dist/preview/renderTimegroupToVideo.d.ts +39 -0
- package/dist/preview/renderTimegroupToVideo.js +274 -0
- package/dist/preview/renderTimegroupToVideo.js.map +1 -0
- package/dist/preview/renderers.js +16 -0
- package/dist/preview/renderers.js.map +1 -0
- package/dist/preview/statsTrackingStrategy.js +201 -0
- package/dist/preview/statsTrackingStrategy.js.map +1 -0
- package/dist/preview/thumbnailCacheSettings.js +52 -0
- package/dist/preview/thumbnailCacheSettings.js.map +1 -0
- package/dist/preview/workers/WorkerPool.js +178 -0
- package/dist/preview/workers/WorkerPool.js.map +1 -0
- package/dist/sandbox/PlaybackControls.js +10 -0
- package/dist/sandbox/PlaybackControls.js.map +1 -0
- package/dist/sandbox/ScenarioRunner.js +1 -0
- package/dist/sandbox/index.js +2 -0
- package/dist/style.css +66 -69
- package/dist/transcoding/types/index.d.ts +2 -1
- package/dist/transcoding/utils/UrlGenerator.d.ts +6 -1
- package/dist/transcoding/utils/UrlGenerator.js +12 -3
- package/dist/transcoding/utils/UrlGenerator.js.map +1 -1
- package/dist/utils/LRUCache.js +1 -375
- package/dist/utils/LRUCache.js.map +1 -1
- package/dist/utils/frameTime.js +14 -0
- package/dist/utils/frameTime.js.map +1 -0
- package/package.json +3 -3
- package/test/profilingPlugin.ts +223 -0
- package/test/recordReplayProxyPlugin.js +22 -27
- package/test/thumbnail-performance-test.html +116 -0
- package/test/visualRegressionUtils.ts +286 -0
- package/types.json +1 -1
- package/dist/elements/TimegroupController.d.ts +0 -18
- package/dist/msToTimeCode.js +0 -17
- package/dist/msToTimeCode.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SelectionModel.js","names":[],"sources":["../../../src/canvas/selection/SelectionModel.ts"],"sourcesContent":["import type { SelectionState } from \"../api/types.js\";\n\n/**\n * Create a DOMRect-like object. Polyfill for Node.js environments.\n */\nfunction createRect(\n x: number,\n y: number,\n width: number,\n height: number,\n): DOMRect {\n if (typeof DOMRect !== \"undefined\") {\n return new DOMRect(x, y, width, height);\n }\n // Polyfill for Node.js\n return {\n x,\n y,\n width,\n height,\n left: x,\n top: y,\n right: x + width,\n bottom: y + height,\n toJSON: () => ({ x, y, width, height }),\n } as DOMRect;\n}\n\n/**\n * Pure selection logic - semantics separate from mechanism.\n * Manages selection state and operations.\n */\nexport class SelectionModel extends EventTarget {\n private _selectedIds = new Set<string>();\n private _primaryId: string | null = null;\n private _selectionMode: SelectionState = \"none\";\n private _boxSelectStart: { x: number; y: number } | null = null;\n private _boxSelectCurrent: { x: number; y: number } | null = null;\n private _groups = new Map<string, Set<string>>();\n private _elementToGroup = new Map<string, string>();\n\n /**\n * Emit selectionchange event with current selection state.\n */\n private _emitSelectionChange(): void {\n // Convert Set to array with primary first\n const selectedIdsArray =\n this._primaryId && this._selectedIds.has(this._primaryId)\n ? [\n this._primaryId,\n ...Array.from(this._selectedIds).filter(\n (id) => id !== this._primaryId,\n ),\n ]\n : Array.from(this._selectedIds);\n\n this.dispatchEvent(\n new CustomEvent(\"selectionchange\", {\n detail: {\n selectedIds: selectedIdsArray,\n selectionMode: this._selectionMode,\n },\n bubbles: false,\n composed: false,\n }),\n );\n }\n\n /**\n * Get current selection state.\n */\n get selectedIds(): ReadonlySet<string> {\n return this._selectedIds;\n }\n\n /**\n * Get current selection mode.\n */\n get selectionMode(): SelectionState {\n return this._selectionMode;\n }\n\n /**\n * Get current box selection bounds, if active.\n */\n get boxSelectBounds(): DOMRect | null {\n if (!this._boxSelectStart || !this._boxSelectCurrent) {\n return null;\n }\n const left = Math.min(this._boxSelectStart.x, this._boxSelectCurrent.x);\n const top = Math.min(this._boxSelectStart.y, this._boxSelectCurrent.y);\n const right = Math.max(this._boxSelectStart.x, this._boxSelectCurrent.x);\n const bottom = Math.max(this._boxSelectStart.y, this._boxSelectCurrent.y);\n return createRect(left, top, right - left, bottom - top);\n }\n\n /**\n * Select a single element.\n */\n select(id: string): void {\n this._selectedIds.clear();\n this._selectedIds.add(id);\n this._primaryId = id;\n this._selectionMode = \"single\";\n this._emitSelectionChange();\n }\n\n /**\n * Select multiple elements.\n */\n selectMultiple(ids: string[]): void {\n this._selectedIds.clear();\n for (const id of ids) {\n this._selectedIds.add(id);\n }\n this._primaryId = ids.length > 0 ? (ids[0] ?? null) : null;\n this._selectionMode =\n ids.length === 0 ? \"none\" : ids.length === 1 ? \"single\" : \"multiple\";\n this._emitSelectionChange();\n }\n\n /**\n * Add element to selection (for multi-select).\n */\n addToSelection(id: string): void {\n this._selectedIds.add(id);\n if (!this._primaryId) {\n this._primaryId = id;\n }\n this._updateSelectionMode();\n this._emitSelectionChange();\n }\n\n /**\n * Remove element from selection.\n */\n deselect(id: string): void {\n this._selectedIds.delete(id);\n if (this._primaryId === id) {\n // Set primary to first remaining, or null if none\n const remaining = Array.from(this._selectedIds);\n this._primaryId = remaining.length > 0 ? (remaining[0] ?? null) : null;\n }\n this._updateSelectionMode();\n this._emitSelectionChange();\n }\n\n /**\n * Toggle element selection state.\n */\n toggle(id: string): void {\n if (this._selectedIds.has(id)) {\n this.deselect(id);\n } else {\n this.addToSelection(id);\n }\n }\n\n /**\n * Clear all selections.\n */\n clear(): void {\n this._selectedIds.clear();\n this._primaryId = null;\n this._selectionMode = \"none\";\n this._boxSelectStart = null;\n this._boxSelectCurrent = null;\n this._emitSelectionChange();\n }\n\n /**\n * Start box selection.\n */\n startBoxSelect(x: number, y: number): void {\n this._boxSelectStart = { x, y };\n this._boxSelectCurrent = { x, y };\n this._selectionMode = \"box-selecting\";\n }\n\n /**\n * Update box selection.\n */\n updateBoxSelect(x: number, y: number): void {\n if (this._selectionMode !== \"box-selecting\") {\n return;\n }\n this._boxSelectCurrent = { x, y };\n }\n\n /**\n * End box selection and select elements within bounds.\n * @param hitTest - Function to find elements within bounds\n * @param addToSelection - If true, add to existing selection; if false, replace selection\n */\n endBoxSelect(\n hitTest: (bounds: DOMRect) => string[],\n addToSelection = false,\n ): void {\n if (\n this._selectionMode !== \"box-selecting\" ||\n !this._boxSelectStart ||\n !this._boxSelectCurrent\n ) {\n return;\n }\n const bounds = this.boxSelectBounds;\n if (bounds) {\n const ids = hitTest(bounds);\n if (addToSelection) {\n // Add each element to selection\n for (const id of ids) {\n this.addToSelection(id);\n }\n } else {\n // Replace selection\n this.selectMultiple(ids);\n }\n }\n this._boxSelectStart = null;\n this._boxSelectCurrent = null;\n // Note: selectMultiple/addToSelection already emit events, so no need to emit again\n }\n\n /**\n * Create a group from selected elements.\n */\n createGroup(ids: string[]): string {\n if (ids.length === 0) {\n throw new Error(\"Cannot create group with no elements\");\n }\n const groupId = `group-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;\n const groupSet = new Set(ids);\n this._groups.set(groupId, groupSet);\n for (const id of ids) {\n this._elementToGroup.set(id, groupId);\n }\n return groupId;\n }\n\n /**\n * Ungroup a group.\n */\n ungroup(groupId: string): void {\n const group = this._groups.get(groupId);\n if (!group) {\n return;\n }\n for (const id of group) {\n this._elementToGroup.delete(id);\n }\n this._groups.delete(groupId);\n }\n\n /**\n * Select all elements in a group.\n */\n selectGroup(groupId: string): void {\n const group = this._groups.get(groupId);\n if (!group) {\n return;\n }\n this.selectMultiple(Array.from(group));\n // Note: selectMultiple already emits event\n }\n\n /**\n * Get group ID for an element, if any.\n */\n getGroupId(elementId: string): string | undefined {\n return this._elementToGroup.get(elementId);\n }\n\n /**\n * Get all element IDs in a group.\n */\n getGroupElements(groupId: string): string[] {\n const group = this._groups.get(groupId);\n return group ? Array.from(group) : [];\n }\n\n /**\n * Update selection mode based on current selection count.\n */\n private _updateSelectionMode(): void {\n const count = this._selectedIds.size;\n if (count === 0) {\n this._selectionMode = \"none\";\n } else if (count === 1) {\n this._selectionMode = \"single\";\n } else {\n this._selectionMode = \"multiple\";\n }\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { SelectionState } from "../api/types.js";
|
|
2
|
+
|
|
3
|
+
//#region src/canvas/selection/selectionContext.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Selection context interface for Lit context.
|
|
7
|
+
*/
|
|
8
|
+
interface SelectionContext {
|
|
9
|
+
selectedIds: ReadonlySet<string>;
|
|
10
|
+
selectionMode: SelectionState;
|
|
11
|
+
boxSelectBounds: DOMRect | null;
|
|
12
|
+
select: (id: string) => void;
|
|
13
|
+
selectMultiple: (ids: string[]) => void;
|
|
14
|
+
addToSelection: (id: string) => void;
|
|
15
|
+
deselect: (id: string) => void;
|
|
16
|
+
toggle: (id: string) => void;
|
|
17
|
+
clear: () => void;
|
|
18
|
+
startBoxSelect: (x: number, y: number) => void;
|
|
19
|
+
updateBoxSelect: (x: number, y: number) => void;
|
|
20
|
+
endBoxSelect: (hitTest: (bounds: DOMRect) => string[], addToSelection?: boolean) => void;
|
|
21
|
+
createGroup: (ids: string[]) => string;
|
|
22
|
+
ungroup: (groupId: string) => void;
|
|
23
|
+
selectGroup: (groupId: string) => void;
|
|
24
|
+
getGroupId: (elementId: string) => string | undefined;
|
|
25
|
+
getGroupElements: (groupId: string) => string[];
|
|
26
|
+
addEventListener: (type: "selectionchange", listener: (event: CustomEvent) => void) => void;
|
|
27
|
+
removeEventListener: (type: "selectionchange", listener: (event: CustomEvent) => void) => void;
|
|
28
|
+
}
|
|
29
|
+
//#endregion
|
|
30
|
+
export { SelectionContext };
|
|
31
|
+
//# sourceMappingURL=selectionContext.d.ts.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { createContext } from "@lit/context";
|
|
2
|
+
|
|
3
|
+
//#region src/canvas/selection/selectionContext.ts
|
|
4
|
+
/**
|
|
5
|
+
* Lit context for selection state.
|
|
6
|
+
* Provided by EFCanvas, consumed by child elements.
|
|
7
|
+
*/
|
|
8
|
+
const selectionContext = createContext(Symbol("selectionContext"));
|
|
9
|
+
|
|
10
|
+
//#endregion
|
|
11
|
+
export { selectionContext };
|
|
12
|
+
//# sourceMappingURL=selectionContext.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selectionContext.js","names":[],"sources":["../../../src/canvas/selection/selectionContext.ts"],"sourcesContent":["import { createContext } from \"@lit/context\";\nimport type { SelectionState } from \"../api/types.js\";\n\n/**\n * Selection context interface for Lit context.\n */\nexport interface SelectionContext {\n selectedIds: ReadonlySet<string>;\n selectionMode: SelectionState;\n boxSelectBounds: DOMRect | null;\n select: (id: string) => void;\n selectMultiple: (ids: string[]) => void;\n addToSelection: (id: string) => void;\n deselect: (id: string) => void;\n toggle: (id: string) => void;\n clear: () => void;\n startBoxSelect: (x: number, y: number) => void;\n updateBoxSelect: (x: number, y: number) => void;\n endBoxSelect: (\n hitTest: (bounds: DOMRect) => string[],\n addToSelection?: boolean,\n ) => void;\n createGroup: (ids: string[]) => string;\n ungroup: (groupId: string) => void;\n selectGroup: (groupId: string) => void;\n getGroupId: (elementId: string) => string | undefined;\n getGroupElements: (groupId: string) => string[];\n addEventListener: (\n type: \"selectionchange\",\n listener: (event: CustomEvent) => void,\n ) => void;\n removeEventListener: (\n type: \"selectionchange\",\n listener: (event: CustomEvent) => void,\n ) => void;\n}\n\n/**\n * Lit context for selection state.\n * Provided by EFCanvas, consumed by child elements.\n */\nexport const selectionContext = createContext<SelectionContext>(\n Symbol(\"selectionContext\"),\n);\n"],"mappings":";;;;;;;AAyCA,MAAa,mBAAmB,cAC9B,OAAO,mBAAmB,CAC3B"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
//#region src/elements/ContainerInfo.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Container information interface for elements that can contain children.
|
|
4
|
+
* Provides information about container capabilities and display mode.
|
|
5
|
+
*/
|
|
6
|
+
interface ContainerInfo {
|
|
7
|
+
/**
|
|
8
|
+
* Whether this element is a container that can contain children.
|
|
9
|
+
*/
|
|
10
|
+
isContainer: boolean;
|
|
11
|
+
/**
|
|
12
|
+
* The display mode of the container.
|
|
13
|
+
* "flex" | "grid" | "block" | null
|
|
14
|
+
*/
|
|
15
|
+
displayMode: "flex" | "grid" | "block" | null;
|
|
16
|
+
/**
|
|
17
|
+
* Whether this container can contain children.
|
|
18
|
+
* This may differ from isContainer if the container is not configured to accept children.
|
|
19
|
+
*/
|
|
20
|
+
canContainChildren: boolean;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Helper function to get container info from any HTMLElement.
|
|
24
|
+
* Reads computed styles to determine display mode.
|
|
25
|
+
*/
|
|
26
|
+
declare function getContainerInfoFromElement(element: HTMLElement | null): ContainerInfo;
|
|
27
|
+
//#endregion
|
|
28
|
+
export { ContainerInfo, getContainerInfoFromElement };
|
|
29
|
+
//# sourceMappingURL=ContainerInfo.d.ts.map
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
//#region src/elements/ContainerInfo.ts
|
|
2
|
+
/**
|
|
3
|
+
* Helper function to get container info from any HTMLElement.
|
|
4
|
+
* Reads computed styles to determine display mode.
|
|
5
|
+
*/
|
|
6
|
+
function getContainerInfoFromElement(element) {
|
|
7
|
+
if (!element) return {
|
|
8
|
+
isContainer: false,
|
|
9
|
+
displayMode: null,
|
|
10
|
+
canContainChildren: false
|
|
11
|
+
};
|
|
12
|
+
const display = window.getComputedStyle(element).display;
|
|
13
|
+
const isGrid = display === "grid" || display === "inline-grid";
|
|
14
|
+
const isFlex = display === "flex" || display === "inline-flex";
|
|
15
|
+
const isBlock = display === "block" || display === "inline-block";
|
|
16
|
+
const isContainer = isGrid || isFlex || isBlock;
|
|
17
|
+
let displayMode = null;
|
|
18
|
+
if (isFlex) displayMode = "flex";
|
|
19
|
+
else if (isGrid) displayMode = "grid";
|
|
20
|
+
else if (isBlock) displayMode = "block";
|
|
21
|
+
return {
|
|
22
|
+
isContainer,
|
|
23
|
+
displayMode,
|
|
24
|
+
canContainChildren: isContainer
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
//#endregion
|
|
29
|
+
export { getContainerInfoFromElement };
|
|
30
|
+
//# sourceMappingURL=ContainerInfo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ContainerInfo.js","names":["displayMode: \"flex\" | \"grid\" | \"block\" | null"],"sources":["../../src/elements/ContainerInfo.ts"],"sourcesContent":["/**\n * Container information interface for elements that can contain children.\n * Provides information about container capabilities and display mode.\n */\n\nexport interface ContainerInfo {\n /**\n * Whether this element is a container that can contain children.\n */\n isContainer: boolean;\n\n /**\n * The display mode of the container.\n * \"flex\" | \"grid\" | \"block\" | null\n */\n displayMode: \"flex\" | \"grid\" | \"block\" | null;\n\n /**\n * Whether this container can contain children.\n * This may differ from isContainer if the container is not configured to accept children.\n */\n canContainChildren: boolean;\n}\n\n/**\n * Helper function to get container info from any HTMLElement.\n * Reads computed styles to determine display mode.\n */\nexport function getContainerInfoFromElement(\n element: HTMLElement | null,\n): ContainerInfo {\n if (!element) {\n return {\n isContainer: false,\n displayMode: null,\n canContainChildren: false,\n };\n }\n\n const computedStyle = window.getComputedStyle(element);\n const display = computedStyle.display;\n\n // Determine if it's a container (grid or flex)\n const isGrid = display === \"grid\" || display === \"inline-grid\";\n const isFlex = display === \"flex\" || display === \"inline-flex\";\n const isBlock = display === \"block\" || display === \"inline-block\";\n\n const isContainer = isGrid || isFlex || isBlock;\n\n let displayMode: \"flex\" | \"grid\" | \"block\" | null = null;\n if (isFlex) {\n displayMode = \"flex\";\n } else if (isGrid) {\n displayMode = \"grid\";\n } else if (isBlock) {\n displayMode = \"block\";\n }\n\n return {\n isContainer,\n displayMode,\n canContainChildren: isContainer,\n };\n}\n"],"mappings":";;;;;AA4BA,SAAgB,4BACd,SACe;AACf,KAAI,CAAC,QACH,QAAO;EACL,aAAa;EACb,aAAa;EACb,oBAAoB;EACrB;CAIH,MAAM,UADgB,OAAO,iBAAiB,QAAQ,CACxB;CAG9B,MAAM,SAAS,YAAY,UAAU,YAAY;CACjD,MAAM,SAAS,YAAY,UAAU,YAAY;CACjD,MAAM,UAAU,YAAY,WAAW,YAAY;CAEnD,MAAM,cAAc,UAAU,UAAU;CAExC,IAAIA,cAAgD;AACpD,KAAI,OACF,eAAc;UACL,OACT,eAAc;UACL,QACT,eAAc;AAGhB,QAAO;EACL;EACA;EACA,oBAAoB;EACrB"}
|
|
@@ -2,15 +2,25 @@ import { MediaEngine } from "../transcoding/types/index.js";
|
|
|
2
2
|
import { EFMedia } from "./EFMedia.js";
|
|
3
3
|
import * as _lit_task8 from "@lit/task";
|
|
4
4
|
import { Task } from "@lit/task";
|
|
5
|
-
import * as
|
|
5
|
+
import * as lit_html1 from "lit-html";
|
|
6
6
|
import * as lit_html_directives_ref_js1 from "lit-html/directives/ref.js";
|
|
7
7
|
|
|
8
8
|
//#region src/elements/EFAudio.d.ts
|
|
9
9
|
declare const EFAudio_base: typeof EFMedia;
|
|
10
10
|
declare class EFAudio extends EFAudio_base {
|
|
11
|
-
|
|
11
|
+
/**
|
|
12
|
+
* EFAudio only requires audio tracks - skip video track validation
|
|
13
|
+
* to avoid unnecessary network requests to transcoding service.
|
|
14
|
+
*/
|
|
15
|
+
get requiredTracks(): "audio" | "video" | "both";
|
|
16
|
+
/**
|
|
17
|
+
* Audio volume level (0.0 to 1.0)
|
|
18
|
+
* @domAttribute "volume"
|
|
19
|
+
*/
|
|
20
|
+
volume: number;
|
|
12
21
|
audioElementRef: lit_html_directives_ref_js1.Ref<HTMLAudioElement>;
|
|
13
|
-
|
|
22
|
+
protected updated(changedProperties: Map<PropertyKey, unknown>): void;
|
|
23
|
+
render(): lit_html1.TemplateResult<1>;
|
|
14
24
|
frameTask: Task<readonly [_lit_task8.TaskStatus, _lit_task8.TaskStatus, _lit_task8.TaskStatus, _lit_task8.TaskStatus], void>;
|
|
15
25
|
/**
|
|
16
26
|
* Legacy getter for fragment index task (maps to audioSegmentIdTask)
|
package/dist/elements/EFAudio.js
CHANGED
|
@@ -11,7 +11,7 @@ import { createRef, ref } from "lit/directives/ref.js";
|
|
|
11
11
|
let EFAudio = class EFAudio$1 extends TWMixin(EFMedia) {
|
|
12
12
|
constructor(..._args) {
|
|
13
13
|
super(..._args);
|
|
14
|
-
this.
|
|
14
|
+
this.volume = 1;
|
|
15
15
|
this.audioElementRef = createRef();
|
|
16
16
|
this.frameTask = new Task(this, {
|
|
17
17
|
autoRun: EF_INTERACTIVE,
|
|
@@ -21,15 +21,68 @@ let EFAudio = class EFAudio$1 extends TWMixin(EFMedia) {
|
|
|
21
21
|
this.audioSegmentFetchTask.status,
|
|
22
22
|
this.mediaEngineTask.status
|
|
23
23
|
],
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
24
|
+
onError: (error) => {
|
|
25
|
+
this.frameTask.taskComplete.catch(() => {});
|
|
26
|
+
if (error instanceof DOMException && error.name === "AbortError" || error instanceof Error && (error.name === "AbortError" || error.message?.includes("signal is aborted") || error.message?.includes("The user aborted a request"))) return;
|
|
27
|
+
console.error("EFAudio frameTask error", error);
|
|
28
|
+
},
|
|
29
|
+
task: async ([_audioBufferStatus, _audioSeekStatus, _audioSegmentFetchStatus, _mediaEngineStatus], { signal }) => {
|
|
30
|
+
try {
|
|
31
|
+
await this.mediaEngineTask.taskComplete;
|
|
32
|
+
} catch (error) {
|
|
33
|
+
if (error instanceof DOMException && error.name === "AbortError") {
|
|
34
|
+
signal?.throwIfAborted();
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
throw error;
|
|
38
|
+
}
|
|
39
|
+
signal?.throwIfAborted();
|
|
40
|
+
try {
|
|
41
|
+
await this.audioSegmentFetchTask.taskComplete;
|
|
42
|
+
} catch (error) {
|
|
43
|
+
if (error instanceof DOMException && error.name === "AbortError") {
|
|
44
|
+
signal?.throwIfAborted();
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
throw error;
|
|
48
|
+
}
|
|
49
|
+
signal?.throwIfAborted();
|
|
50
|
+
try {
|
|
51
|
+
await this.audioSeekTask.taskComplete;
|
|
52
|
+
} catch (error) {
|
|
53
|
+
if (error instanceof DOMException && error.name === "AbortError") {
|
|
54
|
+
signal?.throwIfAborted();
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
throw error;
|
|
58
|
+
}
|
|
59
|
+
signal?.throwIfAborted();
|
|
60
|
+
try {
|
|
61
|
+
await this.audioBufferTask.taskComplete;
|
|
62
|
+
} catch (error) {
|
|
63
|
+
if (error instanceof DOMException && error.name === "AbortError") {
|
|
64
|
+
signal?.throwIfAborted();
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
throw error;
|
|
68
|
+
}
|
|
69
|
+
signal?.throwIfAborted();
|
|
30
70
|
}
|
|
31
71
|
});
|
|
32
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* EFAudio only requires audio tracks - skip video track validation
|
|
75
|
+
* to avoid unnecessary network requests to transcoding service.
|
|
76
|
+
*/
|
|
77
|
+
get requiredTracks() {
|
|
78
|
+
return "audio";
|
|
79
|
+
}
|
|
80
|
+
updated(changedProperties) {
|
|
81
|
+
super.updated(changedProperties);
|
|
82
|
+
if (this.audioElementRef.value) {
|
|
83
|
+
if (changedProperties.has("volume") || changedProperties.size === 0) this.audioElementRef.value.volume = this.volume;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
33
86
|
render() {
|
|
34
87
|
return html`<audio ${ref(this.audioElementRef)}></audio>`;
|
|
35
88
|
}
|
|
@@ -42,9 +95,10 @@ let EFAudio = class EFAudio$1 extends TWMixin(EFMedia) {
|
|
|
42
95
|
}
|
|
43
96
|
};
|
|
44
97
|
__decorate([property({
|
|
45
|
-
type:
|
|
46
|
-
attribute: "
|
|
47
|
-
|
|
98
|
+
type: Number,
|
|
99
|
+
attribute: "volume",
|
|
100
|
+
reflect: true
|
|
101
|
+
})], EFAudio.prototype, "volume", void 0);
|
|
48
102
|
EFAudio = __decorate([customElement("ef-audio")], EFAudio);
|
|
49
103
|
|
|
50
104
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EFAudio.js","names":["EFAudio"],"sources":["../../src/elements/EFAudio.ts"],"sourcesContent":["import { Task } from \"@lit/task\";\nimport { html } from \"lit\";\nimport { customElement, property } from \"lit/decorators.js\";\nimport { createRef, ref } from \"lit/directives/ref.js\";\nimport { EF_INTERACTIVE } from \"../EF_INTERACTIVE.js\";\nimport { TWMixin } from \"../gui/TWMixin.js\";\nimport { EFMedia } from \"./EFMedia.js\";\n\n@customElement(\"ef-audio\")\nexport class EFAudio extends TWMixin(EFMedia) {\n
|
|
1
|
+
{"version":3,"file":"EFAudio.js","names":["EFAudio"],"sources":["../../src/elements/EFAudio.ts"],"sourcesContent":["import { Task } from \"@lit/task\";\nimport { html } from \"lit\";\nimport { customElement, property } from \"lit/decorators.js\";\nimport { createRef, ref } from \"lit/directives/ref.js\";\nimport { EF_INTERACTIVE } from \"../EF_INTERACTIVE.js\";\nimport { TWMixin } from \"../gui/TWMixin.js\";\nimport { EFMedia } from \"./EFMedia.js\";\n\n@customElement(\"ef-audio\")\nexport class EFAudio extends TWMixin(EFMedia) {\n /**\n * EFAudio only requires audio tracks - skip video track validation\n * to avoid unnecessary network requests to transcoding service.\n */\n override get requiredTracks(): \"audio\" | \"video\" | \"both\" {\n return \"audio\";\n }\n\n /**\n * Audio volume level (0.0 to 1.0)\n * @domAttribute \"volume\"\n */\n @property({ type: Number, attribute: \"volume\", reflect: true })\n volume = 1.0;\n\n audioElementRef = createRef<HTMLAudioElement>();\n\n protected updated(\n changedProperties: Map<PropertyKey, unknown>,\n ): void {\n super.updated(changedProperties);\n \n // Sync volume property to HTMLAudioElement whenever it changes or element is first rendered\n if (this.audioElementRef.value) {\n if (changedProperties.has(\"volume\") || changedProperties.size === 0) {\n this.audioElementRef.value.volume = this.volume;\n }\n }\n }\n\n render() {\n return html`<audio ${ref(this.audioElementRef)}></audio>`;\n }\n\n frameTask = new Task(this, {\n autoRun: EF_INTERACTIVE,\n args: () =>\n [\n this.audioBufferTask.status,\n this.audioSeekTask.status,\n this.audioSegmentFetchTask.status,\n this.mediaEngineTask.status,\n ] as const,\n onError: (error) => {\n // CRITICAL: Attach .catch() handler to taskComplete BEFORE the promise is rejected.\n // This prevents unhandled rejection when hostUpdate() triggers _performTask() without awaiting.\n this.frameTask.taskComplete.catch(() => {});\n \n // Don't log AbortErrors - these are expected when tasks are cancelled\n const isAbortError = \n (error instanceof DOMException && error.name === \"AbortError\") ||\n (error instanceof Error && (\n error.name === \"AbortError\" ||\n error.message?.includes(\"signal is aborted\") ||\n error.message?.includes(\"The user aborted a request\")\n ));\n \n if (isAbortError) {\n return;\n }\n \n console.error(\"EFAudio frameTask error\", error);\n },\n task: async ([_audioBufferStatus, _audioSeekStatus, _audioSegmentFetchStatus, _mediaEngineStatus], { signal }) => {\n // Wrap all taskComplete awaits in try/catch to handle AbortErrors\n try {\n await this.mediaEngineTask.taskComplete;\n } catch (error) {\n if (error instanceof DOMException && error.name === \"AbortError\") {\n signal?.throwIfAborted();\n return;\n }\n throw error;\n }\n signal?.throwIfAborted();\n \n try {\n await this.audioSegmentFetchTask.taskComplete;\n } catch (error) {\n if (error instanceof DOMException && error.name === \"AbortError\") {\n signal?.throwIfAborted();\n return;\n }\n throw error;\n }\n signal?.throwIfAborted();\n \n try {\n await this.audioSeekTask.taskComplete;\n } catch (error) {\n if (error instanceof DOMException && error.name === \"AbortError\") {\n signal?.throwIfAborted();\n return;\n }\n throw error;\n }\n signal?.throwIfAborted();\n \n try {\n await this.audioBufferTask.taskComplete;\n } catch (error) {\n if (error instanceof DOMException && error.name === \"AbortError\") {\n signal?.throwIfAborted();\n return;\n }\n throw error;\n }\n signal?.throwIfAborted();\n // REMOVED: this.rootTimegroup?.requestUpdate() was causing infinite update loops.\n // When EFAudio's frameTask ran, it would trigger root to update, which triggered\n // OwnCurrentTimeController.hostUpdated on all children, which triggered more\n // frameTask runs, creating an infinite cycle.\n // The root timegroup already updates when currentTime changes - no need to force it here.\n },\n });\n\n /**\n * Legacy getter for fragment index task (maps to audioSegmentIdTask)\n * Still used by EFCaptions\n */\n get fragmentIndexTask() {\n return this.audioSegmentIdTask;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"ef-audio\": EFAudio;\n }\n}\n"],"mappings":";;;;;;;;;;AASO,oBAAMA,kBAAgB,QAAQ,QAAQ,CAAC;;;gBAcnC;yBAES,WAA6B;mBAmBnC,IAAI,KAAK,MAAM;GACzB,SAAS;GACT,YACE;IACE,KAAK,gBAAgB;IACrB,KAAK,cAAc;IACnB,KAAK,sBAAsB;IAC3B,KAAK,gBAAgB;IACtB;GACH,UAAU,UAAU;AAGlB,SAAK,UAAU,aAAa,YAAY,GAAG;AAW3C,QAPG,iBAAiB,gBAAgB,MAAM,SAAS,gBAChD,iBAAiB,UAChB,MAAM,SAAS,gBACf,MAAM,SAAS,SAAS,oBAAoB,IAC5C,MAAM,SAAS,SAAS,6BAA6B,EAIvD;AAGF,YAAQ,MAAM,2BAA2B,MAAM;;GAEjD,MAAM,OAAO,CAAC,oBAAoB,kBAAkB,0BAA0B,qBAAqB,EAAE,aAAa;AAEhH,QAAI;AACF,WAAM,KAAK,gBAAgB;aACpB,OAAO;AACd,SAAI,iBAAiB,gBAAgB,MAAM,SAAS,cAAc;AAChE,cAAQ,gBAAgB;AACxB;;AAEF,WAAM;;AAER,YAAQ,gBAAgB;AAExB,QAAI;AACF,WAAM,KAAK,sBAAsB;aAC1B,OAAO;AACd,SAAI,iBAAiB,gBAAgB,MAAM,SAAS,cAAc;AAChE,cAAQ,gBAAgB;AACxB;;AAEF,WAAM;;AAER,YAAQ,gBAAgB;AAExB,QAAI;AACF,WAAM,KAAK,cAAc;aAClB,OAAO;AACd,SAAI,iBAAiB,gBAAgB,MAAM,SAAS,cAAc;AAChE,cAAQ,gBAAgB;AACxB;;AAEF,WAAM;;AAER,YAAQ,gBAAgB;AAExB,QAAI;AACF,WAAM,KAAK,gBAAgB;aACpB,OAAO;AACd,SAAI,iBAAiB,gBAAgB,MAAM,SAAS,cAAc;AAChE,cAAQ,gBAAgB;AACxB;;AAEF,WAAM;;AAER,YAAQ,gBAAgB;;GAO3B,CAAC;;;;;;CA9GF,IAAa,iBAA6C;AACxD,SAAO;;CAYT,AAAU,QACR,mBACM;AACN,QAAM,QAAQ,kBAAkB;AAGhC,MAAI,KAAK,gBAAgB,OACvB;OAAI,kBAAkB,IAAI,SAAS,IAAI,kBAAkB,SAAS,EAChE,MAAK,gBAAgB,MAAM,SAAS,KAAK;;;CAK/C,SAAS;AACP,SAAO,IAAI,UAAU,IAAI,KAAK,gBAAgB,CAAC;;;;;;CAyFjD,IAAI,oBAAoB;AACtB,SAAO,KAAK;;;YA7Gb,SAAS;CAAE,MAAM;CAAQ,WAAW;CAAU,SAAS;CAAM,CAAC;sBAdhE,cAAc,WAAW"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { TemporalMixinInterface } from "./EFTemporal.js";
|
|
2
1
|
import { EFSourceMixinInterface } from "./EFSourceMixin.js";
|
|
2
|
+
import { TemporalMixinInterface } from "./EFTemporal.js";
|
|
3
3
|
import { FetchMixinInterface } from "./FetchMixin.js";
|
|
4
|
-
import { EFAudio } from "./EFAudio.js";
|
|
5
4
|
import { EFVideo } from "./EFVideo.js";
|
|
5
|
+
import { EFAudio } from "./EFAudio.js";
|
|
6
6
|
import { Task, TaskStatus } from "@lit/task";
|
|
7
|
-
import * as
|
|
7
|
+
import * as lit3 from "lit";
|
|
8
8
|
import { LitElement, PropertyValueMap } from "lit";
|
|
9
|
-
import * as
|
|
9
|
+
import * as lit_html3 from "lit-html";
|
|
10
10
|
|
|
11
11
|
//#region src/elements/EFCaptions.d.ts
|
|
12
12
|
interface WordSegment {
|
|
@@ -25,8 +25,8 @@ interface Caption {
|
|
|
25
25
|
}
|
|
26
26
|
declare const EFCaptionsActiveWord_base: (new (...args: any[]) => TemporalMixinInterface) & typeof LitElement;
|
|
27
27
|
declare class EFCaptionsActiveWord extends EFCaptionsActiveWord_base {
|
|
28
|
-
static styles:
|
|
29
|
-
render():
|
|
28
|
+
static styles: lit3.CSSResult[];
|
|
29
|
+
render(): lit_html3.TemplateResult<1> | undefined;
|
|
30
30
|
wordStartMs: number;
|
|
31
31
|
wordEndMs: number;
|
|
32
32
|
wordText: string;
|
|
@@ -38,8 +38,8 @@ declare class EFCaptionsActiveWord extends EFCaptionsActiveWord_base {
|
|
|
38
38
|
}
|
|
39
39
|
declare const EFCaptionsSegment_base: (new (...args: any[]) => TemporalMixinInterface) & typeof LitElement;
|
|
40
40
|
declare class EFCaptionsSegment extends EFCaptionsSegment_base {
|
|
41
|
-
static styles:
|
|
42
|
-
render():
|
|
41
|
+
static styles: lit3.CSSResult[];
|
|
42
|
+
render(): lit_html3.TemplateResult<1> | undefined;
|
|
43
43
|
segmentStartMs: number;
|
|
44
44
|
segmentEndMs: number;
|
|
45
45
|
segmentText: string;
|
|
@@ -49,8 +49,8 @@ declare class EFCaptionsSegment extends EFCaptionsSegment_base {
|
|
|
49
49
|
get durationMs(): number;
|
|
50
50
|
}
|
|
51
51
|
declare class EFCaptionsBeforeActiveWord extends EFCaptionsSegment {
|
|
52
|
-
static styles:
|
|
53
|
-
render():
|
|
52
|
+
static styles: lit3.CSSResult[];
|
|
53
|
+
render(): lit_html3.TemplateResult<1> | undefined;
|
|
54
54
|
hidden: boolean;
|
|
55
55
|
segmentText: string;
|
|
56
56
|
segmentStartMs: number;
|
|
@@ -60,8 +60,8 @@ declare class EFCaptionsBeforeActiveWord extends EFCaptionsSegment {
|
|
|
60
60
|
get durationMs(): number;
|
|
61
61
|
}
|
|
62
62
|
declare class EFCaptionsAfterActiveWord extends EFCaptionsSegment {
|
|
63
|
-
static styles:
|
|
64
|
-
render():
|
|
63
|
+
static styles: lit3.CSSResult[];
|
|
64
|
+
render(): lit_html3.TemplateResult<1> | undefined;
|
|
65
65
|
hidden: boolean;
|
|
66
66
|
segmentText: string;
|
|
67
67
|
segmentStartMs: number;
|
|
@@ -72,7 +72,8 @@ declare class EFCaptionsAfterActiveWord extends EFCaptionsSegment {
|
|
|
72
72
|
}
|
|
73
73
|
declare const EFCaptions_base: (new (...args: any[]) => EFSourceMixinInterface) & (new (...args: any[]) => TemporalMixinInterface) & (new (...args: any[]) => FetchMixinInterface) & typeof LitElement;
|
|
74
74
|
declare class EFCaptions extends EFCaptions_base {
|
|
75
|
-
|
|
75
|
+
#private;
|
|
76
|
+
static styles: lit3.CSSResult[];
|
|
76
77
|
targetSelector: string;
|
|
77
78
|
set target(value: string);
|
|
78
79
|
wordStyle: string;
|
|
@@ -95,10 +96,10 @@ declare class EFCaptions extends EFCaptions_base {
|
|
|
95
96
|
segmentContainers: HTMLCollectionOf<EFCaptionsSegment>;
|
|
96
97
|
beforeActiveWordContainers: HTMLCollectionOf<EFCaptionsBeforeActiveWord>;
|
|
97
98
|
afterActiveWordContainers: HTMLCollectionOf<EFCaptionsAfterActiveWord>;
|
|
98
|
-
render():
|
|
99
|
+
render(): lit_html3.TemplateResult<1>;
|
|
99
100
|
transcriptionsPath(): string | null;
|
|
100
101
|
captionsPath(): string | null;
|
|
101
|
-
protected md5SumLoader: Task<readonly [string, typeof fetch],
|
|
102
|
+
protected md5SumLoader: Task<readonly [string, typeof fetch], any>;
|
|
102
103
|
private transcriptionDataTask;
|
|
103
104
|
private transcriptionFragmentPath;
|
|
104
105
|
private fragmentIndexTask;
|
|
@@ -107,6 +108,7 @@ declare class EFCaptions extends EFCaptions_base {
|
|
|
107
108
|
unifiedCaptionsDataTask: Task<readonly [Caption | null | undefined, Caption | null | undefined], Caption | null | undefined>;
|
|
108
109
|
frameTask: Task<readonly [TaskStatus, number], void>;
|
|
109
110
|
connectedCallback(): void;
|
|
111
|
+
disconnectedCallback(): void;
|
|
110
112
|
protected updated(changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>): void;
|
|
111
113
|
updateTextContainers(): void;
|
|
112
114
|
get targetElement(): EFAudio | EFVideo | null;
|
|
@@ -124,5 +126,5 @@ declare global {
|
|
|
124
126
|
}
|
|
125
127
|
}
|
|
126
128
|
//#endregion
|
|
127
|
-
export {
|
|
129
|
+
export { EFCaptions, EFCaptionsActiveWord, EFCaptionsAfterActiveWord, EFCaptionsBeforeActiveWord, EFCaptionsSegment };
|
|
128
130
|
//# sourceMappingURL=EFCaptions.d.ts.map
|
|
@@ -3,10 +3,10 @@ import { __decorate } from "../_virtual/_@oxc-project_runtime@0.94.0/helpers/dec
|
|
|
3
3
|
import { EFTemporal, flushStartTimeMsCache } from "./EFTemporal.js";
|
|
4
4
|
import { EFSourceMixin } from "./EFSourceMixin.js";
|
|
5
5
|
import { FetchMixin } from "./FetchMixin.js";
|
|
6
|
-
import { flushSequenceDurationCache } from "./EFTimegroup.js";
|
|
7
6
|
import { EFAudio } from "./EFAudio.js";
|
|
8
|
-
import { EFVideo } from "./EFVideo.js";
|
|
9
7
|
import { CrossUpdateController } from "./CrossUpdateController.js";
|
|
8
|
+
import { EFVideo } from "./EFVideo.js";
|
|
9
|
+
import { flushSequenceDurationCache } from "./EFTimegroup.js";
|
|
10
10
|
import { Task, TaskStatus } from "@lit/task";
|
|
11
11
|
import { LitElement, css, html } from "lit";
|
|
12
12
|
import { customElement, property } from "lit/decorators.js";
|
|
@@ -266,10 +266,12 @@ let EFCaptions = class EFCaptions$1 extends EFSourceMixin(EFTemporal(FetchMixin(
|
|
|
266
266
|
args: () => [this.target, this.fetch],
|
|
267
267
|
task: async ([_target, fetch], { signal }) => {
|
|
268
268
|
if (!this.targetElement) return null;
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
269
|
+
const src = this.targetElement.src ?? "";
|
|
270
|
+
let normalizedSrc = src.startsWith("/") ? src.slice(1) : src;
|
|
271
|
+
normalizedSrc = normalizedSrc.replace(/^\/+/, "");
|
|
272
|
+
const response = await fetch(`/api/v1/isobmff_files/local/md5?src=${encodeURIComponent(normalizedSrc)}`, { signal });
|
|
273
|
+
if (!response.ok) return;
|
|
274
|
+
return (await response.json()).md5 ?? void 0;
|
|
273
275
|
}
|
|
274
276
|
});
|
|
275
277
|
this.transcriptionDataTask = new Task(this, {
|
|
@@ -287,7 +289,8 @@ let EFCaptions = class EFCaptions$1 extends EFSourceMixin(EFTemporal(FetchMixin(
|
|
|
287
289
|
this.fragmentIndexTask = new Task(this, {
|
|
288
290
|
autoRun: EF_INTERACTIVE,
|
|
289
291
|
args: () => [this.transcriptionDataTask.value, this.ownCurrentTimeMs],
|
|
290
|
-
task: async ([transcription, ownCurrentTimeMs]) => {
|
|
292
|
+
task: async ([transcription, ownCurrentTimeMs], { signal }) => {
|
|
293
|
+
signal?.throwIfAborted();
|
|
291
294
|
if (!transcription) return null;
|
|
292
295
|
return Math.floor(ownCurrentTimeMs / transcription.work_slice_ms);
|
|
293
296
|
}
|
|
@@ -335,17 +338,38 @@ let EFCaptions = class EFCaptions$1 extends EFSourceMixin(EFTemporal(FetchMixin(
|
|
|
335
338
|
this.unifiedCaptionsDataTask = new Task(this, {
|
|
336
339
|
autoRun: EF_INTERACTIVE,
|
|
337
340
|
args: () => [this.customCaptionsDataTask.value, this.transcriptionFragmentDataTask.value],
|
|
338
|
-
task: async ([_customData, _transcriptionData]) => {
|
|
339
|
-
|
|
340
|
-
if (this.
|
|
341
|
+
task: async ([_customData, _transcriptionData], { signal }) => {
|
|
342
|
+
signal?.throwIfAborted();
|
|
343
|
+
if (this.customCaptionsDataTask.status === TaskStatus.PENDING) {
|
|
344
|
+
await this.customCaptionsDataTask.taskComplete;
|
|
345
|
+
signal?.throwIfAborted();
|
|
346
|
+
}
|
|
347
|
+
if (this.transcriptionFragmentDataTask.status === TaskStatus.PENDING) {
|
|
348
|
+
await this.transcriptionFragmentDataTask.taskComplete;
|
|
349
|
+
signal?.throwIfAborted();
|
|
350
|
+
}
|
|
341
351
|
return this.customCaptionsDataTask.value || this.transcriptionFragmentDataTask.value;
|
|
342
352
|
}
|
|
343
353
|
});
|
|
344
354
|
this.frameTask = new Task(this, {
|
|
345
355
|
autoRun: EF_INTERACTIVE,
|
|
346
356
|
args: () => [this.unifiedCaptionsDataTask.status, this.ownCurrentTimeMs],
|
|
347
|
-
|
|
348
|
-
|
|
357
|
+
onError: (error) => {
|
|
358
|
+
this.frameTask.taskComplete.catch(() => {});
|
|
359
|
+
if (error instanceof DOMException && error.name === "AbortError" || error instanceof Error && (error.name === "AbortError" || error.message?.includes("signal is aborted") || error.message?.includes("The user aborted a request"))) return;
|
|
360
|
+
console.error("EFCaptions frameTask error", error);
|
|
361
|
+
},
|
|
362
|
+
task: async ([_status, _ownCurrentTimeMs], { signal }) => {
|
|
363
|
+
try {
|
|
364
|
+
await this.unifiedCaptionsDataTask.taskComplete;
|
|
365
|
+
} catch (error) {
|
|
366
|
+
if (error instanceof DOMException && error.name === "AbortError") {
|
|
367
|
+
signal?.throwIfAborted();
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
throw error;
|
|
371
|
+
}
|
|
372
|
+
signal?.throwIfAborted();
|
|
349
373
|
this.updateTextContainers();
|
|
350
374
|
}
|
|
351
375
|
});
|
|
@@ -368,6 +392,7 @@ let EFCaptions = class EFCaptions$1 extends EFSourceMixin(EFTemporal(FetchMixin(
|
|
|
368
392
|
set target(value) {
|
|
369
393
|
this.targetSelector = value;
|
|
370
394
|
}
|
|
395
|
+
#cachedIntrinsicDurationMs = null;
|
|
371
396
|
render() {
|
|
372
397
|
return html`<slot></slot>`;
|
|
373
398
|
}
|
|
@@ -379,30 +404,78 @@ let EFCaptions = class EFCaptions$1 extends EFSourceMixin(EFTemporal(FetchMixin(
|
|
|
379
404
|
captionsPath() {
|
|
380
405
|
if (!this.targetElement) return null;
|
|
381
406
|
if (this.targetElement.assetId) return `${this.apiHost}/api/v1/caption_files/${this.targetElement.assetId}`;
|
|
382
|
-
|
|
407
|
+
const targetSrc = this.targetElement.src;
|
|
408
|
+
let normalizedSrc = targetSrc.startsWith("/") ? targetSrc.slice(1) : targetSrc;
|
|
409
|
+
normalizedSrc = normalizedSrc.replace(/^\/+/, "");
|
|
410
|
+
return `/api/v1/assets/local/captions?src=${encodeURIComponent(normalizedSrc)}`;
|
|
383
411
|
}
|
|
384
412
|
transcriptionFragmentPath(transcriptionId, fragmentIndex) {
|
|
385
413
|
return `${this.apiHost}/api/v1/transcriptions/${transcriptionId}/fragments/${fragmentIndex}`;
|
|
386
414
|
}
|
|
415
|
+
#rootTimegroupUpdateController;
|
|
387
416
|
connectedCallback() {
|
|
388
417
|
super.connectedCallback();
|
|
389
418
|
const target = this.targetSelector ? document.getElementById(this.targetSelector) : null;
|
|
390
419
|
if (target && (target instanceof EFAudio || target instanceof EFVideo)) new CrossUpdateController(target, this);
|
|
391
420
|
else if (this.hasCustomCaptionsData && this.rootTimegroup) new CrossUpdateController(this.rootTimegroup, this);
|
|
421
|
+
if (this.rootTimegroup) {
|
|
422
|
+
this.#rootTimegroupUpdateController = {
|
|
423
|
+
hostUpdated: () => {
|
|
424
|
+
Promise.resolve().then(() => {
|
|
425
|
+
this.updateTextContainers();
|
|
426
|
+
});
|
|
427
|
+
},
|
|
428
|
+
hostDisconnected: () => {
|
|
429
|
+
this.#rootTimegroupUpdateController = void 0;
|
|
430
|
+
}
|
|
431
|
+
};
|
|
432
|
+
this.rootTimegroup.addController(this.#rootTimegroupUpdateController);
|
|
433
|
+
}
|
|
392
434
|
new MutationObserver(() => {
|
|
393
435
|
if (this.style.display === "none") {
|
|
394
436
|
this.style.removeProperty("display");
|
|
395
437
|
this.style.opacity = "0";
|
|
396
438
|
this.style.pointerEvents = "none";
|
|
439
|
+
} else if (!this.style.display || this.style.display === "") {
|
|
440
|
+
this.style.removeProperty("opacity");
|
|
441
|
+
this.style.removeProperty("pointer-events");
|
|
397
442
|
}
|
|
398
443
|
}).observe(this, {
|
|
399
444
|
attributes: true,
|
|
400
445
|
attributeFilter: ["style"]
|
|
401
446
|
});
|
|
402
447
|
}
|
|
448
|
+
disconnectedCallback() {
|
|
449
|
+
super.disconnectedCallback();
|
|
450
|
+
if (this.#rootTimegroupUpdateController && this.rootTimegroup) {
|
|
451
|
+
this.rootTimegroup.removeController(this.#rootTimegroupUpdateController);
|
|
452
|
+
this.#rootTimegroupUpdateController = void 0;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
403
455
|
updated(changedProperties) {
|
|
456
|
+
if (this.rootTimegroup && !this.#rootTimegroupUpdateController) {
|
|
457
|
+
this.#rootTimegroupUpdateController = {
|
|
458
|
+
hostUpdated: () => {
|
|
459
|
+
Promise.resolve().then(() => {
|
|
460
|
+
this.updateTextContainers();
|
|
461
|
+
});
|
|
462
|
+
},
|
|
463
|
+
hostDisconnected: () => {
|
|
464
|
+
this.#rootTimegroupUpdateController = void 0;
|
|
465
|
+
}
|
|
466
|
+
};
|
|
467
|
+
this.rootTimegroup.addController(this.#rootTimegroupUpdateController);
|
|
468
|
+
}
|
|
469
|
+
if (changedProperties.has("rootTimegroup") && this.#rootTimegroupUpdateController) {
|
|
470
|
+
const oldRootTimegroup = changedProperties.get("rootTimegroup");
|
|
471
|
+
if (oldRootTimegroup && oldRootTimegroup !== this.rootTimegroup) {
|
|
472
|
+
oldRootTimegroup.removeController(this.#rootTimegroupUpdateController);
|
|
473
|
+
this.#rootTimegroupUpdateController = void 0;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
404
476
|
this.updateTextContainers();
|
|
405
477
|
if (changedProperties.has("captionsData") || changedProperties.has("captionsSrc") || changedProperties.has("captionsScript")) {
|
|
478
|
+
this.#cachedIntrinsicDurationMs = null;
|
|
406
479
|
this.requestUpdate("intrinsicDurationMs");
|
|
407
480
|
flushSequenceDurationCache();
|
|
408
481
|
flushStartTimeMsCache();
|
|
@@ -416,7 +489,16 @@ let EFCaptions = class EFCaptions$1 extends EFSourceMixin(EFTemporal(FetchMixin(
|
|
|
416
489
|
updateTextContainers() {
|
|
417
490
|
const captionsData = this.unifiedCaptionsDataTask.value;
|
|
418
491
|
if (!captionsData) return;
|
|
419
|
-
|
|
492
|
+
let currentTimeMs = this.ownCurrentTimeMs;
|
|
493
|
+
if (this.hasCustomCaptionsData && this.parentTimegroup) {
|
|
494
|
+
const videoElement = Array.from(this.parentTimegroup.children).find((child) => child instanceof EFVideo);
|
|
495
|
+
if (videoElement) {
|
|
496
|
+
const sourceInMs = videoElement.sourceInMs ?? 0;
|
|
497
|
+
currentTimeMs = videoElement.currentSourceTimeMs - sourceInMs;
|
|
498
|
+
currentTimeMs = Math.max(0, Math.min(currentTimeMs, this.durationMs));
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
const currentTimeSec = currentTimeMs / 1e3;
|
|
420
502
|
const currentWord = captionsData.word_segments.find((word) => currentTimeSec >= word.start && currentTimeSec < word.end);
|
|
421
503
|
const currentSegment = captionsData.segments.find((segment) => currentTimeSec >= segment.start && currentTimeSec < segment.end);
|
|
422
504
|
for (const wordContainer of this.activeWordContainers) if (currentWord) {
|
|
@@ -520,6 +602,7 @@ let EFCaptions = class EFCaptions$1 extends EFSourceMixin(EFTemporal(FetchMixin(
|
|
|
520
602
|
return !!(this.captionsData || this.captionsSrc || this.captionsScript);
|
|
521
603
|
}
|
|
522
604
|
get intrinsicDurationMs() {
|
|
605
|
+
if (this.#cachedIntrinsicDurationMs !== null) return this.#cachedIntrinsicDurationMs;
|
|
523
606
|
let captionsData = null;
|
|
524
607
|
if (this.captionsData) captionsData = this.captionsData;
|
|
525
608
|
else if (this.captionsScript) {
|
|
@@ -528,11 +611,19 @@ let EFCaptions = class EFCaptions$1 extends EFSourceMixin(EFTemporal(FetchMixin(
|
|
|
528
611
|
captionsData = JSON.parse(scriptElement.textContent);
|
|
529
612
|
} catch {}
|
|
530
613
|
} else if (this.customCaptionsDataTask.value) captionsData = this.customCaptionsDataTask.value;
|
|
531
|
-
if (!captionsData)
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
614
|
+
if (!captionsData) {
|
|
615
|
+
if (!this.captionsData && !this.captionsScript && !this.captionsSrc) this.#cachedIntrinsicDurationMs = void 0;
|
|
616
|
+
return;
|
|
617
|
+
}
|
|
618
|
+
let result;
|
|
619
|
+
if (captionsData.segments.length === 0 && captionsData.word_segments.length === 0) result = 0;
|
|
620
|
+
else {
|
|
621
|
+
const maxSegmentEnd = captionsData.segments.length > 0 ? captionsData.segments.reduce((max, s) => s.end > max ? s.end : max, 0) : 0;
|
|
622
|
+
const maxWordEnd = captionsData.word_segments.length > 0 ? captionsData.word_segments.reduce((max, w) => w.end > max ? w.end : max, 0) : 0;
|
|
623
|
+
result = Math.max(maxSegmentEnd, maxWordEnd) * 1e3;
|
|
624
|
+
}
|
|
625
|
+
this.#cachedIntrinsicDurationMs = result;
|
|
626
|
+
return result;
|
|
536
627
|
}
|
|
537
628
|
get hasOwnDuration() {
|
|
538
629
|
return !!(this.captionsData || this.captionsScript || this.customCaptionsDataTask.value);
|