PageSourceSearch

https://www.ariefinance.com/assets/analytics.v1.js

js ariefinance.com collected 2026-10-08 01:29:35 UTC 6,873 bytes, 181 lines download raw bytes

1/*
2 * ARIE Finance — GA4 / GTM event layer (dataLayer only).
3 *
4 * Loads only on the marketing single-page site (index.html); utility
5 * routes (/salestracker, /managementreport, /internal/*, /logout) do
6 * not include this file, so no analytics is pushed from those pages.
7 *
8 * Consent Mode: Advanced. Before explicit acceptance analytics_storage
9 * is denied and Google may send cookieless pings; the site's cookie
10 * banner handles the explicit accept / essential-only flip.
11 * Advertising storage/consent is never granted.
12 *
13 * PII policy: we never push name, email, phone, company, message body,
14 * uploaded files, or free text from any form into the dataLayer. Only
15 * non-personal intent slugs, CTA text, and URLs of tel:/mailto: links
16 * (which are the site's public contact details) are captured.
17 */
18(function () {
19  'use strict';
20
21  var dl = (window.dataLayer = window.dataLayer || []);
22  function push(evt, params) {
23    try {
24      var obj = { event: evt };
25      if (params) {
26        for (var k in params) {
27          if (Object.prototype.hasOwnProperty.call(params, k)) obj[k] = params[k];
28        }
29      }
30      dl.push(obj);
31    } catch (e) { /* never break the site for analytics */ }
32  }
33
34  // ---------- section_view (single-page hash routes) ----------
35  var SECTIONS = [
36    'home', 'about', 'services', 'direct-clients', 'introducers',
37    'team', 'careers', 'contact', 'compliance', 'home-services',
38    'safeguarding', 'eligibility', 'policies',
39    'compliance-facts', 'compliance-is-is-not'
40  ];
41  var seen = Object.create(null);
42
43  function currentSection() {
44    var raw = (location.hash || '#home').replace(/^#/, '');
45    raw = raw.split('?')[0].split('&')[0];
46    return raw || 'home';
47  }
48  function fireSection() {
49    var s = currentSection();
50    if (!s || seen[s]) return;
51    if (SECTIONS.indexOf(s) === -1) return;
52    seen[s] = true;
53    push('section_view', {
54      section_name: s,
55      page_title: document.title,
56      page_location: location.href
57    });
58  }
59  window.addEventListener('hashchange', fireSection);
60  if (document.readyState === 'loading') {
61    document.addEventListener('DOMContentLoaded', fireSection);
62  } else {
63    fireSection();
64  }
65
66  // ---------- helpers ----------
67  function textOf(el) {
68    return (el.textContent || '').replace(/\s+/g, ' ').trim().slice(0, 120);
69  }
70  function ctaLocation(el) {
71    var s = el.closest ? el.closest('section') : null;
72    if (s && s.id) return s.id;
73    if (s && s.className) return String(s.className).split(/\s+/)[0] || 'section';
74    return 'unknown';
75  }
76  function currentContactTopic() {
77    var checked = document.querySelector('input[name="topic"]:checked');
78    if (!checked) return '';
79    var t = checked.getAttribute('data-topic');
80    return t || '';
81  }
82
83  var START_APP_RE = /start\s+your\s+application/i;
84  var SPEAK_RE = /^(speak to our team|speak to the team|contact arie finance)$/i;
85
86  // ---------- click delegation ----------
87  document.addEventListener('click', function (ev) {
88    var link = ev.target && ev.target.closest ? ev.target.closest('a[href], button') : null;
89    if (!link) return;
90
91    var href = link.getAttribute ? link.getAttribute('href') : null;
92    if (href) {
93      if (href.indexOf('mailto:') === 0) {
94        push('email_click', { link_url: href, link_text: textOf(link) });
95        return;
96      }
97      if (href.indexOf('tel:') === 0) {
98        push('phone_click', { link_url: href, link_text: textOf(link) });
99        return;
100      }
101    }
102
103    var t = textOf(link);
104    if (!t) return;
105
106    // start_application: customer/client application CTA intent only.
107    // Strict identity: the DOM element must be the site's contact-route
108    // anchor (data-route="contact"). This rejects any unrelated future
109    // button labelled "Apply" — for example a hypothetical careers
110    // Apply control — from being classified as a commercial CTA.
111    // Matched text: "Start Your Application" or the exact mobile short
112    // label "Apply" that lives inside the same data-route="contact"
113    // anchor as "Start Your Application" (verified in the repo).
114    if (link.matches && link.matches('a[data-route="contact"]')) {
115      if (START_APP_RE.test(t) || t === 'Apply') {
116        push('start_application', { cta_text: t, cta_location: ctaLocation(link) });
117        return;
118      }
119    }
120
121    // speak_to_team: general commercial contact CTAs.
122    if (SPEAK_RE.test(t)) {
123      push('speak_to_team', { cta_text: t, cta_location: ctaLocation(link) });
124      return;
125    }
126  }, true);
127
128  // ---------- contact_topic_selected (engagement) ----------
129  // Fires whenever the contact-form intent radio changes. Parameter
130  // contact_topic is the non-personal slug from the radio's data-topic
131  // attribute (e.g. "account", "payments", "introducer", "referral",
132  // "support", "other"). Selection is INTEREST, not a submitted lead;
133  // the actual submitted lead is contact_form_submit with the same
134  // contact_topic value.
135  document.addEventListener('change', function (ev) {
136    var t = ev.target;
137    if (!t || t.name !== 'topic') return;
138    if (!t.checked) return;
139    var slug = t.getAttribute && t.getAttribute('data-topic');
140    if (!slug) return;
141    push('contact_topic_selected', { contact_topic: slug });
142  }, true);
143
144  // ---------- form_start / form_submit ----------
145  // form_start on first user interaction with each form, once.
146  // form_submit when the site's existing success element gets
147  // .is-visible (set by the confirmed-success branch in the site's
148  // contact/careers submit handler, after /api/website-form returns
149  // {ok:true}). For the contact form, contact_topic is attached from
150  // whichever intent radio is checked at that moment.
151  document.querySelectorAll('form[data-form]').forEach(function (form) {
152    var name = form.dataset.form; // "contact" | "careers"
153    var started = false;
154    function start() {
155      if (started) return;
156      started = true;
157      push(name + '_form_start', { form_name: name });
158    }
159    form.addEventListener('input', start, true);
160    form.addEventListener('change', start, true);
161  });
162
163  document.querySelectorAll('[data-success]').forEach(function (success) {
164    var name = success.getAttribute('data-success'); // "contact" | "careers"
165    if (!name) return;
166    try {
167      var mo = new MutationObserver(function () {
168        if (success.classList.contains('is-visible')) {
169          var params = { form_name: name };
170          if (name === 'contact') {
171            var topic = currentContactTopic();
172            if (topic) params.contact_topic = topic;
173          }
174          push(name + '_form_submit', params);
175          mo.disconnect();
176        }
177      });
178      mo.observe(success, { attributes: true, attributeFilter: ['class'] });
179    } catch (e) { /* MutationObserver unavailable — form_submit will not fire */ }
180  });
181})();

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.