Two components of the det-id bug class were missed in the earlier migration: NumberCounter's wrapper/counter ids and count-up script, and the shared form-relay-wiring fid (used by ContactForm/FormContainer). Both used Math.random() for exported HTML ids, breaking caching/diffing across exports. Migrate both to scopeId(nodeId, fallbackSeed, prefix), threading nodeId through NumberCounter.toHtml and relayFormWiring (via ContactForm.toHtml and FormContainer.toHtml, both now passing nodeId as their 3rd arg).
51 lines
2.4 KiB
TypeScript
51 lines
2.4 KiB
TypeScript
/**
|
|
* Shared contact-form relay wiring for HTML export.
|
|
*
|
|
* Any form component that wants to deliver submissions by email (ContactForm,
|
|
* FormContainer, ...) emits the SAME marker/placeholder/honeypot shape so the
|
|
* WHP publish step (`fs_rewrite_contact_forms`) can provision a token, rewrite
|
|
* the action, and strip the marker. Keeping this in one place means the two
|
|
* components can't drift apart (a drift would leak the recipient into published
|
|
* HTML — see PR #47 review).
|
|
*/
|
|
|
|
import { escapeAttr, safeUrl, scopeId } from './escape';
|
|
|
|
export interface RelayWiring {
|
|
/** true when a recipient is set (relay path); false = legacy formAction fallback */
|
|
useRelay: boolean;
|
|
/** the `<!--WHP-FORM ...-->` marker (stripped at publish); '' when not relay */
|
|
marker: string;
|
|
/** value for the form's `action` attribute (placeholder when relay, else the escaped fallback) */
|
|
actionAttr: string;
|
|
/** hidden honeypot `<input>` to render as the form's first child; '' when not relay */
|
|
honeypot: string;
|
|
}
|
|
|
|
/**
|
|
* @param recipientEmail the "Send submissions to" address (empty/undefined = no relay)
|
|
* @param thankYouUrl optional post-submit redirect (blank = hosted thank-you page)
|
|
* @param fallbackAction the form's existing action to use when no recipient is set
|
|
* @param nodeId the Craft node id of the calling form component, used to scope
|
|
* the marker/placeholder id deterministically and uniquely --
|
|
* see `scopeId` in ./escape. Falls back to a stable hash of the
|
|
* recipient/thankYouUrl/fallbackAction when omitted (never random).
|
|
*/
|
|
export function relayFormWiring(
|
|
recipientEmail: string | undefined,
|
|
thankYouUrl: string | undefined,
|
|
fallbackAction: string | undefined,
|
|
nodeId?: string,
|
|
): RelayWiring {
|
|
if (!recipientEmail) {
|
|
return { useRelay: false, marker: '', actionAttr: escapeAttr(safeUrl(fallbackAction || '#')), honeypot: '' };
|
|
}
|
|
const fid = scopeId(nodeId, `${recipientEmail}::${thankYouUrl || ''}::${fallbackAction || ''}`, 'F');
|
|
return {
|
|
useRelay: true,
|
|
marker: `<!--WHP-FORM id="${fid}" recipient="${escapeAttr(recipientEmail)}" thankyou="${escapeAttr(thankYouUrl || '')}"-->`,
|
|
actionAttr: `__WHP_FORM_ACTION__${fid}__`,
|
|
honeypot: `<input type="text" name="_gotcha" tabindex="-1" autocomplete="off" style="position:absolute;left:-9999px" aria-hidden="true">`,
|
|
};
|
|
}
|