PageSourceSearch

https://www.shinjukubc.com/wp-content/themes/juno_clinic_service/js/common.js?0819&ver=1.0.0

js shinjukubc.com collected 2026-10-04 14:20:26 UTC 12,964 bytes, 428 lines download raw bytes

1$(function () {
2  /**********
3   * グローバルナビ
4   **********/
5  $('#ji-header-globalnavi-open-trigger').on('click', function () {
6    $('#ji-header-globalnavi').addClass('js-open');
7    $('body').addClass('js-fixed');
8  });
9  $('#ji-header-globalnavi-close-trigger').on('click', function () {
10    $('#ji-header-globalnavi').removeClass('js-open');
11    $('body').removeClass('js-fixed');
12  });
13
14  /**********
15   * アコーディンの表示設定
16   **********/
17  $('.jc-acc-trigger').on('click', function () {
18    $(this).toggleClass('js-active').next('.jc-acc-content').slideToggle(400);
19    $(this).next('.jc-acc-content').toggleClass('js-active');
20  });
21
22  /**********
23   * アコーディン(開くだけ)の表示設定
24   **********/
25  $('.jc-open-trigger').on('click', function () {
26    $(this).addClass('js-inactive');
27    $(this).removeClass('c-btn'); // 通常ボタンのclassを削除
28    $(this).addClass('c-btn-inactive'); // 非活性ボタンのclassを付与
29    $(this).next('.jc-open-content').addClass('js-active');
30    $(this).next('.jc-open-content').fadeIn(400);
31  });
32
33  /**********
34   * 目次のアコーディン処理
35   **********/
36  $('.toc_title').on('click', function () {
37    $(this).toggleClass('js-active').next('.toc_list').slideToggle(400);
38    $(this).next('.toc_list').toggleClass('js-active');
39  });
40
41  /**********
42   * タブ切り替え
43   **********/
44  $('.jc-tab').on('click', function () {
45    $(this)
46      .addClass('js-active')
47      .siblings('.js-active')
48      .removeClass('js-active');
49    var target = $(this).data('target');
50    $(target)
51      .addClass('js-active')
52      .siblings('.js-active')
53      .removeClass('js-active');
54    return false;
55  });
56
57  /**********
58   * ページトップのスクロール処理
59   **********/
60  var window_cash = $(window);
61
62  /*var pos_fix = function () {
63    now = window_cash.scrollTop();
64    under = window_cash.height() / 2;
65    if (now > under) {
66      $("#ji-pagetop, #ji-pagetop2, #ji-toc").fadeIn(600);
67    } else {
68      $("#ji-pagetop, #ji-pagetop2, #ji-toc").fadeOut(600);
69    }
70  };
71  
72  $(window).on("load scroll resize", function () {
73    pos_fix();
74  });*/
75
76  $('#ji-pagetop, #ji-pagetop2').on('click', function () {
77    var speed = 600; // ミリ秒
78    $('html, body').animate({ scrollTop: 0 }, speed, 'swing');
79    return false;
80  });
81
82  /**********
83   * ページ内スクロール(Smooth Scroll)処理
84   **********/
85  $('a[href^="#"]').on('click', function () {
86    var speed = 600; // ミリ秒
87    var href = $(this).attr('href');
88    var target = $(href == '#' || href == '' ? 'html' : href);
89    var header_h = document.getElementById('ji-header').offsetHeight; // 共通ヘッダーの高さ
90    var position = target.offset().top - header_h - 32;
91    $('body, html').animate({ scrollTop: position }, speed, 'swing');
92    return false;
93  });
94
95  /**********
96   * 共通ヘッダーのスクロール追従表示
97   **********/
98  $(window).scroll(function () {
99    if ($(window).scrollTop() > 40) {
100      // 40px分スクロールしたら
101      $('#ji-header').addClass('js-scroll-fixed');
102      $('body').addClass('js-scroll-fixed');
103    } else {
104      $('#ji-header').removeClass('js-scroll-fixed');
105      $('body').removeClass('js-scroll-fixed');
106    }
107  });
108
109  /**********
110   * hover menu 処理
111   **********/
112  if (window.matchMedia('(min-width:769px)').matches) {
113    $('.js-hovermenu').hover(
114      function () {
115        $('.hovermenu_inner').fadeIn('fast');
116      },
117      function () {
118        $('.hovermenu_inner').fadeOut('fast');
119      },
120    );
121  }
122  if (window.matchMedia('(max-width:768px)').matches) {
123    $('.js-hovermenu').on('click', function () {
124      $('.hovermenu_inner').slideToggle(400);
125    });
126  }
127
128  /**********
129   * 写真のfadeIn処理
130   **********/
131  $(window).scroll(function () {
132    $('.jc-scroll-fade-up').each(function () {
133      var targetTop = $(this).offset().top;
134      var scrollTop = $(window).scrollTop();
135      var windowHeight = $(window).height();
136      if (scrollTop > targetTop - windowHeight + windowHeight / 4) {
137        $(this).addClass('js-show');
138      }
139    });
140  });
141
142  /**********
143   * 割引プランのタブ
144   **********/
145  /* 選択中のタブの左隣に位置するタブにclassを付与する */
146  /* classを付与したタブの右側枠線を削除する */
147  $('#ji-navi-price-tabs .is-current').prev().addClass('js-current-before');
148
149  /**********
150   * お問い合わせフォーム
151   **********/
152  /* エラーになっている入力欄にError用のclassを付与する */
153  if ($('.m-form-parts__input .c-form-error')[0]) {
154    $('.m-form-parts__input .c-form-error')
155      .parents('.m-form-parts__input')
156      .addClass('is-error');
157  }
158
159  /* エラーになっている入力欄がある場合、ボタン下部にエラーメッセージを表示する */
160  if ($('.m-form-parts__input .c-form-error')[0]) {
161    $('#ji-form-error-message').show();
162  } else {
163    $('#ji-form-error-message').hide();
164  }
165
166  /**********
167   * フロートCTAクローズボタン
168   **********/
169  $('.js-floatcta_close_btn').on('click', function () {
170    $('.m-floatcta').css({ display: 'none' });
171    $('.l-footer-pagetop__fixed').css({ bottom: '4vw' });
172    document.cookie =
173      'fixcta=' + encodeURIComponent('hidden') + ';Max-Age=86400';
174  });
175
176  /**********
177   * フロートCTA表示・非表示
178   **********/
179  $(window).on('load scroll', function () {
180    var cookieValue = document.cookie
181      .split('; ')
182      .find((row) => row.startsWith('fixcta'));
183
184    if (cookieValue) {
185      return;
186    }
187
188    if ($('.js-fix-footer').length) {
189      if ($(window).scrollTop() > 300) {
190        $('.js-fix-footer').fadeIn(400);
191        //var fh = $(".js-fix-footer").outerHeight() + 8;
192        var fh = $('#float_cta').outerHeight() + 8;
193        $('.l-footer-pagetop__fixed').css({ bottom: fh + 'px' });
194        $('.m-toc-btn').css({ 'margin-bottom': '62px' });
195      } else {
196        $('.js-fix-footer').fadeOut(400);
197        $('.l-footer-pagetop__fixed').css({ bottom: '2.666vw' });
198        $('.m-toc-btn').css({ 'margin-bottom': '0' });
199      }
200    }
201  });
202
203  initCtaParamTracker();
204
205  function initCtaParamTracker() {
206    console.log('initCtaParamTracker');
207
208    // 設定
209    const CONFIG = {
210      // クリック時にURLを保存するためのデータ属性(遷移元リンク)
211      SAVE_URL_ATTR: 'data-cta-param-save',
212      // accパラメータを付与するためのデータ属性(CTAリンク)
213      ADD_PARAM_ATTR: 'data-cta-param-apply',
214      // セッションストレージのキー
215      STORAGE_KEY: 'cta-param:referrer-path',
216      // URLパラメータ名
217      PARAM_NAME: 'acc',
218      // 最大パス長
219      MAX_PATH_LENGTH: 2048,
220    };
221
222    // ========================================
223    // バリデーション
224    // ========================================
225
226    /**
227     * パス文字列のバリデーション
228     * @param {string} path - チェックするパス
229     * @returns {boolean} 有効な場合true
230     */
231    function isValidPath(path) {
232      if (!path || typeof path !== 'string') {
233        return false;
234      }
235
236      // 長さチェック
237      if (path.length > CONFIG.MAX_PATH_LENGTH) {
238        console.error('Path too long:', path.length);
239        return false;
240      }
241
242      // 制御文字のチェック
243      if (/[\x00-\x1F\x7F]/.test(path)) {
244        console.error('Control characters detected in path');
245        return false;
246      }
247
248      return true;
249    }
250
251    // ========================================
252    // ユーティリティ関数
253    // ========================================
254
255    /**
256     * sessionStorageが利用可能かチェック
257     * @returns {boolean} 利用可能な場合true
258     */
259    function isSessionStorageAvailable() {
260      try {
261        const testKey = '__storage_test__';
262        sessionStorage.setItem(testKey, 'test');
263        sessionStorage.removeItem(testKey);
264        return true;
265      } catch (e) {
266        console.error('sessionStorage is not available:', e);
267        return false;
268      }
269    }
270
271    // ========================================
272    // コア機能
273    // ========================================
274
275    /**
276     * 現在のページパスを取得
277     * クエリ文字列・ハッシュは含めず、パス部分のみを返す
278     * 例: https://xxxxxx.com/aaaa/bbbbb/cccc#dddd?eee=ffff -> /aaaa/bbbbb/cccc
279     * @returns {string} ページパス
280     */
281    function getCurrentPath() {
282      return window.location.pathname;
283    }
284
285    /**
286     * URLにaccパラメータを付与
287     * @param {string} url - 元のURL
288     * @param {string} path - 付与するパス
289     * @returns {string|null} パラメータ付きURL、失敗時はnull
290     */
291    function addAccParam(url, path) {
292      if (!isValidPath(path)) {
293        console.error('Invalid path rejected:', path);
294        return null;
295      }
296
297      try {
298        const urlObj = new URL(url, window.location.origin);
299        urlObj.searchParams.set(CONFIG.PARAM_NAME, path);
300        return urlObj.toString();
301      } catch (e) {
302        console.error('Failed to add parameter:', e);
303        return null;
304      }
305    }
306
307    /**
308     * セッションストレージにパスを保存
309     * @param {string} path - 保存するパス
310     * @returns {boolean} 成功した場合true
311     */
312    function savePath(path) {
313      if (!isSessionStorageAvailable()) {
314        return false;
315      }
316
317      if (!isValidPath(path)) {
318        console.error('Invalid path, not saving:', path);
319        return false;
320      }
321
322      try {
323        sessionStorage.setItem(CONFIG.STORAGE_KEY, path);
324        return true;
325      } catch (e) {
326        console.error('Failed to save to sessionStorage:', e);
327        return false;
328      }
329    }
330
331    /**
332     * セッションストレージからパスを取得
333     * @returns {string|null} 保存されたパス、または null
334     */
335    function getSavedPath() {
336      if (!isSessionStorageAvailable()) {
337        return null;
338      }
339
340      try {
341        const path = sessionStorage.getItem(CONFIG.STORAGE_KEY);
342
343        // 取得した値をバリデーション
344        if (path && isValidPath(path)) {
345          return path;
346        }
347
348        return null;
349      } catch (e) {
350        console.error('Failed to read from sessionStorage:', e);
351        return null;
352      }
353    }
354
355    /**
356     * クリック時の処理をdocumentへのイベント委譲で設定する
357     *
358     * 同一リンクに両属性が付く場合を考慮し、1つのハンドラ内で
359     * 「save → apply」の順に処理する。これによりapplyは
360     * save直後の最新の保存値(=今クリックしたページのパス)を使う。
361     *
362     * preventDefaultは行わず、書き換えたhrefへブラウザの標準遷移に任せる。
363     * これにより target="_blank" の自動noopener・修飾キークリック等が
364     * ネイティブのまま維持される。
365     */
366    function setupLinkHandler() {
367      document.addEventListener('click', function (e) {
368        const link = e.target.closest(
369          'a[' + CONFIG.SAVE_URL_ATTR + '], a[' + CONFIG.ADD_PARAM_ATTR + ']',
370        );
371        if (!link) {
372          return;
373        }
374
375        // 1) 保存(現在のパスをsessionStorageへ)
376        if (link.hasAttribute(CONFIG.SAVE_URL_ATTR)) {
377          savePath(getCurrentPath());
378        }
379
380        // 2) 付与(保存済みパスをaccパラメータとしてhrefへ)
381        if (link.hasAttribute(CONFIG.ADD_PARAM_ATTR)) {
382          const savedPath = getSavedPath();
383          if (!savedPath) {
384            return;
385          }
386
387          const originalHref = link.getAttribute('href');
388          if (!originalHref || originalHref.startsWith('#')) {
389            return;
390          }
391
392          const updatedHref = addAccParam(originalHref, savedPath);
393          if (updatedHref) {
394            // hrefを書き換えるだけ。preventDefaultしないので標準遷移が走る
395            link.setAttribute('href', updatedHref);
396          } else {
397            console.error('Failed to update link, keeping original href');
398          }
399        }
400      });
401    }
402
403    /**
404     * 初期化処理
405     */
406    function init() {
407      // sessionStorageの利用可能性チェック
408      if (!isSessionStorageAvailable()) {
409        console.error('This script requires sessionStorage support');
410        return;
411      }
412
413      // documentへのイベント委譲のため、DOM構築の完了を待つ必要はない
414      setupLinkHandler();
415    }
416
417    // 初期化実行
418    init();
419  }
420});
421
422/**********
423 * Bodyに共通ヘッダー分の上部余白を付与する
424 **********/
425$(window).on('load', function () {
426  var header_h = document.getElementById('ji-header').offsetHeight; // 共通ヘッダーの高さ
427  $('body').css({ 'padding-top': header_h });
428});

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.