mirror of
https://github.com/GNS3/gns3-web-ui.git
synced 2025-01-03 03:26:42 +00:00
Merge pull request #1052 from mother/ad-banner-updates
Ad Banner Updates
This commit is contained in:
commit
ca251bd984
@ -1,4 +1,4 @@
|
|||||||
<div [ngClass]="{dark: darkThemeEnabled, light: !darkThemeEnabled}">
|
<div [ngClass]="{dark: darkThemeEnabled, light: !darkThemeEnabled}">
|
||||||
<router-outlet></router-outlet>
|
<router-outlet></router-outlet>
|
||||||
<app-notification-box></app-notification-box>
|
<app-adbutler></app-adbutler>
|
||||||
</div>
|
</div>
|
||||||
|
@ -182,7 +182,6 @@ import { AdbutlerComponent } from './components/adbutler/adbutler.component';
|
|||||||
import { ConsoleService } from './services/settings/console.service';
|
import { ConsoleService } from './services/settings/console.service';
|
||||||
import { DefaultConsoleService } from './services/settings/default-console.service';
|
import { DefaultConsoleService } from './services/settings/default-console.service';
|
||||||
import { NodeCreatedLabelStylesFixer } from './components/project-map/helpers/node-created-label-styles-fixer';
|
import { NodeCreatedLabelStylesFixer } from './components/project-map/helpers/node-created-label-styles-fixer';
|
||||||
import { NotificationBoxComponent } from './components/notification-box/notification-box.component';
|
|
||||||
import { NonNegativeValidator } from './validators/non-negative-validator';
|
import { NonNegativeValidator } from './validators/non-negative-validator';
|
||||||
import { RotationValidator } from './validators/rotation-validator';
|
import { RotationValidator } from './validators/rotation-validator';
|
||||||
import { DuplicateActionComponent } from './components/project-map/context-menu/actions/duplicate-action/duplicate-action.component';
|
import { DuplicateActionComponent } from './components/project-map/context-menu/actions/duplicate-action/duplicate-action.component';
|
||||||
@ -400,7 +399,6 @@ import { OverlayContainer, OverlayModule } from '@angular/cdk/overlay';
|
|||||||
ShowNodeActionComponent,
|
ShowNodeActionComponent,
|
||||||
ConsoleComponent,
|
ConsoleComponent,
|
||||||
NodesMenuComponent,
|
NodesMenuComponent,
|
||||||
NotificationBoxComponent,
|
|
||||||
ProjectMapMenuComponent,
|
ProjectMapMenuComponent,
|
||||||
HelpComponent,
|
HelpComponent,
|
||||||
ConfigEditorDialogComponent,
|
ConfigEditorDialogComponent,
|
||||||
|
@ -1 +1,11 @@
|
|||||||
<div class="ad" #ad></div>
|
<div class="ad" [ngClass]="{hidden: !isVisible, lightTheme: isLightThemeEnabled}">
|
||||||
|
<div class="adInnerContainer">
|
||||||
|
<span class="adBody">
|
||||||
|
<a [href]="adUrl" target="_blank">{{ adBody }}</a>
|
||||||
|
</span>
|
||||||
|
<button>
|
||||||
|
<a target="_blank" [href]="adUrl">{{ buttonLabel }}</a>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<mat-icon (click)="hide()" class="close-button">close</mat-icon>
|
||||||
|
</div>
|
||||||
|
@ -1,30 +1,57 @@
|
|||||||
.ad {
|
.ad {
|
||||||
background-color: transparent;
|
position: fixed;
|
||||||
width: 400px;
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background-color: #a8ecff;
|
||||||
padding-top: 10px;
|
padding-top: 10px;
|
||||||
padding-bottom: 10px;
|
padding-bottom: 10px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.adInnerContainer {
|
||||||
|
margin: auto;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.adBody {
|
||||||
|
padding-right: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.close-button {
|
||||||
|
position: absolute;
|
||||||
|
top: 15px;
|
||||||
|
right: 15px;
|
||||||
|
color: #000 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightTheme {
|
||||||
|
background-color: #ddf9ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hidden {
|
||||||
|
visibility: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
button {
|
button {
|
||||||
background-color: #0097a7;
|
background-color: #01d4ff;
|
||||||
margin-top: 2px;
|
margin-top: 2px;
|
||||||
border: none;
|
border: none;
|
||||||
outline: none;
|
outline: none;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
color: white;
|
color: white;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
font-size: 11px;
|
||||||
padding-right: 15px;
|
padding-right: 15px;
|
||||||
padding-left: 15px;
|
padding-left: 15px;
|
||||||
border-radius: 4px;
|
border-radius: 6px;
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: #0097a7;
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
a {
|
a {
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #122124;
|
||||||
|
}
|
||||||
|
@ -1,47 +1,67 @@
|
|||||||
import { Component, OnInit, ElementRef, ViewChild, ViewEncapsulation, Input, Output, EventEmitter } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import { ThemeService } from '../../services/theme.service';
|
||||||
import { AdButlerResponse } from '../../models/adbutler';
|
import { AdButlerResponse } from '../../models/adbutler';
|
||||||
import { ToasterService } from '../../services/toaster.service';
|
|
||||||
|
const adButlerResponseBodyRegex: RegExp = /<a href="(.*)">(.*)<\/a><br\/>(.*)<br\/>\s*<button><a .*>(.*)<\/a>\s*<\/button>/i;
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-adbutler',
|
selector: 'app-adbutler',
|
||||||
templateUrl: './adbutler.component.html',
|
templateUrl: './adbutler.component.html',
|
||||||
styleUrls: ['./adbutler.component.scss'],
|
styleUrls: ['./adbutler.component.scss']
|
||||||
encapsulation: ViewEncapsulation.None
|
|
||||||
})
|
})
|
||||||
|
|
||||||
export class AdbutlerComponent implements OnInit {
|
export class AdbutlerComponent implements OnInit {
|
||||||
@ViewChild('ad') ad: ElementRef;
|
isVisible: boolean = false;
|
||||||
theme: string;
|
isLightThemeEnabled: boolean = false;
|
||||||
onLoad = new EventEmitter();
|
|
||||||
htmlCode: string;
|
// Default ad props in case adbutler request fails
|
||||||
staticCode: string = `<a href="https://try.solarwinds.com/gns3-free-toolset-giveaway?CMP=LEC-HAD-GNS3-SW_NA_X_NP_X_X_EN_STSGA_SW-ST-20200901_ST_OF1_TRY-NWSLTR">
|
adUrl: string = 'https://try.solarwinds.com/gns3-free-toolset-giveaway?CMP=LEC-HAD-GNS3-SW_NA_X_NP_X_X_EN_STSGA_SW-ST-20200901_ST_OF1_TRY-NWSLTR';
|
||||||
Access Our Favorite Network Free Tools!
|
adBody: string = 'Network Config Generator makes it easy configure network devices, including VLANs without opening the CLI'
|
||||||
</a><br/>
|
buttonLabel: string = 'Check it out!'
|
||||||
Access 20+ network performance management, monitoring, and troubleshooting tools for FREE ($200 Value).<br/>
|
|
||||||
<button>
|
|
||||||
<a target="_blank" href="https://try.solarwinds.com/gns3-free-toolset-giveaway?CMP=LEC-HAD-GNS3-SW_NA_X_NP_X_X_EN_STSGA_SW-ST-20200901_ST_OF1_TRY-NWSLTR">
|
|
||||||
Check it out!
|
|
||||||
</a>
|
|
||||||
</button>`;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private httpClient: HttpClient
|
private httpClient: HttpClient,
|
||||||
|
private themeService: ThemeService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
hide() {
|
||||||
|
this.isVisible = false;
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.httpClient
|
this.httpClient
|
||||||
.get('https://servedbyadbutler.com/adserve/;ID=165803;size=0x0;setID=371476;type=json;').subscribe(
|
.get<AdButlerResponse>('https://servedbyadbutler.com/adserve/;ID=165803;size=0x0;setID=371476;type=json;')
|
||||||
response => {
|
.subscribe(response => {
|
||||||
if (response && response['placements'] && response['placements'].placement_1 && response['placements'].placement_1.body) {
|
if (response?.placements?.placement_1?.body) {
|
||||||
this.onLoad.emit(true);
|
try {
|
||||||
this.htmlCode = response['placements'].placement_1.body;
|
// Use a regexp to parse the AdButler response. Preferably we would use the AdButler API
|
||||||
this.ad.nativeElement.insertAdjacentHTML('beforeend', this.htmlCode);
|
// directly to get the data we need through a JSON response, but making an API request
|
||||||
} else {
|
// involves storing credentials, which would be unwise to store in this repo. Best thing
|
||||||
this.onLoad.emit(true);
|
// would to have gns3.com proxy the JSON ad data to this web ui app.
|
||||||
this.htmlCode = this.staticCode;
|
const htmlWithoutNewlines = response.placements.placement_1.body.replace(/(\r\n|\n|\r)/gm, '');
|
||||||
|
const parsedAdResponseParts = adButlerResponseBodyRegex.exec(htmlWithoutNewlines);
|
||||||
|
|
||||||
|
// Ad title (2nd capture group) currently not used
|
||||||
|
this.adUrl = parsedAdResponseParts[1].trim();
|
||||||
|
this.adBody = parsedAdResponseParts[3].trim();
|
||||||
|
this.buttonLabel = parsedAdResponseParts[4].trim();
|
||||||
|
} catch (e) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.isVisible = true;
|
||||||
},
|
},
|
||||||
error => {}
|
error => {}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.themeService.getActualTheme() === 'light'
|
||||||
|
? this.isLightThemeEnabled = true
|
||||||
|
: this.isLightThemeEnabled = false;
|
||||||
|
|
||||||
|
this.themeService.themeChanged.subscribe(() => {
|
||||||
|
this.themeService.getActualTheme() === 'light'
|
||||||
|
? this.isLightThemeEnabled = true
|
||||||
|
: this.isLightThemeEnabled = false;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
<div class="notification-box" [ngClass]="{hidden: !isVisible}">
|
|
||||||
<mat-progress-bar mode="determinate" [value]="progress"></mat-progress-bar>
|
|
||||||
<div style="display: flex; height: 102px;">
|
|
||||||
<div class="content" [ngClass]="{lightTheme: isLightThemeEnabled}">
|
|
||||||
<template #dynamicComponentContainer></template>
|
|
||||||
<mat-icon (click)="closeNotification()" class="close-button">close</mat-icon>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
@ -1,39 +0,0 @@
|
|||||||
.notification-box {
|
|
||||||
position: fixed;
|
|
||||||
bottom: 20px;
|
|
||||||
right: 20px;
|
|
||||||
width: 412px;
|
|
||||||
height: 108px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content {
|
|
||||||
background-color: #263238;
|
|
||||||
padding-left: 8px;
|
|
||||||
border-left: 2px solid #0097a7;
|
|
||||||
border-right: 2px solid #0097a7;
|
|
||||||
border-bottom: 2px solid #0097a7;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lightTheme {
|
|
||||||
background-color: white!important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.close-button {
|
|
||||||
position: fixed;
|
|
||||||
bottom: 90px;
|
|
||||||
right: 30px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mat-icon:hover {
|
|
||||||
color: #0097a7;
|
|
||||||
}
|
|
||||||
|
|
||||||
.check-button {
|
|
||||||
background-color: #0097a7;
|
|
||||||
margin-top: -10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hidden {
|
|
||||||
visibility: hidden;
|
|
||||||
}
|
|
@ -1,118 +0,0 @@
|
|||||||
import { Component, OnInit, OnDestroy, ComponentFactoryResolver, ViewContainerRef, ViewChild } from '@angular/core';
|
|
||||||
import { timer, Observable, Subscription } from 'rxjs';
|
|
||||||
import { ThemeService } from '../../services/theme.service';
|
|
||||||
import { AdbutlerComponent } from '../adbutler/adbutler.component';
|
|
||||||
import { Router } from '@angular/router';
|
|
||||||
import { Location } from '@angular/common';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-notification-box',
|
|
||||||
templateUrl: './notification-box.component.html',
|
|
||||||
styleUrls: ['./notification-box.component.scss']
|
|
||||||
})
|
|
||||||
export class NotificationBoxComponent implements OnInit, OnDestroy {
|
|
||||||
@ViewChild('dynamicComponentContainer', { read: ViewContainerRef }) dynamicComponentContainer;
|
|
||||||
|
|
||||||
timer: Observable<number>;
|
|
||||||
viewTimer: Observable<number>;
|
|
||||||
timerSubscription: Subscription;
|
|
||||||
viewTimerSubscription: Subscription;
|
|
||||||
viewsCounter = 0;
|
|
||||||
ticks: number = 1000;
|
|
||||||
progress: number = 0;
|
|
||||||
isAdLoaded = false;
|
|
||||||
isVisible = false;
|
|
||||||
interval = 10;
|
|
||||||
|
|
||||||
delayTime: number = 5000;
|
|
||||||
breakTime: number = 20 * 60;
|
|
||||||
isEndless: boolean = true;
|
|
||||||
|
|
||||||
numberOfViews: number = 1;
|
|
||||||
isLightThemeEnabled: boolean = false;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private themeService: ThemeService,
|
|
||||||
private componentFactoryResolver: ComponentFactoryResolver,
|
|
||||||
private viewContainerRef: ViewContainerRef,
|
|
||||||
private location: Location
|
|
||||||
) {}
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
let adbutler = localStorage.getItem('adbutler');
|
|
||||||
var today = new Date().toISOString().substring(0, 10);
|
|
||||||
|
|
||||||
// to show ad once a day
|
|
||||||
// if (!this.location.path().includes('nodes') && !(adbutler == today)) this.startTimer();
|
|
||||||
|
|
||||||
if (!this.location.path().includes('nodes')) this.startTimer();
|
|
||||||
this.themeService.getActualTheme() === 'light' ? this.isLightThemeEnabled = true : this.isLightThemeEnabled = false;
|
|
||||||
|
|
||||||
this.themeService.themeChanged.subscribe((value: string) => {
|
|
||||||
this.themeService.getActualTheme() === 'light' ? this.isLightThemeEnabled = true : this.isLightThemeEnabled = false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
ngAfterViewInit() {
|
|
||||||
this.createDynamicAdComponent();
|
|
||||||
}
|
|
||||||
|
|
||||||
createDynamicAdComponent() : void {
|
|
||||||
const factory = this.componentFactoryResolver.resolveComponentFactory(AdbutlerComponent);
|
|
||||||
const componentRef = this.dynamicComponentContainer.createComponent(factory);
|
|
||||||
componentRef.instance.theme = this.themeService.getActualTheme() === 'light';
|
|
||||||
componentRef.instance.onLoad.subscribe(event => {
|
|
||||||
this.onLoadingAdbutler(event);
|
|
||||||
})
|
|
||||||
componentRef.changeDetectorRef.detectChanges();
|
|
||||||
}
|
|
||||||
|
|
||||||
startTimer() {
|
|
||||||
this.timer = timer(this.delayTime, 1000);
|
|
||||||
setTimeout(() => {
|
|
||||||
this.showNotification();
|
|
||||||
}, 5000);
|
|
||||||
|
|
||||||
this.timerSubscription = this.timer.subscribe(() => {
|
|
||||||
this.ticks++;
|
|
||||||
if (this.ticks > this.breakTime && !this.isVisible && navigator.onLine && this.isAdLoaded) {
|
|
||||||
this.ticks = 0;
|
|
||||||
this.showNotification();
|
|
||||||
this.viewsCounter++;
|
|
||||||
if (!this.isEndless){
|
|
||||||
if (this.viewsCounter === this.numberOfViews) {
|
|
||||||
this.timerSubscription.unsubscribe();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onLoadingAdbutler(event) {
|
|
||||||
this.isAdLoaded = event;
|
|
||||||
}
|
|
||||||
|
|
||||||
showNotification() {
|
|
||||||
// localStorage.setItem('adbutler', new Date().toISOString().substring(0, 10));
|
|
||||||
|
|
||||||
this.viewTimer = timer(0, 100);
|
|
||||||
this.progress = 0;
|
|
||||||
this.isVisible = true;
|
|
||||||
this.viewTimerSubscription = this.viewTimer.subscribe(() => {
|
|
||||||
this.progress += 1;
|
|
||||||
if (this.progress > 100) {
|
|
||||||
this.isVisible = false;
|
|
||||||
this.viewTimerSubscription.unsubscribe();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
closeNotification() {
|
|
||||||
this.isVisible = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnDestroy() {
|
|
||||||
this.timerSubscription.unsubscribe();
|
|
||||||
this.viewTimerSubscription.unsubscribe();
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user