「MediaWiki:Forum.js」の版間の差分
編集の要約なし |
編集の要約なし |
||
| 165行目: | 165行目: | ||
</details>` : ''; | </details>` : ''; | ||
// ================================================= | // ================================================= | ||
// ========== 書式ツールバーHTML ========== | |||
const toolbarHtml = `<div id="f-toolbar" style="margin-bottom:.4em;display:flex;gap:.3em;flex-wrap:wrap;align-items:center;padding:.3em;background:#f8f8f8;border:1px solid #ccc;border-radius:3px;"> | |||
<input type="button" class="mw-ui-button f-tb-btn" data-start="'''" data-end="'''" value="B" title="太字" style="font-weight:bold;min-width:2em;padding:0 .5em;"> | |||
<input type="button" class="mw-ui-button f-tb-btn" data-start="''" data-end="''" value="I" title="斜体" style="font-style:italic;min-width:2em;padding:0 .5em;"> | |||
<span style="font-size:.85em;color:#555;margin-left:.3em;">文字色:</span> | |||
${['#cc0000','#e07000','#007700','#0055cc','#7700aa','#555555'].map(c => | |||
`<span class="f-tb-color" data-color="${c}" title="${c}" style="display:inline-block;width:1.2em;height:1.2em;background:${c};border:2px solid #aaa;border-radius:2px;cursor:pointer;vertical-align:middle;"></span>` | |||
).join('')} | |||
</div>`; | |||
// ========================================= | |||
const msg = Object.assign({ | const msg = Object.assign({ | ||
loading: '<p>読み込み中...</p>', | loading: '<p>読み込み中...</p>', | ||
postform: `<div id="f-form"><h2>投稿${fedit ? `の編集 (<a href="#post-${fedit}")>#${fedit}</a>)` : ''}</h2>${anonSettingsHtml}<div class="mw-ui-checkbox" style="margin-bottom:.3em;${fedit ? 'display:none;' : ''}"><input type="checkbox" class="mw-ui-checkbox" id="f-reply-cb"><label for="f-reply-cb" style="user-select:none;">返信する</label></div><input type="number" id="f-reply" class="mw-ui-input" style="widht:50%;margin-bottom:.5em;"><textarea accesskey="," id="wpTextbox1" cols="80" rows="25" class="mw-editfont-monospace"></textarea><input type="button" id="f-post" value="投稿" class="mw-ui-button mw-ui-progressive" style="margin-top:.5em;"><input type="button" id="f-preview" value="プレビュー" class="mw-ui-button" style="margin: .5em 0 0 .5em;"><fieldset hidden><legend>プレビュー</legend><div id="f-preview-content"></div></fieldset><style>.mw-ui-checkbox:has(#f-reply-cb:checked)+input{display:block;}#f-reply{display:none;}</style></div>`, | postform: `<div id="f-form"><h2>投稿${fedit ? `の編集 (<a href="#post-${fedit}")>#${fedit}</a>)` : ''}</h2>${anonSettingsHtml}<div class="mw-ui-checkbox" style="margin-bottom:.3em;${fedit ? 'display:none;' : ''}"><input type="checkbox" class="mw-ui-checkbox" id="f-reply-cb"><label for="f-reply-cb" style="user-select:none;">返信する</label></div><input type="number" id="f-reply" class="mw-ui-input" style="widht:50%;margin-bottom:.5em;">${toolbarHtml}<textarea accesskey="," id="wpTextbox1" cols="80" rows="25" class="mw-editfont-monospace"></textarea><input type="button" id="f-post" value="投稿" class="mw-ui-button mw-ui-progressive" style="margin-top:.5em;"><input type="button" id="f-preview" value="プレビュー" class="mw-ui-button" style="margin: .5em 0 0 .5em;"><fieldset hidden><legend>プレビュー</legend><div id="f-preview-content"></div></fieldset><style>.mw-ui-checkbox:has(#f-reply-cb:checked)+input{display:block;}#f-reply{display:none;}</style></div>`, | ||
postsummary: 'post', | postsummary: 'post', | ||
replysummary: 'reply to', | replysummary: 'reply to', | ||
editsummary: 'edit', | editsummary: 'edit', | ||
deletesummary: 'delete post', | deletesummary: 'delete post', | ||
deletethreadsummary: 'スレッドの削除', | |||
toppage_css: "<style>.f-sticky>td:first-child>a::before{content:'';background-image:url(https://upload.wikimedia.org/wikipedia/commons/a/a5/OOjs_UI_icon_pushPin.svg);width:.8em;height:.8em;margin-right:.2em;display:inline-block;background-size:.8em}#f-loadmore{display:block;margin-left:auto;margin-right:auto;}</style>", | toppage_css: "<style>.f-sticky>td:first-child>a::before{content:'';background-image:url(https://upload.wikimedia.org/wikipedia/commons/a/a5/OOjs_UI_icon_pushPin.svg);width:.8em;height:.8em;margin-right:.2em;display:inline-block;background-size:.8em}#f-loadmore{display:block;margin-left:auto;margin-right:auto;}</style>", | ||
load_more: '<input type="button" value="もっと読み込む" class="mw-ui-button" id="f-loadmore">', | load_more: '<input type="button" value="もっと読み込む" class="mw-ui-button" id="f-loadmore">', | ||
create: '<input type="button" class="mw-ui-button mw-ui-progressive" value="スレッドを作成">', | create: '<input type="button" class="mw-ui-button mw-ui-progressive" value="スレッドを作成">', | ||
createform: | createform: `<div id="f-form"><label>スレッド名: <input type="text" id="f-threadname" class="mw-ui-input" style="margin-bottom:.5em;"></label>${toolbarHtml}<textarea accesskey="," id="wpTextbox1" cols="80" rows="25" class="mw-editfont-monospace"></textarea><input type="button" value="スレッドを作成" id="f-create" class="mw-ui-button mw-ui-progressive" style="margin-top:.5em;"><input type="button" id="f-preview" value="プレビュー" class="mw-ui-button" style="margin: .5em 0 0 .5em;"><fieldset hidden><legend>プレビュー</legend><div id="f-preview-content"></div></fieldset></div>`, | ||
createthreadsummary: 'スレッドの作成', | createthreadsummary: 'スレッドの作成', | ||
posterror: 'エラー: 投稿できませんでした', | posterror: 'エラー: 投稿できませんでした', | ||
| 247行目: | 259行目: | ||
}); | }); | ||
}, | }, | ||
// ========== スレッド削除(管理者のみ) ========== | |||
deleteThread: async () => { | |||
const threadName = mw.config.get('wgPageName').replace(mw.forum.toppage + '/', ''); | |||
if (!confirm(`スレッド「${threadName}」を削除しますか?\nこの操作は取り消せません。`)) return; | |||
fetch('/mediawiki/forum-proxy.php', { | |||
method: 'POST', | |||
headers: { 'Content-Type': 'application/json' }, | |||
body: JSON.stringify({ | |||
action: 'delete', | |||
title: mw.config.get('wgPageName'), | |||
reason: msg.deletethreadsummary | |||
}) | |||
}).then(r => r.json()).then(data => { | |||
if (data.result === 'Success') { | |||
location.href = mw.config.get('wgArticlePath').replace('$1', mw.forum.toppage); | |||
} else { | |||
mw.notify(msg.deleteerror); | |||
} | |||
}).catch(() => mw.notify(msg.deleteerror)); | |||
}, | |||
// ================================================= | |||
// ========== 書式ツールバーの初期化 ========== | |||
initToolbar: () => { | |||
const toolbar = document.querySelector('#f-toolbar'); | |||
if (!toolbar) return; | |||
const ta = document.querySelector('#wpTextbox1'); | |||
// 選択範囲をマークアップで囲むヘルパー | |||
const wrapText = (start, end) => { | |||
const s = ta.selectionStart, e = ta.selectionEnd; | |||
const selected = ta.value.substring(s, e); | |||
ta.value = ta.value.substring(0, s) + start + selected + end + ta.value.substring(e); | |||
ta.selectionStart = s + start.length; | |||
ta.selectionEnd = s + start.length + selected.length; | |||
ta.focus(); | |||
}; | |||
// 太字・斜体ボタン | |||
toolbar.querySelectorAll('.f-tb-btn').forEach(btn => { | |||
btn.onclick = () => wrapText(btn.dataset.start, btn.dataset.end); | |||
}); | |||
// 文字色ボタン | |||
toolbar.querySelectorAll('.f-tb-color').forEach(btn => { | |||
btn.onclick = () => wrapText(`<span style="color:${btn.dataset.color}">`, '</span>'); | |||
}); | |||
}, | |||
// ============================================= | |||
// ========== 名前設定UIの初期化 ========== | // ========== 名前設定UIの初期化 ========== | ||
initAnonSettings: () => { | initAnonSettings: () => { | ||
| 302行目: | 364行目: | ||
mc.innerHTML = msg.createform; | mc.innerHTML = msg.createform; | ||
document.querySelector("#f-preview").onclick = func.preview; | document.querySelector("#f-preview").onclick = func.preview; | ||
func.initToolbar(); | |||
mw.loader.using('ext.wikiEditor'); | mw.loader.using('ext.wikiEditor'); | ||
document.querySelector('#f-create').onclick = function () { | document.querySelector('#f-create').onclick = function () { | ||
| 367行目: | 430行目: | ||
// 名前設定UIを初期化(匿名ユーザーのみ) | // 名前設定UIを初期化(匿名ユーザーのみ) | ||
func.initAnonSettings(); | func.initAnonSettings(); | ||
// 書式ツールバーを初期化 | |||
func.initToolbar(); | |||
// 管理者にスレッド削除ボタンを表示 | |||
if (isAdmin) { | |||
const delThreadBtn = document.createElement('input'); | |||
delThreadBtn.type = 'button'; | |||
delThreadBtn.value = 'スレッドを削除'; | |||
delThreadBtn.className = 'mw-ui-button mw-ui-destructive'; | |||
delThreadBtn.style.cssText = 'margin-left:.5em;'; | |||
delThreadBtn.onclick = func.deleteThread; | |||
const ind = document.querySelector('.mw-indicators'); | |||
if (ind) ind.appendChild(delThreadBtn); | |||
} | |||
document.querySelector('#f-post').onclick = (async () => { | document.querySelector('#f-post').onclick = (async () => { | ||