', {
text: '没有匹配选项',
class: 'bgm-dropdown-item',
css: { color: '#999', cursor: 'default' }
}).appendTo($dropdownContent);
}
};
// 将选项值插入到输入框
function insertOptionValue(inputElem, value) {
const text = inputElem.value;
const pos = inputElem.selectionStart;
const mode = inputElem.dataset.dropdownMode || 'append'; // 获取插入模式
const conn = inputElem.dataset.dropdownConnector || '、';
// 根据不同的插入模式处理
if (mode === 'replace') {
// 直接替换
inputElem.value = value;
} else if (mode === 'append') {
// 自动补全逻辑改进
if (text) {
const currentWord = text.slice(0, pos).toLowerCase();
if (value.toLowerCase().startsWith(currentWord)) {
// 如果当前输入是目标值的开头,直接替换整个值
inputElem.value = value + text.slice(pos);
inputElem.setSelectionRange(value.length, value.length);
inputElem.focus();
return;
}
// 处理分隔符和空格
const lastChar = text.slice(-1);
if (['、',',',',','+',' '].includes(lastChar)) {
// 如果最后一个字符是分隔符,直接添加新值
inputElem.value = text.trimRight() + value;
} else {
// 否则添加分隔符和新值
inputElem.value = text + conn + value;
}
} else {
// 如果输入框为空,直接设置值
inputElem.value = value;
}
}
inputElem.focus();
}
// 处理所有字段
const processAllFields = () => {
const $ = window.jQuery || window.$;
// 处理ID字段和对应的属性字段
$('input.inputtext.id').each(function() {
const $idInput = $(this);
const idValue = $idInput.val().trim();
const $propInput = $idInput.next('.inputtext.prop');
// 为空ID字段添加下拉菜单(如果配置了)
if (idValue === '' && config[''] && !$idInput.data('dropdownAdded')) {
createDropdown(this, config[''].options, config[''].mode);
}
// 为其他配置的字段添加下拉菜单
if ($propInput.length) {
Object.entries(config).forEach(([key, options]) => {
const keys = key.split(',').map(k => k.trim());
if (keys.includes(idValue) && !$propInput.data('dropdownAdded')) {
createDropdown($propInput[0], options.options, options.mode, options.connector);
}
});
}
});
};
// 处理动态添加的字段
const processDynamicField = (element) => {
const $ = window.jQuery || window.$;
const $element = $(element);
// 如果元素本身是输入框
if ($element.is('input.inputtext.id')) {
const $idInput = $element;
const idValue = $idInput.val().trim();
const $propInput = $idInput.next('.inputtext.prop');
// 空ID字段处理
if (idValue === '' && config['']) {
createDropdown($idInput[0], config[''].options, config[''].mode);
}
// 属性字段处理
if ($propInput.length) {
Object.entries(config).forEach(([key, options]) => {
const keys = key.split(',').map(k => k.trim());
if (keys.includes(idValue)) {
createDropdown($propInput[0], options.options, options.mode, options.connector);
}
});
}
}
// 如果元素是容器
else {
// 处理常规ID字段
$element.find('input.inputtext.id').each(function() {
const $idInput = $(this);
const idValue = $idInput.val().trim();
const $propInput = $idInput.next('.inputtext.prop');
// 空ID字段处理
if (idValue === '' && config['']) {
createDropdown($idInput[0], config[''].options, config[''].mode);
}
// 属性字段处理
if ($propInput.length) {
Object.entries(config).forEach(([key, options]) => {
const keys = key.split(',').map(k => k.trim());
if (keys.includes(idValue)) {
createDropdown($propInput[0], options.options, options.mode, options.connector);
}
});
}
});
}
};
// 初始化函数
const init = () => {
const $ = window.jQuery || window.$;
// 添加样式
// injectStyles(); // 已移除,按照要求不包含样式相关代码
// 添加设置按钮
addSettingsButton();
// 初始处理所有字段
$(document).ready(function() {
processAllFields();
// 监听动态添加的字段
$(document).on('DOMNodeInserted', function(e) {
const $target = $(e.target);
if ($target.find('input.inputtext.id').length || $target.is('input.inputtext.id')) {
setTimeout(() => processDynamicField(e.target), 100);
}
});
// 点击页面其他位置时隐藏所有下拉框
$(document).on('click', function(e) {
if (!$(e.target).closest('.bgm-input-wrapper').length && !$(e.target).closest('.bgm-config-modal').length) {
$('.bgm-dropdown-content').removeClass('bgm-dropdown-active');
}
});
});
// 监听添加新行的按钮点击事件
$(document).on('click', '.newbtn', function() {
setTimeout(processAllFields, 100);
});
// 处理现有字段ID值变化的情况
$(document).on('change', 'input.inputtext.id', function() {
const $idInput = $(this);
const idValue = $idInput.val().trim();
const $propInput = $idInput.next('.inputtext.prop');
// 若属性字段已有下拉菜单,需要移除
if ($propInput.data('dropdownAdded')) {
if ($propInput.next('.bgm-dropdown-content').length) {
$propInput.next('.bgm-dropdown-content').remove();
}
$propInput.data('dropdownAdded', false);
// 如果输入框被包装了,尝试解包
if ($propInput.parent().hasClass('bgm-input-wrapper')) {
$propInput.unwrap();
}
}
// 添加新的下拉菜单
if ($propInput.length) {
Object.entries(config).forEach(([key, options]) => {
const keys = key.split(',').map(k => k.trim());
if (keys.includes(idValue)) {
createDropdown($propInput[0], options.options, options.mode, options.connector);
}
});
}
});
};
// 执行初始化
init();
}
/* =============
单行本快捷创建
===============*/
function initBgmCreateSubject() {
// 在条目页面添加"新条目"按钮
function addCreateButton() {
const currentPath = location.pathname;
// 只有精确匹配 /subject/数字 时才继续
const matchSubject = currentPath.match(/^\/subject\/(\d+)$/);
if (!matchSubject) return; // 如果不匹配,直接退出函数
// 确保作品类型是"小说"或"漫画"
const genreSmall = document.querySelector('small.grey');
if (!genreSmall || !(genreSmall.textContent === '小说' || genreSmall.textContent === '漫画')) return;
// 查找导航栏,并避免重复添加按钮
const nav = document.querySelector(".subjectNav .navTabs, .navTabs");
if (!nav || nav.querySelector(".create-button")) return;
// 添加通知区域,确保在点击按钮前已准备好
addNotificationArea();
// 创建"新条目"按钮并插入导航栏
const createLi = document.createElement("li");
createLi.className = "create-button";
const subjectId = matchSubject[1];
createLi.innerHTML = `
新条目`;
// 按钮点击事件:拉取编辑页信息并跳转到创建页
createLi.querySelector("a").addEventListener("click", () => {
// 先显示通知:正在准备打开新页面
showNotification("已复制条目内容,正在打开新建页面...");
const editUrl = `https://bangumi.tv/subject/${subjectId}/edit`;
const title = document.querySelector('h1 a[property="v:itemreviewed"]')?.textContent?.trim();
GM_xmlhttpRequest({
method: "GET",
url: editUrl,
onload: function (response) {
const parser = new DOMParser();
const doc = parser.parseFromString(response.responseText, "text/html");
const textarea = doc.querySelector('#subject_summary');
if (textarea) {
const content = textarea.value;
const type = content.includes("Infobox animanga/Novel") ? "Novel" :
content.includes("Infobox animanga/Manga") ? "Manga" : "Unknown";
// 如果无法识别类型则提示
if (type === "Unknown") {
alert("未识别 Infobox 类型(支持 Novel 或 Manga)");
return;
}
// 使用 localStorage 存储数据,并添加 subjectId 作为标识
const keyPrefix = `infobox_${subjectId}`;
localStorage.setItem(`${keyPrefix}_content`, content);
localStorage.setItem(`${keyPrefix}_type`, type);
localStorage.setItem(`${keyPrefix}_title`, title || '');
// 在新标签页打开新建条目页面,并传递 subjectId 参数
window.open(`https://bgm.tv/new_subject/1?source=${subjectId}`, "_blank");
} else {
alert("未找到 Infobox 内容,请确认已登录并有权限访问编辑页。");
}
},
onerror: function () {
// 请求失败时提示
alert("请求失败,请检查网络或登录状态。");
}
});
});
nav.appendChild(createLi); // 将按钮添加到导航栏
}
// 自动填充新建条目的表单内容
function fillNewSubjectForm() {
// 获取 URL 中传递的 source 参数,即当前条目的 subjectId
function getQueryParam(param) {
const url = new URL(window.location.href);
return url.searchParams.get(param);
}
const sourceId = getQueryParam("source");
if (!sourceId) return; // 如果没有传递 sourceId,则不执行填充操作
// 确保通知区域已创建
addNotificationArea();
const keyPrefix = `infobox_${sourceId}`;
const content = localStorage.getItem(`${keyPrefix}_content`);
const type = localStorage.getItem(`${keyPrefix}_type`);
const originalTitle = localStorage.getItem(`${keyPrefix}_title`);
if (!content || !type) return; // 如果没有获取到 infobox 内容或类型,则不继续执行
// 定义类型与分类选项的映射
const typeMap = {
"Novel": { id: "cat_novel", tpl: "Novel" },
"Manga": { id: "cat_comic", tpl: "Manga" }
};
const category = typeMap[type];
if (!category) return;
// 选择对应的分类单选框
const radioBtn = document.getElementById(category.id);
if (radioBtn) {
radioBtn.click();
}
// 新页面显示填充通知
showNotification("条目信息已复制,点击[Wiki模式]粘贴内容");
// 轮询检测表单是否加载完毕
const fillInterval = setInterval(() => {
const infobox = document.querySelector("#subject_infobox");
const titleInput = document.querySelector('input[name="subject_title"]');
const simpleModeLink = document.querySelector('a[onclick*="WCODEtoNormal"]');
// 当输入框加载完毕且可见,填充数据
if (infobox && titleInput && infobox.offsetParent !== null) {
infobox.value = content;
if (originalTitle) {
let newTitle = originalTitle;
const match = originalTitle.match(/\((\d+)\)$/);
if (match) {
const num = parseInt(match[1], 10) + 1;
newTitle = originalTitle.replace(/\(\d+\)$/, `(${num})`);
} else {
newTitle = `${originalTitle} (1)`;
}
titleInput.value = newTitle;
}
if (simpleModeLink) simpleModeLink.click(); // 切换回普通模式
clearInterval(fillInterval); // 停止轮询
// 填充完毕后删除 localStorage 中的数据,防止影响下次创建
localStorage.removeItem(`${keyPrefix}_content`);
localStorage.removeItem(`${keyPrefix}_type`);
localStorage.removeItem(`${keyPrefix}_title`);
}
}, 300); // 每 300ms 检查一次
}
// 从当前新建条目页面添加"复制创建"功能
function addCloneButton() {
// 确保当前页面是新建条目页面
if (!location.pathname.includes("/new_subject/")) return;
// 查找标题元素
const titleHeader = document.querySelector('h1');
if (!titleHeader || titleHeader.textContent !== '添加新书') return;
// 确保按钮未重复添加
if (document.querySelector('#clone-entry-button')) return;
// 添加通知区域
addNotificationArea();
// 创建按钮
const cloneButton = document.createElement('button');
cloneButton.id = 'clone-entry-button';
cloneButton.textContent = '新条目';
cloneButton.style.backgroundColor = '#F09199';
cloneButton.style.color = 'white';
cloneButton.style.border = 'none';
cloneButton.style.padding = '5px 10px';
cloneButton.style.borderRadius = '4px';
cloneButton.style.marginLeft = '10px';
cloneButton.style.cursor = 'pointer';
cloneButton.style.fontWeight = 'bold';
cloneButton.style.textAlign = 'center';
// 添加按钮到标题旁边
titleHeader.appendChild(cloneButton);
// 添加点击事件
cloneButton.addEventListener('click', () => {
// 获取当前表单内容
const infobox = document.querySelector("#subject_infobox");
const titleInput = document.querySelector('input[name="subject_title"]');
if (!infobox || !titleInput) {
alert("无法获取表单内容");
return;
}
const content = infobox.value;
const title = titleInput.value;
const type = content.includes("Infobox animanga/Novel") ? "Novel" :
content.includes("Infobox animanga/Manga") ? "Manga" : "Unknown";
if (type === "Unknown") {
alert("未识别 Infobox 类型(支持 Novel 或 Manga)");
return;
}
// 生成唯一ID作为存储键
const cloneId = 'clone_' + Date.now();
// 保存内容到 localStorage
localStorage.setItem(`infobox_${cloneId}_content`, content);
localStorage.setItem(`infobox_${cloneId}_type`, type);
localStorage.setItem(`infobox_${cloneId}_title`, title);
// 显示通知
showNotification("已复制条目内容,正在打开新建页面...");
// 打开新的条目创建页面
window.open(`https://bgm.tv/new_subject/1?source=${cloneId}`, "_blank");
});
}
// 添加通知区域
function addNotificationArea() {
// 检查是否已存在通知区域
if (document.querySelector('#bgm-notification-area')) return;
// 创建通知区域
const notificationArea = document.createElement('div');
notificationArea.id = 'bgm-notification-area';
notificationArea.style.position = 'fixed';
notificationArea.style.top = '10px';
notificationArea.style.right = '10px';
notificationArea.style.padding = '8px 15px';
notificationArea.style.backgroundColor = '#369CF8';
notificationArea.style.color = 'white';
notificationArea.style.borderRadius = '5px';
notificationArea.style.zIndex = '9999';
notificationArea.style.display = 'none';
document.body.appendChild(notificationArea);
}
// 显示通知
function showNotification(message) {
// 确保通知区域存在
if (!document.querySelector('#bgm-notification-area')) {
addNotificationArea();
}
const notificationArea = document.querySelector('#bgm-notification-area');
notificationArea.textContent = message;
notificationArea.style.display = 'block';
// 3秒后隐藏通知
setTimeout(() => {
notificationArea.style.display = 'none';
}, 3000);
// 如果支持GM通知,也显示一个
if (typeof GM_notification !== 'undefined') {
GM_notification({
title: 'Bangumi 条目创建助手',
text: message,
timeout: 3000
});
}
}
// 初始化
function init() {
// 若当前页面是条目页面,添加"新条目"按钮
if (location.pathname.match(/^\/subject\/\d+$/)) {
addCreateButton();
}
// 若当前页面是创建条目页,添加功能
if (location.pathname.includes("/new_subject/")) {
addCloneButton();
// 如果有source参数,则填充表单
if (location.search.includes("source=")) {
fillNewSubjectForm();
}
}
}
// 页面加载完成后执行初始化
window.addEventListener("load", init);
// 也可以在DOM加载完成后就执行,提高响应速度
if (document.readyState === "interactive" || document.readyState === "complete") {
init();
} else {
document.addEventListener("DOMContentLoaded", init);
}
}
/*===========
启动所有功能
============*/
function startEnhancer() {
initNavButtons();
observeURLChanges();
initCoverUpload();
initBatchRelation();
initBgmDropdownMenu();
initBgmCreateSubject();
console.log("Bangumi Ultimate Enhancer 已启动");
}
// 在DOM加载完成后启动脚本
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', startEnhancer);
} else {
startEnhancer();
}
})();