PageSourceSearch

https://seoulchurch.or.kr/js/site_animation.js?1760599857

js seoulchurch.or.kr collected 2026-09-25 09:48:50 UTC 5,696 bytes, 185 lines download raw bytes

1const SITE_ANIMATION = (() => {
2	const body = document.body;
3	const widgets = body.querySelectorAll('div[doz_type="widget"]');
4	const aniClass = 'ds_animated';
5
6	const init = (dsAnimation, load) => {
7		document.addEventListener('DOMContentLoaded', () => {
8			startAnimation(dsAnimation, load);
9		});
10	};
11
12	const addCustomListener = (eventType, element, widgetKey, callback) => {
13		const eventName = `${eventType}.${widgetKey}`;
14		element.addEventListener(eventType, callback);
15
16		return { eventName, eventType, element, callback };
17	};
18
19	const startAnimation = (dsAnimation, load) => {
20		widgets.forEach(widget => {
21			const widgetData = widget.querySelector('._widget_data');
22
23			if (!widgetData) return; // 위젯이 DB에 없는 경우 리턴
24
25			if (widgetData.classList.contains('_ds_animated_except')) return;
26
27			if (dsAnimation === 'Y') {
28				widgetData.classList.add(aniClass);
29			} else if (!widgetData.classList.contains('wg_animated')) {
30				return;
31			}
32
33			const widgetKey = widget.id;
34
35			if (dsAnimation === 'Y' && load === 'Y') {
36				scrollAnimation(widget, dsAnimation, "N");
37			}
38
39			const onScrollOrResize = () => {
40				setTimeout(() => {
41					scrollAnimation(widget, dsAnimation, load);
42				}, 100);
43			};
44
45			// 각각의 이벤트 타입에 대해 리스너 추가
46			addCustomListener('load', window, widgetKey, onScrollOrResize);
47			addCustomListener('resize', window, widgetKey, onScrollOrResize);
48			addCustomListener('scroll', window, widgetKey, onScrollOrResize);
49		});
50	};
51
52	const scrollAnimation = (widget, dsAnimation, load) => {
53		const windowWidth = window.innerWidth;
54		const windowHeight = window.innerHeight;
55		const bottomOfWindow = window.scrollY + windowHeight;
56		let bottomOfObject = widget.getBoundingClientRect().top + window.scrollY;
57		let deviceType = windowWidth < 992 ? 'mobile' : 'pc';
58
59		if (windowWidth <= 1024 && windowWidth >= 767) {
60			const offset = widget.getBoundingClientRect().top - document.body.getBoundingClientRect().top;
61			bottomOfObject = offset * 0.85;
62		}
63
64		// widget의 데이터를 들고 오기 위해 해당 obj 찾기
65		let obj = widget.querySelector('._widget_data[data-widget-parent-is-mobile="N"]');
66		if (deviceType === 'mobile') {
67			obj = widget.querySelector('._widget_data');
68		}
69
70		if (!obj) return;
71
72		const wgExceptionType = obj.getAttribute('data-widget-type');
73
74		if (wgExceptionType === "booking") {
75			const widgetAnimationDone = obj.getAttribute('data-animation-done');
76			if (widgetAnimationDone === 'Y') return; // 이미 애니메이션이 완료된 위젯은 리턴
77		}
78
79		const wgAniClass = obj.getAttribute('data-widget-anim');
80		const wgAniDuration = obj.getAttribute('data-widget-anim-duration');
81		const wgAniDelay = obj.getAttribute('data-widget-anim-delay');
82
83		// widget type 이 icon, button 인 경우 wg_animated 클래스를 찾아야 함
84		if (wgExceptionType === 'icon' || wgExceptionType === 'button') {
85			obj = deviceType === 'mobile'
86				? widget.querySelectorAll('.wg_animated')
87				: widget.querySelectorAll('div[data-widget-parent-is-mobile="N"] .wg_animated');
88		}
89
90		if (!obj) return;
91
92		const wgData = {
93			wgExceptionType,
94			wgAniClass,
95			wgAniDuration,
96			wgAniDelay,
97			aniClass,
98			dsAnimation
99		}
100
101		const attachAnimationEndListener = (element) => {
102			// 이미 애니메이션이 완료된 경우 리턴
103			if (element.getAttribute('data-animation-done') === 'Y') return;
104
105			if (element.classList.contains('wg_animated')) {
106				element.addEventListener('animationend', () => {
107					element.classList.remove(wgAniClass);
108					element.classList.remove(aniClass);
109					element.style.opacity = '1';
110					element.setAttribute('data-animation-done', 'Y');
111				}, { once: true });
112			}
113		};
114
115		if (wgExceptionType === 'icon' || wgExceptionType === 'button') {
116			obj.forEach(item => {
117				animationFunction(item, wgData, bottomOfWindow, bottomOfObject, deviceType, load);
118			});
119		} else {
120			animationFunction(obj, wgData, bottomOfWindow, bottomOfObject, deviceType, load);
121			if (wgExceptionType === 'booking') {
122				// 에니메이션이 끝나면, 애니메이션 관련된 class 제거
123				attachAnimationEndListener(obj);
124			}
125		}
126	};
127
128	const animationFunction = (wgObj, wgData, bottomOfWindow, bottomOfObject, deviceType, load) => {
129		if (!wgObj || !wgData) return;
130
131		const { wgExceptionType, wgAniClass, wgAniDuration, wgAniDelay, aniClass, dsAnimation } = wgData;
132
133		if (wgObj.classList.contains('wg_animated')) {
134			wgObj.classList.remove(aniClass);
135			if (bottomOfWindow > bottomOfObject) {
136				wgObj.classList.add(wgAniClass);
137				wgObj.style.animationDuration = `${wgAniDuration}s`;
138				wgObj.style.webkitAnimationDuration = `${wgAniDuration}s`;
139				wgObj.style.animationDelay = `${wgAniDelay}s`;
140
141				if (!wgAniClass.includes('fadeIn')) {
142					wgObj.style.opacity = '1';
143				}
144				wgObj.style.visibility = 'visible';
145
146			} else {
147				if (deviceType !== 'mobile' && load !== 'Y') {
148					wgObj.classList.remove(wgAniClass);
149				}
150
151				if (!wgAniClass.includes('fadeIn')) {
152					wgObj.style.opacity = '0';
153				}
154				wgObj.style.visibility = 'hidden';
155			}
156
157		} else {
158			if (dsAnimation !== 'Y' || body.classList.contains('shop_mypage')) return;
159
160			if (bottomOfWindow > bottomOfObject) {
161				wgObj.classList.add(aniClass);
162				if (wgExceptionType === 'code') {
163					wgObj.classList.remove(aniClass);
164				}
165			} else {
166				if (deviceType !== 'mobile' && load !== 'Y') {
167					wgObj.classList.remove(aniClass);
168					wgObj.style.opacity = '0';
169					if (wgExceptionType === 'code') {
170						wgObj.style.opacity = '1';
171					}
172				}
173			}
174
175			wgObj.style.visibility = 'visible';
176		}
177	}
178
179
180	return {
181		init: (dsAnimation, load) => {
182			init(dsAnimation, load);
183		}
184	};
185})();

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.