PageSourceSearch

https://www.frenchmorning.com/wp-content/plugins/memberpress/js/readylaunch/general.js?ver=1.12.17

js frenchmorning.com collected 2026-09-24 09:06:07 UTC 8,202 bytes, 236 lines download raw bytes

1document.addEventListener('DOMContentLoaded', function () {
2  var userMenuButton = document.getElementById('user-menu-button');
3  var profileMenuDropdown =
4    document.querySelector('.profile-menu__dropdown') ||
5    document.querySelector('.wp-block-memberpress-pro-profile-menu__dropdown');
6  var mobileMenuButton =
7    document.querySelector('.profile-menu__button.--is-mobile') ||
8    document.querySelector('.wp-block-memberpress-pro-profile-menu__button.--is-mobile');
9  var meprAccountNav = document.getElementById('mepr-account-nav');
10  var clAccount = document.querySelector('.mepr-rl-account');
11  var isClAccountDrawer =
12    clAccount && meprAccountNav && clAccount.contains(meprAccountNav);
13
14  var mobileOverlay = null;
15
16  function ensureMobileDrawerCloseIcon() {
17    if (!isClAccountDrawer || !mobileMenuButton) {
18      return;
19    }
20    if (mobileMenuButton.querySelector('.mepr-account-mobile-menu-close-icon')) {
21      return;
22    }
23    var ns = 'http://www.w3.org/2000/svg';
24    var closeSvg = document.createElementNS(ns, 'svg');
25    closeSvg.setAttribute('class', 'mepr-account-mobile-menu-close-icon mepr-rl-shell-mobile-menu-close-icon');
26    closeSvg.setAttribute('fill', 'none');
27    closeSvg.setAttribute('viewBox', '0 0 24 24');
28    closeSvg.setAttribute('stroke', 'currentColor');
29    closeSvg.setAttribute('stroke-width', '2');
30    closeSvg.setAttribute('aria-hidden', 'true');
31    var p1 = document.createElementNS(ns, 'path');
32    p1.setAttribute('stroke-linecap', 'round');
33    p1.setAttribute('stroke-linejoin', 'round');
34    p1.setAttribute('d', 'M6 18L18 6M6 6l12 12');
35    closeSvg.appendChild(p1);
36    mobileMenuButton.appendChild(closeSvg);
37  }
38
39  function toggleProfileDropdown() {
40    if (profileMenuDropdown) {
41      profileMenuDropdown.classList.toggle('is-open');
42    }
43  }
44
45  function closeProfileDropdown() {
46    if (profileMenuDropdown) {
47      profileMenuDropdown.classList.remove('is-open');
48    }
49  }
50
51  function ensureOverlay() {
52    if (!isClAccountDrawer || mobileOverlay) {
53      return mobileOverlay;
54    }
55    mobileOverlay = document.createElement('div');
56    mobileOverlay.className = 'mepr-account-mobile-overlay mepr-rl-shell-mobile-overlay';
57    mobileOverlay.setAttribute('aria-hidden', 'true');
58    document.body.appendChild(mobileOverlay);
59    mobileOverlay.addEventListener('click', closeClAccountDrawer);
60    return mobileOverlay;
61  }
62
63  function mergeProfileQuicklinks() {
64    if (!isClAccountDrawer || !meprAccountNav) {
65      return;
66    }
67    if (meprAccountNav.querySelector('.mepr-account-mobile-quicklinks')) {
68      return;
69    }
70    var dropdown =
71      document.querySelector('.profile-menu__dropdown') ||
72      document.querySelector('.wp-block-memberpress-pro-profile-menu__dropdown');
73    if (!dropdown) {
74      return;
75    }
76    var links = dropdown.querySelectorAll('a[href]');
77    if (!links.length) {
78      return;
79    }
80    var wrap = document.createElement('div');
81    wrap.className = 'mepr-account-mobile-quicklinks mepr-rl-shell-mobile-quicklinks';
82    wrap.setAttribute('role', 'group');
83
84    links.forEach(function (a) {
85      wrap.appendChild(a.cloneNode(true));
86    });
87
88    var ul = meprAccountNav.querySelector('ul');
89    if (ul) {
90      meprAccountNav.insertBefore(wrap, ul);
91    } else {
92      meprAccountNav.insertBefore(wrap, meprAccountNav.firstChild);
93    }
94  }
95
96  function removeMobileQuicklinks() {
97    if (!meprAccountNav) {
98      return;
99    }
100    var quick = meprAccountNav.querySelector('.mepr-account-mobile-quicklinks');
101    if (quick) {
102      quick.remove();
103    }
104  }
105
106  function openClAccountDrawer() {
107    if (!meprAccountNav) {
108      return;
109    }
110    mergeProfileQuicklinks();
111    var ov = ensureOverlay();
112    meprAccountNav.classList.add('open');
113    document.body.classList.add('mepr-rl-account-mobile-nav-open', 'mepr-rl-shell-mobile-nav-open');
114    if (ov) {
115      ov.classList.add('is-visible');
116    }
117    if (mobileMenuButton) {
118      mobileMenuButton.setAttribute('aria-expanded', 'true');
119      mobileMenuButton.setAttribute('aria-label', 'Close menu');
120    }
121  }
122
123  function closeClAccountDrawer() {
124    if (!meprAccountNav) {
125      return;
126    }
127    var wasOpen = meprAccountNav.classList.contains('open');
128    meprAccountNav.classList.remove('open');
129    if (mobileOverlay) {
130      mobileOverlay.classList.remove('is-visible');
131    }
132    if (mobileMenuButton) {
133      mobileMenuButton.setAttribute('aria-expanded', 'false');
134      mobileMenuButton.setAttribute('aria-label', 'Open menu');
135    }
136
137    /* Defer body-class removal + quicklinks cleanup until the slide-out
138     * transition completes. Removing them synchronously drops the header
139     * z-index (shell.css raises it to 100000 only while the body class is
140     * set) and pops the cloned profile links out of the DOM — both happen
141     * at frame 0 while the drawer is still at translateX(0), which is the
142     * "colored flicker at the top" during slide-out. */
143    var doCleanup = function () {
144      if (meprAccountNav.classList.contains('open')) {
145        return; /* user re-opened mid-slide-out */
146      }
147      document.body.classList.remove('mepr-rl-account-mobile-nav-open', 'mepr-rl-shell-mobile-nav-open');
148      removeMobileQuicklinks();
149    };
150
151    if (wasOpen && window.innerWidth < 840) {
152      var onSlideOutEnd = function (ev) {
153        if (ev.target !== meprAccountNav || ev.propertyName !== 'transform') {
154          return;
155        }
156        meprAccountNav.removeEventListener('transitionend', onSlideOutEnd);
157        doCleanup();
158      };
159      meprAccountNav.addEventListener('transitionend', onSlideOutEnd);
160    } else {
161      /* Desktop resize handler or already-closed: nothing to animate. */
162      doCleanup();
163    }
164  }
165
166  function toggleClAccountDrawer() {
167    if (meprAccountNav.classList.contains('open')) {
168      closeClAccountDrawer();
169    } else {
170      openClAccountDrawer();
171    }
172  }
173
174  if (userMenuButton && profileMenuDropdown) {
175    userMenuButton.addEventListener('click', toggleProfileDropdown);
176
177    document.addEventListener('click', function (event) {
178      var isFromMenu =
179        userMenuButton.contains(event.target) ||
180        profileMenuDropdown.contains(event.target) ||
181        (mobileMenuButton && mobileMenuButton.contains(event.target));
182      if (!isFromMenu) {
183        closeProfileDropdown();
184      }
185    });
186  }
187
188  if (mobileMenuButton) {
189    if (isClAccountDrawer && meprAccountNav) {
190      ensureMobileDrawerCloseIcon();
191      mobileMenuButton.setAttribute('aria-label', 'Open menu');
192      mobileMenuButton.addEventListener(
193        'click',
194        function (e) {
195          e.preventDefault();
196          e.stopImmediatePropagation();
197          toggleClAccountDrawer();
198        },
199        true
200      );
201
202      document.addEventListener('keydown', function (e) {
203        if (e.key === 'Escape' && meprAccountNav.classList.contains('open')) {
204          closeClAccountDrawer();
205        }
206      });
207
208      meprAccountNav.addEventListener('click', function (e) {
209        var t = e.target;
210        if (t && t.closest && t.closest('a') && meprAccountNav.classList.contains('open')) {
211          closeClAccountDrawer();
212        }
213      });
214
215      window.addEventListener('resize', function () {
216        /* Always reset drawer state when returning to desktop (avoids stray body/overlay class). */
217        if (window.innerWidth >= 840) {
218          closeClAccountDrawer();
219        }
220      });
221    } else if (meprAccountNav) {
222      mobileMenuButton.addEventListener('click', function () {
223        meprAccountNav.classList.toggle('open');
224      });
225    } else if (profileMenuDropdown) {
226      /* No drawer / no account nav (e.g. Courses, Login, or any FSE page
227       * that ships the profile-menu without an account or coaching drawer):
228       * the mobile button now shows the avatar, so reuse the desktop
229       * dropdown handler so users on these routes can still reach
230       * Account / Logout / etc. Coaching pages bind their own drawer
231       * handler in capture phase with stopImmediatePropagation, so this
232       * bubble-phase listener is naturally suppressed there. */
233      mobileMenuButton.addEventListener('click', toggleProfileDropdown);
234    }
235  }
236});

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.