User:ZhuofanWu/block.js: Difference between revisions
Jump to navigation
Jump to search
Content deleted Content added
// Edit via Wikiplus |
(No difference)
|
Latest revision as of 05:26, 16 November 2025
(function() {
'use strict';
var nameSpace = {
"0":"(Main)",
"1":"Talk",
"2":"User",
"3":"User talk",
"4":"Project",
"5":"Project talk",
"6":"File",
"7":"File talk",
"8":"MediaWiki",
"9":"MediaWiki talk",
"10":"Template",
"11":"Template talk",
"12":"Help",
"13":"Help talk",
"14":"Category",
"15":"Category talk",
"100":"Portal",
"101":"Portal talk",
"102":"School",
"103":"School talk",
"104":"Subject",
"105":"Subject talk",
"106":"Experiment",
"107":"Experiment talk",
"108":"Lesson",
"109":"Lesson talk",
"110":"Transwiki",
"111":"Transwiki talk",
"112":"TimedText",
"113":"TimedText talk",
"828":"Module",
"829":"Module talk"
};
var presetBlockTime = [
"半小时",
"1小时",
"2小时",
"12小时",
"1日",
"31小时",
"3日",
"5日",
"1周",
"2周",
"1个月",
"3个月",
"6个月",
"1年",
"2年",
"不限期"
];
var customBlockTimeUnit = [
"分钟",
"小时",
"天",
"周",
"月",
"年"
];
var TimeZoneUnit = [
"UTC",
"UTC+8"
];
var blockReasonList = [
"破坏",
"跨维基项目破坏",
"编辑战",
"纯破坏用户",
"仅散发广告/宣传的用户",
"[[:w:zh:WP:CIV|无礼的行为]]、",
"[[:w:zh:WP:NPA|攻击别人]]",
"[[:w:zh:WP:騷擾|骚扰用户]]",
"[[:w:zh:WP:擾亂|扰乱]]",
"[[:w:zh:WP:GAME|游戏维基规则]]",
"确认为[[:w:zh:WP:SOCK|傀儡]]或[[:w:zh:WP:MEAT|真人傀儡]]",
"滥用[[:w:zh:WP:SOCK|傀儡]]",
"屡次增加不实资料",
"增加无意义文字",
"无故删除内容",
"多次加入[[WV:C|侵犯版权]]的内容",
"机器人发生故障并必须紧急停止",
"剥夺编辑对话页权限",
"用户名软封禁-误导性用户名",
"用户名软封禁-宣传性用户名",
"用户名软封禁-攻击/侮辱性用户名",
"用户名软封禁-混淆性用户名"
];
var BlockHelper = {
init: function() {
var namespaces = ['User', 'User_talk'];
var namespace = mw.config.get('wgCanonicalNamespace');
var specialPage = mw.config.get('wgCanonicalSpecialPageName');
if (namespaces.indexOf(namespace) !== -1 || specialPage === 'Contributions') {
mw.loader.using(['oojs-ui-core', 'oojs-ui-windows', 'oojs-ui-widgets', 'mediawiki.api'], function() {
var portletLink = mw.util.addPortletLink('p-tb', '#', '封禁助手', 't-blockhelper', '打开封禁助手工具');
$(portletLink).on('click', function(e) {
e.preventDefault();
BlockHelper.openDialog();
});
});
}
},
openDialog: function() {
var windowManager = new OO.ui.WindowManager();
$(document.body).append(windowManager.$element);
var dialog = new BlockHelperDialog();
windowManager.addWindows([dialog]);
windowManager.openWindow(dialog);
}
};
function BlockHelperDialog(config) {
BlockHelperDialog.super.call(this, config);
}
OO.inheritClass(BlockHelperDialog, OO.ui.ProcessDialog);
BlockHelperDialog.static.name = 'blockHelperDialog';
BlockHelperDialog.static.title = '封禁助手';
BlockHelperDialog.static.size = 'full';
BlockHelperDialog.static.actions = [
{ action: 'submit', label: '执行封禁', flags: ['primary', 'progressive'] },
{ action: 'cancel', label: '取消', flags: 'safe' }
];
BlockHelperDialog.prototype.initialize = function() {
BlockHelperDialog.super.prototype.initialize.apply(this, arguments);
this.pageInputs = [];
this.blockInfo = { current: [], rangeBlocks: [], logs: [] };
this.createLeftColumn();
this.createMiddleColumn();
this.createRightColumn();
var mainLayout = new OO.ui.HorizontalLayout({
items: [this.leftColumn, this.middleColumn, this.rightColumn],
classes: ['blockhelper-main-layout']
});
this.content = new OO.ui.PanelLayout({
padded: true,
expanded: false,
classes: ['blockhelper-content']
});
this.content.$element.append(mainLayout.$element);
this.$body.append(this.content.$element);
this.addStyles();
this.setupEventHandlers();
this.extractDefaultTarget();
this.updateMiddleColumnFromLeft();
};
BlockHelperDialog.prototype.addStyles = function() {
mw.util.addCSS(
'.blockhelper-main-layout { display: flex; gap: 20px; width: 100%; }' +
'.blockhelper-column { flex: 1; min-width: 0; }' +
'.blockhelper-column-left { flex: 1.5; }' +
'.blockhelper-column-middle { flex: 1.2; }' +
'.blockhelper-column-right { flex: 1.3; }' +
'.blockhelper-fieldset { margin-bottom: 20px; }' +
'.blockhelper-page-row { display: flex; gap: 5px; align-items: center; margin-bottom: 5px; }' +
'.blockhelper-page-input { flex: 1; }' +
'.blockhelper-duration-custom { display: flex; gap: 10px; align-items: center; margin-top: 10px; }' +
'.blockhelper-duration-custom > *:first-child { flex: 1; }' +
'.blockhelper-duration-datetime { display: flex; gap: 10px; align-items: center; margin-top: 10px; }' +
'.blockhelper-duration-datetime > *:first-child { flex: 2; }' +
'.blockhelper-info-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; }' +
'.blockhelper-info-table { width: 100%; border-collapse: collapse; margin-top: 10px; font-size: 12px; }' +
'.blockhelper-info-table th, .blockhelper-info-table td { border: 1px solid #a2a9b1; padding: 5px; text-align: left; }' +
'.blockhelper-info-table th { background-color: #eaecf0; font-weight: bold; }'
);
};
BlockHelperDialog.prototype.createLeftColumn = function() {
var self = this;
this.targetInput = new OO.ui.TextInputWidget({ placeholder: '用户名或IP地址' });
var targetField = new OO.ui.FieldLayout(this.targetInput, {
label: '封禁对象',
align: 'top'
});
this.blockTypeRadio = new OO.ui.RadioSelectWidget({
items: [
new OO.ui.RadioOptionWidget({ data: 'sitewide', label: '全站' }),
new OO.ui.RadioOptionWidget({ data: 'partial', label: '部分页面' })
]
});
this.blockTypeRadio.selectItemByData('sitewide');
var blockTypeField = new OO.ui.FieldLayout(this.blockTypeRadio, {
label: '封禁类型',
align: 'top'
});
this.partialBlockContainer = new OO.ui.FieldsetLayout({ classes: ['blockhelper-partial-container'] });
this.partialBlockContainer.toggle(false);
this.pagesContainer = new OO.ui.Widget();
this.addPageInput();
var addPageBtn = new OO.ui.ButtonWidget({ label: '+', framed: false });
addPageBtn.on('click', function() { self.addPageInput(); });
var pagesField = new OO.ui.FieldLayout(
new OO.ui.Widget({
content: [new OO.ui.LabelWidget({ label: '页面' }), this.pagesContainer, addPageBtn]
}),
{ align: 'top' }
);
var nsOptions = [];
for (var nsId in nameSpace) {
nsOptions.push(new OO.ui.MenuOptionWidget({ data: nsId, label: nameSpace[nsId] }));
}
this.namespaceSelect = new OO.ui.MenuTagMultiselectWidget({
options: nsOptions,
placeholder: '选择命名空间'
});
var nsField = new OO.ui.FieldLayout(this.namespaceSelect, { label: '命名空间', align: 'top' });
this.uploadCheckbox = new OO.ui.CheckboxInputWidget();
var uploadField = new OO.ui.FieldLayout(this.uploadCheckbox, { label: '上传文件(包括覆盖文件)', align: 'inline' });
this.moveCheckbox = new OO.ui.CheckboxInputWidget();
var moveField = new OO.ui.FieldLayout(this.moveCheckbox, { label: '移动页面及文件', align: 'inline' });
this.createCheckbox = new OO.ui.CheckboxInputWidget();
var createField = new OO.ui.FieldLayout(this.createCheckbox, { label: '创建新页面及上传新文件', align: 'inline' });
this.thanksCheckbox = new OO.ui.CheckboxInputWidget();
var thanksField = new OO.ui.FieldLayout(this.thanksCheckbox, { label: '发送感谢', align: 'inline' });
this.partialBlockContainer.addItems([pagesField, nsField, uploadField, moveField, createField, thanksField]);
this.durationTypeRadio = new OO.ui.RadioSelectWidget({
items: [
new OO.ui.RadioOptionWidget({ data: 'preset', label: '预设持续时间' }),
new OO.ui.RadioOptionWidget({ data: 'custom', label: '自定义持续时间' }),
new OO.ui.RadioOptionWidget({ data: 'datetime', label: '指定日期与时间' })
]
});
this.durationTypeRadio.selectItemByData('preset');
this.presetDurationSelect = new OO.ui.DropdownWidget({
menu: { items: presetBlockTime.map(function(time) { return new OO.ui.MenuOptionWidget({ data: time, label: time }); }) }
});
this.presetDurationSelect.getMenu().selectItemByData('1日');
this.customDurationInput = new OO.ui.NumberInputWidget({ value: 1, min: 1 });
this.customDurationUnitSelect = new OO.ui.DropdownWidget({
menu: { items: customBlockTimeUnit.map(function(unit) { return new OO.ui.MenuOptionWidget({ data: unit, label: unit }); }) }
});
this.customDurationUnitSelect.getMenu().selectItemByData('天');
this.customDurationContainer = new OO.ui.Widget({
content: [
new OO.ui.HorizontalLayout({
items: [this.customDurationInput, this.customDurationUnitSelect],
classes: ['blockhelper-duration-custom']
})
]
});
this.customDurationContainer.toggle(false);
this.datetimeInput = new OO.ui.TextInputWidget({
type: 'datetime-local',
placeholder: 'YYYY-MM-DD HH:MM:SS'
});
this.timezoneSelect = new OO.ui.DropdownWidget({
menu: { items: TimeZoneUnit.map(function(tz) { return new OO.ui.MenuOptionWidget({ data: tz, label: tz }); }) }
});
this.timezoneSelect.getMenu().selectItemByData('UTC+8');
this.datetimeContainer = new OO.ui.Widget({
content: [
new OO.ui.HorizontalLayout({
items: [this.datetimeInput, this.timezoneSelect],
classes: ['blockhelper-duration-datetime']
})
]
});
this.datetimeContainer.toggle(false);
var durationField = new OO.ui.FieldLayout(
new OO.ui.Widget({
content: [this.durationTypeRadio, this.presetDurationSelect, this.customDurationContainer, this.datetimeContainer]
}),
{ label: '期限', align: 'top' }
);
this.reasonSelect = new OO.ui.DropdownWidget({
menu: { items: blockReasonList.map(function(reason) { return new OO.ui.MenuOptionWidget({ data: reason, label: reason }); }) }
});
this.reasonInput = new OO.ui.MultilineTextInputWidget({ rows: 3, placeholder: '附加原因' });
var reasonField = new OO.ui.FieldLayout(
new OO.ui.Widget({ content: [this.reasonSelect, this.reasonInput] }),
{ label: '封禁原因', align: 'top' }
);
this.nocreateCheckbox = new OO.ui.CheckboxInputWidget({ selected: true });
var nocreateField = new OO.ui.FieldLayout(this.nocreateCheckbox, { label: '账号创建', align: 'inline' });
this.noemailCheckbox = new OO.ui.CheckboxInputWidget();
var noemailField = new OO.ui.FieldLayout(this.noemailCheckbox, { label: '发送电子邮件', align: 'inline' });
this.allowusertalkCheckbox = new OO.ui.CheckboxInputWidget();
var allowusertalkField = new OO.ui.FieldLayout(this.allowusertalkCheckbox, { label: '编辑自己的讨论页', align: 'inline' });
var detailsFieldset = new OO.ui.FieldsetLayout({
label: '封禁细节',
items: [nocreateField, noemailField, allowusertalkField],
classes: ['blockhelper-fieldset']
});
this.autoblockCheckbox = new OO.ui.CheckboxInputWidget();
this.autoblockField = new OO.ui.FieldLayout(this.autoblockCheckbox, {
label: '将此账号最后所使用的,以及后续编辑所在的所有IP地址封禁1天',
align: 'inline'
});
this.hardblockCheckbox = new OO.ui.CheckboxInputWidget({ selected: true });
this.hardblockField = new OO.ui.FieldLayout(this.hardblockCheckbox, {
label: '封禁使用该IP地址登录的用户',
align: 'inline'
});
this.watchuserCheckbox = new OO.ui.CheckboxInputWidget();
var watchuserField = new OO.ui.FieldLayout(this.watchuserCheckbox, { label: '监视目标的用户页和讨论页', align: 'inline' });
var extraFieldset = new OO.ui.FieldsetLayout({
label: '额外选项',
items: [this.autoblockField, this.hardblockField, watchuserField],
classes: ['blockhelper-fieldset']
});
this.leftColumn = new OO.ui.PanelLayout({
padded: true,
framed: true,
expanded: false,
classes: ['blockhelper-column', 'blockhelper-column-left']
});
this.leftColumn.$element.append(
targetField.$element,
blockTypeField.$element,
this.partialBlockContainer.$element,
durationField.$element,
reasonField.$element,
detailsFieldset.$element,
extraFieldset.$element
);
};
BlockHelperDialog.prototype.addPageInput = function() {
var self = this;
var input = new OO.ui.TextInputWidget({ placeholder: '页面名称', classes: ['blockhelper-page-input'] });
var removeBtn = new OO.ui.ButtonWidget({ label: '-', framed: false });
var row = new OO.ui.HorizontalLayout({
items: [input, removeBtn],
classes: ['blockhelper-page-row']
});
removeBtn.on('click', function() {
var index = self.pageInputs.indexOf(input);
if (index > -1) {
self.pageInputs.splice(index, 1);
}
row.$element.remove();
if (self.pageInputs.length === 0) {
self.addPageInput();
}
self.updateMiddleColumnFromLeft();
});
input.on('change', function() {
self.updateMiddleColumnFromLeft();
});
this.pageInputs.push(input);
this.pagesContainer.$element.append(row.$element);
};
BlockHelperDialog.prototype.createMiddleColumn = function() {
var self = this;
this.notifyCheckbox = new OO.ui.CheckboxInputWidget({ selected: true });
var notifyField = new OO.ui.FieldLayout(this.notifyCheckbox, { label: '是否通知封禁对象', align: 'inline' });
this.templateSelect = new OO.ui.DropdownWidget({
menu: {
items: [
new OO.ui.MenuOptionWidget({ data: 'uw-block', label: 'uw-block' }),
new OO.ui.MenuOptionWidget({ data: 'uw-pblock', label: 'uw-pblock' }),
new OO.ui.MenuOptionWidget({ data: 'uw-ublock', label: 'uw-ublock' })
]
}
});
this.templateSelect.getMenu().selectItemByData('uw-block');
var templateField = new OO.ui.FieldLayout(this.templateSelect, { label: '消息模板', align: 'top' });
this.paramReasonInput = new OO.ui.TextInputWidget({ placeholder: 'reason' });
this.paramIndefSelect = new OO.ui.DropdownWidget({
menu: {
items: [
new OO.ui.MenuOptionWidget({ data: '', label: '无' }),
new OO.ui.MenuOptionWidget({ data: 'yes', label: 'yes' })
]
}
});
this.paramIndefSelect.getMenu().selectItemByData('');
this.paramTimeInput = new OO.ui.TextInputWidget({ placeholder: 'time' });
this.paramNotalkSelect = new OO.ui.DropdownWidget({
menu: {
items: [
new OO.ui.MenuOptionWidget({ data: '', label: '无' }),
new OO.ui.MenuOptionWidget({ data: 'yes', label: 'yes' })
]
}
});
this.paramNotalkSelect.getMenu().selectItemByData('');
this.paramPageInput = new OO.ui.TextInputWidget({ placeholder: 'page' });
this.paramAreaInput = new OO.ui.TextInputWidget({ placeholder: 'area' });
this.paramReasonField = new OO.ui.FieldLayout(this.paramReasonInput, { label: 'reason', align: 'top' });
this.paramIndefField = new OO.ui.FieldLayout(this.paramIndefSelect, { label: 'indef', align: 'top' });
this.paramTimeField = new OO.ui.FieldLayout(this.paramTimeInput, { label: 'time', align: 'top' });
this.paramNotalkField = new OO.ui.FieldLayout(this.paramNotalkSelect, { label: 'notalk', align: 'top' });
this.paramPageField = new OO.ui.FieldLayout(this.paramPageInput, { label: 'page', align: 'top' });
this.paramAreaField = new OO.ui.FieldLayout(this.paramAreaInput, { label: 'area', align: 'top' });
this.ublockReasonSelect = new OO.ui.DropdownWidget({
menu: {
items: [
new OO.ui.MenuOptionWidget({ data: '误导', label: '误导' }),
new OO.ui.MenuOptionWidget({ data: '宣传', label: '宣传' }),
new OO.ui.MenuOptionWidget({ data: '破坏/攻击/侮辱', label: '破坏/攻击/侮辱' }),
new OO.ui.MenuOptionWidget({ data: '混淆', label: '混淆' })
]
}
});
this.blockParamsContainer = new OO.ui.FieldsetLayout({
label: '模板参数',
items: []
});
this.pblockParamsContainer = new OO.ui.FieldsetLayout({
label: '模板参数',
items: []
});
this.pblockParamsContainer.toggle(false);
this.ublockReasonField = new OO.ui.FieldLayout(this.ublockReasonSelect, { label: '原因', align: 'top' });
this.ublockParamsContainer = new OO.ui.FieldsetLayout({
label: '模板参数',
items: [
this.ublockReasonField
]
});
this.ublockParamsContainer.toggle(false);
this.middleColumn = new OO.ui.PanelLayout({
padded: true,
framed: true,
expanded: false,
classes: ['blockhelper-column', 'blockhelper-column-middle']
});
this.middleColumn.$element.append(
notifyField.$element,
templateField.$element,
this.blockParamsContainer.$element,
this.pblockParamsContainer.$element,
this.ublockParamsContainer.$element
);
this.updateTemplateParamsVisibility();
};
BlockHelperDialog.prototype.createRightColumn = function() {
var self = this;
this.refreshButton = new OO.ui.ButtonWidget({ icon: 'reload', label: '刷新' });
this.refreshButton.on('click', function() {
self.queryBlockInfo();
});
var header = $('<div>').addClass('blockhelper-info-header')
.append($('<h3>').text('封禁信息'))
.append(this.refreshButton.$element);
this.currentBlocksSection = this.createCollapsibleSection('现有封禁', 0);
this.rangeBlocksSection = this.createCollapsibleSection('现有的段封禁', 0);
this.blockLogsSection = this.createCollapsibleSection('封禁日志', 0);
this.rightColumn = new OO.ui.PanelLayout({
padded: true,
framed: true,
expanded: false,
classes: ['blockhelper-column', 'blockhelper-column-right']
});
this.rightColumn.$element.append(
header,
this.currentBlocksSection.$element,
this.rangeBlocksSection.$element,
this.blockLogsSection.$element
);
};
BlockHelperDialog.prototype.createCollapsibleSection = function(title, count) {
var header = new OO.ui.ButtonWidget({
framed: false,
label: title + ' (' + count + ')',
indicator: 'down'
});
var content = $('<div>').hide();
header.on('click', function() {
content.toggle();
header.setIndicator(content.is(':visible') ? 'up' : 'down');
});
var section = new OO.ui.Widget();
section.$element.append(header.$element, content);
section.header = header;
section.content = content;
return section;
};
BlockHelperDialog.prototype.setupEventHandlers = function() {
var self = this;
this.blockTypeRadio.on('select', function(item) {
var isPartial = item.getData() === 'partial';
self.partialBlockContainer.toggle(isPartial);
if (isPartial) {
self.allowusertalkCheckbox.setSelected(false);
self.allowusertalkCheckbox.setDisabled(true);
self.templateSelect.getMenu().selectItemByData('uw-pblock');
} else {
self.allowusertalkCheckbox.setDisabled(false);
var reasonSelect = self.reasonSelect.getMenu().findSelectedItem();
var reason = reasonSelect ? reasonSelect.getData() : '';
self.updateTemplateByReason(reason);
}
self.updateMiddleColumnFromLeft();
});
this.durationTypeRadio.on('select', function(item) {
var type = item.getData();
self.presetDurationSelect.toggle(type === 'preset');
self.customDurationContainer.toggle(type === 'custom');
self.datetimeContainer.toggle(type === 'datetime');
self.updateMiddleColumnFromLeft();
});
this.notifyCheckbox.on('change', function(selected) {
self.templateSelect.setDisabled(!selected);
var isEnabled = selected && self.notifyCheckbox.isSelected();
self.paramReasonInput.setDisabled(!isEnabled);
self.paramIndefSelect.setDisabled(!isEnabled);
self.paramTimeInput.setDisabled(!isEnabled);
self.paramNotalkSelect.setDisabled(!isEnabled);
self.paramPageInput.setDisabled(!isEnabled);
self.paramAreaInput.setDisabled(!isEnabled);
self.ublockReasonSelect.setDisabled(!isEnabled);
});
this.templateSelect.getMenu().on('select', function(item) {
self.updateTemplateParamsVisibility();
});
this.targetInput.on('change', function() {
self.updateExtraOptionsVisibility();
self.updateMiddleColumnFromLeft();
});
this.targetInput.$input.on('blur', function() {
self.queryBlockInfo();
});
this.reasonSelect.getMenu().on('select', function(item) {
self.updateTemplateByReason(item.getData());
self.updateMiddleColumnFromLeft();
});
this.reasonInput.on('change', function() {
self.updateMiddleColumnFromLeft();
});
this.presetDurationSelect.getMenu().on('select', function() {
self.updateMiddleColumnFromLeft();
});
this.customDurationInput.on('change', function() {
self.updateMiddleColumnFromLeft();
});
this.customDurationUnitSelect.getMenu().on('select', function() {
self.updateMiddleColumnFromLeft();
});
this.allowusertalkCheckbox.on('change', function() {
self.updateMiddleColumnFromLeft();
});
this.namespaceSelect.on('change', function() {
self.updateMiddleColumnFromLeft();
});
};
BlockHelperDialog.prototype.extractDefaultTarget = function() {
var namespace = mw.config.get('wgCanonicalNamespace');
var title = mw.config.get('wgTitle');
var specialPage = mw.config.get('wgCanonicalSpecialPageName');
var username = '';
if (namespace === 'User' || namespace === 'User_talk') {
username = title.split('/')[0];
} else if (specialPage === 'Contributions') {
var urlParams = new URLSearchParams(window.location.search);
username = urlParams.get('target') || '';
if (!username) {
var pathMatch = mw.config.get('wgPageName').match(/Special:Contributions\/(.+)/);
if (pathMatch) {
username = decodeURIComponent(pathMatch[1]);
}
}
}
if (username) {
this.targetInput.setValue(username);
this.updateExtraOptionsVisibility();
this.queryBlockInfo();
}
};
BlockHelperDialog.prototype.updateExtraOptionsVisibility = function() {
var target = this.targetInput.getValue().trim();
var isIP = this.isIPOrCIDR(target);
this.autoblockField.toggle(!isIP && target !== '');
this.hardblockField.toggle(isIP);
};
BlockHelperDialog.prototype.updateTemplateParamsVisibility = function() {
var template = this.templateSelect.getMenu().findSelectedItem();
var templateData = template ? template.getData() : 'uw-block';
this.blockParamsContainer.toggle(templateData === 'uw-block');
this.pblockParamsContainer.toggle(templateData === 'uw-pblock');
this.ublockParamsContainer.toggle(templateData === 'uw-ublock');
this.refreshTemplateParamFieldsets(templateData);
};
BlockHelperDialog.prototype.refreshTemplateParamFieldsets = function(templateData) {
this.clearFieldset(this.blockParamsContainer);
this.clearFieldset(this.pblockParamsContainer);
if (templateData === 'uw-block') {
this.blockParamsContainer.addItems([
this.paramReasonField,
this.paramIndefField,
this.paramTimeField,
this.paramNotalkField,
this.paramPageField
]);
} else if (templateData === 'uw-pblock') {
this.pblockParamsContainer.addItems([
this.paramReasonField,
this.paramIndefField,
this.paramTimeField,
this.paramNotalkField,
this.paramPageField,
this.paramAreaField
]);
}
};
BlockHelperDialog.prototype.clearFieldset = function(fieldset) {
if (!fieldset || typeof fieldset.getItems !== 'function') {
return;
}
var items = fieldset.getItems();
if (items && items.length) {
fieldset.removeItems(items.slice());
}
};
BlockHelperDialog.prototype.updateTemplateByReason = function(reason) {
var blockType = this.blockTypeRadio.findSelectedItem().getData();
var usernameReasons = [
'用户名软封禁-误导性用户名',
'用户名软封禁-宣传性用户名',
'用户名软封禁-攻击/侮辱性用户名',
'用户名软封禁-混淆性用户名'
];
if (usernameReasons.indexOf(reason) !== -1) {
this.templateSelect.getMenu().selectItemByData('uw-ublock');
var reasonMap = {
'用户名软封禁-误导性用户名': '误导',
'用户名软封禁-宣传性用户名': '宣传',
'用户名软封禁-攻击/侮辱性用户名': '破坏/攻击/侮辱',
'用户名软封禁-混淆性用户名': '混淆'
};
this.ublockReasonSelect.getMenu().selectItemByData(reasonMap[reason]);
} else {
if (blockType === 'partial') {
this.templateSelect.getMenu().selectItemByData('uw-pblock');
} else {
this.templateSelect.getMenu().selectItemByData('uw-block');
}
}
this.updateTemplateParamsVisibility();
};
BlockHelperDialog.prototype.updateMiddleColumnFromLeft = function() {
var reasonSelect = this.reasonSelect.getMenu().findSelectedItem();
var reasonText = reasonSelect ? reasonSelect.getData() : '';
var additionalReason = this.reasonInput.getValue();
var fullReason = reasonText + (additionalReason ? ' ' + additionalReason : '');
this.paramReasonInput.setValue(fullReason);
var durationType = this.durationTypeRadio.findSelectedItem().getData();
var duration = '';
var isIndefinite = false;
if (durationType === 'preset') {
var presetItem = this.presetDurationSelect.getMenu().findSelectedItem();
duration = presetItem ? presetItem.getData() : '';
isIndefinite = duration === '不限期';
} else if (durationType === 'custom') {
var value = this.customDurationInput.getValue();
var unit = this.customDurationUnitSelect.getMenu().findSelectedItem();
duration = value + (unit ? unit.getData() : '');
}
this.paramIndefSelect.getMenu().selectItemByData(isIndefinite ? 'yes' : '');
this.paramTimeInput.setValue(durationType !== 'datetime' ? duration : '');
var notalk = this.allowusertalkCheckbox.isSelected() ? 'yes' : '';
this.paramNotalkSelect.getMenu().selectItemByData(notalk);
var pages = [];
for (var i = 0; i < this.pageInputs.length; i++) {
var pageValue = this.pageInputs[i].getValue();
if (pageValue) {
pages.push(pageValue);
}
}
var namespaces = this.namespaceSelect.getValue();
var area = '';
if (namespaces.length > 0) {
area = namespaces.map(function(nsId) { return nameSpace[nsId]; }).join(', ');
} else if (pages.length > 0) {
area = pages.join(', ');
}
this.paramAreaInput.setValue(area);
this.paramPageInput.setValue(pages.join(', '));
};
BlockHelperDialog.prototype.queryBlockInfo = function() {
var self = this;
var target = this.targetInput.getValue().trim();
if (!target) {
return;
}
target = this.normalizeIPv6(target);
this.targetInput.setValue(target);
var isIP = this.isIPOrCIDR(target);
this.rangeBlocksSection.toggle(isIP);
var api = new mw.Api();
api.get({
action: 'query',
list: 'blocks',
bkusers: target,
bklimit: 50,
bkprop: 'id|user|by|timestamp|expiry|reason|range|flags'
}).done(function(data) {
self.blockInfo.current = data.query.blocks || [];
self.updateBlockSection(self.currentBlocksSection, self.blockInfo.current, 'current');
});
if (isIP) {
api.get({
action: 'query',
list: 'blocks',
bkip: target,
bklimit: 50,
bkprop: 'id|user|by|timestamp|expiry|reason|range|flags'
}).done(function(data) {
self.blockInfo.rangeBlocks = data.query.blocks || [];
self.updateBlockSection(self.rangeBlocksSection, self.blockInfo.rangeBlocks, 'range');
});
}
api.get({
action: 'query',
list: 'logevents',
letype: 'block',
letitle: 'User:' + target,
lelimit: 50,
leprop: 'user|timestamp|comment|details'
}).done(function(data) {
self.blockInfo.logs = data.query.logevents || [];
self.updateBlockSection(self.blockLogsSection, self.blockInfo.logs, 'log');
});
};
BlockHelperDialog.prototype.isIPOrCIDR = function(target) {
var ipv4Regex = /^(\d{1,3}\.){3}\d{1,3}(\/\d{1,2})?$/;
var ipv6Regex = /^([0-9a-fA-F]{0,4}:){2,7}[0-9a-fA-F]{0,4}(\/\d{1,3})?$/;
return ipv4Regex.test(target) || ipv6Regex.test(target);
};
BlockHelperDialog.prototype.normalizeIPv6 = function(ip) {
if (!/^([0-9a-fA-F]{0,4}:){2,7}[0-9a-fA-F]{0,4}(\/\d{1,3})?$/.test(ip)) {
return ip;
}
var parts = ip.split('/');
var addr = parts[0];
var cidr = parts[1] || '';
if (addr.indexOf('::') !== -1) {
var sides = addr.split('::');
var left = sides[0] ? sides[0].split(':') : [];
var right = sides[1] ? sides[1].split(':') : [];
var missing = 8 - left.length - right.length;
var middle = [];
for (var i = 0; i < missing; i++) {
middle.push('0');
}
addr = left.concat(middle, right).join(':');
}
return addr + (cidr ? '/' + cidr : '');
};
BlockHelperDialog.prototype.updateBlockSection = function(section, data, type) {
section.header.setLabel(section.header.getLabel().replace(/\(\d+\)/, '(' + data.length + ')'));
if (data.length === 0) {
section.content.html('<p>无记录</p>');
return;
}
var table = $('<table>').addClass('blockhelper-info-table');
var thead, tbody;
if (type === 'log') {
thead = $('<thead>').append(
$('<tr>')
.append($('<th>').text('时间'))
.append($('<th>').text('操作员'))
.append($('<th>').text('操作'))
.append($('<th>').text('原因'))
);
tbody = $('<tbody>');
data.forEach(function(log) {
var row = $('<tr>')
.append($('<td>').text(log.timestamp))
.append($('<td>').text(log.user))
.append($('<td>').text(log.action))
.append($('<td>').text(log.comment || ''));
tbody.append(row);
});
} else {
thead = $('<thead>').append(
$('<tr>')
.append($('<th>').text('用户'))
.append($('<th>').text('封禁者'))
.append($('<th>').text('开始时间'))
.append($('<th>').text('到期时间'))
.append($('<th>').text('原因'))
);
tbody = $('<tbody>');
data.forEach(function(block) {
var row = $('<tr>')
.append($('<td>').text(block.user))
.append($('<td>').text(block.by))
.append($('<td>').text(block.timestamp))
.append($('<td>').text(block.expiry))
.append($('<td>').text(block.reason || ''));
tbody.append(row);
});
}
table.append(thead, tbody);
section.content.html('').append(table);
};
BlockHelperDialog.prototype.getActionProcess = function(action) {
var dialog = this;
if (action === 'submit') {
return new OO.ui.Process(function() {
var data = dialog.collectData();
dialog.handle(data);
dialog.close({ action: action });
});
} else if (action === 'cancel') {
return new OO.ui.Process(function() {
dialog.close({ action: action });
});
}
return BlockHelperDialog.super.prototype.getActionProcess.call(this, action);
};
BlockHelperDialog.prototype.collectData = function() {
var data = {
target: this.targetInput.getValue(),
blockType: this.blockTypeRadio.findSelectedItem().getData(),
partial: {},
duration: {},
reason: {},
details: {},
extra: {},
notify: {
enabled: this.notifyCheckbox.isSelected(),
template: this.templateSelect.getMenu().findSelectedItem().getData(),
params: {}
},
blockInfo: this.blockInfo
};
if (data.blockType === 'partial') {
var pages = [];
for (var i = 0; i < this.pageInputs.length; i++) {
var page = this.pageInputs[i].getValue();
if (page) pages.push(page);
}
data.partial = {
pages: pages,
namespaces: this.namespaceSelect.getValue(),
upload: this.uploadCheckbox.isSelected(),
move: this.moveCheckbox.isSelected(),
create: this.createCheckbox.isSelected(),
thanks: this.thanksCheckbox.isSelected()
};
}
var durationType = this.durationTypeRadio.findSelectedItem().getData();
data.duration.type = durationType;
if (durationType === 'preset') {
var preset = this.presetDurationSelect.getMenu().findSelectedItem();
data.duration.value = preset ? preset.getData() : '';
} else if (durationType === 'custom') {
data.duration.value = this.customDurationInput.getValue();
var unit = this.customDurationUnitSelect.getMenu().findSelectedItem();
data.duration.unit = unit ? unit.getData() : '';
} else {
data.duration.datetime = this.datetimeInput.getValue();
var tz = this.timezoneSelect.getMenu().findSelectedItem();
data.duration.timezone = tz ? tz.getData() : '';
}
var reasonSelect = this.reasonSelect.getMenu().findSelectedItem();
data.reason.selected = reasonSelect ? reasonSelect.getData() : '';
data.reason.additional = this.reasonInput.getValue();
data.details = {
nocreate: this.nocreateCheckbox.isSelected(),
noemail: this.noemailCheckbox.isSelected(),
allowusertalk: this.allowusertalkCheckbox.isSelected()
};
data.extra = {
autoblock: this.autoblockCheckbox.isSelected(),
hardblock: this.hardblockCheckbox.isSelected(),
watchuser: this.watchuserCheckbox.isSelected()
};
if (data.notify.enabled) {
if (data.notify.template === 'uw-ublock') {
var ublockReason = this.ublockReasonSelect.getMenu().findSelectedItem();
data.notify.params.reason = ublockReason ? ublockReason.getData() : '';
} else {
var indefItem = this.paramIndefSelect.getMenu().findSelectedItem();
var notalkItem = this.paramNotalkSelect.getMenu().findSelectedItem();
data.notify.params = {
reason: this.paramReasonInput.getValue(),
indef: indefItem ? indefItem.getData() : '',
time: this.paramTimeInput.getValue(),
notalk: notalkItem ? notalkItem.getData() : '',
page: this.paramPageInput.getValue()
};
if (data.notify.template === 'uw-pblock') {
data.notify.params.area = this.paramAreaInput.getValue();
}
}
}
return data;
};
BlockHelperDialog.prototype.handle = function(data) {
console.log('Block data collected:', data);
};
BlockHelperDialog.prototype.getBodyHeight = function() {
return 600;
};
$(function() {
BlockHelper.init();
});
})();