MediaWiki:Gadget-jastyle.js
// **********************************************************************
// **                 ***WARNING GLOBAL GADGET FILE***                 **
// **             changes to this file affect many users.              **
// **           please discuss on the talk page before editing         **
// **                                                                  **
// **********************************************************************
//
// jastyle - autostyle helper gadget script for Japanese wikis.
//
if(!window.WikiGadgets) WikiGadgets = new Object();
WikiGadgets.JaStyle = function() { return this; }
WikiGadgets.JaStyle.version = '0.8.0.1';
WikiGadgets.JaStyle.namespaces = [ , 'Category', 'Template', 'Portal', 'Help' ];
WikiGadgets.JaStyle.install = function() {
var html = , i;
var form = document.getElementById('editform');
if(!form) return;
for(i = 0; i < WikiGadgets.JaStyle.namespaces.length; ++i) {
if(WikiGadgets.JaStyle.namespaces[i] == mw.config.get('wgCanonicalNamespace')) {
addHandler(form, 'submit', WikiGadgets.JaStyle.run);
html += '<label><input type="checkbox" id="dontstyle" value="1" />disable autostyle</label> ';
break;
}
}
html += '<button>style</button>';
html += ' (jastyle version ' + WikiGadgets.JaStyle.version + ')';
var p = document.createElement('p');
p.innerHTML = html;
form.parentNode.insertBefore(p, form);
};
WikiGadgets.JaStyle.run = function() {
var runner = new WikiGadgets.JaStyle();
return runner.run();
};
WikiGadgets.JaStyle.prototype = {
run: function() {
var edit = document.getElementById('wpTextbox1'), s;
this.strips = new Array();
s = edit.value;
s = this.fixup_crlf(s);
s = this.fixup_fullwidth(s);
s = this.fixup_kana(s);
s = this.fixup_compatibles(s);
s = this.fixup_wikiformat(s);
s = this.strip(s);
s = this.fixup_tag(s);
s = this.fixup_lines(s);
s = this.fixup_space(s);
s = this.unstrip(s);
edit.value = s + "\n";
},
// utilities
escapeHTML: function(s) {
var div = document.createElement('div');
div.appendChild(document.createTextNode(s));
return div.innerHTML;
},
unescapeHTML: function(s) {
var div = document.createElement('div');
div.innerHTML = s.replace(/</g, '<').replace(/>/g, '>');
return div.childNodes[0].nodeValue;
},
trim: function(s) {
return s.replace(/^\s+/, ).replace(/\s+$/, );
},
isDisabled: function() {
var e = this.$('dontstyle');
return (e && e.checked);
},
// CRLF
fixup_crlf: function(s) {
return s.replace(/\r*\n|\r/g, "\n");
},
// 全角英数・記号
fixup_fullwidth: function(s) {
return s.
replace(/#/g, '#').replace(/$/g, '$').
replace(/%/g, '%').replace(/&/g, '&').
replace(/-/g, '-').replace(/^/g, '^').
replace(/@/g, '@').replace(/+/g, '+').
replace(/*/g, '*').replace(/</g, '<').
replace(/>/g, '>').replace(///g, '/').
replace(/_/g, '_').
replace(/1/g,'1').replace(/2/g,'2').replace(/3/g,'3').replace(/4/g,'4').
replace(/5/g,'5').replace(/6/g,'6').replace(/7/g,'7').replace(/8/g,'8').
replace(/9/g,'9').replace(/0/g,'0').replace(/A/g,'A').replace(/B/g,'B').
replace(/C/g,'C').replace(/D/g,'D').replace(/E/g,'E').replace(/F/g,'F').
replace(/G/g,'G').replace(/H/g,'H').replace(/I/g,'I').replace(/J/g,'J').
replace(/K/g,'K').replace(/L/g,'L').replace(/M/g,'M').replace(/N/g,'N').
replace(/O/g,'O').replace(/P/g,'P').replace(/Q/g,'Q').replace(/R/g,'R').
replace(/S/g,'S').replace(/T/g,'T').replace(/U/g,'U').replace(/V/g,'V').
replace(/W/g,'W').replace(/X/g,'X').replace(/Y/g,'Y').replace(/Z/g,'Z').
replace(/a/g,'a').replace(/b/g,'b').replace(/c/g,'c').replace(/d/g,'d').
replace(/e/g,'e').replace(/f/g,'f').replace(/g/g,'g').replace(/h/g,'h').
replace(/i/g,'i').replace(/j/g,'j').replace(/k/g,'k').replace(/l/g,'l').
replace(/m/g,'m').replace(/n/g,'n').replace(/o/g,'o').replace(/p/g,'p').
replace(/q/g,'q').replace(/r/g,'r').replace(/s/g,'s').replace(/t/g,'t').
replace(/u/g,'u').replace(/v/g,'v').replace(/w/g,'w').replace(/x/g,'x').
replace(/y/g,'y').replace(/z/g,'z').
// 救済
replace(/([A-Za-z0-9]).[ \s]*/g, '$1. ').
replace(/([A-Za-z0-9]),[ \s]*/g, '$1, ').
// 句読点
replace(/[,､]/g, '、').replace(/[.｡]/g, '。');
},
// 半角カナ
fixup_kana: function(s) {
return s.
replace(/ｶﾞ/g, 'ガ').replace(/ｷﾞ/g, 'ギ').replace(/ｸﾞ/g, 'グ').
replace(/ｹﾞ/g, 'ゲ').replace(/ｺﾞ/g, 'ゴ').replace(/ｻﾞ/g, 'ザ').
replace(/ｼﾞ/g, 'ジ').replace(/ｽﾞ/g, 'ズ').replace(/ｾﾞ/g, 'ゼ').
replace(/ｿﾞ/g, 'ゾ').replace(/ﾀﾞ/g, 'ダ').replace(/ﾁﾞ/g, 'ヂ').
replace(/ﾂﾞ/g, 'ヅ').replace(/ﾃﾞ/g, 'デ').replace(/ﾄﾞ/g, 'ド').
replace(/ﾊﾞ/g, 'バ').replace(/ﾋﾞ/g, 'ビ').replace(/ﾌﾞ/g, 'ブ').
replace(/ﾍﾞ/g, 'ベ').replace(/ﾎﾞ/g, 'ボ').replace(/ﾊﾟ/g, 'パ').
replace(/ﾋﾟ/g, 'ピ').replace(/ﾌﾟ/g, 'プ').replace(/ﾍﾟ/g, 'ペ').
replace(/ﾎﾟ/g, 'ポ').replace(/ｳﾞ/g, 'ヴ').
replace(/ｧ/g, 'ァ').replace(/ｨ/g, 'ィ').replace(/ｩ/g, 'ゥ').
replace(/ｪ/g, 'ェ').replace(/ｫ/g, 'ォ').replace(/ｯ/g, 'ッ').
replace(/ｬ/g, 'ャ').replace(/ｭ/g, 'ュ').replace(/ｮ/g, 'ョ').
replace(/ｱ/g, 'ア').replace(/ｲ/g, 'イ').replace(/ｳ/g, 'ウ').
replace(/ｴ/g, 'エ').replace(/ｵ/g, 'オ').replace(/ｶ/g, 'カ').
replace(/ｷ/g, 'キ').replace(/ｸ/g, 'ク').replace(/ｹ/g, 'ケ').
replace(/ｺ/g, 'コ').replace(/ｻ/g, 'サ').replace(/ｼ/g, 'シ').
replace(/ｽ/g, 'ス').replace(/ｾ/g, 'セ').replace(/ｿ/g, 'ソ').
replace(/ﾀ/g, 'タ').replace(/ﾁ/g, 'チ').replace(/ﾂ/g, 'ツ').
replace(/ﾃ/g, 'テ').replace(/ﾄ/g, 'ト').replace(/ﾅ/g, 'ナ').
replace(/ﾆ/g, 'ニ').replace(/ﾇ/g, 'ヌ').replace(/ﾈ/g, 'ネ').
replace(/ﾉ/g, 'ノ').replace(/ﾊ/g, 'ハ').replace(/ﾋ/g, 'ヒ').
replace(/ﾌ/g, 'フ').replace(/ﾍ/g, 'ヘ').replace(/ﾎ/g, 'ホ').
replace(/ﾏ/g, 'マ').replace(/ﾐ/g, 'ミ').replace(/ﾑ/g, 'ム').
replace(/ﾒ/g, 'メ').replace(/ﾓ/g, 'モ').replace(/ﾔ/g, 'ヤ').
replace(/ﾕ/g, 'ユ').replace(/ﾖ/g, 'ヨ').replace(/ﾗ/g, 'ラ').
replace(/ﾘ/g, 'リ').replace(/ﾙ/g, 'ル').replace(/ﾚ/g, 'レ').
replace(/ﾛ/g, 'ロ').replace(/ﾜ/g, 'ワ').replace(/ｦ/g, 'ヲ').
replace(/ﾝ/g, 'ン').replace(/ｰ/g, 'ー').
replace(/｢/g, '「').replace(/｣/g, '」').replace(/･/g, '・').
replace(/ﾞ/g, '゛').replace(/ﾟ/g, '゜');
},
// 機種依存記号
fixup_compatibles: function(s) {
return s.
replace(/①/g, '(1)').replace(/②/g, '(2)').replace(/③/g, '(3)').
replace(/④/g, '(4)').replace(/⑤/g, '(5)').replace(/⑥/g, '(6)').
replace(/⑦/g, '(7)').replace(/⑧/g, '(8)').replace(/⑨/g, '(9)').
replace(/⑩/g, '(10)').replace(/⑪/g, '(11)').replace(/⑫/g, '(12)').
replace(/⑬/g, '(13)').replace(/⑭/g, '(14)').replace(/⑮/g, '(15)').
replace(/⑯/g, '(16)').replace(/⑰/g, '(17)').replace(/⑱/g, '(18)').
replace(/⑲/g, '(19)').replace(/⑳/g, '(20)').
replace(/Ⅰ/g, 'I').replace(/Ⅱ/g, 'II').replace(/Ⅲ/g, 'III').
replace(/Ⅳ/g, 'IV').replace(/Ⅴ/g, 'V').replace(/Ⅵ/g, 'VI').
replace(/Ⅶ/g, 'VII').replace(/Ⅷ/g, 'VIII').replace(/Ⅸ/g, 'IX').
replace(/Ⅹ/g, 'X').replace(/㍉/g, 'ミリ').replace(/㌔/g, 'キロ').
replace(/㌢/g, 'センチ').replace(/㍍/g, 'メートル').
replace(/㌘/g, 'グラム').replace(/㌧/g, 'トン').replace(/㌃/g, 'アール').
replace(/㌶/g, 'ヘクタール').replace(/㍑/g, 'リットル').
replace(/㍗/g, 'ワット').replace(/㌍/g, 'カロリー').replace(/㌦/g, 'ドル').
replace(/㌣/g, 'セント').replace(/㌫/g, 'パーセント').
replace(/㍊/g, 'ミリバール').replace(/㌻/g, 'ページ').
replace(/㎜/g, 'mm').replace(/㎝/g, 'cm').replace(/㎞/g, 'km').
replace(/㎎/g, 'mg').replace(/㎏/g, 'kg').replace(/㏄/g, 'cc').
replace(/㎡/g, 'm²').replace(/㍻/g, '平成').
replace(/〝/g, '「').replace(/〟/g, '」').replace(/№/g, 'No.').
replace(/㏍/g, 'K.K.').replace(/℡/g, 'Tel').replace(/㊤/g, '(上)').
replace(/㊥/g, '(中)').replace(/㊦/g, '(下)').replace(/㊧/g, '(左)').
replace(/㊨/g, '(右)').replace(/㈱/g, '(株)').replace(/㈲/g, '(有)').
replace(/㈹/g, '(代)').replace(/㍾/g, '明治').replace(/㍽/g, '大正').
replace(/㍼/g, '昭和');
},
// Wiki記法
fixup_wikiformat: function(s) {
s = s.
replace(/\s*\n-----*\s*/g, "\n----\n\n").
replace(/\{\{msg:/ig, '{').
replace(/\{\{SERVER\}\}\{\{localurl:/ig, '{fullurl:').
replace(/(\[\[:?)Category:/ig, '$1Category:').
replace(/\s*<\/?br\s*\/?>/ig, ' ').
replace(/\s*<\/?hr\s*\/?>\s*/ig, "\n----\n\n");
if(location.host == 'ja.wikipedia.org') {
s = s.replace(/\[\[w(:[a-z]{2,3}:)/g, '[$1').replace(/\[\[w:/ig, '[:en:');
}
return s;
},
// strip
strip: function(s) {
var self = this;
s = s.replace(/<pre[^>]*?>(.|\n)*?<\/pre>/g,
function(str) {
var i = strips.length;
self.strips[i] = str;
return ;
});
return s;
},
unstrip: function(s) {
var self = this;
return s.replace(//g, function(str, n) { return self.strips[n]; });
},
// タグ
fixup_tag: function(s) {
var self = this;
s = s.
replace(/<(\/)?([\w\-:]+)([^>]*)>/g, function(str, close, tagName, tagAttrs) {
var re = /([\w\-:]+)(\s*=\s*("([^"]+)"|'([^']+)'|([^\s"']+)))?\s*/g;
var emptyElement = ;
tagName = tagName.toLowerCase();
if(tagAttrs.match(/\/$/)) {
emptyElement = '/';
tagAttrs = tagAttrs.replace(/\/$/, );
}
var attrs = new Object(), match;
if(!close) {
while(match = re.exec(tagAttrs)) {
attrs[match[1].toLowerCase()] = match[2] ? self.unescapeHTML(match[4] || match[5] || match[6]) : false;
}
}
attrs.style = self.trim(attrs.style || ).replace(/[^;]$/, '$&;');
switch(tagName) {
case 'center':
tagName = 'div'; attrs.style += 'text-align:center;';
break;
//    case 'font':
//      tagName = 'span';
//      if(attrs.color) attrs.style += 'color:' + attrs.color + ';';
//      if(attrs.face) attrs.style += "font-family:'" + attrs.face + "';";
//      delete attrs.color; delete attrs.size; delete attrs.face;
//      break;
case 'table':
if(attrs.border === false) { attrs.frame = 'border'; delete attrs.border; }
break;
}
attrs.style = attrs.style.replace(/;$/, );
if(attrs.style === ) delete attrs.style;
var out = '<' + (close || ) + tagName;
if(!close) {
for(var key in attrs) {
out += ' ' + key + '="' + self.escapeHTML(attrs[key] || key) + '"';
}
}
out += emptyElement + '>';
return out;
});
return s;
},
// 行頭認識がいるもの
fixup_lines: function(s) {
var lines = s.split('\n');
var out = , pre_p = false;
for(var i = 0; i < lines.length; i++) {
var line = lines[i].
// 行頭の全角空白
replace(/^ +/g, ).
// 行頭の * : # ;
replace(/^([\*\:\#\;]+)[\s ]*/, '$1 ').
// REDIRECTだけ戻す
replace(/^# REDIRECT[^\[]*\[\[/i, '#REDIRECT[');
//      // で終わる行を ; に置き換え
//      replace(/^\'\'\'(.*?)\'\'\'$/, '; \'\'\'$1\'\'\).
if(!line.match(/^ /)) {
// 行末空白・連続空白除去 (<pre>中はしない)
line = line.replace(/[\s ]+$/, ).replace(/[  \t]+/g, ' ');
pre_p = false;
} else if(line.match(/^[\s ]+$/) && !pre_p) {
// 孤立した空白のみの行
line = ;
} else {
pre_p = true;
}
// == ==
if(line.match(/^=.*[^=]=/)) {
line = line.
replace(/^(={1,5})[\s ]*/, '$1 ').
replace(/[\s ]*(={1,5})$/, ' $1').
replace(/関連(記事|事項|用語)/g, '関連項目').
replace(/外部(参照)?((への)?リンク|サイト)|関連リンク/g, '外部リンク');
}
// interwiki
if(line.match(/^\[\[([a-z]{2,3}|bat-smg|be-x-old|cbk-zam|fiu-vro|map-bms|nds-nl|roa-rup|roa-tara|simple|tokipona|zh-classical|zh-min-nan|zh-yue):.*?\]\]$/)) {
line = decodeURIComponent(line).
replace(/&#((x[\dA-Fa-f]+)|\d+);/ig,
function(str, dec, hex) {
var ch = hex ? parseInt("0" + hex) : parseInt(dec, 10);
return String.fromCharCode(ch);
}).
replace(/_/g, ' ');
}
out += line + '\n';
}
return out;
},
fixup_space: function(s) {
return s.
replace(/^\s+/, ).replace(/\s+$/, ).
// 二行以上の空行トルツメ
replace(/\n{3,}/g, '\n\n').
// 見出しの後の空行トルツメ
replace(/==\n+/g, '==\n').
// 見出しの前に空行を挿入
replace(/([^=\n])\n+==/g, '$1\n\n==');
}
};
$(WikiGadgets.JaStyle.install);