PageSourceSearch

https://alistapart.com/wp-content/plugins/jetpack/modules/subscrip…/subscribe-modal.js?ver=16.3-a.3

js alistapart.com collected 2026-09-24 06:47:08 UTC 3,822 bytes, 123 lines download raw bytes

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.