UNPKG

@flosportsinc/ng-video-autoplay

Version:

Simple way to ensure videos autoplay even if they need to be muted first.

293 lines (289 loc) 9.79 kB
import { Directive, ElementRef, Renderer2, Input, ContentChildren, NgModule } from '@angular/core'; import { takeUntil, share, map, tap, take, filter, flatMap } from 'rxjs/operators'; import { fromEvent, Subject } from 'rxjs'; import { either, maybe } from 'typescript-monads'; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ // tslint:disable:no-object-mutation /** @type {?} */ var filterHalted = (/** * @param {?} source * @return {?} */ function (source) { return source.pipe(filter((/** * @param {?} res * @return {?} */ function (res) { return res.halted === true; }))); }); /** @type {?} */ var tryPlayVideoAsIs = (/** * @param {?} source * @return {?} */ function (source) { return source.pipe(flatMap((/** * @param {?} videoElement * @return {?} */ function (videoElement) { return videoElement.play() .then((/** * @return {?} */ function () { return ({ videoElement: videoElement, halted: false }); })) .catch((/** * @return {?} */ function () { return ({ videoElement: videoElement, halted: true }); })); })), filterHalted); }); /** @type {?} */ var tryPlayVideoMuted = (/** * @param {?} source * @return {?} */ function (source) { return source.pipe(map((/** * @param {?} res * @return {?} */ function (res) { res.videoElement.muted = true; res.videoElement.volume = 0; return res.videoElement; })), tryPlayVideoAsIs); }) // 1) attempt to play as-is (including autoplay + unmuted) // 2) attempt to play muted, showing unmite button // 3) show click to play ; // 1) attempt to play as-is (including autoplay + unmuted) // 2) attempt to play muted, showing unmite button // 3) show click to play var FloVideoAutoplayDirective = /** @class */ (function () { function FloVideoAutoplayDirective(elmRef, rd) { var _this = this; this.elmRef = elmRef; this.rd = rd; this.floVideoAutoplay = true; this.floVideoAutoplayIndex = 0; this.onDestroySource = new Subject(); this.onDestroy = this.onDestroySource.pipe(share()); this.canExecute = (/** * @return {?} */ function () { return _this.floVideoAutoplay === true || _this.floVideoAutoplay === ''; }); this.maybeVideoElement = (/** * @return {?} */ function () { return maybe(_this.elmRef.nativeElement).filter((/** * @param {?} e * @return {?} */ function (e) { return e.nodeName === 'VIDEO'; })); }); this.maybeUnmuteActionRef = (/** * @return {?} */ function () { return maybe(_this.floVideoAutoplayClickUnmuteRef).filter((/** * @param {?} a * @return {?} */ function (a) { return (/** @type {?} */ (a)) !== ''; })); }); this.maybePlayActionRef = (/** * @return {?} */ function () { return maybe(_this.floVideoAutoplayClickPlayRef).filter((/** * @param {?} a * @return {?} */ function (a) { return (/** @type {?} */ (a)) !== ''; })); }); this.hideRef = (/** * @param {?} ref * @return {?} */ function (ref) { return _this.rd.setStyle(ref, 'display', 'none'); }); this.showRef = (/** * @param {?} ref * @return {?} */ function (ref) { return _this.rd.setStyle(ref, 'display', 'block'); }); this.volumeChange = (/** * @param {?} videoElement * @return {?} */ function (videoElement) { return fromEvent(videoElement, 'volumechange', { passive: true }).pipe(map((/** * @param {?} evt * @return {?} */ function (evt) { return (/** @type {?} */ (evt.target)); })), share(), takeUntil(_this.onDestroy)); }); this.initOnVideo = (/** * @param {?} videoElement * @return {?} */ function (videoElement) { return fromEvent(videoElement, 'loadstart').pipe(tap((/** * @return {?} */ function () { return videoElement.setAttribute('autoplay', 'true'); })), map((/** * @param {?} evt * @return {?} */ function (evt) { return (/** @type {?} */ (evt.target)); })), tryPlayVideoAsIs, tryPlayVideoMuted, take(1)).subscribe((/** * @param {?} res * @return {?} */ function (res) { res.videoElement.preload = 'none'; res.videoElement.muted = false; res.videoElement.volume = 1; _this.maybePlayActionRef().tapSome(_this.showRef); })); }); this.runUnmuteSequence = (/** * @param {?} actionRef * @return {?} */ function (actionRef) { return (/** * @param {?} runOnce * @return {?} */ function (runOnce) { return (/** * @param {?} videoElement * @return {?} */ function (videoElement) { videoElement.setAttribute('autoplay', 'true'); fromEvent(actionRef, 'click').pipe(takeUntil(_this.onDestroy)).subscribe((/** * @return {?} */ function () { videoElement.muted = false; videoElement.volume = 1; })); _this.volumeChange(videoElement).pipe(filter((/** * @param {?} v * @return {?} */ function (v) { return !v.muted || v.volume > 0; })), takeUntil(_this.onDestroy)) .subscribe((/** * @return {?} */ function () { return _this.hideRef(actionRef); })); /** @type {?} */ var showRef = _this.volumeChange(videoElement).pipe(filter((/** * @param {?} v * @return {?} */ function (v) { return v.muted || v.volume <= 0; }))); (runOnce ? showRef.pipe(take(1)) : showRef).subscribe((/** * @return {?} */ function () { return _this.showRef(actionRef); })); }); }); }); } /** * @return {?} */ FloVideoAutoplayDirective.prototype.ngAfterContentInit = /** * @return {?} */ function () { var _this = this; if (!this.canExecute()) { return; } this.maybeVideoElement().tapSome(this.initOnVideo); this.videos.map((/** * @param {?} a * @return {?} */ function (a) { return a.nativeElement; })).forEach(this.initOnVideo); this.maybeUnmuteActionRef().tapSome((/** * @param {?} ref * @return {?} */ function (ref) { _this.hideRef(ref); either(_this.maybeVideoElement().valueOrUndefined(), maybe(_this.videos.toArray()[_this.floVideoAutoplayIndex]).map((/** * @param {?} a * @return {?} */ function (a) { return a.nativeElement; })).valueOrUndefined()) .tap({ left: _this.runUnmuteSequence(ref)(false), right: _this.runUnmuteSequence(ref)(true) }); })); this.maybePlayActionRef().tapSome((/** * @param {?} actionRef * @return {?} */ function (actionRef) { _this.hideRef(actionRef); fromEvent(actionRef, 'click').pipe(takeUntil(_this.onDestroy)).subscribe((/** * @return {?} */ function () { _this.hideRef(actionRef); _this.maybeVideoElement().tapSome((/** * @param {?} v * @return {?} */ function (v) { return v.play(); })); })); })); }; /** * @return {?} */ FloVideoAutoplayDirective.prototype.ngOnDestroy = /** * @return {?} */ function () { this.onDestroySource.next(); this.onDestroySource.complete(); }; FloVideoAutoplayDirective.decorators = [ { type: Directive, args: [{ selector: '[floVideoAutoplay]' },] } ]; /** @nocollapse */ FloVideoAutoplayDirective.ctorParameters = function () { return [ { type: ElementRef }, { type: Renderer2 } ]; }; FloVideoAutoplayDirective.propDecorators = { floVideoAutoplay: [{ type: Input }], floVideoAutoplayClickUnmuteRef: [{ type: Input }], floVideoAutoplayClickPlayRef: [{ type: Input }], floVideoAutoplayIndex: [{ type: Input }], videos: [{ type: ContentChildren, args: ['floVideoAutoplay', { descendants: true },] }] }; return FloVideoAutoplayDirective; }()); /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ var FloVideoAutoplayModule = /** @class */ (function () { function FloVideoAutoplayModule() { } FloVideoAutoplayModule.decorators = [ { type: NgModule, args: [{ declarations: [ FloVideoAutoplayDirective ], exports: [ FloVideoAutoplayDirective ] },] } ]; return FloVideoAutoplayModule; }()); export { FloVideoAutoplayModule, FloVideoAutoplayDirective as ɵa }; //# sourceMappingURL=flosportsinc-ng-video-autoplay.js.map