注意: 保存後、変更を確認するにはブラウザーのキャッシュを消去する必要がある場合があります。

  • Firefox / Safari: Shift を押しながら 再読み込み をクリックするか、Ctrl-F5 または Ctrl-R を押してください (Mac では ⌘-R)
  • Google Chrome: Ctrl-Shift-R を押してください (Mac では ⌘-Shift-R)
  • Microsoft Edge: Ctrl を押しながら 最新の情報に更新 をクリックするか、Ctrl-F5 を押してください。
/* ========================================
 * 屋台比較
 * 最大4店舗を localStorage に保存
 * Template側にはbuttonを書かず、
 * JavaScriptでbuttonを生成する
 * ======================================== */

mw.loader.using( 'mediawiki.storage' ).then( function () {

    'use strict';

    const STORAGE_KEY = 'matsuriWikiCompareStalls';
    const MAX_COMPARE = 4;

    /**
     * 比較候補を取得
     */
    function getCompareStalls() {

        const raw = mw.storage.get( STORAGE_KEY );

        if ( !raw ) {
            return [];
        }

        try {

            const ids = JSON.parse( raw );

            if ( !Array.isArray( ids ) ) {
                return [];
            }

            return [ ...new Set(
                ids
                    .map( String )
                    .filter( function ( id ) {
                        return id !== '';
                    } )
            ) ].slice( 0, MAX_COMPARE );

        } catch ( e ) {

            return [];

        }
    }


    /**
     * 比較候補を保存
     */
    function saveCompareStalls( ids ) {

        mw.storage.set(
            STORAGE_KEY,
            JSON.stringify( ids )
        );

    }


    /**
     * メッセージ表示
     */
    function showMessage( control, message, isError ) {

        const messageElement =
            control.querySelector(
                '.stall-compare-message'
            );

        if ( !messageElement ) {
            return;
        }

        messageElement.textContent = message;

        messageElement.classList.toggle(
            'stall-compare-message-error',
            Boolean( isError )
        );

    }


    /**
     * 比較ボタン生成
     */
    function createCompareButtons() {

        document
            .querySelectorAll(
                '.stall-compare-placeholder'
            )
            .forEach( function ( placeholder ) {

                /*
                 * すでに生成済みなら何もしない
                 */
                if (
                    placeholder.dataset.initialized === '1'
                ) {
                    return;
                }

                /*
                 * id:
                 * stall-compare-placeholder-1
                 * ↓
                 * stallId = "1"
                 */
                const prefix =
                    'stall-compare-placeholder-';

                if (
                    !placeholder.id.startsWith( prefix )
                ) {
                    return;
                }

                const stallId =
                    placeholder.id.substring(
                        prefix.length
                    );

                if ( !stallId ) {
                    return;
                }

                /*
                 * JavaScript側で本物のbuttonを作る
                 */
                const button =
                    document.createElement( 'button' );

                button.type = 'button';

                button.className =
                    'stall-compare-button';

                button.dataset.stallId =
                    stallId;

                button.setAttribute(
                    'aria-pressed',
                    'false'
                );

                button.textContent =
                    '比較に追加';

                placeholder.appendChild( button );

                placeholder.dataset.initialized =
                    '1';

            } );

    }


    /**
     * ボタン状態更新
     */
    function updateCompareButtons() {

        const ids =
            getCompareStalls();

        document
            .querySelectorAll(
                '.stall-compare-button'
            )
            .forEach( function ( button ) {

                const stallId =
                    String(
                        button.dataset.stallId || ''
                    );

                const selected =
                    ids.includes( stallId );

                if ( selected ) {

                    button.textContent =
                        '比較から外す';

                    button.classList.add(
                        'stall-compare-button-selected'
                    );

                    button.setAttribute(
                        'aria-pressed',
                        'true'
                    );

                } else {

                    button.textContent =
                        '比較に追加';

                    button.classList.remove(
                        'stall-compare-button-selected'
                    );

                    button.setAttribute(
                        'aria-pressed',
                        'false'
                    );

                }

            } );

    }


    /**
     * 比較ボタンクリック
     */
    document.addEventListener(
        'click',
        function ( event ) {

            const button =
                event.target.closest(
                    '.stall-compare-button'
                );

            if ( !button ) {
                return;
            }

            event.preventDefault();

            const stallId =
                String(
                    button.dataset.stallId || ''
                );

            const control =
                button.closest(
                    '.stall-compare-control'
                );

            if ( !stallId ) {

                if ( control ) {

                    showMessage(
                        control,
                        '屋台IDを取得できませんでした。',
                        true
                    );

                }

                return;
            }

            let ids =
                getCompareStalls();

            const index =
                ids.indexOf( stallId );


            /*
             * 登録済み
             * → 比較候補から外す
             */
            if ( index !== -1 ) {

                ids.splice(
                    index,
                    1
                );

                saveCompareStalls(
                    ids
                );

                updateCompareButtons();

                if ( control ) {

                    showMessage(
                        control,
                        '比較候補から外しました。',
                        false
                    );

                }

                return;
            }


            /*
             * 最大4店舗
             */
            if (
                ids.length >= MAX_COMPARE
            ) {

                if ( control ) {

                    showMessage(
                        control,
                        '比較できる屋台は最大4店舗です。',
                        true
                    );

                }

                return;
            }


            /*
             * 比較候補へ追加
             */
            ids.push(
                stallId
            );

            saveCompareStalls(
                ids
            );

            updateCompareButtons();

            if ( control ) {

                showMessage(
                    control,
                    '比較候補に追加しました(' +
                        ids.length +
                        '/4)。',
                    false
                );

            }

        }
    );


    /**
     * 初期化
     */
    function initStallCompare() {

        createCompareButtons();
        updateCompareButtons();

    }


    /*
     * 通常ページ
     */
    initStallCompare();


    /*
     * MediaWiki本文再描画時
     */
    mw.hook(
        'wikipage.content'
    ).add(
        function () {

            initStallCompare();

        }
    );

} );