PageSourceSearch

https://ratherlow.co.kr/ind-script/optimizer_user.php?filename=lZB…6841bc694c0b9f3add0798e&t=1771724963&user=T

js ratherlow.co.kr collected 2026-10-06 14:04:31 UTC 94,489 bytes, 2,580 lines download raw bytes

1/* =========================
2 * © MUNDANE
3 * 본 파일은 먼데인이 본 스킨을 위해 제작/구성한 커스텀 JavaScript 코드입니다.
4 * 무단 복제, 수정, 재배포 및 타 프로젝트 사용을 금합니다.
5 * ※ 본 스킨은 jQuery, Swiper 등 제3자 라이브러리를 사용할 수 있으며,
6 * 해당 라이브러리의 권리/라이선스는 각 저작권자에게 있습니다.
7========================= */
8
9
10
11var _0x170d25=_0x5d00;(function(_0x5e6716,_0x108d0b){var _0x4eb7a5=_0x5d00,_0x3ff56c=_0x5e6716();while(!![]){try{var _0x1e911e=-parseInt(_0x4eb7a5(0x9f))/0x1+parseInt(_0x4eb7a5(0xcb))/0x2+-parseInt(_0x4eb7a5(0xa9))/0x3+parseInt(_0x4eb7a5(0x9a))/0x4*(parseInt(_0x4eb7a5(0xd7))/0x5)+parseInt(_0x4eb7a5(0xc1))/0x6+-parseInt(_0x4eb7a5(0xa4))/0x7*(parseInt(_0x4eb7a5(0xa7))/0x8)+parseInt(_0x4eb7a5(0xe6))/0x9;if(_0x1e911e===_0x108d0b)break;else _0x3ff56c['push'](_0x3ff56c['shift']());}catch(_0x1c5b5a){_0x3ff56c['push'](_0x3ff56c['shift']());}}}(_0x5922,0x5c293));function qs(_0x566242,_0x1e6f27){var _0x28e036=_0x5d00;return(_0x1e6f27||document)[_0x28e036(0xbc)](_0x566242);}function qsa(_0x1f2a5d,_0x198325){var _0x484e94=_0x5d00;return Array[_0x484e94(0xa1)][_0x484e94(0xd6)][_0x484e94(0xac)]((_0x198325||document)[_0x484e94(0xd4)](_0x1f2a5d));}function matches(_0x22bf70,_0x26cce3){var _0x261989=_0x5d00;if(!_0x22bf70||_0x22bf70['nodeType']!==0x1)return![];var _0xb505fe=Element['prototype'],_0x78aa9a=_0xb505fe['matches']||_0xb505fe[_0x261989(0xbd)]||_0xb505fe['webkitMatchesSelector'];return _0x78aa9a['call'](_0x22bf70,_0x26cce3);}function _0x5922(){var _0x1ac660=['<div\x20id=\x22','\x20\x20\x20\x20<div\x20class=\x22mundane-license-notice__text\x22>','setHours','body','nodeType','setDate','push','4349691cRwwXT','\x20\x20\x20\x20\x20\x20\x20\x20라이선스\x20정보가\x20확인되지\x20않아\x20안내가\x20표시됩니다.<br/>','18844xhpbJO','\x22\x20class=\x22mundane-license-notice\x22\x20style=\x22display:none;\x22>','.popup_pagination','DOMContentLoaded','jQuery','322615khKXcB','display','prototype','\x20\x20\x20\x20\x20\x20\x20\x20정상\x20사용\x20중이라면\x20<a\x20href=\x22','parentElement','7uLTNrL','div','onclick','5378808nQeQNh','data-','1263036pLiZqb','</a>\x20로\x20문의\x20바랍니다.','getAttribute','call','assign','watchOverflow','style','split','Swiper','hasLicense','contains','stop','http://studiomundane.kr','\x20\x20\x20\x20\x20\x20<strong>라이선스\x20확인\x20안내</strong>','\x20\x20\x20\x20</div>','meta[name=\x22mundane-license\x22]','addEventListener','fraction','dataset','querySelector','msMatchesSelector','createElement','length','.weeks-btn','1964922QEdVvr','content','match','license','insertAdjacentHTML','charAt','cookie','none','MUNDANE','.type-image-text','580332hArZOs','getDate','MUNDANE_SWIPER_PRESETS','fadeIn','=([^;]+)','.swiper-slide','classList','.popup-color[style]','.main-popup','querySelectorAll','\x20\x20\x20\x20\x20\x20<button\x20type=\x22button\x22\x20class=\x22mln-btn\x20mln-close\x22>닫기</button>','slice','735dxeVQl','(^|;)\x5cs*','forEach','className','trim','appendChild','mundane_license_notice','join'];_0x5922=function(){return _0x1ac660;};return _0x5922();}function closest(_0x443cec,_0x5e4bc0){var _0x8f15cd=_0x5d00;while(_0x443cec&&_0x443cec[_0x8f15cd(0xe3)]===0x1){if(matches(_0x443cec,_0x5e4bc0))return _0x443cec;_0x443cec=_0x443cec[_0x8f15cd(0xa3)];}return null;}function getData(_0x20cf8a,_0x2c30a2){var _0x546008=_0x5d00;if(!_0x20cf8a)return'';if(_0x20cf8a[_0x546008(0xbb)]&&_0x20cf8a[_0x546008(0xbb)][_0x2c30a2]!=null)return _0x20cf8a['dataset'][_0x2c30a2];return _0x20cf8a['getAttribute'](_0x546008(0xa8)+_0x2c30a2)||'';}function fadeInEl(_0x3c1688,_0x3f2ed0){var _0x54a08f=_0x5d00;if(!_0x3c1688||!window['jQuery'])return;jQuery(_0x3c1688)[_0x54a08f(0xb4)](!![],!![])[_0x54a08f(0xce)](_0x3f2ed0||0x96);}function fadeOutEl(_0x3a6632,_0x53b5d8){var _0x371c75=_0x5d00;if(!_0x3a6632||!window[_0x371c75(0x9e)])return;jQuery(_0x3a6632)[_0x371c75(0xb4)](!![],!![])['fadeOut'](_0x53b5d8||0x96);}function _0x5d00(_0x3c12a3,_0xb29df0){_0x3c12a3=_0x3c12a3-0x9a;var _0x5922a0=_0x5922();var _0x5d0018=_0x5922a0[_0x3c12a3];return _0x5d0018;}function setCookieUntil(_0x3858ff,_0x4201f0,_0x234acc){var _0x227d97=_0x5d00;document[_0x227d97(0xc7)]=_0x3858ff+'='+encodeURIComponent(_0x4201f0)+';\x20path=/;\x20expires='+_0x234acc['toUTCString']();}function setCookieDays(_0x53d037,_0x3b9d0c,_0x5f4487){var _0x19cd3c=_0
11x5d00,_0x5520c9=new Date();_0x5520c9[_0x19cd3c(0xe4)](_0x5520c9[_0x19cd3c(0xcc)]()+_0x5f4487),setCookieUntil(_0x53d037,_0x3b9d0c,_0x5520c9);}function getCookie(_0x3cb42e){var _0x2f0c68=_0x5d00,_0x45da63=document[_0x2f0c68(0xc7)][_0x2f0c68(0xc3)](new RegExp(_0x2f0c68(0xd8)+_0x3cb42e+_0x2f0c68(0xcf)));return _0x45da63?decodeURIComponent(_0x45da63[0x2]):null;}function hideToday(_0x450d99){var _0x3ebaf2=_0x5d00,_0xaf074b=new Date();_0xaf074b[_0x3ebaf2(0xe1)](0x17,0x3b,0x3b,0x3e7),setCookieUntil(_0x450d99,'Y',_0xaf074b);}function readMundaneLicense(){var _0x4684bf=_0x5d00,_0x528822=qs(_0x4684bf(0xb8));return _0x528822?(_0x528822[_0x4684bf(0xab)](_0x4684bf(0xc2))||'')[_0x4684bf(0xdb)]():'';}function initMundaneLicenseState(){var _0x22616d=_0x5d00;window[_0x22616d(0xc9)]=window[_0x22616d(0xc9)]||{},window[_0x22616d(0xc9)]['license']=readMundaneLicense(),window[_0x22616d(0xc9)][_0x22616d(0xb2)]=!!window['MUNDANE'][_0x22616d(0xc4)];}function hasMundaneLicense(){var _0x410a60=_0x5d00;return!!(window[_0x410a60(0xc9)]&&window[_0x410a60(0xc9)][_0x410a60(0xb2)]);}var LICENSE_NOTICE_ID=_0x170d25(0xdd),LICENSE_CONTACT_ADDR=_0x170d25(0xb5),LICENSE_CONTACT_EMAIL='[email protected]';function buildLicenseNoticeHtml(){var _0x3abd68=_0x170d25;return[_0x3abd68(0xdf)+LICENSE_NOTICE_ID+_0x3abd68(0x9b),'\x20\x20<div\x20class=\x22mundane-license-notice__inner\x22>',_0x3abd68(0xe0),_0x3abd68(0xb6),'\x20\x20\x20\x20\x20\x20<p>','\x20\x20\x20\x20\x20\x20\x20\x20본\x20스킨은\x20<b>MUNDANE(먼데인)</b>의\x20저작물입니다.<br/>',_0x3abd68(0xe7),_0x3abd68(0xa2)+LICENSE_CONTACT_ADDR+'\x22\x20target=\x22_blank\x22\x20rel=\x22noopener\x20noreferrer\x22>'+LICENSE_CONTACT_EMAIL+_0x3abd68(0xaa),'\x20\x20\x20\x20\x20\x20</p>',_0x3abd68(0xb7),'\x20\x20\x20\x20<div\x20class=\x22mundane-license-notice__actions\x22>',_0x3abd68(0xd5),_0x3abd68(0xb7),'\x20\x20</div>','</div>'][_0x3abd68(0xde)]('');}function showLicenseNotice(){var _0x2dfc84=_0x170d25;if(hasMundaneLicense())return;var _0x400b3f=qs('#'+LICENSE_NOTICE_ID);!_0x400b3f&&(document[_0x2dfc84(0xe2)][_0x2dfc84(0xc5)]('beforeend',buildLicenseNoticeHtml()),_0x400b3f=qs('#'+LICENSE_NOTICE_ID)),fadeInEl(_0x400b3f,0x96);}var OVERLAY_ID='popup_overlay',OVERLAY_TARGET_SELECTOR=_0x170d25(0xca);
11function ensureOverlay(){var _0x2ef8b0=_0x170d25,_0x38df28=qs('#'+OVERLAY_ID);return!_0x38df28&&(_0x38df28=document[_0x2ef8b0(0xbe)](_0x2ef8b0(0xa5)),_0x38df28['id']=OVERLAY_ID,_0x38df28[_0x2ef8b0(0xda)]='popup-overlay',_0x38df28[_0x2ef8b0(0xaf)][_0x2ef8b0(0xa0)]=_0x2ef8b0(0xc8),document[_0x2ef8b0(0xe2)][_0x2ef8b0(0xdc)](_0x38df28)),_0x38df28;}function closeOverlayPopup(_0x9a21b8){fadeOutEl(_0x9a21b8,0xc8),fadeOutEl(qs('#'+OVERLAY_ID),0xc8);}function initOverlayBehavior(_0x25a51c){var _0x342894=_0x170d25,_0x436158=ensureOverlay();fadeInEl(_0x436158,0xc8),_0x436158[_0x342894(0xa6)]=function(){closeOverlayPopup(_0x25a51c);};}function getPopupTypeKey(_0x5776ad){var _0x1f71bc=_0x170d25,_0x4a4463=window[_0x1f71bc(0xcd)]||{},_0x3d8221=Object['keys'](_0x4a4463);for(var _0x26b794=0x0;_0x26b794<_0x3d8221[_0x1f71bc(0xbf)];_0x26b794++){if(_0x5776ad[_0x1f71bc(0xd1)][_0x1f71bc(0xb3)](_0x3d8221[_0x26b794]))return _0x3d8221[_0x26b794];}return null;}function buildSwiperOptions(_0x51daa3){var _0x2b8e07=_0x170d25;if(!hasMundaneLicense())return showLicenseNotice(),null;var _0x24659f=qsa('.swiper-slide',_0x51daa3)[_0x2b8e07(0xbf)],_0x102eda=_0x24659f===0x1,_0x37ca7e={'slidesPerView':0x1,'slidesPerGroup':0x1},_0x517167=qs(_0x2b8e07(0x9c),_0x51daa3);_0x517167&&!_0x102eda&&(_0x37ca7e['pagination']={'el':_0x517167,'type':_0x2b8e07(0xba)});if(_0x102eda)return _0x37ca7e['loop']=![],_0x37ca7e[_0x2b8e07(0xae)]=!![],_0x37ca7e;var _0x7ec355=window[_0x2b8e07(0xcd)]||{},_0x46aec1=getPopupTypeKey(_0x51daa3),_0x25fe3f=_0x46aec1?_0x7ec355[_0x46aec1]||{}:{},_0x4c3944={};return Object[_0x2b8e07(0xad)](_0x4c3944,_0x37ca7e),_0x4c3944['loop']=!![],Object[_0x2b8e07(0xad)](_0x4c3944,_0x25fe3f),_0x4c3944;}function initMainPopup(_0x32a0cc){var _0xd65168=_0x170d25;if(!_0x32a0cc)return;_0x32a0cc[_0xd65168(0xaf)]['display']=_0xd65168(0xc8);var _0x486f0e=qsa(_0xd65168(0xd0),_0x32a0cc)[_0xd65168(0xbf)];if(_0x486f0e<0x1)return;var _0x5f8f97=getData(_0x32a0cc,_0xd65168(0xc7))||_0x32a0cc[_0xd65168(0xab)]('id');if(!_0x5f8f97)return;if(!hasMundaneLicense()){showLicenseNotice();return;}!getCookie(_0x5f8f97)&&(fadeInEl(_0x32a0cc,0x96),matches(_0x32a0cc,OVERLAY_TARGET_SELECTOR)&&initOverlayBehavior(_0x32a0cc));var _0x53e824=qs('.swiper',_0x32a0cc);if(_0x53e824&&window[_0xd65168(0xb1)]){var _0x3eaaba=buildSwiperOptions(_0x32a0cc);if(_0x3eaaba)new Swiper(_0x53e824,_0x3eaaba);}}document[_0x170d25(0xb9)]('click',function(_0x11d852){var _0x2799ad=_0x170d25,_0x4f820e=_0x11d852['target'];if(closest(_0x4f820e,'#'+LICENSE_NOTICE_ID+'\x20.mln-close')){fadeOutEl(qs('#'+LICENSE_NOTICE_ID),0x96);return;}var _0x3f7a52=closest(_0x4f820e,_0x2799ad(0xd3));if(!_0x3f7a52)return;var _0x51dbbd=getData(_0x3f7a52,_0x2799ad(0xc7))||_0x3f7a52[_0x2799ad(0xab)]('id');if(!_0x51dbbd)return;if(closest(_0x4f820e,'.today-btn')){hideToday(_0x51dbbd),fadeOutEl(_0x3f7a52,0x96),fadeOutEl(qs('#'+OVERLAY_ID),0x96);return;}if(closest(_0x4f820e,_0x2799ad(0xc0))){setCookieDays(_0x51dbbd,'Y',0x7),fadeOutEl(_0x3f7a52,0x96),fadeOutEl(qs('#'+OVERLAY_ID),0x96);return;}closest(_0x4f820e,'.close-btn')&&(matches(_0x3f7a52,OVERLAY_TARGET_SELECTOR)?closeOverlayPopup(_0x3f7a52):fadeOutEl(_0x3f7a52,0x96));});function liftPopupColorVarsToRoot(){var _0x26e905=_0x170d25;qsa(_0x26e905(0xd3))[_0x26e905(0xd9)](function(_0x404e86){var _0xd24f68=_0x26e905,_0x15b900=qs(_0xd24f68(0xd2),_0x404e86);if(!_0x15b900)return;var _0x246041=_0x15b900[_0xd24f68(0xab)](_0xd24f68(0xaf));if(!_0x246041)return;var _0x4bd37e=_0x246041['split'](';'),_0xea5ab0=[];for(var _0x73cf9b=0x0;_0x73cf9b<_0x4bd37e[_0xd24f68(0xbf)];_0x73cf9b++){var _0x45b87d=_0x4bd37e[_0x73cf9b][_0xd24f68(0xdb)]();if(!_0x45b87d)continue;var _0xf84198=_0x45b87d[_0xd24f68(0xb0)](':');if(_0xf84198['length']<0x2)continue;var _0x141f56=_0xf84198[0x0]['trim'](),_0x3bcd35=_0xf84198[_0xd24f68(0xd6)](0x1)['join'](':')[_0xd24f68(0xdb)]();_0x3bcd35[_0xd24f68(0xc6)](0x0)==='#'&&_0xea5ab0[_0xd24f68(0xe5)](_0x141f56+':'+_0x3bcd35);}if(_0xea5ab0['length']<0x1)return;var _0x5b3527=_0x404e86[_0xd24f68(0xab)](_0xd24f68(0xaf))||'',_0x528a85=_0x5b3527?_0x5b3527+';'+_0xea5ab0[_0xd24f68(0xde)](';'):_0xea5ab0[_0xd24f68(0xde)](';');_0x404e86['setAttribute'](_0xd24f68(0xaf),_0x528a85);});}document['addEventListener'](_0x170d25(0x9d),function(){var _0x4e00d2=_0x170d25;initMundaneLicenseState(),liftPopupColorVarsToRoot(),!hasMundaneLicense()&&showLicenseNotice(),qsa(_0x4e00d2(0xd3))[_0x4e00d2(0xd9)](function(_0xa198a7){initMainPopup(_0xa198a7);});});
12
13
14window.MUNDANE_SWIPER_PRESETS = window.MUNDANE_SWIPER_PRESETS || {
15    'type-image': {
16        effect: 'fade',
17        fadeEffect: { crossFade: true },
18        autoHeight: true,
19        speed: 1500,
20        autoplay: { delay: 2500, disableOnInteraction: false },
21    },
22    'type-image-text': {
23        effect: 'slide',
24        autoHeight: true,
25        speed: 700,
26        navigation: {
27            prevEl: '.prev-btn',
28            nextEl: '.next-btn'
29        },
30    },
31    'type-text': {
32        effect: 'slide',
33        autoHeight: true,
34        speed: 1500,
35    },
36};
37
38/* =========================
39 * © MUNDANE
40 * 본 파일은 먼데인이 본 스킨을 위해 제작/구성한 커스텀 JavaScript 코드입니다.
41 * 무단 복제, 수정, 재배포 및 타 프로젝트 사용을 금합니다.
42 * ※ 본 스킨은 jQuery, Swiper 등 제3자 라이브러리를 사용할 수 있으며,
43 * 해당 라이브러리의 권리/라이선스는 각 저작권자에게 있습니다.
44========================= */
45
46(function ($) {
47
48    'use strict';
49
50    const MUNLoading = {
51
52        opt: {
53            overlaySelector: '#loading',
54            scopeSelector: '[data-loading-scope]',
55            attrName: 'data-is-loading',
56            fadeInSpeed: 200,
57            fadeOutSpeedMain: 500,
58            fadeOutSpeedSub: 500,
59            firstHideDelay: 200,
60            failSafeMs: 8000,
61            clickDelay: 80,
62            introStorageKey: 'MUN_LOADING_INTRO_SESSION_SEEN',
63            introFirstHideDelay: 900,
64            introFadeOutSpeedMain: 600,
65            introFadeOutSpeedSub: 600
66        },
67
68        state: {
69            isNavigating: false,
70            didInitHide: false,
71            failSafeTimer: null,
72            allowIntro: true,
73            didBindGlobalFailSafe: false
74        },
75
76        setOpt: function (obj) {
77            if (!obj) return;
78            $.extend(true, MUNLoading.opt, obj);
79        },
80
81        init: function () {
82            MUNLoading.bindTransition();
83            MUNLoading.bindBFCacheFix();
84            MUNLoading.bindFailSafe();
85            MUNLoading.applyScope();
86
87            const key = MUNLoading.opt.introStorageKey;
88            const $overlay = $(MUNLoading.opt.overlaySelector);
89            const $introImg = $overlay.find('img');
90
91            try {
92                MUNLoading.state.allowIntro = sessionStorage.getItem(key) !== '1';
93            } catch (e) {
94                MUNLoading.state.allowIntro = true;
95            }
96
97            if (MUNLoading.state.allowIntro) {
98                $introImg.show();
99                try { sessionStorage.setItem(key, '1'); } catch (e) {}
100            } else {
101                $introImg.hide();
102            }
103
104            MUNLoading.hideOnInit();
105
106            $(document)
107                .off('mun:categoryRendered.munLoading')
108                .on('mun:categoryRendered.munLoading', function () {
109                    MUNLoading.applyScope();
110                });
111        },
112
113        applyScope: function () {
114
115            const opt = MUNLoading.opt;
116
117            $(opt.scopeSelector).each(function () {
118
119                const $scope = $(this);
120
121                $scope.find('a').each(function () {
122
123                    const $a = $(this);
124
125                    if (MUNLoading.isSkippable($a)) return;
126                    if ($a.is('[' + opt.attrName + ']')) return;
127
128                    $a.attr(opt.attrName, '1');
129                });
130            });
131        },
132
133        bindTransition: function () {
134
135            const opt = MUNLoading.opt;
136
137            $(document)
138                .off('click.munLoading')
139                .on('click.munLoading', 'a[' + opt.attrName + '="1"]', function (e) {
140
141                    const $a = $(this);
142
143                    if (MUNLoading.isSkippable($a)) return;
144                    if ($a.is('[data-no-loading], [' + opt.attrName + '="0"]')) return;
145
146                    const href = String($a.attr('href') || '').trim();
147                    if (!href) return;
148
149                    e.preventDefault();
150
151                    MUNLoading.state.isNavigating = true;
152                    MUNLoading.show();
153
154                    setTimeout(function () {
155                        location.href = href;
156                    }, opt.clickDelay);
157                });
158        },
159
160        hideOnInit: function () {
161
162            const opt = MUNLoading.opt;
163            const startTime = Date.now();
164
165            const isIntro = !!MUNLoading.state.allowIntro;
166
167            const delay = isIntro ? opt.introFirstHideDelay : opt.firstHideDelay;
168
169            const speed = (function () {
170
171                if (isIntro) {
172                    return ($('#main').length > 0) ? opt.introFadeOutSpeedMain : opt.introFadeOutSpeedSub;
173                }
174
175                return ($('#main').length > 0) ? opt.fadeOutSpeedMain : opt.fadeOutSpeedSub;
176            })();
177
178            function doHide() {
179
180                if (MUNLoading.state.isNavigating) return;
181                if (MUNLoading.state.didInitHide) return;
182
183                MUNLoading.state.didInitHide = true;
184                MUNLoading.hide(speed);
185            }
186
187            setTimeout(function () {
188                doHide();
189            }, delay);
190
191            $(window)
192                .off('load.munLoadingInit')
193                .on('load.munLoadingInit', function () {
194
195                    if (MUNLoading.state.isNavigating) return;
196                    if (MUNLoading.state.didInitHide) return;
197
198                    const elapsed = Date.now() - startTime;
199                    if (elapsed < delay) return;
200
201                    doHide();
202                });
203        },
204
205        bindBFCacheFix: function () {
206
207            $(window)
208                .off('pageshow.munLoading')
209                .on('pageshow.munLoading', function (e) {
210
211                    const persisted = e && e.originalEvent && e.originalEvent.persisted;
212                    if (!persisted) return;
213
214                    MUNLoading.state.isNavigating = false;
215                    MUNLoading.state.didInitHide = true;
216                    MUNLoading.hide(0);
217                });
218        },
219
220        bindFailSafe: function () {
221
222            const opt = MUNLoading.opt;
223
224            if (MUNLoading.state.failSafeTimer) {
225                clearTimeout(MUNLoading.state.failSafeTimer);
226            }
227
228            MUNLoading.state.failSafeTimer = setTimeout(function () {
229                MUNLoading.hide(opt.fadeOutSpeedSub);
230            }, opt.failSafeMs);
231
232            if (MUNLoading.state.didBindGlobalFailSafe) return;
233            MUNLoading.state.didBindGlobalFailSafe = true;
234
235            window.addEventListener('error', function () {
236                MUNLoading.hide(opt.fadeOutSpeedSub);
237            });
238
239            window.addEventListener('unhandledrejection', function () {
240                MUNLoading.hide(opt.fadeOutSpeedSub);
241            });
242        },
243
244        show: function () {
245
246            const opt = MUNLoading.opt;
247            const $overlay = $(opt.overlaySelector);
248            if (!$overlay.length) return;
249
250            $overlay.find('img').hide();
251
252            $overlay.stop(true, true).addClass('on').fadeIn(opt.fadeInSpeed);
253        },
254
255        hide: function (speed) {
256
257            const opt = MUNLoading.opt;
258            const $overlay = $(opt.overlaySelector);
259            if (!$overlay.length) return;
260
261            const s = typeof speed === 'number' ? speed : opt.fadeOutSpeedSub;
262
263            if (s === 0) {
264                $overlay.stop(true, true).hide().removeClass('on');
265                return;
266            }
267
268            $overlay.stop(true, true).fadeOut(s, function () {
269                $overlay.removeClass('on').hide();
270            });
271        },
272
273        isSkippable: function ($a) {
274
275            if (!$a || !$a.length) return true;
276
277            const href = String($a.attr('href') || '').trim();
278            if (!href) return true;
279            if (href === '#' || href === '#;' || href === '#none') return true;
280            if (href.charAt(0) === '#') return true;
281            if (/^javascript:/i.test(href)) return true;
282
283            const target = String($a.attr('target') || '').toLowerCase();
284            if (target === '_blank') return true;
285            if ($a.is('[download]')) return true;
286            if (/^(tel:|mailto:)/i.test(href)) return true;
287            if (MUNLoading.isExternalLink(href)) return true;
288
289            return false;
290        },
291
292        isExternalLink: function (href) {
293
294            const h = String(href || '').trim();
295            if (!h) return false;
296
297            if (!/^(https?:)?\/\//i.test(h)) return false;
298
299            const a = document.createElement('a');
300            a.href = h;
301
302            const linkHost = String(a.hostname || '').toLowerCase();
303            const curHost = String(location.hostname || '').toLowerCase();
304
305            if (!linkHost) return false;
306
307            return linkHost !== curHost;
308        }
309    };
310
311    window.MUNLoading = MUNLoading;
312
313})(jQuery);
314(function ($) {
315
316    'use strict';
317
318    $(function () {
319
320        if (!window.MUNLoading) return;
321
322        const uiOpt = {
323            overlaySelector: '#loading',
324            scopeSelector: '[data-loading-scope]',
325            attrName: 'data-is-loading',
326            fadeInSpeed: 200,
327            fadeOutSpeedMain: 500,
328            fadeOutSpeedSub: 500,
329            firstHideDelay: 200,
330            failSafeMs: 8000,
331            clickDelay: 80,
332            introStorageKey: 'MUN_LOADING_INTRO_SESSION_SEEN',
333            introFirstHideDelay: 900,
334            introFadeOutSpeedMain: 600,
335            introFadeOutSpeedSub: 600
336        };
337
338        window.MUNLoading.setOpt(uiOpt);
339        window.MUNLoading.init();
340
341    });
342
343})(jQuery);
344/* =========================
345 * © MUNDANE
346 * 본 파일은 먼데인이 본 스킨을 위해 제작/구성한 커스텀 JavaScript 코드입니다.
347 * 무단 복제, 수정, 재배포 및 타 프로젝트 사용을 금합니다.
348 * ※ 본 스킨은 jQuery, Swiper 등 제3자 라이브러리를 사용할 수 있으며,
349 * 해당 라이브러리의 권리/라이선스는 각 저작권자에게 있습니다.
350========================= */
351
352
353$(function () {
354
355    const methods = {
356        aSubCategory: {},
357        aCategoryByNo: {},
358
359        get: function () {
360            $.ajax({
361                url: '/exec/front/Product/SubCategory',
362                dataType: 'json',
363                success: function (aData) {
364
365                    if (!aData || !aData.length) return;
366
367                    for (let i = 0; i < aData.length; i++) {
368                        const cate = aData[i];
369                        const parent = cate.parent_cate_no;
370
371                        methods.aCategoryByNo[String(cate.cate_no)] = cate;
372
373                        if (!methods.aSubCategory[parent]) {
374                            methods.aSubCategory[parent] = [];
375                        }
376                        methods.aSubCategory[parent].push(cate);
377                    }
378
379                    $('.category-Area').each(function () {
380                        const $root = $(this);
381                        methods.render($root);
382                    });
383
384                    methods.renderMenuCategory();
385
386                    $(document).trigger('mun:categoryRendered');
387                }
388            });
389        },
390
391        render: function ($root) {
392
393            $root.find('> ul > li').each(function () {
394
395                const $li = $(this);
396                const $a = $li.children('a').first();
397                const href = $a.attr('href');
398                if (!href) return;
399
400                const cateNo = methods.getParam(href, 'cate_no') || methods.getParamSeo(href);
401                if (!cateNo) return;
402
403                const cateObj = methods.aCategoryByNo[String(cateNo)];
404
405                if (cateObj) {
406                    methods.addPageClass($li, cateObj);
407
408                    const newHref = methods.cateLink(cateObj);
409                    if (newHref) {
410                        $a.attr('href', newHref);
411                    }
412                }
413
414                methods.isActive($a);
415
416                const $subTree = methods.renderSub(cateNo, 2, 4);
417                $a.attr('data-is-loading', '1');
418                if ($subTree) {
419                    $li.append($subTree);
420                }
421            });
422
423            $root.find('a.is-active').each(function () {
424                methods.openActivePath($(this));
425            });
426        },
427
428        renderSub: function (parentCateNo, depth, maxDepth) {
429
430            const subList = methods.aSubCategory[parentCateNo];
431
432            if (!subList || subList.length === 0 || depth > maxDepth) {
433                return null;
434            }
435
436            const depthClassMap = {
437                2: 'middle-category',
438                3: 'small-category',
439                4: 'sub-category'
440            };
441
442            const className = depthClassMap[depth] || ('depth-' + depth);
443
444            const $wrapper = $('<div></div>')
445            .addClass(className)
446            .addClass('depth-' + depth);
447
448            const splitDepths = { 2: true, 3: true, 4: true };
449            const onlyWhenMixed = true;
450
451            const makeLi = function (cate) {
452
453                const $li = $('<li></li>');
454
455                const $a = $('<a></a>', {
456                    href: methods.cateLink(cate),
457                    text: cate.name
458                });
459
460                methods.isActive($a);
461
462                $li.append($a);
463
464                const $child = methods.renderSub(cate.cate_no, depth + 1, maxDepth);
465                $a.attr('data-is-loading', '1');
466                if ($child) {
467                    $li.append($child);
468                }
469
470                return $li;
471            };
472
473            const canSplit = !!splitDepths[depth];
474
475            const getPageKey = function (cate) {
476
477                const d = String(cate.design_page_url || '')
478                .replace(/^\//, '')
479                .split('?')[0]
480                .toLowerCase();
481
482                if (d && d !== 'product/list.html') {
483                    return d;
484                }
485
486                return 'product/list.html';
487            };
488
489            const toSlug = function (s) {
490                return String(s || '')
491                    .toLowerCase()
492                    .replace(/^\//, '')
493                    .replace(/\.html.*$/i, '')
494                    .replace(/[^\w\-]+/g, '_')
495                    .replace(/_+/g, '_')
496                    .replace(/^_+|_+$/g, '');
497            };
498
499            if (canSplit) {
500
501                const groups = {};
502                const order = [];
503
504                $.each(subList, function (_, cate) {
505
506                    const key = getPageKey(cate);
507
508                    if (!groups[key]) {
509                        groups[key] = [];
510                        order.push(key);
511                    }
512
513                    groups[key].push(cate);
514                });
515
516                const keyCount = order.length;
517
518                if (!onlyWhenMixed || keyCount > 1) {
519
520                    order.sort(function (a, b) {
521                        const aIsList = (a === 'product/list.html');
522                        const bIsList = (b === 'product/list.html');
523                        if (aIsList && !bIsList) return 1;
524                        if (!aIsList && bIsList) return -1;
525                        return 0;
526                    });
527
528                    $.each(order, function (_, key) {
529
530                        const slug = toSlug(key);
531
532                        const $ul = $('<ul></ul>')
533                        .addClass('cate-ul')
534                        .addClass('cate-ul--' + slug)
535                        .attr('data-page-key', key);
536
537                        $.each(groups[key], function (_, cate) {
538                            $ul.append(makeLi(cate));
539                        });
540
541                        $wrapper.append($ul);
542                    });
543
544                    return $wrapper;
545                }
546            }
547
548            const $ul = $('<ul></ul>');
549            $.each(subList, function (_, cate) {
550                $ul.append(makeLi(cate));
551            });
552
553            $wrapper.append($ul);
554            return $wrapper;
555        },
556
557        addPageClass: function ($li, cate) {
558
559            if (!$li || !$li.length || !cate) return;
560
561            const d = cate.design_page_url;
562
563            if (d && d !== '/product/list.html') {
564                const slug = String(d)
565                .replace(/^\//, '')
566                .replace(/\.html.*$/i, '')
567                .replace(/[^\w\-]+/g, '_')
568                .replace(/_+/g, '_')
569                .replace(/^_+|_+$/g, '');
570
571                if (slug) {
572                    $li.addClass('page-' + slug);
573                }
574            }
575        },
576
577        isActive: function ($a) {
578            if (!$a || !$a.length) return;
579
580            const href = $a.attr('href') || '';
581            if (!href) return;
582            if (/^#/.test(href)) return;
583            if (/^javascript:/i.test(href)) return;
584
585            const currentPath = location.pathname || '';
586            const currentSearch = location.search || '';
587
588            const currentCateNo = methods.getParam(currentSearch, 'cate_no') || methods.getParamSeo(currentPath);
589            let currentBoardNo = methods.getParam(currentSearch, 'board_no');
590
591            if (!currentBoardNo && /^\/board\//.test(currentPath)) {
592                currentBoardNo = methods.getParamSeo(currentPath);
593            }
594
595            if (currentCateNo) {
596                const linkCateNo = methods.getParam(href, 'cate_no') || methods.getParamSeo(methods.getPathname(href));
597                if (linkCateNo && String(linkCateNo) === String(currentCateNo)) {
598                    $a.addClass('is-active');
599                }
600                return;
601            }
602
603            if (currentBoardNo) {
604                const linkBoardNo = methods.getParam(href, 'board_no');
605                if (linkBoardNo && String(linkBoardNo) === String(currentBoardNo)) {
606                    $a.addClass('is-active');
607                }
608                return;
609            }
610
611            const targetPath = methods.getPathname(href);
612            if (targetPath && targetPath === currentPath) {
613                $a.addClass('is-active');
614            }
615        },
616
617        openActivePath: function ($a) {
618            if (!$a || !$a.length) return;
619
620            $a.parents('li').each(function () {
621                const $li = $(this);
622                $li.addClass('is-open');
623            });
624        },
625
626        renderMenuCategory: function () {
627
628            const $titleBox = $('.mun-menu-title');
629            const $navBox = $('.mun-menu-nav');
630
631            if (!$titleBox.length && !$navBox.length) return;
632
633            const opt = {
634                showListOnDepth1: false,
635                showSiblingsOnDepth2WhenEmpty: false,
636                showParentTitleOnDepth2WhenEmpty: false,
637                hideNavWhenEmpty: true,
638                hideTitleWhenEmpty: true
639            };
640            methods.menuOpt = opt;
641
642            const currentPath = location.pathname || '';
643            const currentSearch = location.search || '';
644
645            const currentCateNo = methods.getParam(currentSearch, 'cate_no') || methods.getParamSeo(currentPath);
646
647            if (!currentCateNo) {
648                if ($titleBox.length) $titleBox.hide();
649                if ($navBox.length) $navBox.hide();
650                return;
651            }
652
653            const depth = methods.getDepth(currentCateNo);
654
655            const curObj = methods.aCategoryByNo[String(currentCateNo)] || null;
656            const parentNo = curObj ? String(curObj.parent_cate_no || '') : '';
657
658            const children = methods.aSubCategory[String(currentCateNo)] || [];
659            const siblings = parentNo ? (methods.aSubCategory[parentNo] || []) : [];
660
661            let list = [];
662            let mode = '';
663            let viewDepth = 0;
664
665            if (depth === 1) {
666                if (opt.showListOnDepth1 && children.length > 0) {
667                    list = children;
668                    mode = 'children';
669                    viewDepth = 2;
670                } else {
671                    list = [];
672                }
673            }
674
675            if (depth === 2) {
676                if (children.length > 0) {
677                    list = children;
678                    mode = 'children';
679                    viewDepth = 3;
680                } else {
681                    if (opt.showSiblingsOnDepth2WhenEmpty && siblings.length > 1) {
682                        list = siblings;
683                        mode = 'siblings';
684                        viewDepth = 2;
685                    } else {
686                        list = [];
687                    }
688                }
689            }
690
691            if (depth === 3) {
692                if (children.length > 0) {
693                    list = children;
694                    mode = 'children';
695                    viewDepth = 4;
696                } else {
697                    if (siblings.length > 1) {
698                        list = siblings;
699                        mode = 'siblings';
700                        viewDepth = 3;
701                    } else {
702                        list = [];
703                    }
704                }
705            }
706
707            if (depth >= 4) {
708                if (siblings.length > 1) {
709                    list = siblings;
710                    mode = 'siblings';
711                    viewDepth = depth;
712                } else {
713                    list = [];
714                }
715            }
716
717            const titleText = methods.getMenuTitleText(currentCateNo);
718
719            if ($titleBox.length) {
720                if (titleText) {
721                    $titleBox.show().text(titleText);
722                } else {
723                    if (opt.hideTitleWhenEmpty) $titleBox.hide();
724                    else $titleBox.show().text('');
725                }
726            }
727
728            if (!$navBox.length) return;
729
730            $navBox.empty();
731
732            if (!list || list.length === 0) {
733                if (opt.hideNavWhenEmpty) $navBox.hide();
734                else $navBox.show();
735                return;
736            }
737
738            $navBox.show();
739
740            const $ul = $('<ul></ul>')
741            .addClass('mun-menu-nav__list')
742            .addClass('depth-' + viewDepth)
743            .addClass('mode-' + mode);
744
745            $.each(list, function (_, cate) {
746
747                const $li = $('<li></li>').addClass('mun-menu-nav__item');
748
749                const $a = $('<a></a>', {
750                    href: methods.cateLink(cate),
751                    text: cate.name
752                }).addClass('mun-menu-nav__link');
753
754                methods.isActive($a);
755
756                $li.append($a);
757                $ul.append($li);
758            });
759
760            $navBox.append($ul);
761        },
762
763        getMenuTitleText: function (currentCateNo) {
764
765            const cur = methods.aCategoryByNo[String(currentCateNo)] || null;
766            if (!cur) return '';
767
768            const depth = methods.getDepth(currentCateNo);
769
770            const parent = cur.parent_cate_no ? (methods.aCategoryByNo[String(cur.parent_cate_no)] || null) : null;
771
772            const children = methods.aSubCategory[String(currentCateNo)] || [];
773
774            const parentNo = parent ? String(parent.cate_no) : '';
775            const siblings = parentNo ? (methods.aSubCategory[parentNo] || []) : [];
776
777            if (depth === 1) return cur.name || '';
778            
779            if (depth === 2) {
780                const hasChildren = children.length > 0;
781                const opt = methods.menuOpt || {};
782
783                if (opt.showParentTitleOnDepth2WhenEmpty === true && !hasChildren) {
784                    return parent ? (parent.name || '') : (cur.name || '');
785                }
786                return cur.name || '';
787            }
788
789            if (depth === 3) {
790                const hasSiblings = siblings.length > 1;
791                const hasChildren = children.length > 0;
792
793                if (hasSiblings && !hasChildren) {
794                    return parent ? (parent.name || '') : (cur.name || '');
795                }
796                return cur.name || '';
797            }
798
799            if (depth >= 4) {
800                const hasSiblings = siblings.length > 1;
801                if (hasSiblings) {
802                    return parent ? (parent.name || '') : (cur.name || '');
803                }
804                return cur.name || '';
805            }
806
807            return cur.name || '';
808        },
809
810        getDepth: function (cateNo) {
811            let depth = 0;
812            let cur = String(cateNo || '');
813
814            while (cur && methods.aCategoryByNo[cur]) {
815                depth += 1;
816
817                const parent = methods.aCategoryByNo[cur].parent_cate_no;
818                if (!parent || String(parent) === '0') break;
819
820                cur = String(parent);
821
822                if (depth > 20) break;
823            }
824
825            return depth;
826        },
827
828        cateLink: function (cate) {
829
830            const listLink = cate.link_product_list || '';
831            let prefix = '';
832
833            const m = String(listLink).match(/^\/(shop\d+)(?:\/(skin-[^\/]+))?\//);
834            if (m && m[1]) {
835                prefix = '/' + m[1];
836                if (m[2]) {
837                    prefix = prefix + '/' + m[2];
838                }
839            } else {
840                const m2 = String(listLink).match(/^\/(skin-[^\/]+)\//);
841                if (m2 && m2[1]) {
842                    prefix = '/' + m2[1];
843                }
844            }
845
846            const d = String(cate.design_page_url || '').replace(/^\//, '');
847
848            if (!d || d === 'product/list.html') {
849                return listLink;
850            }
851
852            let base = '/' + d;
853
854            if (prefix) {
855                base = prefix + base;
856            }
857
858            return base + (cate.param || '');
859        },
860
861        getParam: function (sUrl, sKey) {
862            let s = String(sUrl || '');
863
864            if (s.charAt(0) === '?') {
865                s = s.substring(1);
866            }
867
868            const aUrl = s.split('?');
869            const query = aUrl.length > 1 ? aUrl[1] : aUrl[0];
870            if (!query) return null;
871
872            const aFields = query.split('&');
873            for (let i = 0; i < aFields.length; i++) {
874                const aField = aFields[i].split('=');
875                if (aField[0] === sKey) return aField[1];
876            }
877            return null;
878        },
879
880        getParamSeo: function (sUrl) {
881
882            const aUrl = String(sUrl || '').split('/');
883            const seg = aUrl[aUrl.length - 2] || '';
884
885            if (/^\d+$/.test(seg)) return seg;
886
887            return null;
888        },
889
890        getPathname: function (href) {
891            if (!href) return '';
892            const a = document.createElement('a');
893            a.href = href;
894            return a.pathname || '';
895        }
896    };
897
898    window.MUNCategory = methods;
899
900    methods.get();
901
902    $('[data-active-scope] a').each(function () {
903        methods.isActive($(this));
904    });
905
906});
907
908/* =========================
909 * © MUNDANE
910 * 본 파일은 먼데인이 본 스킨을 위해 제작/구성한 커스텀 JavaScript 코드입니다.
911 * 무단 복제, 수정, 재배포 및 타 프로젝트 사용을 금합니다.
912 * ※ 본 스킨은 jQuery, Swiper 등 제3자 라이브러리를 사용할 수 있으며,
913 * 해당 라이브러리의 권리/라이선스는 각 저작권자에게 있습니다.
914========================= */
915
916
917$(function () {
918
919    const methods = window.MUNCategory;
920    if (!methods) return;
921
922    $(document)
923        .off('mun:categoryRendered.munSkinUI')
924        .on('mun:categoryRendered.munSkinUI', function () {
925
926        methods.applyMobileCateUI = function (userOpt) {
927
928            const opt = $.extend({
929                layerBreakpoint: 1024,
930                layerMaxDepth: 3,               
931                autoOpenOnMenuOpen: true,
932                autoOpenMaxListDepth: 2,        
933                storageKeyAuto: 'MUN_MOBILE_CATE_AUTOOPEN'
934            }, (userOpt || {}));
935
936            const $root = $('.mobile-category');
937            if (!$root.length) return;
938
939            const $section3 = $root.find('.section3');
940            if (!$section3.length) return;
941
942            const stack = [];
943
944            function isMobile() {
945                return $(window).width() < opt.layerBreakpoint;
946            }
947
948            function getChildContainer($a) {
949                const $sub = $a.siblings('.middle-category, .small-category, .sub-category');
950                if ($sub.length && $sub.find('> ul > li').length > 0) return $sub.first();
951
952                const $fallback = $a.siblings().filter(function () {
953                    return $(this).find('> ul > li').length > 0 || $(this).find('> ul.cate-ul > li').length > 0;
954                }).first();
955
956                return $fallback;
957            }
958
959            function getClickDepth($a) {
960                const $sub = getChildContainer($a);
961                if ($sub.length) {
962                    const m = String($sub.attr('class') || '').match(/\bdepth-(2|3|4)\b/);
963                    if (m && m[1]) return Number(m[1]) - 1;
964                }
965                return 1;
966            }
967
968            function cleanText($a) {
969                const $copy = $a.clone();
970                $copy.find('.arrows, .arrow').remove();
971                return $.trim($copy.text());
972            }
973
974            function buildShellIfNeeded() {
975                if ($section3.find('.mun-layer-shell').length) return;
976
977                const html = [
978                    '<div class="mun-layer-shell" aria-hidden="true">',
979                    '<div class="mun-layer-head">',
980                    '<button type="button" class="mun-layer-back" aria-label="Back"><strong></strong><span></span></button>',
981                    '<p class="mun-layer-title"></p>',
982                    '</div>',
983                    '<div class="mun-layer-panels">',
984                    '<div class="mun-layer-track"></div>',
985                    '</div>',
986                    '</div>'
987                ].join('');
988
989                $section3.empty().append(html);
990            }
991
992            function setSection3Active(on) {
993                if (on) {
994                    $section3.addClass('active').attr('aria-hidden', 'false');
995                    $section3.find('.mun-layer-shell').attr('aria-hidden', 'false');
996                } else {
997                    $section3.removeClass('active').attr('aria-hidden', 'true');
998                    $section3.find('.mun-layer-shell').attr('aria-hidden', 'true');
999                }
1000            }
1001
1002            function renderPanels() {
1003                buildShellIfNeeded();
1004
1005                const $shell = $section3.find('.mun-layer-shell');
1006                const $track = $shell.find('.mun-layer-track');
1007                const $title = $shell.find('.mun-layer-title');
1008                const $back = $shell.find('.mun-layer-back');
1009
1010                $track.empty();
1011
1012                for (let i = 0; i < stack.length; i += 1) {
1013                    const item = stack[i];
1014                    const $panel = $('<div class="mun-layer-panel"></div>');
1015                    $panel.append(item.$content);
1016                    $track.append($panel);
1017                }
1018
1019                const idx = stack.length - 1;
1020                $track.css({ transform: 'translateX(-' + String(idx * 100) + '%)' });
1021
1022                $title.text(stack.length ? (stack[stack.length - 1].title || '') : '');
1023                $back.toggle(stack.length > 0);
1024
1025                setSection3Active(stack.length > 0);
1026            }
1027
1028            function pushPanelFromAnchor($a) {
1029                const $sub = getChildContainer($a);
1030                if (!$sub.length) return false;
1031
1032                const depth = getClickDepth($a);
1033
1034                if (depth >= opt.layerMaxDepth) return false;
1035
1036                const $content = $('<div class="mun-layer-content"></div>');
1037                $content.append($sub.children().clone(true, true));
1038
1039                if (!$content.children().length) return false;
1040
1041                stack.push({
1042                    title: cleanText($a),
1043                    $content: $content
1044                });
1045
1046                renderPanels();
1047                return true;
1048            }
1049
1050            function popPanel() {
1051                if (!stack.length) return;
1052                stack.pop();
1053                renderPanels();
1054            }
1055
1056            function closeAll() {
1057                stack.length = 0;
1058                setSection3Active(false);
1059                $section3.empty();
1060            }
1061
1062            function markAutoOpenOnNextOpen() {
1063                try {
1064                    sessionStorage.setItem(opt.storageKeyAuto, '1');
1065                } catch (e) {}
1066            }
1067
1068            function clearAutoOpen() {
1069                try {
1070                    sessionStorage.removeItem(opt.storageKeyAuto);
1071                } catch (e) {}
1072            }
1073
1074            function shouldAutoOpen() {
1075                if (!opt.autoOpenOnMenuOpen) return false;
1076                try {
1077                    return sessionStorage.getItem(opt.storageKeyAuto) === '1';
1078                } catch (e) {}
1079                return false;
1080            }
1081
1082            function findDeepestActiveAnchorInSection1() {
1083                const $cands = $root.find('.section1 a.is-active');
1084                if (!$cands.length) return $();
1085
1086                let $best = $();
1087                let bestDepth = -1;
1088
1089                $cands.each(function () {
1090                    const $a = $(this);
1091                    const $li = $a.closest('li');
1092                    if (!$li.length) return;
1093
1094                    let d = 1;
1095                    $li.parents('li').each(function () { d += 1; });
1096
1097                    if (d > bestDepth) {
1098                        bestDepth = d;
1099                        $best = $a;
1100                    }
1101                });
1102
1103                return $best;
1104            }
1105
1106            function autoOpenToActivePath() {
1107                if (!isMobile()) return;
1108                if (!shouldAutoOpen()) return;
1109
1110                const $active = findDeepestActiveAnchorInSection1();
1111                if (!$active.length) return;
1112
1113                const anchors = [];
1114                let $li = $active.closest('li');
1115
1116                while ($li.length) {
1117                    const $a = $li.children('a').first();
1118                    if ($a.length && getChildContainer($a).length) {
1119                        if ($.inArray($a.get(0), $.map(anchors, function (x) { return x.get(0); })) === -1) {
1120                            anchors.push($a);
1121                        }
1122                    }
1123                    $li = $li.parent().closest('li');
1124                }
1125
1126                if (!anchors.length) {
1127                    const $middle = $active.closest('.middle-category');
1128                    if ($middle.length) {
1129                        const $parentA = $middle.prev('a');
1130                        if ($parentA.length && getChildContainer($parentA).length) {
1131                            anchors.push($parentA);
1132                        }
1133                    }
1134                }
1135
1136                anchors.reverse(); 
1137
1138                closeAll();
1139
1140                for (let i = 0; i < anchors.length; i += 1) {
1141                    const $a = anchors[i];
1142                    const depth = getClickDepth($a);
1143
1144                    if (depth >= opt.layerMaxDepth) break;
1145                    if (depth >= opt.autoOpenMaxListDepth) break;
1146
1147                    const ok = pushPanelFromAnchor($a);
1148                    if (!ok) break;
1149                }
1150
1151                const $shell = $section3.find('.mun-layer-shell');
1152                if ($shell.length) {
1153                    const $last = $shell.find('.mun-layer-panel').last();
1154                    const $cur = $last.find('a.is-active').first();
1155                    if ($cur.length && $cur.get(0) && $cur.get(0).scrollIntoView) {
1156                        $cur.get(0).scrollIntoView({ block: 'center' });
1157                    }
1158                }
1159            }
1160
1161            $root
1162                .off('click.munMobileCateLayer')
1163                .on('click.munMobileCateLayer', '.section1 .category-Area a, .section3 .mun-layer-panel a', function (e) {
1164
1165                if (!isMobile()) return;
1166
1167                const $a = $(this);
1168
1169                const pushed = pushPanelFromAnchor($a);
1170                if (pushed) {
1171                    e.preventDefault();
1172                    e.stopImmediatePropagation();
1173                    return;
1174                }
1175
1176                markAutoOpenOnNextOpen();
1177            });
1178
1179            $root
1180                .off('click.munMobileCateLayerBack')
1181                .on('click.munMobileCateLayerBack', '.section3 .mun-layer-back', function () {
1182                if (!isMobile()) return;
1183
1184                clearAutoOpen();
1185
1186                if (stack.length <= 1) {
1187                    closeAll();
1188                    return;
1189                }
1190                popPanel();
1191            });
1192
1193            $(window)
1194                .off('resize.munMobileCateLayer')
1195                .on('resize.munMobileCateLayer', function () {
1196                if (!isMobile()) closeAll();
1197            });
1198
1199            methods.openMobileCateLayerAuto = function () {
1200                autoOpenToActivePath();
1201            };
1202
1203            methods.closeMobileCateLayer = function () {
1204                closeAll();
1205            };
1206        };
1207
1208
1209
1210        methods.applyMobileCateAnimation = function () {
1211
1212            const $mobile = $('.mobile-category');
1213            if (!$mobile.length) return;
1214
1215            const $sec1 = $mobile.find('.section1').first();
1216            const $sec2 = $mobile.find('.section2').first();
1217
1218            if (!$sec1.length && !$sec2.length) return;
1219
1220            let order = 1;
1221
1222            if ($sec1.length) {
1223                $sec1.addClass('animation-list').css({ '--animation-order': order });
1224                order += 1;
1225            }
1226
1227            if ($sec2.length) {
1228
1229                const attrStart1 = $sec2.attr('data-anim-start');
1230                const attrStart2 = $sec2.attr('animation_order');
1231                const startRaw = (attrStart1 != null ? attrStart1 : attrStart2);
1232
1233                let start = order;
1234                if (startRaw != null && !isNaN(Number(startRaw))) {
1235                    start = Number(startRaw);
1236                }
1237
1238                const $targets = $sec2.find('.group');
1239
1240                let idx = 0;
1241                $targets.each(function () {
1242
1243                    const $el = $(this);
1244
1245                    if ($el.hasClass('displaynone')) return;
1246                    if ($el.is(':hidden')) return;
1247
1248                    $el.addClass('animation-list').css({ '--animation-order': start + idx });
1249                    idx += 1;
1250                });
1251            }
1252        };
1253
1254
1255        methods.applyMobileCateUI();
1256        //methods.applyMobileCateAnimation();
1257    });
1258
1259});
1260
1261/* =========================
1262 * © MUNDANE
1263 * 본 파일은 먼데인이 본 스킨을 위해 제작/구성한 커스텀 JavaScript 코드입니다.
1264 * 무단 복제, 수정, 재배포 및 타 프로젝트 사용을 금합니다.
1265 * ※ 본 스킨은 jQuery, Swiper 등 제3자 라이브러리를 사용할 수 있으며,
1266 * 해당 라이브러리의 권리/라이선스는 각 저작권자에게 있습니다.
1267========================= */
1268
1269$(function () {
1270
1271    if (!window.MUN) window.MUN = {};
1272    if (!window.MUN.product) window.MUN.product = {};
1273
1274    const H = window.MUN.helper || {};
1275
1276    const Product = {
1277
1278        init: function () {
1279            Product.bindModal();
1280            Product.bindSort();
1281            Product.bindThumbHover();
1282
1283            Product.applyTo($('.ec-base-product'));
1284
1285            Product.observeMoreProducts();
1286        },
1287
1288        applyTo: function ($scope) {
1289            if (!$scope || !$scope.length) return;
1290
1291            Product.applySoldout($scope);
1292
1293            if (window.MUN && window.MUN.ui && typeof window.MUN.ui.runFadeLight === 'function') {
1294                window.MUN.ui.runFadeLight();
1295            }
1296            if (window.MUN && window.MUN.ui && typeof window.MUN.ui.collectFadeSections === 'function') {
1297                window.MUN.ui.collectFadeSections();
1298                if (typeof window.MUN.ui.runFadeSection === 'function') {
1299                    window.MUN.ui.runFadeSection();
1300                }
1301            }
1302        },
1303
1304        bindModal: function () {
1305
1306            const $modal = $('#M_modal');
1307            if (!$modal.length) return;
1308
1309            $(document).off('click.munModalOpen')
1310            .on('click.munModalOpen', '.M_modal .mun-prd-thumb a', function (e) {
1311                e.preventDefault();
1312
1313                const href = $(this).attr('href') || '';
1314                if (!href) return;
1315
1316                $modal.scrollTop(0);
1317
1318                $modal.load(href, function () {
1319                    $('html').addClass('modal');
1320                });
1321            });
1322
1323            $(document).off('click.munModalClose')
1324            .on('click.munModalClose', '#M_modal', function (e) {
1325                if (e.target !== this) return;
1326                $('html').removeClass('modal');
1327            });
1328        },
1329
1330        bindSort: function () {
1331
1332            $(document).off('click.munSortToggle')
1333            .on('click.munSortToggle', '.product-sort.title', function (e) {
1334                e.preventDefault();
1335                $(this).toggleClass('state');
1336            });
1337
1338            $(document).off('click.munSortLink')
1339            .on('click.munSortLink', '.product-sort.link a', function (e) {
1340                e.preventDefault();
1341
1342                const link = $(this).attr('link') || $(this).attr('href') || '';
1343                if (!link) return;
1344
1345                const base = (location.href.split('&')[0] || '').replace('#;', '');
1346                location.replace(base + link);
1347            });
1348        },
1349
1350        applySoldout: function ($scope) {
1351
1352            const $targets = $scope.find('.mun-prd-list');
1353
1354            $targets.each(function () {
1355                const $root = $(this);
1356
1357                if ($root.data('munSoldoutDone') === 1) return;
1358
1359                if ($root.find('.mun-prd-sold_out img').length) {
1360                    $root.addClass('soldout');
1361                    $root.find('.mun-prd-sold_out img').remove();
1362                }
1363
1364                $root.data('munSoldoutDone', 1);
1365            });
1366        },
1367
1368        bindThumbHover: function () {
1369
1370            const $list = $('.ec-base-product');
1371            if (!$list.length) return;
1372
1373            $(document).off('mouseenter.munPrdHover mouseleave.munPrdHover')
1374            .on('mouseenter.munPrdHover', '.mun-prd-thumb', function () {
1375                $(this).closest('.mun-prd-list').addClass('hover');
1376            })
1377            .on('mouseleave.munPrdHover', '.mun-prd-list-cover', function () {
1378                $(this).closest('.mun-prd-list').removeClass('hover');
1379            });
1380
1381            $(document).off('touchstart.munPrdHover')
1382            .on('touchstart.munPrdHover', '.mun-prd-thumb img', function () {
1383                if (typeof H.winW === 'function' && H.winW() >= 1024) return;
1384                if (!H.winW && $(window).width() >= 1024) return;
1385
1386                const $li = $(this).closest('.mun-prd-list');
1387                if ($li.hasClass('hover')) return;
1388
1389                $('.mun-prd-list').removeClass('hover');
1390                $li.addClass('hover');
1391            });
1392        },
1393
1394        observeMoreProducts: function () {
1395
1396            if (!H || typeof H.observeAddedNodes !== 'function') return;
1397
1398            const $root = $('.ec-base-product .prdList');
1399            if (!$root.length) return;
1400
1401            H.observeAddedNodes($root, function ($node) {
1402
1403                const $li = $node.is('li') ? $node : $node.find('li').first();
1404                if (!$li.length) return;
1405
1406                Product.applyTo($li.closest('.ec-base-product').length ? $li.closest('.ec-base-product') : $li);
1407            });
1408        }
1409    };
1410
1411    window.MUN.product = Product;
1412
1413    Product.init();
1414
1415});
1416/* =========================
1417 * © MUNDANE
1418 * 본 파일은 먼데인이 본 스킨을 위해 제작/구성한 커스텀 JavaScript 코드입니다.
1419 * 무단 복제, 수정, 재배포 및 타 프로젝트 사용을 금합니다.
1420 * ※ 본 스킨은 jQuery, Swiper 등 제3자 라이브러리를 사용할 수 있으며,
1421 * 해당 라이브러리의 권리/라이선스는 각 저작권자에게 있습니다.
1422========================= */
1423
1424$(function () {
1425
1426    if (!window.MUN) window.MUN = {};
1427    const H = window.MUN.helper || {};
1428
1429    const MUNMultiPopup = {
1430
1431        sel: {
1432            openBtn: '.multi_popup_btn',
1433            closeBtn: '.multi_popup_close_btn',
1434            popup: '#multi_popup',
1435            listLink: '.multi_popup_list a',
1436            listItem: '.multi_popup_list li',
1437            globalBtnLi: '.group.sub.multi'
1438        },
1439
1440        textMap: {
1441            '한국어': '한국어 (KR | KRW)',
1442            'English': 'English (EN | USD)',
1443            '日本語': '日本語 (JP | JPY)',
1444            '中文': '中文 (CN | CNY)'
1445        },
1446
1447        init: function () {
1448            MUNMultiPopup.bind();
1449            MUNMultiPopup.renameListText();
1450            MUNMultiPopup.toggleGlobalButton();
1451        },
1452
1453        bind: function () {
1454
1455            $(document).off('click.munMultiPopupOpen')
1456                .on('click.munMultiPopupOpen', MUNMultiPopup.sel.openBtn, function (e) {
1457                e.preventDefault();
1458                $(MUNMultiPopup.sel.popup).addClass('active');
1459            });
1460
1461            $(document).off('click.munMultiPopupClose')
1462                .on('click.munMultiPopupClose', MUNMultiPopup.sel.closeBtn, function (e) {
1463                e.preventDefault();
1464                $(MUNMultiPopup.sel.popup).removeClass('active');
1465            });
1466        },
1467
1468        renameListText: function () {
1469
1470            const map = MUNMultiPopup.textMap;
1471
1472            $(MUNMultiPopup.sel.listLink).each(function () {
1473
1474                const $a = $(this);
1475                const t = $.trim($a.text());
1476
1477                if (map[t]) {
1478                    $a.text(map[t]);
1479                    return;
1480                }
1481
1482                for (const key in map) {
1483                    if (t.indexOf(key) > -1) {
1484                        $a.text(map[key]);
1485                        break;
1486                    }
1487                }
1488            });
1489        },
1490
1491        toggleGlobalButton: function () {
1492
1493            const $items = $(MUNMultiPopup.sel.listItem);
1494            const $globalLi = $(MUNMultiPopup.sel.globalBtnLi);
1495
1496            if ($items.length <= 1) {
1497                $globalLi.addClass('displaynone');
1498            } else {
1499                $globalLi.removeClass('displaynone');
1500            }
1501        }
1502    };
1503
1504    const UI = {
1505
1506        fadeLightState: {
1507            ticking: false
1508        },
1509
1510        fadeSectionState: {
1511            ticking: false,
1512            sections: []
1513        },
1514
1515        init: function () {
1516            MUNMultiPopup.init();
1517
1518            UI.applyBackgroundType();
1519            UI.replaceRequiredDot();
1520            UI.replacePaginateIcons();
1521            UI.applyPlaceholderFromTitle();
1522            UI.applyAddOptionPlaceholder();
1523            UI.applyOptionSelectTitle();
1524            UI.applyFormTextWrap();
1525            UI.bindToggleList();
1526            UI.applyDetailAddOptionTitleCut();
1527            UI.applyMunCut();
1528            UI.hidePromotionDate();
1529            UI.fixQuantityDummy();
1530            UI.initFadeLight();
1531            UI.initFadeSection();
1532            UI.observeMoreFadeTargets();
1533        },
1534
1535        initFadeLight: function () {
1536            UI.bindFadeLight();
1537            UI.runFadeLight();
1538
1539            $(window).off('load.munFadeLight').on('load.munFadeLight', function () {
1540                UI.runFadeLight();
1541            });
1542        },
1543
1544        bindFadeLight: function () {
1545
1546            const onScrollResize = function () {
1547                if (UI.fadeLightState.ticking) return;
1548                UI.fadeLightState.ticking = true;
1549
1550                window.requestAnimationFrame(function () {
1551                    UI.fadeLightState.ticking = false;
1552                    UI.runFadeLight();
1553                });
1554            };
1555
1556            $(window).off('scroll.munFadeLight resize.munFadeLight')
1557            .on('scroll.munFadeLight resize.munFadeLight', onScrollResize);
1558        },
1559
1560        runFadeLight: function () {
1561
1562            const offsetRatio = 1.1;
1563            const activeClass = 'fade-in';
1564
1565            const st = $(window).scrollTop();
1566            const wh = $(window).height();
1567            const triggerY = st + (wh / offsetRatio);
1568
1569            $('.fade').each(function () {
1570
1571                const $el = $(this);
1572
1573                if ($el.data('munFaded') === 1) return;
1574                if ($el.hasClass(activeClass)) {
1575                    $el.data('munFaded', 1);
1576                    return;
1577                }
1578
1579                const top = $el.offset().top;
1580
1581                if (triggerY >= top) {
1582                    $el.addClass(activeClass);
1583                    $el.data('munFaded', 1);
1584                }
1585            });
1586        },
1587
1588        initFadeSection: function () {
1589            UI.collectFadeSections();
1590            UI.bindFadeSection();
1591            UI.runFadeSection();
1592
1593            $(window).off('load.munFadeSectionInit').on('load.munFadeSectionInit', function () {
1594                UI.collectFadeSections();
1595                UI.runFadeSection();
1596            });
1597        },
1598
1599        collectFadeSections: function () {
1600
1601            UI.fadeSectionState.sections = [];
1602
1603            $('.fade_section').each(function () {
1604
1605                const $section = $(this);
1606                const items = [];
1607
1608                $section.find('.fade-list').each(function () {
1609
1610                    const $el = $(this);
1611
1612                    const prop = $el.attr('transition_property') || '';
1613                    const move = Number($el.attr('fade_set_top') || 0);
1614                    const delay = Number($el.attr('fade_set_delay') || 0);
1615                    const speed = Number($el.attr('fade_set_speed') || 0.6);
1616                    const sizePct = Number($el.attr('fade_set_size') || 0);
1617
1618                    if (!$el.data('munFadeInit')) {
1619                        $el.data('munFadeInit', 1);
1620
1621                        if (!prop || prop === 'top') {
1622                            $el.css({
1623                                'opacity': '0',
1624                                'top': move + 'px',
1625                                'transition-property': 'opacity,top',
1626                                'transition-duration': speed + 's',
1627                                'transition-delay': delay + 's',
1628                                'transition-timing-function': 'ease'
1629                            });
1630                        } else if (prop === 'left') {
1631                            $el.css({
1632                                'opacity': '0',
1633                                'left': move + 'px',
1634                                'transition-property': 'opacity,left',
1635                                'transition-duration': speed + 's',
1636                                'transition-delay': delay + 's',
1637                                'transition-timing-function': 'ease'
1638                            });
1639                        } else {
1640                            $el.css({
1641                                'opacity': '0',
1642                                'transition-property': 'opacity',
1643                                'transition-duration': speed + 's',
1644                                'transition-delay': delay + 's',
1645                                'transition-timing-function': 'ease'
1646                            });
1647                        }
1648
1649                        if (sizePct > 0) {
1650                            const wh = window.innerHeight || $(window).height();
1651                            $el.height(wh * (sizePct / 100));
1652                        }
1653                    }
1654
1655                    items.push({ $el: $el, prop: prop });
1656                });
1657
1658                if (items.length) {
1659                    UI.fadeSectionState.sections.push({ $section: $section, items: items });
1660                }
1661            });
1662        },
1663
1664        bindFadeSection: function () {
1665
1666            const onScrollResize = function () {
1667                if (UI.fadeSectionState.ticking) return;
1668                UI.fadeSectionState.ticking = true;
1669
1670                window.requestAnimationFrame(function () {
1671                    UI.fadeSectionState.ticking = false;
1672                    UI.runFadeSection();
1673                });
1674            };
1675
1676            $(window).off('scroll.munFadeSection resize.munFadeSection')
1677            .on('scroll.munFadeSection resize.munFadeSection', onScrollResize);
1678        },
1679
1680        runFadeSection: function () {
1681
1682            const sections = UI.fadeSectionState.sections;
1683            if (!sections.length) return;
1684
1685            const offsetRatio = 1.1;
1686            const sectionOffset = -120;
1687
1688            const st = $(window).scrollTop();
1689            const wh = $(window).height();
1690            const triggerY = st + (wh / offsetRatio);
1691
1692            for (let i = 0; i < sections.length; i++) {
1693
1694                const sec = sections[i];
1695                const secTop = sec.$section.offset().top + sectionOffset;
1696
1697                if (triggerY < secTop) continue;
1698
1699                for (let j = 0; j < sec.items.length; j++) {
1700
1701                    const it = sec.items[j];
1702                    const $el = it.$el;
1703
1704                    if ($el.data('munFadedSection') === 1) continue;
1705                    $el.data('munFadedSection', 1);
1706
1707                    if (!it.prop || it.prop === 'top') {
1708                        $el.css({ 'opacity': '1', 'top': '0px' });
1709                    } else if (it.prop === 'left') {
1710                        $el.css({ 'opacity': '1', 'left': '0px' });
1711                    } else {
1712                        $el.css({ 'opacity': '1' });
1713                    }
1714                }
1715            }
1716        },
1717
1718        observeMoreFadeTargets: function () {
1719
1720            if (!H || typeof H.observeAddedNodes !== 'function') return;
1721
1722            const $roots = $('.ec-base-product .prdList, #contents, #wrap');
1723
1724            $roots.each(function () {
1725
1726                const $root = $(this);
1727                if (!$root.length) return;
1728
1729                H.observeAddedNodes($root, function ($node) {
1730
1731                    if ($node.find('.fade').length || $node.hasClass('fade')) {
1732                        UI.runFadeLight();
1733                    }
1734
1735                    if ($node.find('.fade_section').length || $node.hasClass('fade_section')) {
1736                        UI.collectFadeSections();
1737                        UI.runFadeSection();
1738                    }
1739                });
1740            });
1741        },
1742
1743        applyBackgroundType: function () {
1744            $('.background-type').each(function () {
1745                const $el = $(this);
1746                const $img = $el.find('img').first();
1747                const src = $img.attr('src') || '';
1748
1749                if (src) {
1750                    $el.css('background-image', 'url(' + src + ')');
1751                    $img.remove();
1752                }
1753
1754                const pct = Number($el.attr('data-bg-height-percent') || 0);
1755                if (pct > 0) {
1756                    const h = (window.innerHeight || $(window).height()) * (pct / 100);
1757                    $el.height(h);
1758                }
1759            });
1760        },
1761
1762        replaceRequiredDot: function () {
1763            const dot = '/web/upload/mundane/grey_dot.png';
1764
1765            $('img').each(function () {
1766                const $img = $(this);
1767                const src = $img.attr('src') || '';
1768
1769                if (
1770                    src === '//img.echosting.cafe24.com/skin/base/order/ico_required.gif' ||
1771                    src === '//img.echosting.cafe24.com/skin/base_ko_KR/order/ico_required.gif' ||
1772                    src === '//img.echosting.cafe24.com/skin/base/common/ico_required_blue.gif'
1773                ) {
1774                    $img.attr('src', dot);
1775                }
1776            });
1777        },
1778
1779        replacePaginateIcons: function () {
1780            const prev = '/web/upload/mundane/i_arrival_prev.png';
1781            const next = '/web/upload/mundane/i_arrival_next.png';
1782
1783            const $p = $('.ec-base-paginate');
1784            if (!$p.length) return;
1785
1786            $p.find('> a:nth-of-type(1) img').attr('src', prev);
1787            $p.find('> a:nth-of-type(2) img').attr('src', next);
1788        },
1789
1790        applyPlaceholderFromTitle: function () {
1791            $('.ePlaceholder input, .ePlaceholder textarea').each(function () {
1792                const $inp = $(this);
1793                const title = $inp.parents('[title]').first().attr('title') || '';
1794                if (title) $inp.attr('placeholder', title);
1795            });
1796        },
1797
1798        applyAddOptionPlaceholder: function () {
1799            $('.ePlaceholder_addoption input').each(function () {
1800                const $inp = $(this);
1801                const t = $inp.closest('.mun-detail-desc').find('.mun-detail-title').first().text() || '';
1802                const v = $.trim(t);
1803                if (v) $inp.attr('placeholder', v);
1804            });
1805        },
1806
1807        applyOptionSelectTitle: function () {
1808            $('#mun_option .mun-option select').each(function () {
1809                const $sel = $(this);
1810                const t = $sel.attr('option_title') || '';
1811                if (!t) return;
1812                $sel.children('option:first-child').text(t);
1813            });
1814        },
1815
1816        applyFormTextWrap: function () {
1817            const $targets = $('.mun-formSP, .mun-formSE, .mun-formcalendar');
1818            if (!$targets.length) return;
1819
1820            $targets.each(function () {
1821                if (typeof H.wrapTextNodes === 'function') {
1822                    H.wrapTextNodes($(this), 'mun-formText');
1823                } else {
1824                    $(this).contents().filter(function () {
1825                        return this.nodeType === 3;
1826                    }).wrap('<span class="mun-formText"></span>');
1827                }
1828            });
1829        },
1830
1831        bindToggleList: function () {
1832            $(document).off('click.munToggleList')
1833            .on('click.munToggleList', '.ec-base-table.toggleList .toggleList-btn', function (e) {
1834                e.preventDefault();
1835                $(this).closest('.ec-base-table.toggleList').toggleClass('view');
1836            });
1837        },
1838
1839        applyDetailAddOptionTitleCut: function () {
1840            $('.mun-option-addoption .mun-detail-title').each(function () {
1841                const $t = $(this);
1842                const s = $t.text() || '';
1843                const head = s.split('[')[0];
1844                $t.text($.trim(head));
1845            });
1846        },
1847
1848        applyMunCut: function () {
1849            $('.mun_cut').each(function () {
1850                const $el = $(this);
1851                const n = Number($el.attr('data-cut') || $el.attr('mun_cut') || 0);
1852                if (!n) return;
1853
1854                const t = $el.text() || '';
1855
1856                if (typeof H.cutText === 'function') {
1857                    $el.text(H.cutText(t, n));
1858                } else {
1859                    if (t.length > n) $el.text(t.substr(0, n) + '...');
1860                }
1861            });
1862        },
1863
1864        hidePromotionDate: function () {
1865            const $t = $('.mun-detail-desc .product_promotion_date');
1866            if ($t.length) {
1867                $t.parent().css('display', 'none');
1868            }
1869        },
1870
1871        fixQuantityDummy: function () {
1872            if ($('#NewProductQuantityDummy').length > 0 && $('#totalProducts').length > 0) {
1873                $('#NewProductQuantityDummy').parents('li.mun-detail-list').remove();
1874            }
1875        }
1876    };
1877
1878    window.MUN.ui = UI;
1879
1880    UI.init();
1881
1882});
1883/* =========================
1884 * © MUNDANE
1885 * 본 파일은 먼데인이 본 스킨을 위해 제작/구성한 커스텀 JavaScript 코드입니다.
1886 * 무단 복제, 수정, 재배포 및 타 프로젝트 사용을 금합니다.
1887 * ※ 본 스킨은 jQuery, Swiper 등 제3자 라이브러리를 사용할 수 있으며,
1888 * 해당 라이브러리의 권리/라이선스는 각 저작권자에게 있습니다.
1889========================= */
1890
1891(function (window, $) {
1892
1893    if (!window.MUN) window.MUN = {};
1894
1895    const MUNHelper = {
1896
1897        trim: function (v) {
1898            return $.trim(String(v || ''));
1899        },
1900
1901        winW: function () {
1902            return window.innerWidth || $(window).width();
1903        },
1904
1905        cutText: function (text, maxLen) {
1906            const s = String(text || '');
1907            const n = Number(maxLen || 0);
1908            if (!n || n <= 0) return s;
1909            if (s.length <= n) return s;
1910            return s.substr(0, n) + '...';
1911        },
1912
1913        wrapTextNodes: function ($root, wrapClass) {
1914            const cls = String(wrapClass || 'mun-formText');
1915            $root.contents().filter(function () {
1916                return this.nodeType === 3 && $.trim(this.nodeValue).length > 0;
1917            }).wrap('<span class="' + cls + '"></span>');
1918        },
1919
1920        nsOffOn: function ($el, onType, ns, handler) {
1921            $el.off(onType + '.' + ns).on(onType + '.' + ns, handler);
1922        }
1923    };
1924
1925    window.MUN.helper = MUNHelper;
1926
1927})(window, jQuery);
1928
1929/* =========================
1930 * © MUNDANE
1931 * 본 파일은 먼데인이 본 스킨을 위해 제작/구성한 커스텀 JavaScript 코드입니다.
1932 * 무단 복제, 수정, 재배포 및 타 프로젝트 사용을 금합니다.
1933 * ※ 본 스킨은 jQuery, Swiper 등 제3자 라이브러리를 사용할 수 있으며,
1934 * 해당 라이브러리의 권리/라이선스는 각 저작권자에게 있습니다.
1935========================= */
1936
1937$(function () {
1938
1939    if (!window.MUN) window.MUN = {};
1940    const H = window.MUN.helper;
1941
1942    const Layout = {
1943
1944        sel: {
1945            logoBox: '.logo .app-box',
1946            logoImg: '.logo_img img',
1947            mobileBtn: '.mobile-btn',
1948            searchBtn: '.search-btn',
1949            bgOpacity: '#background-opacity',
1950
1951            headerNotice: '#header_notice',
1952            headerNoticeClose: '.header-notice-close',
1953            headerNoticeMargin: '.header_notice_margin',
1954            headerNoticePadding: '.header_notice_padding',
1955
1956            winHeight: '.window-height',
1957            winHeightLayout: '.window-height-layout',
1958            winHeightLayoutN: '.window-height-layoutN',
1959            winHeightLayoutNC: '.window-height-layoutNC',
1960            winHeightLayoutMH: '.window-height-layoutMH',
1961            winHeightContent: '.window-height-content',
1962            winHeightMargin: '.window-height-margin',
1963            stickyTopLayout: '.sticky-top-layout',
1964            stickyTopNoticeH: '.sticky-top-noticeH',
1965
1966            header: '#header',
1967            headerPadding: '.header_layout_padding',
1968            headerMargin: '.header_layout_margin'
1969        },
1970
1971        key: {
1972            headerNotice: 'header_notice'
1973        },
1974
1975        init: function () {
1976            Layout.applyLogoRule();
1977            Layout.bindMobileSlide();
1978            Layout.bindSearchPopup();
1979
1980            Layout.initHeaderNoticeSwiper();
1981            Layout.applyHeaderNoticeHeight();
1982            Layout.applyMediaSize();
1983
1984            Layout.bindResize();
1985            Layout.bindPageshowFix();
1986
1987            $(window).on('load.munLayout', function () { Layout.applyMediaSize(); });
1988        },
1989
1990        applyLogoRule: function () {
1991            $(Layout.sel.logoBox).each(function () {
1992                const $box = $(this);
1993                const $img = $box.find(Layout.sel.logoImg);
1994                const src = $img.attr('src') || '';
1995
1996                if (src && src.length > 0) {
1997                    $box.find('.logo_text').remove();
1998                } else {
1999                    $box.find('.logo_img').remove();
2000                }
2001            });
2002        },
2003
2004        opt: {
2005            // 모바일 슬라이드 열 때 검색을 닫을지
2006            closeSearchWhenOpenMobileSlide: true,
2007
2008            // 검색 열 때 모바일 슬라이드를 닫을지
2009            closeMobileSlideWhenOpenSearch: true,
2010
2011            // bgOpacity 클릭 시 모바일 슬라이드 닫을지
2012            closeMobileSlideOnBg: true,
2013
2014            // bgOpacity 클릭 시 검색 닫을지
2015            closeSearchOnBg: true
2016        },
2017        
2018        bindMobileSlide: function () {
2019
2020            $(document).off('click.munMobileSlideOpen')
2021                .on('click.munMobileSlideOpen', Layout.sel.mobileBtn, function (e) {
2022                e.preventDefault();
2023
2024                // 옵션: 모바일 슬라이드 열릴 때 검색 닫기
2025                if (Layout.opt.closeSearchWhenOpenMobileSlide) {
2026                    $('html').removeClass('search');
2027                }
2028
2029                $('html').toggleClass('mobile-slide');
2030
2031                const methods = window.MUNCategory;
2032
2033                if ($('html').hasClass('mobile-slide')) {
2034                    if (methods && typeof methods.openMobileCateLayerAuto === 'function') {
2035                        methods.openMobileCateLayerAuto();
2036                    }
2037                } else {
2038                    if (methods && typeof methods.closeMobileCateLayer === 'function') {
2039                        methods.closeMobileCateLayer();
2040                    }
2041                }
2042            });
2043
2044            $(document).off('click.munMobileSlideClose')
2045                .on('click.munMobileSlideClose', Layout.sel.bgOpacity, function (e) {
2046                e.preventDefault();
2047
2048                // 옵션: bg 클릭 시 모바일 슬라이드 닫기
2049                if (Layout.opt.closeMobileSlideOnBg) {
2050                    $('html').removeClass('mobile-slide');
2051
2052                    const methods = window.MUNCategory;
2053                    if (methods && typeof methods.closeMobileCateLayer === 'function') {
2054                        methods.closeMobileCateLayer();
2055                    }
2056                }
2057
2058                // 옵션: bg 클릭 시 검색 닫기
2059                if (Layout.opt.closeSearchOnBg) {
2060                    $('html').removeClass('search');
2061                }
2062            });
2063        },
2064        
2065        bindSearchPopup: function () {
2066
2067            $(document).off('click.munSearchOpen')
2068                .on('click.munSearchOpen', Layout.sel.searchBtn, function (e) {
2069                e.preventDefault();
2070
2071                // 옵션: 검색 열릴 때 모바일 슬라이드 닫기
2072                if (Layout.opt.closeMobileSlideWhenOpenSearch) {
2073                    $('html').removeClass('mobile-slide');
2074
2075                    const methods = window.MUNCategory;
2076                    if (methods && typeof methods.closeMobileCateLayer === 'function') {
2077                        methods.closeMobileCateLayer();
2078                    }
2079                }
2080
2081                $('html').toggleClass('search');
2082            });
2083
2084            $(document).off('click.munSearchClose')
2085                .on('click.munSearchClose', '.search-background', function (e) {
2086                e.preventDefault();
2087                $('html').removeClass('search');
2088            });
2089
2090            $(document).off('click.munSearchCloseByBg')
2091                .on('click.munSearchCloseByBg', Layout.sel.bgOpacity, function () {
2092                if (Layout.opt.closeSearchOnBg) {
2093                    $('html').removeClass('search');
2094                }
2095            });
2096
2097            const v = $('.M_search_target').text();
2098            if (v) {
2099                $('#category_no option[value="' + v + '"]').prop('selected', true);
2100            }
2101        },
2102
2103        initHeaderNoticeSwiper: function () {
2104
2105            if (typeof Swiper !== 'function') return;
2106
2107            const $wrap = $('.header_notice_slide');
2108            if (!$wrap.length) return;
2109
2110            const slideCnt = $wrap.find('.swiper-slide').length;
2111
2112            const opt = {
2113                direction: 'vertical',
2114                autoHeight: true,
2115                slidesPerView: 1,
2116                slidesPerGroup: 1,
2117                touchRatio: 0,
2118                autoplay: { delay: 2000, disableOnInteraction: false },
2119                speed: 1000,
2120                watchOverflow: true,
2121                loop: slideCnt > 1
2122            };
2123
2124            try {
2125                new Swiper('.header_notice_slide', opt);
2126            } catch (e) {
2127            }
2128        },
2129
2130        applyHeaderNoticeHeight: function () {
2131
2132            const $notice = $(Layout.sel.headerNotice);
2133            if (!$notice.length) return;
2134
2135            const isClosed = sessionStorage.getItem(Layout.key.headerNotice) === 'close';
2136
2137            if (isClosed) {
2138                $notice.remove();
2139                Layout.applyMediaSize();
2140                Layout.applyHeaderNoticePadding(0);
2141                Layout.applyHeaderNoticeMargin(0);
2142                return;
2143            }
2144
2145            const h = $notice.outerHeight() || 0;
2146            Layout.applyHeaderNoticePadding(h);
2147            Layout.applyHeaderNoticeMargin(h);
2148
2149            $(document).off('click.munHeaderNoticeClose')
2150                .on('click.munHeaderNoticeClose', Layout.sel.headerNoticeClose, function (e) {
2151                e.preventDefault();
2152
2153                sessionStorage.setItem(Layout.key.headerNotice, 'close');
2154
2155                const $n = $(Layout.sel.headerNotice);
2156                $n.stop(true, true).slideUp(200, function () {
2157                    $n.remove();
2158                    Layout.applyHeaderNoticePadding(0);
2159                    Layout.applyHeaderNoticeMargin(0);
2160                    Layout.applyMediaSize();
2161                });
2162            });
2163        },
2164
2165        applyHeaderNoticePadding: function (px) {
2166            const n = Number(px || 0);
2167            const $p = $(Layout.sel.headerNoticePadding);
2168            if ($p.length) $p.css('padding-top', n);
2169        },
2170
2171        applyHeaderNoticeMargin: function (px) {
2172            const n = Number(px || 0);
2173            const $m = $(Layout.sel.headerNoticeMargin);
2174            if ($m.length) $m.css('margin-top', n);
2175        },
2176
2177        applyMediaSize: function () {
2178
2179            const wh = window.innerHeight || $(window).height();
2180
2181            const $header = $(Layout.sel.header);
2182            const headerH = $header.length ? ($header.innerHeight() || $header.height() || 0) : 0;
2183
2184            const $notice = $(Layout.sel.headerNotice);
2185            const noticeH = $notice.length ? ($notice.innerHeight() || $notice.height() || 0) : 0;
2186
2187            const $footerFixed = $('#footer.fixed');
2188            const footerH = $footerFixed.length ? ($footerFixed.innerHeight() || $footerFixed.height() || 0) : 0;
2189
2190            // 기본: 100vh 대체 (모바일 주소창 대응)
2191            $(Layout.sel.winHeight).height(wh);
2192
2193            // 헤더 제외
2194            $(Layout.sel.winHeightLayout).height(wh - headerH);
2195
2196            // 공지띠만 제외 (일부 스킨에서 "notice only" 레이아웃용)
2197            $(Layout.sel.winHeightLayoutN).height(wh - noticeH);
2198
2199            // 헤더 + 공지띠 제외
2200            $(Layout.sel.winHeightLayoutNC).height(wh - headerH - noticeH);
2201
2202            // 헤더 + 공지띠 + 하단고정 제외 (모바일 하단바 같은)
2203            $(Layout.sel.winHeightLayoutMH).height(wh - headerH - noticeH - footerH);
2204
2205            // 컨텐츠 전용(헤더/공지/푸터 모두 제외하고 싶을 때)
2206            $(Layout.sel.winHeightContent).height(wh - headerH - noticeH - footerH);
2207
2208            // 마진용
2209            $(Layout.sel.winHeightMargin).css('margin-top', wh);
2210
2211            // sticky 위치/패딩 보정
2212            if ($(Layout.sel.stickyTopNoticeH).length) {
2213                $(Layout.sel.stickyTopNoticeH).css('padding-top', noticeH);
2214            }
2215            if ($(Layout.sel.stickyTopLayout).length) {
2216                $(Layout.sel.stickyTopLayout).css('top', headerH);
2217            }
2218
2219            // 헤더 패딩/마진 보정
2220            if ($(Layout.sel.headerPadding).length) {
2221                $(Layout.sel.headerPadding).css('padding-top', headerH);
2222            }
2223            if ($(Layout.sel.headerMargin).length) {
2224                $(Layout.sel.headerMargin).css('margin-top', headerH);
2225            }
2226        },
2227
2228        bindResize: function () {
2229
2230            H.nsOffOn($(window), 'resize', 'munLayout', function () {
2231                Layout.applyMediaSize();
2232
2233                // PC 전환 시 모바일 슬라이드 강제 제거 + 검색도 같이 제거
2234                if (H.winW() > 1024) {
2235                    $('html').removeClass('mobile-slide');
2236                    $('html').removeClass('search');
2237
2238                    const methods = window.MUNCategory;
2239                    if (methods && typeof methods.closeMobileCateLayer === 'function') {
2240                        methods.closeMobileCateLayer();
2241                    }
2242                }
2243            });
2244        },
2245
2246        /* ---------------------------
2247         * BFCache 복원 시(뒤로가기) 모바일에서 꼬임 방지
2248         * ------------------------- */
2249        bindPageshowFix: function () {
2250
2251            window.addEventListener('pageshow', function (e) {
2252
2253                if (e.persisted && H.winW() < 1024) {
2254
2255                    document.documentElement.classList.remove('mobile-slide');
2256                    document.documentElement.classList.remove('search');
2257
2258                    Layout.applyMediaSize();
2259                    Layout.applyHeaderNoticeHeight();
2260
2261                    // window.location.reload();
2262                }
2263            });
2264        }
2265    };
2266    
2267    Layout.init();
2268
2269}
2269);
2270$(function () {
2271
2272    const $footer = $('#footer');
2273    if (!$footer.length) return;
2274
2275    const ACTIVE_CLASS = 'active';
2276
2277    function openFooter() {
2278        $footer.addClass(ACTIVE_CLASS);
2279    }
2280
2281    function closeFooter() {
2282        $footer.removeClass(ACTIVE_CLASS);
2283    }
2284
2285    function toggleFooter() {
2286        $footer.toggleClass(ACTIVE_CLASS);
2287    }
2288
2289    // 버튼 클릭
2290    $(document)
2291        .off('click.munFooterInfoOpen')
2292        .on('click.munFooterInfoOpen', '#footer .info-btn', function (e) {
2293        e.preventDefault();
2294        e.stopPropagation();
2295        toggleFooter();
2296    });
2297
2298    // 배경 클릭 닫기
2299    $(document)
2300        .off('click.munFooterInfoClose')
2301        .on('click.munFooterInfoClose', '#footer .footer-bg', function (e) {
2302        e.preventDefault();
2303        closeFooter();
2304    });
2305
2306    // ESC 키로 닫기 (접근성)
2307    $(document)
2308        .off('keydown.munFooterInfoEsc')
2309        .on('keydown.munFooterInfoEsc', function (e) {
2310        if (e.key === 'Escape') {
2311            closeFooter();
2312        }
2313    });
2314
2315});
2316/**
2317 * 움직이는 배너 Jquery Plug-in
2318 * @author  cafe24
2319 */
2320
2321(function($){
2322
2323    $.fn.floatBanner = function(options) {
2324        options = $.extend({}, $.fn.floatBanner.defaults , options);
2325
2326        return this.each(function() {
2327            var aPosition = $(this).position();
2328            var jbOffset = $(this).offset();
2329            var node = this;
2330
2331            $(window).on('scroll', function() {
2332                var _top = $(document).scrollTop();
2333                _top = (aPosition.top < _top) ? _top : aPosition.top;
2334
2335                setTimeout(function () {
2336                    var newinit = $(document).scrollTop();
2337
2338                    if ( newinit > jbOffset.top ) {
2339                        _top -= jbOffset.top;
2340                        var container_height = $("#wrap").height();
2341                        var quick_height = $(node).height();
2342                        var cul = container_height - quick_height;
2343                        if(_top > cul){
2344                            _top = cul;
2345                        }
2346                    } else {
2347                        _top = 0;
2348                    }
2349
2350                    $(node).stop().animate({top: _top}, options.animate);
2351                }, options.delay);
2352            });
2353        });
2354    };
2355
2356    $.fn.floatBanner.defaults = {
2357        'animate'  : 500,
2358        'delay'    : 500
2359    };
2360
2361})(jQuery);
2362
2363/**
2364 * 문서 구동후 시작
2365 */
2366$(function(){
2367    $('#banner:visible, #quick:visible').floatBanner();
2368
2369    //placeholder
2370    $(".ePlaceholder input, .ePlaceholder textarea").each(function(i){
2371        var placeholderName = $(this).parents().attr('title');
2372        $(this).attr("placeholder", placeholderName);
2373    });
2374    /* placeholder ie8, ie9 */
2375    $.fn.extend({
2376        placeholder : function() {
2377            //IE 8 버전에는 hasPlaceholderSupport() 값이 false를 리턴
2378           if (hasPlaceholderSupport() === true) {
2379                return this;
2380            }
2381            //hasPlaceholderSupport() 값이 false 일 경우 아래 코드를 실행
2382            return this.each(function(){
2383                var findThis = $(this);
2384                var sPlaceholder = findThis.attr('placeholder');
2385                if ( ! sPlaceholder) {
2386                   return;
2387                }
2388                findThis.wrap('<label class="ePlaceholder" />');
2389                var sDisplayPlaceHolder = $(this).val() ? ' style="display:none;"' : '';
2390                findThis.before('<span' + sDisplayPlaceHolder + '>' + sPlaceholder + '</span>');
2391                this.onpropertychange = function(e){
2392                    e = event || e;
2393                    if (e.propertyName == 'value') {
2394                        $(this).trigger('focusout');
2395                    }
2396                };
2397                //공통 class
2398                var agent = navigator.userAgent.toLowerCase();
2399                if (agent.indexOf("msie") != -1) {
2400                    $(".ePlaceholder").css({"position":"relative"});
2401                    $(".ePlaceholder span").css({"position":"absolute", "padding":"0 4px", "color":"#878787"});
2402                    $(".ePlaceholder label").css({"padding":"0"});
2403                }
2404            });
2405        }
2406    });
2407
2408    $(':input[placeholder]').placeholder(); //placeholder() 함수를 호출
2409
2410    //클릭하면 placeholder 숨김
2411    $('body').on('click', '.ePlaceholder span', function(){
2412        $(this).hide();
2413    });
2414
2415    //input창 포커스 인 일때 placeholder 숨김
2416    $('body').on('focusin', '.ePlaceholder :input', function(){
2417        $(this).prev('span').hide();
2418    });
2419
2420    //input창 포커스 아웃 일때 value 가 true 이면 숨김, false 이면 보여짐
2421    $('body').on('focusout', '.ePlaceholder :input', function(){
2422        if (this.value) {
2423            $(this).prev('span').hide();
2424        } else {
2425            $(this).prev('span').show();
2426        }
2427    });
2428
2429    //input에 placeholder가 지원이 되면 true를 안되면 false를 리턴값으로 던져줌
2430    function hasPlaceholderSupport() {
2431        if ('placeholder' in document.createElement('input')) {
2432            return true;
2433        } else {
2434            return false;
2435        }
2436    }
2437});
2438
2439/**
2440 *  썸네일 이미지 엑박일경우 기본값 설정
2441 */
2442$(window).on('load', function() {
2443    $("img.thumb,img.ThumbImage,img.BigImage").each(function($i,$item){
2444        var $img = new Image();
2445        $img.onerror = function () {
2446            $item.src="//img.echosting.cafe24.com/thumb/img_product_big.gif";
2447        }
2448        $img.src = this.src;
2449    });
2450});
2451
2452/**
2453 *  tooltip
2454 */
2455$('.eTooltip').each(function(i){
2456    $(this).find('.btnClose').attr('tabIndex','-1');
2457});
2458//tooltip input focus
2459$('.eTooltip').find('input').on('focus', function() {
2460    var targetName = returnTagetName(this);
2461    targetName.siblings('.ec-base-tooltip').show();
2462});
2463$('.eTooltip').find('input').on('focusout', function() {
2464    var targetName = returnTagetName(this);
2465    targetName.siblings('.ec-base-tooltip').hide();
2466});
2467function returnTagetName(_this){
2468    var ePlacename = $(_this).parent().attr("class");
2469    var targetName;
2470    if(ePlacename == "ePlaceholder"){ //ePlaceholder 대응
2471        targetName = $(_this).parents();
2472    }else{
2473        targetName = $(_this);
2474    }
2475    return targetName;
2476}
2477
2478/**
2479 *  eTab
2480 */
2481$("body").on("click", ".eTab a", function(e){
2482    // 클릭한 li 에 selected 클래스 추가, 기존 li에 있는 selected 클래스는 삭제.
2483    var _li = $(this).parent("li").addClass("selected").siblings().removeClass("selected"),
2484    _target = $(this).attr("href"),
2485    _siblings = $(_target).attr("class"),
2486    _arr = _siblings.split(" "),
2487    _classSiblings = "."+_arr[0];
2488
2489    //클릭한 탭에 해당하는 요소는 활성화, 기존 요소는 비활성화 함.
2490    $(_target).show().siblings(_classSiblings).hide();
2491
2492
2493    //preventDefault 는 a 태그 처럼 클릭 이벤트 외에 별도의 브라우저 행동을 막기 위해 사용됨.
2494    e.preventDefault();
2495});
2496
2497
2498
2499//window popup script
2500function winPop(url) {
2501    window.open(url, "popup", "width=300,height=300,left=10,top=10,resizable=no,scrollbars=no");
2502}
2503/**
2504 * document.location.href split
2505 * return array Param
2506 */
2507function getQueryString(sKey)
2508{
2509    var sQueryString = document.location.search.substring(1);
2510    var aParam       = {};
2511
2512    if (sQueryString) {
2513        var aFields = sQueryString.split("&");
2514        var aField  = [];
2515        for (var i=0; i<aFields.length; i++) {
2516            aField = aFields[i].split('=');
2517            aParam[aField[0]] = aField[1];
2518        }
2519    }
2520
2521    aParam.page = aParam.page ? aParam.page : 1;
2522    return sKey ? aParam[sKey] : aParam;
2523};
2524
2525$(document).ready(function(){
2526    // tab
2527    $.eTab = function(ul){
2528        $(ul).find('a').click(function(){
2529            var _li = $(this).parent('li').addClass('selected').siblings().removeClass('selected'),
2530                _target = $(this).attr('href'),
2531                _siblings = '.' + $(_target).attr('class');
2532            $(_target).show().siblings(_siblings).hide();
2533            return false
2534        });
2535    }
2536    if ( window.call_eTab ) {
2537        call_eTab();
2538    };
2539});
2540(function($){
2541$.fn.extend({
2542    center: function() {
2543        this.each(function() {
2544            var
2545                $this = $(this),
2546                $w = $(window);
2547            $this.css({
2548                position: "absolute",
2549                top: ~~(($w.height() - $this.outerHeight()) / 2) + $w.scrollTop() + "px",
2550                left: ~~(($w.width() - $this.outerWidth()) / 2) + $w.scrollLeft() + "px"
2551            });
2552        });
2553        return this;
2554    }
2555});
2556$(function() {
2557    var $container = function(){/*
2558<div id="modalContainer">
2559    <iframe id="modalContent" scroll="0" scrolling="no" frameBorder="0"></iframe>
2560</div>');
2561*/}.toString().slice(14,-3);
2562    $('body')
2563    .append($('<div id="modalBackpanel"></div>'))
2564    .append($($container));
2565    function closeModal () {
2566        $('#modalContainer').hide();
2567        $('#modalBackpanel').hide();
2568    }
2569    $('#modalBackpanel').click(closeModal);
2570    zoom = function ($piProductNo, $piCategoryNo, $piDisplayGroup) {
2571        var $url = '/product/image_zoom.html?product_no=' + $piProductNo + '&cate_no=' + $piCategoryNo + '&display_group=' + $piDisplayGroup;
2572        $('#modalContent').attr('src', $url);
2573        $('#modalContent').bind("load",function(){
2574            $(".header .close",this.contentWindow.document.body).bind("click", closeModal);
2575        });
2576        $('#modalBackpanel').css({width:$("body").width(),height:$("body").height(),opacity:.4}).show();
2577        $('#modalContainer').center().show();
2578    }
2579});
2580})(jQuery);

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.