PageSourceSearch

https://mymind.com/js/main.js

js mymind.com collected 2026-09-24 10:19:12 UTC 16,554 bytes, 277 lines download raw bytes

1/* =====================================================================
2   mymind.com — static site behaviour
3   ---------------------------------------------------------------------
4   Everything the Semplice theme runtime used to do for these pages, rewritten without jQuery:
5     1. page reveal on load (navbar slides in, content fades in) and fade-out on internal link clicks
6     2. sticky navbar (adds .is-sticky once the page is scrolled) + the --vh custom property
7     3. hamburger / overlay menu open & close (with the staggered menu items)
8     4. "motion" animations from Semplice's editor (GSAP + ScrollTrigger; data comes from mm.motion([...]) at the end of each page)
9     5. Lottie modules (lottie-web) sized like Semplice did, played when scrolled into view
10     6. lightbox for images marked .semplice-lightbox (PhotoSwipe 4, only loaded on pages that use it)
11     7. YouTube lightbox: mm.videoLightbox({videos, triggers, exclude}) — the video links on /, /adhd, /mobile and /videos
12        open the embed in a lightbox on top of the page (replaces the pages' former jQuery scripts)
13   Dependencies: js/vendor/gsap.min.js + ScrollTrigger.min.js (always); lottie.min.js / photoswipe (per page).
14   ===================================================================== */
15window.mm = (function () {
16  'use strict';
17  var $ = function (sel, ctx) { return (ctx || document).querySelector(sel); };
18  var $$ = function (sel, ctx) { return Array.prototype.slice.call((ctx || document).querySelectorAll(sel)); };
19  var nav = $('.semplice-navbar');
20  var overlay = $('#overlay-menu');
21  var holder = $('#content-holder');
22  var content = $('.content-container');
23  var hamburger = $('.hamburger');
24  var mm = { lottie: {}, gsap: {} };
25  if (window.gsap && window.ScrollTrigger) gsap.registerPlugin(ScrollTrigger);
26
27  /* ---------- helpers ---------- */
28  function rgba(str) {                 // "rgb(255, 255, 255)" / "rgba(...)" → {r,g,b,a}
29    var m = (str || '').match(/[\d.]+/g) || [0, 0, 0, 0];
30    return { r: +m[0] || 0, g: +m[1] || 0, b: +m[2] || 0, a: m.length > 3 ? +m[3] : 1 };
31  }
32  function isExternal(href) {
33    if (href.indexOf(':') < 0 && href.indexOf('//') < 0) return false;
34    var a = document.createElement('a'); a.href = href;
35    return a.host !== location.host;
36  }
37
38  /* ---------- 1. page reveal / page change ---------- */
39  function revealPage() {              // pages without a navbar (e.g. /inactive-account-policy) still fade their content in
40    if (!window.gsap) return;
41    if (nav && !nav.classList.contains('non-sticky-nav')) {
42      gsap.to(nav, 0.8, { y: 0, ease: 'expo.out', clearProps: 'y', onComplete: function () { nav.style.transform = 'none'; nav.style.transition = ''; } });
43    } else if (nav) nav.style.transform = 'translateY(0)';
44    if (content) gsap.to(content, 0.6, { opacity: 1, ease: 'sine.out' });
45  }
46  function leavePage(url) {            // Semplice "static transitions": navbar up, page fades out, then navigate
47    if (nav && !$('.no-menu-transition')) { nav.style.transition = 'none'; gsap.to(nav, 0.7, { yPercent: -100, ease: 'expo.inOut' }); }
48    gsap.to(holder, 0.6, { opacity: 0, ease: 'sine.out', onComplete: function () { window.location = url; } });
49  }
50  document.addEventListener('click', function (e) {
51    var a = e.target.closest('a');
52    if (!a || e.defaultPrevented || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey || e.button !== 0) return;
53    if (a.classList.contains('semplice-event')) return;
54    var href = a.getAttribute('href');
55    if (a.getAttribute('target') === '_blank' || href === null || href === '') return;
56    if (isExternal(href) || href.charAt(0) === '#' || href.indexOf('#') > -1 || href.indexOf('replyto') > -1 || /^(mailto|tel|javascript):/.test(href)) return;
57    e.preventDefault();
58    leavePage(a.href);
59  });
60
61  /* ---------- 2. sticky navbar + --vh (site custom JS) ---------- */
62  var pageTop = holder ? holder.offsetTop : 0;
63  var headerEl = $('.sticky-nav');
64  window.addEventListener('scroll', function () {
65    var y = (document.documentElement && document.documentElement.scrollTop) || document.body.scrollTop;
66    if (!headerEl) return;
67    if (y > pageTop) headerEl.classList.add('is-sticky'); else headerEl.classList.remove('is-sticky');
68  });
69  window.addEventListener('resize', function () {
70    var vh = window.innerHeight * 0.01;
71    document.documentElement.style.setProperty('--vh', vh + 'px');
72  });
73
74  /* ---------- 3. overlay menu ---------- */
75  var menu = {
76    inner: function () { return $('.overlay-menu-inner nav'); },
77    responsiveOverlay: function () {
78      var h = $('header') ? $('header').offsetHeight : 0, n = menu.inner();
79      if (!n) return;
80      if (2 * h + (n.offsetHeight + 40) >= window.innerHeight) { n.classList.add('align-top'); n.style.top = (h + 40) + 'px'; }
81      else { n.classList.remove('align-top'); n.style.top = ''; }
82    },
83    navbarBg: function (visibility) {
84      var t = visibility === 'visible' ? menu.rgba.a : 0;
85      nav.style.backgroundColor = 'rgba(' + menu.rgba.r + ', ' + menu.rgba.g + ', ' + menu.rgba.b + ', ' + t + ')';
86    },
87    open: function (el) {
88      hamburger.setAttribute('disabled', 'disabled'); hamburger.setAttribute('data-status', 'open');
89      el.classList.remove('open-menu'); el.classList.add('close-menu');
90      menu.rgba = rgba(getComputedStyle(nav).backgroundColor);
91      menu.navbarBg(nav.getAttribute('data-bg-overlay-visibility'));
92      gsap.killTweensOf(overlay); overlay.style.display = 'block'; overlay.style.zIndex = '119';
93      gsap.to(overlay, 0.35, { opacity: 1, onComplete: menu.afterOpen });
94      setTimeout(function () { menu.showItems($$('.overlay-menu-inner nav ul li')); }, 50);
95    },
96    afterOpen: function () {
97      var innerEl = $('.overlay-menu-inner');
98      innerEl.parentNode.insertBefore(nav, innerEl); nav.style.position = 'absolute';
99      var before = window.innerWidth; document.body.classList.add('open-menu'); var after = window.innerWidth;
100      holder.style.width = (100 * before / after) + '%';
101      hamburger.removeAttribute('disabled');
102    },
103    showItems: function (items) {
104      var t = 0;
105      items.forEach(function (li) {
106        li.classList.add('before-fade');
107        gsap.to(li, 0.35, { opacity: 1, y: 0, clearProps: 'y', delay: t, onComplete: function () { li.classList.remove('before-fade'); } });
108        t += 0.08;
109      });
110    },
111    close: function (el) {
112      if (hamburger.getAttribute('disabled') === 'disabled') return;
113      var cls = 'open-menu'; if ($('nav.standard')) cls += ' responsive-menu';
114      hamburger.setAttribute('disabled', 'disabled'); hamburger.setAttribute('data-status', 'closed');
115      el.classList.remove('close-menu'); cls.split(' ').forEach(function (c) { el.classList.add(c); });
116      menu.navbarBg('visible');
117      overlay.parentNode.insertBefore(nav, overlay);
118      if ((!nav.classList.contains('non-sticky-nav') && window.innerWidth > 767.9) || nav.classList.contains('use-headroom')) nav.style.position = 'fixed';
119      document.body.classList.remove('open-menu');
120      holder.style.width = '100%';
121      gsap.to(overlay, 0.35, { opacity: 0, onComplete: menu.afterClose });
122    },
123    afterClose: function () {
124      overlay.style.zIndex = '-1'; overlay.style.display = 'none';
125      $$('.overlay-menu-inner nav ul li').forEach(function (li) { li.removeAttribute('style'); });
126      hamburger.removeAttribute('disabled');
127    }
128  };
129  document.addEventListener('click', function (e) {
130    var t = e.target.closest('.semplice-menu');
131    if (!t || !overlay) return;
132    e.preventDefault();
133    if (hamburger.getAttribute('data-status') === 'open') menu.close($('.close-menu')); else menu.open($('.open-menu'));
134  });
135  window.addEventListener('hashchange', function () { if (document.body.classList.contains('open-menu')) menu.close($('.close-menu')); });
136  window.addEventListener('pageshow', function (e) { if (e.persisted) window.location.reload(); });
137
138  /* ---------- 4. motion (Semplice editor animations) ---------- */
139  function motion(items) {
140    if (!window.gsap) return;
141    items.forEach(function (it) {
142      var opts = { repeat: it.repeat || 0 };
143      if (it.yoyo) opts.yoyo = true;
144      if (it.scroll) opts.scrollTrigger = it.scroll;
145      if (it.scrub) opts.scrollTrigger = it.scrub;
146      if (it.lottieScrub) {            // Semplice "on scroll" Lottie: the frame follows the scroll progress
147        var lid = it.lottieScrub;
148        opts.scrollTrigger = Object.assign({}, it.scrub, { onUpdate: function (self) {
149          var a = mm.lottie[lid]; if (a && a.totalFrames) a.goToAndStop(Math.floor(self.progress * (a.totalFrames - 1)), true);
150        } });
151      }
152      if (it.lottie) opts.onStart = function () { if (mm.lottie[it.lottie]) mm.lottie[it.lottie].play(); };
153      var tl = gsap.timeline(opts);
154      mm.gsap[it.id] = tl;
155      (it.set || []).forEach(function (s) { gsap.set(s[0], s[1]); });
156      (it.to || []).forEach(function (s) { tl.to(s[0], s[1]); });
157      tl.pause();
158      if (it.hover) {
159        var playing = false;
160        document.addEventListener('mouseover', function (e) { if (e.target.closest(it.hover) && !playing) { playing = true; tl.play(); } });
161        document.addEventListener('mouseout', function (e) {
162          var el = e.target.closest(it.hover);
163          if (el && playing && !(e.relatedTarget && el.contains(e.relatedTarget))) { playing = false; tl.reverse(); }
164        });
165      }
166    });
167    window.dispatchEvent(new Event('scroll'));
168  }
169
170  /* ---------- 5. Lottie ---------- */
171  function bool(v) { return v === 'true' ? true : v === 'false' ? false : v; }
172  function contentWidth(el) {         // like jQuery's .width(): fractional content-box width
173    var cs = getComputedStyle(el); return el.getBoundingClientRect().width - parseFloat(cs.paddingLeft) - parseFloat(cs.paddingRight) - parseFloat(cs.borderLeftWidth) - parseFloat(cs.borderRightWidth);
174  }
175  function initLottie() {
176    $$('.lottie-holder[data-lottie]').forEach(function (h) {
177      var id = h.id.replace(/_lottie$/, ''), module = document.getElementById(id);
178      var opts = JSON.parse(h.getAttribute('data-lottie-options') || '{}');
179      var w = +h.getAttribute('data-lottie-width'), hh = +h.getAttribute('data-lottie-height');
180      var p = { width: 'grid', custom_width: 570, justify: 'left', event: 'on_load', loop: false, speed: 1 }
180, custom = false, type = 'grid';
181      Object.keys(p).forEach(function (k) {
182        if (opts[k] === undefined) return;
183        var s = bool(opts[k]);
184        if (k === 'speed') s = s / 10;
185        if (k === 'width' && s === 'custom') { custom = true; type = 'custom'; }
186        p[k] = s;
187      });
188      var ratio = (hh / w).toFixed(2), mw = contentWidth(module), a;
189      if (custom && mw >= parseInt(p.custom_width)) a = parseInt(p.custom_width); else a = mw;
190      var height = Math.round(ratio * a);
191      $('.semplice-lottie', module).style.justifyContent = { left: 'flex-start', center: 'center', right: 'flex-end' }[p.justify];
192      h.style.width = a + 'px'; h.style.height = height + 'px';
193      h.setAttribute('data-width-type', type); h.setAttribute('data-ratio', ratio); h.setAttribute('data-custom-width', p.custom_width);
194      mm.lottie[id] = lottie.loadAnimation({ container: h, renderer: 'svg', loop: p.loop, autoplay: false, path: h.getAttribute('data-lottie'), rendererSettings: { className: id + '_lottie_styles', viewBoxOnly: true } });
195      mm.lottie[id].setSpeed(p.speed);
196      var style = document.createElement('style'); style.textContent = '.' + id + '_lottie_styles{width:100%;height:auto;max-width:100%}'; document.head.appendChild(style);
197    });
198  }
199  function resizeLottie() {
200    $$('.lottie-holder').forEach(function (h) {
201      var t = h.getAttribute('data-width-type'), s = parseInt(h.getAttribute('data-custom-width')), n = parseFloat(h.getAttribute('data-ratio'));
202      var o = contentWidth(h.closest('.column-content')), e = s;
203      if (t !== 'custom' || o < e) e = o;
204      h.style.width = e + 'px'; h.style.height = Math.round(n * e) + 'px';
205    });
206  }
207
208  /* ---------- 6. lightbox ---------- */
209  function initLightbox() {
210    var items = $$('.lightbox-item');
211    items.forEach(function (img, i) { img.setAttribute('data-photoswipe-index', i); });
212    if (!items.length || !window.PhotoSwipe) return;
213    holder.addEventListener('click', function (e) {
214      var a = e.target.closest('.semplice-lightbox');
215      if (!a) return;
216      var index = parseInt($('img', a).getAttribute('data-photoswipe-index'));
217      var pswp = $('.pswp'), slides = $$('.lightbox-item').map(function (el) {
218        return { src: el.getAttribute('src'), w: el.getAttribute('width'), h: el.getAttribute('height'), msrc: el.getAttribute('src'), title: el.getAttribute('caption') || '' };
219      });
220      mm.gallery = new PhotoSwipe(pswp, PhotoSwipeUI_Default, slides, {
221        index: index, history: false, shareEl: false,
222        getThumbBoundsFn: function (i) { var el = $$('.lightbox-item')[i], t = window.pageYOffset || document.documentElement.scrollTop, r = el.getBoundingClientRect(); return { x: r.left, y: r.top + t, w: r.width }; }
223      });
224      mm.gallery.init();
225    });
226  }
227
228  /* ---------- 7. YouTube lightbox ---------- */
229  var CLOSE_ICON = '<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M0.376009 17.808C-0.125336 18.3093 -0.125336 19.1221 0.376009 19.6235C0.877355 20.1248 1.6902 20.1248 2.19154 19.6235L9.99973 11.8155L17.8085 19.624C18.3098 20.1253 19.1226 20.1253 19.624 19.624C20.1253 19.1227 20.1253 18.3098 19.624 17.8085L11.8153 10L19.624 2.19148C20.1253 1.69015 20.1253 0.877331 19.624 0.375999C19.1226 -0.125333 18.3098 -0.125334 17.8085 0.375999L9.99973 8.18452L2.19154 0.376547C1.6902 -0.124785 0.877355 -0.124785 0.376009 0.376547C-0.125336 0.877879 -0.125336 1.6907 0.376009 2.19203L8.18419 10L0.376009 17.808Z"/></svg>';
230  function videoLightbox(o) {
231    var videos = o.videos || {}, box = null;
232    function open(id) {
233      if (!videos[id]) return;
234      close(true);
235      box = document.createElement('div'); box.className = 'mm-lightbox'; box.setAttribute('role', 'dialog'); box.setAttribute('aria-modal', 'true');
236      box.innerHTML = '<div class="mm-lightbox-frame"><iframe src="https://www.youtube.com/embed/' + videos[id] + '?autoplay=1" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></div>' +
237                      '<button class="mm-lightbox-close" type="button" aria-label="Close video">' + CLOSE_ICON + '</button>';
238      document.body.appendChild(box); document.body.style.overflow = 'hidden';
239      requestAnimationFrame(function () { requestAnimationFrame(function () { box.classList.add('is-open'); }); });
240      if (window.location.hash !== '#' + id) history.replaceState(null, document.title, window.location.pathname + window.location.search + '#' + id);
241    }
242    function close(silent) {
243      if (!box) return;
244      var b = box; box = null; b.classList.remove('is-open');
245      setTimeout(function () { if (b.parentNode) b.parentNode.removeChild(b); }, 200);
246      document.body.style.overflow = '';
247      if (!silent) history.replaceState(null, document.title, window.location.pathname + window.location.search);
248    }
249    document.addEventListener('click', function (e) {
250      if (box && (e.target.closest('.mm-lightbox-close') || (e.target.closest('.mm-lightbox') && !e.target.closest('.mm-lightbox-frame')))) { close(); return; }
251      var t = e.target.closest(o.triggers);
252      if (!t || (o.exclude && e.target.closest(o.exclude))) return;
253      var id = (t.className.match(/(?:^|\s)videoid-(\S+)/) || [])[1];
254      if (!id) return;
255      e.preventDefault(); open(id);
256    });
257    document.addEventListener('keydown', function (e) { if (e.key === 'Escape') close(); });
258    var id0 = window.location.hash.replace('#', '');
259    if (id0 && videos[id0]) open(id0);
260  }
261
262  /* ---------- init ---------- */
263  function init() {
264    if (nav && overlay) menu.responsiveOverlay();
265    revealPage();
266    if (window.lottie) initLottie();
267    initLightbox();
268    window.addEventListener('resize', function () {
269      if (overlay) menu.responsiveOverlay();
270      document.body.style.height = window.innerHeight + 'px';
271      resizeLottie();
272    });
273  }
274  if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init); else init();
275  mm.motion = motion; mm.menu = menu; mm.videoLightbox = videoLightbox;
276  return mm;
277})();

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.