PageSourceSearch

https://www.seesaw-hair.com/wp-content/themes/seesaw2025/common/scripts/modules/page.js

js seesaw-hair.com collected 2026-09-25 19:11:18 UTC 22,419 bytes, 891 lines download raw bytes

1import { shaderWipe, shaderLoop } from '../modules/shader.js';
2
3const mediaQuerySp = window.matchMedia(
4	'screen and (orientation: portrait) and (max-width: 767px)'
5);
6const mediaQueryPc = window.matchMedia(
7	'screen and (orientation: landscape) and (max-width: 767px), screen and (min-width: 768px)'
8);
9
10function isTouchDevice() {
11	return 'ontouchstart' in window || navigator.maxTouchPoints;
12}
13
14function lineUpHover( baseClass ) {
15	if ( ! isTouchDevice() ) {
16		const buttons = document.querySelector(
17			`.${ baseClass }__line-up__links__grid`
18		);
19		const items = document.querySelectorAll(
20			`.${ baseClass }__line-up__links__grid__block`
21		);
22		const itemForAll = document.querySelector(
23			`.${ baseClass }__line-up__images__image[image-id="all"]`
24		);
25
26		let images = document.querySelectorAll(
27			`.${ baseClass }__line-up__images__image`
28		);
29
30		// タイマーを格納するオブジェクトを用意
31		const resetTimers = {};
32
33		images.forEach( ( image ) => {
34			image.classList.add( 'canZoomReset' );
35		} );
36
37		items.forEach( ( item ) => {
38			item.addEventListener( 'mouseenter', function () {
39				const targetImageId = this.getAttribute( 'target-image-id' );
40				const imageToActivate = document.querySelector(
41					`.${ baseClass }__line-up__images__image[image-id="${ targetImageId }"]`
42				);
43				if ( ! targetImageId || ! imageToActivate ) return;
44
45				if (
46					! imageToActivate.classList.contains( 'active' ) /*&&
47					imageToActivate.classList.contains( 'canZoomReset' )*/
48				) {
49					//imageToActivate.classList.remove( 'zoom' );
50					/*imageToActivate.classList.remove( 'canZoomReset' );*/
51				}
52
53				requestAnimationFrame( () => {
54					images.forEach( ( image ) => {
55						image.classList.remove( 'actived' );
56						if ( image.classList.contains( 'active' ) ) {
57							image.classList.remove( 'zoom' );
58							image.classList.remove( 'active' );
59							image.classList.add( 'actived' );
60						}
61					} );
62
63					imageToActivate.classList.add( 'active' );
64					imageToActivate.classList.add( 'zoom' );
65
66					// 既存のタイマーをクリア
67					if ( resetTimers[ targetImageId ] ) {
68						clearTimeout( resetTimers[ targetImageId ] );
69					}
70
71					// 新しいタイマーを設定
72					resetTimers[ targetImageId ] = setTimeout( function () {
73						/*imageToActivate.classList.add( 'canZoomReset' );*/
74						delete resetTimers[ targetImageId ];
75					}, 2000 );
76				} );
77			} );
78		} );
79
80		if ( ! buttons ) return;
81
82		buttons.addEventListener( 'mouseleave', function () {
83			const imageToActivate = itemForAll;
84			if ( ! imageToActivate ) return;
85
86			if (
87				! imageToActivate.classList.contains( 'active' ) /*&&
88				imageToActivate.classList.contains( 'canZoomReset' )*/
89			) {
90				//imageToActivate.classList.remove( 'zoom' );
91				//imageToActivate.classList.remove( 'canZoomReset' );
92			}
93
94			requestAnimationFrame( () => {
95				images.forEach( ( image ) => {
96					image.classList.remove( 'actived' );
97					if ( image.classList.contains( 'active' ) ) {
98						image.classList.remove( 'zoom' );
99						image.classList.remove( 'active' );
100						image.classList.add( 'actived' );
101					}
102				} );
103
104				imageToActivate.classList.add( 'active' );
105				imageToActivate.classList.add( 'zoom' );
106
107				const allImageId = 'all';
108
109				// 既存のタイマーをクリア
110				if ( resetTimers[ allImageId ] ) {
111					clearTimeout( resetTimers[ allImageId ] );
112				}
113
114				// 新しいタイマーを設定
115				resetTimers[ allImageId ] = setTimeout( function () {
116					/*imageToActivate.classList.add( 'canZoomReset' );*/
117					delete resetTimers[ allImageId ];
118				}, 2000 );
119			} );
120		} );
121	}
122}
123
124export function top() {
125	const windowHeight = window.innerHeight;
126
127	/* リンクバナー BOF */
128	// `.close` 要素を取得
129	const closeButton = document.querySelector(
130		'.fv-links__salon-search .close'
131	);
132
133	document.querySelector( 'main' ).classList.add( 'banner-active' );
134
135	// クリックイベントリスナーを追加
136	closeButton.addEventListener( 'click', function ( event ) {
137		event.preventDefault(); // デフォルトの動作を防ぐ
138
139		// 親要素(リンク)の `.active` クラスを削除
140		const parentLink = closeButton.parentElement;
141		parentLink.classList.remove( 'active' );
142		document.querySelector( 'main' ).classList.remove( 'banner-active' );
143	} );
144	/* リンクバナー EOF */
145
146	/* gallery BOF */
147	const toGalleryText = new Swiper( '.top__to-gallery__hover-text', {
148		loop: true,
149		slidesPerView: 'auto',
150		speed: 4000,
151		allowTouchMove: false,
152		autoplay: {
153			delay: 0,
154		},
155	} );
156
157	toGalleryText.autoplay.stop(); //デフォルトでautoplayを停止
158
159	function galleryStakerInit() {
160		let onMouseMove = false;
161		let lastMousePosition = { x: 0, y: 0 };
162
163		function updateMousePosition( event ) {
164			onMouseMove = true;
165
166			lastMousePosition.x = event.clientX;
167			lastMousePosition.y = event.clientY;
168
169			onMouseMove = false;
170		}
171
172		document.addEventListener( 'mousemove', updateMousePosition );
173
174		const container = document.querySelector( '.top__to-gallery' );
175		const hoverText = document.querySelector(
176			'.top__to-gallery__hover-text'
177		);
178
179		window.addEventListener( 'scroll', ( e ) => {
180			const scrollPosition = window.scrollY; // pageYOffsetの代わりにscrollYを使用
181
182			if ( scrollPosition >= windowHeight ) {
183				if ( ! onMouseMove ) {
184					const rect = container.getBoundingClientRect();
185
186					const mousePos = {
187						x: 0,
188						y: lastMousePosition.y - rect.top,
189					};
190
191					gsap.to( hoverText, {
192						duration: 0.6,
193						ease: 'power2.out',
194						x: mousePos.x,
195						y: mousePos.y,
196					} );
197				}
198			}
199		} );
200
201		container.addEventListener( 'mousemove', ( e ) => {
202			onMouseMove = true;
203
204			const rect = container.getBoundingClientRect();
205
206			const mousePos = {
207				x: 0,
208				y: e.clientY - rect.top,
209			};
210
211			gsap.to( hoverText, {
212				duration: 0.6,
213				ease: 'power2.out',
214				x: mousePos.x,
215				y: mousePos.y,
216			} );
217
218			onMouseMove = false;
219		} );
220	}
221
222	if ( mediaQueryPc.matches ) {
223		galleryStakerInit();
224	}
225
226	/* gallery EOF */
227
228	/* Feature BOF */
229	const featureSlider = new Swiper(
230		'.top__feature__categories__pickups__slider',
231		{
232			loop: true,
233			autoplay: {
234				delay: 3500, //デフォルトの表示時間を指定
235			},
236			speed: 1000,
237			pagination: {
238				el: '.swiper-pagination',
239				type: 'fraction',
240			},
241			effect: 'fade',
242			navigation: {
243				nextEl: '.swiper-button-next',
244				prevEl: '.swiper-button-prev',
245			},
246		}
247	);
248
249	if ( featureSlider.slides.length <= 1 ) {
250		document
251			.querySelector( '.top__feature__categories__pickups__slider' )
252			.classList.add( 'single-slide' );
253	}
254
255	featureSlider.slideNext();
256	setTimeout( () => {
257		featureSlider.slideNext(); //クラス付与を強制
258	}, 2000 );
259
260	featureSlider.autoplay.stop(); //デフォルトでautoplayを停止
261
262	/* Feature EOF */
263
264	/* TOギャラリーのfixed表示トリガー */
265	window.addEventListener( 'scroll', function () {
266		const targetElement = document.querySelector( '.top__to-gallery' );
267		const scrollPosition = window.scrollY; // pageYOffsetの代わりにscrollYを使用
268
269		// スクロール位置が画面の高さ以上の場合にクラスを追加
270		if ( scrollPosition >= windowHeight ) {
271			targetElement.classList.add( 'active' );
272			if ( ! toGalleryText.autoplay.running ) {
273				toGalleryText.autoplay.start();
274			}
275			if ( ! featureSlider.autoplay.running ) {
276				featureSlider.autoplay.start();
277			}
278		} else {
279			targetElement.classList.remove( 'active' );
280			if ( toGalleryText.autoplay.running ) {
281				toGalleryText.autoplay.stop();
282			}
283			if ( featureSlider.autoplay.running ) {
284				featureSlider.autoplay.stop();
285			}
286		}
287	} );
288
289	/* line up EOF */
290	//lineUpHover( 'top' );
291	/* line up BOF */
292}
293
294export function about() {
295	//lineUpHover( 'about' );
296
297	/* TOギャラリーのfixed表示トリガー */
298	const overlayElement = document.querySelector( '.about__kv' );
299	const target = document.querySelector( '.about__whats' );
300
301	// スクロールイベントのリスナーを設定
302	/*
303	window.addEventListener( 'scroll', () => {
304		// 要素の位置を取得
305		const overlayRect = overlayElement.getBoundingClientRect();
306
307		// 画面上端を通過したかどうか確認
308		if ( overlayRect.top < 0 ) {
309			target.classList.add( 'active' );
310		} else {
311			target.classList.remove( 'active' );
312		}
313	} );*/
314
315	//modal
316	MicroModal.init( {
317		awaitCloseAnimation: true,
318		awaitOpenAnimation: true,
319		disableScroll: true,
320	} );
321}
322
323export function lineUp() {
324	//how to use
325	const tabs = document.querySelectorAll(
326		'.hair-care__how-to-use__descriptions__tab'
327	);
328
329	const firstTabTextSection = tabs[ 0 ].querySelector(
330		'.hair-care__how-to-use__descriptions__tab__texts'
331	);
332	firstTabTextSection.style.maxHeight = `${ firstTabTextSection.scrollHeight }px`;
333
334	tabs.forEach( ( tab ) => {
335		const toggle = tab.querySelector(
336			'.hair-care__how-to-use__descriptions__tab__headings'
337		);
338
339		toggle.addEventListener( 'click', function () {
340			tab.classList.toggle( 'active' );
341
342			//開閉の単一性はPCのみ
343			if ( ! mediaQuerySp.matches ) {
344				tabs.forEach( ( otherTab ) => {
345					if ( otherTab !== tab ) {
346						otherTab.classList.remove( 'active' );
347						otherTab.querySelector(
348							'.hair-care__how-to-use__descriptions__tab__texts'
349						).style.maxHeight = 0;
350					}
351				} );
352			}
353
354			const textSection = tab.querySelector(
355				'.hair-care__how-to-use__descriptions__tab__texts'
356			);
357			if ( tab.classList.contains( 'active' ) ) {
358				textSection.style.maxHeight = textSection.scrollHeight + 'px';
359			} else {
360				textSection.style.maxHeight = 0;
361			}
362		} );
363	} );
364
365	//fragrance
366	/*
367	const triggers = document.querySelectorAll( '.image-trigger' );
368	triggers.forEach( ( trigger ) => {
369		ScrollTrigger.create( {
370			trigger: trigger,
371			start: 'top 60%',
372			end: 'bottom 60%',
373			//markers: true,
374			onEnter: ( self ) => {
375				const images = document.querySelectorAll(
376					'.hair-care__tech-fragrance__images__image'
377				);
378				images.forEach( ( image ) => {
379					image.classList.remove( 'active' );
380				} );
381				const id = trigger.getAttribute( 'data-target' );
382				const targetImage = document.querySelector(
383					`.hair-care__tech-fragrance__images__image[image-id="${ id }"]`
384				);
385				if ( targetImage ) {
386					targetImage.classList.add( 'active' );
387				}
388			},
389			onEnterBack: ( self ) => {
390				const images = document.querySelectorAll(
391					'.hair-care__tech-fragrance__images__image'
392				);
393				images.forEach( ( image ) => {
394					image.classList.remove( 'active' );
395				} );
396				const id = trigger.getAttribute( 'data-target' );
397				const targetImage = document.querySelector(
398					`.hair-care__tech-fragrance__images__image[image-id="${ id }"]`
399				);
400				if ( targetImage ) {
401					targetImage.classList.add( 'active' );
402				}
403			},
404			onLeaveBack: ( self ) => {},
405			onLeave: ( self ) => {},
406		} );
407	} );
408	 */
409
410	//shaderLoop
411	shaderLoop(
412		'#shaderLoopTechnology',
413		[
414			'/wp-content/themes/seesaw2025/hair-care/images/hair_care_lineup_scatterd.png',
415			'/wp-content/themes/seesaw2025/hair-care/images/hair_care_lineup_scatterd2.png',
416			'/wp-content/themes/seesaw2025/hair-care/images/hair_care_lineup_scatterd3.png',
417		]
418	);
419	// shaderLoop(
420	// 	'#shaderLoopFragrance',
421	// 	[
422	// 		'/wp-content/themes/seesaw2025/hair-care/images/wind_reflects.png',
423	// 	]
424	// );
425
426	//shaderTransition
427	shaderWipe(
428		'#shaferTransition',
429		[
430			'/wp-content/themes/seesaw2025/hair-care/images/hair_care_lineup_scatterd.png',
431			'/wp-content/themes/seesaw2025/hair-care/images/hair_care_lineup_scatterd2.png',
432			'/wp-content/themes/seesaw2025/hair-care/images/hair_care_lineup_scatterd3.png',
433		],
434		[ '/wp-content/themes/seesaw2025/hair-care/images/wind_reflects.png' ]
435	);
436
437	//mutual link
438	gsap.to( '.mutual-links__border', {
439		width: '100%',
440		scrollTrigger: {
441			trigger: '.mutual-links',
442			start: '5% bottom 100%',
443			end: '55% bottom 100%',
444			duration: 1,
445			scrub: true,
446		},
447	} );
448	new Swiper( '.mutual-links__clickable__images', {
449		loop: true,
450		autoplay: {
451			delay: 2500, //デフォルトの表示時間を指定
452		},
453		allowTouchMove: false,
454		effect: 'fade',
455		slidesPerView: 'auto',
456		speed: 1000,
457	} );
458
459	new Swiper( '.mutual-links__hover-text', {
460		loop: true,
461		slidesPerView: 'auto',
462		speed: 4000,
463		allowTouchMove: false,
464		autoplay: {
465			delay: 0,
466		},
467	} );
468
469	//modal
470	MicroModal.init( {
471		awaitCloseAnimation: true,
472		awaitOpenAnimation: true,
473		disableScroll: true,
474	} );
475}
476
477export function special() {
478	const triggers = document.querySelectorAll( '.special__grid__block' );
479	const zoomTimestamps = new Map();
480
481	triggers.forEach( ( trigger ) => {
482		ScrollTrigger.create( {
483			trigger: trigger,
484			start: 'top 40%',
485			end: 'bottom 55%',
486			//markers: true,
487			onEnter: ( self ) => {
488				triggers.forEach( ( block ) => {
489					block.classList.remove( 'previous' );
490				} );
491
492				triggers.forEach( ( block ) => {
493					if ( block.classList.contains( 'active' ) ) {
494						block.classList.remove( 'active' );
495						block.classList.add( 'previous' );
496					} else if ( block !== trigger ) {
497						block.classList.remove( 'active' );
498
499						if ( ! shouldKeepZoom( block ) ) {
500							block.classList.remove( 'zoom' );
501						}
502					}
503				} );
504				requestAnimationFrame( () => {
505					trigger.classList.add( 'zoom', 'active' );
506					zoomTimestamps.set( trigger, Date.now() );
507				} );
508			},
509			onEnterBack: ( self ) => {
510				triggers.forEach( ( block ) => {
511					block.classList.remove( 'previous' );
512				} );
513
514				triggers.forEach( ( block ) => {
515					if ( block.classList.contains( 'active' ) ) {
516						block.classList.remove( 'active' );
517						block.classList.add( 'previous' );
518					} else if ( block !== trigger ) {
519						block.classList.remove( 'active' );
520
521						if ( ! shouldKeepZoom( block ) ) {
522							block.classList.remove( 'zoom' );
523						}
524					}
525				} );
526				requestAnimationFrame( () => {
527					trigger.classList.add( 'zoom', 'active' );
528					zoomTimestamps.set( trigger, Date.now() );
529				} );
530			},
531			onLeaveBack: ( self ) => {},
532			onLeave: ( self ) => {},
533		} );
534	} );
535
536	function shouldKeepZoom( element ) {
537		const lastAddedTime = zoomTimestamps.get( element );
538		const currentTime = Date.now();
539		return lastAddedTime && currentTime - lastAddedTime <= 2000; //CSSでopacityのduration
540	}
541}
542
543export function archivePage() {
544	//modal
545	MicroModal.init( {
546		awaitCloseAnimation: true,
547		awaitOpenAnimation: true,
548		disableScroll: true,
549	} );
550}
551
552export function storyTop() {
553	//modal
554	MicroModal.init( {
555		awaitCloseAnimation: true,
556		awaitOpenAnimation: true,
557		disableScroll: true,
558	} );
559
560	const swiper = new Swiper( '.top-slider', {
561		loop: true,
562		effect: 'fade',
563
564		autoplay: {
565			delay: 5000, // スライドが表示される時間(ミリ秒)
566			//disableOnInteraction: false, // ユーザー操作後も自動再生を続ける
567		},
568
569		speed: 1000,
570
571		// If we need pagination
572		pagination: {
573			el: '.swiper-pagination',
574			type: 'fraction',
575		},
576
577		// Navigation arrows
578		navigation: {
579			nextEl: '.swiper-button-next',
580			prevEl: '.swiper-button-prev',
581		},
582	} );
583}
584
585export function single( fac ) {
586	// Preload
587	var main_image = $( '.c-article > .main-image > img' );
588
589	if ( main_image.length > 0 ) {
590		fac.html.addClass( 'fac-preload' );
591
592		var loader = new fac.ImageLoader( main_image );
593		loader.callbacks.all_loaded.add( function () {
594			fac.html.removeClass( 'fac-preload' );
595		} );
596		loader.start();
597	}
598
599	//Slider
600	var sliders = $( '.wp-block-gallery.slider' );
601
602	if ( sliders.length > 0 ) {
603		sliders.each( function ( index, element ) {
604			var slider = $( element );
605			var container = slider.find( '.blocks-gallery-grid' );
606			var area;
607
608			if ( container.length > 0 ) {
609				area = $( '<div></div>' )
610					.addClass( 'area' )
611					.prependTo( slider )
612					.append( container );
613
614				slider.find( 'img' ).each( function ( index, element ) {
615					var img = $( element );
616					var li = img.closest( 'li' );
617					var width = parseInt( img.attr( 'width' ) );
618					var height = parseInt( img.attr( 'height' ) );
619					if ( width === height ) {
620						li.addClass( 'square' );
621					} else if ( width > height ) {
622						li.addClass( 'landscape' );
623					} else {
624						li.addClass( 'portrait' );
625					}
626				} );
627			} else {
628				area = $( '<div></div>' )
629					.addClass( 'area' )
630					.prependTo( slider );
631				var ul = $( '<ul ></ul>' )
632					.addClass( 'blocks-gallery-grid' )
633					.prependTo( area );
634
635				slider.find( 'figure' ).each( function ( index, element ) {
636					var $element = $( element );
637					var img = $element.find( 'img' );
638					var width = parseInt( img.attr( 'width' ) );
639					var height = parseInt( img.attr( 'height' ) );
640
641					const li = $( '<li></li>' ); // jQuery object
642					li.addClass( 'blocks-gallery-item' );
643
644					if ( width === height ) {
645						li.addClass( 'square' );
646					} else if ( width > height ) {
647						li.addClass( 'landscape' );
648					} else {
649						li.addClass( 'portrait' );
650					}
651
652					li.append( element );
653					ul.append( li );
654				} );
655
656				container = ul;
657			}
658
659			var emblaApi = EmblaCarousel( slider.get( 0 ), {
660				container: container.get( 0 ),
661				containScroll: false,
662			} );
663			emblaApi.on( 'select', onSelect );
664
665			function onSelect() {
666				checkCanScroll();
667			}
668
669			function checkCanScroll() {
670				buttonPrev.attr( 'disabled', ! emblaApi.canScrollPrev() );
671				buttonNext.attr( 'disabled', ! emblaApi.canScrollNext() );
672			}
673
674			var buttonPrev = $( '<button />' )
675				.addClass( 'scrollPrev' )
676				.appendTo( area )
677				.on( 'click', emblaApi.scrollPrev );
678
679			var buttonNext = $( '<button />' )
680				.addClass( 'scrollNext' )
681				.appendTo( area )
682				.on( 'click', emblaApi.scrollNext );
683
684			checkCanScroll();
685		} );
686	}
687
688	//STEP
689	var target = $( '#step > .list' );
690
691	if ( target.length > 0 ) {
692		var options = {
693			transition: 'slide',
694			duration: 0.7,
695			easing: 'cubic-bezier(0.645, 0.045, 0.355, 1)',
696			loop: false,
697		};
698
699		var gallery = new fac.Gallery( target, options );
700		gallery.start();
701
702		//Auto break
703		var targets = $( '#step .list > li > .image > .item > p' );
704		targets.each( function () {
705			var target = $( this );
706			target.html(
707				Mikan( target.html().trim(), { className: '', style: '' } )
708			);
709		} );
710
711		//Reveal
712		var full_targets = [ '.c-article > header > h1' ];
713
714		var small_targets = [];
715
716		var reveal;
717
718		fac.main?.addContentSizeEvent(
719			'single',
720			function () {
721				if ( reveal ) reveal.destroy();
722				reveal = new fac.Reveal( full_targets, { type: 'move' } );
723			},
724			function () {
725				if ( reveal ) reveal.destroy();
726				reveal = new fac.Reveal( small_targets, { type: 'move' } );
727			}
728		);
729	}
730
731	//引換ボタン
732	const exchangeBtn = document.querySelector(
733		'.wp-block-button.js-exchange'
734	);
735	const exchangeImg = document.querySelector( '.wp-block-image.js-exchange' );
736
737	if ( exchangeBtn && exchangeImg ) {
738		function setCookie( name, value, days ) {
739			const date = new Date();
740			date.setTime( date.getTime() + days * 24 * 60 * 60 * 1000 );
741			document.cookie = `${ name }=${ value }; expires=${ date.toUTCString() }; path=/`;
742		}
743
744		function getCookie( name ) {
745			const cookies = document.cookie.split( ';' );
746			for ( let i = 0; i < cookies.length; i++ ) {
747				const cookie = cookies[ i ].trim();
748				if ( cookie.startsWith( name + '=' ) ) {
749					return cookie.substring( name.length + 1 );
750				}
751			}
752			return null;
753		}
754
755		function exchangeCompleted() {
756			exchangeBtn.classList.add( 'is-end' );
757			const link = exchangeBtn.querySelector( '.wp-block-button__link' );
758			link.textContent = 'プレゼント引換券は使用済みです';
759
760			exchangeImg.classList.add( 'is-end' );
761		}
762
763		function init() {
764			if ( getCookie( 'exchangeCompleted' ) === 'true' ) {
765				exchangeCompleted();
766			}
767			exchangeBtn.addEventListener( 'click', () => {
768				setCookie( 'exchangeCompleted', 'true', 90 );
769				exchangeCompleted();
770			} );
771		}
772
773		init();
774	}
775
776	//googleマップモジュール
777	( function ( $ ) {
778		function initMap( $el ) {
779			// Find marker elements within map.
780			var $markers = $el.find( '.wp-block-google-map__inner' );
781
782			// Create gerenic map.
783			var mapArgs = {
784				zoom: $el.data( 'zoom' ) || 16,
785				mapTypeId: google.maps.MapTypeId.ROADMAP,
786			};
787			var map = new google.maps.Map( $el[ 0 ], mapArgs );
788
789			// Add markers.
790			map.markers = [];
791			$markers.each( function () {
792				initMarker( $( this ), map );
793			} );
794
795			// Center map based on markers.
796			centerMap( map );
797
798			// Return map instance.
799			return map;
800		}
801
802		/**
803		 * initMarker
804		 *
805		 * Creates a marker for the given jQuery element and map.
806		 *
807		 * @date    22/10/19
808		 * @since   5.8.6
809		 *
810		 * @param   jQuery $el The jQuery element.
811		 * @param   object The map instance.
812		 * @return  object The marker instance.
813		 */
814		function initMarker( $marker, map ) {
815			// Get position from marker.
816			var lat = $marker.data( 'lat' );
817			var lng = $marker.data( 'lng' );
818			var latLng = {
819				lat: parseFloat( lat ),
820				lng: parseFloat( lng ),
821			};
822
823			// Create marker instance.
824			var marker = new google.maps.Marker( {
825				position: latLng,
826				map: map,
827			} );
828
829			// Append to reference for later use.
830			map.markers.push( marker );
831
832			// If marker contains HTML, add it to an infoWindow.
833			if ( $marker.html() ) {
834				// Create info window.
835				var infowindow = new google.maps.InfoWindow( {
836					content: $marker.html(),
837				} );
838
839				// Show info window when marker is clicked.
840				google.maps.event.addListener( marker, 'click', function () {
841					infowindow.open( map, marker );
842				} );
843			}
844		}
845
846		/**
847		 * centerMap
848		 *
849		 * Centers the map showing all markers in view.
850		 *
851		 * @date    22/10/19
852		 * @since   5.8.6
853		 *
854		 * @param   object The map instance.
855		 * @return  void
856		 */
857		function centerMap( map ) {
858			// Create map boundaries from all map markers.
859			var bounds = new google.maps.LatLngBounds();
860			map.markers.forEach( function ( marker ) {
861				bounds.extend( {
862					lat: marker.position.lat(),
863					lng: marker.position.lng(),
864				} );
865			} );
866
867			// Case: Single marker.
868			if ( map.markers.length == 1 ) {
869				map.setCenter( bounds.getCenter() );
870
871				// Case: Multiple markers.
872			} else {
873				map.fitBounds( bounds );
874			}
875		}
876
877		// Render maps on page load.
878		$( document ).ready( function () {
879			$( '.wp-block-google-map' ).each( function () {
880				var map = initMap( $( this ) );
881			} );
882		} );
883	} )( jQuery );
884
885	//modal
886	MicroModal.init( {
887		awaitCloseAnimation: true,
888		awaitOpenAnimation: true,
889		disableScroll: true,
890	} );
891}

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.