From: Cyperghost Date: Fri, 1 Mar 2024 10:56:55 +0000 (+0100) Subject: Move the reCAPTCHA widget overlay to the `pageOverlayContainer` when widget form... X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=b50949e6a1de1a6c97c6982eebc10e197d99cf42;p=GitHub%2FWoltLab%2FWCF.git Move the reCAPTCHA widget overlay to the `pageOverlayContainer` when widget form elements are placed in a dialog. --- diff --git a/ts/WoltLabSuite/Core/Bootstrap.ts b/ts/WoltLabSuite/Core/Bootstrap.ts index 736d3cd3b0..5484935875 100644 --- a/ts/WoltLabSuite/Core/Bootstrap.ts +++ b/ts/WoltLabSuite/Core/Bootstrap.ts @@ -31,7 +31,7 @@ import * as UiObjectActionToggle from "./Ui/Object/Action/Toggle"; import { init as initSearch } from "./Ui/Search"; import { PageMenuMainProvider } from "./Ui/Page/Menu/Main/Provider"; import { whenFirstSeen } from "./LazyLoader"; -import { adoptPageOverlayContainer } from "./Helper/PageOverlay"; +import { adoptPageOverlayContainer, getPageOverlayContainer } from "./Helper/PageOverlay"; // perfectScrollbar does not need to be bound anywhere, it just has to be loaded for WCF.js import "perfect-scrollbar"; @@ -168,4 +168,40 @@ export function setup(options: BoostrapOptions): void { whenFirstSeen("[data-google-maps-geocoding]", () => { void import("./Component/GoogleMaps/Geocoding").then(({ setup }) => setup()); }); + + // Move the reCAPTCHA widget overlay to the `pageOverlayContainer` + // when widget form elements are placed in a dialog. + const observer = new MutationObserver((mutations) => { + for (const mutation of mutations) { + for (const node of mutation.addedNodes) { + if (!(node instanceof HTMLElement)) { + continue; + } + + if (node.querySelectorAll(".g-recaptcha-bubble-arrow").length === 0) { + return; + } + + const iframe = node.querySelector("iframe"); + if (!iframe) { + return; + } + const name = "a-" + iframe.name.split("-")[1]; + const widget = document.querySelector(`iframe[name="${name}"]`); + if (!widget) { + return; + } + const dialog = widget.closest("woltlab-core-dialog"); + if (!dialog) { + return; + } + + getPageOverlayContainer().append(node); + node.classList.add("g-recaptcha-container"); + } + } + }); + observer.observe(document.body, { + childList: true, + }); } diff --git a/wcfsetup/install/files/js/WoltLabSuite/Core/Bootstrap.js b/wcfsetup/install/files/js/WoltLabSuite/Core/Bootstrap.js index 3c7f0fb550..cba11338bc 100644 --- a/wcfsetup/install/files/js/WoltLabSuite/Core/Bootstrap.js +++ b/wcfsetup/install/files/js/WoltLabSuite/Core/Bootstrap.js @@ -133,6 +133,38 @@ define(["require", "exports", "tslib", "./Core", "./Date/Picker", "./Devtools", (0, LazyLoader_1.whenFirstSeen)("[data-google-maps-geocoding]", () => { void new Promise((resolve_5, reject_5) => { require(["./Component/GoogleMaps/Geocoding"], resolve_5, reject_5); }).then(tslib_1.__importStar).then(({ setup }) => setup()); }); + // Move the reCAPTCHA widget overlay to the `pageOverlayContainer` + // when widget form elements are placed in a dialog. + const observer = new MutationObserver((mutations) => { + for (const mutation of mutations) { + for (const node of mutation.addedNodes) { + if (!(node instanceof HTMLElement)) { + continue; + } + if (node.querySelectorAll(".g-recaptcha-bubble-arrow").length === 0) { + return; + } + const iframe = node.querySelector("iframe"); + if (!iframe) { + return; + } + const name = "a-" + iframe.name.split("-")[1]; + const widget = document.querySelector(`iframe[name="${name}"]`); + if (!widget) { + return; + } + const dialog = widget.closest("woltlab-core-dialog"); + if (!dialog) { + return; + } + (0, PageOverlay_1.getPageOverlayContainer)().append(node); + node.classList.add("g-recaptcha-container"); + } + } + }); + observer.observe(document.body, { + childList: true, + }); } exports.setup = setup; }); diff --git a/wcfsetup/install/files/style/ui/recaptcha.scss b/wcfsetup/install/files/style/ui/recaptcha.scss index b77b0085fd..5ac8c2144b 100644 --- a/wcfsetup/install/files/style/ui/recaptcha.scss +++ b/wcfsetup/install/files/style/ui/recaptcha.scss @@ -2,3 +2,21 @@ #recaptcha_response_field { margin-top: 20px; } + +/* ReCAPTCHA container for a dialog element */ +.g-recaptcha-container { + position: fixed !important; + + > div:not(:first-child):nth-of-type(-n+3) { + display: none !important; + } + + > div:last-child { + position: fixed !important; + top: 0 !important; + left: 0 !important; + bottom: 0 !important; + right: 0 !important; + margin: auto !important; + } +}