PageSourceSearch

https://takamatsu-inc.co.jp/wp-content/themes/sunmi/_assets/js/script.js

js takamatsu-inc.co.jp collected 2026-10-06 05:45:10 UTC 15,492 bytes, 525 lines download raw bytes

1// モジュール定義
2const myModule = {};
3
4// monitorImagesLoad関数
5(function() {
6  myModule.monitorImagesLoad = function(targetOrTargets, callback) {
7      if (targetOrTargets instanceof NodeList) {
8          let totalTargets = targetOrTargets.length;
9          let loadedTargets = 0;
10          targetOrTargets.forEach((target) => {
11              this.monitorImagesLoad(target, () => {
12                  loadedTargets++;
13                  if (loadedTargets === totalTargets) {
14                      callback();
15                  }
16              });
17          });
18      } else {
19          const images = targetOrTargets.querySelectorAll('img');
20          let imagesToLoad = images.length;
21          if (imagesToLoad === 0) {
22              callback(targetOrTargets);
23              return;
24          }
25          images.forEach((image) => {
26              if (image.complete) {
27                  if (image.naturalWidth === 0 || image.naturalHeight === 0) {
28                      console.error(`Image failed to load or is broken: ${image.src}`);
29                  }
30                  imagesToLoad--;
31                  if (imagesToLoad === 0) {
32                      callback(targetOrTargets);
33                  }
34              } else {
35                  image.addEventListener('error', () => {
36                      console.error(`Image failed to load or is broken: ${image.src}`);
37                      imagesToLoad--;
38                      if (imagesToLoad === 0) {
39                          callback(targetOrTargets);
40                      }
41                  });
42                  image.addEventListener('load', () => {
43                      imagesToLoad--;
44                      if (imagesToLoad === 0) {
45                          callback(targetOrTargets);
46                      }
47                  });
48              }
49          });
50      }
51  };
52})();
53
54// throttle関数
55(function() {
56  myModule.throttle = function(func, wait, options = {}) {
57    let context, args, result;
58    let timeout = null;
59    let previous = 0;
60
61    const later = () => {
62      previous = options.leading === false ? 0 : Date.now();
63      timeout = null;
64      result = func.apply(context, args);
65      if (!timeout) context = args = null;
66    };
67
68    const throttled = function () {
69      const now = Date.now();
70      if (!previous && options.leading === false) previous = now;
71      const remaining = wait - (now - previous);
72      context = this;
73      args = arguments;
74  
75      if (remaining <= 0 || remaining > wait) {
76        if (timeout) {
77          clearTimeout(timeout);
78          timeout = null;
79        }
80        previous = now;
81        result = func.apply(context, args);
82        if (!timeout) context = args = null;
83      } else if (!timeout && options.trailing !== false) {
84        timeout = setTimeout(later, remaining);
85      }
86      return result;
87    };
88
89    throttled.cancel = () => {
90      clearTimeout(timeout);
91      previous = 0;
92      timeout = context = args = null;
93    };
94
95    return throttled;
96  };
97})();
98
99// debounce関数
100(function() {
101  myModule.debounce = function(func, wait, immediate) {
102    let timeout, args, context, timestamp, result;
103
104    const later = () => {
105      const last = Date.now() - timestamp;
106
107      if (last < wait) {
108        timeout = setTimeout(later, wait - last);
109      } else {
110        timeout = null;
111        if (!immediate) {
112          result = func.apply(context, args);
113          if (!timeout) context = args = null;
114        }
115      }
116    };
117
118    const debounced = function () {
119      context = this;
120      args = arguments;
121      timestamp = Date.now();
122      const callNow = immediate && !timeout;
123      if (!timeout) timeout = setTimeout(later, wait);
124      if (callNow) {
125        result = func.apply(context, args);
126        context = args = null;
127      }
128
129      return result;
130    };
131
132    debounced.cancel = () => {
133      clearTimeout(timeout);
134      timeout = context = args = null;
135    };
136
137    return debounced;
138  };
139})();
140
141// ウィンドウサイズ判定
142(function() {
143  const mediaQueryList = window.matchMedia('(max-width: 767px)');
144  function screen(e) {
145    if (e.matches) {
146      window.dispatchEvent(new Event('mqChangeSp'));
147    } else {
148      window.dispatchEvent(new Event('mqChangePc'));
149    }
150  }
151  function initialCheck() {
152    screen(mediaQueryList);
153    mediaQueryList.addEventListener('change', screen);
154  }
155  if (document.readyState === 'loading') {
156    document.addEventListener('DOMContentLoaded', initialCheck);
157  } else {
158    initialCheck();
159  }
160})();
161
162// ヘッダー 表示切り替え
163(function() {
164  let flg;
165  const header = document.querySelector('header');
166  const headerHeight = 123;
167  let scrollTop;
168  let mainPosition;
169  let switchingPosition = 800;
170  const classNameFixed = 'is-fixed';
171  const classNameShow = 'is-show';
172  let isEventAttached = false;
173  const throttledHeaderSwitching = myModule.throttle(() => {
174    headerSwitching();
175  }, 300);
176
177  window.addEventListener('mqChangeSp', () => {
178    flg = 'sp';
179    handleDeviceChange();
180  });
181  window.addEventListener('mqChangePc', () => {
182    flg = 'pc';
183    handleDeviceChange();
184  });
185
186  function headerSwitching() {
187    mainPosition = document.querySelector('body').getBoundingClientRect().top;
188    scrollTop = Math.abs(mainPosition);
189
190    if (scrollTop >= headerHeight && scrollTop < switchingPosition) {
191      header.classList.add(classNameFixed);
192      header.classList.remove(classNameShow);
193    } else if (scrollTop >= headerHeight && scrollTop >= switchingPosition) {
194      header.classList.add(classNameFixed, classNameShow);
195    } else {
196      header.classList.remove(classNameFixed, classNameShow);
197    }
198  }
199
200  function addScrollEvent() {
201    if (!isEventAttached) {
202      window.addEventListener('scroll', throttledHeaderSwitching);
203      isEventAttached = true;
204    }
205  }
206
207  function removeScrollEvent() {
208    if (isEventAttached) {
209      window.removeEventListener('scroll', throttledHeaderSwitching);
210      header.classList.remove(classNameFixed, classNameShow);
211      isEventAttached = false;
212    }
213  }
214
215  function handleDeviceChange() {
216    if (flg === 'pc') {
217      headerSwitching();
218      addScrollEvent();
219    } else if (flg === 'sp') {
220      removeScrollEvent();
221    }
222  }
223  document.addEventListener('DOMContentLoaded', () => {
224    handleDeviceChange();
225  });
226})();
227
228// smooth scroll
229document.addEventListener('DOMContentLoaded', () => {
230  const anchorLinks = document.querySelectorAll('a[href^="#"]');
231  anchorLinks.forEach(link => {
232    link.addEventListener('click', e => {
233      e.preventDefault();
234      const targetId = link.getAttribute('href');
235      const targetElement = document.querySelector(targetId);
236      if (targetElement) {
237        const targetOffsetTop = window.pageYOffset + targetElement.getBoundingClientRect().top;
238        window.scrollTo({
239          top: targetOffsetTop,
240          behavior: "smooth"
241        });
242      }
243    });
244  });
245});
246
247// ハンバーガーメニュー
248document.addEventListener('DOMContentLoaded', () => {
249  const navToggle = document.querySelector('.header-navToggle');
250  const body = document.body;
251  const html = document.documentElement; // htmlタグを取得
252
253  if (navToggle) {
254    navToggle.addEventListener('click', () => {
255      navToggle.classList.toggle('active');
256      const hamburgerMenu = document.querySelector('.header-hamburger');
257      if (hamburgerMenu) {
258        hamburgerMenu.classList.toggle('active');
259        if (hamburgerMenu.classList.contains('active')) {
260          body.style.overflow = 'hidden';
261          html.style.overflow = 'hidden'; // htmlタグにもスクロール禁止を設定
262        } else {
263          body.style.overflow = 'auto';
264          html.style.overflow = 'auto'; // スクロール許可
265        }
266      }
267    });
268  }
269});
270
271
272// モーダル
273// モーダルウィンドウを開く処理
274document.querySelectorAll('.js-modal-open').forEach(element => {
275  element.addEventListener('click', function(event) {
276      event.preventDefault(); // デフォルトのイベントを阻止
277      var target = this.dataset.target;
278      var modal = document.getElementById(target);
279      if (modal) {
280          scrollPosition = window.pageYOffset; // 現在のスクロール位置を保存
281
282          document.body.style.cssText = `position: fixed; top: -${scrollPosition}px; width: 100%;`;
283          modal.style.display = 'block';
284          modal.style.opacity = 0;
285
286          setTimeout(() => {
287              modal.style.transition = 'opacity 0.5s ease';
288              modal.style.opacity = 1;
289          }, 10); // 微小な遅延を設けてアニメーションを開始
290      } else {
291          console.error(`Modal with ID ${target} not found`);
292      }
293  });
294});
295
296// モーダルウィンドウを閉じる処理
297document.querySelectorAll('.js-modal-close').forEach(element => {
298  element.addEventListener('click', function(event) {
299      event.preventDefault(); // デフォルトのイベントを阻止
300      closeModal(this.closest('.modal'));
301  });
302});
303
304// .modal-bgをクリックしてモーダルを閉じる処理
305document.querySelectorAll('.modal-bg').forEach(element => {
306  element.addEventListener('click', function(event) {
307      if (event.target === this) {
308          closeModal(this.closest('.modal'));
309      }
310  });
311});
312
313function closeModal(modal) {
314  modal.style.opacity = 0;
315
316  setTimeout(() => {
317      modal.style.display = 'none';
318      modal.style.transition = '';
319      document.body.style.cssText = ''; // bodyのスタイルをリセット
320      window.scrollTo(0, scrollPosition); // 保存された位置にスクロール
321  }, 500); // フェードアウトの完了を待つ
322}
323
324// もっと見る
325(function() {
326  const element = document.querySelector('[data-shop-detail]');
327
328  if (element) {
329    //ボタンを取得
330    const btn = element.querySelector('.more__btn');
331    //コンテンツを取得
332    const content = element.querySelector('.more__content');
333  
334    //ボタンクリックでイベント発火
335    btn.addEventListener('click', function(){
336      if(!content.classList.contains('open')){
337        //コンテンツの実際の高さを代入
338        content.style.maxHeight = content.scrollHeight + 'px';
339        //openクラスを追加
340        content.classList.add('open');
341        btn.classList.add('open'); // ボタンにもクラスを追加
342        //もっと見るボタンのテキストを設定
343        btn.textContent = '閉じる';
344      } else {
345        //コンテンツの高さを固定値を代入
346        content.style.maxHeight = '800px';
347        //openクラスを削除
348        content.classList.remove('open');
349        btn.classList.remove('open'); // ボタンのクラスを削除
350        //もっと見るボタンのテキストを設定
351        btn.textContent = 'もっと見る';
352      }
353    });
354  }
355
356})();
357
358// 最新情報スライダー
359(function() {
360  const slider = document.querySelector('#news_splide');
361  if (slider) {
362    const splide = new Splide(slider, {
363      fixedWidth : '40%',
364      rewind: true,
365      arrows: false,
366      autoplay: true,
367      interval: 3000,
368      speed: 1000,
369      focus: 'left',
370      gap: 30,
371      pagination: false,
372      breakpoints: {
373        768: {
374          fixedWidth : '70%',
375          gap: 7
376        }
377      }
378    });
379
380    splide.mount();
381  }
382})();
383
384// レストランスライダー
385(function() {
386  const slider = document.querySelector('#restrant_splide');
387  if (slider) {
388    const splide = new Splide(slider, {
389      type   : 'loop',
390      padding: '10%',
391      gap: 0,
392      drag   : 'free',
393      focus  : 'center',
394      arrows: false,
395      pagination: false,
396      perPage: 1,
397      autoScroll: {
398        speed: 1,
399        pauseOnHover: false,
400        pauseOnFocus: false,
401      },
402    });
403
404    splide.mount(window.splide.Extensions);  // AutoScroll拡張機能をマウント
405  }
406})();
407
408// パララックス
409(function() {
410  const elm = document.querySelector('[data-parallax]');
411
412  if (elm) {
413    let flg;
414    let rellaxInstance = null;
415
416    window.addEventListener('mqChangeSp', () => {
417      flg = 'sp';
418    });
419    window.addEventListener('mqChangePc', () => {
420      flg = 'pc';
421    });
422
423    // アクセス時
424    document.addEventListener('DOMContentLoaded', () => {
425      const targets = document.querySelectorAll('[data-parallax-wrapper]');
426      myModule.monitorImagesLoad(targets, () => {
427        initRellax();
428      });
429    });
430    // リサイズ時
431    window.addEventListener('resize', myModule.debounce(() => {
432      initRellax();
433    }, 300));
434
435    function initRellax() {
436      if (flg === 'pc' && rellaxInstance === null) {
437        rellaxInstance = new Rellax('[data-parallax]', {
438          speed: -5,
439          center: true,
440          vertical: true
441        });
442      } 
443      else if (flg !== 'pc' && rellaxInstance !== null) {
444        rellaxInstance.destroy();
445        rellaxInstance = null;
446      }
447    }
448  }
449})();
450
451// トップページ スプラッシュ
452(function() {
453  const splash = document.querySelector('[data-top-splash]');
454  const splashBG = document.querySelector('[data-top-splash-bg]');
455
456  if (splash) {
457    const cookie = 'top-splash';
458    const className = 'is-show';
459    const classNameBG = 'is-hide';
460
461    if (!Cookies.get(cookie)) {
462      const html = document.querySelector('html');
463      const body = document.querySelector('body');
464      const closeButton = document.querySelector('[data-top-splash-close]');
465      const currentScrollY = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
466
467      // スプラッシュを表示
468      body.style.cssText = 'position: fixed; top: ' + -currentScrollY + 'px;' + 'width: 100%;';
469      splash.classList.add(className);
470
471      // 「レストランのご案内」ボタンクリックでスプラッシュを閉じる
472      closeButton.addEventListener('click', () => {
473        body.style.cssText = 'position: ; top: ; width: ;';
474        body.scrollTop = currentScrollY;
475        html.scrollTop = currentScrollY;
476        splash.classList.remove(className);
477        splashBG.classList.add(classNameBG);
478      });
479
480      // クッキーを保存(期限 : 1日)
481      Cookies.set(cookie, 'shown', { expires: 1 });
482    } else {
483      splashBG.classList.add(classNameBG);
484    }
485  }
486})();
487
488// 個室フロアページ フィルタリング
489(function() {
490  const select = document.querySelector('[data-private-select]');
491
492  if (select) {
493    const sections = document.querySelectorAll('[data-private-section]');
494    const items = document.querySelectorAll('[data-private-item]');
495    const filteredClassName = 'is-filtered';
496    const selectedClassName = 'is-selected';
497
498    function privateSelectChange() {
499      const selectedValue = select.value;
500
501      if (selectedValue === "") {
502        sections.forEach(section => {
503          section.classList.remove(filteredClassName);
504        });
505        items.forEach(item => {
506          item.classList.remove(selectedClassName);
507        });
508      } else {
509        sections.forEach(section => {
510          section.classList.add(filteredClassName);
511          items.forEach(item => {
512            if (item.getAttribute('data-private-item') === selectedValue) {
513              item.classList.add(selectedClassName);
514            } else {
515              item.classList.remove(selectedClassName);
516            }
517          });
518        });
519      }
520    }
521
522    privateSelectChange();
523    select.addEventListener('change', privateSelectChange);
524  }
525})();

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.