PageSourceSearch

https://robotis-shop-en.com/assets/js/common.js?v=1790787698

js robotis-shop-en.com collected 2026-09-30 17:01:44 UTC 10,895 bytes, 341 lines download raw bytes

1
2/*************************************
3* 소소한 도움주는 함수 모음
4*************************************/
5// 숫자 타입 체크
6function isNumeric(str) {
7  if (typeof str !== 'string') return false;
8  return !isNaN(str) && !isNaN(parseFloat(str));
9}
10
11// 언어 가져오기
12function getLang() {
13  const get_lang = document.querySelector('html').getAttribute('lang');
14  return get_lang;
15}
16
17// 전역 접근
18window.isNumeric = isNumeric;
19window.getLang = getLang;
20
21
22
23/*************************************
24* Footer의 패밀리사이트 드롭다운 Handler
25*************************************/
26document.addEventListener('DOMContentLoaded', function() {
27  const familySiteWrapper = document.querySelector('.family-site-wrapper');
28  const familySiteBtn = document.querySelector('.family-site-btn');
29  
30  if (!familySiteBtn || !familySiteWrapper) return;
31  
32  // 버튼 클릭 시 드롭다운 토글
33  familySiteBtn.addEventListener('click', function(e) {
34    e.stopPropagation();
35    familySiteWrapper.classList.toggle('active');
36  });
37  
38  // 드롭다운 링크 클릭 시 드롭다운 닫기
39  const dropdownLinks = document.querySelectorAll('.family-site-link');
40  dropdownLinks.forEach(function(link) {
41    link.addEventListener('click', function(e) {
42      // 링크의 기본 동작은 유지하고 드롭다운만 닫기
43      setTimeout(function() {
44        familySiteWrapper.classList.remove('active');
45      }, 100);
46    });
47  });
48  
49  // 문서의 다른 곳 클릭 시 드롭다운 닫기
50  document.addEventListener('click', function(e) {
51    if (!familySiteWrapper.contains(e.target)) {
52      familySiteWrapper.classList.remove('active');
53    }
54  });
55});
56
57
58
59/*************************************
60*  GNB, 햄버거 메뉴, 언어변경 초기화 함수 모음
61*************************************/
62
63// 즉시실행 함수로 전체 초기화 코드 감쌈
64(function() {
65  'use strict';
66
67  // 전역 변수 설정
68  setupGlobals();   
69})();
70
71// 전역 변수 설정 (언어, 스크롤 컨테이너 셀렉터 등) 
72function setupGlobals() {
73  window.lang = window.lang || 'ko'; // 언어 기본값
74}
75
76// 헤더 초기화 함수
77function initHeader() {
78  var $header = $('.header');
79  var $gnbBar = $('.gnb_bar');
80  var $body = $('body');
81  var $hamburger = $('.hamburger_btn');
82  var $currentD1 = null;
83
84  // GNB 메뉴 마우스 오버 이벤트
85  $header.find('.d1').on('mouseover', function() {
86
87    $body.addClass('menu_open');
88    $header.addClass('is_open');
89    $header.removeClass('scrolled');
90
91    if ($currentD1) $currentD1.removeClass('is_hover');
92
93    $(this).addClass('is_hover');
94    $currentD1 = $(this);
95    resizeHeaderHeight($currentD1);
96
97    // GNB 바 애니메이션
98    if ($currentD1.length && $gnbBar.length) {
99      var parentRect = $currentD1[0].offsetParent.getBoundingClientRect();
100      var rect = $currentD1[0].getBoundingClientRect();
101      var left = rect.left - parentRect.left;
102      $gnbBar.css('width', `calc(${rect.width}px - 2em)`);
103      $gnbBar.css('transform', `translateX(calc(${left}px + 1em))`);
104    }
105  });
106
107  // GNB 메뉴 마우스 리브 이벤트
108  $header.on('mouseleave', function() {
109    if ($currentD1) {
110      $currentD1.removeClass('is_hover');
111      $currentD1 = null;
112    }
113    resizeHeaderHeight($header);
114    $gnbBar.css('width', '0');
115    $gnbBar.css('transform', 'translateX(0)');  
116    
117    $body.removeClass('menu_open');
118    $header.removeClass('is_open');
119
120  });
121
122  // 햄버거 메뉴 클릭 이벤트 바인딩
123  if ($hamburger.length) {
124    $hamburger.off('click').on('click', function(e) {
125      // 햄버거 버튼의 init 클래스 제거(초기 애니메이션 등)
126      $hamburger.removeClass('init');
127      this.blur();
128
129      // 사이드 메뉴(ham_menu)와 GNB 래퍼(gnb_wrap) 선택
130      var $hamMenu = $('.ham_menu');
131      var $gnbWrap = $('.gnb_wrap');
132
133      // is_side_menu 클래스를 토글하여 열고 닫기 모두 처리
134      $header.toggleClass('is_side_menu');
135
136      if ($header.hasClass('is_side_menu')) {
137        // 사이드 메뉴 열림: ham_menu 숨김, gnb_wrap 보임
138        if ($hamMenu.length) $hamMenu.css({'opacity': '1', 'visibility': 'visible'});
139        if ($gnbWrap.length) $gnbWrap.css('opacity', '0');
140      } else {
141        // 사이드 메뉴 닫힘: ham_menu 보임, gnb_wrap 숨김
142        if ($hamMenu.length) $hamMenu.css({'opacity': '0', 'visibility': 'hidden'});
143        if ($gnbWrap.length) $gnbWrap.css('opacity', '1');
144        $header.removeClass('is_open');
145      }
146
147      e.preventDefault();
148      e.stopPropagation();
149    });
150  }
151
152  // 헤더 높이 조정 함수
153  function resizeHeaderHeight($target) {
154    var $d2 = $target.find('.d2-wrap');
155    if (!$d2.length){
156      document.documentElement.style.setProperty('--header-height', '60px');
157      return; 
158    } 
159    var d2Height = $d2[0].clientHeight;
160    document.documentElement.style.setProperty('--header-height', d2Height);
161  }
162 
163}
164
165
166// 언어 선택 드롭다운 - 시작
167//initHeaderDropdown()으로 전체 코드를 감싸서 DOMContentLoaded 이후에 실행되도록 변경. 요소가 존재할 때 이벤트가 정상적으로 바인딩
168function initHeaderDropdown() {
169  
170  const $langDropdown = document.querySelector('.lang_dropdown.lang');
171  let time;
172  let beforeDelta = 0;
173
174  // 언어 버튼 클릭 이벤트 (각 언어에 맞는 URL로 이동하는데 쓸수 있으나 지금은 안씀)
175  document.querySelectorAll('.lang_dropdown').forEach(lang_dropdown => {
176    const navButtons = lang_dropdown.querySelectorAll('.lang_dropdown_item');
177    if (!navButtons || !navButtons.length) return;
178
179    navButtons.forEach(navButton => {
180      navButton.addEventListener('click', function(e) {
181        e.preventDefault(); 
182        try { 
183          const selectedSite = (this.getAttribute('hreflang') || '').toLowerCase(); 
184          const url = new URL(window.location.href);
185          const originalPath = url.pathname || '/';
186          const segments = originalPath.split('/').filter(Boolean);
187
188          // If first segment is a supported site code, replace it; otherwise prepend
189          if (segments.length ) {
190            segments[0] = selectedSite;
191          } else {
192            segments.unshift(selectedSite);
193          }// Rebuild pathname, preserve trailing slash if existed
194          const trailingSlash = originalPath.endsWith('/') ? '/' : '';
195          url.pathname = '/' + segments.join('/') + trailingSlash;
196          // Navigate
197          window.location.href = url.toString();
198
199        } catch (e) {
200          
201        }
202      });
203    });
204  });
205
206
207  // 다른 영역 클릭 시 드롭다운 닫기
208  document.body.addEventListener('click', initDropStatus);
209
210  // 드롭다운 닫기 (다른 영역 클릭 시)
211  function initDropStatus(e) {
212    document.querySelectorAll('.lang_dropdown').forEach(el => {
213      if (e.target.parentNode !== el) {
214        el.classList.add('closed');
215      }
216    });
217  }
218  
219  // 드롭다운 위치 계산
220  function setDropdownPosition() {
221    const $region = document.querySelector('.menu_lang');
222    if (!$region || !$langDropdown) return;
223
224    const rect = $region.getBoundingClientRect();
225    $langDropdown.style.top = `calc(1.37em + ${rect.top}px)`;
226    $langDropdown.style.left = `calc(1.37em + ${rect.left}px - ${rect.height / 2}px)`;
227
228    setHeaderMultiLangHeight();
229  }
230
231  const multiLangPad = 12;
232
233  function setHeaderMultiLangHeight() {
234    const $dropdownLang = document.querySelector('.lang_dropdown.lang');
235    const $dropdownList = $dropdownLang ? $dropdownLang.querySelector('.lang_dropdown__list') : null;
236    if ($dropdownList) {
237      $dropdownList.style.setProperty('--height', $dropdownList.scrollHeight + multiLangPad + 'px');
238    }
239  }
240
241  // 언어 변경 버튼 클릭 이벤트
242  const $regionBtn = document.querySelector('.menu_lang');
243  if ($regionBtn) {
244    $regionBtn.addEventListener('click', function(e) {
245      setDropdownPosition();
246      this.blur();
247
248      const $dropdown = $langDropdown ? $langDropdown.closest('.lang_dropdown') : null;
249      if ($dropdown) {
250        $dropdown.classList.toggle('closed');
251      }
252      setHeaderMultiLangHeight();
253      e.preventDefault();
254      e.stopPropagation();
255    });
256  }
257
258  // 윈도우 리사이즈 이벤트
259  window.addEventListener('resize', function() {
260    if (time) clearTimeout(time);
261
262    setDropdownPosition();
263    time = setTimeout(function() {
264      setDropdownPosition();
265    }, 200);
266  });
267
268  setDropdownPosition();
269
270}
271// 언어 선택 드롭다운 - 끝
272
273// 메뉴 닫기 함수 - 스크롤 시 호출됨
274function closeMenu() {
275  const $header = $('.header');
276  const $body = $('body');
277  
278  if ($header.length === 0) return;
279
280  /**
281   * 1. 햄버거 사이드 메뉴가 열려있는 경우 (is_side_menu)
282   * GNB 드롭다운(is_open)만 닫고, 사이드 메뉴는 유지함
283   */
284  if ($header.hasClass('is_side_menu')) {
285    $header.removeClass('is_open'); // 상단 GNB 드롭다운 상태만 해제
286    // return을 하지 않고 여기서 멈추거나, 사이드 메뉴 로직을 건너뜁니다.
287    return; 
288  }
289
290  /**
291   * 2. 일반적인 상황 (사이드 메뉴가 아닐 때)
292   * 모든 메뉴 상태를 초기화
293   */
294  $header.removeClass('is_open');
295  $body.removeClass('menu_open');
296  
297  // 햄버거 메뉴 레이어 숨김 처리 (사이드 메뉴가 아닐 때만 실행)
298  const $hamMenu = $('.ham_menu');
299  const $gnbWrap = $('.gnb_wrap');
300  if ($hamMenu.length) $hamMenu.css({'opacity': '0', 'visibility': 'hidden'});
301  if ($gnbWrap.length) $gnbWrap.css('opacity', '1');
302}
303
304
305
306// 페이지 로드 완료 후 헤더 및 언어 드롭다운 초기화 (중복 방지)
307function runHeaderInits() {
308  if (!window.__headerInited) {
309    window.__headerInited = true;
310    initHeader();
311    initHeaderDropdown();
312  }
313}
314if (document.readyState === 'loading') {
315  document.addEventListener('DOMContentLoaded', runHeaderInits);
316} else {
317  runHeaderInits();
318}
319 
320 
321// 마우스 스크롤 시 헤더 드롭다운 메뉴 닫기 및 헤더 스타일 변경
322window.addEventListener('scroll', function() {
323
324  closeMenu(); // 드롭다운 메뉴 닫기
325
326  // 스크롤 위치에 따른 헤더 스타일 변경
327  var $header = document.querySelector('.header');
328  if (!$header) return;
329  if (window.scrollY > 60) {
330    $header.classList.add('scrolled');
331  } else {
332    $header.classList.remove('scrolled');
333  }
334});
335
336// 전역에서 접근 가능하도록 window에 등록
337window.initHeader = initHeader;
338window.initHeaderDropdown = initHeaderDropdown;
339window.closeMenu = closeMenu; 
340 
341 

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.