PluginProbe
HubSpot All-In-One Marketing – Forms, Popups, Live Chat / 11.3.75
HubSpot All-In-One Marketing – Forms, Popups, Live Chat v11.3.75
11.3.75 11.3.73 11.3.71 11.3.70 11.3.69 11.3.64 11.3.65 11.3.62 11.3.61 11.3.56 11.3.58 11.0.31 11.0.52 11.0.54 11.0.56 11.0.58 11.0.7 11.1.10 11.1.11 11.1.13 11.1.14 11.1.15 11.1.2 11.1.20 11.1.21 All 73 releases
← All changes | scripts/shared/Form/PreviewForm.tsx +73 -11 11.1.1411.3.75 View file →
@@ -1,29 +1,91 @@
1 1 import React, { useEffect, useRef } from 'react';
2 2 import UIOverlay from '../UIComponents/UIOverlay';
3 -import { formsScriptPayload, hublet } from '../../constants/leadinConfig';
4 -import useFormScript from './hooks/useFormsScript';
3 +import {
4 + formsScript,
5 + formsScriptPayload,
6 + hublet as region,
7 +} from '../../constants/leadinConfig';
8 +import PreviewDisabled from '../Common/PreviewDisabled';
5 9
6 10 export default function PreviewForm({
7 11 portalId,
8 12 formId,
13 + fullSiteEditor,
14 + embedVersion,
9 15 }: {
10 16 portalId: number;
11 17 formId: string;
18 + fullSiteEditor?: boolean;
19 + embedVersion?: string;
12 20 }) {
21 + const isFormV4 = embedVersion === 'v4';
22 +
13 23 const inputEl = useRef<HTMLDivElement>(null);
14 - const ready = useFormScript();
15 24
16 25 useEffect(() => {
17 - if (!ready) {
18 - return;
19 - }
20 26 if (inputEl.current) {
27 + //@ts-expect-error Hubspot global
28 + const hbspt = window.parent.hbspt || window.hbspt;
21 29 inputEl.current.innerHTML = '';
22 - const embedScript = document.createElement('script');
23 - embedScript.innerHTML = `hbspt.forms.create({ portalId: '${portalId}', formId: '${formId}', region: '${hublet}', ${formsScriptPayload} });`;
24 - inputEl.current.appendChild(embedScript);
30 + const isQa = formsScriptPayload.includes('qa');
31 + if (isFormV4) {
32 + // WP 6.3+ renders the block-editor canvas inside an iframe
33 + // (iframe[name="editor-canvas"]). The block's DOM lives in that iframe,
34 + // but our React runs in the top window's JS realm, so the global
35 + // `document` here is the TOP frame's document, not the iframe's. The v4
36 + // forms embed script scans its executing context's local `document`
37 + // (getElementsByClassName('hs-form-frame') + MutationObserver on
38 + // document.body) and has no programmatic create() API. So both the
39 + // placeholder and the embed script must live in the IFRAME's document
40 + // for hydration to happen. Route everything through the placeholder's
41 + // ownerDocument to target the correct realm.
42 + const doc = inputEl.current.ownerDocument;
43 +
44 + const container = doc.createElement('div');
45 + container.classList.add('hs-form-frame');
46 + container.dataset.region = region;
47 + container.dataset.formId = formId;
48 + container.dataset.portalId = portalId.toString();
49 + container.dataset.env = isQa ? 'qa' : '';
50 + inputEl.current.appendChild(container);
51 +
52 + // Derive the portal-specific embed URL from the v2 script URL: take its
53 + // host (origin) so we follow whatever host a PHP filter applies to the
54 + // v2 URL, and append the v4 embed path. Inject it into the iframe's
55 + // document so it executes in the iframe window and scans the iframe
56 + // document where the placeholder is. Running post-mount means doc.body
57 + // exists, so the script's MutationObserver initializes without the
58 + // "not a Node" crash seen when it's loaded too early in the iframe
59 + // head. One copy per iframe window is enough — its MutationObserver
60 + // hydrates any later placeholders too.
61 + const v4EmbedUrl = formsScript
62 + ? `${new URL(formsScript).origin}/forms/embed/${portalId}.js`
63 + : '';
64 + const v4AlreadyPresent =
65 + !v4EmbedUrl || !!doc.querySelector(`script[src="${v4EmbedUrl}"]`);
66 + if (v4EmbedUrl && !v4AlreadyPresent) {
67 + const embedScript = doc.createElement('script');
68 + embedScript.src = v4EmbedUrl;
69 + embedScript.defer = true;
70 + doc.body.appendChild(embedScript);
71 + }
72 + } else {
73 + const additionalParams = isQa ? { env: 'qa' } : {};
74 +
75 + hbspt.forms.create({
76 + portalId,
77 + formId,
78 + region,
79 + target: `#${inputEl.current.id}`,
80 + ...additionalParams,
81 + });
82 + }
25 83 }
26 - }, [formId, portalId, ready, inputEl]);
84 + }, [formId, portalId, inputEl, isFormV4]);
27 85
28 - return <UIOverlay ref={inputEl} />;
86 + if (fullSiteEditor) {
87 + return <PreviewDisabled />;
88 + }
89 +
90 + return <UIOverlay ref={inputEl} id={`hbspt-previewform-${formId}`} />;
29 91 }