PageSourceSearch

https://www.toli.co.jp/common/js/menu-active-pc.js

js toli.co.jp collected 2026-09-24 20:47:26 UTC 9,415 bytes, 265 lines download raw bytes

1/**
2 * 東リサイト PCメニューアクティブ表示
3 * SSIで読み込まれる共通ヘッダーのメニュー項目を現在のページに応じてアクティブ表示
4 * @version 1.0.0
5 */
6
7(function() {
8  'use strict';
9
10  // ページ読み込み完了後に実行
11  document.addEventListener('DOMContentLoaded', function() {
12    
13    // 現在のURLパスを取得
14    const currentPath = location.pathname;
15    
16    // PCメニューのアクティブ表示
17    function setActiveMenuPC() {
18      // メインナビゲーションのリンクを取得
19      const navLinks = document.querySelectorAll('.p-headerPC__navText a, .p-headerPC__dropDownNavItem a, a.p-headerPC__navText');
20      
21      navLinks.forEach(link => {
22        const href = link.getAttribute('href');
23        
24        // 現在のパスと一致するかチェック
25        if (href && isCurrentPage(href, currentPath)) {
26          // リンク自体にactiveクラスを追加
27          link.classList.add('active');
28          
29          // 親要素にもactiveクラスを追加(メインナビ項目)
30          const parentNavItem = link.closest('.p-headerPC__navItem');
31          if (parentNavItem) {
32            parentNavItem.classList.add('active');
33          }
34          
35          // ドロップダウン内のアイテムの場合
36          const dropDownItem = link.closest('.p-headerPC__dropDownNavItem');
37          if (dropDownItem) {
38            dropDownItem.classList.add('active');
39            
40            // ドロップダウンメニューの親ナビゲーション項目もアクティブに
41            const parentDropDown = dropDownItem.closest('.p-headerPC__dropDownNav');
42            if (parentDropDown) {
43              const parentNavOfDropDown = parentDropDown.closest('.p-headerPC__navItem');
44              if (parentNavOfDropDown) {
45                parentNavOfDropDown.classList.add('active-parent');
46              }
47            }
48          }
49        }
50      });
51    }
52    
53    // URLマッチング関数(階層構造に対応)
54    function isCurrentPage(linkHref, currentPath) {
55      // /product/casestudy の場合は非アクティブ化
56      if (currentPath.includes('/product/casestudy')) {
57        return false;
58      }
59      
60      // 完全一致
61      if (linkHref === currentPath) {
62        return true;
63      }
64      
65      // 末尾のスラッシュを正規化
66      const linkPathClean = linkHref.replace(/\/$/, '');
67      const currentPathClean = currentPath.replace(/\/$/, '');
68      
69      // 完全一致(スラッシュ正規化後)
70      if (linkPathClean === currentPathClean) {
71        return true;
72      }
73      
74      // セクションごとのマッチングルール
75      const sectionRules = {
76        // 商品を探す
77        '/product/': {
78          patterns: ['/product/search/', '/product/favorite'],
79          subPaths: [
80            '/product/search/floor_result',
81            '/product/search/carpet_result',
82            '/product/search/wall_result',
83            '/product/search/curtain_result',
84            '/product/search/baseboard_result',
85            '/product/search/adhesive_result'
86          ]
87        },
88        // ショールーム
89        '/showroom/': {
90          patterns: ['/showroom/'],
91          locations: [
92            '/showroom/tokyo.html',
93            '/showroom/osaka.html',
94            '/showroom/nagoya.html',
95            '/showroom/sapporo.html',
96            '/showroom/fukuoka.html',
97            '/showroom/okayama.html',
98            '/showroom/takamatsu.html'
99          ]
100        },
101        // デジタルカタログ
102        '/digital_catalog/': {
103          patterns: ['/digital_catalog/'],
104          tabs: ['?tab=floor', '?tab=carpet', '?tab=wall', '?tab=curtain', '?tab=baseboard']
105        },
106        // 企業・IR・採用
107        '/company/': {
108          patterns: ['/company/'],
109          pages: [
110            '/company/president_speech.html',
111            '/company/philosophy.html',
112            '/company/company_outline.html',
113            '/company/toli_history.html',
114            '/company/charter.html',
115            '/company/eigyousho.html'
116          ]
117        },
118        '/ir/': {
119          patterns: ['/ir/', '/ir_en/'],
120          sections: [
121            '/ir/message/',
122            '/ir/plan/',
123            '/ir/walking/',
124            '/ir/strength/',
125            '/ir/business/',
126            '/ir/governance/'
127          ]
128        },
129        // サステナビリティ
130        '/sustainability/': {
131          patterns: ['/sustainability/']
132        },
133        // 販売店
134        '/shop/': {
135          patterns: ['/shop/'],
136          subPaths: [
137            '/shop/list',
138            '/shop/detail',
139            '/shop/list.html',
140            '/shop/detail.html'
141          ]
142        },
143        // メンバー
144        '/member/': {
145          patterns: ['/member/'],
146          pages: ['/member/login', '/member/logout', '/member/faq']
147        }
148      };
149      
150      // セクションルールに基づいてマッチング
151      for (const [sectionPath, rules] of Object.entries(sectionRules)) {
152        // メインセクションのパターンマッチング
153        if (rules.patterns) {
154          for (const pattern of rules.patterns) {
155            // リンクがこのパターンに該当し、現在のページがセクション内にある場合
156            if (linkHref.includes(pattern) && currentPath.startsWith(sectionPath)) {
157              return true;
158            }
159          }
160        }
161        
162        // サブページの詳細マッチング
163        if (currentPath.startsWith(sectionPath)) {
164          // 現在のページがセクション内の特定ページの場合
165          if (rules.subPaths && rules.subPaths.includes(currentPath)) {
166            if (linkHref.includes(sectionPath)) {
167              return true;
168            }
169          }
170          if (rules.locations && rules.locations.includes(currentPath)) {
171            if (linkHref.includes(sectionPath)) {
172              return true;
173            }
174          }
175          if (rules.pages && rules.pages.includes(currentPath)) {
176            if (linkHref.includes(sectionPath)) {
177              return true;
178            }
179          }
180          if (rules.sections && rules.sections.some(section => currentPath.startsWith(section))) {
181            if (linkHref.includes(sectionPath)) {
182              return true;
183            }
184          }
185        }
186      }
187      
188      return false;
189    }
190    
191    // デバッグモード(開発時のみ使用)
192    // function debugMode() {
193    //   console.log('Current Path:', currentPath);
194    //   const activeElements = document.querySelectorAll('.active, .active-parent');
195    //   console.log('Active Elements:', activeElements);
196    //   
197    //   // 販売店リンクの詳細デバッグ
198    //   const shopLinks = document.querySelectorAll('a[href="/shop/"]');
199    //   console.log('Shop Links Found:', shopLinks);
200    //   shopLinks.forEach((link, index) => {
201    //     console.log(`Shop Link ${index}:`, link.getAttribute('href'), 'Match Result:', isCurrentPage(link.getAttribute('href'), currentPath));
202    //   });
203    // }
204    
205    // 実行
206    setActiveMenuPC();
207    
208    // デバッグモード(必要に応じてコメントアウト)
209    // debugMode();
210  });
211})();
212
213
214  // Redirect and link fix for /saiyou -> /
215  $(function(){
216    var RECRUIT_ROOT = 'https://recruit.toli.co.jp/';
217    var RECRUIT_CAREER_SRC = 'https://recruit.toli.co.jp/recruit/index.html?career';
218    var RECRUIT_CAREER_DST = 'https://recruit.toli.co.jp/recruit/career/index.html';
219    try {
220      var hrefNow = window.location.href.replace(/\/+$/,'/');
221      if (hrefNow === 'https://recruit.toli.co.jp/saiyou' || hrefNow === 'https://recruit.toli.co.jp/saiyou/') {
222        if (hrefNow !== RECRUIT_ROOT) {
223          window.location.replace(RECRUIT_ROOT);
224          return;
225        }
226      }
227      // Direct visit redirect for career query mapping
228      if (window.location.href === RECRUIT_CAREER_SRC) {
229        window.location.replace(RECRUIT_CAREER_DST);
230        return;
231      }
232    } catch(e) {}
233  
234    $('a[href]').each(function(){
235      try {
236        var href = $(this).attr('href');
237        if (!href) return;
238        // Case 1: relative path '/saiyou' or '/saiyou/' -> absolute RECRUIT_ROOT
239        if (href === '/saiyou' || href === '/saiyou/') {
240          $(this).attr('href', RECRUIT_ROOT);
241          return;
242        }
243        // Case 1b: relative recruit career query -> absolute new career URL
244        if (href === '/recruit/index.html?career') {
245          $(this).attr('href', RECRUIT_CAREER_DST);
246          return;
247        }
248        // Case 2: absolute link to recruit domain with /saiyou path -> RECRUIT_ROOT
249        if (/^https?:\/\/recruit\.toli\.co\.jp(\/saiyou\/?|$)/i.test(href)) {
250          // if it's exactly /saiyou or /saiyou/ or has only that path
251          var tmp = document.createElement('a'); tmp.href = href;
252          var p = tmp.pathname.replace(/\/+$/,'/');
253          if (p === '/saiyou/' || p === '/saiyou') {
254            $(this).attr('href', RECRUIT_ROOT);
255            return;
256          }
257        }
258        // Case 3: absolute link exactly matching old career URL -> new career URL
259        if (href === RECRUIT_CAREER_SRC) {
260          $(this).attr('href', RECRUIT_CAREER_DST);
261          return;
262        }
263      } catch(e) {}
264    });
265    });

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.