1/* global Jetpack_Subscriptions */ 2const { domReady } = wp; 3domReady( () => { 4 const modal = document.querySelector( '.jetpack-subscribe-modal' ); 5 const modalDismissedCookie = 'jetpack_post_subscribe_modal_dismissed'; 6 const skipUrlParam = 'jetpack_skip_subscription_popup'; 7 8 function hasEnoughTimePassed() { 9 const lastDismissed = localStorage.getItem( modalDismissedCookie ); 10 return lastDismissed ? Date.now() - lastDismissed > Jetpack_Subscriptions.modalInterval : true; 11 } 12 13 // Subscriber ended up here e.g. from emails: 14 // we won't show the modal to them in future since they most likely are already a subscriber. 15 function skipModal() { 16 const url = new URL( window.location.href ); 17 if ( url.searchParams.has( skipUrlParam ) ) { 18 url.searchParams.delete( skipUrlParam ); 19 window.history.replaceState( {}, '', url ); 20 storeCloseTimestamp(); 21 return true; 22 } 23 24 return false; 25 } 26 27 if ( ! modal || ! hasEnoughTimePassed() || skipModal() ) { 28 return; 29 } 30 31 const modalLoadTimeout = setTimeout( openModal, Jetpack_Subscriptions.modalLoadTime ); 32 33 const targetElement = ( 34 document.querySelector( '.entry-content' ) || document.documentElement 35 ).getBoundingClientRect(); 36 37 function hasPassedScrollThreshold() { 38 const scrollPosition = window.scrollY + window.innerHeight / 2; 39 const scrollPositionThreshold = 40 targetElement.top + 41 ( targetElement.height * Jetpack_Subscriptions.modalScrollThreshold ) / 100; 42 return scrollPosition > scrollPositionThreshold; 43 } 44 45 function onScroll() { 46 requestAnimationFrame( () => { 47 if ( hasPassedScrollThreshold() ) { 48 openModal(); 49 } 50 } ); 51 } 52 53 window.addEventListener( 'scroll', onScroll, { passive: true } ); 54 55 // This take care of the case where the user has multiple tabs open. 56 function onLocalStorage( event ) { 57 if ( event.key === modalDismissedCookie ) { 58 closeModal(); 59 removeEventListeners(); 60 } 61 } 62 window.addEventListener( 'storage', onLocalStorage ); 63 64 // When the form is submitted, and next modal loads, it'll fire "subscription-modal-loaded" signalling that this form can be hidden. 65 const form = modal.querySelector( 'form' ); 66 if ( form ) { 67 form.addEventListener( 'subscription-modal-loaded', closeModal ); 68 } 69 70 // User can edit modal, and could remove close link. 71 function onCloseButtonClick( event ) { 72 event.preventDefault(); 73 closeModal(); 74 } 75 const close = document.getElementsByClassName( 'jetpack-subscribe-modal__close' )[ 0 ]; 76 if ( close ) { 77 close.addEventListener( 'click', onCloseButtonClick ); 78 } 79 80 function closeOnWindowClick( event ) { 81 if ( event.target === modal ) { 82 closeModal(); 83 } 84 } 85 86 function closeModalOnEscapeKeydown( event ) { 87 if ( event.key === 'Escape' ) { 88 closeModal(); 89 } 90 } 91 92 function openModal() { 93 // If the user is typing in a form, don't open the modal or has anything else focused. 94 if ( document.activeElement && document.activeElement.tagName !== 'BODY' ) { 95 return; 96 } 97 98 modal.classList.add( 'open' ); 99 document.body.classList.add( 'jetpack-subscribe-modal-open' ); 100 window.addEventListener( 'keydown', closeModalOnEscapeKeydown ); 101 window.addEventListener( 'click', closeOnWindowClick ); 102 removeEventListeners(); 103 } 104 105 function closeModal() { 106 modal.classList.remove( 'open' ); 107 document.body.classList.remove( 'jetpack-subscribe-modal-open' ); 108 window.removeEventListener( 'keydown', closeModalOnEscapeKeydown ); 109 window.removeEventListener( 'storage', onLocalStorage ); 110 window.removeEventListener( 'click', closeOnWindowClick ); 111 storeCloseTimestamp(); 112 } 113 114 // Remove all event listeners. That would add the modal again. 115 function removeEventListeners() { 116 window.removeEventListener( 'scroll', onScroll ); 117 clearTimeout( modalLoadTimeout ); 118 } 119 120 function storeCloseTimestamp() { 121 localStorage.setItem( modalDismissedCookie, Date.now() ); 122 } 123} );
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.