利用者:Mr.sirokuma/common.js
ナビゲーションに移動
検索に移動
注意: 保存後、変更を確認するにはブラウザーのキャッシュを消去する必要がある場合があります。
- Firefox / Safari: Shift を押しながら 再読み込み をクリックするか、Ctrl-F5 または Ctrl-R を押してください (Mac では ⌘-R)
- Google Chrome: Ctrl-Shift-R を押してください (Mac では ⌘-Shift-R)
- Microsoft Edge: Ctrl を押しながら 最新の情報に更新 をクリックするか、Ctrl-F5 を押してください。
/**
* 個人メニューバーにカスタムリンクを追加
*/
$(function() {
// 1. サブサブページへのリンク
mw.util.addPortletLink(
'p-personal',
mw.util.getUrl('利用者:Mr.sirokuma/サブページ'),
'サブサブページ',
'pt-subsubpage',
'サブページへ移動します',
null,
'#pt-preferences' // 個人設定の前に挿入
);
// 2. 作成したページへのリンク
mw.util.addPortletLink(
'p-personal',
mw.util.getUrl('利用者:Mr.sirokuma/作成したページ'),
'作成したページ',
'pt-myworks',
'作成したページ一覧へ移動します',
null,
'#pt-preferences' // 同じく個人設定の前に挿入
);
});
/**
* サイドバー最下部に編集回数ランクバーを設置(完全日本語版)
*/
(function() {
const userName = mw.config.get('wgUserName');
if (!userName) return;
$.getJSON(mw.util.wikiScript('api'), {
action: 'query',
list: 'users',
ususers: userName,
usprop: 'editcount',
format: 'json'
}).done(function(data) {
const editCount = data.query.users[0].editcount;
// 100刻みの計算
const nextMilestone = (Math.floor(editCount / 100) + 1) * 100;
const prevMilestone = Math.floor(editCount / 100) * 100;
const remaining = nextMilestone - editCount;
const progress = ((editCount - prevMilestone) / (nextMilestone - prevMilestone)) * 100;
// 称号の定義(日本語)
let rankName = "";
const ranks = [
{ min: 0, name: "🥚 編集者のたまご" },
{ min: 50, name: "🐣 ひよっこ編集者" },
{ min: 100, name: "🌱 草取り初段" },
{ min: 200, name: "🖋️ 執筆の修行身" },
{ min: 300, name: "☘️ 一人前の編集者" },
{ min: 400, name: "🍃 風の編集者" },
{ min: 500, name: "🔥 炎の編集者" },
{ min: 750, name: "🌊 知の探究者" },
{ min: 1000, name: "📜 歴史の編纂者" },
{ min: 1500, name: "🛡️ ウィキの守護神" },
{ min: 2000, name: "🛠️ 驚異の職人技" },
{ min: 3000, name: "⚖️ 公正なる裁定者" },
{ min: 5000, name: "🏛️ 栄誉ある執筆家" },
{ min: 7500, name: "🔮 叡智の賢者" },
{ min: 10000, name: "🌌 百科事典の覇者" },
{ min: 30000, name: "👑 生ける伝説" }
];
for (let i = ranks.length - 1; i >= 0; i--) {
if (editCount >= ranks[i].min) {
rankName = ranks[i].name;
break;
}
}
const contribUrl = mw.util.getUrl('Special:Contributions/' + userName);
const html = `
<nav id="p-edit-rank-jp" class="vector-menu vector-menu-portal portal" style="margin: 15px 8px; padding: 12px; background: #ffffff; border-radius: 10px; border: 1px solid #c8ccd1; box-shadow: 0 2px 5px rgba(0,0,0,0.05);">
<div style="font-size: 0.85em; font-weight: bold; color: #202122; margin-bottom: 3px;">${rankName}</div>
<div style="font-size: 0.65em; color: #72777d; margin-bottom: 10px;">現在のランク</div>
<a href="${contribUrl}" style="text-decoration: none; color: inherit;" title="あなたの投稿記録を表示します">
<div style="background: #eaecf0; border-radius: 10px; height: 10px; width: 100%; overflow: hidden; border: 1px solid #c8ccd1; position: relative;">
<div style="background: linear-gradient(90deg, #36c 0%, #447ff5 100%); height: 100%; width: ${progress}%; transition: width 1.5s ease-in-out;"></div>
</div>
<div style="margin-top: 10px; display: flex; flex-direction: column; gap: 5px;">
<div style="display: flex; justify-content: space-between; align-items: baseline;">
<span style="font-size: 0.7em; color: #54595d;">次の目標まで あと <b>${remaining}</b></span>
<span style="font-size: 0.8em; font-weight: bold; color: #36c;">${progress.toFixed(0)}%</span>
</div>
<div style="font-size: 0.7em; color: #72777d; border-top: 1px solid #eeeeee; padding-top: 5px; display: flex; justify-content: space-between;">
<span>通算編集回数</span>
<span><b>${editCount.toLocaleString()}</b> 回</span>
</div>
</div>
</a>
</nav>
`;
// サイドバーの「一番最後」に配置
const $sidebar = $('#mw-panel, #sidebar, .mw-sidebar');
if ($sidebar.length) {
$sidebar.append(html);
} else {
// 万が一メインのパネルが見つからない場合は既存のメニューの後ろへ
$('.vector-menu-portal').last().after(html);
}
});
})();
/**
* 鉄道・道路・会社 テンプレート挿入ボタン(5種セット)
*/
(function(mw, $) {
const action = mw.config.get('wgAction');
if (!['edit', 'submit'].includes(action)) return;
// --- テンプレート定義 ---
const templates = {
station: `{{駅情報
|社色=
|文字色=
|駅名=
|画像=
|px1=
|画像説明=
|よみがな=
|副駅名=
|前の駅1=
|駅間A1=
|駅間B1=
|次の駅1=
|電報略号=
|駅番号1=
|所属事業者=
|所属路線=
|キロ程1=
|起点駅=
|所在地=
|座標=
|地図国コード=
|座標右上表示=
|駅構造=
|ホーム=
|開業年月日=
|廃止年月日=
|乗車人員=
|乗車人員n=
|乗降人員=
|乗降人員n=
|統計年度=
|乗換=
|備考=
}}`,
route: `{{Infobox 鉄道路線
| 路線名 =
| 路線色 = #000000
| 路線色2 = #000000
| ロゴ =
| ロゴサイズ =
| 画像 =
| 画像サイズ =
| 画像説明 =
| 通称 =
| 現況 =
| 国 =
| 所在地 =
| 種類 =
| 路線網 =
| 区間 =
| 起点 = 駅
| 終点 = 駅
| 駅数 = 駅
| 停留場数 = 停留場
| 停留所数 = 停留所
| 経由路線 =
| 輸送実績 =
| 1日利用者数 =
| 電報略号 =
| 路線記号 =
| 路線番号 =
| 路線色3 =
| 開業 =
| 項目1 =
| 日付1 =
| 項目2 =
| 日付2 =
| 項目3 =
| 日付3 =
| 最終延伸 =
| 全通 =
| 休止 =
| 廃止 =
| 再開 =
| 所有者 =
| 運営者 =
| 運転指令所 =
| 車両基地 =
| 使用車両 =
| 路線構造 =
| 路線距離 = km
| 営業キロ = km
| 軌間 = mm
| 線路数 =
| 複線区間 =
| 電化区間 =
| 電化方式 =
| 車両限界 =
| 最大勾配 = ‰
| 最小曲線半径 = m
| 高低差 = m
| 閉塞方式 =
| 保安装置 =
| ラック方式 =
| 最高速度 = km/h
| 駅間平均長 =
| 諸元備考 =
| 諸元備考内容 =
| 路線図 =
| 路線図名 =
| 路線図表示 =
}}`,
company: `{{基礎情報 会社
|社名 =
|英文社名 =
|ロゴ =
|画像 =
|画像説明 =
|種類 =
|機関設計 =
|市場情報 =
|略称 =
|国籍 =
|本社郵便番号 =
|本社所在地 =
|本店郵便番号 =
|本店所在地 =
|設立 =
|業種 =
|法人番号 =
|統一金融機関コード =
|SWIFTコード =
|事業内容 =
|代表者 =
|資本金 =
|発行済株式総数 =
|売上高 =
|営業利益 =
|経常利益 =
|純利益 =
|純資産 =
|総資産 =
|従業員数 =
|支店舗数 =
|決算期 =
|会計監査人 =
|所有者 =
|主要株主 =
|主要部門 =
|主要子会社 =
|関係する人物 =
|外部リンク =
|特記事項 =
}}`,
train: `{{基礎情報 列車
|色=
|文字色=
|列車名=
|ローマ字=
|画像=
|画像説明=
|国=
|種別=
|列車番号=
|現況=
|前身=
|運行開始=
|種別変更=
|運行終了=
|後継=
|運行事業者=
|走行距離=
|所要時間=
|走行路線=
|運行区間=
|起点=
|起終点=
|終点=
|停車駅数=
|使用車両=
|両数=
|最高速度=
|平均速度=
|表定速度=
|外部リンク=
|備考=
}}`,
road: `{{Infobox road
| 背景色 =
| 文字色 =
| アイコン =
| 名称 =
| 画像 =
| 画像サイズ =
| 画像説明 =
| 別称 =
| 現況 =
| 国 =
| 種類 =
| 路線延長 =
| 総延長 =
| 実延長 =
| 陸上区間 =
| 海上区間 =
| 制定年 =
| 開通年 =
| 最終延伸 =
| 廃止年 =
| 起点 =
| 終点 =
| 経由地 =
| 接続道路 =
| 備考 =
}}`
};
// --- 挿入関数 ---
const insertTpl = (tpl) => {
const $txtArea = $('#wpTextbox1');
if (!$txtArea.length) return;
const el = $txtArea[0];
const start = el.selectionStart;
const end = el.selectionEnd;
const fullText = $txtArea.val();
// 前後に改行を入れて、確実にブロックとして挿入
const textToInsert = "\n" + tpl + "\n";
$txtArea.val(fullText.substring(0, start) + textToInsert + fullText.substring(end));
el.focus();
el.setSelectionRange(start + 1, start + textToInsert.length - 1);
$txtArea.trigger('change');
};
// --- ボタン設置 ---
const setup = () => {
const $target = $('.section-main .group-insert, #toolbar');
if (!$target.length) {
setTimeout(setup, 1000);
return;
}
const btnStyle = {
'margin': '2px 3px',
'padding': '3px 6px',
'cursor': 'pointer',
'background': '#f8f9fa',
'border': '1px solid #c8ccd1',
'border-radius': '2px',
'font-size': '11.5px',
'font-weight': 'bold',
'display': 'inline-block'
};
const createBtn = (label, tplKey) => {
return $('<span>').text(label).css(btnStyle).on('click', (e) => {
e.preventDefault();
insertTpl(templates[tplKey]);
});
};
// ボタンを生成してツールバーへ追加
$target.first().append(
createBtn('🚉駅', 'station'),
createBtn('🛤️路線', 'route'),
createBtn('🚄列車', 'train'),
createBtn('🏢会社', 'company'),
createBtn('🛣️道路', 'road')
);
};
$(setup);
})(mediaWiki, jQuery);
/**
* Enpedia 執筆支援ツール【超豪華・永続版】
*/
(function() {
'use strict';
const OPTION_NAME = 'enpedia-omikuji-save';
const omikujiData = [
{ rank: "超大吉", msg: "伝説の編集者。あなたの書いた一文が歴史に残るでしょう。" },
{ rank: "大吉", msg: "誤字脱字がゼロ。読みやすすぎて涙が出るレベルの記事が書けます。" },
{ rank: "大吉", msg: "出典(ソース)が向こうから歩いてくるレベルで見つかります。" },
{ rank: "中吉", msg: "適当に書いた導入文が、驚くほどきれいにまとまります。" },
{ rank: "中吉", msg: "プレビュー1回で完璧。サーバーとの相性も抜群な一日。" },
{ rank: "中吉", msg: "赤リンクが青く染まっていく。あなたの執筆がWikiを救う。" },
{ rank: "小吉", msg: "他人の修正が、実はあなたのミスではなく「改善」だったと判明。" },
{ rank: "小吉", msg: "以前から気になっていた細かいバグや表記揺れがスッキリ直る。" },
{ rank: "小吉", msg: "今日は地味なメンテナンス作業が捗ります。カテゴリ整理が吉。" },
{ rank: "末吉", msg: "新しいテンプレートの使い道が見つかるかも。試行錯誤が大事。" },
{ rank: "末吉", msg: "執筆に行き詰まったら、一度別の記事を読んでみると閃きが。" },
{ rank: "末吉", msg: "大きな進展はないけれど、着実な一歩。保存はこまめに。" },
{ rank: "吉", msg: "いつか書きたいと思っていたネタの資料が偶然手に入ります。" },
{ rank: "吉", msg: "議論が平和に解決。相互理解こそWikiの醍醐味です。" },
{ rank: "吉", msg: "お茶を飲みながら編集すると吉。リラックスして向き合おう。" },
{ rank: "凶", msg: "プレビューしたつもりで、していなかった。ケアレスミスに注意。" },
{ rank: "凶", msg: "「保存」ボタンを押した瞬間に誤字を見つける。あるあるですね。" },
{ rank: "凶", msg: "編集合戦の気配。今日は深追いせず、一旦寝て落ち着こう。" },
{ rank: "大凶", msg: "ブラウザがクラッシュする予感。下書きは必ず外部メモ帳に!" },
{ rank: "執筆神", msg: "【激レア】もはや運勢を超越。あなたが書くことすべてが真実になる。" }
];
const getTodayStr = () => new Date().toISOString().split('T')[0];
// --- おみくじ永続化の強化 ---
const loadResult = (callback) => {
const today = getTodayStr();
const local = localStorage.getItem(OPTION_NAME);
if (local && local.startsWith(today)) {
return callback(parseInt(local.split('|')[1]));
}
if (!mw.config.get('wgUserName')) return callback(null);
new mw.Api().get({ action: 'query', meta: 'userinfo', uiprop: 'options' }).then(data => {
const saved = data.query.userinfo.options[OPTION_NAME];
if (saved && saved.startsWith(today)) {
localStorage.setItem(OPTION_NAME, saved);
return callback(parseInt(saved.split('|')[1]));
}
callback(null);
});
};
const saveResult = (index) => {
const val = getTodayStr() + '|' + index;
localStorage.setItem(OPTION_NAME, val); // 即時反映用
if (mw.config.get('wgUserName')) {
new mw.Api().saveOption(OPTION_NAME, val);
}
};
const setupOmikuji = () => {
loadResult((savedIndex) => {
const isDrawn = savedIndex !== null;
const res = isDrawn ? omikujiData[savedIndex] : { rank: "?", msg: "運勢未確定" };
const html = `
<div id="p-omikuji" class="portal" role="navigation">
<h3 style="display:block; font-size:12px; color:#555; font-weight:bold; padding:4px 0;">🔮 今日の運勢: <span id="omi-status-top" style="color:#d00;">${res.rank}</span></h3>
<div class="body" style="background:#f9f9f9; border:1px solid #ddd; border-radius:4px; padding:8px; text-align:center;">
<div id="omi-result" style="font-weight:bold; font-size:16px; margin-bottom:5px; color:#d00;">${res.rank}</div>
<div id="omi-msg" style="font-size:11px; color:#444; line-height:1.4; min-height:3em;">${res.msg}</div>
${!isDrawn ? '<button id="omi-btn" style="margin-top:10px; cursor:pointer; padding:4px 12px; font-size:11px; border-radius:3px; border:1px solid #ccc; background:#fff;">おみくじを引く</button>' : ''}
</div>
</div>`;
const $sidebar = $('#mw-panel, .mw-sidebar, #sidebar, #p-navigation');
if ($sidebar.length) $sidebar.last().after(html);
$('#omi-btn').on('click', function() {
const index = Math.floor(Math.random() * omikujiData.length);
const finalRes = omikujiData[index];
$('#omi-result').text(finalRes.rank).hide().fadeIn();
$('#omi-msg').text(finalRes.msg).hide().fadeIn();
$('#omi-status-top').text(finalRes.rank);
$(this).remove();
saveResult(index);
});
});
};
// --- 文字数カウンター(豪華演出版) ---
const setupCounter = () => {
if (!['edit', 'submit'].includes(mw.config.get('wgAction'))) return;
const $textbox = $('#wpTextbox1');
if (!$textbox.length) return;
const $counter = $('<div id="enp-word-count"></div>').css({
position: 'fixed', bottom: '20px', right: '20px',
backgroundColor: 'rgba(0, 0, 0, 0.75)', color: '#fff',
padding: '8px 18px', borderRadius: '30px', fontSize: '14px',
zIndex: '9999', pointerEvents: 'none', fontWeight: 'bold',
boxShadow: '0 4px 10px rgba(0,0,0,0.3)', transition: 'all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275)'
}).text('文字数: 0');
$('body').append($counter);
let lastVal = $textbox.val().length;
const milestones = [500, 1000, 2000, 3000, 5000, 6000, 7000, 8000, 9000, 10000];
$textbox.on('input keyup change', () => {
const current = $textbox.val().length;
if (current === lastVal) return; // 変化なしなら終了
$counter.text('文字数: ' + current.toLocaleString());
// 1. 超派手なキリ番演出 (500, 1000...)
const hitMilestone = milestones.find(m => lastVal < m && current >= m);
if (hitMilestone) {
// 背景を虹色アニメーションに
$counter.css({
transform: 'scale(2.5) rotate(720deg) translateY(-50px)',
background: 'linear-gradient(45deg, #ff0000, #ff7f00, #ffff00, #00ff00, #0000ff, #4b0082, #8b00ff)',
boxShadow: '0 0 40px #fff, 0 0 70px #ff00ff'
});
// 画面全体に一瞬フラッシュ
const $flash = $('<div style="position:fixed;top:0;left:0;width:100%;height:100%;background:#fff;z-index:9998;opacity:0.5;"></div>').appendTo('body');
$flash.fadeOut(1000, function(){ $(this).remove(); });
setTimeout(() => {
$counter.css({ transform: 'scale(1) rotate(0deg)', background: 'rgba(0, 0, 0, 0.75)', boxShadow: '0 4px 10px rgba(0,0,0,0.3)' });
}, 1500);
} else if (Math.floor(current / 100) > Math.floor(lastVal / 100)) {
// 2. 通常の100文字演出
$counter.css({ transform: 'scale(1.5) translateY(-15px)', backgroundColor: '#d4af37' });
setTimeout(() => {
$counter.css({ transform: 'scale(1)', backgroundColor: 'rgba(0, 0, 0, 0.75)' });
}, 400);
}
lastVal = current;
});
};
$(function() {
setupOmikuji();
setupCounter();
});
})();