「MediaWiki:Common.js」の版間の差分
提供: MochiuWiki : SUSE, EC, PCB
📢 Webサイト閉鎖と移転のお知らせ
このWebサイトは2026年9月に閉鎖いたします。
新しい記事は移転先で追加しております。(旧サイトでは記事を追加しておりません)
タグ: 置換 手動差し戻し |
編集の要約なし タグ: 差し戻し済み |
||
| 1行目: | 1行目: | ||
/* ここにあるすべてのJavaScriptは、すべてのページ読み込みですべての利用者に対して読み込まれます */ | /* ここにあるすべてのJavaScriptは、すべてのページ読み込みですべての利用者に対して読み込まれます */ | ||
// ======================================== | |||
// ダークモード切り替え機能(サイドバー&上部バー配置版) | |||
// MediaWiki:Common.js に追加してください | |||
// ======================================== | |||
(function() { | |||
'use strict'; | |||
// 設定 | |||
const THEME_KEY = 'fluent-theme-preference'; | |||
const THEME_DARK = 'dark'; | |||
const THEME_LIGHT = 'light'; | |||
const THEME_AUTO = 'auto'; | |||
// 現在のテーマを取得 | |||
function getCurrentTheme() { | |||
return localStorage.getItem(THEME_KEY) || THEME_AUTO; | |||
} | |||
// テーマを適用 | |||
function applyTheme(theme) { | |||
const html = document.documentElement; | |||
html.classList.remove('theme-dark', 'theme-light', 'theme-auto'); | |||
html.classList.add('theme-' + theme); | |||
localStorage.setItem(THEME_KEY, theme); | |||
updateAllThemeButtons(theme); | |||
} | |||
// すべてのボタンを更新 | |||
function updateAllThemeButtons(theme) { | |||
const buttons = document.querySelectorAll('.theme-toggle-button, .theme-toggle-link'); | |||
buttons.forEach(function(button) { | |||
updateThemeButton(button, theme); | |||
}); | |||
} | |||
// ボタンの表示を更新 | |||
function updateThemeButton(button, theme) { | |||
if (!button) return; | |||
const configs = { | |||
'light': { | |||
icon: '☀️', | |||
text: 'ライトモード', | |||
title: 'ライトモードに切り替え', | |||
nextMode: 'ダークモードに切り替え' | |||
}, | |||
'dark': { | |||
icon: '🌙', | |||
text: 'ダークモード', | |||
title: 'ダークモードに切り替え', | |||
nextMode: '自動モードに切り替え' | |||
}, | |||
'auto': { | |||
icon: '🌗', | |||
text: '自動切替', | |||
title: '自動(システム設定)', | |||
nextMode: 'ライトモードに切り替え' | |||
} | |||
}; | |||
const config = configs[theme]; | |||
// アイコン要素があれば更新 | |||
const iconSpan = button.querySelector('.theme-icon'); | |||
if (iconSpan) { | |||
iconSpan.textContent = config.icon; | |||
} | |||
// テキスト要素があれば更新 | |||
const textSpan = button.querySelector('.theme-text'); | |||
if (textSpan) { | |||
textSpan.textContent = config.text; | |||
} | |||
// ボタン全体のテキストを更新(テキストリンク用) | |||
if (button.classList.contains('theme-toggle-text-only')) { | |||
button.textContent = config.icon + ' ' + config.text; | |||
} | |||
button.title = config.nextMode; | |||
button.setAttribute('aria-label', config.nextMode); | |||
} | |||
// テーマを切り替え | |||
function toggleTheme(e) { | |||
if (e) { | |||
e.preventDefault(); | |||
e.stopPropagation(); | |||
} | |||
const current = getCurrentTheme(); | |||
let next; | |||
switch(current) { | |||
case THEME_LIGHT: | |||
next = THEME_DARK; | |||
break; | |||
case THEME_DARK: | |||
next = THEME_AUTO; | |||
break; | |||
case THEME_AUTO: | |||
default: | |||
next = THEME_LIGHT; | |||
break; | |||
} | |||
applyTheme(next); | |||
} | |||
// サイドバーにボタンを追加 | |||
function addSidebarButton() { | |||
// 既に存在する場合はスキップ | |||
if (document.getElementById('theme-toggle-sidebar')) return; | |||
// サイドバーの「ツール」セクションを探す | |||
const sideNavigation = document.getElementById('site-navigation'); | |||
if (!sideNavigation) return; | |||
// ボタンコンテナを作成 | |||
const container = document.createElement('div'); | |||
container.id = 'theme-toggle-sidebar'; | |||
container.className = 'theme-toggle-container'; | |||
// タイトル(オプション) | |||
const title = document.createElement('h3'); | |||
title.textContent = '表示設定'; | |||
title.className = 'theme-section-title'; | |||
// ボタンを作成 | |||
const button = document.createElement('button'); | |||
button.className = 'theme-toggle-button theme-toggle-sidebar-button'; | |||
button.setAttribute('aria-label', 'テーマ切り替え'); | |||
button.setAttribute('type', 'button'); | |||
const iconSpan = document.createElement('span'); | |||
iconSpan.className = 'theme-icon'; | |||
const textSpan = document.createElement('span'); | |||
textSpan.className = 'theme-text'; | |||
button.appendChild(iconSpan); | |||
button.appendChild(textSpan); | |||
button.addEventListener('click', toggleTheme); | |||
container.appendChild(title); | |||
container.appendChild(button); | |||
// サイドバーの先頭に追加 | |||
sideNavigation.insertBefore(container, sideNavigation.firstChild); | |||
return button; | |||
} | |||
// 上部バーにボタンを追加 | |||
function addTopBarButton() { | |||
// 既に存在する場合はスキップ | |||
if (document.getElementById('theme-toggle-topbar')) return; | |||
// ページツール(編集、履歴などのエリア)を探す | |||
const pageTools = document.getElementById('page-tools'); | |||
if (!pageTools) return; | |||
// ボタンを作成 | |||
const button = document.createElement('button'); | |||
button.id = 'theme-toggle-topbar'; | |||
button.className = 'theme-toggle-button theme-toggle-topbar-button'; | |||
button.setAttribute('aria-label', 'テーマ切り替え'); | |||
button.setAttribute('type', 'button'); | |||
const iconSpan = document.createElement('span'); | |||
iconSpan.className = 'theme-icon'; | |||
iconSpan.style.marginRight = '4px'; | |||
const textSpan = document.createElement('span'); | |||
textSpan.className = 'theme-text'; | |||
button.appendChild(iconSpan); | |||
button.appendChild(textSpan); | |||
button.addEventListener('click', toggleTheme); | |||
// ページツールの最後に追加 | |||
pageTools.appendChild(button); | |||
return button; | |||
} | |||
// ヘッダーにシンプルなボタンを追加(右上) | |||
function addHeaderButton() { | |||
// 既に存在する場合はスキップ | |||
if (document.getElementById('theme-toggle-header')) return; | |||
const userTools = document.getElementById('user-tools'); | |||
if (!userTools) return; | |||
// シンプルなアイコンボタンを作成 | |||
const button = document.createElement('button'); | |||
button.id = 'theme-toggle-header'; | |||
button.className = 'theme-toggle-button theme-toggle-header-button'; | |||
button.setAttribute('aria-label', 'テーマ切り替え'); | |||
button.setAttribute('type', 'button'); | |||
const iconSpan = document.createElement('span'); | |||
iconSpan.className = 'theme-icon'; | |||
button.appendChild(iconSpan); | |||
button.addEventListener('click', toggleTheme); | |||
// search-iconの後に挿入 | |||
const searchIcon = document.getElementById('search-icon'); | |||
if (searchIcon && searchIcon.nextSibling) { | |||
userTools.insertBefore(button, searchIcon.nextSibling); | |||
} else { | |||
userTools.appendChild(button); | |||
} | |||
return button; | |||
} | |||
// 初期化 | |||
function init() { | |||
// 複数の場所にボタンを追加 | |||
addSidebarButton(); // サイドバーに追加 | |||
addTopBarButton(); // 上部バー(ページツール)に追加 | |||
addHeaderButton(); // ヘッダー右上に追加 | |||
// 保存されたテーマを適用 | |||
const savedTheme = getCurrentTheme(); | |||
applyTheme(savedTheme); | |||
} | |||
// DOMContentLoaded時に初期化 | |||
if (document.readyState === 'loading') { | |||
document.addEventListener('DOMContentLoaded', init); | |||
} else { | |||
init(); | |||
} | |||
// MediaWikiフックとの連携 | |||
if (typeof mw !== 'undefined' && mw.hook) { | |||
mw.hook('wikipage.content').add(function() { | |||
const savedTheme = getCurrentTheme(); | |||
applyTheme(savedTheme); | |||
}); | |||
} | |||
})(); | |||
2025年11月10日 (月) 08:45時点における版
/* ここにあるすべてのJavaScriptは、すべてのページ読み込みですべての利用者に対して読み込まれます */
// ========================================
// ダークモード切り替え機能(サイドバー&上部バー配置版)
// MediaWiki:Common.js に追加してください
// ========================================
(function() {
'use strict';
// 設定
const THEME_KEY = 'fluent-theme-preference';
const THEME_DARK = 'dark';
const THEME_LIGHT = 'light';
const THEME_AUTO = 'auto';
// 現在のテーマを取得
function getCurrentTheme() {
return localStorage.getItem(THEME_KEY) || THEME_AUTO;
}
// テーマを適用
function applyTheme(theme) {
const html = document.documentElement;
html.classList.remove('theme-dark', 'theme-light', 'theme-auto');
html.classList.add('theme-' + theme);
localStorage.setItem(THEME_KEY, theme);
updateAllThemeButtons(theme);
}
// すべてのボタンを更新
function updateAllThemeButtons(theme) {
const buttons = document.querySelectorAll('.theme-toggle-button, .theme-toggle-link');
buttons.forEach(function(button) {
updateThemeButton(button, theme);
});
}
// ボタンの表示を更新
function updateThemeButton(button, theme) {
if (!button) return;
const configs = {
'light': {
icon: '☀️',
text: 'ライトモード',
title: 'ライトモードに切り替え',
nextMode: 'ダークモードに切り替え'
},
'dark': {
icon: '🌙',
text: 'ダークモード',
title: 'ダークモードに切り替え',
nextMode: '自動モードに切り替え'
},
'auto': {
icon: '🌗',
text: '自動切替',
title: '自動(システム設定)',
nextMode: 'ライトモードに切り替え'
}
};
const config = configs[theme];
// アイコン要素があれば更新
const iconSpan = button.querySelector('.theme-icon');
if (iconSpan) {
iconSpan.textContent = config.icon;
}
// テキスト要素があれば更新
const textSpan = button.querySelector('.theme-text');
if (textSpan) {
textSpan.textContent = config.text;
}
// ボタン全体のテキストを更新(テキストリンク用)
if (button.classList.contains('theme-toggle-text-only')) {
button.textContent = config.icon + ' ' + config.text;
}
button.title = config.nextMode;
button.setAttribute('aria-label', config.nextMode);
}
// テーマを切り替え
function toggleTheme(e) {
if (e) {
e.preventDefault();
e.stopPropagation();
}
const current = getCurrentTheme();
let next;
switch(current) {
case THEME_LIGHT:
next = THEME_DARK;
break;
case THEME_DARK:
next = THEME_AUTO;
break;
case THEME_AUTO:
default:
next = THEME_LIGHT;
break;
}
applyTheme(next);
}
// サイドバーにボタンを追加
function addSidebarButton() {
// 既に存在する場合はスキップ
if (document.getElementById('theme-toggle-sidebar')) return;
// サイドバーの「ツール」セクションを探す
const sideNavigation = document.getElementById('site-navigation');
if (!sideNavigation) return;
// ボタンコンテナを作成
const container = document.createElement('div');
container.id = 'theme-toggle-sidebar';
container.className = 'theme-toggle-container';
// タイトル(オプション)
const title = document.createElement('h3');
title.textContent = '表示設定';
title.className = 'theme-section-title';
// ボタンを作成
const button = document.createElement('button');
button.className = 'theme-toggle-button theme-toggle-sidebar-button';
button.setAttribute('aria-label', 'テーマ切り替え');
button.setAttribute('type', 'button');
const iconSpan = document.createElement('span');
iconSpan.className = 'theme-icon';
const textSpan = document.createElement('span');
textSpan.className = 'theme-text';
button.appendChild(iconSpan);
button.appendChild(textSpan);
button.addEventListener('click', toggleTheme);
container.appendChild(title);
container.appendChild(button);
// サイドバーの先頭に追加
sideNavigation.insertBefore(container, sideNavigation.firstChild);
return button;
}
// 上部バーにボタンを追加
function addTopBarButton() {
// 既に存在する場合はスキップ
if (document.getElementById('theme-toggle-topbar')) return;
// ページツール(編集、履歴などのエリア)を探す
const pageTools = document.getElementById('page-tools');
if (!pageTools) return;
// ボタンを作成
const button = document.createElement('button');
button.id = 'theme-toggle-topbar';
button.className = 'theme-toggle-button theme-toggle-topbar-button';
button.setAttribute('aria-label', 'テーマ切り替え');
button.setAttribute('type', 'button');
const iconSpan = document.createElement('span');
iconSpan.className = 'theme-icon';
iconSpan.style.marginRight = '4px';
const textSpan = document.createElement('span');
textSpan.className = 'theme-text';
button.appendChild(iconSpan);
button.appendChild(textSpan);
button.addEventListener('click', toggleTheme);
// ページツールの最後に追加
pageTools.appendChild(button);
return button;
}
// ヘッダーにシンプルなボタンを追加(右上)
function addHeaderButton() {
// 既に存在する場合はスキップ
if (document.getElementById('theme-toggle-header')) return;
const userTools = document.getElementById('user-tools');
if (!userTools) return;
// シンプルなアイコンボタンを作成
const button = document.createElement('button');
button.id = 'theme-toggle-header';
button.className = 'theme-toggle-button theme-toggle-header-button';
button.setAttribute('aria-label', 'テーマ切り替え');
button.setAttribute('type', 'button');
const iconSpan = document.createElement('span');
iconSpan.className = 'theme-icon';
button.appendChild(iconSpan);
button.addEventListener('click', toggleTheme);
// search-iconの後に挿入
const searchIcon = document.getElementById('search-icon');
if (searchIcon && searchIcon.nextSibling) {
userTools.insertBefore(button, searchIcon.nextSibling);
} else {
userTools.appendChild(button);
}
return button;
}
// 初期化
function init() {
// 複数の場所にボタンを追加
addSidebarButton(); // サイドバーに追加
addTopBarButton(); // 上部バー(ページツール)に追加
addHeaderButton(); // ヘッダー右上に追加
// 保存されたテーマを適用
const savedTheme = getCurrentTheme();
applyTheme(savedTheme);
}
// DOMContentLoaded時に初期化
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
// MediaWikiフックとの連携
if (typeof mw !== 'undefined' && mw.hook) {
mw.hook('wikipage.content').add(function() {
const savedTheme = getCurrentTheme();
applyTheme(savedTheme);
});
}
})();