注意: 保存後、変更を確認するにはブラウザーのキャッシュを消去する必要がある場合があります。
- 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();
}
);
} );