From d37b9901599c7953a8601e1946786210125c0c84 Mon Sep 17 00:00:00 2001 From: Ryan Barlow Date: Wed, 11 Feb 2026 21:35:16 +0000 Subject: [PATCH 1/4] hide ads properly --- src/client/GutterAds.ts | 165 +++++++++++++++++++++++++++++++++------- 1 file changed, 139 insertions(+), 26 deletions(-) diff --git a/src/client/GutterAds.ts b/src/client/GutterAds.ts index 4495a802a3..1462aad62d 100644 --- a/src/client/GutterAds.ts +++ b/src/client/GutterAds.ts @@ -9,10 +9,25 @@ export class GutterAds extends LitElement { @state() private adLoaded: boolean = false; + @state() + private isXlViewport: boolean = false; + + @state() + private leftAdVisible: boolean = false; + + @state() + private rightAdVisible: boolean = false; + + @state() + private isProbingAds: boolean = false; + private leftAdType: string = "standard_iab_left2"; private rightAdType: string = "standard_iab_rght1"; private leftContainerId: string = "gutter-ad-container-left"; private rightContainerId: string = "gutter-ad-container-right"; + private xlMediaQuery: MediaQueryList | null = null; + private noContentCheckTimer: number | null = null; + private noContentCheckCount = 0; // Override createRenderRoot to disable shadow DOM createRenderRoot() { @@ -23,6 +38,10 @@ export class GutterAds extends LitElement { connectedCallback() { super.connectedCallback(); + this.xlMediaQuery = window.matchMedia("(min-width: 1280px)"); + this.isXlViewport = this.xlMediaQuery.matches; + this.xlMediaQuery.addEventListener("change", this.handleViewportChange); + document.addEventListener("userMeResponse", () => { if (window.adsEnabled) { console.log("showing gutter ads"); @@ -41,24 +60,50 @@ export class GutterAds extends LitElement { public show(): void { this.isVisible = true; + this.leftAdVisible = false; + this.rightAdVisible = false; + this.isProbingAds = true; this.requestUpdate(); - // Wait for the update to complete, then load ads - this.updateComplete.then(() => { - this.loadAds(); - }); + if (this.isXlViewport) { + // Wait for the update to complete, then load ads + this.updateComplete.then(() => { + this.loadAds(); + }); + } } public close(): void { try { window.ramp.destroyUnits(this.leftAdType); window.ramp.destroyUnits(this.rightAdType); + this.adLoaded = false; + this.leftAdVisible = false; + this.rightAdVisible = false; + this.isProbingAds = false; + this.stopNoContentCheck(); console.log("successfully destroyed gutter ads"); } catch (e) { console.error("error destroying gutter ads", e); } } + private handleViewportChange = (event: MediaQueryListEvent) => { + this.isXlViewport = event.matches; + + if (!this.isXlViewport && this.adLoaded) { + this.close(); + return; + } + + if (this.isVisible && this.isXlViewport) { + this.requestUpdate(); + this.updateComplete.then(() => { + this.loadAds(); + }); + } + }; + private loadAds(): void { console.log("loading ramp ads"); // Ensure the container elements exist before loading ads @@ -94,6 +139,7 @@ export class GutterAds extends LitElement { }, ]); this.adLoaded = true; + this.startNoContentCheck(); console.log( "Playwire ads loaded:", this.leftAdType, @@ -108,37 +154,104 @@ export class GutterAds extends LitElement { } } + private hasInjectedAdContent(containerId: string): boolean { + const container = this.querySelector(`#${containerId}`); + if (!container) return false; + + // Treat common ad payload elements as real content. + if ( + container.querySelector("iframe, img, video, ins, canvas, object, embed") + ) { + return true; + } + + const root = container.firstElementChild as HTMLElement | null; + if (!root) return false; + if (root.childElementCount > 0) return true; + + return Boolean(root.textContent?.trim()); + } + + private startNoContentCheck(): void { + this.stopNoContentCheck(); + this.noContentCheckCount = 0; + this.isProbingAds = true; + + this.noContentCheckTimer = window.setInterval(() => { + this.noContentCheckCount += 1; + this.leftAdVisible = this.hasInjectedAdContent(this.leftContainerId); + this.rightAdVisible = this.hasInjectedAdContent(this.rightContainerId); + + if (this.noContentCheckCount >= 10) { + this.isProbingAds = false; + this.adLoaded = this.leftAdVisible || this.rightAdVisible; + if (!this.adLoaded) { + this.isVisible = false; + this.stopNoContentCheck(); + } + } + }, 1000); + } + + private stopNoContentCheck(): void { + if (this.noContentCheckTimer) { + window.clearInterval(this.noContentCheckTimer); + this.noContentCheckTimer = null; + } + } + disconnectedCallback() { + this.xlMediaQuery?.removeEventListener("change", this.handleViewportChange); + this.xlMediaQuery = null; + this.stopNoContentCheck(); super.disconnectedCallback(); } render() { - if (!this.isVisible) { + if (!this.isVisible || !this.isXlViewport) { return html``; } + const leftMounted = this.leftAdVisible || this.isProbingAds; + const rightMounted = this.rightAdVisible || this.isProbingAds; + const probeClass = + "absolute w-px h-px overflow-hidden pointer-events-none opacity-0"; + const leftClass = this.leftAdVisible + ? "fixed flex transform -translate-y-1/2 w-[160px] min-h-[600px] z-[100] pointer-events-auto items-center justify-center" + : probeClass; + const rightClass = this.rightAdVisible + ? "fixed flex transform -translate-y-1/2 w-[160px] min-h-[600px] z-[100] pointer-events-auto items-center justify-center" + : probeClass; + return html` - - - - - + ${leftMounted + ? html` + +
+
+
+ ` + : html``} + ${rightMounted + ? html` + +
+
+
+ ` + : html``} `; } } From 1ba2d0f3a140c548725f48625f90fa4c8c479938 Mon Sep 17 00:00:00 2001 From: Ryan Barlow Date: Wed, 11 Feb 2026 21:45:20 +0000 Subject: [PATCH 2/4] rabbit --- src/client/GutterAds.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/client/GutterAds.ts b/src/client/GutterAds.ts index 1462aad62d..c98782b565 100644 --- a/src/client/GutterAds.ts +++ b/src/client/GutterAds.ts @@ -74,14 +74,16 @@ export class GutterAds extends LitElement { } public close(): void { + this.isVisible = false; + this.adLoaded = false; + this.leftAdVisible = false; + this.rightAdVisible = false; + this.isProbingAds = false; + this.stopNoContentCheck(); + try { window.ramp.destroyUnits(this.leftAdType); window.ramp.destroyUnits(this.rightAdType); - this.adLoaded = false; - this.leftAdVisible = false; - this.rightAdVisible = false; - this.isProbingAds = false; - this.stopNoContentCheck(); console.log("successfully destroyed gutter ads"); } catch (e) { console.error("error destroying gutter ads", e); @@ -183,11 +185,11 @@ export class GutterAds extends LitElement { this.rightAdVisible = this.hasInjectedAdContent(this.rightContainerId); if (this.noContentCheckCount >= 10) { + this.stopNoContentCheck(); this.isProbingAds = false; this.adLoaded = this.leftAdVisible || this.rightAdVisible; if (!this.adLoaded) { this.isVisible = false; - this.stopNoContentCheck(); } } }, 1000); From bad0e24258c27a3d7f88fa5226dd25097caccbe4 Mon Sep 17 00:00:00 2001 From: Ryan Barlow Date: Wed, 11 Feb 2026 21:56:45 +0000 Subject: [PATCH 3/4] rabbit --- src/client/GutterAds.ts | 63 ++++++++++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 20 deletions(-) diff --git a/src/client/GutterAds.ts b/src/client/GutterAds.ts index c98782b565..0977306fcc 100644 --- a/src/client/GutterAds.ts +++ b/src/client/GutterAds.ts @@ -9,6 +9,8 @@ export class GutterAds extends LitElement { @state() private adLoaded: boolean = false; + private adLoadRequested: boolean = false; + @state() private isXlViewport: boolean = false; @@ -28,6 +30,15 @@ export class GutterAds extends LitElement { private xlMediaQuery: MediaQueryList | null = null; private noContentCheckTimer: number | null = null; private noContentCheckCount = 0; + private adWorkToken = 0; + private handleUserMeResponse = () => { + if (window.adsEnabled) { + console.log("showing gutter ads"); + this.show(); + } else { + console.log("not showing gutter ads"); + } + }; // Override createRenderRoot to disable shadow DOM createRenderRoot() { @@ -41,15 +52,7 @@ export class GutterAds extends LitElement { this.xlMediaQuery = window.matchMedia("(min-width: 1280px)"); this.isXlViewport = this.xlMediaQuery.matches; this.xlMediaQuery.addEventListener("change", this.handleViewportChange); - - document.addEventListener("userMeResponse", () => { - if (window.adsEnabled) { - console.log("showing gutter ads"); - this.show(); - } else { - console.log("not showing gutter ads"); - } - }); + document.addEventListener("userMeResponse", this.handleUserMeResponse); } // Called after the component's DOM is first rendered @@ -59,7 +62,10 @@ export class GutterAds extends LitElement { } public show(): void { + this.adWorkToken += 1; this.isVisible = true; + this.adLoaded = false; + this.adLoadRequested = false; this.leftAdVisible = false; this.rightAdVisible = false; this.isProbingAds = true; @@ -74,8 +80,10 @@ export class GutterAds extends LitElement { } public close(): void { + this.adWorkToken += 1; this.isVisible = false; this.adLoaded = false; + this.adLoadRequested = false; this.leftAdVisible = false; this.rightAdVisible = false; this.isProbingAds = false; @@ -93,7 +101,7 @@ export class GutterAds extends LitElement { private handleViewportChange = (event: MediaQueryListEvent) => { this.isXlViewport = event.matches; - if (!this.isXlViewport && this.adLoaded) { + if (!this.isXlViewport && (this.adLoaded || this.isProbingAds)) { this.close(); return; } @@ -107,6 +115,7 @@ export class GutterAds extends LitElement { }; private loadAds(): void { + const adWorkToken = this.adWorkToken; console.log("loading ramp ads"); // Ensure the container elements exist before loading ads const leftContainer = this.querySelector(`#${this.leftContainerId}`); @@ -122,13 +131,19 @@ export class GutterAds extends LitElement { return; } - if (this.adLoaded) { + if (this.adLoadRequested || this.adLoaded) { console.log("Ads already loaded, skipping"); return; } + this.adLoadRequested = true; + try { window.ramp.que.push(() => { + if (adWorkToken !== this.adWorkToken || !this.isVisible) { + return; + } + try { window.ramp.spaAddAds([ { @@ -140,18 +155,19 @@ export class GutterAds extends LitElement { selectorId: this.rightContainerId, }, ]); - this.adLoaded = true; - this.startNoContentCheck(); + this.startNoContentCheck(adWorkToken); console.log( "Playwire ads loaded:", this.leftAdType, this.rightAdType, ); } catch (e) { + this.adLoadRequested = false; console.log(e); } }); } catch (error) { + this.adLoadRequested = false; console.error("Failed to load Playwire ads:", error); } } @@ -174,12 +190,17 @@ export class GutterAds extends LitElement { return Boolean(root.textContent?.trim()); } - private startNoContentCheck(): void { + private startNoContentCheck(adWorkToken: number): void { this.stopNoContentCheck(); this.noContentCheckCount = 0; this.isProbingAds = true; this.noContentCheckTimer = window.setInterval(() => { + if (adWorkToken !== this.adWorkToken) { + this.stopNoContentCheck(); + return; + } + this.noContentCheckCount += 1; this.leftAdVisible = this.hasInjectedAdContent(this.leftContainerId); this.rightAdVisible = this.hasInjectedAdContent(this.rightContainerId); @@ -188,7 +209,9 @@ export class GutterAds extends LitElement { this.stopNoContentCheck(); this.isProbingAds = false; this.adLoaded = this.leftAdVisible || this.rightAdVisible; + this.adLoadRequested = this.adLoaded; if (!this.adLoaded) { + this.adLoadRequested = false; this.isVisible = false; } } @@ -203,7 +226,9 @@ export class GutterAds extends LitElement { } disconnectedCallback() { + this.adWorkToken += 1; this.xlMediaQuery?.removeEventListener("change", this.handleViewportChange); + document.removeEventListener("userMeResponse", this.handleUserMeResponse); this.xlMediaQuery = null; this.stopNoContentCheck(); super.disconnectedCallback(); @@ -218,12 +243,10 @@ export class GutterAds extends LitElement { const rightMounted = this.rightAdVisible || this.isProbingAds; const probeClass = "absolute w-px h-px overflow-hidden pointer-events-none opacity-0"; - const leftClass = this.leftAdVisible - ? "fixed flex transform -translate-y-1/2 w-[160px] min-h-[600px] z-[100] pointer-events-auto items-center justify-center" - : probeClass; - const rightClass = this.rightAdVisible - ? "fixed flex transform -translate-y-1/2 w-[160px] min-h-[600px] z-[100] pointer-events-auto items-center justify-center" - : probeClass; + const visibleClass = + "fixed flex transform -translate-y-1/2 w-[160px] min-h-[600px] z-[100] pointer-events-auto items-center justify-center"; + const leftClass = this.leftAdVisible ? visibleClass : probeClass; + const rightClass = this.rightAdVisible ? visibleClass : probeClass; return html` ${leftMounted From 50dfc8f67516b2f8a81c06e29fd0e7475b247c41 Mon Sep 17 00:00:00 2001 From: Ryan Barlow Date: Wed, 11 Feb 2026 23:56:11 +0000 Subject: [PATCH 4/4] revert --- src/client/GutterAds.ts | 214 ++++++++-------------------------------- 1 file changed, 40 insertions(+), 174 deletions(-) diff --git a/src/client/GutterAds.ts b/src/client/GutterAds.ts index 0977306fcc..e35f808862 100644 --- a/src/client/GutterAds.ts +++ b/src/client/GutterAds.ts @@ -9,36 +9,10 @@ export class GutterAds extends LitElement { @state() private adLoaded: boolean = false; - private adLoadRequested: boolean = false; - - @state() - private isXlViewport: boolean = false; - - @state() - private leftAdVisible: boolean = false; - - @state() - private rightAdVisible: boolean = false; - - @state() - private isProbingAds: boolean = false; - private leftAdType: string = "standard_iab_left2"; private rightAdType: string = "standard_iab_rght1"; private leftContainerId: string = "gutter-ad-container-left"; private rightContainerId: string = "gutter-ad-container-right"; - private xlMediaQuery: MediaQueryList | null = null; - private noContentCheckTimer: number | null = null; - private noContentCheckCount = 0; - private adWorkToken = 0; - private handleUserMeResponse = () => { - if (window.adsEnabled) { - console.log("showing gutter ads"); - this.show(); - } else { - console.log("not showing gutter ads"); - } - }; // Override createRenderRoot to disable shadow DOM createRenderRoot() { @@ -49,10 +23,14 @@ export class GutterAds extends LitElement { connectedCallback() { super.connectedCallback(); - this.xlMediaQuery = window.matchMedia("(min-width: 1280px)"); - this.isXlViewport = this.xlMediaQuery.matches; - this.xlMediaQuery.addEventListener("change", this.handleViewportChange); - document.addEventListener("userMeResponse", this.handleUserMeResponse); + document.addEventListener("userMeResponse", () => { + if (window.adsEnabled) { + console.log("showing gutter ads"); + this.show(); + } else { + console.log("not showing gutter ads"); + } + }); } // Called after the component's DOM is first rendered @@ -62,33 +40,16 @@ export class GutterAds extends LitElement { } public show(): void { - this.adWorkToken += 1; this.isVisible = true; - this.adLoaded = false; - this.adLoadRequested = false; - this.leftAdVisible = false; - this.rightAdVisible = false; - this.isProbingAds = true; this.requestUpdate(); - if (this.isXlViewport) { - // Wait for the update to complete, then load ads - this.updateComplete.then(() => { - this.loadAds(); - }); - } + // Wait for the update to complete, then load ads + this.updateComplete.then(() => { + this.loadAds(); + }); } public close(): void { - this.adWorkToken += 1; - this.isVisible = false; - this.adLoaded = false; - this.adLoadRequested = false; - this.leftAdVisible = false; - this.rightAdVisible = false; - this.isProbingAds = false; - this.stopNoContentCheck(); - try { window.ramp.destroyUnits(this.leftAdType); window.ramp.destroyUnits(this.rightAdType); @@ -98,24 +59,7 @@ export class GutterAds extends LitElement { } } - private handleViewportChange = (event: MediaQueryListEvent) => { - this.isXlViewport = event.matches; - - if (!this.isXlViewport && (this.adLoaded || this.isProbingAds)) { - this.close(); - return; - } - - if (this.isVisible && this.isXlViewport) { - this.requestUpdate(); - this.updateComplete.then(() => { - this.loadAds(); - }); - } - }; - private loadAds(): void { - const adWorkToken = this.adWorkToken; console.log("loading ramp ads"); // Ensure the container elements exist before loading ads const leftContainer = this.querySelector(`#${this.leftContainerId}`); @@ -123,27 +67,23 @@ export class GutterAds extends LitElement { if (!leftContainer || !rightContainer) { console.warn("Ad containers not found in DOM"); + this.isVisible = false; return; } if (!window.ramp) { console.warn("Playwire RAMP not available"); + this.isVisible = false; return; } - if (this.adLoadRequested || this.adLoaded) { + if (this.adLoaded) { console.log("Ads already loaded, skipping"); return; } - this.adLoadRequested = true; - try { window.ramp.que.push(() => { - if (adWorkToken !== this.adWorkToken || !this.isVisible) { - return; - } - try { window.ramp.spaAddAds([ { @@ -155,128 +95,54 @@ export class GutterAds extends LitElement { selectorId: this.rightContainerId, }, ]); - this.startNoContentCheck(adWorkToken); + this.adLoaded = true; console.log( "Playwire ads loaded:", this.leftAdType, this.rightAdType, ); } catch (e) { - this.adLoadRequested = false; + this.isVisible = false; console.log(e); } }); } catch (error) { - this.adLoadRequested = false; + this.isVisible = false; console.error("Failed to load Playwire ads:", error); } } - private hasInjectedAdContent(containerId: string): boolean { - const container = this.querySelector(`#${containerId}`); - if (!container) return false; - - // Treat common ad payload elements as real content. - if ( - container.querySelector("iframe, img, video, ins, canvas, object, embed") - ) { - return true; - } - - const root = container.firstElementChild as HTMLElement | null; - if (!root) return false; - if (root.childElementCount > 0) return true; - - return Boolean(root.textContent?.trim()); - } - - private startNoContentCheck(adWorkToken: number): void { - this.stopNoContentCheck(); - this.noContentCheckCount = 0; - this.isProbingAds = true; - - this.noContentCheckTimer = window.setInterval(() => { - if (adWorkToken !== this.adWorkToken) { - this.stopNoContentCheck(); - return; - } - - this.noContentCheckCount += 1; - this.leftAdVisible = this.hasInjectedAdContent(this.leftContainerId); - this.rightAdVisible = this.hasInjectedAdContent(this.rightContainerId); - - if (this.noContentCheckCount >= 10) { - this.stopNoContentCheck(); - this.isProbingAds = false; - this.adLoaded = this.leftAdVisible || this.rightAdVisible; - this.adLoadRequested = this.adLoaded; - if (!this.adLoaded) { - this.adLoadRequested = false; - this.isVisible = false; - } - } - }, 1000); - } - - private stopNoContentCheck(): void { - if (this.noContentCheckTimer) { - window.clearInterval(this.noContentCheckTimer); - this.noContentCheckTimer = null; - } - } - disconnectedCallback() { - this.adWorkToken += 1; - this.xlMediaQuery?.removeEventListener("change", this.handleViewportChange); - document.removeEventListener("userMeResponse", this.handleUserMeResponse); - this.xlMediaQuery = null; - this.stopNoContentCheck(); super.disconnectedCallback(); } render() { - if (!this.isVisible || !this.isXlViewport) { + if (!this.isVisible) { return html``; } - const leftMounted = this.leftAdVisible || this.isProbingAds; - const rightMounted = this.rightAdVisible || this.isProbingAds; - const probeClass = - "absolute w-px h-px overflow-hidden pointer-events-none opacity-0"; - const visibleClass = - "fixed flex transform -translate-y-1/2 w-[160px] min-h-[600px] z-[100] pointer-events-auto items-center justify-center"; - const leftClass = this.leftAdVisible ? visibleClass : probeClass; - const rightClass = this.rightAdVisible ? visibleClass : probeClass; - return html` - ${leftMounted - ? html` - -
-
-
- ` - : html``} - ${rightMounted - ? html` - -
-
-
- ` - : html``} + + + + + `; } }