diff --git a/projects/flosportsinc/ng-ad-block/README.md b/projects/flosportsinc/ng-ad-block/README.md index 4221b2e2..7eda7b03 100644 --- a/projects/flosportsinc/ng-ad-block/README.md +++ b/projects/flosportsinc/ng-ad-block/README.md @@ -34,4 +34,32 @@ import { FloAdBlockServerModule } from '@flosportsinc/ng-universal-services/ad-b ] }) export class AppServerModule { } +``` + +## Usage + +### Programmatic +```js +import { NgComponent } from '@angular/core' +import { AdBlockService } from '@flosportsinc/ng-ad-block' + +@NgModule() +export class SomeComponent { + constructor(ads: AdBlockService) { + ads.isAnAdBlockerActive.subscribe(isBlocked => { + // access the boolean here + }) + } +} +``` + +### Stuctural HTML +To hide or show content depending on ad-blocker detection status simply decorate your html like so: + +```html + +
I am an ad that can likely be shown to the user
+ + +
Hey, turn off your ad-blocker
``` \ No newline at end of file diff --git a/projects/flosportsinc/ng-ad-block/common/ad-block.directive.spec.ts b/projects/flosportsinc/ng-ad-block/common/ad-block.directive.spec.ts new file mode 100644 index 00000000..2c4588a1 --- /dev/null +++ b/projects/flosportsinc/ng-ad-block/common/ad-block.directive.spec.ts @@ -0,0 +1,73 @@ +import { Component, NgModule } from '@angular/core' +import { TestBed } from '@angular/core/testing' +import { By } from '@angular/platform-browser' +import { of } from 'rxjs' +import { FloAdBlockModule } from './ad-block.module' +import { FloIfAdBlockedDirective } from './ad-block.directive' +import { AD_BLOCK_LOADER } from './ad-block.tokens' +import { AdBlockService } from './ad-block.service' + +@Component({ + selector: 'flo-test-component', + template: ` +
floIfAdBlocked
+
floIfNotAdBlocked
+`}) +export class FloTestComponent { } + +export const trueLoader = () => of(true) +export const falseLoader = () => of(false) + +@NgModule({ + declarations: [FloTestComponent], + imports: [FloAdBlockModule], + exports: [FloAdBlockModule, FloTestComponent], + providers: [ + AdBlockService, + { provide: AD_BLOCK_LOADER, useFactory: falseLoader } + ] +}) +export class FloFullscreenTestModule { } + +const createSut = () => { + const sut = TestBed.createComponent(FloTestComponent) + sut.detectChanges() + return sut +} + +describe(FloIfAdBlockedDirective.name, () => { + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [FloFullscreenTestModule] + }).compileComponents() + }) + + it('should compile', () => { + expect(createSut()).toBeTruthy() + }) + + it('should show floIfAdBlocked element', () => { + TestBed.resetTestingModule() + TestBed.configureTestingModule({ + imports: [FloFullscreenTestModule], + providers: [ + { provide: AD_BLOCK_LOADER, useFactory: trueLoader } + ] + }) + const sut = createSut() + const element1 = sut.debugElement.query(By.css('#floIfAdBlocked')) + const element2 = sut.debugElement.query(By.css('#floIfNotAdBlocked')) + sut.detectChanges() + expect(element1.nativeElement.innerText).toEqual('floIfAdBlocked') + expect(element2).toBeNull() + }) + + it('should show floIfNotAdBlocked element', () => { + const sut = createSut() + const element1 = sut.debugElement.query(By.css('#floIfAdBlocked')) + const element2 = sut.debugElement.query(By.css('#floIfNotAdBlocked')) + sut.detectChanges() + expect(element1).toBeNull() + expect(element2.nativeElement.innerText).toEqual('floIfNotAdBlocked') + }) +}) diff --git a/projects/flosportsinc/ng-ad-block/common/ad-block.directive.ts b/projects/flosportsinc/ng-ad-block/common/ad-block.directive.ts new file mode 100644 index 00000000..9ccd11fd --- /dev/null +++ b/projects/flosportsinc/ng-ad-block/common/ad-block.directive.ts @@ -0,0 +1,70 @@ +import { Directive, TemplateRef, ViewContainerRef, ChangeDetectorRef, OnInit, OnDestroy } from '@angular/core' +import { AdBlockService } from './ad-block.service' +import { Subject } from 'rxjs' +import { takeUntil } from 'rxjs/operators' + +export abstract class FloAdBlockDirective implements OnInit, OnDestroy { + constructor(protected tr: TemplateRef, protected vc: ViewContainerRef, + protected ads: AdBlockService, protected cd: ChangeDetectorRef) { } + + protected readonly ngOnDestroy$ = new Subject() + // tslint:disable-next-line: readonly-keyword + protected showWhenAdBlocked: boolean + + ngOnInit() { + this.ads.isAnAdBlockerActive() + .pipe(takeUntil(this.ngOnDestroy$)) + .subscribe(isActive => { + if (isActive) { + if (this.showWhenAdBlocked) { + this.vc.createEmbeddedView(this.tr) + } else { + this.vc.clear() + } + } else { + if (this.showWhenAdBlocked) { + this.vc.clear() + } else { + this.vc.createEmbeddedView(this.tr) + } + } + this.cd.detectChanges() + }) + } + + ngOnDestroy() { + this.ngOnDestroy$.next() + this.ngOnDestroy$.complete() + } +} + +const IF_BLOCKED_SELECTOR = 'floIfAdBlocked' +const IF_NOT_BLOCKED_SELECTOR = 'floIfNotAdBlocked' + +@Directive({ + selector: `[${IF_BLOCKED_SELECTOR}]`, + inputs: [IF_BLOCKED_SELECTOR] +}) +export class FloIfAdBlockedDirective extends FloAdBlockDirective { + constructor(protected tr: TemplateRef, protected vc: ViewContainerRef, protected ads: AdBlockService, + protected cd: ChangeDetectorRef) { + super(tr, vc, ads, cd) + this.showWhenAdBlocked = true + } + + readonly elmInputKey = IF_BLOCKED_SELECTOR +} + +@Directive({ + selector: `[${IF_NOT_BLOCKED_SELECTOR}]`, + inputs: [IF_NOT_BLOCKED_SELECTOR] +}) +export class FloIfNotAdBlockedDirective extends FloAdBlockDirective { + constructor(protected tr: TemplateRef, protected vc: ViewContainerRef, protected ads: AdBlockService, + protected cd: ChangeDetectorRef) { + super(tr, vc, ads, cd) + this.showWhenAdBlocked = false + } + + readonly elmInputKey = IF_NOT_BLOCKED_SELECTOR +} diff --git a/projects/flosportsinc/ng-ad-block/common/ad-block.module.ts b/projects/flosportsinc/ng-ad-block/common/ad-block.module.ts index a71e3fa6..4f8e3adc 100644 --- a/projects/flosportsinc/ng-ad-block/common/ad-block.module.ts +++ b/projects/flosportsinc/ng-ad-block/common/ad-block.module.ts @@ -1,7 +1,10 @@ import { NgModule } from '@angular/core' import { AdBlockService } from './ad-block.service' +import { FloIfAdBlockedDirective, FloIfNotAdBlockedDirective } from './ad-block.directive' @NgModule({ - providers: [AdBlockService] + providers: [AdBlockService], + declarations: [FloIfAdBlockedDirective, FloIfNotAdBlockedDirective], + exports: [FloIfAdBlockedDirective, FloIfNotAdBlockedDirective] }) export class FloAdBlockModule { } diff --git a/projects/flosportsinc/ng-ad-block/public_api.ts b/projects/flosportsinc/ng-ad-block/public_api.ts index 33f3daac..c6d03fc9 100644 --- a/projects/flosportsinc/ng-ad-block/public_api.ts +++ b/projects/flosportsinc/ng-ad-block/public_api.ts @@ -2,3 +2,4 @@ export * from './common/ad-block.interface' export * from './common/ad-block.module' export * from './common/ad-block.service' export * from './common/ad-block.tokens' +export * from './common/ad-block.directive' diff --git a/src/app/flo.module.ts b/src/app/flo.module.ts index 8d58d6df..03e93af3 100644 --- a/src/app/flo.module.ts +++ b/src/app/flo.module.ts @@ -8,9 +8,11 @@ import { FloNodeEnvTransferModule } from '@flosportsinc/ng-env-transfer-state' import { FloFullscreenModule } from '@flosportsinc/ng-fullscreen' import { FloFetchFillModule } from '@flosportsinc/ng-fetch-fill' import { SvgTransferStateModule } from '@flosportsinc/ng-svg-transfer-state' +import { FloAdBlockModule } from '@flosportsinc/ng-ad-block' @NgModule({ imports: [ + FloAdBlockModule, FloVideoEventsModule, FloVideoAutoplayModule, FloFullscreenModule, @@ -30,6 +32,7 @@ import { SvgTransferStateModule } from '@flosportsinc/ng-svg-transfer-state' }) ], exports: [ + FloAdBlockModule, FloVideoEventsModule, FloVideoAutoplayModule, FloFullscreenModule,