PageSourceSearch

https://0gichul.com/layouts/0gichul/js/story-modal-loader.js?v=427e90db4627

js 0gichul.com collected 2026-10-08 10:51:02 UTC 19,542 bytes, 400 lines download raw bytes

1(function () {
2    'use strict';
3    var config = document.querySelector('template[data-layout-modal-style]');
4    var parent = config && config.parentNode;
5    var source = config && config.getAttribute('data-style-url');
6    var pending = null, link = null, loaded = false;
7    function current() {
8        return !config || (config.isConnected && config.parentNode === parent
9            && document.querySelector('template[data-layout-modal-style]') === config
10            && config.getAttribute('data-style-url') === source);
11    }
12    function ready() { return current() && (!config || (loaded && link && link.isConnected && link.getAttribute('href') === source)); }
13    window.gichulLayoutModalStyleReady = ready;
14    window.gichulLoadLayoutModalStyle = function () {
15        if(ready()) return Promise.resolve();
16        if(!current() || !source) return Promise.reject(new Error('Modal style unavailable'));
17        if(pending) return pending;
18        if(link) link.remove();loaded=false;
19        var tag = document.createElement('link');tag.rel='stylesheet';tag.href=source;
20        link=tag;
21        pending = new Promise(function (resolve,reject) {
22            var settled=false;
23            var timer=window.setTimeout(function () { finish(new Error('Modal style timeout')); },15000);
24            function finish(error) {
25                if(settled)return;settled=true;window.clearTimeout(timer);tag.onload=tag.onerror=null;
26                if(!error && (!current() || !tag.isConnected || tag.getAttribute('href')!==source)) error=new Error('Modal style changed');
27                if(error) { tag.remove();if(link===tag) { link=null;loaded=false; } reject(error); }
28                else { loaded=true;resolve(); }
29            }
30            tag.onload=function () { finish(); };tag.onerror=function () { finish(new Error('Modal style failed')); };
31            try { document.head.appendChild(tag); } catch(error) { finish(error); }
32        });
33        var request=pending;
34        request.then(function () { if(pending===request) pending=null; },function () { if(pending===request) pending=null; });
35        return request;
36    };
37})();
38	(function initStoryModalViewportHeightVar() {
39		if(typeof window.refreshStoryModalViewportHeight === 'function') return;
40		var root = document.documentElement;
41		var viewportWork = null, pageActive = true, resumeForce = false;
42
43		function currentViewport() {
44			return pageActive && !document.hidden && root === document.documentElement && root.isConnected;
45		}
46
47		function setViewportValue(name, value) {
48			if(root.style.getPropertyValue(name) !== value || root.style.getPropertyPriority(name)) {
49				root.style.setProperty(name, value);
50			}
51		}
52
53		function apply(options) {
54			var viewport = window.visualViewport;
55			var layoutHeight = window.innerHeight || document.documentElement.clientHeight || 0;
56			var shouldResetOffset = root.classList.contains('story-ios-keyboard-cleanup')
57				|| document.body.classList.contains('story-ios-keyboard-cleanup')
58				|| root.classList.contains('story-modal-height-freeze')
59				|| (viewport && typeof viewport.scale === 'number' && viewport.scale > 1.01);
60			var offsetTop = !shouldResetOffset && viewport && typeof viewport.offsetTop === 'number'
61				? Math.max(0, Math.round(viewport.offsetTop || 0))
62				: 0;
63			setViewportValue('--story-modal-offset-top', String(offsetTop) + 'px');
64			var height = viewport && viewport.height && layoutHeight
65				? Math.min(viewport.height, layoutHeight)
66				: (viewport && viewport.height ? viewport.height : layoutHeight);
67			if (!height) return;
68			setViewportValue('--app-dvh', String(Math.round(height)) + 'px');
69			if ((options && options.forceStoryModalHeight) || !root.classList.contains('story-modal-height-freeze')) {
70				setViewportValue('--story-modal-vh', String(Math.round(height + offsetTop)) + 'px');
71			}
72		}
73
74		function cancelViewportWork() {
75			var work = viewportWork;
76			viewportWork = null;
77			if(!work) return;
78			if(work.raf) window.cancelAnimationFrame(work.id);
79			else window.clearTimeout(work.id);
80		}
81
82		function schedule() {
83			if(viewportWork || !currentViewport()) return;
84			var work = {raf: typeof window.requestAnimationFrame === 'function', id: 0};
85			viewportWork = work;
86			var run = function() {
87				if(viewportWork !== work) return;
88				viewportWork = null;
89				if(!currentViewport()) return;
90				var force = resumeForce;
91				resumeForce = false;
92				apply({forceStoryModalHeight: force});
93			};
94			work.id = work.raf ? window.requestAnimationFrame(run) : window.setTimeout(run,16);
95		}
96
97		window.refreshStoryModalViewportHeight = function() {
98			cancelViewportWork();
99			if(!currentViewport()) { resumeForce = true; return; }
100			resumeForce = false;
101			apply({ forceStoryModalHeight: true });
102		};
103
104		schedule();
105		window.addEventListener('resize', schedule);
106		window.addEventListener('orientationchange', schedule);
107		window.addEventListener('pagehide', function() { pageActive = false; cancelViewportWork(); });
108		window.addEventListener('pageshow', function() { pageActive = true; schedule(); });
109		document.addEventListener('visibilitychange', function() {
110			if(document.hidden) cancelViewportWork();
111			else schedule();
112		});
113		if (window.visualViewport) {
114			window.visualViewport.addEventListener('resize', schedule);
115			window.visualViewport.addEventListener('scroll', schedule);
116		}
117	})();
118
119(function() {
120	'use strict';
121	if(typeof window.openStoryProfileModal === 'function') return;
122	var source = document.currentScript && document.currentScript.getAttribute('data-modal-src');
123	if(!source) return;
124	var pending = null, latest = null;
125
126	function isLoaded() {
127		return typeof window.openStoryProfileModal === 'function' && window.openStoryProfileModal !== open;
128	}
129	function cancel() { latest = null; }
130	function fallback(request) {
131		var path = request.member > 0 ? '/story/' + request.member : '/story/';
132		try {
133			var target = new URL(request.options.targetStoryUrl || path, location.href);
134			if(target.origin === location.origin && /^\/story(?:\/|$)/.test(target.pathname)) path = target.href;
135		} catch(e) {}
136		location.assign(path);
137	}
138	function loadScript() {
139		if(pending) {
140			if(pending._storyModalTimedOut && latest) {
141				var request = latest;
142				latest = null;
143				fallback(request);
144			}
145			return;
146		}
147		var script = document.createElement('script');
148		script.src = source;
149		script.async = true;
150		pending = script;
151		var timer = window.setTimeout(function() {
152			if(pending !== script) return;
153			// A removed script may still execute. Keep it in flight to avoid duplicate initialization.
154			script._storyModalTimedOut = true;
155			var request = latest;
156			latest = null;
157			if(request) fallback(request);
158		}, 15000);
159		function finish(success) {
160			if(pending !== script) return;
161			window.clearTimeout(timer);
162			script.onload = script.onerror = null;
163			pending = null;
164			var request = latest;
165			latest = null;
166			if(!success) script.remove();
167			if(!request) return;
168			if(isLoaded()) window.openStoryProfileModal(request.member, request.options);
169			else fallback(request);
170		}
171		script.onload = function() { finish(true); };
172		script.onerror = function() { finish(false); };
173		document.head.appendChild(script);
174	}
175	var stylePending = null;
176	function load() {
177		if(stylePending) return;
178		stylePending = window.gichulLoadLayoutModalStyle();
179		stylePending.then(function () { stylePending=null;loadScript(); },function () {
180			stylePending=null;var request=latest;latest=null;if(request)fallback(request);
181		});
182	}
183	function open(memberSrl, options) {
184		var member = parseInt(memberSrl, 10) || 0, opts = options || {};
185		if(isLoaded()) return window.openStoryProfileModal(member, opts);
186		if(member <= 0 && !opts.directStoryFrame && !opts.storyMainFrame) return false;
187		latest = {member: member, options: opts};
188		load();
189		return true;
190	}
191	window.openStoryProfileModal = open;
192	window.closeStoryProfileModal = cancel;
193	window.addEventListener('popstate', cancel);
194	window.addEventListener('pagehide', cancel);
195	document.addEventListener('keydown', function(e) { if(e.key === 'Escape') cancel(); });
196	function warmOnIntent(e) {
197		if(isLoaded() || pending || (navigator.connection && navigator.connection.saveData)) return;
198		var link = e.target && e.target.closest && e.target.closest(
199			'a[data-open-story-main-modal], a[data-open-my-story-modal], a[data-open-story-compose-modal], a[class*="member_"]'
200		);
201		if(!link || link.getAttribute('data-story-modal') === 'off' || link.classList.contains('story-modal-skip')) return;
202		if(link.closest('#storyProfileModal')) return;
203		var explicitTrigger = link.hasAttribute('data-open-story-main-modal')
204			|| link.hasAttribute('data-open-my-story-modal') || link.hasAttribute('data-open-story-compose-modal');
205		if(!explicitTrigger && (link.closest('.mid_menu_member') || !/(?:^|\s)member_[1-9]\d*(?:\s|$)/.test(String(link.className)))) return;
206		// Download/initialize only; opening and navigation still require a click.
207		load();
208	}
209	document.addEventListener('pointerover', warmOnIntent, { passive: true });
210	document.addEventListener('focusin', warmOnIntent);
211	document.addEventListener('touchstart', warmOnIntent, { passive: true });
212	document.addEventListener('click', function(e) {
213		if(isLoaded() || e.defaultPrevented || e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey || e.isTrusted === false) return;
214		var link = e.target && e.target.closest && e.target.closest('a[class*="member_"]');
215		if(!link || link.closest('#storyProfileModal') || link.closest('.mid_menu_member')
216			|| link.getAttribute('data-story-modal') === 'off' || link.classList.contains('story-modal-skip')) return;
217		var match = String(link.className).match(/(?:^|\s)member_(\d+)(?:\s|$)/);
218		if(!match || Number(match[1]) <= 0) return;
219		e.preventDefault();
220		e.stopPropagation();
221		var name = String(link.textContent || '').replace(/\s+/g, ' ').trim();
222		var img = link.querySelector('img');
223		open(match[1], {
224			displayName: name && name !== '회원정보' ? name : String(link.getAttribute('data-nick') || '').trim(),
225			profileImage: img ? String(img.getAttribute('src') || '').trim() : '',
226			avatarColor: link.style.backgroundColor || link.getAttribute('data-avatar-color') || '#667eea'
227		});
228	}, true);
229	window.addEventListener('message', function(e) {
230		var data = e.data;
231		if(isLoaded() || !data || data.type !== 'gstore:open-story-profile' || (e.origin && e.origin !== location.origin)) return;
232		var member = parseInt(data.memberSrl || data.member_srl || '0', 10) || 0;
233		if(member <= 0) return;
234		open(member, {
235			displayName: String(data.displayName || data.nickName || '').trim(),
236			profileImage: String(data.profileImage || '').trim(),
237			avatarColor: String(data.avatarColor || '').trim(),
238			targetStoryUrl: String(data.targetStoryUrl || data.storyUrl || data.url || '').trim(),
239			preferStoryFrame: data.preferStoryFrame !== false,
240			pushFrameBack: data.pushFrameBack === true,
241			source: String(data.source || '')
242		});
243	});
244})();
245
246(function() {
247    'use strict';
248    if(window.gichulCenterLoaders) return;
249    window.gichulCenterLoaders = {};
250    window.gichulCenterStyleGuards = {};
251    ['Messages', 'Notifications'].forEach(function(kind) {
252        var key = kind.toLowerCase();
253        var config = document.querySelector('[data-center-assets="' + key + '"]');
254        if(!config) return;
255        var url = config.getAttribute('data-script-url');
256        var styleUrl = config.getAttribute('data-style-url');
257        var configParent = config.parentNode;
258        var stylePending = null, styleLink = null, styleLoaded = false;
259        var exportName = 'Gichul' + kind + 'Center';
260        var modal = document.getElementById(key + 'CenterModal');
261        var modalParent = modal && modal.parentNode;
262        var selector = '[data-open-' + key + '-modal="1"]';
263        var pending = null, intent = null, generation = 0;
264
265        function current() {
266            return config.isConnected && config.parentNode === configParent
267                && modal && modal.isConnected && modal.parentNode === modalParent && document.getElementById(key + 'CenterModal') === modal
268                && document.querySelector('[data-center-assets="' + key + '"]') === config
269                && config.getAttribute('data-script-url') === url
270                && config.getAttribute('data-style-url') === styleUrl;
271        }
272        function activeStyle(link) {
273            if(!link || !link.isConnected || link.getAttribute('href') !== styleUrl || link.rel !== 'stylesheet'
274                || link.disabled || !link.sheet || link.sheet.disabled) return false;
275            var media = link.sheet.media && link.sheet.media.mediaText;
276            return (!link.media || window.matchMedia(link.media).matches) && (!media || window.matchMedia(media).matches);
277        }
278        function styleReady() {
279            return current() && (!styleUrl || (styleLoaded && activeStyle(styleLink)));
280        }
281        function loadStyle() {
282            if(!current()) return Promise.reject(new Error('Center assets changed'));
283            if(!styleUrl) return Promise.resolve(); // Older cached HTML already contains the full inline style.
284            if(styleReady()) return Promise.resolve();
285            if(stylePending) return stylePending;
286            if(styleLink) styleLink.remove();
287            styleLoaded = false;
288            var link = document.createElement('link');
289            link.rel = 'stylesheet'; link.href = styleUrl; styleLink = link;
290            var request = new Promise(function(resolve,reject) {
291                var settled = false;
292                var timer = window.setTimeout(function() { finish(new Error('Center style timeout')); },15000);
293                function finish(error) {
294                    if(settled) return;
295                    settled = true; window.clearTimeout(timer); link.onload = link.onerror = null;
296                    if(!error && (!current() || !activeStyle(link))) error = new Error('Center style changed');
297                    if(error) { link.remove(); if(styleLink === link) { styleLink = null; styleLoaded = false; } reject(error); }
298                    else { styleLoaded = true; resolve(); }
299                }
300                link.onload = function() { finish(); };
301                link.onerror = function() { finish(new Error('Center style unavailable')); };
302                try { (document.head || document.documentElement).appendChild(link); }
303                catch(error) { finish(error); }
304            });
305            stylePending = request;
306            function release() { if(stylePending === request) stylePending = null; }
307            request.then(release,release);
308            return request;
309        }
310        function ready() { return window[exportName] && typeof window[exportName].open === 'function'; }
311        function clearIntent() {
312            generation++;
313            if(intent && intent.link) intent.link.removeAttribute('aria-busy');
314            intent = null;
315        }
316        window.gichulCenterLoaders[key] = clearIntent;
317        function loadScript() {
318            if(!current()) return Promise.reject(new Error('Center assets changed'));
319            if(ready()) return Promise.resolve();
320            if(pending) return pending;
321            var script = document.createElement('script');
322            var request = new Promise(function(resolve, reject) {
323                var settled = false;
324                var timer = window.setTimeout(function() { finish(new Error('timeout')); }, 15000);
325                function finish(error) {
326                    if(settled) return;
327                    settled = true;
328                    window.clearTimeout(timer);
329                    script.onload = script.onerror = null;
330                    if(error) { script.remove(); reject(error); }
331                    else resolve();
332                }
333                script.src = url;
334                script.onload = function() { finish(ready() && styleReady() ? null : new Error('unavailable')); };
335                script.onerror = function() { finish(new Error('unavailable')); };
336                try { (document.head || document.documentElement).appendChild(script); }
337                catch(error) { finish(error); }
338            });
339            pending = request;
340            function release() { if(pending === request) pending = null; }
341            request.then(release, release);
342            return request;
343        }
344        function load() { return loadStyle().then(loadScript); }
345        function open(options, link) {
346            if(!current()) return false;
347            if(ready() && styleReady()) { clearIntent(); return window[exportName].open(options); }
348            clearIntent();
349            var request = {id: generation, options: options, link: link};
350            intent = request;
351            if(link) link.setAttribute('aria-busy', 'true');
352            load().then(function() {
353                if(intent !== request || request.id !== generation || !current()) { if(intent === request) clearIntent(); return; }
354                if(!styleReady()) throw new Error('Center style changed');
355                clearIntent();
356                window[exportName].open(request.options);
357            }).catch(function() {
358                if(intent !== request || request.id !== generation) return;
359                clearIntent();
360                if(window.showToast) window.showToast('창을 불러오지 못했습니다. 다시 시도해 주세요.', 'info', 2500);
361            });
362            // The request is accepted while assets load; callers must suppress link navigation.
363            return true;
364        }
365        function close() {
366            clearIntent();
367            if(ready()) return window[exportName].close();
368        }
369        window.gichulCenterStyleGuards[key] = function(options) {
370            if(styleReady()) return true;
371            if(current()) open(options);
372            return false;
373        };
374        window['open' + kind + 'Modal'] = open;
375        window['close' + kind + 'Modal'] = close;
376        document.addEventListener('click', function(event) {
377            if((ready() && styleReady()) || event.defaultPrevented || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;
378            var link = event.target && event.target.closest && event.target.closest(selector);
379            if(!link || (modal && modal.contains(link))) return;
380            event.preventDefault();
381            event.stopImmediatePropagation();
382            var options;
383            if(kind === 'Messages') {
384                var target = 0;
385                try {
386                    var parsed = new URL(link.getAttribute('href') || '', window.location.origin);
387                    target = parseInt(parsed.searchParams.get('target') || parsed.searchParams.get('target_member_srl') || parsed.searchParams.get('target_srl') || '0', 10) || 0;
388                } catch(error) {}
389                options = {targetMemberSrl: target};
390            }
391            open(options, link);
392        }, true);
393        document.addEventListener('keydown', function(event) { if(event.key === 'Escape') clearIntent(); });
394        window.addEventListener('pagehide', close);
395        window.addEventListener('popstate', clearIntent);
396        if(kind === 'Messages') window.addEventListener('message', function(event) {
397            if(event.data && event.data.type === 'gstore:close-messages-modal' && (!event.origin || event.origin === window.location.origin)) close();
398        });
399    });
400})();

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.