UNPKG

59 kBJavaScriptView Raw
1import { Overlay, OverlayModule } from '@angular/cdk/overlay';
2import { DOCUMENT, CommonModule } from '@angular/common';
3import { Pipe, Component, ChangeDetectionStrategy, ViewEncapsulation, ChangeDetectorRef, Input, HostBinding, EventEmitter, Renderer2, Output, ViewChild, ContentChild, InjectionToken, Inject, ElementRef, HostListener, Injectable, Injector, ɵɵdefineInjectable, ɵɵinject, INJECTOR, NgModule, Directive, TemplateRef, ViewContainerRef } from '@angular/core';
4import { timer, Subject, Observable, fromEvent } from 'rxjs';
5import { tap, map, takeUntil, startWith, debounceTime } from 'rxjs/operators';
6import { PortalInjector, ComponentPortal, TemplatePortal } from '@angular/cdk/portal';
7import { Directionality, BidiModule } from '@angular/cdk/bidi';
8import { DOWN_ARROW, UP_ARROW, LEFT_ARROW, RIGHT_ARROW, PAGE_UP, PAGE_DOWN } from '@angular/cdk/keycodes';
9
10/**
11 * @fileoverview added by tsickle
12 * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
13 */
14class ParseDurationPipe {
15 // tslint:disable-next-line:no-any
16 /**
17 * @param {?} value
18 * @param {?=} format
19 * @return {?}
20 */
21 transform(value, format = 'HH:MM:SS') {
22 /** @type {?} */
23 const coerceInteger = Number.parseInt(value, 10);
24 if (Number.isNaN(coerceInteger)) {
25 return 'N/A';
26 }
27 /** @type {?} */
28 const seconds = coerceInteger % 60;
29 /** @type {?} */
30 const minutes = Math.floor(coerceInteger / 60) % 60;
31 /** @type {?} */
32 const hours = Math.floor(coerceInteger / 3600);
33 return format
34 .split(':')
35 .map((/**
36 * @param {?} segment
37 * @return {?}
38 */
39 segment => {
40 const { length } = segment;
41 if (length === 0) {
42 throw new TypeError('Invalid format. Empty segment.');
43 }
44 if (length > 2) {
45 throw new TypeError('Invalid format for segment ' + segment);
46 }
47 if (segment.length === 2 && segment[0] !== segment[1]) {
48 throw new TypeError('Invalid format for segment ' + segment);
49 }
50 /** @type {?} */
51 let val;
52 switch (segment[0]) {
53 case 'H':
54 val = hours.toString();
55 break;
56 case 'M':
57 val = minutes.toString();
58 break;
59 case 'S':
60 val = seconds.toString();
61 break;
62 default:
63 throw new TypeError('Invalid format for segment ' + segment);
64 }
65 while (val.length < length) {
66 val = '0' + val;
67 }
68 return val;
69 }))
70 .join(':');
71 }
72}
73ParseDurationPipe.decorators = [
74 { type: Pipe, args: [{
75 name: 'bmParseDuration',
76 },] }
77];
78
79/**
80 * @fileoverview added by tsickle
81 * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
82 */
83class BMMediaOutputComponent {
84 /**
85 * @param {?} changeDetectorRef
86 */
87 constructor(changeDetectorRef) {
88 this.changeDetectorRef = changeDetectorRef;
89 this.format = 'MM:SS';
90 this.formater = new ParseDurationPipe();
91 this.changeDetectorRef.detach();
92 }
93 /**
94 * @param {?} v
95 * @return {?}
96 */
97 set time(v) {
98 if (v || v === 0) {
99 this.innerTime = this.formater.transform(Math.max(0, v), this.format);
100 this.changeDetectorRef.markForCheck();
101 }
102 }
103}
104BMMediaOutputComponent.decorators = [
105 { type: Component, args: [{
106 selector: 'bm-media-output',
107 template: "<span class=\"bm-media-output__content\">{{innerTime}}</span>",
108 changeDetection: ChangeDetectionStrategy.OnPush,
109 encapsulation: ViewEncapsulation.None,
110 styles: [".bm-media-output__content{padding:0 .4em}"]
111 }] }
112];
113/** @nocollapse */
114BMMediaOutputComponent.ctorParameters = () => [
115 { type: ChangeDetectorRef }
116];
117BMMediaOutputComponent.propDecorators = {
118 format: [{ type: Input }],
119 time: [{ type: Input }]
120};
121
122/**
123 * @fileoverview added by tsickle
124 * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
125 */
126class ProgressBarComponent {
127 /**
128 * @param {?} _cdr
129 */
130 constructor(_cdr) {
131 this._cdr = _cdr;
132 this.min = 0;
133 this.role = 'progressbar';
134 this.max = 100;
135 /**
136 * Sets if the bar should display or not an animation after value changes
137 */
138 this.staticBar = false;
139 this._value = 0;
140 }
141 /**
142 * @param {?} v
143 * @return {?}
144 */
145 set value(v) {
146 this._value = Math.min(Math.max(0, Number.isNaN(v) ? 0 : v), this.max);
147 this.innerWidth = Math.round((10000 * this._value) / this.max) / 100;
148 this._cdr.markForCheck();
149 }
150 /**
151 * @return {?}
152 */
153 get value() {
154 return this._value;
155 }
156}
157ProgressBarComponent.decorators = [
158 { type: Component, args: [{
159 selector: 'bm-progress',
160 template: "<div [ngStyle]=\"{ 'width.%': innerWidth }\" class=\"bm-inner-progress-bar\"></div>\n",
161 changeDetection: ChangeDetectionStrategy.OnPush,
162 styles: [":host{height:.5em;border-radius:.4em;background-color:var(--secondary-color-hover,#959494);display:inline-block;max-width:100%;min-width:10em;position:relative}:host(:not([static=true])) .bm-inner-progress-bar{transition:width 2s}.bm-inner-progress-bar{height:.5em;border-radius:.4em;background-color:var(--header-background-color,#3e71ad)}"]
163 }] }
164];
165/** @nocollapse */
166ProgressBarComponent.ctorParameters = () => [
167 { type: ChangeDetectorRef }
168];
169ProgressBarComponent.propDecorators = {
170 min: [{ type: HostBinding, args: ['attr.aria-valuemin',] }],
171 role: [{ type: HostBinding, args: ['attr.role',] }],
172 max: [{ type: HostBinding, args: ['attr.aria-valuemax',] }, { type: Input }],
173 value: [{ type: HostBinding, args: ['attr.aria-valuenow',] }, { type: Input }],
174 staticBar: [{ type: Input }, { type: HostBinding, args: ['attr.static',] }]
175};
176
177/**
178 * @fileoverview added by tsickle
179 * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
180 */
181class BMATAudioPlayerComponent {
182 /**
183 * @param {?} _renderer
184 */
185 constructor(_renderer) {
186 this._renderer = _renderer;
187 // Forward attributes to audio
188 this.autoplay = false;
189 this.controls = false;
190 this.loop = false;
191 this.muted = false;
192 this.preload = 'none';
193 /**
194 * Echo of play HTMLAudioElement event
195 */
196 this.play = new EventEmitter();
197 /**
198 * Echo of play HTMLAudioElement event
199 */
200 this.pause = new EventEmitter();
201 this.isDisabled = true;
202 this.isLoading = false;
203 this.isPlaying = false;
204 this._isMouseDown = false;
205 this._progressUpdater$ = timer(500, 500).pipe(tap(this.calculateElapsed.bind(this)));
206 }
207 /**
208 * @param {?} v
209 * @return {?}
210 */
211 set src(v) {
212 this._src = v;
213 this.isDisabled = !v;
214 }
215 /**
216 * @return {?}
217 */
218 get src() {
219 return this._src;
220 }
221 /**
222 * @return {?}
223 */
224 ngAfterContentInit() {
225 if (this.progressBar) {
226 this.progressBar.value = 0;
227 this.progressBar.staticBar = true;
228 }
229 if (this.mediaOutput) {
230 this.mediaOutput.time = 0;
231 }
232 }
233 /**
234 * @param {?} event
235 * @return {?}
236 */
237 onButtonMousedown(event) {
238 event.preventDefault();
239 this._mouseDownTime = new Date().getTime();
240 this._isMouseDown = true;
241 this._playBackTimerSubscription = timer(BMATAudioPlayerComponent.HOLD_TIME).subscribe((/**
242 * @return {?}
243 */
244 () => {
245 /** @type {?} */
246 const now = new Date().getTime();
247 /** @type {?} */
248 const deltaTime = now - this._mouseDownTime;
249 if (this._isMouseDown && deltaTime > BMATAudioPlayerComponent.HOLD_TIME) {
250 this._renderer.setProperty(this.audioElement.nativeElement, 'playbackRate', BMATAudioPlayerComponent.ACCELERATED_RATE);
251 }
252 }));
253 }
254 /**
255 * @param {?} event
256 * @return {?}
257 */
258 onloadeddata(event) {
259 event.stopPropagation();
260 this.isLoading = true;
261 }
262 /**
263 * @return {?}
264 */
265 ondurationchange() {
266 this.calculateElapsed();
267 }
268 /**
269 * @param {?} event
270 * @return {?}
271 */
272 oncanplay(event) {
273 event.stopPropagation();
274 this.isLoading = false;
275 }
276 /**
277 * @param {?} event
278 * @return {?}
279 */
280 onplay(event) {
281 event.stopPropagation();
282 this.isPlaying = true;
283 this.play.emit();
284 if (this.progressBar) {
285 this._timerSubscription = this._progressUpdater$.subscribe();
286 }
287 }
288 /**
289 * @param {?} event
290 * @return {?}
291 */
292 onplaying(event) {
293 event.stopPropagation();
294 this.isPlaying = true;
295 this.isLoading = false;
296 }
297 /**
298 * @param {?} event
299 * @return {?}
300 */
301 onpause(event) {
302 event.stopPropagation();
303 this.isPlaying = false;
304 this.pause.emit();
305 if (this._timerSubscription) {
306 this._timerSubscription.unsubscribe();
307 }
308 }
309 /**
310 * @param {?} event
311 * @return {?}
312 */
313 onwaiting(event) {
314 event.stopPropagation();
315 this.isLoading = true;
316 }
317 /**
318 * @param {?} event
319 * @return {?}
320 */
321 onended(event) {
322 this.isPlaying = false;
323 event.stopPropagation();
324 if (this._timerSubscription) {
325 this._timerSubscription.unsubscribe();
326 this.progressBar.value = 100;
327 }
328 }
329 /**
330 * @return {?}
331 */
332 togglePlay() {
333 this._renderer.setProperty(this.audioElement.nativeElement, 'playbackRate', 1);
334 this._isMouseDown = false;
335 /** @type {?} */
336 const now = new Date().getTime();
337 /** @type {?} */
338 const deltaTime = now - this._mouseDownTime;
339 this._playBackTimerSubscription.unsubscribe();
340 if (deltaTime > BMATAudioPlayerComponent.HOLD_TIME) {
341 return;
342 }
343 if (this.audioElement && this.audioElement.nativeElement) {
344 if (this.isPlaying) {
345 this.audioElement.nativeElement.pause();
346 }
347 else {
348 this.audioElement.nativeElement.play();
349 }
350 }
351 }
352 /**
353 * @private
354 * @return {?}
355 */
356 calculateElapsed() {
357 /** @type {?} */
358 const nativeAudio = this.audioElement.nativeElement;
359 if (this.progressBar) {
360 /** @type {?} */
361 const currentPosition = Math.min(100, (100 * nativeAudio.currentTime) / nativeAudio.duration);
362 this.progressBar.value =
363 !Number.isNaN(currentPosition) && currentPosition > 0
364 ? currentPosition
365 : 0;
366 }
367 if (this.mediaOutput) {
368 this.mediaOutput.time = nativeAudio.currentTime;
369 }
370 }
371}
372/**
373 * Threshold of time to consider a mousedown a hold event.
374 */
375BMATAudioPlayerComponent.HOLD_TIME = 200;
376/**
377 * Playback rate when playing audio in accelerated mode.
378 */
379BMATAudioPlayerComponent.ACCELERATED_RATE = 3;
380BMATAudioPlayerComponent.decorators = [
381 { type: Component, args: [{
382 selector: 'bm-audio-player',
383 template: "<audio\n #audio\n (canplay)=\"oncanplay($event)\"\n (durationchange)=\"ondurationchange()\"\n (ended)=\"onended($event)\"\n (loadeddata)=\"onloadeddata($event)\"\n (pause)=\"onpause($event)\"\n (play)=\"onplay($event)\"\n (playing)=\"onplaying($event)\"\n (waiting)=\"onwaiting($event)\"\n [autoplay]=\"autoplay\"\n [controls]=\"controls\"\n [loop]=\"loop\"\n [muted]=\"muted\"\n [preload]=\"preload\"\n [src]=\"src\"\n></audio>\n<button\n (mousedown)=\"onButtonMousedown($event)\"\n (mouseup)=\"togglePlay()\"\n [class.bm-audio-player__button--playing]=\"isPlaying\"\n [disabled]=\"isDisabled\"\n aria-label=\"Toggle audio play\"\n class=\"bm-audio-player__button\"\n i18n-aria-label\n>\n <i\n [ngClass]=\"{\n 'fab fa-youtube': !isLoading,\n 'fas fa-spinner': isLoading\n }\"\n ></i>\n</button>\n<ng-content select=\"bm-progress, bm-media-output\"></ng-content>\n",
384 changeDetection: ChangeDetectionStrategy.OnPush,
385 // tslint:disable-next-line:use-component-view-encapsulation
386 encapsulation: ViewEncapsulation.None,
387 styles: ["bm-audio-player{display:inline-flex;align-items:center}.bm-audio-player__button{border:0;background:0 0;padding:0;font-size:2rem;margin:0 .2em;color:var(--secondary-color,#bcbcbc)}.bm-audio-player__button--playing{color:var(--header-background-color,#3e71ad)}.bm-audio-player__button[disabled]{color:var(--header-color,#f8f8f8)}.fa-spinner{-webkit-transform-origin:50% 50%;transform-origin:50% 50%;-webkit-animation:2s linear infinite spin;animation:2s linear infinite spin}@-webkit-keyframes spin{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes spin{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}", "bm-progress bm-audio-player,bm-progress bm-media-output{margin:0 .2em}"]
388 }] }
389];
390/** @nocollapse */
391BMATAudioPlayerComponent.ctorParameters = () => [
392 { type: Renderer2 }
393];
394BMATAudioPlayerComponent.propDecorators = {
395 autoplay: [{ type: Input }],
396 controls: [{ type: Input }],
397 loop: [{ type: Input }],
398 muted: [{ type: Input }],
399 preload: [{ type: Input }],
400 src: [{ type: Input }],
401 play: [{ type: Output }],
402 pause: [{ type: Output }],
403 audioElement: [{ type: ViewChild, args: ['audio', { static: true },] }],
404 progressBar: [{ type: ContentChild, args: [ProgressBarComponent, { static: true },] }],
405 mediaOutput: [{ type: ContentChild, args: [BMMediaOutputComponent, { static: true },] }]
406};
407
408/**
409 * @fileoverview added by tsickle
410 * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
411 */
412/**
413 * Injection token to provide the
414 * @type {?}
415 */
416const CONNECTED_PLAYER_CLOSE_REQUEST = new InjectionToken('bmat.angular.media-players.connected-player-close-request');
417
418/**
419 * @fileoverview added by tsickle
420 * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
421 */
422/**
423 * Injection token to provide the
424 * @type {?}
425 */
426const CONNECTED_PLAYER_SRC = new InjectionToken('bmat.angular.media-players.connected-player-src');
427
428/**
429 * @fileoverview added by tsickle
430 * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
431 */
432/**
433 * Injection token to provide the
434 * @type {?}
435 */
436const CONNECTED_PLAYER_VOLUME = new InjectionToken('bmat.angular.media-players.connected-player-volume');
437
438/**
439 * @fileoverview added by tsickle
440 * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
441 */
442/**
443 * Connected video player, to be called using the remote service
444 */
445class ConnectedVideoPlayerComponent {
446 /**
447 * @param {?} src
448 * @param {?} _closeRequest
449 * @param {?} _document
450 * @param {?} volume
451 * @param {?} _cdr
452 */
453 constructor(src,
454 // tslint:disable-next-line:no-any
455 _closeRequest, _document, volume, _cdr) {
456 this._document = _document;
457 this._cdr = _cdr;
458 this.autoplay = true;
459 this._focusWithin = false;
460 this.src = src;
461 this._closeRequest = _closeRequest;
462 this.volume = volume;
463 }
464 /**
465 * @return {?}
466 */
467 get focusWithin() {
468 return this._focusWithin;
469 }
470 /**
471 * @return {?}
472 */
473 onFocusin() {
474 this._focusWithin = true;
475 }
476 /**
477 * @return {?}
478 */
479 onFocusout() {
480 this._focusWithin = false;
481 }
482 /**
483 * @param {?} e
484 * @return {?}
485 */
486 onDocumentKeydown(e) {
487 if (e.key === 'Escape') {
488 this._closeRequest();
489 }
490 }
491 /**
492 * @return {?}
493 */
494 close() {
495 this._closeRequest();
496 }
497 /**
498 * @return {?}
499 */
500 onMediaEnded() {
501 this._closeRequest();
502 }
503 /**
504 * @return {?}
505 */
506 checkAfterVideoElement() {
507 this._cdr.markForCheck();
508 }
509 /**
510 * @return {?}
511 */
512 onVideoPlay() {
513 this.isPlaying = true;
514 this._cdr.markForCheck();
515 }
516 /**
517 * @return {?}
518 */
519 onVideoPause() {
520 this.isPlaying = false;
521 this._cdr.markForCheck();
522 }
523 /**
524 * @return {?}
525 */
526 togglePlay() {
527 if (this._videoElement) {
528 if (this._videoElement.nativeElement.paused) {
529 this._videoElement.nativeElement.play();
530 }
531 else {
532 this._videoElement.nativeElement.pause();
533 }
534 }
535 }
536 /**
537 * @param {?} $event
538 * @return {?}
539 */
540 onSliderSeek($event) {
541 if (this._videoElement) {
542 this._videoElement.nativeElement.currentTime = $event;
543 }
544 }
545 /**
546 * @return {?}
547 */
548 toggleFullScreen() {
549 if (this._fullscreenWrapper &&
550 this._fullscreenWrapper.nativeElement.requestFullscreen) {
551 if (this._document.fullscreenElement) {
552 this._document.exitFullscreen();
553 }
554 else {
555 this._fullscreenWrapper.nativeElement
556 .requestFullscreen()
557 .catch((/**
558 * @param {?} err
559 * @return {?}
560 */
561 err => console.error(err)));
562 }
563 }
564 }
565 /**
566 * @return {?}
567 */
568 displayFullScreenBtn() {
569 return (this._fullscreenWrapper &&
570 this._fullscreenWrapper.nativeElement.requestFullscreen);
571 }
572}
573ConnectedVideoPlayerComponent.decorators = [
574 { type: Component, args: [{
575 selector: 'bm-connected-video-player',
576 template: "<div\n #fullscreenWrapper\n class=\"bm-connected-video-player-controls__fullscreen-wrap\"\n>\n <video\n (durationchange)=\"checkAfterVideoElement()\"\n (ended)=\"onMediaEnded()\"\n (pause)=\"onVideoPause()\"\n (play)=\"onVideoPlay()\"\n (timeupdate)=\"checkAfterVideoElement()\"\n [autoplay]=\"autoplay\"\n [src]=\"src\"\n [volume]=\"volume\"\n #videoElement\n class=\"bm-connected-video-player\"\n nocontrols\n ></video>\n <div\n class=\"bm-connected-video-player-controls bm-connected-video-player-controls--top\"\n style=\"text-align: right;\"\n >\n <button\n type=\"button\"\n class=\"bm-connected-video-player-controls__btn\"\n i18n-title\n title=\"Close video\"\n (click)=\"close()\"\n >\n <svg\n aria-hidden=\"true\"\n data-prefix=\"fas\"\n data-icon=\"times\"\n class=\"bm-connected-video-player__icon\"\n role=\"img\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 352 512\"\n >\n <path\n fill=\"currentColor\"\n d=\"M242.72 256l100.07-100.07c12.28-12.28 12.28-32.19 0-44.48l-22.24-22.24c-12.28-12.28-32.19-12.28-44.48 0L176 189.28 75.93 89.21c-12.28-12.28-32.19-12.28-44.48 0L9.21 111.45c-12.28 12.28-12.28 32.19 0 44.48L109.28 256 9.21 356.07c-12.28 12.28-12.28 32.19 0 44.48l22.24 22.24c12.28 12.28 32.2 12.28 44.48 0L176 322.72l100.07 100.07c12.28 12.28 32.2 12.28 44.48 0l22.24-22.24c12.28-12.28 12.28-32.19 0-44.48L242.72 256z\"\n ></path>\n </svg>\n </button>\n </div>\n <div\n class=\"bm-connected-video-player-controls bm-connected-video-player-controls--bottom\"\n >\n <bm-media-progress-slider\n style=\"width: 100%;\"\n [duration]=\"videoElement.duration\"\n [value]=\"videoElement.currentTime\"\n (seek)=\"onSliderSeek($event)\"\n ></bm-media-progress-slider>\n <div class=\"bm-connected-video-player-controls__second-level\">\n <div class=\"bm-connected-video-player-controls__play-ctrl\">\n <button\n type=\"button\"\n class=\"bm-connected-video-player-controls__btn\"\n i18n-title\n title=\"Toggle play\"\n (click)=\"togglePlay()\"\n >\n <ng-template #playIcon>\n <svg\n aria-hidden=\"true\"\n data-prefix=\"fas\"\n data-icon=\"play\"\n class=\"bm-connected-video-player__icon\"\n role=\"img\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 448 512\"\n >\n <path\n fill=\"currentColor\"\n d=\"M424.4 214.7L72.4 6.6C43.8-10.3 0 6.1 0 47.9V464c0 37.5 40.7 60.1 72.4 41.3l352-208c31.4-18.5 31.5-64.1 0-82.6z\"\n ></path>\n </svg>\n </ng-template>\n <svg\n *ngIf=\"isPlaying; else playIcon\"\n aria-hidden=\"true\"\n data-prefix=\"fas\"\n data-icon=\"play\"\n class=\"bm-connected-video-player__icon\"\n role=\"img\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 448 512\"\n >\n <path\n fill=\"currentColor\"\n d=\"M144 479H48c-26.5 0-48-21.5-48-48V79c0-26.5 21.5-48 48-48h96c26.5 0 48 21.5 48 48v352c0 26.5-21.5 48-48 48zm304-48V79c0-26.5-21.5-48-48-48h-96c-26.5 0-48 21.5-48 48v352c0 26.5 21.5 48 48 48h96c26.5 0 48-21.5 48-48z\"\n ></path>\n </svg>\n </button>\n <span class=\"bm-connected-video-player-controls__time-indicator\">{{\n videoElement.currentTime | bmParseDuration\n }}</span>\n /\n <span class=\"bm-connected-video-player-controls__time-indicator\">{{\n videoElement.duration | bmParseDuration\n }}</span>\n </div>\n <div>\n <button\n *ngIf=\"displayFullScreenBtn()\"\n type=\"button\"\n class=\"bm-connected-video-player-controls__btn\"\n i18n-title\n title=\"Toggle fullscreen\"\n (click)=\"toggleFullScreen()\"\n >\n <svg\n aria-hidden=\"true\"\n data-prefix=\"fas\"\n data-icon=\"expand-alt\"\n role=\"img\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 448 512\"\n class=\"bm-connected-video-player__icon\"\n >\n <path\n fill=\"currentColor\"\n d=\"M212.686 315.314L120 408l32.922 31.029c15.12 15.12 4.412 40.971-16.97 40.971h-112C10.697 480 0 469.255 0 456V344c0-21.382 25.803-32.09 40.922-16.971L72 360l92.686-92.686c6.248-6.248 16.379-6.248 22.627 0l25.373 25.373c6.249 6.248 6.249 16.378 0 22.627zm22.628-118.628L328 104l-32.922-31.029C279.958 57.851 290.666 32 312.048 32h112C437.303 32 448 42.745 448 56v112c0 21.382-25.803 32.09-40.922 16.971L376 152l-92.686 92.686c-6.248 6.248-16.379 6.248-22.627 0l-25.373-25.373c-6.249-6.248-6.249-16.378 0-22.627z\"\n class=\"\"\n ></path>\n </svg>\n </button>\n </div>\n </div>\n </div>\n</div>\n",
577 changeDetection: ChangeDetectionStrategy.OnPush,
578 styles: [":host{display:inline-block;position:relative;overflow:hidden;max-width:100%;width:64em;height:36em;background-color:#000}:host(.focus-within) .bm-connected-video-player-controls--bottom,:host(.focus-within) .bm-connected-video-player-controls--top,:host(:hover) .bm-connected-video-player-controls--bottom,:host(:hover) .bm-connected-video-player-controls--top{-webkit-transform:translateY(0);transform:translateY(0)}.bm-connected-video-player{width:100%}.bm-connected-video-player__fullscreen-wrap{position:absolute;top:0;left:0;right:0;bottom:0}.bm-connected-video-player__icon{display:inline-block;font-size:inherit;height:1.5em;width:1.1em}.bm-connected-video-player-controls{color:#fff;position:absolute;left:0;right:0;padding:.5em 1em;background-color:rgba(0,0,0,.35);transition:.2s ease-in-out}.bm-connected-video-player-controls--top{top:0;-webkit-transform:translateY(-100%);transform:translateY(-100%)}.bm-connected-video-player-controls--bottom{padding-bottom:.5em;bottom:0;-webkit-transform:translateY(100%);transform:translateY(100%)}.bm-connected-video-player-controls__play-ctrl{display:inline-flex;align-items:center}.bm-connected-video-player-controls__second-level{margin-top:.25em;display:flex;justify-content:space-between;width:100%}.bm-connected-video-player-controls__btn{color:#fff;border:0;background:0 0}.bm-connected-video-player-controls__time-indicator{width:4em;color:#fff;margin:.5em}"]
579 }] }
580];
581/** @nocollapse */
582ConnectedVideoPlayerComponent.ctorParameters = () => [
583 { type: String, decorators: [{ type: Inject, args: [CONNECTED_PLAYER_SRC,] }] },
584 { type: undefined, decorators: [{ type: Inject, args: [CONNECTED_PLAYER_CLOSE_REQUEST,] }] },
585 { type: undefined, decorators: [{ type: Inject, args: [DOCUMENT,] }] },
586 { type: Number, decorators: [{ type: Inject, args: [CONNECTED_PLAYER_VOLUME,] }] },
587 { type: ChangeDetectorRef }
588];
589ConnectedVideoPlayerComponent.propDecorators = {
590 _videoElement: [{ type: ViewChild, args: ['videoElement', { read: ElementRef, static: true },] }],
591 _fullscreenWrapper: [{ type: ViewChild, args: ['fullscreenWrapper', { read: ElementRef, static: true },] }],
592 focusWithin: [{ type: HostBinding, args: ['class.focus-within',] }],
593 onFocusin: [{ type: HostListener, args: ['focusin',] }],
594 onFocusout: [{ type: HostListener, args: ['focusout',] }],
595 onDocumentKeydown: [{ type: HostListener, args: ['document:keydown', ['$event'],] }]
596};
597
598/**
599 * @fileoverview added by tsickle
600 * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
601 */
602/** @enum {number} */
603const PlayerType = {
604 Audio: 0,
605 Video: 1,
606};
607PlayerType[PlayerType.Audio] = 'Audio';
608PlayerType[PlayerType.Video] = 'Video';
609/** @type {?} */
610const defaultOptions = {
611 playerType: PlayerType.Audio,
612 volume: 1,
613};
614/** @enum {string} */
615const ConnectedPlayerEventTypes = {
616 OPEN: 'OPEN',
617 CLOSE: 'CLOSE',
618};
619/**
620 * Remote to display always a single player connected
621 * to another component. Used in tables.
622 */
623class ConnectedMediaRemoteService {
624 /**
625 * @param {?} _injector
626 * @param {?} _overlay
627 */
628 constructor(_injector, _overlay) {
629 this._injector = _injector;
630 this._overlay = _overlay;
631 this._playerEventsSubject = new Subject();
632 }
633 /**
634 * @return {?}
635 */
636 getEvents() {
637 return new Observable((/**
638 * @param {?} observer
639 * @return {?}
640 */
641 observer => {
642 /** @type {?} */
643 const subs = this._playerEventsSubject.subscribe(observer);
644 return (/**
645 * @return {?}
646 */
647 () => {
648 subs.unsubscribe();
649 });
650 }));
651 }
652 /**
653 * @param {?} src
654 * @param {?} host
655 * @param {?=} options
656 * @return {?}
657 */
658 open(src, host, options = {}) {
659 this.close();
660 /** @type {?} */
661 const actualOptions = Object.assign({}, defaultOptions, options);
662 if (host === null && actualOptions.playerType === PlayerType.Audio) {
663 throw new TypeError('Audio players should be connected to a host.');
664 }
665 switch (actualOptions.playerType) {
666 case PlayerType.Audio:
667 this.setUpAudioPlayer(src, (/** @type {?} */ (host)), actualOptions);
668 break;
669 case PlayerType.Video:
670 this.setUpVideoPlayer(src, actualOptions);
671 break;
672 default:
673 throw new TypeError('Unknown PlayerType.');
674 }
675 this._playerEventsSubject.next({
676 kind: ConnectedPlayerEventTypes.OPEN,
677 source: host,
678 });
679 }
680 /**
681 * @return {?}
682 */
683 isOpen() {
684 return this._overlayRef.hasAttached();
685 }
686 /**
687 * @return {?}
688 */
689 close() {
690 if (this._overlayRef) {
691 this._overlayRef.dispose();
692 this._playerEventsSubject.next({
693 kind: ConnectedPlayerEventTypes.CLOSE,
694 source: null,
695 });
696 }
697 }
698 /**
699 * @private
700 * @param {?} src
701 * @param {?} host
702 * @param {?} options
703 * @return {?}
704 */
705 setUpAudioPlayer(src, host, options) {
706 /** @type {?} */
707 const domEle = host && ((/** @type {?} */ (host))).nativeElement
708 ? ((/** @type {?} */ (host))).nativeElement
709 : ((/** @type {?} */ (host)));
710 if (!domEle) {
711 throw new TypeError('Invalid host element');
712 }
713 /** @type {?} */
714 const providers = new WeakMap();
715 providers.set(CONNECTED_PLAYER_SRC, src);
716 providers.set(CONNECTED_PLAYER_VOLUME, options.volume);
717 /** @type {?} */
718 const portalInjector = new PortalInjector(this._injector, providers);
719 /** @type {?} */
720 const componentPortal = new ComponentPortal(ConnectedAudioPlayerComponent, null, portalInjector);
721 /** @type {?} */
722 const positionStrategy = this._overlay
723 .position()
724 .flexibleConnectedTo(domEle)
725 .withPositions([
726 {
727 originX: 'start',
728 originY: 'bottom',
729 overlayX: 'start',
730 overlayY: 'top',
731 },
732 {
733 originX: 'start',
734 originY: 'top',
735 overlayX: 'start',
736 overlayY: 'bottom',
737 },
738 {
739 originX: 'end',
740 originY: 'bottom',
741 overlayX: 'end',
742 overlayY: 'top',
743 },
744 {
745 originX: 'end',
746 originY: 'top',
747 overlayX: 'end',
748 overlayY: 'bottom',
749 },
750 ]);
751 /** @type {?} */
752 const scrollStrategy = this._overlay.scrollStrategies.reposition();
753 this._overlayRef = this._overlay.create({
754 positionStrategy,
755 scrollStrategy,
756 });
757 return this._overlayRef.attach(componentPortal);
758 }
759 /**
760 * @private
761 * @param {?} src
762 * @param {?} options
763 * @return {?}
764 */
765 setUpVideoPlayer(src, options) {
766 /** @type {?} */
767 const providers = new WeakMap();
768 providers.set(CONNECTED_PLAYER_SRC, src);
769 providers.set(CONNECTED_PLAYER_CLOSE_REQUEST, this.close.bind(this));
770 providers.set(CONNECTED_PLAYER_VOLUME, options.volume);
771 /** @type {?} */
772 const portalInjector = new PortalInjector(this._injector, providers);
773 /** @type {?} */
774 const componentPortal = new ComponentPortal(ConnectedVideoPlayerComponent, null, portalInjector);
775 /** @type {?} */
776 const positionStrategy = this._overlay
777 .position()
778 .global()
779 .centerHorizontally()
780 .centerVertically();
781 /** @type {?} */
782 const scrollStrategy = this._overlay.scrollStrategies.block();
783 this._overlayRef = this._overlay.create({
784 positionStrategy,
785 scrollStrategy,
786 hasBackdrop: true,
787 });
788 this._overlayRef.backdropClick().subscribe((/**
789 * @return {?}
790 */
791 () => this.close()));
792 return this._overlayRef.attach(componentPortal);
793 }
794}
795ConnectedMediaRemoteService.decorators = [
796 { type: Injectable, args: [{
797 providedIn: 'root',
798 },] }
799];
800/** @nocollapse */
801ConnectedMediaRemoteService.ctorParameters = () => [
802 { type: Injector },
803 { type: Overlay }
804];
805/** @nocollapse */ ConnectedMediaRemoteService.ngInjectableDef = ɵɵdefineInjectable({ factory: function ConnectedMediaRemoteService_Factory() { return new ConnectedMediaRemoteService(ɵɵinject(INJECTOR), ɵɵinject(Overlay)); }, token: ConnectedMediaRemoteService, providedIn: "root" });
806
807/**
808 * @fileoverview added by tsickle
809 * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
810 */
811/**
812 * Connected audio player. Created by a ComponentPortal
813 */
814class ConnectedAudioPlayerComponent {
815 /**
816 * @param {?} src
817 * @param {?} volume
818 * @param {?} _cdr
819 * @param {?} _elementRef
820 * @param {?} _remote
821 */
822 constructor(src, volume, _cdr, _elementRef, _remote) {
823 this._cdr = _cdr;
824 this._elementRef = _elementRef;
825 this._remote = _remote;
826 this.src = src;
827 this.volume = volume;
828 }
829 /**
830 * @return {?}
831 */
832 get duration() {
833 if (this._audioElement && this._audioElement.nativeElement) {
834 return this._audioElement.nativeElement.duration;
835 }
836 return 0;
837 }
838 /**
839 * @return {?}
840 */
841 get currentTime() {
842 if (this._audioElement && this._audioElement.nativeElement) {
843 return this._audioElement.nativeElement.currentTime;
844 }
845 return 0;
846 }
847 /**
848 * @param {?} e
849 * @return {?}
850 */
851 onDocumentClick(e) {
852 if (this._remote.isOpen() && !this._audioElement.nativeElement.paused) {
853 /** @type {?} */
854 let parent = (/** @type {?} */ (e.target));
855 while (parent &&
856 parent.tagName !== 'BODY' &&
857 parent !== this._elementRef.nativeElement) {
858 parent = (/** @type {?} */ (parent.parentElement));
859 }
860 if (parent !== this._elementRef.nativeElement) {
861 this._remote.close();
862 }
863 }
864 }
865 /**
866 * @param {?} e
867 * @return {?}
868 */
869 onDocumentKeydown(e) {
870 if (this._remote.isOpen() &&
871 !this._audioElement.nativeElement.paused &&
872 e.key === 'Escape') {
873 this._remote.close();
874 }
875 }
876 /**
877 * @param {?} $event
878 * @return {?}
879 */
880 onSliderSeek($event) {
881 if (this._audioElement) {
882 this._audioElement.nativeElement.currentTime = $event;
883 }
884 }
885 /**
886 * @return {?}
887 */
888 onTimeupdate() {
889 this._cdr.markForCheck();
890 }
891 /**
892 * @return {?}
893 */
894 onMediaEnded() {
895 this._remote.close();
896 }
897 /**
898 * @param {?} e
899 * @return {?}
900 */
901 close(e) {
902 e.preventDefault();
903 this._remote.close();
904 }
905}
906ConnectedAudioPlayerComponent.decorators = [
907 { type: Component, args: [{
908 selector: 'bm-connected-audio-player',
909 template: "<audio\n (ended)=\"onMediaEnded()\"\n (timeupdate)=\"onTimeupdate()\"\n [src]=\"src\"\n [volume]=\"volume\"\n #audioElement\n autoplay\n></audio>\n<span class=\"bm-connected-media-player__time-indicator\">{{\n audioElement.currentTime | bmParseDuration\n}}</span>\n<bm-media-progress-slider\n (seek)=\"onSliderSeek($event)\"\n [duration]=\"duration\"\n [value]=\"currentTime\"\n class=\"bm-connected-media-player__slider\"\n></bm-media-progress-slider>\n<span class=\"bm-connected-media-player__time-indicator\">{{\n audioElement.duration | bmParseDuration\n}}</span>\n<button\n (click)=\"close($event)\"\n class=\"bm-connected-media-player__close_btn\"\n i18n-title\n title=\"Close\"\n type=\"button\"\n>\n <svg\n aria-hidden=\"true\"\n focusable=\"false\"\n data-prefix=\"fas\"\n data-icon=\"times-circle\"\n class=\"svg-inline--fa fa-times-circle fa-w-16\"\n class=\"bm-connected-media-player__close_icon\"\n role=\"img\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 512 512\"\n >\n <path\n fill=\"currentColor\"\n d=\"M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm121.6 313.1c4.7 4.7 4.7 12.3 0 17L338 377.6c-4.7 4.7-12.3 4.7-17 0L256 312l-65.1 65.6c-4.7 4.7-12.3 4.7-17 0L134.4 338c-4.7-4.7-4.7-12.3 0-17l65.6-65-65.6-65.1c-4.7-4.7-4.7-12.3 0-17l39.6-39.6c4.7-4.7 12.3-4.7 17 0l65 65.7 65.1-65.6c4.7-4.7 12.3-4.7 17 0l39.6 39.6c4.7 4.7 4.7 12.3 0 17L312 256l65.6 65.1z\"\n ></path>\n </svg>\n</button>\n",
910 changeDetection: ChangeDetectionStrategy.OnPush,
911 styles: [":host{align-items:center;background-color:#4a4a4a;box-shadow:0 2px 4px 0 rgba(0,0,0,.5);display:inline-flex;flex-wrap:nowrap;justify-content:center;padding:.25em 0}.bm-connected-media-player__time-indicator{color:#fff;margin:.5em 1em;width:4em}.bm-connected-media-player__close_btn{background:0 0;border:0;color:#fff;margin:.5em 1em .5em 0}.bm-connected-media-player__close_icon{width:1em}"]
912 }] }
913];
914/** @nocollapse */
915ConnectedAudioPlayerComponent.ctorParameters = () => [
916 { type: String, decorators: [{ type: Inject, args: [CONNECTED_PLAYER_SRC,] }] },
917 { type: Number, decorators: [{ type: Inject, args: [CONNECTED_PLAYER_VOLUME,] }] },
918 { type: ChangeDetectorRef },
919 { type: ElementRef },
920 { type: ConnectedMediaRemoteService }
921];
922ConnectedAudioPlayerComponent.propDecorators = {
923 _audioElement: [{ type: ViewChild, args: ['audioElement', { read: ElementRef, static: true },] }],
924 onDocumentClick: [{ type: HostListener, args: ['document:click', ['$event'],] }],
925 onDocumentKeydown: [{ type: HostListener, args: ['document:keydown', ['$event'],] }]
926};
927
928/**
929 * @fileoverview added by tsickle
930 * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
931 */
932/**
933 * Module with the duration pipe
934 */
935class ParseDurationPipeModule {
936}
937ParseDurationPipeModule.decorators = [
938 { type: NgModule, args: [{
939 declarations: [ParseDurationPipe],
940 exports: [ParseDurationPipe],
941 },] }
942];
943
944/**
945 * @fileoverview added by tsickle
946 * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
947 */
948/**
949 * Observable Drag. Return relative position without the first
950 * container, or body, with position non static.
951 * @param {?} mousedownEvent
952 * @param {?=} doc
953 * @param {?=} container
954 * @return {?}
955 */
956function dragObservable(mousedownEvent, doc = document, container = null) {
957 if (!container) {
958 container = (/** @type {?} */ (mousedownEvent.target));
959 while (container.tagName !== 'BODY' &&
960 getComputedStyle(container).getPropertyValue('position') !== 'static') {
961 container = (/** @type {?} */ (container.parentElement));
962 }
963 }
964 const { left, width } = container.getBoundingClientRect();
965 /** @type {?} */
966 const offsetX = mousedownEvent.offsetX;
967 /** @type {?} */
968 const mouseup = fromEvent(doc, 'mouseup');
969 /** @type {?} */
970 const mousemove = fromEvent(doc, 'mousemove');
971 return mousemove.pipe(map((/**
972 * @param {?} mousemoveEvent
973 * @return {?}
974 */
975 mousemoveEvent => {
976 mousemoveEvent.preventDefault();
977 return Math.min(1, Math.max(0, (mousemoveEvent.clientX - offsetX - left) / width));
978 })), takeUntil(mouseup));
979}
980
981/**
982 * @fileoverview added by tsickle
983 * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
984 */
985/**
986 * Observable Drag. Return relative position without the first
987 * container, or body, with position non static.
988 * @param {?} mouseenterEvent
989 * @param {?=} doc
990 * @param {?=} container
991 * @return {?}
992 */
993function mouseoverRelativeCoordinatesObservable(mouseenterEvent, doc = document, container = null) {
994 mouseenterEvent.preventDefault();
995 if (!container) {
996 container = (/** @type {?} */ (mouseenterEvent.target));
997 while (container.tagName !== 'BODY' &&
998 getComputedStyle(container).getPropertyValue('position') !== 'static') {
999 container = (/** @type {?} */ (container.parentElement));
1000 }
1001 }
1002 const { left, width } = container.getBoundingClientRect();
1003 /** @type {?} */
1004 const mouseleave = fromEvent(container, 'mouseleave');
1005 /** @type {?} */
1006 const mousemove = fromEvent(doc, 'mousemove');
1007 return mousemove.pipe(map((/**
1008 * @param {?} mousemoveEvent
1009 * @return {?}
1010 */
1011 mousemoveEvent => {
1012 mousemoveEvent.preventDefault();
1013 return Math.min(1, Math.max(0, (mousemoveEvent.clientX - left) / width));
1014 })), takeUntil(mouseleave), startWith(Math.min(1, Math.max(0, (mouseenterEvent.clientX - left) / width))));
1015}
1016
1017/**
1018 * @fileoverview added by tsickle
1019 * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
1020 */
1021/**
1022 * Media progress slider
1023 */
1024class MediaProgressSliderComponent {
1025 /**
1026 * @param {?} _elementRef
1027 * @param {?} _document
1028 * @param {?} _cdr
1029 * @param {?} _dir
1030 */
1031 constructor(_elementRef, _document, _cdr, _dir) {
1032 this._elementRef = _elementRef;
1033 this._document = _document;
1034 this._cdr = _cdr;
1035 this._dir = _dir;
1036 this.valuemin = 0;
1037 this.tabindex = 0;
1038 this.role = 'slider';
1039 this.seek = new EventEmitter();
1040 this._isDragging = false;
1041 this._isOver = false;
1042 }
1043 /**
1044 * @param {?} v
1045 * @return {?}
1046 */
1047 set value(v) {
1048 this._value = v;
1049 }
1050 /**
1051 * @return {?}
1052 */
1053 get value() {
1054 return this._value;
1055 }
1056 /**
1057 * @param {?} $event
1058 * @return {?}
1059 */
1060 onMouseenter($event) {
1061 this._isOver = true;
1062 mouseoverRelativeCoordinatesObservable($event, this._document, this._elementRef.nativeElement).subscribe({
1063 next: (/**
1064 * @param {?} val
1065 * @return {?}
1066 */
1067 val => {
1068 this.pointerTime = val * (this.duration || 0);
1069 /** @type {?} */
1070 const overTime = Math.max(0, this.getRelativeLeft(this.pointerTime) -
1071 this.getRelativeLeft(this.value));
1072 if (overTime > 0 &&
1073 this._previewBar &&
1074 this._previewBar.nativeElement) {
1075 /** @type {?} */
1076 const relativeLeft = this.getRelativeLeft(this.value);
1077 this._previewBar.nativeElement.style.left = `${relativeLeft}px`;
1078 this._previewBar.nativeElement.style.width = `${overTime}px`;
1079 }
1080 this._cdr.markForCheck();
1081 }),
1082 error: (/**
1083 * @return {?}
1084 */
1085 () => {
1086 this._isOver = false;
1087 }),
1088 complete: (/**
1089 * @return {?}
1090 */
1091 () => {
1092 this._isOver = false;
1093 this._cdr.markForCheck();
1094 }),
1095 });
1096 }
1097 /**
1098 * @param {?} e
1099 * @return {?}
1100 */
1101 onClick(e) {
1102 if (!this._isDragging) {
1103 e.preventDefault();
1104 const { offsetX } = e;
1105 const { width } = this._elementRef.nativeElement.getBoundingClientRect();
1106 /** @type {?} */
1107 const percent = offsetX / width;
1108 this.seek.emit(percent * (this.duration || 0));
1109 }
1110 }
1111 // tslint:disable-next-line:cyclomatic-complexity
1112 /**
1113 * @param {?} e
1114 * @return {?}
1115 */
1116 onKeydown(e) {
1117 /** @type {?} */
1118 let emitChanges = false;
1119 if (this.duration) {
1120 /** @type {?} */
1121 const bigStep = 0.1 * this.duration;
1122 switch (e.keyCode) {
1123 case DOWN_ARROW: {
1124 e.preventDefault();
1125 this._value = Math.max(0, this._value - 1);
1126 emitChanges = true;
1127 break;
1128 }
1129 case UP_ARROW: {
1130 e.preventDefault();
1131 this._value = Math.min(this.duration, this._value + 1);
1132 emitChanges = true;
1133 break;
1134 }
1135 case LEFT_ARROW: {
1136 e.preventDefault();
1137 this._value = Math.min(Math.max(0, this._value + (this._dir.value === 'ltr' ? -1 : 1)), this.duration);
1138 emitChanges = true;
1139 break;
1140 }
1141 case RIGHT_ARROW: {
1142 e.preventDefault();
1143 this._value = Math.min(Math.max(0, this._value + (this._dir.value === 'ltr' ? 1 : -1)), this.duration);
1144 emitChanges = true;
1145 break;
1146 }
1147 case PAGE_UP:
1148 e.preventDefault();
1149 this._value = Math.max(0, this._value + bigStep);
1150 emitChanges = true;
1151 break;
1152 case PAGE_DOWN:
1153 e.preventDefault();
1154 this._value = Math.max(0, this._value - bigStep);
1155 emitChanges = true;
1156 break;
1157 default:
1158 }
1159 }
1160 if (emitChanges) {
1161 this.seek.emit(this.value);
1162 }
1163 }
1164 /**
1165 * @param {?} value
1166 * @return {?}
1167 */
1168 getRelativeLeft(value) {
1169 if (this._elementRef.nativeElement && value && this.duration) {
1170 const { width } = this._elementRef.nativeElement.getBoundingClientRect();
1171 /** @type {?} */
1172 const relative = value / (this.duration - this.valuemin);
1173 return relative * width;
1174 }
1175 return 0;
1176 }
1177 /**
1178 * @return {?}
1179 */
1180 showThumb() {
1181 return this._isDragging || this._isOver;
1182 }
1183 /**
1184 * @return {?}
1185 */
1186 showPreviewBar() {
1187 return this._isOver && !this._isDragging;
1188 }
1189 /**
1190 * @param {?} $event
1191 * @return {?}
1192 */
1193 onThumbMousedown($event) {
1194 this._cdr.detach();
1195 this._isDragging = true;
1196 /** @type {?} */
1197 const dragObservable$ = dragObservable($event, this._document, this._elementRef.nativeElement);
1198 // The two observables with different throttles target components
1199 // that should update at different rates. The bounced targets the
1200 // the time tooltip, while the non bounced targets the dragged thumb
1201 // and bars.
1202 dragObservable$
1203 .pipe(debounceTime(15))
1204 .subscribe((/**
1205 * @return {?}
1206 */
1207 () => this._cdr.detectChanges()));
1208 dragObservable$.subscribe({
1209 next: (/**
1210 * @param {?} val
1211 * @return {?}
1212 */
1213 val => {
1214 this._value = val * (this.duration || 0);
1215 /** @type {?} */
1216 const relativeLeft = this.getRelativeLeft(this.value);
1217 ((/** @type {?} */ ($event.target))).style.left = `${relativeLeft}px`;
1218 if (this._doneBar && this._doneBar.nativeElement) {
1219 this._doneBar.nativeElement.style.width = `${relativeLeft}px`;
1220 }
1221 this.seek.emit(this.value);
1222 }),
1223 error: (/**
1224 * @return {?}
1225 */
1226 () => {
1227 this._cdr.reattach();
1228 }),
1229 complete: (/**
1230 * @return {?}
1231 */
1232 () => {
1233 this._cdr.reattach();
1234 setTimeout((/**
1235 * @return {?}
1236 */
1237 () => {
1238 this._isDragging = false;
1239 }), 10);
1240 }),
1241 });
1242 }
1243}
1244MediaProgressSliderComponent.decorators = [
1245 { type: Component, args: [{
1246 selector: 'bm-media-progress-slider',
1247 template: "<span\n *ngIf=\"showPreviewBar()\"\n #previewBar\n class=\"bm-media-progress-slider__bar bm-media-progress-slider__bar--preview\"\n></span>\n<span\n #doneBar\n class=\"bm-media-progress-slider__bar bm-media-progress-slider__bar--done\"\n [ngStyle]=\"{ 'width.px': getRelativeLeft(value) }\"\n></span>\n<span\n *ngIf=\"showThumb()\"\n #thumb\n class=\"bm-media-progress-slider-thumb\"\n [ngStyle]=\"{ 'left.px': getRelativeLeft(value), 'margin-left.em': -0.5 }\"\n (mousedown)=\"onThumbMousedown($event)\"\n></span>\n<span\n *bmMediaProgressTooltip=\"_elementRef\"\n class=\"bm-media-progress-slider-tooltip\"\n >{{ pointerTime | bmParseDuration }}</span\n>\n",
1248 changeDetection: ChangeDetectionStrategy.OnPush,
1249 styles: [":host{height:.5em;border-radius:.4em;display:inline-block;background-color:var(--secondary-color,#bcbcbc);max-width:100%;min-width:200px;position:relative}:host:focus{outline:solid var(--anchor-color,#4399fd) 2px}.bm-media-progress-slider__bar{height:.5em;border-radius:.4em;display:inline-block;position:absolute}.bm-media-progress-slider__bar--done{background-color:var(--header-background-color,#3e71ad)}.bm-media-progress-slider__bar--preview{background-color:var(--secondary-color-hover,#959494)}.bm-media-progress-slider-thumb{position:absolute;background-color:var(--header-background-color,#3e71ad);border-radius:50%;display:inline-block;height:1em;width:1em;top:-.25em}.bm-media-progress-slider-tooltip{display:inline-block;background-color:rgba(0,0,0,.7);border:1px solid #000;border-radius:3px;padding:.25em .5em;color:#fff;font-size:smaller}"]
1250 }] }
1251];
1252/** @nocollapse */
1253MediaProgressSliderComponent.ctorParameters = () => [
1254 { type: ElementRef },
1255 { type: undefined, decorators: [{ type: Inject, args: [DOCUMENT,] }] },
1256 { type: ChangeDetectorRef },
1257 { type: Directionality }
1258];
1259MediaProgressSliderComponent.propDecorators = {
1260 duration: [{ type: HostBinding, args: ['attr.aria-valuemax',] }, { type: Input }],
1261 value: [{ type: HostBinding, args: ['attr.aria-valuenow',] }, { type: Input }],
1262 valuemin: [{ type: HostBinding, args: ['attr.aria-valuemin',] }, { type: Input }],
1263 tabindex: [{ type: HostBinding, args: ['attr.tabindex',] }, { type: Input }],
1264 role: [{ type: HostBinding, args: ['attr.role',] }],
1265 seek: [{ type: Output }],
1266 _doneBar: [{ type: ViewChild, args: ['doneBar', { read: ElementRef, static: true },] }],
1267 _previewBar: [{ type: ViewChild, args: ['previewBar', { read: ElementRef, static: false },] }],
1268 onMouseenter: [{ type: HostListener, args: ['mouseenter', ['$event'],] }],
1269 onClick: [{ type: HostListener, args: ['click', ['$event'],] }],
1270 onKeydown: [{ type: HostListener, args: ['keydown', ['$event'],] }]
1271};
1272
1273/**
1274 * @fileoverview added by tsickle
1275 * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
1276 */
1277/**
1278 * Directive to attach
1279 */
1280class MediaProgressTooltipDirective {
1281 /**
1282 * @param {?} _templateRef
1283 * @param {?} _viewContainerRef
1284 * @param {?} _overlay
1285 * @param {?} _document
1286 * @param {?} _render
1287 */
1288 constructor(_templateRef, _viewContainerRef, _overlay, _document, _render) {
1289 this._templateRef = _templateRef;
1290 this._viewContainerRef = _viewContainerRef;
1291 this._overlay = _overlay;
1292 this._document = _document;
1293 this._render = _render;
1294 this._templatePortal = new TemplatePortal(this._templateRef, this._viewContainerRef);
1295 }
1296 /**
1297 * @param {?} v
1298 * @return {?}
1299 */
1300 set bmMediaProgressTooltip(v) {
1301 if (this._teardownListener) {
1302 this._teardownListener();
1303 }
1304 if (v) {
1305 this._bmMediaProgressTooltip = v;
1306 this._hostDOMEle = ((/** @type {?} */ (v))).nativeElement
1307 ? ((/** @type {?} */ (v))).nativeElement
1308 : ((/** @type {?} */ (v)));
1309 this._teardownListener = this._render.listen(this._hostDOMEle, 'mouseenter', this.onMouseenter.bind(this));
1310 }
1311 else {
1312 this._hostDOMEle = null;
1313 }
1314 }
1315 /**
1316 * @return {?}
1317 */
1318 get bmMediaProgressTooltip() {
1319 return this._bmMediaProgressTooltip;
1320 }
1321 /**
1322 * @return {?}
1323 */
1324 ngOnDestroy() {
1325 this.tearDownPortals();
1326 if (this._teardownListener) {
1327 this._teardownListener();
1328 }
1329 }
1330 /**
1331 * @param {?} $event
1332 * @return {?}
1333 */
1334 onMouseenter($event) {
1335 if (!this._hostDOMEle || this._templatePortal.isAttached) {
1336 return;
1337 }
1338 this.tearDownPortals();
1339 const { width } = this._hostDOMEle.getBoundingClientRect();
1340 this._positionStategy = this._overlay
1341 .position()
1342 .flexibleConnectedTo(this._hostDOMEle)
1343 .withPositions([
1344 {
1345 originX: 'start',
1346 originY: 'top',
1347 overlayX: 'start',
1348 overlayY: 'bottom',
1349 },
1350 ])
1351 .withDefaultOffsetY(-5);
1352 this._overlayRef = this._overlay.create({
1353 positionStrategy: this._positionStategy,
1354 });
1355 const { rootNodes } = this._overlayRef.attach(this._templatePortal);
1356 /** @type {?} */
1357 const getOffset = (/**
1358 * @return {?}
1359 */
1360 () => {
1361 if (rootNodes && rootNodes.length) {
1362 return ((/** @type {?} */ (rootNodes[0]))).getBoundingClientRect().width / 2;
1363 }
1364 return 0;
1365 });
1366 mouseoverRelativeCoordinatesObservable($event, this._document).subscribe({
1367 next: (/**
1368 * @param {?} val
1369 * @return {?}
1370 */
1371 val => {
1372 if (this._positionStategy) {
1373 this._positionStategy
1374 .withDefaultOffsetX(val * width - getOffset())
1375 .reapplyLastPosition();
1376 }
1377 }),
1378 complete: (/**
1379 * @return {?}
1380 */
1381 () => {
1382 this.tearDownPortals();
1383 }),
1384 });
1385 }
1386 /**
1387 * @private
1388 * @return {?}
1389 */
1390 tearDownPortals() {
1391 if (this._templatePortal && this._templatePortal.isAttached) {
1392 this._templatePortal.detach();
1393 }
1394 if (this._overlayRef) {
1395 this._overlayRef.detach();
1396 this._overlayRef.dispose();
1397 }
1398 if (this._positionStategy) {
1399 this._positionStategy.dispose();
1400 }
1401 }
1402}
1403MediaProgressTooltipDirective.decorators = [
1404 { type: Directive, args: [{
1405 selector: '[bmMediaProgressTooltip]',
1406 },] }
1407];
1408/** @nocollapse */
1409MediaProgressTooltipDirective.ctorParameters = () => [
1410 { type: TemplateRef },
1411 { type: ViewContainerRef },
1412 { type: Overlay },
1413 { type: undefined, decorators: [{ type: Inject, args: [DOCUMENT,] }] },
1414 { type: Renderer2 }
1415];
1416MediaProgressTooltipDirective.propDecorators = {
1417 bmMediaProgressTooltip: [{ type: Input }],
1418 value: [{ type: Input }]
1419};
1420
1421/**
1422 * @fileoverview added by tsickle
1423 * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
1424 */
1425/**
1426 * Module with the duration pipe
1427 */
1428class MediaProgressSliderComponentModule {
1429}
1430MediaProgressSliderComponentModule.decorators = [
1431 { type: NgModule, args: [{
1432 imports: [BidiModule, CommonModule, ParseDurationPipeModule],
1433 declarations: [MediaProgressSliderComponent, MediaProgressTooltipDirective],
1434 exports: [MediaProgressSliderComponent, MediaProgressTooltipDirective],
1435 },] }
1436];
1437
1438/**
1439 * @fileoverview added by tsickle
1440 * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
1441 */
1442/**
1443 * Module with the duration pipe
1444 */
1445class ProgressBarComponentModule {
1446}
1447ProgressBarComponentModule.decorators = [
1448 { type: NgModule, args: [{
1449 imports: [CommonModule],
1450 declarations: [ProgressBarComponent],
1451 exports: [ProgressBarComponent],
1452 },] }
1453];
1454
1455/**
1456 * @fileoverview added by tsickle
1457 * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
1458 */
1459class BMATMediaPlayersModule {
1460 // tslint:disable-next-line:function-name
1461 /**
1462 * @return {?}
1463 */
1464 static forRoot() {
1465 return {
1466 ngModule: BMATMediaPlayersModule,
1467 providers: [ConnectedMediaRemoteService],
1468 };
1469 }
1470}
1471BMATMediaPlayersModule.decorators = [
1472 { type: NgModule, args: [{
1473 imports: [
1474 CommonModule,
1475 OverlayModule,
1476 ParseDurationPipeModule,
1477 ProgressBarComponentModule,
1478 MediaProgressSliderComponentModule,
1479 ],
1480 declarations: [
1481 BMATAudioPlayerComponent,
1482 BMMediaOutputComponent,
1483 ConnectedAudioPlayerComponent,
1484 ConnectedVideoPlayerComponent,
1485 ],
1486 exports: [
1487 BMATAudioPlayerComponent,
1488 BMMediaOutputComponent,
1489 ConnectedAudioPlayerComponent,
1490 ConnectedVideoPlayerComponent,
1491 ParseDurationPipeModule,
1492 ProgressBarComponentModule,
1493 MediaProgressSliderComponentModule,
1494 ],
1495 entryComponents: [
1496 ConnectedAudioPlayerComponent,
1497 ConnectedVideoPlayerComponent,
1498 ],
1499 },] }
1500];
1501
1502export { BMATAudioPlayerComponent, BMATMediaPlayersModule, BMMediaOutputComponent, ConnectedMediaRemoteService, ConnectedPlayerEventTypes, ParseDurationPipe, ParseDurationPipeModule, PlayerType, ProgressBarComponent, ProgressBarComponentModule, MediaProgressSliderComponentModule as ɵa, MediaProgressSliderComponent as ɵb, MediaProgressTooltipDirective as ɵc, ConnectedAudioPlayerComponent as ɵd, CONNECTED_PLAYER_SRC as ɵe, CONNECTED_PLAYER_VOLUME as ɵf, ConnectedVideoPlayerComponent as ɵg, CONNECTED_PLAYER_CLOSE_REQUEST as ɵh };
1503//# sourceMappingURL=bmat-angular-media-players.js.map