差分

1版
/*
* 要約欄に書き込める残りバイト数を表示する。
*/
jQuery(function($) {
/* 最大制限バイト数 */
var BYTE_LIMIT = 255;

/* 編集画面かどうかを要約欄の有無で判断する。 */
var $summary = $('#wpSummary');
if ($summary.length === 0) { return; }

/* CSS を設置 */
mw.util.addCSS( '.summary-byte-counter.warn { color: red; }' );

/* カウンターの用意と設置 */
var $label = $('#wpSummaryLabel');
var $counter = $('<span>')
.attr('class', 'summary-byte-counter')
.css({
'display': 'inline-block',
'width': '2em',
'font-weight': 'bold',
'text-align': 'center'
})
.text(BYTE_LIMIT);
$label.append($counter);

// 最初の更新
updateCounter();

/* wikEd への対応 */
if (window.wikEd && window.wikEd.ResizeSummary) {
window.wikEd.ResizeSummary();
}

/* イベントに接続 */
$summary.on({
'keyup': updateCounter,
'focus': updateCounter,
'blur': updateCounter,
'change': updateCounter
});

/*
* 文字列を UTF-8 にした場合のバイト数を取得する。
*/
function numberOfUTF8Bytes(string) {
var len = 0;
if (!string) { return len; }
var code, surrogate = false;
for (var i = 0; ; ++i) {
code = string.charCodeAt(i);
if (isNaN(code)) { break; }
if (code < 0) {
throw new Error('Illegal number: ' + code);
} else if (code <= 0x007F) {
len += 1;
} else if (code <= 0x07FF) {
len += 2;
} else if (code <= 0xD7FF) {
len += 3;
} else if (code <= 0xDBFF) {
surrogate = true;
} else if (code <= 0xDFFF) {
len += 4;
surrogate = false;
} else if (code <= 0xFFFF) {
len += 3;
} else {
throw new Error('Illegal number: ' + code);
}
}
return len;
}

/* 更新用の関数 */
function updateCounter() {
var val = $summary.val();
if (typeof val === 'string') {
var remained = BYTE_LIMIT - numberOfUTF8Bytes(val);
if (remained <= 30) { // 残り30バイト
$counter.addClass('warn');
} else {
$counter.removeClass('warn');
}
$counter.text(remained);
}
}
});