User:ZhuofanWu/block.js: Difference between revisions

From Test Wiki
Jump to navigation Jump to search
Content deleted Content added
ZhuofanWu (talk | contribs)
// 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();
});

})();