PageSourceSearch

https://blu-clinic.jp/wp/wp-content/themes/bluclinic/assets/js/main.js?ver=1.0

js blu-clinic.jp collected 2026-10-08 23:38:57 UTC 8,545 bytes, 280 lines download raw bytes

1jQuery(function($) {
2  // page-top表示
3  const $w = $(window);
4  const $d = $(document);
5
6  const $pt = $(".page-top-btn");
7  const $f = $(".footer__bottom");
8  const hasFooter = $f.length > 0;
9
10  $pt.hide();
11
12  const SHOW = 100;
13  const ptBottom = (sp) => (sp ? "5.13vw" : "30px");
14
15  let ptVisible = false;
16
17  function update() {
18    const st = $w.scrollTop();
19    const sp = $w.width() <= 767;
20
21    const shouldShow = st > SHOW;
22
23    if (shouldShow !== ptVisible) {
24      ptVisible = shouldShow;
25      if (shouldShow) {
26        $pt.stop(true, true).css({ display: 'grid', opacity: 0 }).animate({ opacity: 1 }, 200);
27      } else {
28        $pt.stop(true, true).fadeOut('fast');
29      }
30    }
31
32    if (!hasFooter) return;
33
34    const sh = $d.height();
35    const spn = $w.height() + st;
36    const fh = $f.innerHeight();
37
38    if (sh - spn <= fh) {
39      $pt.css({ position: "absolute", bottom: `calc(${ptBottom(sp)} + ${fh}px)` });
40    } else {
41      $pt.css({ position: "fixed", bottom: ptBottom(sp) });
42    }
43  }
44
45  $w.on("scroll resize", update);
46  update();
47
48  $pt.on("click", function () {
49    window.scrollTo({ top: 0, behavior: "smooth" });
50    return false;
51  });
52
53  /* ドロワーメニュー(SP:〜999px / PC:1000px〜) */
54  function closeAllPopups() {
55    $('.js-lang-toggle, .js-contact-toggle')
56      .attr('aria-expanded', 'false')
57      .removeClass('is-open');
58    $('.header__lang--panel').removeClass('is-open').attr('aria-hidden', 'true');
59    $('.header__drop--panel').removeClass('is-open').attr('aria-hidden', 'true');
60  }
61
62  const $drawer = $('.js-drawer');
63  const $drawerBtn = $('.js-header-toggle');
64
65  function openDrawer() {
66    closeAllPopups();
67    $drawer.addClass('is-open').attr('aria-hidden', 'false');
68    $drawerBtn.addClass('is-open').attr('aria-expanded', 'true');
69    $('body').addClass('is-locked');
70  }
71
72  function closeDrawer() {
73    $drawer.removeClass('is-open').attr('aria-hidden', 'true');
74    $drawerBtn.removeClass('is-open').attr('aria-expanded', 'false');
75    $('body').removeClass('is-locked');
76  }
77
78  $drawerBtn.on('click', function () {
79    if ($drawer.hasClass('is-open')) {
80      closeDrawer();
81    } else {
82      openDrawer();
83    }
84  });
85
86  // PC(1000px〜)になったらドロワーを閉じる
87  const drawerMq = window.matchMedia('(min-width: 1000px)');
88  drawerMq.addEventListener('change', function (e) {
89    if (e.matches) closeDrawer();
90  });
91
92  /* ポップアップ(言語・コンタクト) */
93  function togglePopup($btn, $panel) {
94    var isOpen = $btn.attr('aria-expanded') === 'true';
95    closeAllPopups();
96    if (!isOpen) {
97      $btn.attr('aria-expanded', 'true').addClass('is-open');
98      $panel.addClass('is-open').attr('aria-hidden', 'false');
99    }
100  }
101
102  $('.js-lang-toggle').on('click', function (e) {
103    e.stopPropagation();
104    togglePopup($(this), $(this).next('.header__lang--panel'));
105  });
106
107  $('.js-contact-toggle').on('click', function (e) {
108    e.stopPropagation();
109    togglePopup($(this), $(this).next('.header__drop--panel'));
110  });
111
112  $(document).on('click.popup', function () {
113    closeAllPopups();
114  });
115
116  $(document).on('keydown.popup', function (e) {
117    if (e.key === 'Escape') closeAllPopups();
118  });
119
120  $('.header__lang--panel, .header__drop--panel').on('click', function (e) {
121    e.stopPropagation();
122  });
123
124  // 選択中の言語をボタンに表示
125  function updateLanguageButton() {
126    const $activeLink = $('a[data-stt-changelang][data-stt-active]');
127    if ($activeLink.length) {
128      const fullText = $activeLink.text().trim();
129      const langCode = $activeLink.attr('data-stt-changelang').toUpperCase();
130
131      $('.js-lang-full').text(fullText);
132      $('.js-lang-code').text(langCode);
133    }
134  }
135
136  // 初期表示
137  updateLanguageButton();
138
139  // Shuoto の言語切り替えを監視(MutationObserver を使用)
140  const langList = document.querySelector('.header__lang--list');
141  if (langList) {
142    const observer = new MutationObserver(function () {
143      updateLanguageButton();
144    });
145    observer.observe(langList, { attributes: true, subtree: true, attributeFilter: ['data-stt
145-active'] });
146  }
147
148  // スムーススクロール
149  $('a[href^="#"]').on('click', function (e) {
150    e.preventDefault();// ← URLに #◯◯ が付かなくなる
151    const speed = 600;
152    const href = $(this).attr('href');
153    const target = href === '#' || href === '' ? $('html') : $(href);
154    // ▼ CSS変数 --header-height を取得(px → 数値に変換)
155    const headerHeight = parseInt(
156      getComputedStyle(document.documentElement).getPropertyValue('--header-height')
157    ) || 0;
158    // ▼ 固定ヘッダー分を差し引いた位置
159    const position = target.offset().top - headerHeight;
160    $('html, body').animate({ scrollTop: position }, speed, 'swing');
161  });
162
163  // 切り替える対象にclass属性
164  var $elem = $('.js-switch');
165  var sp = '_sp.';
166  var pc = '_pc.';
167  var replaceWidth = 768;
168
169  function imageSwitch() {
170    var windowWidth = parseInt($(window).width());
171    $elem.each(function() {
172      var $this = $(this);
173      // ウィンドウサイズが768px以上であれば_spを_pcに置換ã
173™ã‚‹ã€‚
174      if(windowWidth >= replaceWidth) {
175        $this.attr('src', $this.attr('src').replace(sp, pc));
176
177      // ウィンドウサイズが768px未満であれば_pcを_spに置換する。
178      } else {
179        $this.attr('src', $this.attr('src').replace(pc, sp));
180      }
181    });
182  }
183  imageSwitch();
184
185  // 動的なリサイズは操作後0.2秒経ってから処理を実行する。
186  var resizeTimer;
187  $(window).on('resize', function() {
188    clearTimeout(resizeTimer);
189    resizeTimer = setTimeout(function() {
190      imageSwitch();
191    }, 200);
192  });
193});
194
195// アニメーション
196jQuery(function ($) {
197  var $animationElements = $('.scrollUp, .fadeIn');
198  var triggerMargin = 100;
199  function checkAnimation() {
200    $animationElements.each(function () {
201      var elementTop = this.getBoundingClientRect().top;
202      if (window.innerHeight > elementTop + triggerMargin) {
203        $(this).addClass('animated');
204      }
205    });
206  }
207  $(window).on('load scroll', checkAnimation);
208  // Safari対策で遅延実行を追加(初期状態でもチェック)
209  setTimeout(checkAnimation, 100);
210});
211
212// FAQ toggle
213jQuery(function ($) {
214  if (!document.querySelector('.faq__question')) return;
215  $(document).on('click', '.faq__question', function (e) {
216    e.preventDefault();
217    var $q = $(this);
218    var $a = $q.next('.faq__answer');
219    if (!$a.length) return;
220    var expanded = $q.attr('aria-expanded') === 'true';
221    $a.stop(true, false).slideToggle(250);
222    $q.toggleClass('--open', !expanded);
223    $q.attr('aria-expanded', !expanded);
224  });
225});
226
227// フォーム:select文字色変更
228document.addEventListener('DOMContentLoaded', function () {
229  const selects = document.querySelectorAll('select');
230  selects.forEach(function (select) {
231    updateSelectColor(select);
232
233    select.addEventListener('change', function () {
234      updateSelectColor(select);
235    });
236  });
237  function updateSelectColor(el) {
238    if (el.selectedIndex === 0) {
239      el.style.color = '#000';
240    } else {
241      el.style.color = '';
242    }
243  }
244});
245
246// モーダルトグル共通関数
247function initToggleModal(buttonSelector, modalSelector, cardSelector = null) {
248  const buttons = document.querySelectorAll(buttonSelector);
249  buttons.forEach((btn) => {
250    // カード要素を見つける(cardSelectorで指定されていれば使用、そうでなければボタンの親を探索)
251    let card = cardSelector ? btn.closest(cardSelector) : btn.closest('div[class*="__card"]');
252    if (!card) card = btn.parentElement;
253
254    const modal = card?.querySelector(modalSelector);
255    const btnText = btn.querySelector('span') || btn;
256    const originalText = btnText.textContent.trim();
257
258    btn.addEventListener('click', (e) => {
259      e.preventDefault();
260      const isOpen = btn.getAttribute('aria-expanded') === 'true';
261
262      if (!isOpen) {
263        btn.setAttribute('aria-expanded', 'true');
264        modal?.setAttribute('aria-hidden', 'false');
265        btnText.textContent = 'CLOSE';
266      } else {
267        btn.setAttribute('aria-expanded', 'false');
268        modal?.setAttribute('aria-hidden', 'true');
269        btnText.textContent = originalText;
270      }
271    });
272  });
273}
274
275// モーダル機能の初期化
276document.addEventListener('DOMContentLoaded', function () {
277  // 汎用モーダルトグル初期化
278  initToggleModal('.js-toggle-modal', '.modal-toggle');
279});
280

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.