User:Heihaheihaha-test/test2.js
外观
注意:保存之后,你必须清除浏览器缓存才能看到做出的更改。Google Chrome、Firefox、Microsoft Edge及Safari:按住⇧ Shift键并单击工具栏的“刷新”按钮。参阅Help:绕过浏览器缓存以获取更多帮助。
// ==UserScript==
// @name 维基百科AI巡查助手 (Gemini)
// @namespace http://tampermonkey.net/
// @version 2.0
// @description 利用Gemini AI辅助维基百科巡查员分析新页面,识别问题并提供处理建议。
// @author (Your Name) & Gemini
// @match https://zh.wikipedia.org/wiki/*
// @grant GM_addStyle
// @grant GM_getValue
// @grant GM_setValue
// @connect generativelanguage.googleapis.com
// @updateURL https://.../your-script.user.js // Optional: Add your script's update URL
// @downloadURL https://.../your-script.user.js // Optional: Add your script's download URL
// ==/UserScript==
(function() {
'use strict';
// --- 配置 ---
const SCRIPT_ID_PREFIX = 'wpAiPatrolHelperGemini_';
const WIKIPEDIA_ARTICLE_URL_REGEX = /^https:\/\/zh\.wikipedia\.org\/wiki\/[^:]+$/;
const MAIN_CONTENT_SELECTOR = '#mw-content-text .mw-parser-output';
const SELECTORS_TO_REMOVE_FROM_CONTENT = [
'.toc', '.mw-editsection', '.navbox', '#catlinks', '.noprint',
'#coordinates', 'table.ambox', '.gallery', 'figure.mw-halign-right',
'figure.mw-halign-left', 'figure.mw-halign-center', 'div.thumb',
'table.infobox', '.wikitable.plainlinks.metadata.ambox.ambox-style',
'.mw-stack.selflink', 'div.printfooter', 'div.mw-hidden-catlinks'
];
const MAX_ARTICLE_TEXT_LENGTH = 30000; // 限制发送给API的文本长度
// --- 全局变量 ---
let actionButton = null;
let resultDialog = null;
let isLoading = false;
let aiConfig = null;
// --- 样式 ---
const SCRIPT_CSS = `
#${SCRIPT_ID_PREFIX}actionButton {
padding: 5px 10px; font-size: 0.85em; background-color: #008080; color: white;
border: 1px solid #006666; border-radius: 4px; cursor: pointer; margin-left: 8px;
line-height: normal;
}
#${SCRIPT_ID_PREFIX}actionButton:hover { background-color: #006666; }
#${SCRIPT_ID_PREFIX}actionButton:disabled { background-color: #cccccc; cursor: not-allowed; }
/* 在左侧“工具”栏中的样式 */
#p-tb #${SCRIPT_ID_PREFIX}actionButton {
all: unset;
color: #0645ad;
cursor: pointer;
font-size: inherit;
}
#p-tb #${SCRIPT_ID_PREFIX}actionButton:hover {
text-decoration: underline;
}
#p-tb #${SCRIPT_ID_PREFIX}actionButton:disabled {
color: #a2a9b1;
cursor: not-allowed;
text-decoration: none;
}
#${SCRIPT_ID_PREFIX}resultDialog {
position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%);
width: 800px; max-width: 95vw; max-height: 85vh;
background-color: #fdfdfd; border: 1px solid #bdc3c7;
box-shadow: 0 5px 15px rgba(0,0,0,0.3); z-index: 2000;
display: none; border-radius: 6px; overflow: hidden;
flex-direction: column; font-size: 14px;
}
#${SCRIPT_ID_PREFIX}resultDialog .dialog-header {
padding: 12px 18px; background-color: #e0e7e7; border-bottom: 1px solid #c8d0d0;
display: flex; justify-content: space-between; align-items: center; cursor: grab;
}
#${SCRIPT_ID_PREFIX}resultDialog .dialog-header h3 {
margin: 0; font-size: 1.3em; color: #205050;
}
#${SCRIPT_ID_PREFIX}resultDialog .dialog-close-btn {
background: none; border: none; font-size: 2em; font-weight: bold;
color: #507070; cursor: pointer; padding: 0 8px; line-height: 1;
}
#${SCRIPT_ID_PREFIX}resultDialog .dialog-close-btn:hover { color: #205050; }
#${SCRIPT_ID_PREFIX}resultDialog .dialog-content {
padding: 15px 20px; overflow-y: auto; line-height: 1.65; color: #333;
flex-grow: 1; background-color: #fff;
}
#${SCRIPT_ID_PREFIX}resultDialog .dialog-content pre {
white-space: pre-wrap; word-wrap: break-word; background-color: #f0f0f0;
border: 1px solid #e0e0e0; padding: 10px 12px; border-radius: 4px;
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
font-size: 0.9em; max-height: 400px; overflow-y: auto;
}
#${SCRIPT_ID_PREFIX}resultDialog .dialog-content code {
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
background-color: #f0f0f0; padding: 0.15em 0.4em; border-radius: 3px; font-size: 0.9em;
}
#${SCRIPT_ID_PREFIX}resultDialog .dialog-content pre code {
background-color: transparent; padding: 0; font-size: inherit;
}
#${SCRIPT_ID_PREFIX}resultDialog .dialog-content h1, #${SCRIPT_ID_PREFIX}resultDialog .dialog-content h2,
#${SCRIPT_ID_PREFIX}resultDialog .dialog-content h3, #${SCRIPT_ID_PREFIX}resultDialog .dialog-content h4 {
margin-top: 1.2em; margin-bottom: 0.6em; color: #1a4040; line-height: 1.3;
padding-bottom: 0.1em; border-bottom: 1px solid #e0e7e7;
}
#${SCRIPT_ID_PREFIX}resultDialog .dialog-content h1 { font-size: 1.7em; }
#${SCRIPT_ID_PREFIX}resultDialog .dialog-content h2 { font-size: 1.5em; }
#${SCRIPT_ID_PREFIX}resultDialog .dialog-content h3 { font-size: 1.3em; }
#${SCRIPT_ID_PREFIX}resultDialog .dialog-content ul, #${SCRIPT_ID_PREFIX}resultDialog .dialog-content ol {
padding-left: 25px; margin-bottom: 1em;
}
#${SCRIPT_ID_PREFIX}resultDialog .dialog-content p { margin-bottom: 1em; }
#${SCRIPT_ID_PREFIX}resultDialog .dialog-content strong { font-weight: bold; }
#${SCRIPT_ID_PREFIX}resultDialog .dialog-content table {
border-collapse: collapse; margin: 1.2em 0; width: 100%;
border: 1px solid #c8d0d0; box-shadow: 0 1px 2px rgba(0,0,0,0.05);
font-size: 0.95em;
}
#${SCRIPT_ID_PREFIX}resultDialog .dialog-content th,
#${SCRIPT_ID_PREFIX}resultDialog .dialog-content td {
border: 1px solid #d8e0e0; padding: 8px 12px; text-align: left;
}
#${SCRIPT_ID_PREFIX}resultDialog .dialog-content th {
background-color: #eaf3f3; font-weight: bold; color: #205050;
}
#${SCRIPT_ID_PREFIX}resultDialog .dialog-content tr:nth-child(even) td {
background-color: #f8fbfb;
}
#${SCRIPT_ID_PREFIX}configWarning {
background-color: #fff3cd; color: #856404; padding: 10px;
border: 1px solid #ffeeba; border-radius: 4px; margin: 10px 0;
text-align: center; font-size: 0.9em;
}
`;
/**
* 将CSS注入页面
*/
function injectStyles() {
if (typeof GM_addStyle !== 'undefined') {
GM_addStyle(SCRIPT_CSS);
} else {
const styleElement = document.createElement('style');
styleElement.id = `${SCRIPT_ID_PREFIX}styles`;
styleElement.textContent = SCRIPT_CSS;
document.head.appendChild(styleElement);
}
}
/**
* 加载并验证AI配置
*/
function loadAiConfig() {
try {
const storedConfig = localStorage.getItem('wpAiPatrolHelperGeminiConfig');
if (storedConfig) {
aiConfig = JSON.parse(storedConfig);
} else if (typeof GM_getValue !== 'undefined') {
const gmStoredConfig = GM_getValue('wpAiPatrolHelperGeminiConfig');
if (gmStoredConfig) aiConfig = JSON.parse(gmStoredConfig);
}
if (!aiConfig || !aiConfig.apiKey || !aiConfig.modelName) {
displayConfigWarning();
return false;
}
const warningDiv = document.getElementById(`${SCRIPT_ID_PREFIX}configWarning`);
if (warningDiv) warningDiv.style.display = 'none';
return true;
} catch (e) {
displayConfigWarning('加载Gemini AI配置时出错。');
console.error("Error loading AI config:", e);
return false;
}
}
/**
* 显示配置缺失的警告信息
*/
function displayConfigWarning(specificMessage = '') {
let warningDiv = document.getElementById(`${SCRIPT_ID_PREFIX}configWarning`);
if (!warningDiv) {
warningDiv = document.createElement('div');
warningDiv.id = `${SCRIPT_ID_PREFIX}configWarning`;
const firstHeading = document.getElementById('firstHeading');
if (firstHeading) {
firstHeading.parentNode.insertBefore(warningDiv, firstHeading.nextSibling);
} else {
const contentDiv = document.getElementById('content');
if (contentDiv) contentDiv.prepend(warningDiv);
}
}
const generalMessage = 'AI巡查助手(Gemini)配置不完整或缺失。请在浏览器开发者控制台 (F12) 中运行指令来设置API密钥及模型名称。详情请参考脚本的安装说明。';
warningDiv.textContent = generalMessage + (specificMessage ? ` (${specificMessage})` : '');
warningDiv.style.display = 'block';
console.info("To configure AI Patrol Helper (Gemini), run the following in your browser's developer console on any zh.wikipedia.org page:\n" +
"localStorage.setItem('wpAiPatrolHelperGeminiConfig', JSON.stringify({\n" +
" apiKey: 'YOUR_GEMINI_API_KEY_HERE',\n" +
" modelName: 'gemini-1.5-flash-latest' \n" +
"}));\n" +
"Then refresh the page.");
}
/**
* 检查当前是否为有效的中文维基百科条目页面
*/
function isChineseWikipediaArticlePage() {
return WIKIPEDIA_ARTICLE_URL_REGEX.test(window.location.href) &&
document.querySelector(MAIN_CONTENT_SELECTOR) &&
!document.getElementById('noarticletext');
}
/**
* 提取并清理条目正文内容
*/
function getArticleContentText() {
const contentElement = document.querySelector(MAIN_CONTENT_SELECTOR);
if (!contentElement) return null;
const clonedContent = contentElement.cloneNode(true);
SELECTORS_TO_REMOVE_FROM_CONTENT.forEach(selector => {
clonedContent.querySelectorAll(selector).forEach(el => el.remove());
});
// 优先使用结构化文本提取,以保留段落
let text = "";
clonedContent.querySelectorAll('p, h1, h2, h3, h4, h5, h6, li, pre, blockquote, dl, dd, dt').forEach(el => {
const trimmedText = (el.innerText || el.textContent || "").trim();
if (trimmedText) {
text += trimmedText + "\n\n";
}
});
// 如果结构化提取失败,使用纯文本
if (!text.trim()) {
text = (clonedContent.innerText || clonedContent.textContent || "").trim();
}
text = text.replace(/\[编辑\]/g, '').replace(/\[\d+\]/g, '').replace(/\n\s*\n/g, '\n\n').trim();
return text.length > MAX_ARTICLE_TEXT_LENGTH ? text.substring(0, MAX_ARTICLE_TEXT_LENGTH) + "\n\n[条目内容过长,已被截断]" : text;
}
/**
* 显示或隐藏加载状态
*/
function showLoadingState(show) {
isLoading = show;
if (actionButton) {
actionButton.textContent = show ? '处理中...' : 'AI巡查助手 (Gemini)';
actionButton.disabled = show;
}
if (show && !resultDialog) {
createResultDialog();
}
if (resultDialog) {
const contentDiv = resultDialog.querySelector(`#${SCRIPT_ID_PREFIX}resultDialog .dialog-content`);
contentDiv.innerHTML = show ? '<p style="text-align:center; padding: 20px;"><i>AI分析中,请稍候...</i></p>' : '';
if (show) resultDialog.style.display = 'flex';
}
}
/**
* 将Markdown格式的AI响应转换为HTML
*/
function escapeHtml(unsafeStr) {
if (typeof unsafeStr !== 'string') return '';
return unsafeStr.replace(/[&<>"']/g, match => ({
'&': '&', '<': '<', '>': '>', '"': '"', "'": '''
}[match]));
}
function processInlineMarkdown(text) {
text = escapeHtml(text);
text = text.replace(/\*\*(.*?)\*\*|__(.*?)__/g, '<strong>$1$2</strong>'); // Bold
text = text.replace(/(?<!\*)\*(?!\s)(.*?[^\s])\*(?!\*)|_(.*?)_/g, '<em>$1$2</em>'); // Italic
text = text.replace(/`([^`]+)`/g, '<code>$1</code>'); // Inline code
return text;
}
function parseMarkdownTableRow(rowLine) {
const trimmed = rowLine.trim();
if (trimmed.startsWith('|') && trimmed.endsWith('|')) {
return trimmed.slice(1, -1).split('|').map(cell => cell.trim());
}
return trimmed.split('|').map(cell => cell.trim());
}
function basicMarkdownToHtml(md) {
let html = '';
const lines = md.split('\n');
let inListType = null; // 'ul' or 'ol'
let inTable = false;
function closeOpenTags() {
if (inListType) {
html += (inListType === 'ul' ? '</ul>\n' : '</ol>\n');
inListType = null;
}
if (inTable) {
html += '</tbody></table>\n';
inTable = false;
}
}
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
// Headings
const headingMatch = line.match(/^(#{1,4})\s+(.*)/);
if (headingMatch) {
closeOpenTags();
const level = headingMatch[1].length;
html += `<h${level}>${processInlineMarkdown(headingMatch[2])}</h${level}>\n`;
continue;
}
// Table
const tableRowMatch = line.match(/^\|.*\|$/);
if (tableRowMatch) {
// Check for separator line to start a table
const nextLine = lines[i + 1] || '';
if (nextLine.match(/^\|(?:\s*:?-+:?\s*\|)+$/)) {
closeOpenTags();
inTable = true;
const headers = parseMarkdownTableRow(line);
html += '<table>\n<thead>\n<tr>\n';
headers.forEach(header => {
html += `<th>${processInlineMarkdown(header)}</th>\n`;
});
html += '</tr>\n</thead>\n<tbody>\n';
i++; // Skip separator line
continue;
}
// If already in a table, process as a row
if (inTable) {
const cells = parseMarkdownTableRow(line);
html += '<tr>\n';
cells.forEach(cell => {
html += `<td>${processInlineMarkdown(cell)}</td>\n`;
});
html += '</tr>\n';
continue;
}
}
// If line is not a table row, but we were in a table, close it.
if (inTable && !tableRowMatch) {
html += '</tbody></table>\n';
inTable = false;
}
// Lists
const ulMatch = line.match(/^\s*[-*+]\s+(.*)/);
const olMatch = line.match(/^\s*\d+\.\s+(.*)/);
if (ulMatch) {
if (inListType !== 'ul') { closeOpenTags(); html += '<ul>\n'; inListType = 'ul'; }
html += `<li>${processInlineMarkdown(ulMatch[1])}</li>\n`;
continue;
}
if (olMatch) {
if (inListType !== 'ol') { closeOpenTags(); html += '<ol>\n'; inListType = 'ol'; }
html += `<li>${processInlineMarkdown(olMatch[1])}</li>\n`;
continue;
}
// If it's not a list item, but we were in a list, close it
if (inListType && !ulMatch && !olMatch) {
closeOpenTags();
}
// Paragraphs
if (line.trim()) {
closeOpenTags(); // A paragraph breaks any open blocks
html += `<p>${processInlineMarkdown(line)}</p>\n`;
}
}
closeOpenTags(); // Close any remaining open tags at the end
return html;
}
/**
* 显示分析结果或错误信息
*/
function displayAnalysisResult(analysisText, isError = false) {
showLoadingState(false);
if (!resultDialog) createResultDialog();
const contentDiv = resultDialog.querySelector(`#${SCRIPT_ID_PREFIX}resultDialog .dialog-content`);
if (isError) {
contentDiv.innerHTML = `<p style="color: red; font-weight: bold;">处理出错:</p><pre>${escapeHtml(analysisText)}</pre>`;
} else {
contentDiv.innerHTML = basicMarkdownToHtml(analysisText);
}
resultDialog.style.display = 'flex';
}
/**
* 调用Gemini API
*/
async function makeAiApiCall(prompt) {
if (!aiConfig) throw new Error("Gemini AI配置未加载。");
const endpointUrl = `https://generativelanguage.googleapis.com/v1beta/models/${aiConfig.modelName}:generateContent?key=${aiConfig.apiKey}`;
const requestBody = {
contents: [{ role: "user", parts: [{ text: prompt }] }],
generationConfig: {
"maxOutputTokens": 8192,
"temperature": 0.4, // Lower temperature for more consistent, factual responses
},
};
try {
const response = await fetch(endpointUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(requestBody)
});
const data = await response.json();
if (!response.ok) {
const errorMsg = data?.error?.message || response.statusText || `HTTP Error ${response.status}`;
throw new Error(`Gemini API调用失败: ${errorMsg}`);
}
if (data.candidates && data.candidates[0]?.content?.parts) {
return data.candidates[0].content.parts.map(part => part.text).join("\n");
}
if (data.promptFeedback?.blockReason) {
throw new Error(`请求被安全设置阻止 (Gemini): ${data.promptFeedback.blockReason}. ${data.promptFeedback.blockReasonMessage || ''}`);
}
throw new Error('未能从Gemini API获取有效回复。请检查控制台的API响应详情。');
} catch (error) {
console.error("API Call Error:", error);
throw error;
}
}
/**
* 处理“AI巡查助手”按钮点击事件
*/
async function handlePatrolCheckAction() {
if (isLoading) return;
if (!loadAiConfig()) {
displayAnalysisResult("无法执行操作:AI配置不正确或缺失。请检查浏览器控制台中的设置说明。", true);
return;
}
const articleText = getArticleContentText();
const articleTitle = (document.querySelector('#firstHeading .mw-page-title-main') || document.querySelector('#firstHeading') || {}).innerText || document.title.replace(' - 维基百科,自由的百科全书', '');
if (!articleText) {
displayAnalysisResult("无法提取条目内容进行分析。", true);
return;
}
showLoadingState(true);
const patrolPrompt = `
你是一位经验丰富、认真负责的中文维基百科巡查员。你的任务是基于新页面巡查的常见标准,分析一个新创建的条目,并向人类巡查员提供清晰、可行的处理建议。
请严格按照以下结构,以Markdown格式输出你的分析报告:
### 1. 总体评估
(在这里用一两句话简要概括条目的整体状况、主题和主要问题。)
### 2. 问题分析与处理建议
(以表格形式呈现。如果某个标准没有发现显著问题,可以不在此列出或简单说明“基本符合要求”。)
| 问题类型 | 分析与说明 | 建议操作 |
| --- | --- | --- |
| **知名度 (Notability)** | (评估主题是否符合通用关注度指引。是否有迹象表明其关注度不足?例如,主题是否仅为地方性、缺乏深度报道等。) | (如果关注度存疑,建议添加 \`{{Notability|||||time=2025-06-10T16:04:00+00:00}}\` 并提报存废讨论。如果明显不符,可建议快速删除,并给出合适的速删理由,如 G11。) |
| **来源 (Sourcing)** | (评估条目是否提供了参考文献。参考文献的质量如何?是可靠来源吗?关键事实是否有引用支持?) | (如果完全没有来源,建议添加 \`{{Unreferenced|time=2025-06-10T16:04:00+00:00}}\`。如果来源不足,建议 \`{{Refimprove|time=2025-06-10T16:04:00+00:00}}\`。) |
| **中立性与语调 (NPOV & Tone)** | (评估条目的语调是否中立、客观。是否存在宣传、广告、粉丝网站或原创研究的语气?) | (如果像爱好者网站,建议添加 \`{{fansite}}\`。如果含宣传语调,可建议 \`{{Cleanup|reason=|time=2025-06-10T16:04:00+00:00}}\` 或速删 G11。) |
| **内容质量与格式** | (评估内容是否为极短的小小作品、劣质翻译、非中文内容,或格式混乱需要维基化。) | (小于50字建议 \`{{Substub|time=2025-06-10T16:04:00+00:00}}\`。机器翻译建议 \`{{RoughTranslation}}\`。非中文内容建议 \`{{NotMandarin|time=2025-06-10T16:04:00+00:00}}\`。格式问题建议 \`{{Wikify|time=2025-06-10T16:04:00+00:00}}\`。) |
| **版权 (Copyright)** | (根据文本内容和行文风格,初步判断是否存在直接复制粘贴的可能。注意:这只是初步怀疑,无法定论。) | (如果高度怀疑,建议巡查员手动使用工具检查。可提示:“文本风格疑似直接复制自……,建议使用查重工具进行核对。”) |
### 3. 最终建议
(根据以上分析,给出一个明确的最终操作建议。例如:“**综合建议:悬挂知名度模板,并提报页面存废讨论。**” 或 “**综合建议:条目基本合格,添加维基化和来源请求模板后可巡查通过。**” 或 “**综合建议:符合快速删除标准G11,建议立即提报速删。**”)
---
现在,请分析以下维基百科条目:
**条目名称**:“${articleTitle}”
**条目内容**(可能已截断):
\`\`\`
${articleText}
\`\`\`
`;
try {
const analysis = await makeAiApiCall(patrolPrompt);
displayAnalysisResult(analysis);
} catch (error) {
displayAnalysisResult(error.message, true);
}
}
/**
* 创建操作按钮并放置到页面上
*/
function createActionButton() {
if (document.getElementById(`${SCRIPT_ID_PREFIX}actionButton`)) return;
actionButton = document.createElement('button');
actionButton.textContent = 'AI巡查助手 (Gemini)';
actionButton.id = `${SCRIPT_ID_PREFIX}actionButton`;
actionButton.title = '使用Gemini AI辅助分析条目质量并提供巡查建议';
actionButton.addEventListener('click', handlePatrolCheckAction);
const toolbarSelectors = [
'#p-tb ul', // [优先] Vector皮肤的“工具”栏
'#p-views ul', // Vector皮肤的顶部标签栏
'.vector-feature-page-tools .vector-menu-content ul',// Vector-2022皮肤的“工具”下拉菜单
'#p-cactions .vector-menu-content ul' // 旧版Vector皮肤的“更多”下拉菜单
];
let targetToolbar = toolbarSelectors.map(s => document.querySelector(s)).find(el => el);
if (targetToolbar) {
const newListItem = document.createElement('li');
newListItem.id = `t-aipatrol`; // 为项目设置ID
newListItem.appendChild(actionButton);
targetToolbar.appendChild(newListItem);
} else {
// 如果找不到工具栏,则作为悬浮按钮
actionButton.style.position = 'fixed';
actionButton.style.top = '100px';
actionButton.style.right = '20px';
actionButton.style.zIndex = '1500';
document.body.appendChild(actionButton);
console.warn("Could not find a standard Wikipedia toolbar. Falling back to a fixed button.");
}
}
/**
* 创建用于显示结果的对话框
*/
function createResultDialog() {
if (document.getElementById(`${SCRIPT_ID_PREFIX}resultDialog`)) return;
resultDialog = document.createElement('div');
resultDialog.id = `${SCRIPT_ID_PREFIX}resultDialog`;
resultDialog.style.display = 'flex';
resultDialog.innerHTML = `
<div class="dialog-header">
<h3>AI巡查助手 (Gemini)</h3>
<button class="dialog-close-btn" title="关闭">×</button>
</div>
<div class="dialog-content"></div>
`;
document.body.appendChild(resultDialog);
resultDialog.querySelector('.dialog-close-btn').addEventListener('click', () => {
resultDialog.style.display = 'none';
});
// 添加拖拽功能
const header = resultDialog.querySelector('.dialog-header');
let isDragging = false;
let currentX, currentY, initialX, initialY, xOffset = 0, yOffset = 0;
header.addEventListener('mousedown', e => {
if (e.target.classList.contains('dialog-close-btn')) return;
initialX = e.clientX - xOffset;
initialY = e.clientY - yOffset;
isDragging = true;
header.style.cursor = 'grabbing';
});
document.addEventListener('mousemove', e => {
if (isDragging) {
e.preventDefault();
currentX = e.clientX - initialX;
currentY = e.clientY - initialY;
xOffset = currentX;
yOffset = currentY;
resultDialog.style.transform = `translate(-50%, -50%) translate(${currentX}px, ${currentY}px)`;
}
});
document.addEventListener('mouseup', () => {
if (isDragging) {
isDragging = false;
header.style.cursor = 'grab';
}
});
}
/**
* 初始化脚本
*/
function initializeScript() {
if (mw && mw.config && mw.config.get('wgIsProbablyEditable') && isChineseWikipediaArticlePage()) {
injectStyles();
createActionButton();
// 首次加载时检查配置,但不阻塞页面
// 点击按钮时会再次进行严格检查
setTimeout(loadAiConfig, 1000);
}
}
// 等待MediaWiki核心模块加载完毕后执行
mw.loader.using(['mediawiki.util']).then(initializeScript);
})();