MediaWiki:Test/vpTagHelper.js
/*
* 井戸端タグ支援ツール
* cpro
* 井戸端サブページの編集画面に、タグ検索・編集機能を追加する
*/
if(mw.config.get('wgPageName').indexOf('Wikipedia:井戸端/subj/') == 0 && //井戸端サブページ
(mw.config.get('wgAction') == 'edit' || mw.config.get('wgAction') == 'submit'))        //編集・プレビュー・差分確認時
{
var vpTag = {};
vpTag.categoryTitle =
encodeURIComponent('Category:井戸端の話題/タグ別'.replace(/ /g, '_'))
.replace('%3A', ':').replace('%2F', '/');
vpTag.limit = 500;
vpTag.URI =
mw.config.get('wgServer') + wgScriptPath + '/api.php?format=json&callback=createVpTagList' +
'&action=query&list=categorymembers&cmnamespace=14&cmprop=title' +
'&cmlimit=' + vpTag.limit.toString() +
'&cmtitle=' + vpTag.categoryTitle;
vpTag.categoryPrefix = 'Category:井戸端の話題/';
vpTag.positionId = 'editform';
vpTag.tagList = [];
vpTag.currentTagList = [];
vpTag.recommendBlock = null;
vpTag.searchResultBlock = null;
$( function() {
var sectionNum = -1;
var sectionParam = document.getElementsByName('wpSection')[0];
if(sectionParam) {
sectionNum = parseInt(sectionParam.getAttribute('value').replace(/(?:T-)?(\d+)/, '$1'));
if(isNaN(sectionNum)) sectionNum = -1;
}
if(sectionNum >= 1) return; //導入部以外の節編集モードでは無効
var refNode = document.getElementById(vpTag.positionId);
if(!refNode) return;
var container = document.createElement('div');
container.setAttribute('id', 'edittools_vptag');
container.style.cssText = 'margin-top:0.25em;border-top:1px solid #ccc;font-size:90%';
container.innerHTML =
'<form><p>\n' +
'<label>井戸端タグ検索:</label>\n' +
'<input id="vptagsearchinput" type="text" />\n' +
'<input type="text" style="position:absolute; visibility:hidden" />\n' + //dummy 誤送信防止
'<button>追加</button>\n' +
'</p></form>\n' +
'<p></p>\n' +
'<p>\n' +
'おすすめタグ:\n' +
'\n' +
'</p>';
refNode.parentNode.insertBefore(container, refNode);
//動的に内容を変化させる要素の保持
vpTag.recommendBlock = document.getElementById('vptagrecommend');
vpTag.searchResultBlock = document.getElementById('vptagsearchresult');
addHandler(document.getElementById('vptagsearchinput'), 'keyup', vpTagSearch);
addHandler(document.getElementById('vptagappend'), 'click', vpTagAppendButton_onclick);
vpTag.currentTagList = getCurrentVpTagList();
mw.loader.load(vpTag.URI);
});
}
//APIのクエリ結果からタグの配列を作成する
function createVpTagList(obj) {
if(!obj['query'] || !obj['query']['categorymembers'])
return;
var cm = obj['query']['categorymembers'];
for(var i = 0; i < cm.length; i++) {
vpTag.tagList.push(cm[i]['title'].substring(vpTag.categoryPrefix.length));
}
//1回のロード件数 (vpTag.limit) より多ければ続きをロードする
if(obj['query-continue'] && obj['query-continue']['categorymembers'] && obj['query-continue']['categorymembers']['cmcontinue']) {
mw.loader.load(vpTag.URI + '&cmcontinue=' + obj['query-continue']['categorymembers']['cmcontinue']);
} else {
//ロード終了後処理: おすすめタグのボタンを生成
createVpTagButtons(getRecommendedVpTagList(), vpTag.recommendBlock)
}
}
function createVpTagButtons(tagList, container) {
for(var i = 0; i < tagList.length; i++) {
var a = document.createElement('a');
a.setAttribute('href', 'javascript:void(0);');
a.appendChild(document.createTextNode(tagList[i]));
toggleVpTagButtonStyle(a, false);
for(var j = 0; j < vpTag.currentTagList.length; j++) {
if(tagList[i].toUpperCase() == vpTag.currentTagList[j].toUpperCase())
toggleVpTagButtonStyle(a, true);
}
addHandler(a, 'click', vpTagButton_onclick);
container.appendChild(document.createTextNode(' '));
container.appendChild(a);
}
}
function clearVpTagButtons(container) {
container.innerHTML = ;
}
function getRecommendedVpTagList(tagList) {
if(tagList == undefined) tagList = vpTag.tagList;
var textarea = document.getElementById('wpTextbox1');
if(!textarea) return;
var text = textarea.value.toUpperCase()
.replace(/\(UTC\)/g, ) //署名の(UTC)は拾わないように除去
.replace(//g, ); //コメント内を拾わない
//井戸端タグ以降を検索対象とする
var searchStart = text.indexOf('{VPTAG');
if(searchStart < 0) searchStart = 0;
var recList = [];
for(var i = 0; i < tagList.length; i++) {
if(text.indexOf(tagList[i].toUpperCase(), searchStart) >= 0)
recList.push(tagList[i]);
}
return recList;
}
function getVpTagSearchList(query, tagList) {
if(tagList == undefined) tagList = vpTag.tagList;
var searchList = [];
for(var i = 0; i < tagList.length; i++) {
if(tagList[i].toUpperCase().indexOf(query.toUpperCase()) >= 0)
searchList.push(tagList[i]);
}
return searchList;
}
function getCurrentVpTagList() {
var tags = [];
var textarea = document.getElementById('wpTextbox1');
var m = textarea.value.match(/\{\{vptag(?:\s*\|\s*([^{}]*?)\s*)?\}\}/i);
if(!m) return tags;
if(m[1] && m[1].length > 0)
tags = m[1].split(/\s*\|\s*/);
return tags;
}
function toggleVpTagButtonStyle(button, toggled) {
var commonStyle = 'white-space:nowrap; padding:0 2px;';
if(toggled) {
button.style.cssText = commonStyle + ' border:inset 1px #ccc; background-color:#eee';
button.className = 'vptagbutton vptagbuttontoggled';
} else {
button.style.cssText = commonStyle;
button.className = 'vptagbutton';
}
}
//events
function vpTagSearch(e) {
if(window.attachEvent && !window.opera) //MSIE
e = window.event;
clearVpTagButtons(vpTag.searchResultBlock);
var query = (e.target || e.srcElement).value;
if(query.length == 0) return;
createVpTagButtons(getVpTagSearchList(query), vpTag.searchResultBlock);
}
function vpTagButton_onclick(e) {
if(window.attachEvent && !window.opera) //MSIE
e = window.event;
var target = (e.target || e.srcElement);
var toggled = toggleVpTag(target.innerHTML);
toggleVpTagButtonStyle(target, toggled);
}
function vpTagAppendButton_onclick(e) {
var tagName = document.getElementById('vptagsearchinput').value;
toggleVpTag(tagName);
}
function toggleVpTag(tagName) {
var textarea = document.getElementById('wpTextbox1');
var reg = /\{\{vptag(?:\s*\|\s*([^{}]*?)\s*)?\}\}/i
var m = textarea.value.match(reg);
if(!m) {
//テンプレートが記述されていなければ </noinclude> の直前にタグ追加
reg = /\s*(?=<\/noinclude>)/i
m = textarea.value.match(reg);
if(!m) return;
}
var tags = [];
if(m[1] && m[1].length > 0)
tags = m[1].split(/\s*\|\s*/);
var toggled = true;
for(var i = 0; i < tags.length; i++) {
if(tags[i] == tagName) {
tags.splice(i, 1);
toggled = false;
break;
}
}
if(toggled)
tags.push(tagName);
vpTag.currentTagList = tags;
var dest = '\n' + tags.join(' ';
textarea.value = textarea.value.replace(reg, dest);
return toggled;
}