Skip to content

Commit 8a5d3fa

Browse files
authored
EthicalAd: add support for fixed footer ad in all the themes (#641)
This is the logic we follow to show the fixed footer ad: * We detect the doctool/theme using our common heuristic. * The image nav bar ad is below the fold. * Inject the fixed footer ad on a specific selector (if needed, eg. "body"). * Add `padding-bottom` to specific CSS selectors to not cover content. ## Examples ### VitePress <img width="1331" height="643" alt="Screenshot_2025-09-30_13-14-45" src="https://github.com/user-attachments/assets/5d83f00e-23fb-4c2a-9124-de93d9abe721" /> ### Material for MkDocs <img width="1329" height="640" alt="Screenshot_2025-09-30_13-15-06" src="https://github.com/user-attachments/assets/bea6a67d-f7e5-4d0e-aeef-766fa25f5436" /> Closes readthedocs/meta#192
1 parent 9d7b0e3 commit 8a5d3fa

File tree

1 file changed

+55
-5
lines changed

1 file changed

+55
-5
lines changed

src/ethicalads.js

Lines changed: 55 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ export class EthicalAdsAddon extends AddonBase {
4444

4545
createAdPlacement() {
4646
let placement;
47-
let selectors;
47+
let fixedFooterAdSelectors;
4848

4949
const placementIdSuffix = docTool.getDocumentationTool() || "nodoctool";
5050

@@ -89,8 +89,8 @@ export class EthicalAdsAddon extends AddonBase {
8989
} else {
9090
// We know it's RTD theme and the ad in the navbar is not above the fold at this point.
9191
// Then, we render the ad as fixed footer.
92-
selectors = ["section", "nav"];
93-
this.setFixedFooterAdProperties(selectors, placement);
92+
fixedFooterAdSelectors = ["section", "nav"];
93+
this.setFixedFooterAdProperties(placement);
9494
knownPlacementFound = true;
9595
}
9696
} else if (docTool.isSphinxFuroLikeTheme()) {
@@ -110,6 +110,10 @@ export class EthicalAdsAddon extends AddonBase {
110110
// placement.setAttribute("data-ea-type", "readthedocs-sidebar");
111111
placement.setAttribute("data-ea-type", "image");
112112
knownPlacementFound = true;
113+
} else {
114+
fixedFooterAdSelectors = ["div.main", "aside.sidebar-drawer"];
115+
this.setFixedFooterAdProperties(placement);
116+
knownPlacementFound = true;
113117
}
114118
} else if (docTool.isSphinxBookThemeLikeTheme()) {
115119
selector = ".sidebar-primary-items__start.sidebar-primary__section";
@@ -119,6 +123,10 @@ export class EthicalAdsAddon extends AddonBase {
119123
placement.classList.add("ethical-alabaster");
120124
placement.setAttribute("data-ea-type", "readthedocs-sidebar");
121125
knownPlacementFound = true;
126+
} else {
127+
fixedFooterAdSelectors = ["div.bd-container__inner"];
128+
this.setFixedFooterAdProperties(placement);
129+
knownPlacementFound = true;
122130
}
123131
} else if (docTool.isSphinxAlabasterLikeTheme()) {
124132
selector = "div.sphinxsidebar > div.sphinxsidebarwrapper";
@@ -128,6 +136,10 @@ export class EthicalAdsAddon extends AddonBase {
128136
placement.classList.add("ethical-alabaster");
129137
placement.setAttribute("data-ea-type", "readthedocs-sidebar");
130138
knownPlacementFound = true;
139+
} else {
140+
fixedFooterAdSelectors = ["div.footer"];
141+
this.setFixedFooterAdProperties(placement);
142+
knownPlacementFound = true;
131143
}
132144
} else if (docTool.isMaterialMkDocsTheme()) {
133145
// Detect the left navbar if it's not hidden or grab the navbar from a post page
@@ -142,6 +154,12 @@ export class EthicalAdsAddon extends AddonBase {
142154

143155
placement.setAttribute("data-ea-type", "readthedocs-sidebar");
144156
knownPlacementFound = true;
157+
// TODO: re-enable fixed footer ad for Material for MkDocs when we are ready.
158+
// https://github.com/readthedocs/addons/pull/641#pullrequestreview-3288251971
159+
// } else {
160+
// fixedFooterAdSelectors = ["footer.md-footer"];
161+
// this.setFixedFooterAdProperties(placement);
162+
// knownPlacementFound = true;
145163
}
146164
} else if (docTool.isDocusaurusTheme()) {
147165
selector = ".menu.thin-scrollbar.menu_SIkG";
@@ -155,6 +173,16 @@ export class EthicalAdsAddon extends AddonBase {
155173

156174
placement.setAttribute("data-ea-type", "image");
157175
knownPlacementFound = true;
176+
} else {
177+
// TODO
178+
// We need this to avois other elements being show on top of the ad.
179+
// We can probably always use `body` for the fixed footer ad in a
180+
// generic way at the bottom of this function.
181+
selector = "body";
182+
183+
fixedFooterAdSelectors = ["footer.footer"];
184+
this.setFixedFooterAdProperties(placement);
185+
knownPlacementFound = true;
158186
}
159187
} else if (docTool.isDocsify()) {
160188
selector = "main > aside > div.sidebar-nav";
@@ -167,6 +195,15 @@ export class EthicalAdsAddon extends AddonBase {
167195
placement.setAttribute("data-ea-type", "readthedocs-sidebar");
168196
placement.setAttribute("data-ea-style", "image");
169197
knownPlacementFound = true;
198+
} else {
199+
selector = "body";
200+
fixedFooterAdSelectors = [
201+
"section.content",
202+
"aside.sidebar",
203+
"button.sidebar-toggle",
204+
];
205+
this.setFixedFooterAdProperties(placement);
206+
knownPlacementFound = true;
170207
}
171208
} else if (docTool.isAntora()) {
172209
selector = "aside nav.nav-menu";
@@ -178,6 +215,10 @@ export class EthicalAdsAddon extends AddonBase {
178215
placement.setAttribute("data-ea-type", "readthedocs-sidebar");
179216
placement.setAttribute("data-ea-style", "image");
180217
knownPlacementFound = true;
218+
} else {
219+
fixedFooterAdSelectors = ["footer.footer"];
220+
this.setFixedFooterAdProperties(placement);
221+
knownPlacementFound = true;
181222
}
182223
} else if (docTool.isMdBook()) {
183224
selector = "nav#sidebar mdbook-sidebar-scrollbox";
@@ -189,6 +230,10 @@ export class EthicalAdsAddon extends AddonBase {
189230
placement.setAttribute("data-ea-type", "readthedocs-sidebar");
190231
placement.setAttribute("data-ea-style", "image");
191232
knownPlacementFound = true;
233+
} else {
234+
fixedFooterAdSelectors = ["div#body-container"];
235+
this.setFixedFooterAdProperties(placement);
236+
knownPlacementFound = true;
192237
}
193238
} else if (docTool.isVitePress()) {
194239
selector = "aside";
@@ -200,6 +245,11 @@ export class EthicalAdsAddon extends AddonBase {
200245
placement.setAttribute("data-ea-type", "readthedocs-sidebar");
201246
placement.setAttribute("data-ea-style", "image");
202247
knownPlacementFound = true;
248+
} else {
249+
selector = "body";
250+
fixedFooterAdSelectors = ["div#VPContent"];
251+
this.setFixedFooterAdProperties(placement);
252+
knownPlacementFound = true;
203253
}
204254
}
205255

@@ -272,7 +322,7 @@ export class EthicalAdsAddon extends AddonBase {
272322
mutation.target,
273323
).height;
274324
console.debug("fixedFooterAdHeight", fixedFooterAdHeight);
275-
for (const selector of selectors) {
325+
for (const selector of fixedFooterAdSelectors) {
276326
const element = document.querySelector(selector);
277327
element.style.setProperty(
278328
"padding-bottom",
@@ -316,7 +366,7 @@ export class EthicalAdsAddon extends AddonBase {
316366
return true;
317367
}
318368

319-
setFixedFooterAdProperties(selectors, placement) {
369+
setFixedFooterAdProperties(placement) {
320370
placement.setAttribute("data-ea-type", "text");
321371
placement.setAttribute("data-ea-style", "fixedfooter");
322372
}

0 commit comments

Comments
 (0)