@@ -39,6 +39,9 @@ declare global {
39
39
interface Window { YT : typeof YT | undefined ; }
40
40
}
41
41
42
+ export const DEFAULT_PLAYER_WIDTH = 640 ;
43
+ export const DEFAULT_PLAYER_HEIGHT = 390 ;
44
+
42
45
// The native YT.Player doesn't expose the set videoId, but we need it for
43
46
// convenience.
44
47
interface Player extends YT . Player {
@@ -62,17 +65,33 @@ type UninitializedPlayer = Pick<Player, 'videoId' | 'destroy' | 'addEventListene
62
65
} )
63
66
export class YouTubePlayer implements AfterViewInit , OnDestroy {
64
67
/** YouTube Video ID to view */
65
- get videoId ( ) : string | undefined {
66
- return this . _player && this . _player . videoId ;
67
- }
68
-
69
68
@Input ( )
69
+ get videoId ( ) : string | undefined { return this . _player && this . _player . videoId ; }
70
70
set videoId ( videoId : string | undefined ) {
71
71
this . _videoId . emit ( videoId ) ;
72
72
}
73
-
74
73
private _videoId = new EventEmitter < string | undefined > ( ) ;
75
74
75
+ /** Height of video player */
76
+ @Input ( )
77
+ get height ( ) : number | undefined { return this . _height ; }
78
+ set height ( height : number | undefined ) {
79
+ this . _height = height || DEFAULT_PLAYER_HEIGHT ;
80
+ this . _heightObs . emit ( this . _height ) ;
81
+ }
82
+ private _height = DEFAULT_PLAYER_HEIGHT ;
83
+ private _heightObs = new EventEmitter < number > ( ) ;
84
+
85
+ /** Width of video player */
86
+ @Input ( )
87
+ get width ( ) : number | undefined { return this . _width ; }
88
+ set width ( width : number | undefined ) {
89
+ this . _width = width || DEFAULT_PLAYER_WIDTH ;
90
+ this . _widthObs . emit ( this . _width ) ;
91
+ }
92
+ private _width = DEFAULT_PLAYER_WIDTH ;
93
+ private _widthObs = new EventEmitter < number > ( ) ;
94
+
76
95
/** Outputs are direct proxies from the player itself. */
77
96
@Output ( ) ready = new EventEmitter < YT . PlayerEvent > ( ) ;
78
97
@Output ( ) stateChange = new EventEmitter < YT . OnStateChangeEvent > ( ) ;
@@ -94,17 +113,25 @@ export class YouTubePlayer implements AfterViewInit, OnDestroy {
94
113
'Please install the YouTube Player API Reference for iframe Embeds: ' +
95
114
'https://developers.google.com/youtube/iframe_api_reference' ) ;
96
115
}
116
+ // Add initial values to all of the inputs.
117
+ const widthObs = this . _widthObs . pipe ( startWith ( this . _width ) ) ;
118
+ const heightObs = this . _heightObs . pipe ( startWith ( this . _height ) ) ;
119
+
97
120
/** An observable of the currently loaded player. */
98
121
const playerObs =
99
122
createPlayerObservable (
100
123
this . _youtubeContainer ,
101
124
this . _videoId ,
125
+ widthObs ,
126
+ heightObs ,
102
127
this . createEventsBoundInZone ( ) ,
103
128
) . pipe ( waitUntilReady ( ) , takeUntil ( this . _destroyed ) , publish ( ) ) ;
104
129
105
130
/** Set up side effects to bind inputs to the player. */
106
131
playerObs . subscribe ( player => this . _player = player ) ;
107
132
133
+ bindSizeToPlayer ( playerObs , widthObs , heightObs ) ;
134
+
108
135
bindCueVideoCall ( playerObs , this . _videoId , this . _destroyed ) ;
109
136
110
137
// After all of the subscriptions are set up, connect the observable.
@@ -146,6 +173,16 @@ export class YouTubePlayer implements AfterViewInit, OnDestroy {
146
173
}
147
174
}
148
175
176
+ /** Listens to changes to the given width and height and sets it on the player. */
177
+ function bindSizeToPlayer (
178
+ playerObs : Observable < YT . Player | undefined > ,
179
+ widthObs : Observable < number > ,
180
+ heightObs : Observable < number >
181
+ ) {
182
+ return combineLatest ( playerObs , widthObs , heightObs )
183
+ . subscribe ( ( [ player , width , height ] ) => player && player . setSize ( width , height ) ) ;
184
+ }
185
+
149
186
/**
150
187
* Returns an observable that emits the loaded player once it's ready. Certain properties/methods
151
188
* won't be available until the iframe finishes loading.
@@ -190,13 +227,16 @@ function fromPlayerOnReady(player: UninitializedPlayer): Observable<Player> {
190
227
function createPlayerObservable (
191
228
youtubeContainer : Observable < HTMLElement > ,
192
229
videoIdObs : Observable < string | undefined > ,
230
+ widthObs : Observable < number > ,
231
+ heightObs : Observable < number > ,
193
232
events : YT . Events ,
194
233
) : Observable < UninitializedPlayer | undefined > {
195
234
196
235
const playerOptions =
197
236
videoIdObs
198
237
. pipe (
199
- map ( ( videoId ) => videoId ? ( { videoId, events} ) : undefined ) ,
238
+ withLatestFrom ( combineLatest ( widthObs , heightObs ) ) ,
239
+ map ( ( [ videoId , [ width , height ] ] ) => videoId ? ( { videoId, width, height, events} ) : undefined ) ,
200
240
) ;
201
241
202
242
return combineLatest ( youtubeContainer , playerOptions )
0 commit comments