// --- Utilities ------------------------------------------------------ function debounce(func) { let timer = null; return function (e) { if (timer) clearTimeout(timer); timer = setTimeout(func, 300, e); }; } // --- No js -------------------------- document.body.classList.toggle('no-js') // -------------------------------------------------------------------- // --- Carousel ------------------------------------------------------- // -------------------------------------------------------------------- // If a slide navigation element is clicked, then scroll // the element into view. This leverages the fact that the // carousel works with pure CSS but this JS addition prevents // polluting the history with anchor links (e.g., #slide-0, // #slide-1, etc) const siteHeader = document.getElementById('masthead') const getAutoIncrValue = () => window.innerWidth >= 980 ? 3 : 1 const scrollViewportLeftToTargetID = function (viewport, id) { const target = viewport.querySelector(id) if ( target ) { viewport.scrollLeft = target.offsetLeft } } document.querySelectorAll('.slider ul.slider-viewport') // Loops through viewports so that multipl carousels can // be included on a single page without any collisions .forEach((viewport) => { // Cache the count and initialize a local idx for the autoplay // feature of the JS-enabled content carousel const slideCnt = viewport.querySelectorAll('.slide').length let autoIdx = 0 let autoIncr = getAutoIncrValue() viewport .querySelectorAll('a.slide-nav') .forEach((ele) => { ele.addEventListener("click", (e) => { e.preventDefault(); // Ensure that the carousel is unobstructed in view window.scrollTo(0, viewport.parentElement.offsetTop - siteHeader.offsetHeight) // If we are in desktop then we have data-target that will // place us in the right group, the standard href provides the // mobile and/or non-JS target for scrolling const targetEleID = e.target.getAttribute('data-target') || e.target.attributes.href.nodeValue scrollViewportLeftToTargetID(viewport, '.slider ' + targetEleID) return }) }) // Set a timeout to automatically scroll each carousel setInterval((vp) => { autoIdx = autoIdx + autoIncr > slideCnt ? 0 : autoIdx + autoIncr scrollViewportLeftToTargetID(viewport, '.slider #slide-' + autoIdx) }, 8000, viewport) // If the document is resized then we need to ensure we scroll // to the beginning of the carousel containers, as the CSS // implementation cannot do this on its own, and in this case, // the scroll offset and new calculated widths of the containers // will be broken window.addEventListener( "resize", debounce(function (e) { autoIncr = getAutoIncrValue() viewport.scrollLeft = 0 autoIdx = 0 })) }) // -------------------------------------------------------------------- // --- Search Bar ------------------------------------------------------- // Enable submit button when text is entered into field // Works for multiple search bars document.querySelectorAll(".search-bar") .forEach((searchForm) => { const searchSubmitBtn = searchForm.querySelector('button[type="submit"]'); const searchField = searchForm.querySelector('input[type="search"]'); // If the search field does not already have a value we will // apply disabled immediately if ( searchField.value.length === 0 ) { searchSubmitBtn.setAttribute("disabled", "disabled"); } searchField.addEventListener("keyup", (event) => { return event.target.value.length ? searchSubmitBtn.removeAttribute("disabled") : searchSubmitBtn.setAttribute("disabled", "disabled"); }); }); // ------ Focus nav search and hide others when activated ------------------------------ const siteSearch = document.querySelector('input#nav-site-search') document.querySelector('#masthead .search-trigger label[for="search-trigger"]') .addEventListener('click', (event) => { const trigger = document.querySelector('#search-trigger') if ( !trigger.checked ) { document .querySelectorAll('#masthead .optional-trigger input#optional-trigger, #masthead .member-menu input#toggle-member-profile') .forEach((ele) => { ele.checked = false }) setTimeout(function() { siteSearch.setAttribute('tabindex', '0') siteSearch.focus() }, 1) } else { siteSearch.removeAttribute('tabindex') } }); // --- Nav bar progressive enhancements -------------------------------- // ------ Close search/more/member nav when
clicked document.querySelector('main') .addEventListener('click', (event) => { document .querySelectorAll('#masthead .search-trigger input#search-trigger, #masthead .optional-trigger input#optional-trigger, #masthead .member-menu input#toggle-member-profile') .forEach((ele) => { ele.checked = false }) return true }); // ------ Hide search/members when more dropdown is clicked ------------------------------ (() => { const moreToggle = document.querySelector('#masthead .optional-trigger label[for="optional-trigger"]') if(!moreToggle) return moreToggle.addEventListener('click', (event) => { const trigger = document.querySelector('#optional-trigger') document .querySelectorAll('#masthead .search-trigger input#search-trigger, #masthead .member-menu input#toggle-member-profile') .forEach((ele) => { ele.checked = false }) }) })(); // ------ Hide search/more when members dropdown is clicked ------------------------------ (() => { const memberProfileToggle = document.querySelector('#masthead .member-menu label[for="toggle-member-profile"]') if(!memberProfileToggle) return memberProfileToggle.addEventListener('click', (event) => { const trigger = document.querySelector('#toggle-member-profile') document .querySelectorAll('#masthead .search-trigger input#search-trigger, #masthead .optional-trigger input#optional-trigger') .forEach((ele) => { ele.checked = false }) }) })(); // --- Share Bar ------------------------------------------------------- // Enable popup for sharing to Facebook, Linkedin, and Twitter. Falls back to // target blank for no-js. document.querySelectorAll('[data-class="popup"]') .forEach((popup) => { popup.addEventListener('click', (event) => { event.preventDefault(); open(popup.getAttribute('href'), 'popup', `menubar=no,toolbar=no,scrollbars=no,width=600,height=300,left=100,top=100`); }) }); // -- Join or Signin Modal ---------------------------------------------- // -- // Join or Signin with Email - AKA email exists. // On 'Enter your email' submit, prevent default form submission // and XHR POST. This is pickedup by the tr_join_signin_with_email init action hook // in /inc/join-signin-functions.php. // The response sets email_exists. If email_exists, set the signin form active, // else set the the join form active. If browser has no JS, then this is done via PHP. function setup_listener_for_join_login_email_exists_form() { var email_exists_form = document.querySelector(".join-signin-email form"); // Need to check if email_exists_form exists before attaching an event listener. if ( ! email_exists_form ) { return; } email_exists_form.addEventListener("submit", (event) => { event.preventDefault(); // Show spinner. var spinner = document.querySelector(".join-signin-wrap .tr-spinner"); spinner.classList.add("show"); // Disable submit button. document.querySelector(".join-signin-email form input[type=\"submit\"]").disabled = true; // Get the join-signin form input values as FormData. // Append 'ajax' key for the endpoint to // know its hit by ajax instead of directly by PHP. var form_data = new FormData(email_exists_form); form_data.append("ajax", true); // Hit the AJAX endpoint for tr_email_exists and set the approiate next form active. var xhr = new XMLHttpRequest(); xhr.responseType = 'json'; xhr.open("POST", email_exists_form.getAttribute("action"), true); xhr.send(form_data); xhr.onreadystatechange = function() { if (this.readyState === XMLHttpRequest.DONE && this.status === 200) { // Hide Spinner. spinner.classList.remove("show"); var response = xhr.response; var email_exists = response.email_exists; var username = response.username_suggestion; // Show and hide appropriate blocks based on this endpoint being hit and its response. document.querySelector("#email-trigger").checked = false; document.querySelector(".join-signin-options, .join-signin-email").classList.remove("active"); document.querySelector((email_exists) ? ".signin-email" : ".join-email").classList.add("active"); // Set signin and register email fields' values to be the previously entered join-signin-email. var email = document.querySelector(".join-signin-email input[type=\"email\"]").value; document.querySelector(".active input[type=\"email\"]").value = email; document.querySelector("form#forgot-pw input[name=\"join-signin-email\"]").value = email; // If email does not exist, set returned username suggestion in username field. if ( !email_exists ) { document.querySelector(".join-email input[name=\"username\"]").value = username; } // Focus password input and set placeholder. The login form doesn't have a way to set // the placeholder without JS. var password_input = document.querySelector(".active input[type=\"password\"]"); password_input.placeholder = "Enter your password"; password_input.focus(); } } }); } setup_listener_for_join_login_email_exists_form(); // Join or Signin with Email // On signin or join submit, prevent default, show spinner, and attempt signin with XHR POST which is // pickedup by the tr_join_signin_with_email init action hook in /inc/join-signin-functions.php. document.querySelectorAll(".signin-email form, .join-email form") .forEach((form) => { form.addEventListener("submit", (event) => { event.preventDefault(); // Show spinner. var spinner = document.querySelector(".join-signin-wrap .tr-spinner"); spinner.classList.add("show"); let buttons = [] // Disable submit button. buttons.push(document.querySelector('#submit-login')) buttons.push(document.querySelector('#submit-join')) buttons.forEach(button => { button.disabled = true; }) // Get the form input values as FormData. // Append 'ajax' key for the endpoint to // know its hit by ajax instead of directly by PHP. var form_data = new FormData(form); form_data.append("ajax", true); // Hit the AJAX endpoint for tr_email_exists and set the approiate next form active. var xhr = new XMLHttpRequest(); xhr.responseType = 'json'; xhr.open("POST", form.getAttribute("action"), true); xhr.send(form_data); xhr.onreadystatechange = function() { if ( this.readyState === XMLHttpRequest.DONE ) { // Hide Spinner. spinner.classList.remove("show"); // Status 200 - Login or Join successful, reload page. if ( this.status === 200 ) { if ( form.id === 'forgot-pw' ) { document.querySelector(".signin-email").classList.remove('active'); document.querySelector(".reset-pw").classList.add('active'); return; } localStorage.setItem('shouldSendLoginEvent', true); const redirectTo = form.querySelector('input[name="redirect_to"]') if ( redirectTo && redirectTo.value !== '' ) { window.location.href = redirectTo.value return } location.reload(); return; } buttons.forEach(button => { button.disabled = false; }) document.querySelector(".active .error-message").classList.add("active"); } } }) }) // --- Adds premium functionality to the sign in modal document.querySelectorAll('[data-action="login"][data-section="premium"]') .forEach((ele) => { ele.addEventListener('click', (event) => { const modal = document.querySelector('div.dropdown.tr-modal') if ( !modal ) { return true } modal.classList.add('modal-tr-premium') modal.querySelector('div.join-signin-options label[for="email-trigger"]').click() modal.querySelector('input[name="email-trigger"]').checked = true }) }) // Reset Join-Signin modal when close button clicked. const trModalCheckBox = document.querySelector('input#tr_modal_trigger_input[type="checkbox"]') if ( null !== trModalCheckBox ) { trModalCheckBox.addEventListener('change', (event) => { if ( event.target.checked === true ) return true; const container = document.querySelector('div.tr-modal.dropdown') const joinSignin = container.querySelector(".join-signin-wrap") container.classList.remove('modal-tr-premium') // Hide spinner. joinSignin.querySelector(".tr-spinner").classList.remove("show"); // Clear input fields. joinSignin.querySelector('input[type="email"]').value = ''; joinSignin.querySelector('input[type="password"]').value = ''; // Enable submit buttons joinSignin.querySelector('input[type="submit"]').disabled = false; // Unset signin and join form wraps from being active. joinSignin.querySelector('.active').classList.remove("active"); // Set join-signin-options wrap active container.querySelector('input[name="email-trigger"]').checked = false document.querySelector(".join-signin-options").classList.add("active"); }); } // -- Login Triggers ---------------------------------------------------- const loginTrigger = document.getElementById('tr_modal_trigger_input') if ( loginTrigger ) { document.querySelectorAll('[data-action="login"]') .forEach((trigger) => { trigger.addEventListener('click', (event) => { event.preventDefault(); const intent = event.target.getAttribute('data-intent') || false let redirectTo = event.target.getAttribute('data-redirect') || window.location.href loginTrigger.click(); if ( redirectTo ) { const redirectInputs = document.querySelectorAll('input[name="redirect_to"]') redirectTo = new URL(redirectTo) redirectTo.searchParams.set('intent', intent) redirectInputs.forEach((input) => { input.setAttribute('data-prev-redirect', input.getAttribute('value')) input.setAttribute('value', redirectTo.href) }) // A little cleanup here... loginTrigger.addEventListener('change', (trigger) => { redirectInputs.forEach((input) => { input.setAttribute('value', input.getAttribute('data-prev-redirect')) }) }) } return false; }) }) } // -- Video Archive Slider ----------------------------------------------- const videoArchiveSlider = document.querySelector(".archive-video-slider"); if (videoArchiveSlider) { const slides = document.querySelectorAll(".video-slide"); const prevArrow = document.querySelector(".prev-slide"); const nextArrow = document.querySelector(".next-slide"); // Show next arrow nextArrow.style.visibility = "visible"; nextArrow.addEventListener("click", event => { event.preventDefault(); const currentSlideIdx = parseInt(videoArchiveSlider.dataset.currentSlide); // Show prev arrow prevArrow.style.visibility = "visible"; slides.forEach(node => { // Shift slides forward const leftPosition = parseInt(node.style.left.split("%").slice(0,1)); const newLeftPosition = (leftPosition - 100).toString() + "%"; node.style.left = newLeftPosition // Update active slide const nextSlide = slides[currentSlideIdx + 1]; if (nextSlide) { node.querySelector(".video-details") && node.querySelector(".video-details").classList.remove("active"); node.classList.remove("active"); nextSlide.querySelector(".video-details") && nextSlide.querySelector(".video-details").classList.add("active"); nextSlide.classList.add("active"); } // Hide next arrow if necessary if (!slides[currentSlideIdx + 2]) { nextArrow.style.visibility = "hidden"; } // Update current slide index videoArchiveSlider.dataset.currentSlide = currentSlideIdx + 1; }) }) prevArrow.addEventListener("click", event => { event.preventDefault(); const currentSlideIdx = parseInt(videoArchiveSlider.dataset.currentSlide); // Show next arrow nextArrow.style.visibility = "visible"; slides.forEach(node => { // Shift slides backward const leftPosition = parseInt(node.style.left.split("%").slice(0,1)); const newLeftPosition = (leftPosition + 100).toString() + "%"; node.style.left = newLeftPosition; // Update active slide const prevSlide = slides[currentSlideIdx - 1]; if (prevSlide) { node.querySelector(".video-details") && node.querySelector(".video-details").classList.remove("active"); node.classList.remove("active"); prevSlide.querySelector(".video-details") && prevSlide.querySelector(".video-details").classList.add("active"); prevSlide.classList.add("active"); } // Hide prev arrow if necessary if (!slides[currentSlideIdx - 2]) { prevArrow.style.visibility = "hidden"; } // Update current slide index videoArchiveSlider.dataset.currentSlide = currentSlideIdx - 1; }) }) } // --- Related Videos Slider ------------------------------------------------------- const relatedVideoSlider = document.querySelector(".video-related"); if (relatedVideoSlider) { const prevArrow = relatedVideoSlider.querySelector(".prev-arrow"); const nextArrow = relatedVideoSlider.querySelector(".next-arrow"); const slates = relatedVideoSlider.querySelectorAll(".slate"); // Show next arrow nextArrow.style.display = "inline"; nextArrow.addEventListener("click", event => { event.preventDefault(); const currentSlideIdx = parseInt(relatedVideoSlider.dataset.currentSlide); // Show prev arrow prevArrow.style.display = "inline"; slates.forEach(node => { const [slateTransformString] = node.style.transform .split("(") .slice(1) .join("") .split("%") .slice(0, 1) const slateTransformValue = slateTransformString && parseInt(slateTransformString) || 0 // Shift slates forward const newTransformValue = "translate3d(" + (slateTransformValue - 100).toString() + "%, 0, 0)"; node.style.transform = newTransformValue // Update active slate const nextSlide = slates[currentSlideIdx + 1]; if (nextSlide) { node.classList.remove("active"); nextSlide.classList.add("active"); } // Hide next arrow if necessary if (!slates[currentSlideIdx + 2]) { nextArrow.style.display = "none"; } // Update current slate index relatedVideoSlider.dataset.currentSlide = currentSlideIdx + 1; }) }) prevArrow.addEventListener("click", event => { event.preventDefault(); const currentSlideIdx = parseInt(relatedVideoSlider.dataset.currentSlide); // Show next arrow nextArrow.style.display = "inline"; slates.forEach(node => { // Shift slates backward const [slateTransformString] = node.style.transform .split("(") .slice(1) .join("") .split("%") .slice(0, 1) const slateTransformValue = slateTransformString && parseInt(slateTransformString) || 0 const newTransformValue = "translate3d(" + (slateTransformValue + 100).toString() + "%, 0, 0)"; node.style.transform = newTransformValue; // Update active slate const prevSlide = slates[currentSlideIdx - 1]; if (prevSlide) { node.classList.remove("active"); prevSlide.classList.add("active"); } // Hide prev arrow if necessary if (!slates[currentSlideIdx - 2]) { prevArrow.style.display = "none"; } // Update current slide index relatedVideoSlider.dataset.currentSlide = currentSlideIdx - 1; }) }) } // --- Load More Galleries ------------------------------------------------------- // AJAX Load More button for infinte scroll var galleryArchive = document.querySelector(".archive-gallery"); if (galleryArchive) { const loadMoreBtn = galleryArchive.querySelector(".load-more-btn") || false; if (loadMoreBtn) { loadMoreBtn.style.display = "block"; // POST FormData to WP admin-ajax // _ajax_nonce and action are required loadMoreBtn.addEventListener("click", async (event) => { event.preventDefault(); var galleryArchive = document.querySelector(".archive-gallery"); const galleryList = galleryArchive.querySelector("ul"); const galleryListItems = galleryList.querySelectorAll("li"); loadMoreBtn.innerHTML = "Loading"; const currentGalleryCount = galleryListItems.length + 1; // adding 1 to include featured gallery // load_more_posts is the name of the localized object // that includes the nonce and ajax_url. It is created // via wp_localize_script const body = new FormData(); body.append("_ajax_nonce", load_more_posts.nonce); body.append("action", "load-more-galleries"); body.append("post_type", "gallery"); body.append("posts_per_page", 20); body.append("offset", currentGalleryCount); body.append("ajax", true); try { const response = await fetch(load_more_posts.ajax_url, { method: "POST", body, }); const data = await response.text(); if (data && (parseInt(data) === -1 || parseInt(data) === 0)) { throw new Error("No more galleries"); } // response.text() is article-summary HTML as string. // Insert it to end of gallery article list as HTML galleryList.insertAdjacentHTML("beforeend", data); } catch (err) { console.error(err); } finally { loadMoreBtn.innerHTML = "Load More"; loadMoreBtn.blur(); } }); } } // --- Image Gallery ------------------------------------------------------- const singleGalleryPage = document.querySelector(".single-gallery"); if (singleGalleryPage) { const gallerySlider = singleGalleryPage.querySelector('.gallery-slider'); const currentImageNumber = document.querySelector('.current-image'); const nextArrows = document.querySelectorAll('.next-arrow'); nextArrows.forEach((arrow) => { arrow.addEventListener('click', event => { event.preventDefault(); incrementSlide(); }); }) const prevArrows = document.querySelectorAll('.back-arrow'); prevArrows.forEach((arrow) => { arrow.addEventListener('click', event => { event.preventDefault(); decrementSlide(); }) }) const nextLink = document.querySelector('.next-link'); nextLink.addEventListener('click', event => { event.preventDefault(); incrementSlide(); }); const prevLink = document.querySelector('.prev-link'); prevLink.addEventListener('click', event => { event.preventDefault(); decrementSlide(); }); function incrementSlide() { const currentSlideIdx = parseInt(gallerySlider.dataset.currentSlide); const slideItems = document.querySelectorAll('.slide'); const nextSlideIdx = currentSlideIdx + 1 > slideItems.length ? slideItems.length : currentSlideIdx + 1; if (slideItems[nextSlideIdx]) { slideItems[currentSlideIdx].classList.remove('active'); slideItems[nextSlideIdx].classList.add('active'); gallerySlider.dataset.currentSlide = nextSlideIdx; currentImageNumber.innerHTML = nextSlideIdx + 1; } prevArrows[0].style.visibility = "visible"; if (slideItems[nextSlideIdx] && !slideItems[nextSlideIdx + 1]) { nextArrows[nextSlideIdx].style.visibility = "hidden"; } } function decrementSlide() { const currentSlideIdx = parseInt(gallerySlider.dataset.currentSlide); const slideItems = document.querySelectorAll('.slide'); const prevSlideIdx = currentSlideIdx - 1 < 0 ? 0 : currentSlideIdx - 1; if (slideItems[prevSlideIdx]) { slideItems[currentSlideIdx].classList.remove('active'); slideItems[prevSlideIdx].classList.add('active'); gallerySlider.dataset.currentSlide = prevSlideIdx; currentImageNumber.innerHTML = prevSlideIdx + 1; } nextArrows[nextArrows.length - 1].style.visibility = "visible"; if (slideItems[prevSlideIdx] && !slideItems[prevSlideIdx - 1]) { prevArrows[prevSlideIdx].style.visibility = "hidden"; } } const imageLinks= document.querySelectorAll(".slide-img"); imageLinks.forEach((imgLink, i) => { imgLink.addEventListener('click', event => { event.preventDefault(); const overlays = document.querySelectorAll('.overlay-dark'); overlays[i].style.visibility = 'visible'; const closeOverlayBtns = document.querySelectorAll('.close-overlay'); closeOverlayBtns[i].style.visibility = 'visible'; }) }) const closeOverlayBtns = document.querySelectorAll('.close-overlay'); closeOverlayBtns.forEach((btn, i) => { btn.addEventListener('click', () => { const overlays = document.querySelectorAll('.overlay-dark'); console.log(btn) overlays[i].style.visibility = 'hidden'; btn.style.visibility = 'hidden'; }) }); } // --- Load More Articles ----------------------------------------------------- const loadMoreBtns = document.querySelectorAll('[data-action="content-load-more"]') loadMoreBtns.forEach((btn) => { btn.style.display = "block" btn.addEventListener('click', async (e) => { e.preventDefault() const b = e.target const targetContainer = document.querySelector('#' + b.getAttribute('data-target')) const query = window[b.id.toLowerCase().replaceAll('-', '_')] query.paged = query.paged == 0 ? 2 : query.paged + 1 b.innerHTML = "Loading"; const body = new FormData(); body.append("_ajax_nonce", load_more_posts.nonce); body.append('action', 'load_more_posts') body.append('query', JSON.stringify(query)) try { const response = await fetch(load_more_posts.ajax_url, { method: "POST", body, }); const data = await response.text(); if (data && (parseInt(data) === -1 || parseInt(data) === 0)) { throw new Error("No more content"); } targetContainer.insertAdjacentHTML("beforeend", data); } catch (err) { console.error(err); } finally { b.innerHTML = "Load More"; b.blur(); } }) }) // -- Logout User ------------------------------------------ // Removing this functionality unless reasoning is presented behind using AJAX // const logout_form = document.querySelector("#logout"); // if ( logout_form ) { // logout_form.addEventListener("submit", (event) => { // event.preventDefault(); // document.querySelector("form#logout input[type=\"submit\"]").disabled = true; // var form_data = new FormData(); // form_data.append("ajax", true); // form_data.append('logout', true); // // Hit the AJAX endpoint for tr_email_exists and set the approiate next form active. // var xhr = new XMLHttpRequest(); // xhr.responseType = 'json'; // xhr.open("POST", location.href, true); // xhr.send(form_data); // xhr.onreadystatechange = function() { // if (this.readyState === XMLHttpRequest.DONE && this.status === 200) { // location.reload(); // } // } // }); // } // ---------------------------------------------------------------------------- // -- Newsletter Subscriptions ------------------------------------------------ // ---------------------------------------------------------------------------- document.querySelectorAll('form[data-action="newsletter-toggle-subscription"]') .forEach((form) => { form.addEventListener("submit", async (event) => { event.preventDefault(); const submit_btn = form.querySelector('button[type="submit"]') const LABEL_DEFAULT = submit_btn.innerHTML const LABEL_UNSUBSCRIBED = 'Subscribe' const LABEL_SUBSCRIBED = 'Unsubscribe' const LABEL_LOADING = 'Please Wait...' submit_btn.disabled = true submit_btn.innerHTML = LABEL_LOADING const body = new FormData(form); body.append("ajax", true); body.append("_ajax_nonce", toggle_newsletter_subscription.nonce); body.append('action', 'toggle_newsletter_subscription') try { const response = await fetch(toggle_newsletter_subscription.ajax_url, {method: "POST", body}); const resp = await response.json(); switch ( resp.status ) { case 'error': throw new Error('TAPI server error occurred') break; case 'subscribed': submit_btn.classList.add('active') submit_btn.innerHTML = LABEL_SUBSCRIBED dataLayer.push({'event': 'newsletter_subscription', 'newsletter': resp.newsletter_sub_key}); break; case 'unsubscribed': submit_btn.classList.remove('active') submit_btn.innerHTML = LABEL_UNSUBSCRIBED dataLayer.push({'event': 'newsletter_unsubscribe', 'newsletter': resp.newsletter_sub_key}); break; default: submit_btn.innerHTML = LABEL_DEFAULT } } catch (err) { alert('Sorry, something went wrong. Please try again later.') console.error(err) submit_btn.innerHTML = LABEL_DEFAULT } finally { submit_btn.disabled = false } }); }); // ---------------------------------------------------------------------------- // -------------------------------------------------------------------------------------- // -- Filter functionality -------------------------------------------------------------- // // Used on various list views and the search views to limit $queries // -------------------------------------------------------------------------------------- document.querySelectorAll('section.filter') .forEach((filterNode) => { const formNode = filterNode.querySelector('form') formNode.addEventListener('submit', (e) => e.preventDefault()) // ----- Dropdown closing functionality --------------------------------------------- document.addEventListener('click', (event) => { const state = formNode.elements['filter-parameters'].value if ( state !== 'on' ) { return }; // This 'load-more' button could be removed, resulting in a false positive if ( event.target.classList.contains('load-more') ) { return; } if ( !filterNode.contains(event.target) ) { setTimeout(() => formNode.reset(), 1) } }) // ----- Dropdown closing ----------------------------------------------------------- filterNode.querySelectorAll('label.filter-trigger') .forEach((label) => { label.addEventListener('click', (event) => { const target = filterNode.querySelector('#' + event.target.getAttribute('for')) if ( !target ) { return } if ( target.checked ) { setTimeout(() => formNode.reset(), 1) } }) }) // ----- Mobile select/option-based Navigation --- filterNode.querySelectorAll("select") .forEach((select) => { select.addEventListener('change', (event) => { window.location.href = event.target.value }) }) // ----- Load More terms button --------------------------------------------------------- filterNode.querySelectorAll('button.load-more') .forEach((btn) => { btn.addEventListener('click', (event) => { event.preventDefault(); const target = event.target.parentNode.parentNode.querySelector('div.is-hidden') target.classList.toggle('is-hidden') // Remove button if the last element... if ( null === event.target.parentNode.parentNode.querySelector('div.is-hidden') ) { event.target.remove() } }) }) }) // ----- Video Feedback Form Enhancements ----------------------------------------------------- const videoFeedbackForm = document.querySelector(".video-feedback-form"); if (videoFeedbackForm) { const formFields = videoFeedbackForm.querySelectorAll(".read-write"); const submitBtn = videoFeedbackForm.querySelector("input[type='submit']"); const errorMessage = videoFeedbackForm.querySelector(".error-message"); formFields.forEach(node => { node.addEventListener("change", () => { node.classList.remove("error"); errorMessage.style.display = "none"; }) }); submitBtn.addEventListener("click", event => { event.preventDefault(); const emptyFields = []; formFields.forEach(node => { if (!node.value) { node.classList.add("error"); errorMessage.style.display = "block"; emptyFields.push(node); } }); if (!emptyFields.length) { videoFeedbackForm.submit(); } }); } // --- Resource Library ----------------------------------------------------------- // Functionality restructured and moved to TA Resource Library plugin in custom-question/cq.js /*document.querySelectorAll('a[data-post-action-link]') .forEach((link) => { link.addEventListener('click', (e) => { event.preventDefault() window.open(event.target.href, 'tr_post') setTimeout(() => { window.location.href = e.target.getAttribute('data-post-action-link') }, 1) return false; }) })*/ // ---------- Share by Email ------------------------------------------------------ document.querySelectorAll("form.share-email-form") .forEach((form) => { form.addEventListener("submit", async (event) => { event.preventDefault(); const submit_btn = form.querySelector('input[type="submit"]'); const LABEL_DEFAULT = submit_btn.value; const LABEL_LOADING = 'Please Wait...'; var response_msg = form.querySelector(".response-msg"); submit_btn.disabled = true; submit_btn.value = LABEL_LOADING; const body = new FormData(form); body.append("ajax", true); body.append("_ajax_nonce", share_email.nonce); body.append('action', 'share-email'); try { const response = await fetch(share_email.ajax_url, {method: "POST", body}); const resp = await response.json(); if ( response.status == 200 ) { response_msg.style.display = 'block'; dataLayer.push({'event': 'share_by_email'}); } else { throw new Error('error occurred'); } } catch (err) { response_msg.style.display = 'block'; response_msg.innerHTML = 'Sorry, something went wrong. Please try again later.'; response_msg.classList.add('error'); } finally { submit_btn.value = LABEL_DEFAULT; submit_btn.disabled = false; } }); }); // -------- Header scroll events for Ads ------------------------------------- function set_site_header_for_skybox_ads() { const body = document.querySelector("body"); var skybox = document.querySelector('#nav-ad'); if (!skybox) { skybox = document.querySelector('#nav-ad-plus-leader'); } if( !body.classList.contains('skybox-loaded') || !skybox) { // Do nothing is skybox not loaded. return; } // Calculate offset for admin-bar height var adminbar_offset = 0; if( body.classList.contains('admin-bar') ) { var admin_bar_obj = document.getElementById('wpadminbar'); if(admin_bar_obj) { adminbar_offset = admin_bar_obj.offsetHeight; } } const skybox_min_height = getComputedStyle(skybox).getPropertyValue('--cc-sbillboard-min-height'); const skybox_max_height = getComputedStyle(skybox).getPropertyValue('--cc-sbillboard-max-height'); const site_header = document.querySelector(".site-header"); const top = window.pageYOffset || document.documentElement.scrollTop; if ( parseInt(top) >= (parseInt(skybox_max_height) - parseInt(skybox_min_height)) ) { site_header.classList.add('fixed'); site_header.style.top = ( parseInt(skybox_min_height) + adminbar_offset) + 'px'; } else if ( site_header.classList.contains('fixed') ) { site_header.classList.remove('fixed'); site_header.style.top = (0 + adminbar_offset) + 'px'; } } // Realign header on skybox container height change var tr_skybox_obj = document.getElementById('nav-ad') || document.getElementById('nav-ad-plus-leader'); var skybox_observer = new MutationObserver(function(){ set_site_header_for_skybox_ads(); }); skybox_observer.observe(tr_skybox_obj, { attributes: true, childList: true, attributeFilter: ['style'] }); set_site_header_for_skybox_ads(); // -------- Members Forms -------------------------------------------------- // Members Preferences - Profile Basics var profile_basics_form = document.querySelector("form#profile-basics"); if ( profile_basics_form ) { // Form validation for social TOU. // If user starts typing in one of the social fields and the verify checkbox // is unchecked, require the verify checkbox and change its label to error red. var input_social_verify = profile_basics_form.querySelector("input#social-verify"); var label_social_verify = profile_basics_form.querySelector("label[for=\"social-verify\"]"); profile_basics_form.querySelectorAll(".social-group input") .forEach((input) => { input.addEventListener("input", (event) => { if ( ! input_social_verify.checked ) { input_social_verify.required = true; label_social_verify.classList.add('error-msg'); } }); }); } // Members Preferences - Contact Info var contact_info_form = document.querySelector("form#contact-info"); if ( contact_info_form ) { // If country does not equal US, hide state field. const country_element = contact_info_form.querySelector("select#country"); const state_element = contact_info_form.querySelector("select#state"); country_element.addEventListener("change", (event) => { if ( country_element.value !== 'US' ) { state_element.parentNode.style.display = 'none'; state_element.required = false; } else { state_element.parentNode.style.display = 'flex'; state_element.required = true; } }); // Dispatch change event to hide or show state based on country value. const change_event = new Event("change"); country_element.dispatchEvent(change_event); } // Members Profile - Contacts - Send Message to user var message_user_form = document.querySelector("form#message-user"); if ( message_user_form ) { // Message user - Character count. var message_user_textarea = message_user_form.querySelector("textarea"); if ( message_user_textarea ) { var message_user_char_count = document.querySelector("form#message-user .char-count"); message_user_char_count.style.display = 'block'; message_user_char_count = message_user_char_count.querySelector("span"); message_user_textarea.addEventListener("input", (event) => { message_user_char_count.innerHTML = 2500 - message_user_textarea.value.length; }); } ajax_members_form_submit_event_listener(message_user_form, 'member-send-message', members_profile_form.nonce, members_profile_form.ajax_url, 'Your message has been sent.'); } document.querySelectorAll("form.email-author-form") .forEach((form) => { ajax_members_form_submit_event_listener(form, 'email-author', email_author.nonce, email_author.ajax_url, 'Sent'); }); // Follow/unfolow members document.querySelectorAll("form.follow-member") .forEach((form) => { form.addEventListener("submit", async (event) => { event.preventDefault(); const submit_btn = form.querySelector('button'); const submit_btn_label = submit_btn.querySelector(".status"); const LABEL_DEFAULT = submit_btn_label.innerHTML; const LABEL_LOADING = 'ing...'; submit_btn.disabled = true; submit_btn_label.innerHTML = LABEL_DEFAULT + LABEL_LOADING; const body = new FormData(form); body.append("ajax", true); body.append("_ajax_nonce", members_profile_form.nonce); body.append('action', 'follow-member'); try { const response = await fetch(members_profile_form.ajax_url, {method: "POST", body}); const resp = await response.json(); if ( response.status == 200) { submit_btn_label.innerHTML = resp.next_action; } else { throw new Error('error occurred'); } } catch (err) { submit_btn_label.innerHTML = LABEL_DEFAULT; } finally { submit_btn.disabled = false; } }); }); // Block/unblock members document.querySelectorAll("form.block-member") .forEach((form) => { form.addEventListener("submit", async (event) => { event.preventDefault(); const submit_btn = form.querySelector('button'); const submit_btn_label = submit_btn.querySelector(".status"); const LABEL_DEFAULT = submit_btn_label.innerHTML; const LABEL_LOADING = 'ing...'; submit_btn.disabled = true; submit_btn_label.innerHTML = LABEL_DEFAULT + LABEL_LOADING; const body = new FormData(form); body.append("ajax", true); body.append("_ajax_nonce", members_profile_form.nonce); body.append('action', 'block-member'); try { const response = await fetch(members_profile_form.ajax_url, {method: "POST", body}); const resp = await response.json(); if ( response.status == 200) { submit_btn_label.innerHTML = resp.next_action; } else { throw new Error('error occurred'); } } catch (err) { submit_btn_label.innerHTML = LABEL_DEFAULT; } finally { submit_btn.disabled = false; } }); }); // ------------ Reusable ajax form submit function ------------------------------------ function ajax_members_form_submit_event_listener(form, action, nonce, ajax_url, save_msg) { form.addEventListener("submit", async (event) => { event.preventDefault(); var member_banner_element = document.querySelector(".content_members .banner"); if(member_banner_element) { member_banner_element.style.display = 'none'; } const submit_btns = form.querySelectorAll('input[type="submit"]'); const LABEL_DEFAULT = submit_btn.value; const LABEL_LOADING = 'Please Wait...'; submit_btns.forEach(btn => { btn.disabled = true; btn.value = LABEL_LOADING; }) const body = new FormData(form); body.append("ajax", true); body.append("_ajax_nonce", nonce); body.append('action', action); try { const response = await fetch(ajax_url, {method: "POST", body}); const resp = await response.json(); if ( response.status == 200 ) { if(member_banner_element) { member_banner_element.style.display = 'block'; member_banner_element.innerHTML = save_msg; member_banner_element.classList.remove('error'); window.scroll({top: 0, left: 0, behavior: 'smooth'}); } else { var msg = form.querySelector(".response-msg"); if (msg) { msg.style.display = 'block'; } } } else { throw new Error('error occurred'); } } catch (err) { var error_msg = 'Sorry, something went wrong. Please try again later.'; if(member_banner_element) { member_banner_element.style.display = 'block'; member_banner_element.innerHTML = error_msg; member_banner_element.classList.add('error'); window.scroll({top: 0, left: 0, behavior: 'smooth'}); } else { var msg = form.querySelector(".response-msg"); if(msg) { msg.style.display = 'block'; msg.innerHTML = error_msg; msg.classList.add('error'); } } } finally { submit_btn.value = LABEL_DEFAULT; submit_btn.disabled = false; } }); } // Show more profile forum posts. document.querySelectorAll("form.show_more_forum_posts") .forEach((form) => { var page = 1; // Hide forum if no posts. if ( document.querySelector('.community-member-posts ul li.no-posts') ) { form.style.display = 'none'; return; } form.addEventListener("submit", async (event) => { event.preventDefault(); const submit_btn = form.querySelector('button[type="submit"]'); submit_btn.disabled = true; const body = new FormData(form); body.append("ajax", true); body.append("_ajax_nonce", show_more_forum_posts.nonce); body.append('action', 'show-more-forum-posts'); body.append('page', page); page++; try { const response = await fetch(show_more_forum_posts.ajax_url, {method: "POST", body}); const html = await response.text(); if ( response.status == 200 ) { var ul = document.querySelector('.community-member-posts ul'); ul.innerHTML = ul.innerHTML + html; // Hide form if no posts. if ( !html ) { form.style.display = 'none'; } } else { throw new Error('error occurred'); } } catch (err) { var error_msg = 'Sorry, something went wrong. Please try again later.'; console.log(error_msg); } finally { submit_btn.disabled = false; } }); }); // -------- SOCIAL REGISTRATION ----------------------------- const social_registration_user_form = document.querySelector(".social-registration form#social_registration_user"); const social_registration_form = document.querySelector(".social-registration form#registerform"); var has_social_registration_finished = false; if (social_registration_form && social_registration_user_form) { social_registration_user_form.addEventListener("submit", async function(event) { event.preventDefault(); if ( ! has_social_registration_finished ) { return; } const body = new FormData(social_registration_user_form); body.append("ajax", true); body.append("_ajax_nonce", social_registration.nonce); body.append('action', 'social-registration'); const response = await fetch(social_registration.ajax_url, {method: "POST", body}); if ( response.status == 200 ) { window.location.href= social_registration.site_url; } else { var error_msg = 'Sorry, something went wrong. Please try again later.'; console.log(error_msg); alert(error_msg); } }); social_registration_form.addEventListener("submit", async function(event) { event.preventDefault(); const submit_btn = social_registration_form.querySelector('input[type="submit"]'); submit_btn.disabled = true; submit_btn.value = 'Please wait...'; const body = new FormData(social_registration_form); const response = await fetch(social_registration_form.getAttribute("action"), {method: "POST", body}); if ( response.status == 200 ) { has_social_registration_finished = true; const submit_event = new Event("submit"); social_registration_user_form.dispatchEvent(submit_event); } else { console.log('Social Login ajax failed'); alert('Something went wrong. Please try again later.'); } }); } document.cookie = 'advanced_ads_browser_width=; Max-Age=0'; function createSpinner() { const spinner = document .createElement('div') spinner.innerHTML = "
" return spinner } // -------------------------------------------------------------------- // --- Member Profile Contact Information Form ------------------------ // -------------------------------------------------------------------- document.querySelector(".page-template-page-members-preferences #contact-information #country")?.addEventListener("change", (e) => { let stateSelect = document.querySelector(".page-template-page-members-preferences #contact-information #state"); if (e.target.value != 'US') { stateSelect.required = false; stateSelect.value = ''; stateSelect.parentElement.style.display = 'none'; stateSelect.style.display = 'none'; } else { stateSelect.required = true; stateSelect.parentElement.style.display = ''; stateSelect.style.display = ''; } });