PageSourceSearch

https://golf-fujico.com/view/asset/user-8-1-5-1078ce03bb0c3d78d17fa78e9f013844.js

js golf-fujico.com collected 2026-10-08 20:28:13 UTC 26,699 bytes, 761 lines download raw bytes

1/* ====================================================================
2   ゴルフショップ フジコ
3   貼り先:クリエイターモード / 全ページ共通 / JavaScript欄
4
5   ★貼り方★
6   JavaScript欄の中身を「全部消してから」、
7   このファイルの中身を丸ごと貼り付けてください。
8   一部だけ差し替えるのではありません。
9
10   このファイルには、もとのテンプレートのコードも
11   すべて含まれています。カート・お気に入り・
12   スライダー・カレンダーはそのまま動きます。
13
14   ★もとのコードから2か所だけ直しています★
15   1. ハンバーガーメニューのボタンが存在しないページで
16      エラーになる箇所に、存在チェックを足しました。
17   2. フォントの二重読み込みを削除しました。
18      詳しくは該当箇所のコメントに書いています。
19   ==================================================================== */
20
21
22$(function () {
23    $('.category-link').on('click', function (event) {
24        var submenu = $(this).next('.sub-menu');
25        var plusIcon = $(this).find('i');
26
27        if (submenu.length) {
28            event.preventDefault();
29            var isVisible = submenu.attr('aria-hidden') === 'false';
30            submenu.attr('aria-hidden', isVisible ? 'true' : 'false');
31
32            if (isVisible) {
33                plusIcon.removeClass('fi-rr-minus-small').addClass('fi-rr-plus-small');
34            } else {
35                plusIcon.removeClass('fi-rr-plus-small').addClass('fi-rr-minus-small');
36            }
37        }
38    });
39
40    $('.search-keyword, .search-price, .original-code').on('keydown', function (e) {
41        if (e.key === 'Enter') {
42            $('.search-url')[0].click();
43        }
44    });
45
46    /* ★削除しました★
47       ここでWebFontLoaderを使い、Noto Sans JPを9ウェイト、
48       Outfitを9ウェイト、計18種類を読み込んでいました。
49
50       ・Noto Sans JP は CSSの @import ですでに読み込み済み
51         (二重取得でした)
52       ・Outfit はサイトのどこでも使われていません
53
54       日本語フォントは1つでも重く、後から読み込まれるたびに
55       文字の大きさが変わってページ全体が動きます。
56       表示速度と、読み込み中のガタつきの両方に効きます。
57
58       戻したい場合は、この囲みを削除して
59       元のコードを書き戻してください。 */
60
61    var searchIcon = document.getElementById('search-icon');
62    var searchBox = document.querySelector('.search-box');
63
64    if (searchIcon && searchBox) {
65        searchIcon.addEventListener('click', function (event) {
66            event.stopPropagation();
67
68            if (searchBox.classList.contains('search-hidden')) {
69                searchBox.classList.remove('search-hidden');
70                searchBox.classList.add('search-visible');
71            } else {
72                searchBox.classList.remove('search-visible');
73                searchBox.classList.add('search-hidden');
74            }
75
76            if (searchBox.classList.contains('search-visible')) {
77                var input = searchBox.querySelector('input');
78                if (input) {
79                    input.focus();
80                }
81            }
82        });
83
84        var searchClose = searchBox.querySelector('.fi-rr-cross');
85        if (searchClose) {
86            searchClose.addEventListener('click', function (event) {
87                event.stopPropagation();
88                searchBox.classList.remove('search-visible');
89                searchBox.classList.add('search-hidden');
90            });
91        }
92
93        document.addEventListener('click', function (event) {
94            if (!searchBox.contains(event.target) && event.target !== searchIcon) {
95                if (searchBox.classList.contains('search-visible')) {
96                    searchBox.classList.remove('search-visible');
97                    searchBox.classList.add('search-hidden');
98                }
99            }
100        });
101    }
102});
103
104function MakeShop_afterListCartEntry(data) {
105    if (data.result) {
106        $('.cart-badge').text(data.totalQuantity).show();
107
108        const notification = $('.cart-notification');
109        notification.stop(true, true).fadeIn(300);
110
111        setTimeout(() => {
112            notification.fadeOut(500);
113        }, 3000);
114    } else {
115        data.method.modal(data.error.message, function () {
116            if (data.systemCode) {
117                location.href = '/view/item/' + data.systemCode;
118            }
119        });
120    }
121    return false;
122}
123
124function MakeShop_afterListFavoriteEntry(data) {
125    if (!data.result) {
126        data.method.modal(data.error.message);
127        return false;
128    }
129
130    $('a[href="' + data.source + '"]').addClass('hide').siblings('.favorite-on').removeClass('hide');
131
132    return false;
133}
134
135function MakeShop_afterListFavoriteRemove(data) {
136    if (!data.result) {
137        data.method.modal(data.error.message);
138        return false;
139    }
140
141    $('a[href="' + data.source + '"]').addClass('hide').siblings('.favorite-off').removeClass('hide');
142
143    return false;
144}
145
146document.addEventListener('DOMContentLoaded', function () {
147    const btn = document.querySelector('.header-hm-btn');
148    const headerLeft = document.querySelector('.header-left');
149    const hmBorder = document.querySelector('.hm-border');
150    if (btn && headerLeft && hmBorder) {
151        btn.addEventListener('click', function () {
152            headerLeft.classList.toggle('active');
153            hmBorder.classList.toggle('active');
154        });
155    }
156});
157
158$(function () {
159    const $container = $('.header-news-swiper-container');
160    const slideCount = $container.find('.swiper-slide').length;
161    var swiper = new Swiper('.header-news-swiper-container', {
162        loop: slideCount > 1,
163        slidesPerView: 1,
164        spaceBetween: 10,
165        direction: 'vertical',
166        autoplay: {
167            delay: 6000,
168            disableOnInteraction: false,
169        },
170        speed: 1000,
171        allowTouchMove: false,
172        autoHeight: true,
173        initialSlide: 0
174    });
175});
176
177document.addEventListener('DOMContentLoaded', () => {
178    const sliderElements = document.querySelectorAll('.item-list-slider-wrap');
179    sliderElements.forEach((el, index) => {
180        new Swiper(el, {
181            slidesPerView: 'auto',
182            grabCursor: true,
183            spaceBetween: 0,
184            speed: 500,
185            loop: false,
186            autoHeight: false,
187            watchSlidesProgress: true,
188            observer: true,
189            observeParents: true,
190            breakpoints: {
191                0: {
192                    slidesOffsetAfter: 100
193                },
194                768: {
195                    slidesOffsetAfter: 200
196                },
197                1024: {
198                    slidesOffsetAfter: 300
199                }
200            },
201            navigation: {
202                nextEl: el.querySelector('.swiper-button-next'),
203                prevEl: el.querySelector('.swiper-button-prev')
204            },
205            pagination: {
206                el: el.querySelector('.swiper-pagination'),
207                type: 'progressbar'
208            }
209        });
210    });
211});
212
213document.addEventListener('DOMContentLoaded', function () {
214    var calendarSwiper = new Swiper('.calendar-swiper-container', {
215        loop: false,
216        navigation: {
217            nextEl: '.calendar-swiper-button-next',
218            prevEl: '.calendar-swiper-button-prev',
219        },
220        breakpoints: {
221            768: {
222                slidesPerView: 2,
223            },
224            767: {
225                slidesPerView: 1,
226            }
227        }
228    });
229
230    $('.day-list').each(function () {
231        var month = $(this).attr('data-month');
232        var day = $(this).attr('data-day');
233        var color = $(this).attr('data-color');
234
235        $('.makeshop-calendar' + month + ' .day' + day).css({
236            'background-color': color,
237            'color': '#fff',
238            'font-weight': 'bold',
239        });
240    });
241});
242
243
244/* ====================================================================
245   ゴルフショップ フジコ
246   貼り先:クリエイターモード / 全ページ共通 / JavaScript欄
247
248   ★貼り方★
249   今ある内容は消さずに、いちばん下に追記してください。
250   以前お渡しした cart-label-ja / fjc-common-add /
251   review-empty-hide を貼っている場合は、それらを削除してから
252   これを貼ってください。内容はすべてここに入っています。
253
254   中身は6つです。
255   1. ヘッダーの高さを測って余白に反映
256   2. 見出しの英語を日本語に
257   3. ボタンの英語を日本語に
258   4. レビューが0件のときセクションを隠す
259   5. カレンダーの休業日に色を付ける
260   6. バナーのクリックを確実にする
261   ==================================================================== */
262
263
264/* このファイルが最後まで読み込まれたことを示す目印。
265   診断で使います。削除しないでください。 */
266window.FJC_COMMON_START = true;
267
268/* --------------------------------------------------------------------
269   1. ヘッダーの高さを実測して余白に反映
270
271   決め打ちだとロゴを画像に変えたときやスマホでずれるので、
272   その都度測って合わせます。
273   お知らせバーが出ているときは、その高さも足します。
274   -------------------------------------------------------------------- */
275
276(function () {
277
278    function setHeaderHeight() {
279        var header = document.querySelector('header');
280        var news = document.querySelector('.header-news-swiper-container');
281        var total = 0;
282
283        if (header) {
284            total += header.offsetHeight;
285        }
286        if (news && getComputedStyle(news).display !== 'none') {
287            total += news.offsetHeight;
288        }
289        if (total > 0) {
290            document.documentElement.style.setProperty('--fjc-header', total + 'px');
291        }
292
293        /* ハンバーガーボタンを揃えるため、ヘッダーの上下の中心も測ります。
294           ヘッダーは position:fixed なので、この値はスクロールしても変わりません。 */
295        if (header) {
296            var r = header.getBoundingClientRect();
297            var mid = Math.round(r.top + r.height / 2);
298            if (mid > 0) {
299                document.documentElement.style.setProperty('--fjc-hm-top', mid + 'px');
300            }
301        }
302    }
303
304    if (document.readyState === 'loading') {
305        document.addEventListener('DOMContentLoaded', setHeaderHeight);
306    } else {
307        setHeaderHeight();
308    }
309    window.addEventListener('load', setHeaderHeight);
310    window.addEventListener('resize', setHeaderHeight);
311
312})();
313
314
315/* --------------------------------------------------------------------
316   2. 見出しの英語を日本語に
317
318   新着・お知らせ・レビューはモジュールを直接直したので、
319   ここが担当するのは主にランキング・チェックアイテム・
320   カレンダーです。
321
322   ★言葉を変えたいときは右側だけ書き換えてください★
323   -------------------------------------------------------------------- */
324
325(function () {
326
327    var HEADING = {
328        'Ranking':       '売れ筋ランキング',
329        'RANKING':       '売れ筋ランキング',
330        'New Arrival':   '新着商品',
331        'New Arrivals':  '新着商品',
332        'NEW ARRIVAL':   '新着商品',
333        'NEW ARRIVALS':  '新着商品',
334        'Review':        'お客様レビュー',
335        'Reviews':       'お客様レビュー',
336        'REVIEW':        'お客様レビュー',
337        'News':          'お知らせ',
338        'NEWS':          'お知らせ',
339        'Checked Item':  '最近見た商品',
340        'Checked Items': '最近見た商品',
341        'CHECKED ITEM':  '最近見た商品',
342        'Schedule':      '営業日カレンダー',
343        'SCHEDULE':      '営業日カレンダー',
344        'Recommend':     'おすすめ商品',
345        'RECOMMEND':     'おすすめ商品',
346        'Special':       '特集',
347        'SPECIAL':       '特集'
348    };
349
350    function run() {
351        var list = document.querySelectorAll(
352            '.section-heading h2, .section-heading h3, .section-heading span, .calendar-date'
353        );
354        for (var i = 0; i < list.length; i++) {
355            var el = list[i];
356            var t = (el.textContent || '').trim();
357            if (t && HEADING[t]) {
358                el.textContent = HEADING[t];
359            }
360        }
361    }
362
363    if (document.readyState === 'loading') {
364        document.addEventListener('DOMContentLoaded', run);
365    } else {
366        run();
367    }
368    setTimeout(run, 800);
369
370})();
371
372
373/* --------------------------------------------------------------------
374   3. ボタンの英語を日本語に
375
376   商品一覧・検索結果・お気に入りなどのボタンは
377   モジュールが出力していて直接直せないため、
378   ここでまとめて置き換えます。
379
380   トップと商品詳細のHTMLにも同じ処理が入っていますが、
381   二重に動いても問題ありません。
382   -------------------------------------------------------------------- */
383
384(function () {
385
386    var LABEL = {
387        'Add Cart':    'カートに入れる',
388        'ADD CART':    'カートに入れる',
389        'Add cart':    'カートに入れる',
390        'Sold Out':    '売り切れ',
391        'SOLD OUT':    '売り切れ',
392        'Coming Soon': '販売期間外'
393    };
394
395    var TARGETS = [
396        '.item-cart',
397        '.item-cart-wrap',
398        '.item-sku-cart',
399        '.item-list-cart',
400        '.item-cart-disabled',
401        '.sku-panel',
402        '.item-tag.sold'
403    ];
404
405    function swap(node) {
406        if (node.nodeType === 3) {
407            var t = node.nodeValue.trim();
408            if (t && LABEL[t]) {
409                node.nodeValue = node.nodeValue.replace(t, LABEL[t]);
410            }
411            return;
412        }
413        if (node.nodeType !== 1) return;
414        var tag = node.tagName;
415        if (tag === 'SCRIPT' || tag === 'STYLE' || tag === 'TEXTAREA' || tag === 'INPUT') return;
416        for (var i = 0; i < node.childNodes.length; i++) {
417            swap(node.childNodes[i]);
418        }
419    }
420
421    function run() {
422        for (var i = 0; i < TARGETS.length; i++) {
423            var list = document.querySelectorAll(TARGETS[i]);
424            for (var j = 0; j < list.length; j++) {
425                swap(list[j]);
426            }
427        }
428    }
429
430    if (document.readyState === 'loading') {
431        document.addEventListener('DOMContentLoaded', run);
432    } else {
433        run();
434    }
435    setTimeout(run, 800);
436
437})();
438
439
440/* --------------------------------------------------------------------
441   4. レビューが0件のときセクションを隠す
442
443   レビューはウィジェットがページ読み込み後に取得します。
444   テンプレートの段階では件数が分からないため、
445   取得結果を見てから判断します。
446
447   ★1件でも投稿されれば自動的に表示されます★
448
449   回線が遅い環境で消えてしまう場合は WAIT の数値を上げてください。
450   -------------------------------------------------------------------- */
451
452(function () {
453
454    var SECTION = '.review-item';
455    var BOX = '.review-item .review-container';
456    var WAIT = 3000;
457    var settled = false;
458
459    function evaluate() {
460        var box = document.querySelector(BOX);
461        if (!box) return;
462        var section = box.closest(SECTION);
463        if (!section) return;
464
465        var hasItem = box.querySelector(
466            '.review-item-list, .review-item-list-name, .review-item-list-content'
467        );
468        if (hasItem) {
469            section.style.display = '';
470            return;
471        }
472
473        var isEmpty = box.querySelector('.review-list-empty');
474        if (isEmpty || settled) {
475            section.style.display = 'none';
476        }
477    }
478
479    function start() {
480        var box = document.querySelector(BOX);
481        if (!box) return;
482
483        evaluate();
484        new MutationObserver(evaluate).observe(box, {
485            childList: true,
486            subtree: true
487        });
488        setTimeout(function () {
489            settled = true;
490            evaluate();
491        }, WAIT);
492    }
493
494    if (document.readyState === 'loading') {
495        document.addEventListener('DOMContentLoaded', start);
496    } else {
497        start();
498    }
499
500})();
501
502
503/* --------------------------------------------------------------------
504   5. カレンダーの休業日に色を付ける
505
506   もとの共通JSにも同じ処理がありますが、
507   直前のSwiper起動と同じ関数の中に書かれているため、
508   Swiperでエラーが起きると着色まで届きません。
509
510   ここでは独立して実行します。二重に色を付けても
511   結果は同じなので、問題ありません。
512
513   クラス名が合わない場合に備えて、
514   日付の数字で探す予備の方法も入れています。
515   -------------------------------------------------------------------- */
516
517(function () {
518
519    function paint() {
520        var inputs = document.querySelectorAll('.day-list');
521        if (!inputs.length) return false;
522
523        var painted = 0;
524
525        for (var i = 0; i < inputs.length; i++) {
526            var m = inputs[i].getAttribute('data-month');
527            var d = inputs[i].getAttribute('data-day');
528            var c = inputs[i].getAttribute('data-color');
529            if (!m || !d || !c) continue;
530
531            var cells = document.querySelectorAll('.makeshop-calendar' + m + ' .day' + d);
532
533            /* 予備:クラス名で見つからなければ、
534               その月の表から数字が一致するセルを探す */
535            if (!cells.length) {
536                var slides = document.querySelectorAll('.calendar-swiper-slide');
537                var slide = slides[Number(m) - 1];
538                if (slide) {
539                    var tds = slide.querySelectorAll('td');
540                    var hit = [];
541                    for (var k = 0; k < tds.length; k++) {
542                        if (tds[k].textContent.trim() === String(Number(d))) {
543                            hit.push(tds[k]);
544                        }
545                    }
546                    cells = hit;
547                }
548            }
549
550            for (var j = 0; j < cells.length; j++) {
551                cells[j].style.setProperty('background-color', c, 'important');
552                cells[j].style.setProperty('color', '#fff', 'important');
553                cells[j].style.setProperty('font-weight', 'bold', 'important');
554                painted++;
555            }
556        }
557
558        return painted > 0;
559    }
560
561    function start() {
562        if (paint()) return;
563        var n = 0;
564        var timer = setInterval(function () {
565            if (paint() || ++n > 10) clearInterval(timer);
566        }, 300);
567    }
568
569    if (document.readyState === 'loading') {
570        document.addEventListener('DOMContentLoaded', start);
571    } else {
572        start();
573    }
574
575})();
576
577
578/* --------------------------------------------------------------------
579   6. バナーの上に透明なリンクを重ねる(パソコンのみ)
580
581   ★これまでの経緯★
582   バナーのリンクもURLも正常です。
583   ホイールクリックでは開くのに、左クリックだけが
584   飲み込まれます。スライダーかmakeshopのスクリプトが
585   クリックを奪っています。
586
587   割り込んで拾う方法を4通り試しましたが、いずれも
588   届きませんでした。そこで発想を変えます。
589
590   ★やること★
591   スライダーの外側に、透明なリンクを1枚重ねます。
592   内部のスクリプトが何をしていても関係ありません。
593   表示中のスライドに合わせて、位置と行き先を
594   自動で追従させます。
595
596   ★パソコンだけに出します★
597   スマホは今も正常に飛ぶので、透明リンクを置ã
597„て
598   スワイプを妨げるほうが損になります。
599
600   ★送り矢印は今までどおり押せます★
601   矢印(z-index:400)より下に置いています。
602   -------------------------------------------------------------------- */
603
604(function () {
605
606    /* マウスを使う環境だけ。スマホ・タブレットでは何もしません */
607    if (!window.matchMedia) return;
608    if (!window.matchMedia('(hover: hover) and (pointer: fine)').matches) return;
609
610    var AREA = '.main-visual';
611    var overlay = null;
612    var area = null;
613
614    /* いま画面の中央に来ているスライドを探す */
615    function currentSlide() {
616        var lis = area.querySelectorAll('li');
617        var center = window.innerWidth / 2;
618        var best = null;
619        var bestDistance = Infinity;
620
621        for (var i = 0; i < lis.length; i++) {
622            var r = lis[i].getBoundingClientRect();
623            if (r.width < 50 || r.height < 20) continue;
624            var d = Math.abs((r.left + r.width / 2) - center);
625            if (d < bestDistance) {
626                bestDistance = d;
627                best = lis[i];
628            }
629        }
630        return best;
631    }
632
633    /* 位置と行き先を合わせる */
634    function sync() {
635        if (!overlay || !area) return;
636
637        var li = currentSlide();
638        if (!li) { overlay.style.display = 'none'; return; }
639
640        var link = li.querySelector('a[href]');
641        var img = li.querySelector('img') || li;
642
643        var r = img.getBoundingClientRect();
644        var ar = area.getBoundingClientRect();
645
646        if (r.width < 50 || r.height < 20) { overlay.style.display = 'none'; return; }
647
648        overlay.style.display = 'block';
649        overlay.style.left = Math.round(r.left - ar.left) + 'px';
650        overlay.style.top = Math.round(r.top - ar.top) + 'px';
651        overlay.style.width = Math.round(r.width) + 'px';
652        overlay.style.height = Math.round(r.height) + 'px';
653
654        if (link) {
655            var href = link.getAttribute('href');
656            if (href && href !== '#' && href.indexOf('javascript:') !== 0) {
657                overlay.setAttribute('href', href);
658                overlay.style.pointerEvents = 'auto';
659                var t = link.getAttribute('target');
660                if (t) { overlay.setAttribute('target', t); }
661                else { overlay.removeAttribute('target'); }
662                return;
663            }
664        }
665        overlay.removeAttribute('href');
666        overlay.style.pointerEvents = 'none';
667    }
668
669    function build() {
670        area = document.querySelector(AREA);
671        if (!area) return false;
672        if (area.querySelector('.fjc-mv-link')) return true;
673        if (!area.querySelector('li')) return false;   /* まだ組み上がっていない */
674
675        if (getComputedStyle(area).position === 'static') {
676            area.style.position = 'relative';
677        }
678
679        overlay = document.createElement('a');
680        overlay.className = 'fjc-mv-link';
681        overlay.setAttribute('aria-label', 'バナーのリンク');
682        area.appendChild(overlay);
683
684        sync();
685
686        /* スライドが動くので、位置と行き先を追い続けます */
687        setInterval(sync, 250);
688        window.addEventListener('resize', sync);
689        window.addEventListener('scroll', sync, { passive: true });
690
691        return true;
692    }
693
694    function start() {
695        if (build()) return;
696        var n = 0;
697        var timer = setInterval(function () {
698            if (build() || ++n > 40) clearInterval(timer);
699        }, 300);
700    }
701
702    if (document.readyState === 'loading') {
703        document.addEventListener('DOMContentLoaded', start);
704    } else {
705        start();
706    }
707
708})();
709
710/* ここまで読み込めた印 */
711window.FJC_COMMON_END = true;
712$(function () {
713    $('.custom-select').each(function () {
714        var $select = $(this);
715
716        var template = '<div class="' + $select.attr('class') + '">';
717        template += '<span class="custom-select-trigger">' + $select.find('option:selected').text() + '</span>';
718        template += '<div class="custom-option-wrapper">';
719
720        $select.find('option').each(function () {
721            template += '<span class="custom-option" data-value="' + $(this).val() + '">' + $(this).html() + '</span>';
722        });
723
724        template += '</div></div>';
725
726        $select.wrap('<div class="custom-select-wrapper"></div>').hide().after(template);
727    });
728
729    $('.custom-option:first-of-type').hover(
730        function () {
731            $(this).parents('.custom-option-wrapper').addClass('option-hover');
732        },
733        function () {
734            $(this).parents('.custom-option-wrapper').removeClass('option-hover');
735        }
736    );
737
738    $('.custom-select-trigger').on('click', function (event) {
739        var $customSelect = $(this).parents('.custom-select');
740        $('html').one('click', function () {
741            $customSelect.removeClass('opened');
742        });
743        $customSelect.toggleClass('opened');
744        event.stopPropagation();
745    });
746
747    $('.custom-option').on('click', function () {
748        var $customSelectWrapper = $(this).parents('.custom-select-wrapper');
749        var selectedValue = $(this).data('value');
750
751        $customSelectWrapper.find('select').val(selectedValue);
752        $customSelectWrapper.find('.custom-option').removeClass('selection');
753        $(this).addClass('selection');
754
755        $(this).parents('.custom-select').find('.custom-select-trigger').text($(this).text());
756
757        $(this).parents('.custom-select').removeClass('opened');
758
759        window.location.href = selectedValue;
760    });
761});

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.