1414
1515import { CoreUtils } from '@services/utils/utils' ;
1616import { ElementController } from './ElementController' ;
17+ import videojs from 'video.js' ;
18+ import { CoreDom } from '@singletons/dom' ;
19+ import { CorePromisedValue } from '@classes/promised-value' ;
20+ import { CoreEventObserver , CoreEvents } from '@singletons/events' ;
1721
1822/**
1923 * Wrapper class to control the interactivity of a media element.
@@ -25,6 +29,10 @@ export class MediaElementController extends ElementController {
2529 private playing ?: boolean ;
2630 private playListener ?: ( ) => void ;
2731 private pauseListener ?: ( ) => void ;
32+ private jsPlayer = new CorePromisedValue < VideoJSPlayer | null > ( ) ;
33+ private jsPlayerListener ?: CoreEventObserver ;
34+ private shouldEnable = false ;
35+ private shouldDisable = false ;
2836
2937 constructor ( media : HTMLMediaElement , enabled : boolean ) {
3038 super ( enabled ) ;
@@ -34,48 +42,127 @@ export class MediaElementController extends ElementController {
3442
3543 media . autoplay = false ;
3644
45+ if ( CoreDom . mediaUsesJavascriptPlayer ( media ) ) {
46+ const player = this . searchJSPlayer ( ) ;
47+ if ( player ) {
48+ this . jsPlayer . resolve ( player ) ;
49+ } else {
50+ this . jsPlayerListener = CoreEvents . on ( CoreEvents . JS_PLAYER_CREATED , data => {
51+ if ( data . element === media ) {
52+ this . jsPlayerListener ?. off ( ) ;
53+ this . jsPlayer . resolve ( data . player as VideoJSPlayer ) ;
54+ }
55+ } ) ;
56+ }
57+ } else {
58+ this . jsPlayer . resolve ( null ) ;
59+ }
60+
3761 enabled && this . onEnabled ( ) ;
3862 }
3963
4064 /**
4165 * @inheritdoc
4266 */
43- onEnabled ( ) : void {
67+ async onEnabled ( ) : Promise < void > {
68+ this . shouldEnable = true ;
69+ this . shouldDisable = false ;
70+
71+ const jsPlayer = await this . jsPlayer ;
72+
73+ if ( ! this . shouldEnable || this . destroyed ) {
74+ return ;
75+ }
76+
4477 const ready = this . playing ?? this . autoplay
45- ? this . media . play ( )
78+ ? ( jsPlayer ?? this . media ) . play ( )
4679 : Promise . resolve ( ) ;
4780
48- ready
49- . then ( ( ) => this . addPlaybackEventListeners ( ) )
50- . catch ( error => CoreUtils . logUnhandledError ( 'Error enabling media element' , error ) ) ;
81+ try {
82+ await ready ;
83+
84+ this . addPlaybackEventListeners ( jsPlayer ) ;
85+ } catch ( error ) {
86+ CoreUtils . logUnhandledError ( 'Error enabling media element' , error ) ;
87+ }
5188 }
5289
5390 /**
5491 * @inheritdoc
5592 */
5693 async onDisabled ( ) : Promise < void > {
57- this . removePlaybackEventListeners ( ) ;
94+ this . shouldDisable = true ;
95+ this . shouldEnable = false ;
5896
59- this . media . pause ( ) ;
97+ const jsPlayer = await this . jsPlayer ;
98+
99+ if ( ! this . shouldDisable || this . destroyed ) {
100+ return ;
101+ }
102+
103+ this . removePlaybackEventListeners ( jsPlayer ) ;
104+
105+ ( jsPlayer ?? this . media ) . pause ( ) ;
106+ }
107+
108+ /**
109+ * @inheritdoc
110+ */
111+ async onDestroy ( ) : Promise < void > {
112+ const jsPlayer = await this . jsPlayer ;
113+
114+ this . removePlaybackEventListeners ( jsPlayer ) ;
115+ jsPlayer ?. dispose ( ) ;
60116 }
61117
62118 /**
63119 * Start listening playback events.
120+ *
121+ * @param jsPlayer Javascript player instance (if any).
64122 */
65- private addPlaybackEventListeners ( ) : void {
66- this . media . addEventListener ( 'play' , this . playListener = ( ) => this . playing = true ) ;
67- this . media . addEventListener ( 'pause' , this . pauseListener = ( ) => this . playing = false ) ;
123+ private addPlaybackEventListeners ( jsPlayer : VideoJSPlayer | null ) : void {
124+ if ( jsPlayer ) {
125+ jsPlayer . on ( 'play' , this . playListener = ( ) => this . playing = true ) ;
126+ jsPlayer . on ( 'pause' , this . pauseListener = ( ) => this . playing = false ) ;
127+ } else {
128+ this . media . addEventListener ( 'play' , this . playListener = ( ) => this . playing = true ) ;
129+ this . media . addEventListener ( 'pause' , this . pauseListener = ( ) => this . playing = false ) ;
130+ }
68131 }
69132
70133 /**
71134 * Stop listening playback events.
135+ *
136+ * @param jsPlayer Javascript player instance (if any).
72137 */
73- private removePlaybackEventListeners ( ) : void {
74- this . playListener && this . media . removeEventListener ( 'play' , this . playListener ) ;
75- this . pauseListener && this . media . removeEventListener ( 'pause' , this . pauseListener ) ;
138+ private removePlaybackEventListeners ( jsPlayer : VideoJSPlayer | null ) : void {
139+ if ( jsPlayer ) {
140+ this . playListener && jsPlayer . off ( 'play' , this . playListener ) ;
141+ this . pauseListener && jsPlayer . off ( 'pause' , this . pauseListener ) ;
142+ } else {
143+ this . playListener && this . media . removeEventListener ( 'play' , this . playListener ) ;
144+ this . pauseListener && this . media . removeEventListener ( 'pause' , this . pauseListener ) ;
145+ }
76146
77147 delete this . playListener ;
78148 delete this . pauseListener ;
79149 }
80150
151+ /**
152+ * Search JS player instance.
153+ *
154+ * @returns Player instance if found.
155+ */
156+ private searchJSPlayer ( ) : VideoJSPlayer | undefined {
157+ return videojs . getPlayer ( this . media . id ) || videojs . getPlayer ( this . media . id . replace ( '_html5_api' , '' ) ) ;
158+ }
159+
81160}
161+
162+ type VideoJSPlayer = {
163+ play : ( ) => Promise < void > ;
164+ pause : ( ) => Promise < void > ;
165+ on : ( name : string , callback : ( ev : Event ) => void ) => void ;
166+ off : ( name : string , callback : ( ev : Event ) => void ) => void ;
167+ dispose : ( ) => void ;
168+ } ;
0 commit comments