PageSourceSearch

https://thinkingthrough.ai/js/clean/ttai-enterprise-modal.js?_m=1773877889

js thinkingthrough.ai collected 2026-09-29 00:40:29 UTC 12,124 bytes, 276 lines download raw bytes

1window.addEventListener("load", () => {
2  function showModal(type = 'enterprise', deviceType) {
3    const headings = {
4      enterprise: 'Enterprise-wide personalized A.I. mastery, at scale, customized for your organization.',
5      schools: "Personalized A.I. mastery for every student, customized for your school's priorities and values.",
6      communities: "Weave critical A.I. literacy into your community's culture and daily life."
7    };
8    const blurbs = {
9      enterprise: '',
10      schools: "Launched December 2025. Set your school's priorities and values to adjust the insights and monitoring, create dedicated discussions and leaderboards, gain insights, and more. For schools that want to graduate A.I.-native students who not only know how to navigate the top tools, but know how to think far more critically and strategically about them too.",
11      communities: "Deploy AI literacy where your residents already are — in libraries, transit hubs, schools, and public spaces. Custom-branded for your city, with locally-themed challenges, leaderboards, and employer-recognized credentials that make learning visible and valuable."
12    };
13    const heading = headings[type] || headings.enterprise;
14    const blurb = blurbs[type] || blurbs.enterprise;
15    const content = `
16    <button class="util-close-modal x-btn"><span class="material-icons-round">close</span></button>
17    <div class="content">
18      ${type !== 'earlyAccess' ? `<h2>${heading}</h2>
19      <p class="first">${blurb}</p>
20      <p>Get in touch to learn more, gain priority access, or discuss pricing.</p>` : `<p class="appText">Launched December 2025. Want early access?</p>`}
21      <div class="inputs-errors-ct">
22        <select name="offering" class="ent-modal-select">
23          <option value="" disabled selected>Which offering are you most interested in?</option>
24          ${type === 'schools' ? `
25          <option value="ai-literacy-app">Critical AI Literacy App</option>
26          <option value="showyourlearning">ShowYourLearning (AI Cheating Solution)</option>
27          <option value="local-challenges">Local Challenges</option>
28          <option value="cognitive-defence">Cognitive Defence Features</option>
29          <option value="pd-sessions">Professional Development Sessions</option>
30          ` : type === 'communities' ? `
31          <option value="local-challenge-deployment">Local Challenge Deployment</option>
32          <option value="custom-city-portal">Custom-Branded City Portal</option>
33          <option value="school-integration">School &amp; Campus Integration</option>
34          <option value="community-ai-literacy">Community AI Literacy Program</option>
35          ` : `
36          <option value="business-upgrade">Business Upgrade for AI</option>
37          <option value="it-stack-upgrade">IT Stack &amp; Practices Upgrade for AI</option>
38          <option value="cybersecurity-upgrade">Cybersecurity Upgrade for AI</option>
39          <option value="ai-upskilling">AI Upskilling</option>
40          `}
41        </select>
42        <div class="inputs-ct">
43          <input type="text" placeholder="Full name" name="name" />
44          <input type="text" placeholder="LinkedIn URL" name="linked" />
45          <input type="text" placeholder="[email protected]" name="emailContact" />
46          <button type="button" class="util-small-btn submit-enterprise"><span class="material-icons-round">send</span></button>
47        </div>
48      </div>
49    </div>
50  `;
51    const { modalObject, modalContainer, modalMain } = util.insertModal(null, {
52      id: "ttaiEnterprise",
53      canClose: true,
54      withCloseBtn: false,
55      removeOnClose: true,
56      content,
57    });
58    modalContainer.classList.add(type);
59    modalObject.show();
60
61    const grecaptchaSiteKey = "6LcOWUsrAAAAALO0BJFuIj0nrxBe-trq9QPaPSCV";
62    function executeRecaptcha(action) {
63      return new Promise((resolve, reject) => {
64        if (!window.grecaptcha || typeof window.grecaptcha.execute !== "function") {
65          return reject(new Error("reCAPTCHA not loaded yet."));
66        }
67        try {
68          grecaptcha.ready(() => {
69            grecaptcha
70              .execute(grecaptchaSiteKey, { action })
71              .then((token) => {
72                if (!token) {
73                  return reject(new Error("reCAPTCHA token is empty."));
74                }
75                resolve(token);
76              })
77              .catch((err) => reject(err));
78          });
79        } catch (err) {
80          reject(err);
81        }
82      });
83    }
84
85    const submitBtn = document.querySelector('#ttaiEnterprise .submit-enterprise');
86    if(submitBtn) {
87      submitBtn.addEventListener('click', submitEnterprise)
88    }
89    function submitEnterprise() {
90      const fields = {
91        firstLast: document.querySelector('#ttaiEnterprise input[name="name"]'),
92        linked: document.querySelector('#ttaiEnterprise input[name="linked"]'),
93        emailContact: document.querySelector('#ttaiEnterprise input[name="emailContact"]'),
94        offering: document.querySelector('#ttaiEnterprise .ent-modal-select'),
95      }
96
97      const params = {
98        name: fields.firstLast ? fields.firstLast.value : '',
99        linkedInURL: fields.linked ? fields.linked.value : '',
100        emailContact: fields.emailContact ? fields.emailContact.value : '',
101        offering: fields.offering ? fields.offering.value : '',
102        type,
103        device: deviceType ? deviceType : ''
104      };
105
106      let formCt = document.querySelector('#ttaiEnterprise .inputs-errors-ct');
107      if(formCt) {
108        util.removeErrors(formCt);
109      }
110      submitBtn.disabled = true;
111      submitBtn.opacity = '0.5';
112      submitBtn.insertAdjacentHTML('afterBegin', `<div class="util-spinner-ct">
113            <div class="util-spinner " style="--spinner-color: 0, 0%, 0%" aria-hidden="true"></div>
114            <p class="util-sr-only">Loading...</p>
115        </div>`);
116      submitBtn.classList.add('loading');
117      executeRecaptcha("contact")
118        .then((token) => {
119          params["g-recaptcha-response"] = token;
120          util.request({
121            url: "/contact/ttaiLandingRequest.json",
122            method: "POST",
123            params,
124            success: function (response) {
125              const spinner = submitBtn.querySelector('.util-spinner-ct');
126              spinner.remove();
127              submitBtn.opacity = 1;
128              submitBtn.disabled = false;
129              submitBtn.classList.remove('loading');
130    
131              if(response.formErrors && Object.keys(response.formErrors) && Object.keys(response.formErrors).length) {
132                if(formCt) {
133                  util.showErrors(response.formErrors, formCt, true, true);
134                }
135              } else {
136                const contentEl = modalMain.querySelector('.content');
137                if(contentEl) {
138                  contentEl.classList.add('thanks');
139                  contentEl.innerHTML = `
140                  <h2>Thanks for your interest!</h2>
141                  <p>We'll be in touch soon.</p>
142                `;
143                };
144              }
145            }
146          });
147        })
148        .catch((err) => {
149          const spinner = submitBtn.querySelector('.util-spinner-ct');
150          if (spinner) {
151            spinner.remove();
152          }
153          submitBtn.opacity = 1;
154          submitBtn.disabled = false;
155          submitBtn.classList.remove('loading');
156          let errorMessage = "Oops.. something went wrong!";
157          if (err.message && err.message.includes("reCAPTCHA")) {
158            errorMessage = "reCAPTCHA validation failed. Please try again.";
159          }
160          if(formCt) {
161            util.showErrors({ name: errorMessage }, formCt, true, true);
162          }
163        });
164    }
165  }
166
167  const openBtns = document.querySelectorAll('.open-contact-modal');
168  openBtns.forEach(btn => {
169    btn.addEventListener('click', () => showModal(btn.dataset ? btn.dataset.type : '', btn.dataset ? btn.dataset.device : ''));
170  });
171
172  // FAQ Accordion
173  document.querySelectorAll('.ent-faq-trigger').forEach(trigger => {
174    trigger.addEventListener('click', () => {
175      const item = trigger.closest('.ent-faq-item');
176      const isActive = item.classList.contains('active');
177      document.querySelectorAll('.ent-faq-item.active').forEach(i => i.classList.remove('active'));
178      if (!isActive) item.classList.add('active');
179    });
180  });
181
182  // Toggle buttons scroll to their respective section
183  function scrollToPanel(panelId) {
184    document.querySelectorAll('.ent-sticky-toggle-btn').forEach(btn => {
185      btn.classList.toggle('active', btn.dataset.panel === panelId);
186    });
187    const target = document.getElementById('panel-' + panelId);
188    if (target) {
189      var offset = 0;
190      var nav = document.querySelector('.ent-nav');
191      var sticky = document.getElementById('entStickyToggle');
192      if (nav) offset += nav.offsetHeight;
193      if (sticky) offset += sticky.offsetHeight;
194      var top = target.getBoundingClientRect().top + window.pageYOffset - offset - 16;
195      window.scrollTo({ top: top, behavior: 'smooth' });
196    }
197  }
198
199  document.querySelectorAll('.ent-sticky-toggle-btn').forEach(btn => {
200    btn.addEventListener('click', () => scrollToPanel(btn.dataset.panel));
201  });
202
203  // Hero CTA scroll buttons (AI Transformation / AI Upskilling)
204  document.querySelectorAll('.ent-toggle-scroll-btn').forEach(btn => {
205    btn.addEventListener('click', () => {
206      const panelId = btn.dataset.target;
207      scrollToPanel(panelId);
208    });
209  });
210
211  // Top nav audience toggle
212  document.querySelectorAll('.ent-nav-toggle-btn').forEach(btn => {
213    btn.addEventListener('click', () => {
214      document.querySelectorAll('.ent-nav-toggle-btn').forEach(b => b.classList.remove('active'));
215      btn.classList.add('active');
216    });
217  });
218
219  // Mobile burger menu toggle
220  var mobileBurger = document.getElementById('entMobileBurger');
221  var mobileMenu = document.getElementById('entMobileMenu');
222  if (mobileBurger && mobileMenu) {
223    mobileBurger.addEventListener('click', function() {
224      mobileBurger.classList.toggle('open');
225      mobileMenu.classList.toggle('open');
226    });
227    document.addEventListener('click', function(e) {
228      if (!mobileBurger.contains(e.target) && !mobileMenu.contains(e.target)) {
229        mobileBurger.classList.remove('open');
230        mobileMenu.classList.remove('open');
231      }
232    });
233  }
234
235  // Communities page — pin sticky toggle when scrolled past its static position
236  if (document.querySelector('.com-page')) {
237    const stickyEl = document.getElementById('entStickyToggle');
238    if (stickyEl) {
239      const sentinel = document.createElement('div');
240      sentinel.style.height = '1px';
241      stickyEl.parentNode.insertBefore(sentinel, stickyEl);
242      const observer = new IntersectionObserver(function(entries) {
243        // Only pin when sentinel scrolls above the viewport (going down)
244        stickyEl.classList.toggle('is-pinned', entries[0].boundingClientRect.top < 0);
245      }, { threshold: 0 });
246      observer.observe(sentinel);
247    }
248  }
249
250  // Schools page — pin hero CTAs when scrolled past their static position
251  if (document.querySelector('.sch-page:not(.com-page)')) {
252    const heroCtas = document.querySelector('.sch-page .ent-hero-ctas');
253    if (heroCtas) {
254      const sentinel = document.createElement('div');
255      heroCtas.parentNode.insertBefore(sentinel, heroCtas);
256      const observer = new IntersectionObserver(function(entries) {
257        heroCtas.classList.toggle('is-pinned', !entries[0].isIntersecting);
258      }, { threshold: 0 });
259      observer.observe(sentinel);
260    }
261  }
262
263  // App mockup carousel — fade left out, fade right in
264  const slides = document.querySelectorAll('.ent-app-slide');
265  if (slides.length > 1) {
266    let current = 0;
267    setInterval(() => {
268      const prev = current;
269      current = (current + 1) % slides.length;
270      slides[prev].classList.add('leaving');
271      slides[prev].classList.remove('active');
272      slides[current].classList.add('active');
273      setTimeout(() => slides[prev].classList.remove('leaving'), 600);
274    }, 3000);
275  }
276});

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.