PageSourceSearch

https://epthinktank.eu/_static/??-eJyFzLEOgzAMBNAfampgoQwV35ImVgk4…/8pbZa7ouLiORIeNpzzux+nruuncXj9APOHPn4=

js epthinktank.eu collected 2026-10-01 09:12:05 UTC 20,765 bytes, 674 lines download raw bytes

1/* global subscriptionData */
2document.addEventListener( 'DOMContentLoaded', function () {
3	const modal = document.getElementsByClassName( 'jetpack-subscription-modal' )[ 0 ];
4
5	if ( ! modal ) {
6		return;
7	}
8
9	const close = document.getElementsByClassName( 'jetpack-subscription-modal__close' )[ 0 ];
10
11	let redirectUrl = '';
12	let hasLoaded = false;
13
14	function reloadOnCloseSubscriptionModal( customUrl ) {
15		const destinationUrl = customUrl ? new URL( customUrl ) : new URL( redirectUrl );
16
17		// Prevent redirect to external sites.
18		if ( destinationUrl.hostname !== window.location.hostname ) {
19			return;
20		}
21
22		try {
23			localStorage.setItem(
24				'jetpack-subscription-modal-on-comment-scroll-to',
25				destinationUrl.hash
26			);
27		} catch {
28			// Ok if we can't set it.
29		}
30
31		// Add cache-busting parameter
32		destinationUrl.searchParams.set( '_ctn', Date.now() );
33		window.location.href = destinationUrl.toString();
34	}
35
36	function JetpackSubscriptionModalOnCommentMessageListener( event ) {
37		let message = event && event.data;
38		if ( typeof message === 'string' ) {
39			try {
40				message = JSON.parse( message );
41			} catch {
42				return;
43			}
44		}
45
46		const type = message && message.type;
47		const data = message && message.data;
48
49		if ( type !== 'subscriptionModalShow' || typeof data.url === 'undefined' ) {
50			return;
51		}
52
53		if ( subscriptionData.homeUrl !== event.origin ) {
54			return;
55		}
56
57		if ( data.email ) {
58			const emailInput = document.querySelector(
59				'.jetpack-subscription-modal__modal-content input[type="email"]'
60			);
61			if ( ! emailInput ) {
62				reloadOnCloseSubscriptionModal( data.url );
63				return;
64			}
65
66			const appSource = document.querySelector(
67				'.jetpack-subscription-modal__modal-content input[name="app_source"]'
68			);
69			if ( ! appSource ) {
70				reloadOnCloseSubscriptionModal( data.url );
71				return;
72			}
73
74			emailInput.value = data.email;
75			if ( data.is_logged_in ) {
76				emailInput.setAttribute( 'readonly', 'readonly' );
77				appSource.value = 'atomic-subscription-modal-li';
78			}
79		}
80
81		if ( ! hasLoaded ) {
82			try {
83				const storedCount = parseInt(
84					sessionStorage.getItem( 'jetpack-subscription-modal-shown-count' )
85				);
86				const showCount = ( isNaN( storedCount ) ? 0 : storedCount ) + 1;
87				sessionStorage.setItem( 'jetpack-subscription-modal-shown-count', showCount );
88
89				if ( showCount > 5 ) {
90					new Image().src =
91						document.location.protocol +
92						'//pixel.wp.com/g.gif?v=wpcom-no-pv&x_jetpack-subscribe-modal-comm=hidden_views_limit&r=' +
93						Math.random();
94
95					reloadOnCloseSubscriptionModal( data.url );
96					return;
97				}
98			} catch {
99				// Ignore any errors.
100			}
101
102			new Image().src =
103				document.location.protocol +
104				'//pixel.wp.com/g.gif?v=wpcom-no-pv&x_jetpack-subscribe-modal-comm=showed&r=' +
105				Math.random();
106
107			modal.classList.toggle( 'open' );
108			hasLoaded = true;
109			redirectUrl = data.url;
110		}
111	}
112
113	window.addEventListener( 'message', JetpackSubscriptionModalOnCommentMessageListener );
114
115	if ( close ) {
116		close.onclick = function ( event ) {
117			event.preventDefault();
118			modal.classList.toggle( 'open' );
119			reloadOnCloseSubscriptionModal();
120		};
121	}
122
123	window.onclick = function ( event ) {
124		if ( event.target === modal ) {
125			modal.style.display = 'none';
126			reloadOnCloseSubscriptionModal();
127		}
128	};
129
130	window.addEventListener( 'load', () => {
131		// Scroll to the last comment.
132		const subscriptionScroll = localStorage.getItem(
133			'jetpack-subscription-modal-on-comment-scroll-to'
134		);
135
136		if ( subscriptionScroll ) {
137			window.location.hash = subscriptionScroll;
138			localStorage.removeItem( 'jetpack-subscription-modal-on-comment-scroll-to' );
139
140			const comment = document.querySelector( subscriptionScroll );
141			if ( comment ) {
142				comment.scrollIntoView( { block: 'center', behavior: 'smooth' } );
143			}
144		}
145	} );
146} );
147;
148/* global wpcom_reblog */
149
150var jetpackLikesWidgetBatch = [];
151var jetpackLikesMasterReady = false;
152
153// Due to performance problems on pages with a large number of widget iframes that need to be loaded,
154// we are limiting the processing at any instant to unloaded widgets that are currently in viewport,
155// plus this constant that will allow processing of widgets above and bellow the current fold.
156// This aim of it is to improve the UX and hide the transition from unloaded to loaded state from users.
157var jetpackLikesLookAhead = 2000; // pixels
158
159// Keeps track of loaded comment likes widget so we can unload them when they are scrolled out of view.
160var jetpackCommentLikesLoadedWidgets = [];
161
162var jetpackLikesDocReadyPromise = new Promise( resolve => {
163	if ( document.readyState !== 'loading' ) {
164		resolve();
165	} else {
166		window.addEventListener( 'DOMContentLoaded', () => resolve() );
167	}
168} );
169
170function JetpackLikesPostMessage( message, target ) {
171	if ( typeof message === 'string' ) {
172		try {
173			message = JSON.parse( message );
174		} catch {
175			return;
176		}
177	}
178
179	if ( target && typeof target.postMessage === 'function' ) {
180		try {
181			target.postMessage(
182				JSON.stringify( {
183					type: 'likesMessage',
184					data: message,
185				} ),
186				'*'
187			);
188		} catch {
189			// Ignore error
190		}
191	}
192}
193
194function JetpackLikesBatchHandler() {
195	const requests = [];
196	document.querySelectorAll( 'div.jetpack-likes-widget-unloaded' ).forEach( widget => {
197		if ( jetpackLikesWidgetBatch.indexOf( widget.id ) > -1 ) {
198			return;
199		}
200
201		if ( ! jetpackIsScrolledIntoView( widget ) ) {
202			return;
203		}
204
205		jetpackLikesWidgetBatch.push( widget.id );
206
207		var regex = /like-(post|comment)-wrapper-(\d+)-(\d+)-(\w+)/,
208			match = regex.exec( widget.id ),
209			info;
210
211		if ( ! match || match.length !== 5 ) {
212			return;
213		}
214
215		info = {
216			blog_id: match[ 2 ],
217			width: widget.width,
218		};
219
220		if ( 'post' === match[ 1 ] ) {
221			info.post_id = match[ 3 ];
222		} else if ( 'comment' === match[ 1 ] ) {
223			info.comment_id = match[ 3 ];
224		}
225
226		info.obj_id = match[ 4 ];
227
228		requests.push( info );
229	} );
230
231	if ( requests.length > 0 ) {
232		JetpackLikesPostMessage(
233			{ event: 'initialBatch', requests: requests },
234			window.frames[ 'likes-master' ]
235		);
236	}
237}
238
239function JetpackLikesMessageListener( event ) {
240	let message = event && event.data;
241	if ( typeof message === 'string' ) {
242		try {
243			message = JSON.parse( message );
244		} catch {
245			return;
246		}
247	}
248
249	const type = message && message.type;
250	const data = message && message.data;
251
252	if ( type !== 'likesMessage' || typeof data.event === 'undefined' ) {
253		return;
254	}
255
256	// We only allow messages from one origin
257	const allowedOrigin = 'https://widgets.wp.com';
258	if ( allowedOrigin !== event.origin ) {
259		return;
260	}
261
262	switch ( data.event ) {
263		case 'masterReady':
264			jetpackLikesDocReadyPromise.then( () => {
265				jetpackLikesMasterReady = true;
266
267				const stylesData = {
268					event: 'injectStyles',
269				};
270				const sdTextColor = document.querySelector( '.sd-text-color' );
271				const sdLinkColor = document.querySelector( '.sd-link-color' );
272				const sdTextColorStyles = ( sdTextColor && getComputedStyle( sdTextColor ) ) || {};
273				const sdLinkColorStyles = ( sdLinkColor && getComputedStyle( sdLinkColor ) ) || {};
274
275				// enable reblogs if we're on a single post page
276				if ( document.body.classList.contains( 'single' ) ) {
277					JetpackLikesPostMessage( { event: 'reblogsEnabled' }, window.frames[ 'likes-master' ] );
278				}
279
280				stylesData.textStyles = {
281					color: sdTextColorStyles.color,
282					fontFamily: sdTextColorStyles[ 'font-family' ],
283					fontSize: sdTextColorStyles[ 'font-size' ],
284					direction: sdTextColorStyles.direction,
285					fontWeight: sdTextColorStyles[ 'font-weight' ],
286					fontStyle: sdTextColorStyles[ 'font-style' ],
287					textDecoration: sdTextColorStyles[ 'text-decoration' ],
288				};
289
290				stylesData.linkStyles = {
291					color: sdLinkColorStyles.color,
292					fontFamily: sdLinkColorStyles[ 'font-family' ],
293					fontSize: sdLinkColorStyles[ 'font-size' ],
294					textDecoration: sdLinkColorStyles[ 'text-decoration' ],
295					fontWeight: sdLinkColorStyles[ 'font-weight' ],
296					fontStyle: sdLinkColorStyles[ 'font-style' ],
297				};
298
299				JetpackLikesPostMessage( stylesData, window.frames[ 'likes-master' ] );
300
301				JetpackLikesBatchHandler();
302			} );
303
304			break;
305
306		// We're keeping this for planned future follow ups.
307		// @see: https://github.com/Automattic/jetpack/pull/42361#discussion_r1995338815
308		case 'showLikeWidget':
309			break;
310
311		// We're keeping this for planned future follow ups.
312		// @see: https://github.com/Automattic/jetpack/pull/42361#discussion_r1995338815
313		case 'showCommentLikeWidget':
314			break;
315
316		case 'killCommentLikes':
317			// If kill switch for comment likes is enabled remove all widgets wrappers and `Loading...` placeholders.
318			document
319				.querySelectorAll( '.jetpack-comment-likes-widget-wrapper' )
320				.forEach( wrapper => wrapper.remove() );
321			break;
322
323		case 'clickReblogFlair':
324			if ( wpcom_reblog && typeof wpcom_reblog.toggle_reblog_box_flair === 'function' ) {
325				wpcom_reblog.toggle_reblog_box_flair( data.obj_id );
326			}
327			break;
328
329		case 'hideOtherGravatars': {
330			hideLikersPopover();
331			break;
332		}
333
334		case 'showOtherGravatars': {
335			const container = document.querySelector( '#likes-other-gravatars' );
336
337			if ( ! container ) {
338				break;
339			}
340
341			const list = container.querySelector( 'ul' );
342
343			container.style.display = 'none';
344			list.innerHTML = '';
345
346			container
347				.querySelectorAll( '.likes-text span' )
348				.forEach( item => ( item.textContent = data.totalLikesLabel ) );
349
350			( data.likers || [] ).forEach( async ( liker, index ) => {
351				if ( liker.profile_URL.substr( 0, 4 ) !== 'http' ) {
352					// We only display gravatars with http or https schema
353					return;
354				}
355
356				const element = document.createElement( 'li' );
357				list.append( element );
358
359				const profileLink = encodeURI( liker.profile_URL );
360				const avatarLink = encodeURI( liker.avatar_URL );
361				element.innerHTML = `<a href="${ profileLink }" rel="nofollow" target="_parent" class="wpl-liker">
362						<img src="${ avatarLink }"
363							alt=""
364							style="width: 28px; height: 28px;" />
365						<span></span>
366					</a>`;
367
368				// Add some extra attributes through native methods, to ensure strings are sanitized.
369				element.classList.add( liker.css_class );
370				element.querySelector( 'img' ).alt = data.avatarAltTitle.replace( '%s', liker.name );
371				element.querySelector( 'span' ).innerText = liker.name;
372
373				if ( index === data.likers.length - 1 ) {
374					element.addEventListener( 'keydown', e => {
375						if ( e.key === 'Tab' && ! e.shiftKey ) {
376							e.preventDefault();
377							hideLikersPopover();
378
379							JetpackLikesPostMessage(
380								{ event: 'focusLikesCount', parent: data.parent },
381								window.frames[ 'likes-master' ]
382							);
383						}
384					} );
385				}
386			} );
387
388			const positionPopup = function () {
389				const containerStyle = getComputedStyle( container );
390				const isRtl = containerStyle.direction === 'rtl';
391
392				const el = document.querySelector( `*[name='${ data.parent }']` );
393				const rect = el.getBoundingClientRect();
394				const win = el.ownerDocument.defaultView;
395				const offset = {
396					top: rect.top + win.pageYOffset,
397					left: rect.left + win.pageXOffset,
398				};
399
400				let containerLeft;
401				container.style.top = offset.top + data.position.top - 1 + 'px';
402
403				if ( isRtl ) {
404					const visibleAvatarsCount = data && data.likers ? Math.min( data.likers.length, 5 ) : 0;
405					// 24px is the width of the avatar + 4px is the padding between avatars
406					containerLeft = offset.left + data.position.left + 24 * visibleAvatarsCount + 4;
407					container.style.transform = 'translateX(-100%)';
408				} else {
409					containerLeft = offset.left + data.position.left;
410				}
411				container.style.left = containerLeft + 'px';
412
413				// If the popup overflows viewport width, we should show it on the next line.
414				// Push it offscreen to calculated rendered width.
415				container.style.left = '-9999px';
416				container.style.display = 'block';
417
418				// If the popup exceeds the viewport width,
419				// flip the position of the popup.
420				const containerWidth = container.offsetWidth;
421				const containerRight = containerLeft + containerWidth;
422				if ( containerRight > win.innerWidth ) {
423					containerLeft = rect.right - containerWidth;
424				}
425
426				// Set the container left
427				container.style.left = containerLeft + 'px';
428				container.setAttribute( 'aria-hidden', 'false' );
429			};
430
431			positionPopup();
432			container.focus();
433
434			const debounce = function ( func, wait ) {
435				var timeout;
436				return function () {
437					var context = this;
438					var args = arguments;
439					clearTimeout( timeout );
440					timeout = setTimeout( function () {
441						func.apply( context, args );
442					}, wait );
443				};
444			};
445
446			const debouncedPositionPopup = debounce( positionPopup, 100 );
447
448			// Keep a reference of this function in the element itself
449			// so that we can destroy it later
450			container.__resizeHandler = debouncedPositionPopup;
451
452			// When window is resized, resize the popup.
453			window.addEventListener( 'resize', debouncedPositionPopup );
454
455			container.focus();
456		}
457	}
458}
459
460window.addEventListener( 'message', JetpackLikesMessageListener );
461
462function hideLikersPopover() {
463	const container = document.querySelector( '#likes-other-gravatars' );
464
465	if ( container ) {
466		container.style.display = 'none';
467		container.setAttribute( 'aria-hidden', 'true' );
468
469		// Remove the resize event listener and cleanup.
470		const resizeHandler = container.__resizeHandler;
471		if ( resizeHandler ) {
472			window.removeEventListener( 'resize', resizeHandler );
473			delete container.__resizeHandler;
474		}
475	}
476}
477
478document.addEventListener( 'click', hideLikersPopover );
479
480function JetpackLikesWidgetQueueHandler() {
481	var wrapperID;
482
483	if ( ! jetpackLikesMasterReady ) {
484		// The master iframe emits `masterReady` a single time, when it finishes loading. On
485		// script-heavy pages it can finish loading — and emit — before this script attaches its
486		// message listener above, so that one event is missed and the queue never starts. Ping the
487		// master iframe while we wait so it re-emits `masterReady` once both it and our listener
488		// are ready.
489		JetpackLikesPostMessage( { event: 'queryMasterReady' }, window.frames[ 'likes-master' ] );
490		setTimeout( JetpackLikesWidgetQueueHandler, 500 );
491		return;
492	}
493
494	// Restore widgets to initial unloaded state when they are scrolled out of view.
495	jetpackUnloadScrolledOutWidgets();
496
497	jetpackObserveUnloadedWidgets();
498
499	var unloadedWidgetsInView = jetpackGetUnloadedWidgetsInView();
500
501	if ( unloadedWidgetsInView.length > 0 ) {
502		// Grab any unloaded widgets for a batch request
503		JetpackLikesBatchHandler();
504	}
505
506	for ( var i = 0, length = unloadedWidgetsInView.length; i <= length - 1; i++ ) {
507		wrapperID = unloadedWidgetsInView[ i ].id;
508
509		if ( ! wrapperID ) {
510			continue;
511		}
512
513		jetpackLoadLikeWidgetIframe( wrapperID );
514	}
515}
516
517function jetpackLoadLikeWidgetIframe( wrapperID ) {
518	if ( typeof wrapperID === 'undefined' ) {
519		return;
520	}
521
522	const wrapper = document.querySelector( '#' + wrapperID );
523	wrapper.querySelectorAll( 'iframe' ).forEach( iFrame => iFrame.remove() );
524
525	const placeholder = wrapper.querySelector( '.likes-widget-placeholder' );
526
527	// Post like iframe
528	if ( placeholder && placeholder.classList.contains( 'post-likes-widget-placeholder' ) ) {
529		const postLikesFrame = document.createElement( 'iframe' );
530
531		postLikesFrame.classList.add( 'post-likes-widget', 'jetpack-likes-widget' );
532		postLikesFrame.name = wrapper.dataset.name;
533		postLikesFrame.src = wrapper.dataset.src;
534		postLikesFrame.height = '55px';
535		postLikesFrame.width = '100%';
536		postLikesFrame.frameBorder = '0';
537		postLikesFrame.scrolling = 'no';
538		postLikesFrame.title = wrapper.dataset.title;
539
540		placeholder.after( postLikesFrame );
541	}
542
543	// Comment like iframe
544	if ( placeholder.classList.contains( 'comment-likes-widget-placeholder' ) ) {
545		const commentLikesFrame = document.createElement( 'iframe' );
546
547		commentLikesFrame.class = 'comment-likes-widget-frame jetpack-likes-widget-frame';
548		commentLikesFrame.name = wrapper.dataset.name;
549		commentLikesFrame.src = wrapper.dataset.src;
550		commentLikesFrame.height = '18px';
551		commentLikesFrame.width = '100%';
552		commentLikesFrame.frameBorder = '0';
553		commentLikesFrame.scrolling = 'no';
554
555		wrapper.querySelector( '.comment-like-feedback' ).after( commentLikesFrame );
556
557		jetpackCommentLikesLoadedWidgets.push( commentLikesFrame );
558	}
559
560	wrapper.classList.remove( 'jetpack-likes-widget-unloaded' );
561	wrapper.classList.add( 'jetpack-likes-widget-loading' );
562
563	wrapper.querySelector( 'iframe' ).addEventListener( 'load', e => {
564		// A widget scrolled out of view mid-load has its iframe dropped, and a reloaded one
565		// replaces it, either of which leaves this closure holding a detached iframe. Acting on
566		// it would hide a placeholder that is now the only thing the widget has left to show.
567		if ( ! wrapper.contains( e.target ) ) {
568			return;
569		}
570
571		JetpackLikesPostMessage(
572			{ event: 'loadLikeWidget', name: e.target.name, width: e.target.width },
573			window.frames[ 'likes-master' ]
574		);
575
576		// The stylesheet is otherwise the only thing that hides the placeholder, so one that never
577		// applies leaves "Loading…" sitting over a widget that loaded fine.
578		if ( placeholder ) {
579			placeholder.style.display = 'none';
580		}
581
582		wrapper.classList.remove( 'jetpack-likes-widget-loading' );
583		wrapper.classList.add( 'jetpack-likes-widget-loaded' );
584	} );
585}
586
587function jetpackGetUnloadedWidgetsInView() {
588	const unloadedWidgets = document.querySelectorAll( 'div.jetpack-likes-widget-unloaded' );
589
590	return [ ...unloadedWidgets ].filter( item => jetpackIsScrolledIntoView( item ) );
591}
592
593function jetpackIsScrolledIntoView( element ) {
594	const top = element.getBoundingClientRect().top;
595	const bottom = element.getBoundingClientRect().bottom;
596
597	// Allow some slack above and bellow the fold with jetpackLikesLookAhead,
598	// with the aim of hiding the transition from unloaded to loaded widget from users.
599	return top + jetpackLikesLookAhead >= 0 && bottom <= window.innerHeight + jetpackLikesLookAhead;
600}
601
602function jetpackUnloadScrolledOutWidgets() {
603	for ( let i = jetpackCommentLikesLoadedWidgets.length - 1; i >= 0; i-- ) {
604		const currentWidgetIframe = jetpackCommentLikesLoadedWidgets[ i ];
605
606		if ( ! jetpackIsScrolledIntoView( currentWidgetIframe ) ) {
607			const widgetWrapper =
608				currentWidgetIframe &&
609				currentWidgetIframe.parentElement &&
610				currentWidgetIframe.parentElement.parentElement;
611
612			// Restore parent class to 'unloaded' so this widget can be picked up by queue manager again if needed.
613			widgetWrapper.classList.remove( 'jetpack-likes-widget-loaded' );
614			widgetWrapper.classList.remove( 'jetpack-likes-widget-loading' );
615			widgetWrapper.classList.add( 'jetpack-likes-widget-unloaded' );
616
617			// An empty string removes the inline declaration rather than setting one, handing the
618			// placeholder back to the stylesheet. The `display: none` set on load would otherwise
619			// outrank it, leaving an unloaded widget with neither an iframe nor a placeholder.
620			const placeholder = widgetWrapper.querySelector( '.likes-widget-placeholder' );
621			if ( placeholder ) {
622				placeholder.style.display = '';
623			}
624
625			// Remove it from the list of loaded widgets.
626			jetpackCommentLikesLoadedWidgets.splice( i, 1 );
627
628			// Remove comment like widget iFrame.
629			currentWidgetIframe.remove();
630		}
631	}
632}
633
634var jetpackWidgetsDelayedExec = function ( after, fn ) {
635	var timer;
636	return function () {
637		clearTimeout( timer );
638		timer = setTimeout( fn, after );
639	};
640};
641
642var jetpackOnScrollStopped = jetpackWidgetsDelayedExec( 250, JetpackLikesWidgetQueueHandler );
643
644// Scrolling is not the only thing that brings a widget into range. A stylesheet that lands late
645// reflows the page without firing a scroll event, and the queue would never look at that widget
646// again, leaving it on "Loading…" until the reader happens to scroll.
647var jetpackLikesWidgetObserver =
648	typeof IntersectionObserver === 'function'
649		? new IntersectionObserver( jetpackOnScrollStopped, {
650				rootMargin: `${ jetpackLikesLookAhead }px`,
651				// jetpackIsScrolledIntoView() wants the widget fully inside the band, so ask to be
652				// told when it gets there - crossing into partial overlap alone would not load it.
653				threshold: [ 0, 1 ],
654			} )
655		: null;
656
657// Observing an element twice is a no-op, so every queue pass can call this to pick up widgets
658// added after load.
659function jetpackObserveUnloadedWidgets() {
660	if ( ! jetpackLikesWidgetObserver ) {
661		return;
662	}
663
664	document
665		.querySelectorAll( 'div.jetpack-likes-widget-unloaded' )
666		.forEach( widget => jetpackLikesWidgetObserver.observe( widget ) );
667}
668
669// Load initial batch of widgets, prior to any scrolling events.
670JetpackLikesWidgetQueueHandler();
671
672// Add event listener to execute queue handler after scroll.
673window.addEventListener( 'scroll', jetpackOnScrollStopped, true );
674;

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.