PageSourceSearch

https://forms.dapta.ai/embed.js

js dapta.ai collected 2026-09-29 00:03:40 UTC 10,715 bytes, 226 lines download raw bytes

1/**
2 * Dapta Forms embed helper: auto-resizes embedded form iframes, carries their
3 * end-of-form redirect up to the host page, and tells a form which page it is
4 * answered on.
5 *
6 * Drop next to any iframe carrying the `data-dapta-forms` attribute:
7 *
8 *   <iframe data-dapta-forms src="https://your-host/acct/f/slug?embed=1"
9 *           title="My form" loading="lazy"
10 *           style="width:100%;border:0;min-height:480px;"></iframe>
11 *   <script src="https://your-host/embed.js" async></script>
12 *
13 * Four messages cross the boundary, all matched to a frame by `event.source`
14 * and never by URL, so several forms can share one page and a message can only
15 * ever act on the frame it came from:
16 *
17 *   dapta-forms:resize   {height}: the embedded page (opened with ?embed=1)
18 *     posts its content height whenever it changes; this script sets the
19 *     matching iframe's height so the form never shows an inner scrollbar.
20 *     Only a number crosses: no answers, no identifiers.
21 *
22 *   dapta-forms:redirect {url}: the form finished and its configured
23 *     destination has to be opened at the TOP level, not inside the frame.
24 *     Checkout pages (Stripe Payment Links above all) refuse to run framed by
25 *     another site and hang on their own skeleton, so a form that redirects to
26 *     one submits into nothing unless the host page navigates itself. The URL
27 *     is the form's published `redirectUrl`, a static string, never built from
28 *     what the visitor typed. It is allowlisted to http(s) before use, exactly
29 *     as the renderer does before assigning `window.location`. This script
30 *     replies `dapta-forms:redirect-ack` so the frame knows not to navigate
31 *     the top as well: two navigations of one document race, and WebKit
32 *     resolves that race by cancelling both.
33 *
34 *   dapta-forms:scroll-into-view: the form swapped its whole screen (the
35 *     ending, the submitting screen) and the new screen starts at the top of
36 *     the frame. On a long one-page form the visitor is scrolled to the button
37 *     they just pressed, far below it, and would be left looking at an empty
38 *     block. This script scrolls the frame's top into view, and ONLY when that
39 *     top is out of the viewport: someone already looking at it is not moved.
40 *     Smooth unless the visitor asked for reduced motion. The form never sends
41 *     it for the screen it loads with, so loading a page never scrolls it.
42 *
43 *   dapta-forms:context-request {id, v: 1}: the form is about to save its
44 *     answers and asks which page it is on. This script answers
45 *     `dapta-forms:context {id, v: 1, pageUri, pageName, pageId?,
46 *     hsPortalId?, hutk?}`: this page's URL and title, its HubSpot page and
47 *     portal ids when it runs HubSpot, and HubSpot's visitor cookie
48 *     (`hubspotutk`), which is what lets HubSpot join the new contact to the
49 *     visits it made before converting. The iframe cannot read any of it: it
50 *     lives on another origin. The answer goes ONLY to one of our frames: its
51 *     `src` must be on the host this script was loaded from, so an iframe
52 *     someone marked with the attribute but that is not our form gets
53 *     nothing, and it must still show the origin of that `src`, so a frame
54 *     that navigated elsewhere is never handed the cookie. (A copy of the
55 *     script with no src of its own, pasted inline, cannot know its host and
56 *     keeps only the second check.) The cookie is left
57 *     out when the visitor opted out of HubSpot tracking (`__hs_opt_out=yes`,
58 *     or a `__hs_do_not_track` cookie) and when it is not HubSpot shaped. This
59 *     script reads cookies and never writes one. Put
60 *     `data-dapta-forms-context="off"` on an iframe to keep all of it from
61 *     that form: the answer is then `{id, v: 1, off: true}` and nothing else.
62 *
63 * Anything that is not one of those messages, in that shape, is ignored. A
64 * copy of this script cached from before a message existed simply ignores it.
65 *
66 * WHY THE REDIRECT HANDLER EXISTS: a plain cross-origin iframe can navigate
67 * its own top, so most embeds never need this message. An iframe given a
68 * `sandbox` attribute that omits `allow-top-navigation` cannot: the browser
69 * refuses it with nothing but a console warning, and the visitor is stranded
70 * on a form that went nowhere. This script runs in the host page, outside that
71 * sandbox, so it can still navigate. Keep it on the page.
72 */
73(function () {
74  'use strict';
75
76  var MAX_HEIGHT = 20000; // sanity cap — a runaway report can't blow up the host page
77  var HTTP_ONLY = /^https?:\/\//i; // same allowlist the renderer applies
78  var leaving = false; // one redirect per page — a second message is a no-op
79
80  var HUTK = /^[0-9a-f]{32}$/i; // HubSpot's visitor cookie: 32 hex characters
81  var DIGITS = /^\d{1,20}$/; // a HubSpot page or portal id
82
83  // The forms host this script was loaded from, read once: `currentScript` is
84  // only set while the script first runs. Null when it cannot be known (an
85  // inline copy, an old browser), and then only the frame's own src is checked.
86  var SCRIPT_ORIGIN = (function () {
87    try {
88      var script = document.currentScript;
89      if (!script || !script.src) return null;
90      var origin = new URL(script.src, window.location.href).origin;
91      return origin && origin !== 'null' ? origin : null;
92    } catch (_) {
93      return null;
94    }
95  })();
96
97  /** True when `source` is the contentWindow of one of OUR embedded frames. */
98  function isOurFrame(source) {
99    var frames = document.querySelectorAll('iframe[data-dapta-forms]');
100    for (var i = 0; i < frames.length; i++) {
101      try {
102        if (source === frames[i].contentWindow) return frames[i];
103      } catch (_) {
104        /* cross-origin contentWindow access can throw — skip that frame */
105      }
106    }
107    return null;
108  }
109
110  /** The origin of a frame's `src`, or null when it has none worth answering. */
111  function srcOrigin(frame) {
112    // No src (a srcdoc frame, say) is no form of ours: it would resolve to this page.
113    if (!frame.src) return null;
114    try {
115      var origin = new URL(frame.src, window.location.href).origin;
116      return origin && origin !== 'null' ? origin : null;
117    } catch (_) {
118      return null;
119    }
120  }
121
122  /** One cookie of this page, or null. Read only: this script never writes one. */
123  function readCookie(name) {
124    var parts = String(document.cookie || '').split(';');
125    for (var i = 0; i < parts.length; i++) {
126      var eq = parts[i].indexOf('=');
127      var key = (eq < 0 ? parts[i] : parts[i].slice(0, eq)).replace(/^\s+|\s+$/g, '');
128      if (key === name) return eq < 0 ? '' : parts[i].slice(eq + 1).replace(/^\s+|\s+$/g, '');
129    }
130    return null;
131  }
132
133  /** The HubSpot portal whose tracking code runs on this page, or null. */
134  function hubspotPortal() {
135    var vars = window.hsVars;
136    if (vars && vars.portal_id != null && DIGITS.test(String(vars.portal_id))) return String(vars.portal_id);
137    var loader = document.getElementById('hs-script-loader');
138    var match = loader && loader.src ? /\/(\d{1,20})\.js(?:[?#]|$)/.exec(loader.src) : null;
139    return match ? match[1] : null;
140  }
141
142  /** This page, as it is right now, for the frame that asked. */
143  function pageContext(id) {
144    var reply = {
145      type: 'dapta-forms:context',
146      id: id,
147      v: 1,
148      pageUri: String(window.location.href),
149      pageName: String(document.title || ''),
150    };
151    var vars = window.hsVars;
152    if (vars && vars.page_id != null && DIGITS.test(String(vars.page_id))) reply.pageId = String(vars.page_id);
153    var portal = hubspotPortal();
154    if (portal) reply.hsPortalId = portal;
155    var optedOut = readCookie('__hs_opt_out') === 'yes' || readCookie('__hs_do_not_track') !== null;
156    var hutk = readCookie('hubspotutk');
157    if (!optedOut && hutk && HUTK.test(hutk)) reply.hutk = hutk;
158    return reply;
159  }
160
161  window.addEventListener('message', function (event) {
162    var data = event && event.data;
163    if (!data) return;
164
165    if (data.type === 'dapta-forms:resize') {
166      if (typeof data.height !== 'number') return;
167      if (!isFinite(data.height) || data.height <= 0) return;
168      var frame = isOurFrame(event.source);
169      if (!frame) return;
170      frame.style.height = Math.min(Math.ceil(data.height), MAX_HEIGHT) + 'px';
171      return;
172    }
173
174    if (data.type === 'dapta-forms:scroll-into-view') {
175      var target = isOurFrame(event.source);
176      if (!target) return;
177      var top = target.getBoundingClientRect().top;
178      var viewport = window.innerHeight || document.documentElement.clientHeight;
179      if (top >= 0 && top < viewport) return; // its top is already on screen
180      var reduce = !!(window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches);
181      try {
182        target.scrollIntoView({ behavior: reduce ? 'auto' : 'smooth', block: 'start' });
183      } catch (_) {
184        target.scrollIntoView(true); // browsers without the options object
185      }
186      return;
187    }
188
189    if (data.type === 'dapta-forms:context-request') {
190      if (data.v !== 1 || typeof data.id !== 'string' || !data.id || data.id.length > 64) return;
191      var asking = isOurFrame(event.source);
192      if (!asking) return;
193      var origin = srcOrigin(asking);
194      // Our forms host only: an iframe marked with the attribute that loads
195      // something else is not our form, whatever it shows.
196      if (!origin || (SCRIPT_ORIGIN && origin !== SCRIPT_ORIGIN)) return;
197      // And it must still show what its own src loaded: one that navigated
198      // elsewhere is not our form any more, and gets nothing.
199      if (event.origin !== origin) return;
200      var off = asking.getAttribute('data-dapta-forms-context') === 'off';
201      try {
202        var reply = off ? { type: 'dapta-forms:context', id: data.id, v: 1, off: true } : pageContext(data.id);
203        event.source.postMessage(reply, origin);
204      } catch (_) {
205        /* the frame is gone; it saves without the page */
206      }
207      return;
208    }
209
210    if (data.type === 'dapta-forms:redirect') {
211      if (leaving) return;
212      if (typeof data.url !== 'string' || !HTTP_ONLY.test(data.url.trim())) return;
213      if (!isOurFrame(event.source)) return;
214      leaving = true;
215      // Answer BEFORE navigating. The frame falls back to navigating the top
216      // itself when no answer arrives, and two navigations of one top-level
217      // document race — WebKit cancels both and the visitor goes nowhere.
218      try {
219        event.source.postMessage({ type: 'dapta-forms:redirect-ack' }, '*');
220      } catch (_) {
221        /* the frame is gone; nothing left to tell */
222      }
223      window.location.href = data.url.trim();
224    }
225  });
226})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.