1 | import { Overlay, OverlayModule } from '@angular/cdk/overlay';
|
2 | import { DOCUMENT, CommonModule } from '@angular/common';
|
3 | import { 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';
|
4 | import { timer, Subject, Observable, fromEvent } from 'rxjs';
|
5 | import { tap, map, takeUntil, startWith, debounceTime } from 'rxjs/operators';
|
6 | import { PortalInjector, ComponentPortal, TemplatePortal } from '@angular/cdk/portal';
|
7 | import { Directionality, BidiModule } from '@angular/cdk/bidi';
|
8 | import { DOWN_ARROW, UP_ARROW, LEFT_ARROW, RIGHT_ARROW, PAGE_UP, PAGE_DOWN } from '@angular/cdk/keycodes';
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 | class ParseDurationPipe {
|
15 |
|
16 | |
17 |
|
18 |
|
19 |
|
20 |
|
21 | transform(value, format = 'HH:MM:SS') {
|
22 |
|
23 | const coerceInteger = Number.parseInt(value, 10);
|
24 | if (Number.isNaN(coerceInteger)) {
|
25 | return 'N/A';
|
26 | }
|
27 |
|
28 | const seconds = coerceInteger % 60;
|
29 |
|
30 | const minutes = Math.floor(coerceInteger / 60) % 60;
|
31 |
|
32 | const hours = Math.floor(coerceInteger / 3600);
|
33 | return format
|
34 | .split(':')
|
35 | .map(( |
36 |
|
37 |
|
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 |
|
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 | }
|
73 | ParseDurationPipe.decorators = [
|
74 | { type: Pipe, args: [{
|
75 | name: 'bmParseDuration',
|
76 | },] }
|
77 | ];
|
78 |
|
79 |
|
80 |
|
81 |
|
82 |
|
83 | class BMMediaOutputComponent {
|
84 | |
85 |
|
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 |
|
95 |
|
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 | }
|
104 | BMMediaOutputComponent.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 |
|
114 | BMMediaOutputComponent.ctorParameters = () => [
|
115 | { type: ChangeDetectorRef }
|
116 | ];
|
117 | BMMediaOutputComponent.propDecorators = {
|
118 | format: [{ type: Input }],
|
119 | time: [{ type: Input }]
|
120 | };
|
121 |
|
122 |
|
123 |
|
124 |
|
125 |
|
126 | class ProgressBarComponent {
|
127 | |
128 |
|
129 |
|
130 | constructor(_cdr) {
|
131 | this._cdr = _cdr;
|
132 | this.min = 0;
|
133 | this.role = 'progressbar';
|
134 | this.max = 100;
|
135 | |
136 |
|
137 |
|
138 | this.staticBar = false;
|
139 | this._value = 0;
|
140 | }
|
141 | |
142 |
|
143 |
|
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 |
|
152 |
|
153 | get value() {
|
154 | return this._value;
|
155 | }
|
156 | }
|
157 | ProgressBarComponent.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 |
|
166 | ProgressBarComponent.ctorParameters = () => [
|
167 | { type: ChangeDetectorRef }
|
168 | ];
|
169 | ProgressBarComponent.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 |
|
179 |
|
180 |
|
181 | class BMATAudioPlayerComponent {
|
182 | |
183 |
|
184 |
|
185 | constructor(_renderer) {
|
186 | this._renderer = _renderer;
|
187 |
|
188 | this.autoplay = false;
|
189 | this.controls = false;
|
190 | this.loop = false;
|
191 | this.muted = false;
|
192 | this.preload = 'none';
|
193 | |
194 |
|
195 |
|
196 | this.play = new EventEmitter();
|
197 | |
198 |
|
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 |
|
209 |
|
210 |
|
211 | set src(v) {
|
212 | this._src = v;
|
213 | this.isDisabled = !v;
|
214 | }
|
215 | |
216 |
|
217 |
|
218 | get src() {
|
219 | return this._src;
|
220 | }
|
221 | |
222 |
|
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 |
|
235 |
|
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 |
|
243 |
|
244 | () => {
|
245 |
|
246 | const now = new Date().getTime();
|
247 |
|
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 |
|
256 |
|
257 |
|
258 | onloadeddata(event) {
|
259 | event.stopPropagation();
|
260 | this.isLoading = true;
|
261 | }
|
262 | |
263 |
|
264 |
|
265 | ondurationchange() {
|
266 | this.calculateElapsed();
|
267 | }
|
268 | |
269 |
|
270 |
|
271 |
|
272 | oncanplay(event) {
|
273 | event.stopPropagation();
|
274 | this.isLoading = false;
|
275 | }
|
276 | |
277 |
|
278 |
|
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 |
|
290 |
|
291 |
|
292 | onplaying(event) {
|
293 | event.stopPropagation();
|
294 | this.isPlaying = true;
|
295 | this.isLoading = false;
|
296 | }
|
297 | |
298 |
|
299 |
|
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 |
|
311 |
|
312 |
|
313 | onwaiting(event) {
|
314 | event.stopPropagation();
|
315 | this.isLoading = true;
|
316 | }
|
317 | |
318 |
|
319 |
|
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 |
|
331 |
|
332 | togglePlay() {
|
333 | this._renderer.setProperty(this.audioElement.nativeElement, 'playbackRate', 1);
|
334 | this._isMouseDown = false;
|
335 |
|
336 | const now = new Date().getTime();
|
337 |
|
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 |
|
354 |
|
355 |
|
356 | calculateElapsed() {
|
357 |
|
358 | const nativeAudio = this.audioElement.nativeElement;
|
359 | if (this.progressBar) {
|
360 |
|
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 |
|
374 |
|
375 | BMATAudioPlayerComponent.HOLD_TIME = 200;
|
376 |
|
377 |
|
378 |
|
379 | BMATAudioPlayerComponent.ACCELERATED_RATE = 3;
|
380 | BMATAudioPlayerComponent.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 |
|
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 |
|
391 | BMATAudioPlayerComponent.ctorParameters = () => [
|
392 | { type: Renderer2 }
|
393 | ];
|
394 | BMATAudioPlayerComponent.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 |
|
410 |
|
411 |
|
412 |
|
413 |
|
414 |
|
415 |
|
416 | const CONNECTED_PLAYER_CLOSE_REQUEST = new InjectionToken('bmat.angular.media-players.connected-player-close-request');
|
417 |
|
418 |
|
419 |
|
420 |
|
421 |
|
422 |
|
423 |
|
424 |
|
425 |
|
426 | const CONNECTED_PLAYER_SRC = new InjectionToken('bmat.angular.media-players.connected-player-src');
|
427 |
|
428 |
|
429 |
|
430 |
|
431 |
|
432 |
|
433 |
|
434 |
|
435 |
|
436 | const CONNECTED_PLAYER_VOLUME = new InjectionToken('bmat.angular.media-players.connected-player-volume');
|
437 |
|
438 |
|
439 |
|
440 |
|
441 |
|
442 |
|
443 |
|
444 |
|
445 | class ConnectedVideoPlayerComponent {
|
446 | |
447 |
|
448 |
|
449 |
|
450 |
|
451 |
|
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 |
|
466 |
|
467 | get focusWithin() {
|
468 | return this._focusWithin;
|
469 | }
|
470 | |
471 |
|
472 |
|
473 | onFocusin() {
|
474 | this._focusWithin = true;
|
475 | }
|
476 | |
477 |
|
478 |
|
479 | onFocusout() {
|
480 | this._focusWithin = false;
|
481 | }
|
482 | |
483 |
|
484 |
|
485 |
|
486 | onDocumentKeydown(e) {
|
487 | if (e.key === 'Escape') {
|
488 | this._closeRequest();
|
489 | }
|
490 | }
|
491 | |
492 |
|
493 |
|
494 | close() {
|
495 | this._closeRequest();
|
496 | }
|
497 | |
498 |
|
499 |
|
500 | onMediaEnded() {
|
501 | this._closeRequest();
|
502 | }
|
503 | |
504 |
|
505 |
|
506 | checkAfterVideoElement() {
|
507 | this._cdr.markForCheck();
|
508 | }
|
509 | |
510 |
|
511 |
|
512 | onVideoPlay() {
|
513 | this.isPlaying = true;
|
514 | this._cdr.markForCheck();
|
515 | }
|
516 | |
517 |
|
518 |
|
519 | onVideoPause() {
|
520 | this.isPlaying = false;
|
521 | this._cdr.markForCheck();
|
522 | }
|
523 | |
524 |
|
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 |
|
538 |
|
539 |
|
540 | onSliderSeek($event) {
|
541 | if (this._videoElement) {
|
542 | this._videoElement.nativeElement.currentTime = $event;
|
543 | }
|
544 | }
|
545 | |
546 |
|
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 |
|
559 |
|
560 |
|
561 | err => console.error(err)));
|
562 | }
|
563 | }
|
564 | }
|
565 | |
566 |
|
567 |
|
568 | displayFullScreenBtn() {
|
569 | return (this._fullscreenWrapper &&
|
570 | this._fullscreenWrapper.nativeElement.requestFullscreen);
|
571 | }
|
572 | }
|
573 | ConnectedVideoPlayerComponent.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 |
|
582 | ConnectedVideoPlayerComponent.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 | ];
|
589 | ConnectedVideoPlayerComponent.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 |
|
600 |
|
601 |
|
602 |
|
603 | const PlayerType = {
|
604 | Audio: 0,
|
605 | Video: 1,
|
606 | };
|
607 | PlayerType[PlayerType.Audio] = 'Audio';
|
608 | PlayerType[PlayerType.Video] = 'Video';
|
609 |
|
610 | const defaultOptions = {
|
611 | playerType: PlayerType.Audio,
|
612 | volume: 1,
|
613 | };
|
614 |
|
615 | const ConnectedPlayerEventTypes = {
|
616 | OPEN: 'OPEN',
|
617 | CLOSE: 'CLOSE',
|
618 | };
|
619 |
|
620 |
|
621 |
|
622 |
|
623 | class ConnectedMediaRemoteService {
|
624 | |
625 |
|
626 |
|
627 |
|
628 | constructor(_injector, _overlay) {
|
629 | this._injector = _injector;
|
630 | this._overlay = _overlay;
|
631 | this._playerEventsSubject = new Subject();
|
632 | }
|
633 | |
634 |
|
635 |
|
636 | getEvents() {
|
637 | return new Observable(( |
638 |
|
639 |
|
640 |
|
641 | observer => {
|
642 |
|
643 | const subs = this._playerEventsSubject.subscribe(observer);
|
644 | return ( |
645 |
|
646 |
|
647 | () => {
|
648 | subs.unsubscribe();
|
649 | });
|
650 | }));
|
651 | }
|
652 | |
653 |
|
654 |
|
655 |
|
656 |
|
657 |
|
658 | open(src, host, options = {}) {
|
659 | this.close();
|
660 |
|
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, ( (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 |
|
682 |
|
683 | isOpen() {
|
684 | return this._overlayRef.hasAttached();
|
685 | }
|
686 | |
687 |
|
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 |
|
700 |
|
701 |
|
702 |
|
703 |
|
704 |
|
705 | setUpAudioPlayer(src, host, options) {
|
706 |
|
707 | const domEle = host && (( (host))).nativeElement
|
708 | ? (( (host))).nativeElement
|
709 | : (( (host)));
|
710 | if (!domEle) {
|
711 | throw new TypeError('Invalid host element');
|
712 | }
|
713 |
|
714 | const providers = new WeakMap();
|
715 | providers.set(CONNECTED_PLAYER_SRC, src);
|
716 | providers.set(CONNECTED_PLAYER_VOLUME, options.volume);
|
717 |
|
718 | const portalInjector = new PortalInjector(this._injector, providers);
|
719 |
|
720 | const componentPortal = new ComponentPortal(ConnectedAudioPlayerComponent, null, portalInjector);
|
721 |
|
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 |
|
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 |
|
761 |
|
762 |
|
763 |
|
764 |
|
765 | setUpVideoPlayer(src, options) {
|
766 |
|
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 |
|
772 | const portalInjector = new PortalInjector(this._injector, providers);
|
773 |
|
774 | const componentPortal = new ComponentPortal(ConnectedVideoPlayerComponent, null, portalInjector);
|
775 |
|
776 | const positionStrategy = this._overlay
|
777 | .position()
|
778 | .global()
|
779 | .centerHorizontally()
|
780 | .centerVertically();
|
781 |
|
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 |
|
790 |
|
791 | () => this.close()));
|
792 | return this._overlayRef.attach(componentPortal);
|
793 | }
|
794 | }
|
795 | ConnectedMediaRemoteService.decorators = [
|
796 | { type: Injectable, args: [{
|
797 | providedIn: 'root',
|
798 | },] }
|
799 | ];
|
800 |
|
801 | ConnectedMediaRemoteService.ctorParameters = () => [
|
802 | { type: Injector },
|
803 | { type: Overlay }
|
804 | ];
|
805 | ConnectedMediaRemoteService.ngInjectableDef = ɵɵdefineInjectable({ factory: function ConnectedMediaRemoteService_Factory() { return new ConnectedMediaRemoteService(ɵɵinject(INJECTOR), ɵɵinject(Overlay)); }, token: ConnectedMediaRemoteService, providedIn: "root" });
|
806 |
|
807 |
|
808 |
|
809 |
|
810 |
|
811 |
|
812 |
|
813 |
|
814 | class ConnectedAudioPlayerComponent {
|
815 | |
816 |
|
817 |
|
818 |
|
819 |
|
820 |
|
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 |
|
831 |
|
832 | get duration() {
|
833 | if (this._audioElement && this._audioElement.nativeElement) {
|
834 | return this._audioElement.nativeElement.duration;
|
835 | }
|
836 | return 0;
|
837 | }
|
838 | |
839 |
|
840 |
|
841 | get currentTime() {
|
842 | if (this._audioElement && this._audioElement.nativeElement) {
|
843 | return this._audioElement.nativeElement.currentTime;
|
844 | }
|
845 | return 0;
|
846 | }
|
847 | |
848 |
|
849 |
|
850 |
|
851 | onDocumentClick(e) {
|
852 | if (this._remote.isOpen() && !this._audioElement.nativeElement.paused) {
|
853 |
|
854 | let parent = ( (e.target));
|
855 | while (parent &&
|
856 | parent.tagName !== 'BODY' &&
|
857 | parent !== this._elementRef.nativeElement) {
|
858 | parent = ( (parent.parentElement));
|
859 | }
|
860 | if (parent !== this._elementRef.nativeElement) {
|
861 | this._remote.close();
|
862 | }
|
863 | }
|
864 | }
|
865 | |
866 |
|
867 |
|
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 |
|
878 |
|
879 |
|
880 | onSliderSeek($event) {
|
881 | if (this._audioElement) {
|
882 | this._audioElement.nativeElement.currentTime = $event;
|
883 | }
|
884 | }
|
885 | |
886 |
|
887 |
|
888 | onTimeupdate() {
|
889 | this._cdr.markForCheck();
|
890 | }
|
891 | |
892 |
|
893 |
|
894 | onMediaEnded() {
|
895 | this._remote.close();
|
896 | }
|
897 | |
898 |
|
899 |
|
900 |
|
901 | close(e) {
|
902 | e.preventDefault();
|
903 | this._remote.close();
|
904 | }
|
905 | }
|
906 | ConnectedAudioPlayerComponent.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 |
|
915 | ConnectedAudioPlayerComponent.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 | ];
|
922 | ConnectedAudioPlayerComponent.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 |
|
930 |
|
931 |
|
932 |
|
933 |
|
934 |
|
935 | class ParseDurationPipeModule {
|
936 | }
|
937 | ParseDurationPipeModule.decorators = [
|
938 | { type: NgModule, args: [{
|
939 | declarations: [ParseDurationPipe],
|
940 | exports: [ParseDurationPipe],
|
941 | },] }
|
942 | ];
|
943 |
|
944 |
|
945 |
|
946 |
|
947 |
|
948 |
|
949 |
|
950 |
|
951 |
|
952 |
|
953 |
|
954 |
|
955 |
|
956 | function dragObservable(mousedownEvent, doc = document, container = null) {
|
957 | if (!container) {
|
958 | container = ( (mousedownEvent.target));
|
959 | while (container.tagName !== 'BODY' &&
|
960 | getComputedStyle(container).getPropertyValue('position') !== 'static') {
|
961 | container = ( (container.parentElement));
|
962 | }
|
963 | }
|
964 | const { left, width } = container.getBoundingClientRect();
|
965 |
|
966 | const offsetX = mousedownEvent.offsetX;
|
967 |
|
968 | const mouseup = fromEvent(doc, 'mouseup');
|
969 |
|
970 | const mousemove = fromEvent(doc, 'mousemove');
|
971 | return mousemove.pipe(map(( |
972 |
|
973 |
|
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 |
|
983 |
|
984 |
|
985 |
|
986 |
|
987 |
|
988 |
|
989 |
|
990 |
|
991 |
|
992 |
|
993 | function mouseoverRelativeCoordinatesObservable(mouseenterEvent, doc = document, container = null) {
|
994 | mouseenterEvent.preventDefault();
|
995 | if (!container) {
|
996 | container = ( (mouseenterEvent.target));
|
997 | while (container.tagName !== 'BODY' &&
|
998 | getComputedStyle(container).getPropertyValue('position') !== 'static') {
|
999 | container = ( (container.parentElement));
|
1000 | }
|
1001 | }
|
1002 | const { left, width } = container.getBoundingClientRect();
|
1003 |
|
1004 | const mouseleave = fromEvent(container, 'mouseleave');
|
1005 |
|
1006 | const mousemove = fromEvent(doc, 'mousemove');
|
1007 | return mousemove.pipe(map(( |
1008 |
|
1009 |
|
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 |
|
1019 |
|
1020 |
|
1021 |
|
1022 |
|
1023 |
|
1024 | class MediaProgressSliderComponent {
|
1025 | |
1026 |
|
1027 |
|
1028 |
|
1029 |
|
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 |
|
1045 |
|
1046 |
|
1047 | set value(v) {
|
1048 | this._value = v;
|
1049 | }
|
1050 | |
1051 |
|
1052 |
|
1053 | get value() {
|
1054 | return this._value;
|
1055 | }
|
1056 | |
1057 |
|
1058 |
|
1059 |
|
1060 | onMouseenter($event) {
|
1061 | this._isOver = true;
|
1062 | mouseoverRelativeCoordinatesObservable($event, this._document, this._elementRef.nativeElement).subscribe({
|
1063 | next: ( |
1064 |
|
1065 |
|
1066 |
|
1067 | val => {
|
1068 | this.pointerTime = val * (this.duration || 0);
|
1069 |
|
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 |
|
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 |
|
1084 |
|
1085 | () => {
|
1086 | this._isOver = false;
|
1087 | }),
|
1088 | complete: ( |
1089 |
|
1090 |
|
1091 | () => {
|
1092 | this._isOver = false;
|
1093 | this._cdr.markForCheck();
|
1094 | }),
|
1095 | });
|
1096 | }
|
1097 | |
1098 |
|
1099 |
|
1100 |
|
1101 | onClick(e) {
|
1102 | if (!this._isDragging) {
|
1103 | e.preventDefault();
|
1104 | const { offsetX } = e;
|
1105 | const { width } = this._elementRef.nativeElement.getBoundingClientRect();
|
1106 |
|
1107 | const percent = offsetX / width;
|
1108 | this.seek.emit(percent * (this.duration || 0));
|
1109 | }
|
1110 | }
|
1111 |
|
1112 | |
1113 |
|
1114 |
|
1115 |
|
1116 | onKeydown(e) {
|
1117 |
|
1118 | let emitChanges = false;
|
1119 | if (this.duration) {
|
1120 |
|
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 |
|
1166 |
|
1167 |
|
1168 | getRelativeLeft(value) {
|
1169 | if (this._elementRef.nativeElement && value && this.duration) {
|
1170 | const { width } = this._elementRef.nativeElement.getBoundingClientRect();
|
1171 |
|
1172 | const relative = value / (this.duration - this.valuemin);
|
1173 | return relative * width;
|
1174 | }
|
1175 | return 0;
|
1176 | }
|
1177 | |
1178 |
|
1179 |
|
1180 | showThumb() {
|
1181 | return this._isDragging || this._isOver;
|
1182 | }
|
1183 | |
1184 |
|
1185 |
|
1186 | showPreviewBar() {
|
1187 | return this._isOver && !this._isDragging;
|
1188 | }
|
1189 | |
1190 |
|
1191 |
|
1192 |
|
1193 | onThumbMousedown($event) {
|
1194 | this._cdr.detach();
|
1195 | this._isDragging = true;
|
1196 |
|
1197 | const dragObservable$ = dragObservable($event, this._document, this._elementRef.nativeElement);
|
1198 |
|
1199 |
|
1200 |
|
1201 |
|
1202 | dragObservable$
|
1203 | .pipe(debounceTime(15))
|
1204 | .subscribe(( |
1205 |
|
1206 |
|
1207 | () => this._cdr.detectChanges()));
|
1208 | dragObservable$.subscribe({
|
1209 | next: ( |
1210 |
|
1211 |
|
1212 |
|
1213 | val => {
|
1214 | this._value = val * (this.duration || 0);
|
1215 |
|
1216 | const relativeLeft = this.getRelativeLeft(this.value);
|
1217 | (( ($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 |
|
1225 |
|
1226 | () => {
|
1227 | this._cdr.reattach();
|
1228 | }),
|
1229 | complete: ( |
1230 |
|
1231 |
|
1232 | () => {
|
1233 | this._cdr.reattach();
|
1234 | setTimeout(( |
1235 |
|
1236 |
|
1237 | () => {
|
1238 | this._isDragging = false;
|
1239 | }), 10);
|
1240 | }),
|
1241 | });
|
1242 | }
|
1243 | }
|
1244 | MediaProgressSliderComponent.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 |
|
1253 | MediaProgressSliderComponent.ctorParameters = () => [
|
1254 | { type: ElementRef },
|
1255 | { type: undefined, decorators: [{ type: Inject, args: [DOCUMENT,] }] },
|
1256 | { type: ChangeDetectorRef },
|
1257 | { type: Directionality }
|
1258 | ];
|
1259 | MediaProgressSliderComponent.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 |
|
1275 |
|
1276 |
|
1277 |
|
1278 |
|
1279 |
|
1280 | class MediaProgressTooltipDirective {
|
1281 | |
1282 |
|
1283 |
|
1284 |
|
1285 |
|
1286 |
|
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 |
|
1298 |
|
1299 |
|
1300 | set bmMediaProgressTooltip(v) {
|
1301 | if (this._teardownListener) {
|
1302 | this._teardownListener();
|
1303 | }
|
1304 | if (v) {
|
1305 | this._bmMediaProgressTooltip = v;
|
1306 | this._hostDOMEle = (( (v))).nativeElement
|
1307 | ? (( (v))).nativeElement
|
1308 | : (( (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 |
|
1317 |
|
1318 | get bmMediaProgressTooltip() {
|
1319 | return this._bmMediaProgressTooltip;
|
1320 | }
|
1321 | |
1322 |
|
1323 |
|
1324 | ngOnDestroy() {
|
1325 | this.tearDownPortals();
|
1326 | if (this._teardownListener) {
|
1327 | this._teardownListener();
|
1328 | }
|
1329 | }
|
1330 | |
1331 |
|
1332 |
|
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 |
|
1357 | const getOffset = ( |
1358 |
|
1359 |
|
1360 | () => {
|
1361 | if (rootNodes && rootNodes.length) {
|
1362 | return (( (rootNodes[0]))).getBoundingClientRect().width / 2;
|
1363 | }
|
1364 | return 0;
|
1365 | });
|
1366 | mouseoverRelativeCoordinatesObservable($event, this._document).subscribe({
|
1367 | next: ( |
1368 |
|
1369 |
|
1370 |
|
1371 | val => {
|
1372 | if (this._positionStategy) {
|
1373 | this._positionStategy
|
1374 | .withDefaultOffsetX(val * width - getOffset())
|
1375 | .reapplyLastPosition();
|
1376 | }
|
1377 | }),
|
1378 | complete: ( |
1379 |
|
1380 |
|
1381 | () => {
|
1382 | this.tearDownPortals();
|
1383 | }),
|
1384 | });
|
1385 | }
|
1386 | |
1387 |
|
1388 |
|
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 | }
|
1403 | MediaProgressTooltipDirective.decorators = [
|
1404 | { type: Directive, args: [{
|
1405 | selector: '[bmMediaProgressTooltip]',
|
1406 | },] }
|
1407 | ];
|
1408 |
|
1409 | MediaProgressTooltipDirective.ctorParameters = () => [
|
1410 | { type: TemplateRef },
|
1411 | { type: ViewContainerRef },
|
1412 | { type: Overlay },
|
1413 | { type: undefined, decorators: [{ type: Inject, args: [DOCUMENT,] }] },
|
1414 | { type: Renderer2 }
|
1415 | ];
|
1416 | MediaProgressTooltipDirective.propDecorators = {
|
1417 | bmMediaProgressTooltip: [{ type: Input }],
|
1418 | value: [{ type: Input }]
|
1419 | };
|
1420 |
|
1421 |
|
1422 |
|
1423 |
|
1424 |
|
1425 |
|
1426 |
|
1427 |
|
1428 | class MediaProgressSliderComponentModule {
|
1429 | }
|
1430 | MediaProgressSliderComponentModule.decorators = [
|
1431 | { type: NgModule, args: [{
|
1432 | imports: [BidiModule, CommonModule, ParseDurationPipeModule],
|
1433 | declarations: [MediaProgressSliderComponent, MediaProgressTooltipDirective],
|
1434 | exports: [MediaProgressSliderComponent, MediaProgressTooltipDirective],
|
1435 | },] }
|
1436 | ];
|
1437 |
|
1438 |
|
1439 |
|
1440 |
|
1441 |
|
1442 |
|
1443 |
|
1444 |
|
1445 | class ProgressBarComponentModule {
|
1446 | }
|
1447 | ProgressBarComponentModule.decorators = [
|
1448 | { type: NgModule, args: [{
|
1449 | imports: [CommonModule],
|
1450 | declarations: [ProgressBarComponent],
|
1451 | exports: [ProgressBarComponent],
|
1452 | },] }
|
1453 | ];
|
1454 |
|
1455 |
|
1456 |
|
1457 |
|
1458 |
|
1459 | class BMATMediaPlayersModule {
|
1460 |
|
1461 | |
1462 |
|
1463 |
|
1464 | static forRoot() {
|
1465 | return {
|
1466 | ngModule: BMATMediaPlayersModule,
|
1467 | providers: [ConnectedMediaRemoteService],
|
1468 | };
|
1469 | }
|
1470 | }
|
1471 | BMATMediaPlayersModule.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 |
|
1502 | export { 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 |
|