「MediaWiki:Common.js」の版間の差分
Hiratatomotaka (トーク | 投稿記録) 編集の要約なし |
Hiratatomotaka (トーク | 投稿記録) 編集の要約なし |
||
| (同じ利用者による、間の33版が非表示) | |||
| 1行目: | 1行目: | ||
/* ここにあるすべてのJavaScriptは、すべてのページ読み込みですべての利用者に対して読み込まれます */ | /* ここにあるすべてのJavaScriptは、すべてのページ読み込みですべての利用者に対して読み込まれます */ | ||
function my_switch(){ | function my_switch(){ | ||
var uri = new URL(window.location.href); | var uri = new URL(window.location.href); | ||
| 31行目: | 30行目: | ||
"nebula_switch: 閲覧モードでないため、入れ替えは行いません" | "nebula_switch: 閲覧モードでないため、入れ替えは行いません" | ||
); | ); | ||
}else{ | |||
var uri = new URL(window.location.href); | |||
if (is_view_mode(uri)){ | |||
if (document.getElementById("nebula_switch")){ | |||
uri.searchParams.append("nebula_switch", ""); | |||
document.getElementsByClassName("mw-parser-output")[0].innerHTML | |||
+= "<h2>お知らせ:この記事は、「男女逆にして」表示できます</h2>" | |||
+ "<p>WikiNebula では、女性に対して向けられるべきではないような" | |||
+ "差別や冷遇が、男性に対しては現実に起きてしまっていることを、" | |||
+ "記事として取り上げています。</p>" | |||
+ "<p>そのため、 WikiNebula には、男性が経験するこの種の" | |||
+ "差別や女尊男卑を理解しやすくするために、" | |||
+ "男女の立場を入れ替えて表示する「男女入れ替えスイッチ」" | |||
+ "の機能があります。</p>" | |||
+ "<p>現在、男女入れ替えスイッチが無効になっています。" | |||
+ "有効にするには、<a href='" + uri.toString() +"'>こちら</a>を" | |||
+ "クリックしてください</p>"; | |||
} | |||
} | |||
} | } | ||
| 88行目: | 106行目: | ||
content_node.innerHTML = | content_node.innerHTML = | ||
"<h1>エラー: 男女入れ替えスイッチでエラー</h1>" + message | "<h1>エラー: 男女入れ替えスイッチでエラー</h1>" + message | ||
throw new Error("nebula_switch: " + message); | |||
} | } | ||
| 95行目: | 114行目: | ||
Array.from(doc.children[0].children).forEach(function(tag){ | Array.from(doc.children[0].children).forEach(function(tag){ | ||
if (tag.tagName.toLowerCase() == "replace"){ | if (tag.tagName.toLowerCase() == "replace"){ | ||
var is_syntax_error = !( | |||
tag.childNodes[0].nodeName == "#text" | tag.childNodes[0].nodeName == "#text" | ||
&& tag.childNodes[1].nodeName.toLowerCase() == "to" | && tag.childNodes[1].nodeName.toLowerCase() == "to" | ||
&& tag.childNodes[2].nodeName == "#text" | && tag.childNodes[2].nodeName == "#text" | ||
)){ | && tag.childNodes.length == 3 | ||
); | |||
if (is_syntax_error){ | |||
nebula_write_error( | nebula_write_error( | ||
"次のreplace タグが構文エラーです。<br>" | "次のreplace タグが構文エラーです。<br>" | ||
| 110行目: | 131行目: | ||
content_node.innerHTML | content_node.innerHTML | ||
= content_node.innerHTML.replaceAll(before, after); | = content_node.innerHTML.replaceAll(before, after); | ||
} | |||
if (tag.tagName.toLowerCase() == "swap"){ | |||
var is_syntax_error = !( | |||
tag.childNodes[0].nodeName == "#text" | |||
&& tag.childNodes[1].nodeName.toLowerCase() == "for" | |||
&& tag.childNodes[2].nodeName == "#text" | |||
&& tag.childNodes.length == 3 | |||
); | |||
if (is_syntax_error){ | |||
nebula_write_error( | |||
"次のreplace タグが構文エラーです。<br>" | |||
+ "<code>" + code_escape(tag.outerHTML) + "</code>" | |||
); | |||
} | |||
var A = code_unescape(tag.childNodes[0].nodeValue); | |||
var B = code_unescape(tag.childNodes[2].nodeValue); | |||
content_node.innerHTML | |||
= swap_string(content_node.innerHTML, A, B); | |||
} | } | ||
}); | }); | ||
var uri = new URL(window.location.href); | |||
uri.searchParams.delete("nebula_switch"); | |||
content_node.innerHTML | |||
+= "<h2>お知らせ:この記事は、「男女逆にして」表示されています</h2>" | |||
+ "<p>WikiNebula では、女性に対して向けられるべきではないような" | |||
+ "差別や冷遇が、男性に対しては現実に起きてしまっていることを、" | |||
+ "記事として取り上げています。</p>" | |||
+ "<p>そのため、 WikiNebula には、男性が経験するこの種の" | |||
+ "差別や女尊男卑を理解しやすくするために、" | |||
+ "男女の立場を入れ替えて表示する「男女入れ替えスイッチ」" | |||
+ "の機能があります。</p>" | |||
+ "<p>現在、男女入れ替えスイッチが有効になっています。" | |||
+ "無効にするには、<a href='" + uri.toString() +"'>こちら</a>を" | |||
+ "クリックしてください</p>"; | |||
} | } | ||
function code_escape(code){ | function code_escape(code){ | ||
| 125行目: | 183行目: | ||
return textarea.innerText; | return textarea.innerText; | ||
} | } | ||
function swap_string(input_string, x, y) { | |||
// xとyを正規表現の特殊文字からエスケープする | |||
x = x.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); | |||
y = y.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); | |||
// xとyを入れ替える | |||
var regex = new RegExp('(' + x + '|' + y + ')', 'g'); | |||
var result = input_string.replace(regex, function(match) { | |||
return match === x ? y : x; | |||
}); | |||
return result; | |||
} | |||
my_switch(); | my_switch(); | ||
/* ===== SNSシェアボタン ===== */ | |||
mw.loader.using('mediawiki.util').then(function () { | |||
$(function () { | |||
if ( | |||
mw.config.get('wgAction') !== 'view' || | |||
!mw.config.get('wgIsArticle') || | |||
[0, 4].indexOf(mw.config.get('wgNamespaceNumber')) === -1 || | |||
new URL(location.href).searchParams.has('veaction') || | |||
document.getElementById('wn-share-top') | |||
) { | |||
return; | |||
} | |||
var content = document.getElementById('mw-content-text'); | |||
if (!content) { | |||
return; | |||
} | |||
var url = new URL( | |||
mw.util.getUrl(mw.config.get('wgPageName')), | |||
location.origin | |||
).href; | |||
var title = mw.config.get('wgTitle') + ' | WikiNebula'; | |||
var u = encodeURIComponent(url); | |||
var t = encodeURIComponent(title); | |||
var xText = encodeURIComponent(title + ' @WikiNebulaPR'); | |||
var services = [ | |||
{ | |||
name: 'x', | |||
label: 'Xでシェア', | |||
shortLabel: 'X', | |||
url: 'https://twitter.com/intent/tweet?url=' + u + | |||
'&text=' + xText | |||
}, | |||
{ | |||
name: 'facebook', | |||
label: 'Facebookでシェア', | |||
shortLabel: 'Facebook', | |||
url: 'https://www.facebook.com/sharer/sharer.php?u=' + u | |||
}, | |||
{ | |||
name: 'line', | |||
label: 'LINEで送る', | |||
shortLabel: 'LINE', | |||
url: 'https://social-plugins.line.me/lineit/share?url=' + | |||
u + '&text=' + t | |||
} | |||
]; | |||
function makeBar(position) { | |||
var bar = document.createElement('nav'); | |||
bar.id = 'wn-share-' + position; | |||
bar.className = 'wn-share wn-share--' + position; | |||
bar.setAttribute('aria-label', 'この記事をシェア'); | |||
services.forEach(function (service) { | |||
var link = document.createElement('a'); | |||
link.className = 'wn-share__button'; | |||
link.textContent = position === 'sidebar' ? | |||
service.shortLabel : service.label; | |||
link.setAttribute('aria-label', service.label); | |||
link.setAttribute('data-service', service.name); | |||
link.href = service.url; | |||
link.target = '_blank'; | |||
link.rel = 'noopener noreferrer'; | |||
bar.appendChild(link); | |||
}); | |||
return bar; | |||
} | |||
content.insertBefore(makeBar('top'), content.firstChild); | |||
content.appendChild(makeBar('bottom')); | |||
var sidebar = document.querySelector( | |||
'.skin-vector-2022 .vector-main-menu-container' | |||
); | |||
if (sidebar) { | |||
sidebar.insertBefore(makeBar('sidebar'), sidebar.firstChild); | |||
} | |||
}); | |||
}); | |||
/* ===== 公式案内:PCは左側、小さい画面はヘッダー直下 ===== */ | |||
$(function () { | |||
if (!document.body.classList.contains('skin-vector-2022')) { | |||
return; | |||
} | |||
var official = document.getElementById('p-公式案内'); | |||
var sidebar = document.querySelector('.vector-main-menu-container'); | |||
var header = document.querySelector('.vector-header-container'); | |||
if (!official || !sidebar || !header) { | |||
return; | |||
} | |||
// リンク先はMediaWiki:Sidebarから読み取り、URLを二重管理しない | |||
var mobileHost = document.createElement('div'); | |||
mobileHost.className = 'wn-official-mobile-host'; | |||
header.appendChild(mobileHost); | |||
official.classList.add('wn-official-links'); | |||
official.setAttribute('role', 'navigation'); | |||
official.setAttribute('aria-label', '公式案内'); | |||
var mobileLabels = { | |||
'x.com': '公式X', | |||
'twitter.com': '公式X', | |||
'facebook.com': '公式Facebook', | |||
'line.me': '公式オプチャ' | |||
}; | |||
var labels = Array.from(official.querySelectorAll('a')).map(function (link) { | |||
var label = link.firstElementChild || link; | |||
var hostname = new URL(link.href, location.href).hostname.replace(/^www\./, ''); | |||
return { | |||
element: label, | |||
full: label.textContent, | |||
compact: mobileLabels[hostname] || label.textContent | |||
}; | |||
}); | |||
var wideScreen = window.matchMedia('(min-width: 1200px)'); | |||
function placeOfficialLinks() { | |||
labels.forEach(function (label) { | |||
label.element.textContent = wideScreen.matches ? label.full : label.compact; | |||
}); | |||
if (wideScreen.matches) { | |||
var navigation = document.getElementById('mw-navigation'); | |||
sidebar.insertBefore( | |||
official, | |||
navigation && navigation.parentNode === sidebar ? navigation : null | |||
); | |||
} else { | |||
mobileHost.appendChild(official); | |||
} | |||
} | |||
placeOfficialLinks(); | |||
wideScreen.addEventListener('change', placeOfficialLinks); | |||
}); | |||
2026年10月19日 (月) 18:00時点における最新版
/* ここにあるすべてのJavaScriptは、すべてのページ読み込みですべての利用者に対して読み込まれます */
function my_switch(){
var uri = new URL(window.location.href);
var is_switched = uri.searchParams.get("nebula_switch") != null;
if (is_switched){
console.log("nebula_switch: 入れ替え後のページです");
if (is_view_mode(uri)){
console.log("nebula_switch: 閲覧モードです");
var parser = new Switch_parser();
if (parser.parse(document.getElementById("nebula_switch"))){
if (parser.tag_exists){
console.log(
"nebula_switch: 入れ替えタグの解析に成功しました"
);
nebula_run(parser.doc);
}else{
console.log("nebula_switch: 入れ替えタグがありません");
}
}else{
console.log("nebula_switch: 入れ替えタグが異常です");
nebula_write_error(parser.failed_message);
}
}else
console.log(
"nebula_switch: 閲覧モードでないため、入れ替えは行いません"
);
}else{
var uri = new URL(window.location.href);
if (is_view_mode(uri)){
if (document.getElementById("nebula_switch")){
uri.searchParams.append("nebula_switch", "");
document.getElementsByClassName("mw-parser-output")[0].innerHTML
+= "<h2>お知らせ:この記事は、「男女逆にして」表示できます</h2>"
+ "<p>WikiNebula では、女性に対して向けられるべきではないような"
+ "差別や冷遇が、男性に対しては現実に起きてしまっていることを、"
+ "記事として取り上げています。</p>"
+ "<p>そのため、 WikiNebula には、男性が経験するこの種の"
+ "差別や女尊男卑を理解しやすくするために、"
+ "男女の立場を入れ替えて表示する「男女入れ替えスイッチ」"
+ "の機能があります。</p>"
+ "<p>現在、男女入れ替えスイッチが無効になっています。"
+ "有効にするには、<a href='" + uri.toString() +"'>こちら</a>を"
+ "クリックしてください</p>";
}
}
}
}
function is_view_mode(uri){
var view_tab = document.getElementById("ca-view");
if (view_tab)
var is_view_mode_selected
= view_tab.classList.contains("selected");
else
var is_view_mode_selected = false;
var is_not_ve_edit_mode = uri.searchParams.get("veaction") == null;
return is_view_mode_selected && is_not_ve_edit_mode;
}
// ES5 なので class 構文は使えない・・・
function Switch_parser(){
if (this === null) throw new TypeError();
}
Switch_parser.prototype = {
constructor: Switch_parser,
parse: function(switch_tag){
// パース成功の真偽値を返却する
if (switch_tag == null){
this.tag_exists = false;
return true;
}
this.tag_exists = true;
if (!window.DOMParser){
this.failed_message = "DOMParser が有効ではありません。"
+ "お使いのブラウザで DOMParser を有効にしてください。";
return false;
}
var dom_parser = new DOMParser();
var doc = dom_parser.parseFromString(
"<root>" + switch_tag.innerText + "</root>", "text/xml"
);
var parser_error = doc.querySelector("parsererror");
if (parser_error){
this.failed_message = "入れ替えタグに構文エラーがありました\n"
+ parser_error.innerHTML;
return false;
}
this.doc = doc;
return true;
}
};
function nebula_write_error(message){
var content_node =
document.getElementsByClassName("mw-parser-output")[0];
content_node.innerHTML =
"<h1>エラー: 男女入れ替えスイッチでエラー</h1>" + message
throw new Error("nebula_switch: " + message);
}
function nebula_run(doc){
var content_node
= document.getElementsByClassName("mw-parser-output")[0];
Array.from(doc.children[0].children).forEach(function(tag){
if (tag.tagName.toLowerCase() == "replace"){
var is_syntax_error = !(
tag.childNodes[0].nodeName == "#text"
&& tag.childNodes[1].nodeName.toLowerCase() == "to"
&& tag.childNodes[2].nodeName == "#text"
&& tag.childNodes.length == 3
);
if (is_syntax_error){
nebula_write_error(
"次のreplace タグが構文エラーです。<br>"
+ "<code>" + code_escape(tag.outerHTML) + "</code>"
);
}
var before = code_unescape(tag.childNodes[0].nodeValue);
var after = code_unescape(tag.childNodes[2].nodeValue);
content_node.innerHTML
= content_node.innerHTML.replaceAll(before, after);
}
if (tag.tagName.toLowerCase() == "swap"){
var is_syntax_error = !(
tag.childNodes[0].nodeName == "#text"
&& tag.childNodes[1].nodeName.toLowerCase() == "for"
&& tag.childNodes[2].nodeName == "#text"
&& tag.childNodes.length == 3
);
if (is_syntax_error){
nebula_write_error(
"次のreplace タグが構文エラーです。<br>"
+ "<code>" + code_escape(tag.outerHTML) + "</code>"
);
}
var A = code_unescape(tag.childNodes[0].nodeValue);
var B = code_unescape(tag.childNodes[2].nodeValue);
content_node.innerHTML
= swap_string(content_node.innerHTML, A, B);
}
});
var uri = new URL(window.location.href);
uri.searchParams.delete("nebula_switch");
content_node.innerHTML
+= "<h2>お知らせ:この記事は、「男女逆にして」表示されています</h2>"
+ "<p>WikiNebula では、女性に対して向けられるべきではないような"
+ "差別や冷遇が、男性に対しては現実に起きてしまっていることを、"
+ "記事として取り上げています。</p>"
+ "<p>そのため、 WikiNebula には、男性が経験するこの種の"
+ "差別や女尊男卑を理解しやすくするために、"
+ "男女の立場を入れ替えて表示する「男女入れ替えスイッチ」"
+ "の機能があります。</p>"
+ "<p>現在、男女入れ替えスイッチが有効になっています。"
+ "無効にするには、<a href='" + uri.toString() +"'>こちら</a>を"
+ "クリックしてください</p>";
}
function code_escape(code){
var textarea = document.createElement("textarea");
textarea.innerText = code;
return textarea.innerHTML;
}
function code_unescape(code){
var textarea = document.createElement("textarea");
textarea.innerHTML = code;
return textarea.innerText;
}
function swap_string(input_string, x, y) {
// xとyを正規表現の特殊文字からエスケープする
x = x.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
y = y.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
// xとyを入れ替える
var regex = new RegExp('(' + x + '|' + y + ')', 'g');
var result = input_string.replace(regex, function(match) {
return match === x ? y : x;
});
return result;
}
my_switch();
/* ===== SNSシェアボタン ===== */
mw.loader.using('mediawiki.util').then(function () {
$(function () {
if (
mw.config.get('wgAction') !== 'view' ||
!mw.config.get('wgIsArticle') ||
[0, 4].indexOf(mw.config.get('wgNamespaceNumber')) === -1 ||
new URL(location.href).searchParams.has('veaction') ||
document.getElementById('wn-share-top')
) {
return;
}
var content = document.getElementById('mw-content-text');
if (!content) {
return;
}
var url = new URL(
mw.util.getUrl(mw.config.get('wgPageName')),
location.origin
).href;
var title = mw.config.get('wgTitle') + ' | WikiNebula';
var u = encodeURIComponent(url);
var t = encodeURIComponent(title);
var xText = encodeURIComponent(title + ' @WikiNebulaPR');
var services = [
{
name: 'x',
label: 'Xでシェア',
shortLabel: 'X',
url: 'https://twitter.com/intent/tweet?url=' + u +
'&text=' + xText
},
{
name: 'facebook',
label: 'Facebookでシェア',
shortLabel: 'Facebook',
url: 'https://www.facebook.com/sharer/sharer.php?u=' + u
},
{
name: 'line',
label: 'LINEで送る',
shortLabel: 'LINE',
url: 'https://social-plugins.line.me/lineit/share?url=' +
u + '&text=' + t
}
];
function makeBar(position) {
var bar = document.createElement('nav');
bar.id = 'wn-share-' + position;
bar.className = 'wn-share wn-share--' + position;
bar.setAttribute('aria-label', 'この記事をシェア');
services.forEach(function (service) {
var link = document.createElement('a');
link.className = 'wn-share__button';
link.textContent = position === 'sidebar' ?
service.shortLabel : service.label;
link.setAttribute('aria-label', service.label);
link.setAttribute('data-service', service.name);
link.href = service.url;
link.target = '_blank';
link.rel = 'noopener noreferrer';
bar.appendChild(link);
});
return bar;
}
content.insertBefore(makeBar('top'), content.firstChild);
content.appendChild(makeBar('bottom'));
var sidebar = document.querySelector(
'.skin-vector-2022 .vector-main-menu-container'
);
if (sidebar) {
sidebar.insertBefore(makeBar('sidebar'), sidebar.firstChild);
}
});
});
/* ===== 公式案内:PCは左側、小さい画面はヘッダー直下 ===== */
$(function () {
if (!document.body.classList.contains('skin-vector-2022')) {
return;
}
var official = document.getElementById('p-公式案内');
var sidebar = document.querySelector('.vector-main-menu-container');
var header = document.querySelector('.vector-header-container');
if (!official || !sidebar || !header) {
return;
}
// リンク先はMediaWiki:Sidebarから読み取り、URLを二重管理しない
var mobileHost = document.createElement('div');
mobileHost.className = 'wn-official-mobile-host';
header.appendChild(mobileHost);
official.classList.add('wn-official-links');
official.setAttribute('role', 'navigation');
official.setAttribute('aria-label', '公式案内');
var mobileLabels = {
'x.com': '公式X',
'twitter.com': '公式X',
'facebook.com': '公式Facebook',
'line.me': '公式オプチャ'
};
var labels = Array.from(official.querySelectorAll('a')).map(function (link) {
var label = link.firstElementChild || link;
var hostname = new URL(link.href, location.href).hostname.replace(/^www\./, '');
return {
element: label,
full: label.textContent,
compact: mobileLabels[hostname] || label.textContent
};
});
var wideScreen = window.matchMedia('(min-width: 1200px)');
function placeOfficialLinks() {
labels.forEach(function (label) {
label.element.textContent = wideScreen.matches ? label.full : label.compact;
});
if (wideScreen.matches) {
var navigation = document.getElementById('mw-navigation');
sidebar.insertBefore(
official,
navigation && navigation.parentNode === sidebar ? navigation : null
);
} else {
mobileHost.appendChild(official);
}
}
placeOfficialLinks();
wideScreen.addEventListener('change', placeOfficialLinks);
});