跳转到内容

User:PexEric/dates.js

维基百科,自由的百科全书
注意:保存之后,你必须清除浏览器缓存才能看到做出的更改。Google ChromeFirefoxMicrosoft EdgeSafari:按住⇧ Shift键并单击工具栏的“刷新”按钮。参阅Help:绕过浏览器缓存以获取更多帮助。
// 日期格式修正脚本 v1.8 by PexEric
// 优势:1.在条目页添加按钮,不启动编辑器,直接修改提交 2.可自定义处理参数
// 说明:[[User:PexEric/MOSNUM_dates]]

// 另见[[User:Vozhuo/Tool/MOSNUM_dates]]

(function() {
    'use strict';

    // --- 配置管理 ---
    const config = {
        // 脚本信息
        scriptName: '[[User:PexEric/MOSNUM_dates|dates.js]]',
        version: '1.8',
        baseSummary: '修改参考文献日期格式为[[MOS:DATE|ISO格式]]',

        // 功能管理
        processChineseDates: true, // 是否处理 YYYY年MM月DD日
        removeDfParam: false,      // 是否移除 |df= 参数
        minorEdit: true,           // 是否标记为小编辑
        namespace: 0,              // 生效的命名空间 (0 为条目)
        targetParams: ['date', 'access-date', 'archive-date', 'publication-date', 'issue-date'],  // 目标参数

        paramRegexPart: '' // 在下面初始化
    };
    // 初始化参数正则表达式
    config.paramRegexPart = `\\|\\s*(?:${config.targetParams.map(p => p.replace(/-/g, '-?')).join('|')})\\s*=\\s*`;

    // 读取并合并用户自定义配置
    const userConfig = typeof window.MOSNUMDatesConfig === 'object' ? window.MOSNUMDatesConfig : {};
    const overriddenKeys = []; // 记录被用户覆盖的键
    for (const key in userConfig) {
        if (Object.hasOwnProperty.call(userConfig, key) && Object.hasOwnProperty.call(config, key)) {
            // 只覆盖 config 中已存在的键,防止注入无关配置
            // 对于 targetParams,允许用户提供完整数组进行覆盖
            if (key === 'targetParams' && Array.isArray(userConfig[key])) {
                 config[key] = userConfig[key];
                 // 如果覆盖了 targetParams,需要重新计算 paramRegexPart
                 config.paramRegexPart = `\\|\\s*(?:${config.targetParams.map(p => p.replace(/-/g, '-?')).join('|')})\\s*=\\s*`;
                 overriddenKeys.push(key);
            } else if (typeof config[key] === typeof userConfig[key] && key !== 'targetParams' && key !== 'paramRegexPart' && key !== 'version' && key !== 'scriptName') {
                // 仅当类型匹配且不是内部/关键信息时覆盖
                config[key] = userConfig[key];
                overriddenKeys.push(key);
            }
        }
    }
    const hasUserConfig = overriddenKeys.length > 0; // 标记是否存在有效的用户配置覆盖

    // --- 主处理流程 ---
    function enhancedDateFix(text) {
        // 检查 ohc.dateutil 是否可用
        if (typeof ohc === 'undefined' || typeof ohc.dateutil === 'undefined' || typeof ohc.dateutil.regex !== 'function') {
            mw.notify('错误:MOSNUM_utils.js 未加载或加载失败', { type: 'error' });
            throw new Error('MOSNUM_utils.js not available'); // 抛出错误中断执行
        }

        // 构造正则表达式时动态插入参数匹配部分 (使用最终的 config)
        const paramPrefix = `(${config.paramRegexPart})`; // 捕获组 $1

        // 1. 处理英文日期格式 (Day Month, YYYY) -> YYYY-MM-DD
        text = ohc.dateutil.regex(text,
            new RegExp(paramPrefix + '@Day\\s+@Month,?\\s+@YYYY', 'gi'),
            "$1@YYYY-@MM-@DD"
        );
        // 2. 处理英文日期格式 (Month Day, YYYY) -> YYYY-MM-DD
        text = ohc.dateutil.regex(text,
            new RegExp(paramPrefix + '@Month\\s+@Day,?\\s+@YYYY', 'gi'),
            "$1@YYYY-@MM-@DD"
        );
        // 3. 处理中文日期格式 (YYYY年MM月DD日) -> YYYY-MM-DD (根据最终的 config 决定是否执行)
        if (config.processChineseDates) {
            // 注意:ohc.dateutil.regex 不直接支持中文数字,这里用普通正则替换
            text = text.replace(
                 new RegExp(paramPrefix + '(\\d{4})年(\\d{1,2})月(\\d{1,2})日', 'gi'),
                 (match, p1, y, m, d) => {
                     return `${p1}${y}-${String(m).padStart(2, '0')}-${String(d).padStart(2, '0')}`;
                 }
            );
        }
        // 4. 修正 ISO 格式中的分隔符 (YYYY/MM/DD 或 YYYY.MM.DD) -> YYYY-MM-DD
        text = ohc.dateutil.regex(text,
            new RegExp(paramPrefix + '@YYYY[./]@MM[./]@DD', 'gi'),
            "$1@YYYY-@MM-@DD"
        );
        // 5. 修正 UK 风格日期 (DD/MM/YYYY 或 DD.MM.YYYY) -> YYYY-MM-DD
        // 添加检查 d.y > 12 确保年份部分确实是年份
        text = ohc.dateutil.regex(text,
            new RegExp(paramPrefix + '@DD[./]@MM[./]@YYYY', 'gi'),
            "$1@YYYY-@MM-@DD",
            function (d) { return d.y > 12; } // 确保年份大于12,避免误判 MM/DD/YYYY
        );
        // 6. 修正 US 风格日期 (MM/DD/YYYY 或 MM.DD.YYYY) -> YYYY-MM-DD
        // 添加检查 d.y > 12 确保年份部分确实是年份
        text = ohc.dateutil.regex(text,
            new RegExp(paramPrefix + '@MM[./]@DD[./]@YYYY', 'gi'),
            "$1@YYYY-@MM-@DD",
            function (d) { return d.y > 12; } // 确保年份大于12
        );
        // 7. 处理维基百科特有的 Retrieved/Accessed 格式
        text = ohc.dateutil.regex(text,
             /(?:Retrieved|Accessed)[ ]*(?:on |)@Day @Month,? @YYYY/gi,
             "Retrieved @YYYY-@MM-@DD"
        );
         text = ohc.dateutil.regex(text,
             /(?:Retrieved|Accessed)[ ]*(?:on |)@Month @Day,? @YYYY/gi,
             "Retrieved @YYYY-@MM-@DD"
        );
        // 8. 移除 df 参数 (由用户配置决定)
        if (config.removeDfParam) {
             text = text.replace(/\|\s*df\s*=\s*[\w-]*(?=[\s]*[|}])/gi, '');
        }

        return text;
    }

    // --- 主执行函数 ---
    function autoFixDates() {
        // 检查命名空间 (使用 config)
        if (mw.config.get('wgNamespaceNumber') !== config.namespace) return;

        const portletLink = mw.util.addPortletLink(
            'p-cactions',
            '#',
            '修正日期',
            'ca-fix-dates',
            '自动修正模板参数中的日期格式'
        );

        $(portletLink).click(async (e) => {
            e.preventDefault();

            try {
                const api = new mw.Api();
                const pageContent = await api.get({
                    action: 'query',
                    titles: mw.config.get('wgPageName'),
                    prop: 'revisions',
                    rvprop: 'content',
                    rvslots: 'main',
                    formatversion: 2
                }).then(res => res.query.pages[0].revisions[0].slots.main.content);

                const newText = enhancedDateFix(pageContent);

                if (newText === pageContent) {
                    mw.notify('未发现需要修正的日期格式', { type: 'info' });
                    return;
                }

                // --- 动态生成编辑摘要 ---
                let summary = `使用${config.scriptName} v${config.version}${config.baseSummary}`; // 基础摘要
                if (hasUserConfig) {
                    const configDetails = [];
                    // 只显示被用户实际覆盖的配置项及其最终值
                    if (overriddenKeys.includes('processChineseDates')) {
                        configDetails.push(`${config.processChineseDates ? '处理中文日期' : '忽略中文日期'}`);
                    }
                    if (overriddenKeys.includes('removeDfParam')) {
                        configDetails.push(`${config.removeDfParam ? '移除df' : '保留df'}`);
                    }
                    // 可以根据需要添加其他被覆盖项的显示逻辑
                    if (overriddenKeys.includes('targetParams')) {
                         configDetails.push(`自定义参数`);
                    }
                     if (overriddenKeys.includes('minorEdit')) {
                         configDetails.push(`${config.minorEdit ? '小编辑' : '非小编辑'}`);
                    }
                     if (overriddenKeys.includes('namespace')) {
                         configDetails.push(`命名空间=${config.namespace}`);
                    }

                    if (configDetails.length > 0) {
                         summary += `(配置:${configDetails.join(',')})`;
                    }
                }
                // --- 编辑摘要生成结束 ---


                await api.postWithEditToken({
                    action: 'edit',
                    title: mw.config.get('wgPageName'),
                    text: newText,
                    summary: summary, // 使用动态生成的摘要
                    minor: config.minorEdit // 使用最终的 config
                });

                // 强制刷新页面以应用更改并清除缓存
                window.location.reload(true);
                mw.notify('日期格式修正完成', { type: 'success' });

            } catch (error) {
                mw.notify('日期修正失败: ' + error.message, { type: 'error' });
            }
        });
    }

    // 加载依赖
    mw.loader.using(['mediawiki.util', 'mediawiki.api']).then(() => {
        if (typeof ohc === 'undefined' || !ohc.dateutil) {
            mw.loader.load('//en.wikipedia.org/w/index.php?title=User:Ohconfucius/script/MOSNUM_utils.js&action=raw&ctype=text/javascript');
        }
        autoFixDates();
    });

})();
// </nowiki>