diff options
| -rw-r--r-- | docs/_static/css/custom.css | 24 | ||||
| -rw-r--r-- | docs/_templates/layout.html | 40 |
2 files changed, 64 insertions, 0 deletions
diff --git a/docs/_static/css/custom.css b/docs/_static/css/custom.css index cdb036d2..c19f436b 100644 --- a/docs/_static/css/custom.css +++ b/docs/_static/css/custom.css @@ -532,4 +532,28 @@ html { .closeButtonDivLine { bottom: 85px; } +} + +/* Cookiebot consent dialog — safety net (defense-in-depth). + Cookiebot delivers its dialog styling as a constructed stylesheet on + document.adoptedStyleSheets. The adoptedStyleSheets shim in layout.html keeps that + sheet from being dropped by another library (e.g. ReadTheDocs' readthedocs-addons.js, + which reassigns the whole list with a destructive replace). As a backstop, these + rules live in a regular stylesheet — which cascades *before* adopted stylesheets, so + Cookiebot's own CSS overrides every one of them whenever its sheet is present, and + they have no effect on the normal styled banner. They only take effect if that sheet + is ever absent, keeping the dialog a contained, scrollable, centered panel instead of + falling back to position:static and expanding to full page height. Only properties + Cookiebot itself sets are used here, so there is verifiably no leak into the good state. */ +#CybotCookiebotDialog { + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + max-width: 920px; + max-height: 90vh; + overflow: auto; + background: #fff; + box-shadow: 0 0 24px rgba(0, 0, 0, 0.25); + z-index: 2147483631; }
\ No newline at end of file diff --git a/docs/_templates/layout.html b/docs/_templates/layout.html index adc6278d..0b8ee41b 100644 --- a/docs/_templates/layout.html +++ b/docs/_templates/layout.html @@ -2,6 +2,46 @@ {%- set current_version = "1.4.x sagitta" %} {% block extrahead %} {% if gtm_id and cookiebot_id %} + {# Keep Cookiebot's consent dialog from rendering unstyled and breaking the page. + Cookiebot delivers its dialog CSS as a constructed stylesheet via + document.adoptedStyleSheets. That property holds the *whole* sheet list, and + ReadTheDocs' readthedocs-addons.js reassigns it with a destructive replace; when + that lands after Cookiebot's (network-gated) adoption it drops Cookiebot's sheet, + leaving #CybotCookiebotDialog at position:static, expanded to full page height. + This shim makes assignment preserve Cookiebot's sheet specifically. It must run + before the first adoptedStyleSheets write, so it is the first thing in <head>. #} + <script> + (function () { + try { + var desc = Object.getOwnPropertyDescriptor(Document.prototype, "adoptedStyleSheets"); + if (!desc || !desc.get || !desc.set) return; + var guarded = null; + var isCookiebot = function (sheet) { + try { + var rules = sheet.cssRules; + for (var i = 0; i < rules.length; i++) { + if (rules[i].selectorText && rules[i].selectorText.indexOf("CybotCookiebotDialog") !== -1) return true; + } + } catch (e) {} + return false; + }; + Object.defineProperty(document, "adoptedStyleSheets", { + configurable: true, + get: function () { return desc.get.call(document); }, + set: function (sheets) { + for (var i = 0; i < sheets.length; i++) { + if (isCookiebot(sheets[i])) { guarded = sheets[i]; break; } + } + if (guarded && Array.prototype.indexOf.call(sheets, guarded) === -1) { + sheets = Array.prototype.slice.call(sheets).concat(guarded); + } + desc.set.call(document, sheets); + } + }); + } catch (e) {} + })(); + </script> + {# Cookiebot CMP — must load first so its auto-blocker can scan/block other tags #} <script id="Cookiebot" src="https://consent.cookiebot.com/uc.js" |
