From b9973f1277fad9df841abaa0424eff75e8c6de28 Mon Sep 17 00:00:00 2001
From: Miodec
Date: Tue, 12 Jul 2022 13:01:26 +0200
Subject: [PATCH] ads
---
backend/src/api/schemas/config-schema.ts | 1 +
frontend/src/styles/ads.scss | 63 +++++
frontend/src/styles/core.scss | 18 ++
frontend/src/styles/index.scss | 2 +-
frontend/src/styles/popups.scss | 39 +++
frontend/src/styles/test.scss | 3 +-
frontend/src/styles/z_media-queries.scss | 18 ++
frontend/src/ts/config.ts | 238 +++++++++---------
frontend/src/ts/constants/default-config.ts | 2 +-
frontend/src/ts/controllers/ad-controller.ts | 196 +++++++++++++++
.../src/ts/controllers/page-controller.ts | 2 +
frontend/src/ts/elements/commandline-lists.ts | 26 +-
frontend/src/ts/elements/notifications.ts | 3 +
frontend/src/ts/index.ts | 2 +
frontend/src/ts/observables/banner-event.ts | 18 ++
frontend/src/ts/pages/settings.ts | 6 +-
frontend/src/ts/popups/video-ad-popup.ts | 37 +++
frontend/src/ts/test/focus.ts | 1 +
frontend/src/ts/test/result.ts | 2 +
frontend/src/ts/test/test-logic.ts | 2 +
frontend/src/ts/types/types.d.ts | 4 +-
frontend/static/html/pages/about.html | 18 +-
frontend/static/html/pages/account.html | 17 +-
frontend/static/html/pages/settings.html | 52 ++--
frontend/static/html/pages/test.html | 17 ++
frontend/static/html/popups.html | 21 +-
frontend/static/main.html | 34 ++-
27 files changed, 671 insertions(+), 171 deletions(-)
create mode 100644 frontend/src/styles/ads.scss
create mode 100644 frontend/src/ts/controllers/ad-controller.ts
create mode 100644 frontend/src/ts/observables/banner-event.ts
create mode 100644 frontend/src/ts/popups/video-ad-popup.ts
diff --git a/backend/src/api/schemas/config-schema.ts b/backend/src/api/schemas/config-schema.ts
index 98db9a2f3..fbe038937 100644
--- a/backend/src/api/schemas/config-schema.ts
+++ b/backend/src/api/schemas/config-schema.ts
@@ -87,6 +87,7 @@ const CONFIG_SCHEMA = joi.object({
tapeMode: joi.string().valid("off", "letter", "word"),
alwaysShowCPM: joi.boolean(),
enableAds: joi.string().valid("off", "on", "max"),
+ ads: joi.string().valid("off", "result", "on", "sellout"),
hideExtraLetters: joi.boolean(),
strictSpace: joi.boolean(),
minAcc: joi.string().valid("off", "custom"),
diff --git a/frontend/src/styles/ads.scss b/frontend/src/styles/ads.scss
new file mode 100644
index 000000000..46e502dcf
--- /dev/null
+++ b/frontend/src/styles/ads.scss
@@ -0,0 +1,63 @@
+#ad-vertical-left-wrapper,
+#ad-vertical-right-wrapper {
+ margin-top: 2rem;
+ transition: margin-top 0.125s;
+}
+
+#ad-footer-wrapper,
+#ad-footer-small-wrapper {
+ justify-self: center;
+}
+
+#ad-result-wrapper,
+#ad-result-small-wrapper,
+.pageSettings .ad,
+.pageAbout .ad,
+.pageAccount .ad {
+ margin: 1rem auto 0 auto;
+}
+
+#app.focus {
+ .ad {
+ display: none;
+ }
+}
+
+.ad {
+ background: var(--sub-alt-color);
+ display: grid;
+ grid-template-areas: "col";
+
+ div {
+ grid-area: col;
+ }
+
+ .icon {
+ font-size: 3rem;
+ height: 100%;
+ width: 100%;
+ display: grid;
+ justify-content: center;
+ align-items: center;
+ color: var(--sub-color);
+ &.small {
+ font-size: 1.5rem;
+ }
+ }
+
+ &.ad-v {
+ width: 160px;
+ height: 600px;
+ }
+
+ &.ad-h {
+ width: 728px;
+ height: 90px;
+ }
+
+ &.ad-h-s {
+ width: 320px;
+ height: 50px;
+ display: none;
+ }
+}
diff --git a/frontend/src/styles/core.scss b/frontend/src/styles/core.scss
index 9b920afb6..855d9415b 100644
--- a/frontend/src/styles/core.scss
+++ b/frontend/src/styles/core.scss
@@ -35,6 +35,24 @@
/* Firefox */
}
+#app {
+ display: grid;
+ grid-template-columns: auto minmax(0, 1000px) auto;
+ justify-items: center;
+ &.wide125 {
+ grid-template-columns: auto minmax(0, 1250px) auto;
+ }
+ &.wide150 {
+ grid-template-columns: auto minmax(0, 1500px) auto;
+ }
+ &.wide200 {
+ grid-template-columns: auto minmax(0, 2000px) auto;
+ }
+ &.widemax {
+ grid-template-columns: auto minmax(0, 1fr) auto;
+ }
+}
+
#nocss {
display: none !important;
pointer-events: none;
diff --git a/frontend/src/styles/index.scss b/frontend/src/styles/index.scss
index 9e10e95ad..c37ddf495 100644
--- a/frontend/src/styles/index.scss
+++ b/frontend/src/styles/index.scss
@@ -1,4 +1,4 @@
-@import "404", "about", "account", "animations", "banners", "caret",
+@import "404", "ads", "about", "account", "animations", "banners", "caret",
"commandline", "core", "footer", "inputs", "keymap", "leaderboards", "login",
"monkey", "nav", "notifications", "popups", "profile", "scroll", "settings",
"test", "z_media-queries";
diff --git a/frontend/src/styles/popups.scss b/frontend/src/styles/popups.scss
index b2ce55c92..372bddf1b 100644
--- a/frontend/src/styles/popups.scss
+++ b/frontend/src/styles/popups.scss
@@ -479,11 +479,50 @@
place-self: center;
grid-area: check;
}
+ &.ads {
+ grid-template-columns: 1fr;
+ grid-template-areas:
+ "title"
+ "description";
+ a {
+ margin-top: 0.25rem;
+ }
+ }
}
}
}
}
+#videoAdPopupWrapper {
+ display: flex;
+ padding: 2rem;
+ #videoAdPopup {
+ background: var(--bg-color);
+ border-radius: var(--roundness);
+ padding: 2rem;
+ display: grid;
+ gap: 1rem;
+ width: 100%;
+ max-width: 1000px;
+ aspect-ratio: 16/9;
+ display: grid;
+ grid-template-areas: "middle";
+ .preloader {
+ grid-area: middle;
+ display: grid;
+ place-items: center center;
+ gap: 1rem;
+ font-size: 2rem;
+ color: var(--main-color);
+ height: max-content;
+ align-self: center;
+ }
+ .video {
+ grid-area: middle;
+ }
+ }
+}
+
#pbTablesPopupWrapper #pbTablesPopup {
.title {
color: var(--text-color);
diff --git a/frontend/src/styles/test.scss b/frontend/src/styles/test.scss
index 4671e0e7c..1e28d525c 100644
--- a/frontend/src/styles/test.scss
+++ b/frontend/src/styles/test.scss
@@ -883,7 +883,8 @@
#restartTestButtonWithSameWordset,
#nextTestButton,
#practiseWordsButton,
-#watchReplayButton {
+#watchReplayButton,
+#watchVideoAdButton {
position: relative;
border-radius: var(--roundness);
padding: 1rem 2rem;
diff --git a/frontend/src/styles/z_media-queries.scss b/frontend/src/styles/z_media-queries.scss
index 62512896d..54f259361 100644
--- a/frontend/src/styles/z_media-queries.scss
+++ b/frontend/src/styles/z_media-queries.scss
@@ -1,3 +1,12 @@
+@media only screen and (max-width: 1330px) {
+ .ad.ad-v {
+ display: none;
+ }
+ #app {
+ grid-template-columns: auto;
+ }
+}
+
@media only screen and (max-width: 1250px) {
#leaderboardsWrapper #leaderboards {
.mainTitle {
@@ -103,6 +112,12 @@
}
@media only screen and (max-width: 900px) {
+ .ad.ad-h {
+ display: none;
+ }
+ .ad.ad-h-s {
+ display: grid;
+ }
.profile .pbsWords,
.profile .pbsTime {
font-size: 1rem;
@@ -827,6 +842,9 @@
}
@media only screen and (max-width: 350px) {
+ .ad.ad-h-s {
+ display: none;
+ }
#keymap {
display: none !important;
}
diff --git a/frontend/src/ts/config.ts b/frontend/src/ts/config.ts
index f47caeeab..acd5caf5e 100644
--- a/frontend/src/ts/config.ts
+++ b/frontend/src/ts/config.ts
@@ -542,31 +542,22 @@ export function setQuickEnd(qe: boolean, nosave?: boolean): boolean {
return true;
}
-export function setEnableAds(
- val: MonkeyTypes.EnableAds,
- nosave?: boolean
-): boolean {
- if (!isConfigValueValid("enable ads", val, [["on", "off", "max"]])) {
+export function setAds(val: MonkeyTypes.Ads, nosave?: boolean): boolean {
+ if (!isConfigValueValid("ads", val, [["off", "result", "on", "sellout"]])) {
return false;
}
- config.enableAds = "off";
+ config.ads = val;
+ saveToLocalStorage("ads", nosave);
if (!nosave) {
- saveToLocalStorage("enableAds", nosave);
- Notifications.add("Ads have been temporarily disabled", 0);
+ setTimeout(() => {
+ location.reload();
+ }, 3000);
+ Notifications.add("Ad settings changed. Refreshing...", 0);
}
+ ConfigEvent.dispatch("ads", config.ads);
+
return true;
-
- // config.enableAds = val;
- // if (!nosave) {
- // saveToLocalStorage("enableAds", nosave);
- // setTimeout(() => {
- // location.reload();
- // }, 3000);
- // Notifications.add("Ad settings changed. Refreshing...", 0);
- // }
-
- // return true;
}
export function setRepeatQuotes(
@@ -652,9 +643,14 @@ export function setPageWidth(
$("#centerContent").removeClass("wide150");
$("#centerContent").removeClass("wide200");
$("#centerContent").removeClass("widemax");
+ $("#app").removeClass("wide125");
+ $("#app").removeClass("wide150");
+ $("#app").removeClass("wide200");
+ $("#app").removeClass("widemax");
if (val !== "100") {
$("#centerContent").addClass("wide" + val);
+ $("#app").addClass("wide" + val);
}
saveToLocalStorage("pageWidth", nosave);
ConfigEvent.dispatch("pageWidth", config.pageWidth);
@@ -1818,120 +1814,122 @@ export function apply(
setLazyMode(configObj.lazyMode, true);
setShowAverage(configObj.showAverage, true);
setTapeMode(configObj.tapeMode, true);
+ setAds(configObj.ads, true);
- try {
- setEnableAds(configObj.enableAds, true);
+ // try {
+ // setEnableAds(configObj.enableAds, true);
- if (config.enableAds === "max" || config.enableAds === "on") {
- // $("head").append(`
- //
- // `);
+ // if (config.enableAds === "max" || config.enableAds === "on") {
+ // // $("head").append(`
+ // //
+ // // `);
- if (config.enableAds === "max") {
- //
+ // if (config.enableAds === "max") {
+ // //
- $("#ad_rich_media").removeClass("hidden");
- $("#ad_rich_media")
- .html
- // `
`
- ();
- } else {
- $("#ad_rich_media").remove();
- }
+ // $("#ad_rich_media").removeClass("hidden");
+ // $("#ad_rich_media")
+ // .html
+ // // `
`
+ // ();
+ // } else {
+ // $("#ad_rich_media").remove();
+ // }
- //
+ // //
- $("#ad_footer")
- .html
- // `
`
- ();
- $("#ad_footer").removeClass("hidden");
+ // $("#ad_footer")
+ // .html
+ // // `
`
+ // ();
+ // $("#ad_footer").removeClass("hidden");
- // $("#ad_footer2").html(`
`);
- // $("#ad_footer2").removeClass("hidden");
+ // // $("#ad_footer2").html(`
`);
+ // // $("#ad_footer2").removeClass("hidden");
- $("#ad_about1")
- .html
- // `
`
- ();
- $("#ad_about1").removeClass("hidden");
+ // $("#ad_about1")
+ // .html
+ // // `
`
+ // ();
+ // $("#ad_about1").removeClass("hidden");
- $("#ad_about2")
- .html
- // `
`
- ();
- $("#ad_about2").removeClass("hidden");
+ // $("#ad_about2")
+ // .html
+ // // `
`
+ // ();
+ // $("#ad_about2").removeClass("hidden");
- $("#ad_settings0")
- .html
- // `
`
- ();
- $("#ad_settings0").removeClass("hidden");
+ // $("#ad_settings0")
+ // .html
+ // // `
`
+ // ();
+ // $("#ad_settings0").removeClass("hidden");
- $("#ad_settings1")
- .html
- // `
`
- ();
- $("#ad_settings1").removeClass("hidden");
+ // $("#ad_settings1")
+ // .html
+ // // `
`
+ // ();
+ // $("#ad_settings1").removeClass("hidden");
- $("#ad_settings2")
- .html
- // `
`
- ();
- $("#ad_settings2").removeClass("hidden");
+ // $("#ad_settings2")
+ // .html
+ // // `
`
+ // ();
+ // $("#ad_settings2").removeClass("hidden");
- $("#ad_settings3")
- .html
- // `
`
- ();
- $("#ad_settings3").removeClass("hidden");
+ // $("#ad_settings3")
+ // .html
+ // // `
`
+ // ();
+ // $("#ad_settings3").removeClass("hidden");
+
+ // $("#ad_account")
+ // .html
+ // // `
`
+ // ();
+ // $("#ad_account").removeClass("hidden");
+ // $(".footerads").removeClass("hidden");
+ // } else {
+ // $("#adScript").remove();
+ // $(".footerads").remove();
+ // $("#ad_left").remove();
+ // $("#ad_right").remove();
+ // $("#ad_footer").remove();
+ // $("#ad_footer2").remove();
+ // $("#ad_footer3").remove();
+ // $("#ad_settings0").remove();
+ // $("#ad_settings1").remove();
+ // $("#ad_settings2").remove();
+ // $("#ad_settings3").remove();
+ // $("#ad_account").remove();
+ // $("#ad_about1").remove();
+ // $("#ad_about2").remove();
+ // }
+ // } catch (e) {
+ // Notifications.add("Error initialising ads: " + (e as Error).message);
+ // console.log("error initialising ads " + (e as Error).message);
+ // $(".footerads").remove();
+ // $("#ad_left").remove();
+ // $("#ad_right").remove();
+ // $("#ad_footer").remove();
+ // $("#ad_footer2").remove();
+ // $("#ad_footer3").remove();
+ // $("#ad_settings0").remove();
+ // $("#ad_settings1").remove();
+ // $("#ad_settings2").remove();
+ // $("#ad_settings3").remove();
+ // $("#ad_account").remove();
+ // $("#ad_about1").remove();
+ // $("#ad_about2").remove();
+ // }
- $("#ad_account")
- .html
- // `
`
- ();
- $("#ad_account").removeClass("hidden");
- $(".footerads").removeClass("hidden");
- } else {
- $("#adScript").remove();
- $(".footerads").remove();
- $("#ad_left").remove();
- $("#ad_right").remove();
- $("#ad_footer").remove();
- $("#ad_footer2").remove();
- $("#ad_footer3").remove();
- $("#ad_settings0").remove();
- $("#ad_settings1").remove();
- $("#ad_settings2").remove();
- $("#ad_settings3").remove();
- $("#ad_account").remove();
- $("#ad_about1").remove();
- $("#ad_about2").remove();
- }
- } catch (e) {
- Notifications.add("Error initialising ads: " + (e as Error).message);
- console.log("error initialising ads " + (e as Error).message);
- $(".footerads").remove();
- $("#ad_left").remove();
- $("#ad_right").remove();
- $("#ad_footer").remove();
- $("#ad_footer2").remove();
- $("#ad_footer3").remove();
- $("#ad_settings0").remove();
- $("#ad_settings1").remove();
- $("#ad_settings2").remove();
- $("#ad_settings3").remove();
- $("#ad_account").remove();
- $("#ad_about1").remove();
- $("#ad_about2").remove();
- }
ConfigEvent.dispatch(
"configApplied",
undefined,
@@ -1967,6 +1965,8 @@ export function loadFromLocalStorage(): void {
localStorageConfig = newConfig;
saveFullConfigToLocalStorage(true);
console.log("saving localStorage config");
+ } else {
+ reset();
}
// TestLogic.restart(false, true);
loadDone();
diff --git a/frontend/src/ts/constants/default-config.ts b/frontend/src/ts/constants/default-config.ts
index 73a8d1d6a..586654d3d 100644
--- a/frontend/src/ts/constants/default-config.ts
+++ b/frontend/src/ts/constants/default-config.ts
@@ -74,7 +74,7 @@ export default {
minWpmCustomSpeed: 100,
highlightMode: "letter",
alwaysShowCPM: false,
- enableAds: "off",
+ ads: "result",
hideExtraLetters: false,
strictSpace: false,
minAcc: "off",
diff --git a/frontend/src/ts/controllers/ad-controller.ts b/frontend/src/ts/controllers/ad-controller.ts
new file mode 100644
index 000000000..71cac2224
--- /dev/null
+++ b/frontend/src/ts/controllers/ad-controller.ts
@@ -0,0 +1,196 @@
+import { debounce } from "throttle-debounce";
+import * as Misc from "../utils/misc";
+import * as ConfigEvent from "../observables/config-event";
+import * as BannerEvent from "../observables/banner-event";
+import Config from "../config";
+import * as TestActive from "../states/test-active";
+
+const breakpoint = 900;
+let widerThanBreakpoint = true;
+
+let initialised = false;
+
+export function init(): void {
+ $("head").append(``);
+ $("body")
+ .prepend(` `);
+
+ setInterval(() => {
+ if (TestActive.get()) {
+ console.log("test active - stopping ad refresh");
+ return;
+ }
+ refreshVisible();
+ console.log("refreshing visible ads");
+ }, 30000);
+
+ initialised = true;
+}
+
+export function removeAll(): void {
+ removeSellout();
+ removeOn();
+ removeResult();
+}
+
+export function removeSellout(): void {
+ $("#ad-footer-wrapper").remove();
+ $("#ad-footer-small-wrapper").remove();
+ $("#ad-about-1-wrapper").remove();
+ $("#ad-about-1-small-wrapper").remove();
+ $("#ad-about-2-wrapper").remove();
+ $("#ad-about-2-small-wrapper").remove();
+ $("#ad-settings-1-wrapper").remove();
+ $("#ad-settings-1-small-wrapper").remove();
+ $("#ad-settings-2-wrapper").remove();
+ $("#ad-settings-2-small-wrapper").remove();
+ $("#ad-settings-3-wrapper").remove();
+ $("#ad-settings-3-small-wrapper").remove();
+ $("#ad-account-1-wrapper").remove();
+ $("#ad-account-1-small-wrapper").remove();
+ $("#ad-account-2-wrapper").remove();
+ $("#ad-account-2-small-wrapper").remove();
+}
+
+export function removeOn(): void {
+ $("#ad-vertical-right-wrapper").remove();
+ $("#ad-vertical-left-wrapper").remove();
+}
+
+export function removeResult(): void {
+ $("#ad-result-wrapper").remove();
+ $("#ad-result-small-wrapper").remove();
+}
+
+function updateVerticalMargin(): void {
+ const height = $("#bannerCenter").height() as number;
+ const margin = height + Misc.convertRemToPixels(2) + "px";
+ $("#ad-vertical-left-wrapper").css("margin-top", margin);
+ $("#ad-vertical-right-wrapper").css("margin-top", margin);
+}
+
+function updateBreakpoint(noReinstate = false): void {
+ const beforeUpdate = widerThanBreakpoint;
+
+ if (window.innerWidth > breakpoint) {
+ widerThanBreakpoint = true;
+ } else {
+ widerThanBreakpoint = false;
+ }
+ if (noReinstate) return;
+ if (beforeUpdate !== widerThanBreakpoint) {
+ reinstate();
+ }
+}
+
+export async function refreshVisible(): Promise {
+ //@ts-ignore
+ const adDivs = Object.keys(window.egAdPack.gptAdSlots);
+ const visibleAdDivs = [];
+
+ for (let i = 0; i < adDivs.length; i++) {
+ const el = document.querySelectorAll(
+ "[data-adunit-name='" + adDivs[i] + "']"
+ )[0];
+ if (!el) continue;
+ const elParent = el.parentElement as HTMLElement;
+ if (
+ window.getComputedStyle(elParent).getPropertyValue("display") != "none"
+ ) {
+ visibleAdDivs.push(adDivs[i]);
+ }
+ }
+ console.log("refreshing", visibleAdDivs);
+ //@ts-ignore
+ window.egAps.refreshAds(visibleAdDivs);
+}
+
+export function reinstate(): boolean {
+ if (Config.ads === "off") return false;
+ if (!initialised) {
+ init();
+ return true;
+ }
+ try {
+ //@ts-ignore
+ window.egAps.reinstate();
+ return true;
+ } catch (e) {
+ console.error(e);
+ return false;
+ }
+}
+
+export async function renderResult(): Promise {
+ if (Config.ads === "off") return;
+ if (!initialised) {
+ init();
+ }
+ if (widerThanBreakpoint) {
+ // $("#ad-result-wrapper").html(`
+ //
+ //
+ // `);
+ // if ($("#ad-result-wrapper").is(":empty")) {
+ //@ts-ignore
+ // window.egAps.render(["ad-result"]);
+ // } else {
+ //@ts-ignore
+ window.egAps.refreshAds(["ad-result"]);
+ // }
+ } else {
+ // $("#ad-result-small-wrapper").html(`
+ //
+ //
+ // `);
+ // if ($("#ad-result-small-wrapper").is(":empty")) {
+ //@ts-ignore
+ // window.egAps.render(["ad-result-small"]);
+ // } else {
+ //@ts-ignore
+ window.egAps.refreshAds(["ad-result-small"]);
+ // }
+ }
+}
+
+export function destroyResult(): void {
+ // $("#ad-result-wrapper").empty();
+ // $("#ad-result-small-wrapper").empty();
+}
+
+const debouncedMarginUpdate = debounce(100, updateVerticalMargin);
+const debouncedBreakpointUpdate = debounce(100, updateBreakpoint);
+
+$(window).on("resize", () => {
+ debouncedMarginUpdate();
+ debouncedBreakpointUpdate();
+});
+
+ConfigEvent.subscribe((event, value) => {
+ if (event === "ads") {
+ if (value == "off") {
+ removeAll();
+ } else if (value == "result") {
+ removeSellout();
+ removeOn();
+ } else if (value == "on") {
+ removeSellout();
+ }
+ }
+});
+
+BannerEvent.subscribe(() => {
+ updateVerticalMargin();
+});
+
+$(document).ready(() => {
+ updateBreakpoint(true);
+});
diff --git a/frontend/src/ts/controllers/page-controller.ts b/frontend/src/ts/controllers/page-controller.ts
index 6ab49b3e8..bcb3ca988 100644
--- a/frontend/src/ts/controllers/page-controller.ts
+++ b/frontend/src/ts/controllers/page-controller.ts
@@ -10,6 +10,7 @@ import * as PageProfile from "../pages/profile";
import * as Page404 from "../pages/404";
import * as PageTransition from "../states/page-transition";
import type Page from "../pages/page";
+import * as AdController from "../controllers/ad-controller";
export async function change(
page: Page,
@@ -58,6 +59,7 @@ export async function change(
nextPage?.afterShow();
},
async () => {
+ AdController.reinstate();
await nextPage?.beforeShow(params);
}
);
diff --git a/frontend/src/ts/elements/commandline-lists.ts b/frontend/src/ts/elements/commandline-lists.ts
index dadd74c40..9ac2b2020 100644
--- a/frontend/src/ts/elements/commandline-lists.ts
+++ b/frontend/src/ts/elements/commandline-lists.ts
@@ -1212,30 +1212,38 @@ const commandsDifficulty: MonkeyTypes.CommandsGroup = {
export const commandsEnableAds: MonkeyTypes.CommandsGroup = {
title: "Set enable ads...",
- configKey: "enableAds",
+ configKey: "ads",
list: [
{
id: "setEnableAdsOff",
display: "off",
configValue: "off",
exec: (): void => {
- UpdateConfig.setEnableAds("off");
+ UpdateConfig.setAds("off");
},
},
{
id: "setEnableAdsOn",
- display: "on",
- configValue: "on",
+ display: "result",
+ configValue: "result",
exec: (): void => {
- UpdateConfig.setEnableAds("on");
+ UpdateConfig.setAds("result");
},
},
{
- id: "setEnableMax",
- display: "sellout",
- configValue: "max",
+ id: "setEnableOn",
+ display: "on",
+ configValue: "on",
exec: (): void => {
- UpdateConfig.setEnableAds("max");
+ UpdateConfig.setAds("on");
+ },
+ },
+ {
+ id: "setEnableSellout",
+ display: "sellout",
+ configValue: "sellout",
+ exec: (): void => {
+ UpdateConfig.setAds("sellout");
},
},
],
diff --git a/frontend/src/ts/elements/notifications.ts b/frontend/src/ts/elements/notifications.ts
index b5c224aba..8117c97a9 100644
--- a/frontend/src/ts/elements/notifications.ts
+++ b/frontend/src/ts/elements/notifications.ts
@@ -1,5 +1,6 @@
import { debounce } from "throttle-debounce";
import * as Misc from "../utils/misc";
+import * as BannerEvent from "../observables/banner-event";
function updateMargin(): void {
console.log("updating margin");
@@ -165,6 +166,7 @@ class Notification {
`);
updateMargin();
+ BannerEvent.dispatch();
if (this.duration >= 0) {
$(`#bannerCenter .banner[id='${this.id}'] .closeButton`).on(
"click",
@@ -213,6 +215,7 @@ class Notification {
() => {
$(`#bannerCenter .banner[id='${this.id}']`).remove();
updateMargin();
+ BannerEvent.dispatch();
}
);
}
diff --git a/frontend/src/ts/index.ts b/frontend/src/ts/index.ts
index c0e905579..ea4b062af 100644
--- a/frontend/src/ts/index.ts
+++ b/frontend/src/ts/index.ts
@@ -5,6 +5,7 @@ import "./firebase";
import * as DB from "./db";
import "./ui";
+import "./controllers/ad-controller";
import Config from "./config";
import * as TestStats from "./test/test-stats";
import * as Replay from "./test/replay";
@@ -17,6 +18,7 @@ import "./test/caps-warning";
import "./popups/support-popup";
import "./popups/contact-popup";
import "./popups/version-popup";
+import "./popups/video-ad-popup";
import "./popups/edit-preset-popup";
import "./popups/simple-popups";
import "./controllers/input-controller";
diff --git a/frontend/src/ts/observables/banner-event.ts b/frontend/src/ts/observables/banner-event.ts
new file mode 100644
index 000000000..6d6b72ccd
--- /dev/null
+++ b/frontend/src/ts/observables/banner-event.ts
@@ -0,0 +1,18 @@
+type SubscribeFunction = () => void;
+
+const subscribers: SubscribeFunction[] = [];
+
+export function subscribe(fn: SubscribeFunction): void {
+ subscribers.push(fn);
+}
+
+export function dispatch(): void {
+ subscribers.forEach((fn) => {
+ try {
+ fn();
+ } catch (e) {
+ console.error("Banner event subscriber threw an error");
+ console.error(e);
+ }
+ });
+}
diff --git a/frontend/src/ts/pages/settings.ts b/frontend/src/ts/pages/settings.ts
index f5e318df7..707d3eafe 100644
--- a/frontend/src/ts/pages/settings.ts
+++ b/frontend/src/ts/pages/settings.ts
@@ -166,11 +166,7 @@ async function initGroups(): Promise {
UpdateConfig.setRepeatQuotes,
"button"
);
- groups["enableAds"] = new SettingsGroup(
- "enableAds",
- UpdateConfig.setEnableAds,
- "button"
- );
+ groups["ads"] = new SettingsGroup("ads", UpdateConfig.setAds, "button");
groups["alwaysShowWordsHistory"] = new SettingsGroup(
"alwaysShowWordsHistory",
UpdateConfig.setAlwaysShowWordsHistory,
diff --git a/frontend/src/ts/popups/video-ad-popup.ts b/frontend/src/ts/popups/video-ad-popup.ts
new file mode 100644
index 000000000..c723c25f1
--- /dev/null
+++ b/frontend/src/ts/popups/video-ad-popup.ts
@@ -0,0 +1,37 @@
+function show(): void {
+ if ($("#videoAdPopupWrapper").hasClass("hidden")) {
+ $("#videoAdPopupWrapper")
+ .stop(true, true)
+ .css("opacity", 0)
+ .removeClass("hidden")
+ .animate({ opacity: 1 }, 100, () => {
+ //@ts-ignore
+ window.dataLayer.push({ event: "EG_Video" });
+ });
+ }
+}
+
+function hide(): void {
+ if (!$("#videoAdPopupWrapper").hasClass("hidden")) {
+ $("#videoAdPopupWrapper")
+ .stop(true, true)
+ .css("opacity", 1)
+ .animate(
+ {
+ opacity: 0,
+ },
+ 100,
+ () => {
+ $("#videoAdPopupWrapper").addClass("hidden");
+ }
+ );
+ }
+}
+
+$(".pageTest #watchVideoAdButton").on("click", () => {
+ show();
+});
+
+$("#videoAdPopup .button").on("click", (e) => {
+ hide();
+});
diff --git a/frontend/src/ts/test/focus.ts b/frontend/src/ts/test/focus.ts
index 032e6f66f..a44324482 100644
--- a/frontend/src/ts/test/focus.ts
+++ b/frontend/src/ts/test/focus.ts
@@ -23,6 +23,7 @@ export function set(foc: boolean, withCursor = false): void {
$("#middle").removeClass("focus");
$("#bannerCenter").removeClass("focus");
$("#capsWarning").removeClass("focus");
+ $("#app").removeClass("focus");
}
}
diff --git a/frontend/src/ts/test/result.ts b/frontend/src/ts/test/result.ts
index 6594f6822..066309442 100644
--- a/frontend/src/ts/test/result.ts
+++ b/frontend/src/ts/test/result.ts
@@ -14,6 +14,7 @@ import * as TestInput from "./test-input";
import * as Notifications from "../elements/notifications";
import * as Loader from "../elements/loader";
import QuotesController from "../controllers/quotes-controller";
+import * as AdController from "../controllers/ad-controller";
import { Chart } from "chart.js";
import { Auth } from "../firebase";
@@ -710,6 +711,7 @@ export async function update(
$("#result"),
250,
async () => {
+ AdController.renderResult();
TestUI.setResultCalculating(false);
$("#words").empty();
ChartController.result.resize();
diff --git a/frontend/src/ts/test/test-logic.ts b/frontend/src/ts/test/test-logic.ts
index ea3a104ad..41baf942c 100644
--- a/frontend/src/ts/test/test-logic.ts
+++ b/frontend/src/ts/test/test-logic.ts
@@ -53,6 +53,7 @@ import * as Monkey from "./monkey";
import objectHash from "object-hash";
import * as AnalyticsController from "../controllers/analytics-controller";
import { Auth } from "../firebase";
+import * as AdController from "../controllers/ad-controller";
let failReason = "";
@@ -483,6 +484,7 @@ export function restart(
$("#monkey").stop(true, true).css({ animationDuration: "0s" });
$("#typingTest").css("opacity", 0).removeClass("hidden");
$("#wordsInput").val(" ");
+ AdController.destroyResult();
let shouldQuoteRepeat = false;
if (
Config.mode === "quote" &&
diff --git a/frontend/src/ts/types/types.d.ts b/frontend/src/ts/types/types.d.ts
index 5237e2966..b2ea076db 100644
--- a/frontend/src/ts/types/types.d.ts
+++ b/frontend/src/ts/types/types.d.ts
@@ -102,7 +102,7 @@ declare namespace MonkeyTypes {
type HighlightMode = "off" | "letter" | "word";
- type EnableAds = "off" | "on" | "max";
+ type Ads = "off" | "result" | "on" | "sellout";
type MinimumAccuracy = "off" | "custom";
@@ -363,7 +363,7 @@ declare namespace MonkeyTypes {
minWpmCustomSpeed: number;
highlightMode: HighlightMode;
alwaysShowCPM: boolean;
- enableAds: EnableAds;
+ ads: Ads;
hideExtraLetters: boolean;
strictSpace: boolean;
minAcc: MinimumAccuracy;
diff --git a/frontend/static/html/pages/about.html b/frontend/static/html/pages/about.html
index 5e1ea0bc4..63d96f641 100644
--- a/frontend/static/html/pages/about.html
+++ b/frontend/static/html/pages/about.html
@@ -71,7 +71,14 @@
mapped onto a scale from 0 to 100.
-
+
+
results screen
@@ -217,7 +224,14 @@
themes and more
-
+
+
supporters
diff --git a/frontend/static/html/pages/account.html b/frontend/static/html/pages/account.html
index 3b19ee42f..5864b2b12 100644
--- a/frontend/static/html/pages/account.html
+++ b/frontend/static/html/pages/account.html
@@ -280,7 +280,14 @@
-
+
+
+
+
diff --git a/frontend/static/html/pages/settings.html b/frontend/static/html/pages/settings.html
index cb29f572d..5baa33816 100644
--- a/frontend/static/html/pages/settings.html
+++ b/frontend/static/html/pages/settings.html
@@ -27,7 +27,16 @@
danger zone
-
+
+
+
+
account
@@ -773,7 +782,14 @@
-
+
+
sound
@@ -1605,7 +1621,14 @@
-
+
+
theme
@@ -2308,24 +2331,27 @@
-
-
enable ads
+
+
ads
- If you wish to support me without directly donating you can enable ads
- that will be visible at the bottom of the screen. Sellout mode also
- shows ads on both sides of the screen.
+ You can disable or enable ads at any time. "Result" will show one ad on
+ the result page, "on" will add floating vertical banners, and "sellout"
+ will add multiple ads on every page.
(changes will take effect after a refresh).
+
+
monkeytype.com
diff --git a/frontend/static/html/popups.html b/frontend/static/html/popups.html
index 3edc45d23..5855f0e65 100644
--- a/frontend/static/html/popups.html
+++ b/frontend/static/html/popups.html
@@ -64,14 +64,19 @@
-
+
Accept selected
@@ -218,6 +223,16 @@
+
+