TierListMaker.js:修订间差异
来自卡厄思梦境WIKI
创建页面,内容为“(function() { 'use strict'; // 仅在 TierListMaker 页面运行 if (mw.config.get('wgPageName') !== '节奏榜') { return; } // 等待页面加载完成 $(function() { initTierListMaker(); }); function initTierListMaker() { // 添加控制按钮 addControlButtons(); // 初始化拖拽功能 initDragAndDrop(); // 添加样式 addCusto…” |
无编辑摘要 标签:已被回退 |
||
| 第21行: | 第21行: | ||
// 添加样式 | // 添加样式 | ||
addCustomStyles(); | addCustomStyles(); | ||
// 检查URL中是否有ID参数 | |||
checkAndLoadFromURL(); | |||
} | } | ||
| 第50行: | 第53行: | ||
}); | }); | ||
$buttonContainer.append($saveButton, ' ', $clearButton, ' ', $resetButton); | var $saveListButton = $('<button>') | ||
.text('保存榜单') | |||
.addClass('tier-list-save-list-btn') | |||
.click(saveTierListData); | |||
var $loadListButton = $('<button>') | |||
.text('加载榜单') | |||
.addClass('tier-list-load-list-btn') | |||
.click(showLoadDialog); | |||
var $shareButton = $('<button>') | |||
.text('分享榜单') | |||
.addClass('tier-list-share-btn') | |||
.click(shareTierList); | |||
$buttonContainer.append( | |||
$saveButton, ' ', | |||
$saveListButton, ' ', | |||
$loadListButton, ' ', | |||
$shareButton, ' ', | |||
$clearButton, ' ', | |||
$resetButton | |||
); | |||
$('.wikitable').before($buttonContainer); | $('.wikitable').before($buttonContainer); | ||
} | } | ||
| 第57行: | 第83行: | ||
var styles = ` | var styles = ` | ||
<style> | <style> | ||
.tier-list-save-btn, .tier-list-clear-btn, .tier-list-reset-btn { | .tier-list-save-btn, .tier-list-clear-btn, .tier-list-reset-btn, | ||
.tier-list-save-list-btn, .tier-list-load-list-btn, .tier-list-share-btn { | |||
padding: 8px 16px; | padding: 8px 16px; | ||
margin: 0 5px; | margin: 0 5px; | ||
| 第93行: | 第120行: | ||
.tier-list-reset-btn:hover { | .tier-list-reset-btn:hover { | ||
background: #0b7dda; | background: #0b7dda; | ||
} | |||
.tier-list-save-list-btn { | |||
background: #FF9800; | |||
color: white; | |||
} | |||
.tier-list-save-list-btn:hover { | |||
background: #e68900; | |||
} | |||
.tier-list-load-list-btn { | |||
background: #9C27B0; | |||
color: white; | |||
} | |||
.tier-list-load-list-btn:hover { | |||
background: #7B1FA2; | |||
} | |||
.tier-list-share-btn { | |||
background: #00BCD4; | |||
color: white; | |||
} | |||
.tier-list-share-btn:hover { | |||
background: #0097A7; | |||
} | } | ||
| 第145行: | 第199行: | ||
margin-bottom: 10px; | margin-bottom: 10px; | ||
color: #333; | color: #333; | ||
} | |||
.tier-dialog-overlay { | |||
position: fixed; | |||
top: 0; | |||
left: 0; | |||
right: 0; | |||
bottom: 0; | |||
background: rgba(0, 0, 0, 0.5); | |||
z-index: 9998; | |||
display: flex; | |||
align-items: center; | |||
justify-content: center; | |||
} | |||
.tier-dialog { | |||
background: white; | |||
padding: 30px; | |||
border-radius: 10px; | |||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3); | |||
max-width: 500px; | |||
width: 90%; | |||
z-index: 9999; | |||
} | |||
.tier-dialog h3 { | |||
margin-top: 0; | |||
margin-bottom: 20px; | |||
color: #333; | |||
} | |||
.tier-dialog label { | |||
display: block; | |||
margin-bottom: 8px; | |||
font-weight: bold; | |||
color: #555; | |||
} | |||
.tier-dialog input[type="text"] { | |||
width: 100%; | |||
padding: 10px; | |||
border: 2px solid #ddd; | |||
border-radius: 5px; | |||
font-size: 14px; | |||
box-sizing: border-box; | |||
margin-bottom: 15px; | |||
} | |||
.tier-dialog input[type="text"]:focus { | |||
outline: none; | |||
border-color: #2196F3; | |||
} | |||
.tier-dialog-buttons { | |||
display: flex; | |||
justify-content: flex-end; | |||
gap: 10px; | |||
margin-top: 20px; | |||
} | |||
.tier-dialog-btn { | |||
padding: 10px 20px; | |||
border: none; | |||
border-radius: 5px; | |||
font-size: 14px; | |||
font-weight: bold; | |||
cursor: pointer; | |||
transition: all 0.3s; | |||
} | |||
.tier-dialog-btn-primary { | |||
background: #2196F3; | |||
color: white; | |||
} | |||
.tier-dialog-btn-primary:hover { | |||
background: #0b7dda; | |||
} | |||
.tier-dialog-btn-secondary { | |||
background: #ddd; | |||
color: #333; | |||
} | |||
.tier-dialog-btn-secondary:hover { | |||
background: #ccc; | |||
} | |||
.tier-id-display { | |||
background: #f0f8ff; | |||
padding: 15px; | |||
border-radius: 5px; | |||
border: 2px solid #2196F3; | |||
margin: 15px 0; | |||
word-break: break-all; | |||
} | |||
.tier-id-label { | |||
font-weight: bold; | |||
color: #2196F3; | |||
margin-bottom: 5px; | |||
} | |||
.tier-id-value { | |||
font-family: 'Courier New', monospace; | |||
font-size: 16px; | |||
color: #333; | |||
user-select: all; | |||
} | |||
.tier-url-display { | |||
background: #f0f8ff; | |||
padding: 15px; | |||
border-radius: 5px; | |||
border: 2px solid #00BCD4; | |||
margin: 15px 0; | |||
word-break: break-all; | |||
} | |||
.copy-btn { | |||
background: #4CAF50; | |||
color: white; | |||
padding: 5px 15px; | |||
border: none; | |||
border-radius: 3px; | |||
cursor: pointer; | |||
font-size: 12px; | |||
margin-left: 10px; | |||
} | |||
.copy-btn:hover { | |||
background: #45a049; | |||
} | |||
.success-message { | |||
color: #4CAF50; | |||
font-weight: bold; | |||
margin-top: 10px; | |||
} | } | ||
</style> | </style> | ||
| 第248行: | 第440行: | ||
$('#avatar-pool').append($(this)); | $('#avatar-pool').append($(this)); | ||
}); | }); | ||
} | |||
// 保存榜单数据 | |||
function saveTierListData() { | |||
var tierData = collectTierData(); | |||
if (tierData.tiers.length === 0 && tierData.pool.length === $('.avatar-frame').length) { | |||
alert('您还没有放置任何角色到榜单中!'); | |||
return; | |||
} | |||
var listId = generateUniqueId(); | |||
var timestamp = new Date().toISOString(); | |||
var saveData = { | |||
id: listId, | |||
timestamp: timestamp, | |||
data: tierData | |||
}; | |||
// 保存到 localStorage | |||
localStorage.setItem('tierlist_' + listId, JSON.stringify(saveData)); | |||
// 显示保存成功对话框 | |||
showSaveSuccessDialog(listId); | |||
} | |||
// 收集榜单数据 | |||
function collectTierData() { | |||
var data = { | |||
tiers: [], | |||
pool: [] | |||
}; | |||
// 收集表格中的数据 | |||
$('.wikitable tr').each(function(rowIndex) { | |||
var $cells = $(this).find('td'); | |||
if ($cells.length > 0) { | |||
var tierName = $cells.eq(0).text().trim(); | |||
var avatars = []; | |||
$cells.eq(1).find('.avatar-frame').each(function() { | |||
var avatarId = getAvatarIdentifier($(this)); | |||
if (avatarId) { | |||
avatars.push(avatarId); | |||
} | |||
}); | |||
if (avatars.length > 0) { | |||
data.tiers.push({ | |||
name: tierName, | |||
avatars: avatars | |||
}); | |||
} | |||
} | |||
}); | |||
// 收集头像池中的数据 | |||
$('#avatar-pool .avatar-frame').each(function() { | |||
var avatarId = getAvatarIdentifier($(this)); | |||
if (avatarId) { | |||
data.pool.push(avatarId); | |||
} | |||
}); | |||
return data; | |||
} | |||
// 获取头像的唯一标识符 | |||
function getAvatarIdentifier($avatar) { | |||
// 尝试多种方式获取头像标识 | |||
var identifier = null; | |||
// 方法1: 通过图片src | |||
var $img = $avatar.find('img'); | |||
if ($img.length > 0) { | |||
identifier = $img.attr('src'); | |||
} | |||
// 方法2: 通过data属性 | |||
if (!identifier && $avatar.attr('data-avatar-id')) { | |||
identifier = $avatar.attr('data-avatar-id'); | |||
} | |||
// 方法3: 通过alt或title | |||
if (!identifier && $img.attr('alt')) { | |||
identifier = $img.attr('alt'); | |||
} | |||
// 方法4: 通过完整HTML(作为后备) | |||
if (!identifier) { | |||
identifier = $avatar.prop('outerHTML'); | |||
} | |||
return identifier; | |||
} | |||
// 生成唯一ID | |||
function generateUniqueId() { | |||
var timestamp = Date.now().toString(36); | |||
var randomStr = Math.random().toString(36).substr(2, 9); | |||
return timestamp + randomStr; | |||
} | |||
// 显示保存成功对话框 | |||
function showSaveSuccessDialog(listId) { | |||
var shareUrl = window.location.href.split('?')[0] + '?tierid=' + listId; | |||
var $overlay = $('<div>').addClass('tier-dialog-overlay'); | |||
var $dialog = $('<div>').addClass('tier-dialog'); | |||
var $title = $('<h3>').text('榜单保存成功!'); | |||
var $idDisplay = $('<div>').addClass('tier-id-display'); | |||
var $idLabel = $('<div>').addClass('tier-id-label').text('榜单ID:'); | |||
var $idValue = $('<div>').addClass('tier-id-value').text(listId); | |||
var $copyIdBtn = $('<button>').addClass('copy-btn').text('复制ID') | |||
.click(function() { | |||
copyToClipboard(listId); | |||
$(this).text('已复制!').css('background', '#4CAF50'); | |||
setTimeout(() => { | |||
$(this).text('复制ID').css('background', ''); | |||
}, 2000); | |||
}); | |||
$idDisplay.append($idLabel, $idValue, $copyIdBtn); | |||
var $urlDisplay = $('<div>').addClass('tier-url-display'); | |||
var $urlLabel = $('<div>').addClass('tier-id-label').text('分享链接:'); | |||
var $urlValue = $('<div>').addClass('tier-id-value').text(shareUrl); | |||
var $copyUrlBtn = $('<button>').addClass('copy-btn').text('复制链接') | |||
.click(function() { | |||
copyToClipboard(shareUrl); | |||
$(this).text('已复制!').css('background', '#4CAF50'); | |||
setTimeout(() => { | |||
$(this).text('复制链接').css('background', ''); | |||
}, 2000); | |||
}); | |||
$urlDisplay.append($urlLabel, $urlValue, $copyUrlBtn); | |||
var $info = $('<p>').css({'color': '#666', 'margin': '15px 0'}) | |||
.text('保存的榜单将在本地存储,您可以通过ID或链接访问。'); | |||
var $buttons = $('<div>').addClass('tier-dialog-buttons'); | |||
var $closeBtn = $('<button>') | |||
.addClass('tier-dialog-btn tier-dialog-btn-primary') | |||
.text('关闭') | |||
.click(function() { | |||
$overlay.remove(); | |||
}); | |||
$buttons.append($closeBtn); | |||
$dialog.append($title, $idDisplay, $urlDisplay, $info, $buttons); | |||
$overlay.append($dialog); | |||
$('body').append($overlay); | |||
} | |||
// 显示加载对话框 | |||
function showLoadDialog() { | |||
var $overlay = $('<div>').addClass('tier-dialog-overlay'); | |||
var $dialog = $('<div>').addClass('tier-dialog'); | |||
var $title = $('<h3>').text('加载榜单'); | |||
var $label = $('<label>').text('请输入榜单ID:'); | |||
var $input = $('<input>') | |||
.attr('type', 'text') | |||
.attr('placeholder', '输入榜单ID') | |||
.attr('id', 'tier-id-input'); | |||
var $errorMsg = $('<div>') | |||
.css({'color': '#f44336', 'margin-top': '10px', 'display': 'none'}) | |||
.attr('id', 'load-error-msg'); | |||
var $buttons = $('<div>').addClass('tier-dialog-buttons'); | |||
var $loadBtn = $('<button>') | |||
.addClass('tier-dialog-btn tier-dialog-btn-primary') | |||
.text('加载') | |||
.click(function() { | |||
var listId = $input.val().trim(); | |||
if (!listId) { | |||
$errorMsg.text('请输入榜单ID!').show(); | |||
return; | |||
} | |||
if (loadTierListData(listId)) { | |||
$overlay.remove(); | |||
} else { | |||
$errorMsg.text('未找到该榜单,请检查ID是否正确!').show(); | |||
} | |||
}); | |||
var $cancelBtn = $('<button>') | |||
.addClass('tier-dialog-btn tier-dialog-btn-secondary') | |||
.text('取消') | |||
.click(function() { | |||
$overlay.remove(); | |||
}); | |||
$buttons.append($cancelBtn, $loadBtn); | |||
$dialog.append($title, $label, $input, $errorMsg, $buttons); | |||
$overlay.append($dialog); | |||
$('body').append($overlay); | |||
// 聚焦输入框 | |||
setTimeout(() => $input.focus(), 100); | |||
// 支持回车键加载 | |||
$input.on('keypress', function(e) { | |||
if (e.which === 13) { | |||
$loadBtn.click(); | |||
} | |||
}); | |||
} | |||
// 加载榜单数据 | |||
function loadTierListData(listId) { | |||
var savedData = localStorage.getItem('tierlist_' + listId); | |||
if (!savedData) { | |||
return false; | |||
} | |||
try { | |||
var saveData = JSON.parse(savedData); | |||
applyTierData(saveData.data); | |||
// 显示加载成功提示 | |||
showNotification('榜单加载成功!', 'success'); | |||
return true; | |||
} catch (e) { | |||
console.error('加载榜单失败:', e); | |||
return false; | |||
} | |||
} | |||
// 应用榜单数据 | |||
function applyTierData(tierData) { | |||
// 首先清空所有层级 | |||
$('.wikitable td .avatar-frame').each(function() { | |||
$(this).removeClass('in-tier'); | |||
$('#avatar-pool').append($(this)); | |||
}); | |||
// 应用tier数据 | |||
tierData.tiers.forEach(function(tier) { | |||
var $targetCell = null; | |||
// 查找对应的tier单元格 | |||
$('.wikitable tr').each(function() { | |||
var $cells = $(this).find('td'); | |||
if ($cells.length > 0) { | |||
var tierName = $cells.eq(0).text().trim(); | |||
if (tierName === tier.name) { | |||
$targetCell = $cells.eq(1); | |||
return false; | |||
} | |||
} | |||
}); | |||
if ($targetCell) { | |||
tier.avatars.forEach(function(avatarId) { | |||
var $avatar = findAvatarByIdentifier(avatarId); | |||
if ($avatar) { | |||
$avatar.addClass('in-tier'); | |||
$targetCell.append($avatar); | |||
} | |||
}); | |||
} | |||
}); | |||
} | |||
// 根据标识符查找头像 | |||
function findAvatarByIdentifier(identifier) { | |||
var $found = null; | |||
$('.avatar-frame').each(function() { | |||
var $avatar = $(this); | |||
var currentId = getAvatarIdentifier($avatar); | |||
if (currentId === identifier) { | |||
$found = $avatar; | |||
return false; | |||
} | |||
}); | |||
return $found; | |||
} | |||
// 分享榜单 | |||
function shareTierList() { | |||
var tierData = collectTierData(); | |||
if (tierData.tiers.length === 0 && tierData.pool.length === $('.avatar-frame').length) { | |||
alert('您还没有放置任何角色到榜单中!'); | |||
return; | |||
} | |||
// 检查是否已经保存 | |||
var currentUrl = window.location.href; | |||
var urlParams = new URLSearchParams(window.location.search); | |||
var existingId = urlParams.get('tierid'); | |||
if (existingId) { | |||
// 已有ID,直接分享 | |||
var shareUrl = window.location.href.split('?')[0] + '?tierid=' + existingId; | |||
showShareDialog(shareUrl, existingId); | |||
} else { | |||
// 先保存再分享 | |||
var listId = generateUniqueId(); | |||
var timestamp = new Date().toISOString(); | |||
var saveData = { | |||
id: listId, | |||
timestamp: timestamp, | |||
data: tierData | |||
}; | |||
localStorage.setItem('tierlist_' + listId, JSON.stringify(saveData)); | |||
var shareUrl = window.location.href.split('?')[0] + '?tierid=' + listId; | |||
showShareDialog(shareUrl, listId); | |||
} | |||
} | |||
// 显示分享对话框 | |||
function showShareDialog(shareUrl, listId) { | |||
var $overlay = $('<div>').addClass('tier-dialog-overlay'); | |||
var $dialog = $('<div>').addClass('tier-dialog'); | |||
var $title = $('<h3>').text('分享榜单'); | |||
var $urlDisplay = $('<div>').addClass('tier-url-display'); | |||
var $urlLabel = $('<div>').addClass('tier-id-label').text('分享链接:'); | |||
var $urlValue = $('<div>').addClass('tier-id-value').text(shareUrl); | |||
var $copyUrlBtn = $('<button>').addClass('copy-btn').text('复制链接') | |||
.click(function() { | |||
copyToClipboard(shareUrl); | |||
$(this).text('已复制!').css('background', '#4CAF50'); | |||
setTimeout(() => { | |||
$(this).text('复制链接').css('background', ''); | |||
}, 2000); | |||
}); | |||
$urlDisplay.append($urlLabel, $urlValue, $copyUrlBtn); | |||
var $idDisplay = $('<div>').addClass('tier-id-display'); | |||
var $idLabel = $('<div>').addClass('tier-id-label').text('榜单ID:'); | |||
var $idValue = $('<div>').addClass('tier-id-value').text(listId); | |||
var $copyIdBtn = $('<button>').addClass('copy-btn').text('复制ID') | |||
.click(function() { | |||
copyToClipboard(listId); | |||
$(this).text('已复制!').css('background', '#4CAF50'); | |||
setTimeout(() => { | |||
$(this).text('复制ID').css('background', ''); | |||
}, 2000); | |||
}); | |||
$idDisplay.append($idLabel, $idValue, $copyIdBtn); | |||
var $info = $('<p>').css({'color': '#666', 'margin': '15px 0'}) | |||
.text('将此链接分享给其他人,他们可以查看您的榜单!'); | |||
var $buttons = $('<div>').addClass('tier-dialog-buttons'); | |||
var $closeBtn = $('<button>') | |||
.addClass('tier-dialog-btn tier-dialog-btn-primary') | |||
.text('关闭') | |||
.click(function() { | |||
$overlay.remove(); | |||
}); | |||
$buttons.append($closeBtn); | |||
$dialog.append($title, $urlDisplay, $idDisplay, $info, $buttons); | |||
$overlay.append($dialog); | |||
$('body').append($overlay); | |||
} | |||
// 检查URL并加载榜单 | |||
function checkAndLoadFromURL() { | |||
var urlParams = new URLSearchParams(window.location.search); | |||
var tierid = urlParams.get('tierid'); | |||
if (tierid) { | |||
setTimeout(function() { | |||
if (loadTierListData(tierid)) { | |||
showNotification('已加载分享的榜单!ID: ' + tierid, 'success'); | |||
} else { | |||
showNotification('无法加载榜单,ID可能无效或已过期', 'error'); | |||
} | |||
}, 500); | |||
} | |||
} | |||
// 复制到剪贴板 | |||
function copyToClipboard(text) { | |||
if (navigator.clipboard && navigator.clipboard.writeText) { | |||
navigator.clipboard.writeText(text); | |||
} else { | |||
// 后备方案 | |||
var $temp = $('<textarea>'); | |||
$('body').append($temp); | |||
$temp.val(text).select(); | |||
document.execCommand('copy'); | |||
$temp.remove(); | |||
} | |||
} | |||
// 显示通知 | |||
function showNotification(message, type) { | |||
var bgColor = type === 'success' ? '#4CAF50' : '#f44336'; | |||
var $notification = $('<div>') | |||
.css({ | |||
'position': 'fixed', | |||
'top': '20px', | |||
'right': '20px', | |||
'background': bgColor, | |||
'color': 'white', | |||
'padding': '15px 25px', | |||
'border-radius': '5px', | |||
'box-shadow': '0 4px 12px rgba(0,0,0,0.3)', | |||
'z-index': 10000, | |||
'font-size': '14px', | |||
'font-weight': 'bold', | |||
'animation': 'slideIn 0.3s ease-out' | |||
}) | |||
.text(message); | |||
$('body').append($notification); | |||
setTimeout(function() { | |||
$notification.fadeOut(300, function() { | |||
$(this).remove(); | |||
}); | |||
}, 3000); | |||
} | } | ||
2025年10月8日 (三) 12:39的版本
(function() {
'use strict';
// 仅在 TierListMaker 页面运行
if (mw.config.get('wgPageName') !== '节奏榜') {
return;
}
// 等待页面加载完成
$(function() {
initTierListMaker();
});
function initTierListMaker() {
// 添加控制按钮
addControlButtons();
// 初始化拖拽功能
initDragAndDrop();
// 添加样式
addCustomStyles();
// 检查URL中是否有ID参数
checkAndLoadFromURL();
}
function addControlButtons() {
var $buttonContainer = $('<div>')
.attr('id', 'tier-list-controls')
.css({
'margin': '10px 0',
'padding': '10px',
'background': '#f0f0f0',
'border-radius': '5px'
});
var $saveButton = $('<button>')
.text('保存为PNG')
.addClass('tier-list-save-btn')
.click(saveTierListAsPNG);
var $clearButton = $('<button>')
.text('清空所有')
.addClass('tier-list-clear-btn')
.click(clearAllTiers);
var $resetButton = $('<button>')
.text('重置')
.addClass('tier-list-reset-btn')
.click(function() {
location.reload();
});
var $saveListButton = $('<button>')
.text('保存榜单')
.addClass('tier-list-save-list-btn')
.click(saveTierListData);
var $loadListButton = $('<button>')
.text('加载榜单')
.addClass('tier-list-load-list-btn')
.click(showLoadDialog);
var $shareButton = $('<button>')
.text('分享榜单')
.addClass('tier-list-share-btn')
.click(shareTierList);
$buttonContainer.append(
$saveButton, ' ',
$saveListButton, ' ',
$loadListButton, ' ',
$shareButton, ' ',
$clearButton, ' ',
$resetButton
);
$('.wikitable').before($buttonContainer);
}
function addCustomStyles() {
var styles = `
<style>
.tier-list-save-btn, .tier-list-clear-btn, .tier-list-reset-btn,
.tier-list-save-list-btn, .tier-list-load-list-btn, .tier-list-share-btn {
padding: 8px 16px;
margin: 0 5px;
font-size: 14px;
font-weight: bold;
border: none;
border-radius: 4px;
cursor: pointer;
transition: all 0.3s;
}
.tier-list-save-btn {
background: #4CAF50;
color: white;
}
.tier-list-save-btn:hover {
background: #45a049;
}
.tier-list-clear-btn {
background: #f44336;
color: white;
}
.tier-list-clear-btn:hover {
background: #da190b;
}
.tier-list-reset-btn {
background: #2196F3;
color: white;
}
.tier-list-reset-btn:hover {
background: #0b7dda;
}
.tier-list-save-list-btn {
background: #FF9800;
color: white;
}
.tier-list-save-list-btn:hover {
background: #e68900;
}
.tier-list-load-list-btn {
background: #9C27B0;
color: white;
}
.tier-list-load-list-btn:hover {
background: #7B1FA2;
}
.tier-list-share-btn {
background: #00BCD4;
color: white;
}
.tier-list-share-btn:hover {
background: #0097A7;
}
.wikitable td {
min-height: 120px;
min-width: 300px;
padding: 10px;
vertical-align: top;
position: relative;
}
.tier-row-drop-zone {
border: 2px dashed transparent;
transition: all 0.3s;
}
.tier-row-drop-zone.drag-over {
border-color: #2196F3;
background-color: rgba(33, 150, 243, 0.1);
}
.avatar-frame {
cursor: move;
transition: transform 0.2s, opacity 0.2s;
user-select: none;
}
.avatar-frame:hover {
transform: scale(1.05);
}
.avatar-frame.dragging {
opacity: 0.5;
}
.avatar-frame.in-tier {
margin: 5px;
}
#avatar-pool {
border: 2px solid #ddd;
padding: 10px;
margin: 10px 0;
border-radius: 5px;
background: #fafafa;
min-height: 150px;
}
#avatar-pool-title {
font-size: 16px;
font-weight: bold;
margin-bottom: 10px;
color: #333;
}
.tier-dialog-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
z-index: 9998;
display: flex;
align-items: center;
justify-content: center;
}
.tier-dialog {
background: white;
padding: 30px;
border-radius: 10px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
max-width: 500px;
width: 90%;
z-index: 9999;
}
.tier-dialog h3 {
margin-top: 0;
margin-bottom: 20px;
color: #333;
}
.tier-dialog label {
display: block;
margin-bottom: 8px;
font-weight: bold;
color: #555;
}
.tier-dialog input[type="text"] {
width: 100%;
padding: 10px;
border: 2px solid #ddd;
border-radius: 5px;
font-size: 14px;
box-sizing: border-box;
margin-bottom: 15px;
}
.tier-dialog input[type="text"]:focus {
outline: none;
border-color: #2196F3;
}
.tier-dialog-buttons {
display: flex;
justify-content: flex-end;
gap: 10px;
margin-top: 20px;
}
.tier-dialog-btn {
padding: 10px 20px;
border: none;
border-radius: 5px;
font-size: 14px;
font-weight: bold;
cursor: pointer;
transition: all 0.3s;
}
.tier-dialog-btn-primary {
background: #2196F3;
color: white;
}
.tier-dialog-btn-primary:hover {
background: #0b7dda;
}
.tier-dialog-btn-secondary {
background: #ddd;
color: #333;
}
.tier-dialog-btn-secondary:hover {
background: #ccc;
}
.tier-id-display {
background: #f0f8ff;
padding: 15px;
border-radius: 5px;
border: 2px solid #2196F3;
margin: 15px 0;
word-break: break-all;
}
.tier-id-label {
font-weight: bold;
color: #2196F3;
margin-bottom: 5px;
}
.tier-id-value {
font-family: 'Courier New', monospace;
font-size: 16px;
color: #333;
user-select: all;
}
.tier-url-display {
background: #f0f8ff;
padding: 15px;
border-radius: 5px;
border: 2px solid #00BCD4;
margin: 15px 0;
word-break: break-all;
}
.copy-btn {
background: #4CAF50;
color: white;
padding: 5px 15px;
border: none;
border-radius: 3px;
cursor: pointer;
font-size: 12px;
margin-left: 10px;
}
.copy-btn:hover {
background: #45a049;
}
.success-message {
color: #4CAF50;
font-weight: bold;
margin-top: 10px;
}
</style>
`;
$('head').append(styles);
}
function initDragAndDrop() {
// 创建头像池容器
var $avatarPool = $('<div>')
.attr('id', 'avatar-pool')
.addClass('tier-row-drop-zone');
var $poolTitle = $('<div>')
.attr('id', 'avatar-pool-title')
.text('角色池(拖动到上方表格)');
$avatarPool.append($poolTitle);
// 将所有头像移动到头像池
var $avatars = $('.avatar-frame');
$avatars.each(function() {
$(this).addClass('avatar-item').appendTo($avatarPool);
});
$('.wikitable').after($avatarPool);
// 为表格单元格添加drop-zone类
$('.wikitable td').addClass('tier-row-drop-zone');
// 初始化所有头像的拖拽
initAvatarDrag();
// 初始化所有drop zone
initDropZones();
}
function initAvatarDrag() {
$('.avatar-frame').each(function() {
var $avatar = $(this);
$avatar.attr('draggable', 'true');
$avatar.on('dragstart', function(e) {
$(this).addClass('dragging');
e.originalEvent.dataTransfer.effectAllowed = 'move';
e.originalEvent.dataTransfer.setData('text/html', this.outerHTML);
});
$avatar.on('dragend', function(e) {
$(this).removeClass('dragging');
});
});
}
function initDropZones() {
$('.tier-row-drop-zone').each(function() {
var $zone = $(this);
$zone.on('dragover', function(e) {
e.preventDefault();
e.originalEvent.dataTransfer.dropEffect = 'move';
$(this).addClass('drag-over');
});
$zone.on('dragleave', function(e) {
$(this).removeClass('drag-over');
});
$zone.on('drop', function(e) {
e.preventDefault();
$(this).removeClass('drag-over');
var $dragging = $('.avatar-frame.dragging');
if ($dragging.length) {
// 移动现有元素
$dragging.removeClass('dragging');
// 如果是在tier中,添加样式
if ($(this).hasClass('wikitable')) {
$dragging.addClass('in-tier');
} else if ($(this).attr('id') === 'avatar-pool') {
$dragging.removeClass('in-tier');
} else {
$dragging.addClass('in-tier');
}
$(this).append($dragging);
}
});
});
}
function clearAllTiers() {
if (!confirm('确定要清空所有分级吗?')) {
return;
}
// 将所有tier中的头像移回头像池
$('.wikitable td .avatar-frame').each(function() {
$(this).removeClass('in-tier');
$('#avatar-pool').append($(this));
});
}
// 保存榜单数据
function saveTierListData() {
var tierData = collectTierData();
if (tierData.tiers.length === 0 && tierData.pool.length === $('.avatar-frame').length) {
alert('您还没有放置任何角色到榜单中!');
return;
}
var listId = generateUniqueId();
var timestamp = new Date().toISOString();
var saveData = {
id: listId,
timestamp: timestamp,
data: tierData
};
// 保存到 localStorage
localStorage.setItem('tierlist_' + listId, JSON.stringify(saveData));
// 显示保存成功对话框
showSaveSuccessDialog(listId);
}
// 收集榜单数据
function collectTierData() {
var data = {
tiers: [],
pool: []
};
// 收集表格中的数据
$('.wikitable tr').each(function(rowIndex) {
var $cells = $(this).find('td');
if ($cells.length > 0) {
var tierName = $cells.eq(0).text().trim();
var avatars = [];
$cells.eq(1).find('.avatar-frame').each(function() {
var avatarId = getAvatarIdentifier($(this));
if (avatarId) {
avatars.push(avatarId);
}
});
if (avatars.length > 0) {
data.tiers.push({
name: tierName,
avatars: avatars
});
}
}
});
// 收集头像池中的数据
$('#avatar-pool .avatar-frame').each(function() {
var avatarId = getAvatarIdentifier($(this));
if (avatarId) {
data.pool.push(avatarId);
}
});
return data;
}
// 获取头像的唯一标识符
function getAvatarIdentifier($avatar) {
// 尝试多种方式获取头像标识
var identifier = null;
// 方法1: 通过图片src
var $img = $avatar.find('img');
if ($img.length > 0) {
identifier = $img.attr('src');
}
// 方法2: 通过data属性
if (!identifier && $avatar.attr('data-avatar-id')) {
identifier = $avatar.attr('data-avatar-id');
}
// 方法3: 通过alt或title
if (!identifier && $img.attr('alt')) {
identifier = $img.attr('alt');
}
// 方法4: 通过完整HTML(作为后备)
if (!identifier) {
identifier = $avatar.prop('outerHTML');
}
return identifier;
}
// 生成唯一ID
function generateUniqueId() {
var timestamp = Date.now().toString(36);
var randomStr = Math.random().toString(36).substr(2, 9);
return timestamp + randomStr;
}
// 显示保存成功对话框
function showSaveSuccessDialog(listId) {
var shareUrl = window.location.href.split('?')[0] + '?tierid=' + listId;
var $overlay = $('<div>').addClass('tier-dialog-overlay');
var $dialog = $('<div>').addClass('tier-dialog');
var $title = $('<h3>').text('榜单保存成功!');
var $idDisplay = $('<div>').addClass('tier-id-display');
var $idLabel = $('<div>').addClass('tier-id-label').text('榜单ID:');
var $idValue = $('<div>').addClass('tier-id-value').text(listId);
var $copyIdBtn = $('<button>').addClass('copy-btn').text('复制ID')
.click(function() {
copyToClipboard(listId);
$(this).text('已复制!').css('background', '#4CAF50');
setTimeout(() => {
$(this).text('复制ID').css('background', '');
}, 2000);
});
$idDisplay.append($idLabel, $idValue, $copyIdBtn);
var $urlDisplay = $('<div>').addClass('tier-url-display');
var $urlLabel = $('<div>').addClass('tier-id-label').text('分享链接:');
var $urlValue = $('<div>').addClass('tier-id-value').text(shareUrl);
var $copyUrlBtn = $('<button>').addClass('copy-btn').text('复制链接')
.click(function() {
copyToClipboard(shareUrl);
$(this).text('已复制!').css('background', '#4CAF50');
setTimeout(() => {
$(this).text('复制链接').css('background', '');
}, 2000);
});
$urlDisplay.append($urlLabel, $urlValue, $copyUrlBtn);
var $info = $('<p>').css({'color': '#666', 'margin': '15px 0'})
.text('保存的榜单将在本地存储,您可以通过ID或链接访问。');
var $buttons = $('<div>').addClass('tier-dialog-buttons');
var $closeBtn = $('<button>')
.addClass('tier-dialog-btn tier-dialog-btn-primary')
.text('关闭')
.click(function() {
$overlay.remove();
});
$buttons.append($closeBtn);
$dialog.append($title, $idDisplay, $urlDisplay, $info, $buttons);
$overlay.append($dialog);
$('body').append($overlay);
}
// 显示加载对话框
function showLoadDialog() {
var $overlay = $('<div>').addClass('tier-dialog-overlay');
var $dialog = $('<div>').addClass('tier-dialog');
var $title = $('<h3>').text('加载榜单');
var $label = $('<label>').text('请输入榜单ID:');
var $input = $('<input>')
.attr('type', 'text')
.attr('placeholder', '输入榜单ID')
.attr('id', 'tier-id-input');
var $errorMsg = $('<div>')
.css({'color': '#f44336', 'margin-top': '10px', 'display': 'none'})
.attr('id', 'load-error-msg');
var $buttons = $('<div>').addClass('tier-dialog-buttons');
var $loadBtn = $('<button>')
.addClass('tier-dialog-btn tier-dialog-btn-primary')
.text('加载')
.click(function() {
var listId = $input.val().trim();
if (!listId) {
$errorMsg.text('请输入榜单ID!').show();
return;
}
if (loadTierListData(listId)) {
$overlay.remove();
} else {
$errorMsg.text('未找到该榜单,请检查ID是否正确!').show();
}
});
var $cancelBtn = $('<button>')
.addClass('tier-dialog-btn tier-dialog-btn-secondary')
.text('取消')
.click(function() {
$overlay.remove();
});
$buttons.append($cancelBtn, $loadBtn);
$dialog.append($title, $label, $input, $errorMsg, $buttons);
$overlay.append($dialog);
$('body').append($overlay);
// 聚焦输入框
setTimeout(() => $input.focus(), 100);
// 支持回车键加载
$input.on('keypress', function(e) {
if (e.which === 13) {
$loadBtn.click();
}
});
}
// 加载榜单数据
function loadTierListData(listId) {
var savedData = localStorage.getItem('tierlist_' + listId);
if (!savedData) {
return false;
}
try {
var saveData = JSON.parse(savedData);
applyTierData(saveData.data);
// 显示加载成功提示
showNotification('榜单加载成功!', 'success');
return true;
} catch (e) {
console.error('加载榜单失败:', e);
return false;
}
}
// 应用榜单数据
function applyTierData(tierData) {
// 首先清空所有层级
$('.wikitable td .avatar-frame').each(function() {
$(this).removeClass('in-tier');
$('#avatar-pool').append($(this));
});
// 应用tier数据
tierData.tiers.forEach(function(tier) {
var $targetCell = null;
// 查找对应的tier单元格
$('.wikitable tr').each(function() {
var $cells = $(this).find('td');
if ($cells.length > 0) {
var tierName = $cells.eq(0).text().trim();
if (tierName === tier.name) {
$targetCell = $cells.eq(1);
return false;
}
}
});
if ($targetCell) {
tier.avatars.forEach(function(avatarId) {
var $avatar = findAvatarByIdentifier(avatarId);
if ($avatar) {
$avatar.addClass('in-tier');
$targetCell.append($avatar);
}
});
}
});
}
// 根据标识符查找头像
function findAvatarByIdentifier(identifier) {
var $found = null;
$('.avatar-frame').each(function() {
var $avatar = $(this);
var currentId = getAvatarIdentifier($avatar);
if (currentId === identifier) {
$found = $avatar;
return false;
}
});
return $found;
}
// 分享榜单
function shareTierList() {
var tierData = collectTierData();
if (tierData.tiers.length === 0 && tierData.pool.length === $('.avatar-frame').length) {
alert('您还没有放置任何角色到榜单中!');
return;
}
// 检查是否已经保存
var currentUrl = window.location.href;
var urlParams = new URLSearchParams(window.location.search);
var existingId = urlParams.get('tierid');
if (existingId) {
// 已有ID,直接分享
var shareUrl = window.location.href.split('?')[0] + '?tierid=' + existingId;
showShareDialog(shareUrl, existingId);
} else {
// 先保存再分享
var listId = generateUniqueId();
var timestamp = new Date().toISOString();
var saveData = {
id: listId,
timestamp: timestamp,
data: tierData
};
localStorage.setItem('tierlist_' + listId, JSON.stringify(saveData));
var shareUrl = window.location.href.split('?')[0] + '?tierid=' + listId;
showShareDialog(shareUrl, listId);
}
}
// 显示分享对话框
function showShareDialog(shareUrl, listId) {
var $overlay = $('<div>').addClass('tier-dialog-overlay');
var $dialog = $('<div>').addClass('tier-dialog');
var $title = $('<h3>').text('分享榜单');
var $urlDisplay = $('<div>').addClass('tier-url-display');
var $urlLabel = $('<div>').addClass('tier-id-label').text('分享链接:');
var $urlValue = $('<div>').addClass('tier-id-value').text(shareUrl);
var $copyUrlBtn = $('<button>').addClass('copy-btn').text('复制链接')
.click(function() {
copyToClipboard(shareUrl);
$(this).text('已复制!').css('background', '#4CAF50');
setTimeout(() => {
$(this).text('复制链接').css('background', '');
}, 2000);
});
$urlDisplay.append($urlLabel, $urlValue, $copyUrlBtn);
var $idDisplay = $('<div>').addClass('tier-id-display');
var $idLabel = $('<div>').addClass('tier-id-label').text('榜单ID:');
var $idValue = $('<div>').addClass('tier-id-value').text(listId);
var $copyIdBtn = $('<button>').addClass('copy-btn').text('复制ID')
.click(function() {
copyToClipboard(listId);
$(this).text('已复制!').css('background', '#4CAF50');
setTimeout(() => {
$(this).text('复制ID').css('background', '');
}, 2000);
});
$idDisplay.append($idLabel, $idValue, $copyIdBtn);
var $info = $('<p>').css({'color': '#666', 'margin': '15px 0'})
.text('将此链接分享给其他人,他们可以查看您的榜单!');
var $buttons = $('<div>').addClass('tier-dialog-buttons');
var $closeBtn = $('<button>')
.addClass('tier-dialog-btn tier-dialog-btn-primary')
.text('关闭')
.click(function() {
$overlay.remove();
});
$buttons.append($closeBtn);
$dialog.append($title, $urlDisplay, $idDisplay, $info, $buttons);
$overlay.append($dialog);
$('body').append($overlay);
}
// 检查URL并加载榜单
function checkAndLoadFromURL() {
var urlParams = new URLSearchParams(window.location.search);
var tierid = urlParams.get('tierid');
if (tierid) {
setTimeout(function() {
if (loadTierListData(tierid)) {
showNotification('已加载分享的榜单!ID: ' + tierid, 'success');
} else {
showNotification('无法加载榜单,ID可能无效或已过期', 'error');
}
}, 500);
}
}
// 复制到剪贴板
function copyToClipboard(text) {
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(text);
} else {
// 后备方案
var $temp = $('<textarea>');
$('body').append($temp);
$temp.val(text).select();
document.execCommand('copy');
$temp.remove();
}
}
// 显示通知
function showNotification(message, type) {
var bgColor = type === 'success' ? '#4CAF50' : '#f44336';
var $notification = $('<div>')
.css({
'position': 'fixed',
'top': '20px',
'right': '20px',
'background': bgColor,
'color': 'white',
'padding': '15px 25px',
'border-radius': '5px',
'box-shadow': '0 4px 12px rgba(0,0,0,0.3)',
'z-index': 10000,
'font-size': '14px',
'font-weight': 'bold',
'animation': 'slideIn 0.3s ease-out'
})
.text(message);
$('body').append($notification);
setTimeout(function() {
$notification.fadeOut(300, function() {
$(this).remove();
});
}, 3000);
}
function saveTierListAsPNG() {
// 检查是否已加载html2canvas库
if (typeof html2canvas === 'undefined') {
loadHtml2Canvas(function() {
captureTierList();
});
} else {
captureTierList();
}
}
function loadHtml2Canvas(callback) {
mw.loader.using('jquery', function() {
$.getScript('https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.min.js')
.done(function() {
callback();
})
.fail(function() {
alert('加载截图库失败,请检查网络连接');
});
});
}
function captureTierList() {
var $table = $('.wikitable');
if ($table.length === 0) {
alert('未找到表格');
return;
}
// 显示加载提示
var $loading = $('<div>')
.css({
'position': 'fixed',
'top': '50%',
'left': '50%',
'transform': 'translate(-50%, -50%)',
'background': 'rgba(0,0,0,0.8)',
'color': 'white',
'padding': '20px 40px',
'border-radius': '10px',
'z-index': 9999,
'font-size': '18px'
})
.text('正在生成图片...')
.appendTo('body');
html2canvas($table[0], {
backgroundColor: '#ffffff',
scale: 2,
logging: false,
useCORS: true,
allowTaint: true
}).then(function(canvas) {
$loading.remove();
// 转换为blob并下载
canvas.toBlob(function(blob) {
var url = URL.createObjectURL(blob);
var link = document.createElement('a');
var timestamp = new Date().toISOString().slice(0,19).replace(/:/g,'-');
link.download = 'tier-list-' + timestamp + '.png';
link.href = url;
link.click();
URL.revokeObjectURL(url);
});
}).catch(function(error) {
$loading.remove();
console.error('截图失败:', error);
alert('生成图片失败,请重试');
});
}
})();