PageSourceSearch

https://www.hinrichfoundation.com/script/hubspot-form.js

js hinrichfoundation.com collected 2026-10-02 03:01:51 UTC 9,742 bytes, 234 lines download raw bytes

1// =============================================================
2// Matomo + GTM Form Data Push (fixed and unified version)
3// -------------------------------------------------------------
4// - Ensures content_type is set (from data OR URL fallback)
5// - Adds "event" to every dataLayer push (GTM can trigger)
6// - Adds nested payload.event for templates expecting payload.*
7// - Normalizes subscribe_status to "Yes"/"No"
8// - Lowercases email before storing
9// - Pushes Matomo userId (plain email) + Identity Status (new/known)
10// =============================================================
11
12// Helper: map current path to a normalized content_type
13function deriveContentTypeFromPath () {
14   var p = (location.pathname || '').toLowerCase()
15
16   // White paper
17   if (/^\/research\/wp(\/|$)/.test(p)) return 'whitepaper'
18
19   // Infographics
20   if (/^\/research\/infographics(\/|$)/.test(p)) return 'infographic'
21
22   // Podcast
23   if (/^\/research\/podcast(\/|$)/.test(p)) return 'podcast'
24
25   // Discussion Guide (DG)
26   if (/^\/global-trade\/discussion-guides(\/|$)/.test(p)) return 'discu
26ssion_guide'
27
28   // No match
29   return ''
30}
31
32window.handlePageContentForm = () => {
33   if (window.__HF_HUBSPOT_FORM_DLV_DONE) return
34   console.log("Handling page content form for Matomo")
35
36   try {
37      const raw = localStorage.getItem("whitePaperLastSubmission")
38      if (!raw) return
39
40      let d = {}
41      try { d = JSON.parse(raw) || {} } catch (e) { }
42
43      const query = (location.search || "").replace(/^\?/, "").split("&")
44      const utm = function (k) {
45         for (let i = 0;i < query.length;i++) {
46            const kv = query[i].split("=")
47            if (decodeURIComponent(kv[0] || "") === k) return decodeURIComponent(kv[1] || "")
48         }
49         return d[k] || ""
50      }
51
52      const pick = function (...args) {
53         for (const k of args) {
54            if (d && d[k] != null && d[k] !== "") return String(d[k])
55         }
56         return ""
57      }
58
59      const yesNo = function (v) {
60         if (v == null || v === "") return ""
61         if (typeof v === "boolean") return v ? "Yes" : "No"
62         const s = String(v).toLowerCase()
63         if (["true", "yes", "1"].includes(s)) return "Yes"
64         if (["false", "no", "0"].includes(s)) return "No"
65         return ""
66      }
67
68      const email = (pick("email", "userEmail", "mail") || "").trim().toLowerCase()
69
70      // — ensure content_type exists (from storage OR URL)
71      const contentType =
72         pick("content_type", "form_type", "type") || deriveContentTypeFromPath()
73
74      const base = {
75         content_type: contentType, // <- now guaranteed when URL matches
76         form_name: pick("form_name", "whitepaperTitle", "formTitle", "formName", "title", "name") || document.title,
77         asset_id: pick("asset_id", "assetId", "assetID", "id", "slug"),
78         asset_url: location.href,
79         page: location.pathname,
80         submitted_at: new Date().toISOString(),
81
82         author: pick("author"),
83         publish_date: pick("publish_date", "publishDate", "date"),
84         topics: pick("topics", "topic", "tags"),
85
86         email: email,
87         organization: pick("organization", "company", "org", "employer", "institution"),
88         job_title: pick("job_title", "job", "jobtitle", "jobTitle", "occupation", "role", "position", "title"),
89         country: pick("country", "country_code", "location", "countryCode", "country___region"),
90         sector: pick("sector", "industry", "vertical", "sector__emerson_test_"),
91         subscribe_status: (d.hasOwnProperty("subscribe_status")
92            ? yesNo(d.subscribe_status)
93            : (d.hasOwnProperty("subscribe") ? yesNo(d.subscribe) : "")),
94
95         utm_source: utm("utm_source"),
96         utm_medium: utm("utm_medium"),
97         utm_campaign: utm("utm_campaign"),
98      }
99
100      // Push top-level event + nested payload.event
101      window.dataLayer = window.dataLayer || []
102      const dlObj = Object.assign({ event: "hf_asset_form_submit" }, base, {
103         payload: Object.assign({ event: "hf_asset_form_submit" }, base),
104      })
105      window.dataLayer.push(dlObj)
106      console.log("[dataLayer.push][pageContent]", dlObj)
107
108      window.__HF_HUBSPOT_FORM_DLV_DONE = true
109
110      // Optional: Matomo known/new user tracking
111      if (email) {
112         const prev = (localStorage.getItem("matomo_user_id") || "").toLowerCase()
113         const status = prev ? "known" : "new"
114         window._paq = window._paq || []
115         _paq.push(["setUserId", email])
116         _paq.push(["trackEvent", "Identity", "Status", status])
117         try { localStorage.setItem("matomo_user_id", email) } catch (e) { }
118      }
119   } catch (err) {
120      console.warn("[DLV populate error]", err)
121   }
122}
123
124
125window.handleDiscussionGuideForm = ($form) => {
126   console.log("Handling discussion guide form for Matomo")
127   console.log($form)
128   const raw = localStorage.getItem("whitePaperLastSubmission")
129   let d = {}
130   try { d = JSON.parse(raw) || {} } catch (e) { }
131   const pick = function (...args) {
132      for (const k of args) {
133         if (d && d[k] != null && d[k] !== "") return String(d[k])
134      }
135      return ""
136   }
137
138   if (window.__HF_HUBSPOT_FORM_DISCUSSION_GUIDE_DONE) return
139   const formEl =
140      ($form && ($form.get && $form.get(0))) ||
141      ($form && $form[0]) ||
142      $form ||
143      document.getElementById("discussion-form")
144
145   function get (name) {
146      // FIXED selector:
147      const el = formEl && formEl.querySelector(`[name="${name}"]`)
148      return el ? (el.value || "").trim() : ""
149   }
150
151   function pickSelectVal (sel) {
152      const el = formEl && formEl.querySelector(sel)
153      let val = el ? (el.value || "").trim() : ""
154      if (/please select/i.test(val)) val = ""
155      return val
156   }
157   const title = localStorage.getItem("discussion-guide-active-resource-title")
158   // If this form should remain as a separate type, keep 'discussion_guide'
159   // (If you want it to be categorized like the others, swap to deriveContentTypeFromPath())
160   const content_type = "discussion_guide"
161
162   const form_name = get("resource_title") || title || "Discussion Guide"
163   const asset_id = get("resource_id") || location.pathname.split("/").filter(
163Boolean).pop() || title || ""
164   const topics = get("resource_topic") || pick("topics", "topic", "tags") || get("content_topic__form_submission_field_") || pick("content_topic__form_submission_field_") || ""
165
166   const author =
167      (document.querySelector('meta[name="author"]') || {}).content ||
168      get("author__form_submission_field_") ||
169      pick("author__form_submission_field_") ||
170      (document.querySelector('a[href^="/profiles/experts-contributors/"]') || {}).textContent ||
171      ""
172   const publish_date =
173      (document.querySelector('meta[property="article:published_time"]') || {}).content ||
174      (document.querySelector('meta[itemprop="datePublished"]') || {}).content ||
175      get("publish_date__form_submission_field_") ||
176      pick("publish_date__form_submission_field_", "publish_date", "publishDate", "date") ||
177      ""
178
179   const usp = new URLSearchParams(location.search)
180   const utm_source = usp.get("utm_source") || ""
181   const utm_medium = usp.get("utm_medium") || ""
182   const utm_campaign = usp.get("utm_campaign") || ""
183
184   const email = (get("email") || get("Email") || get("EMAIL") || pick("email", "userEmail", "mail") || "").trim().toLowerCase()
185   const organization = get("organization") || get("company") || pick("organization", "company", "org", "employer", "institution")
186   const job_title = get("job_title") || get("jobtitle") || get("title") || pick("job_title", "jobtitle")
187   const country = pickSelectVal('select[name*="country" i], select[id*="country" i]') || get("country") || pick("country", "country_code", "location", "countryCode", "country___region")
188   const sector = pickSelectVal('select[name*="sector" i],   select[id*="sector"  i]') || get("sector") || get("sector__emerson_test_") || pick("sector", "industry", "vertical", "sector__emerson_test_")
189
190   const subscribeEl =
191      formEl &&
192      (formEl.querySelector('input[type="checkbox"][name*="subscribe" i]') ||
193         formEl.querySelector('input[type="checkbox"][id*="subscribe" i]'))
194   const subscribe_status = subscribeEl && subscribeEl.checked ? "Yes" : "No"
195
196   // Push top-level + nested payload.event
197   window.dataLayer = window.dataLayer || []
198   const base = {
199      content_type,
200      form_name,
201      asset_id,
202      asset_url: location.href,
203      author: (author || "").trim(),
204      publish_date,
205      topics,
206      page: location.pathname,
207      submitted_at: new Date().toISOString(),
208      email,
209      organization,
210      job_title,
211      country,
212      sector,
213      subscribe_status,
214      utm_source,
215      utm_medium,
216      utm_campaign,
217   }
218   const dlObj = Object.assign({ event: "hf_asset_form_submit" }, base, {
219      payload: Object.assign({ event: "hf_asset_form_submit" }, base),
220   })
221   window.dataLayer.push(dlObj)
222   console.log("[dataLayer.push][discussionGuide]", dlObj)
223
224   // Optional: Matomo userId tracking
225   if (email) {
226      const prev = (localStorage.getItem("matomo_user_id") || "").toLowerCase()
227      const status = prev ? "known" : "new"
228      window._paq = window._paq || []
229      _paq.push(["setUserId", email])
230      _paq.push(["trackEvent", "Identity", "Status", status])
231      try { localStorage.setItem("matomo_user_id", email) } catch (e) { }
232   }
233   window.__HF_HUBSPOT_FORM_DISCUSSION_GUIDE_DONE = true
234}

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.