User:PexEric/dates.js
外观
注意:保存之后,你必须清除浏览器缓存才能看到做出的更改。Google Chrome、Firefox、Microsoft Edge及Safari:按住⇧ 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>