MediaWiki:Gadget-TierListMaker.js
来自卡厄思梦境WIKI
注意:在发布之后,您可能需要清除浏览器缓存才能看到所作出的更改的影响。
- Firefox或Safari:按住Shift的同时单击刷新,或按Ctrl-F5或Ctrl-R(Mac为⌘-R)
- Google Chrome:按Ctrl-Shift-R(Mac为⌘-Shift-R)
- Edge:按住Ctrl的同时单击刷新,或按Ctrl-F5。
/**
* 战斗员图鉴分级表制作工具
* 支持拖放卡片到表格并导出为PNG
*/
(function() {
'use strict';
// 仅在特定页面启用
if (mw.config.get('wgPageName') !== '节奏榜') {
return;
}
// 等待页面加载完成
mw.loader.using(['mediawiki.util', 'mediawiki.api']).then(function() {
init();
});
function init() {
// 添加控制按钮
addControlPanel();
// 使卡片可拖动
makeCardsDraggable();
// 使表格单元格可接收
makeTableDroppable();
// 添加样式
addStyles();
// 恢复面板状态
restorePanelState();
}
function addControlPanel() {
var $panel = $('<div>')
.attr('id', 'tierlist-control-panel')
.css({
'position': 'fixed',
'top': '100px',
'right': '20px',
'z-index': '9999',
'background': '#fff',
'border': '2px solid #0645ad',
'border-radius': '8px',
'box-shadow': '0 4px 6px rgba(0,0,0,0.1)',
'min-width': '200px',
'transition': 'transform 0.3s ease'
});
// 标题栏(可点击折叠)
var $header = $('<div>')
.attr('id', 'tierlist-panel-header')
.css({
'background': '#0645ad',
'color': '#fff',
'padding': '10px 15px',
'border-radius': '6px 6px 0 0',
'cursor': 'pointer',
'user-select': 'none',
'display': 'flex',
'justify-content': 'space-between',
'align-items': 'center'
})
.hover(
function() { $(this).css('background', '#0b5394'); },
function() { $(this).css('background', '#0645ad'); }
);
var $title = $('<h3>')
.text('分级表工具')
.css({
'margin': '0',
'font-size': '16px',
'flex': '1'
});
var $toggleIcon = $('<span>')
.attr('id', 'tierlist-toggle-icon')
.text('▼')
.css({
'font-size': '12px',
'transition': 'transform 0.3s ease'
});
$header.append($title, $toggleIcon);
$header.click(togglePanel);
// 内容区域
var $content = $('<div>')
.attr('id', 'tierlist-panel-content')
.css({
'padding': '15px'
});
var $exportBtn = $('<button>')
.text('📸 导出为PNG')
.css({
'width': '100%',
'padding': '10px',
'margin': '5px 0',
'background': '#0645ad',
'color': '#fff',
'border': 'none',
'border-radius': '4px',
'cursor': 'pointer',
'font-size': '14px',
'font-weight': 'bold',
'transition': 'background 0.2s'
})
.hover(
function() { $(this).css('background', '#0b5394'); },
function() { $(this).css('background', '#0645ad'); }
)
.click(exportToPNG);
var $clearBtn = $('<button>')
.text('🗑️ 清空表格')
.css({
'width': '100%',
'padding': '10px',
'margin': '5px 0',
'background': '#d33',
'color': '#fff',
'border': 'none',
'border-radius': '4px',
'cursor': 'pointer',
'font-size': '14px',
'font-weight': 'bold',
'transition': 'background 0.2s'
})
.hover(
function() { $(this).css('background', '#a00'); },
function() { $(this).css('background', '#d33'); }
)
.click(clearTable);
var $toggleBtn = $('<button>')
.text('👁️ 切换预览模式')
.attr('id', 'toggle-edit-mode')
.css({
'width': '100%',
'padding': '10px',
'margin': '5px 0',
'background': '#36c',
'color': '#fff',
'border': 'none',
'border-radius': '4px',
'cursor': 'pointer',
'font-size': '14px',
'font-weight': 'bold',
'transition': 'background 0.2s'
})
.hover(
function() { $(this).css('background', '#258'); },
function() { $(this).css('background', '#36c'); }
)
.click(toggleEditMode);
var $info = $('<div>')
.css({
'margin-top': '10px',
'padding': '10px',
'background': '#f8f9fa',
'border-radius': '4px',
'font-size': '12px',
'color': '#666',
'line-height': '1.6'
})
.html('<strong>使用说明:</strong><br>1. 拖动卡片到表格<br>2. 右键点击可删除<br>3. 点击标题栏折叠<br>4. 导出前切换预览');
$content.append($exportBtn, $clearBtn, $toggleBtn, $info);
$panel.append($header, $content);
$('body').append($panel);
// 添加最小化按钮(在面板外)
var $minimizeBtn = $('<button>')
.attr('id', 'tierlist-minimize-btn')
.text('📋')
.css({
'position': 'fixed',
'top': '100px',
'right': '20px',
'z-index': '9998',
'width': '50px',
'height': '50px',
'background': '#0645ad',
'color': '#fff',
'border': '2px solid #0645ad',
'border-radius': '50%',
'cursor': 'pointer',
'font-size': '24px',
'display': 'none',
'box-shadow': '0 4px 6px rgba(0,0,0,0.1)',
'transition': 'all 0.2s'
})
.hover(
function() {
$(this).css({
'background': '#0b5394',
'transform': 'scale(1.1)'
});
},
function() {
$(this).css({
'background': '#0645ad',
'transform': 'scale(1)'
});
}
)
.click(function() {
showPanel();
});
$('body').append($minimizeBtn);
}
function togglePanel() {
var $content = $('#tierlist-panel-content');
var $icon = $('#tierlist-toggle-icon');
var $panel = $('#tierlist-control-panel');
if ($content.is(':visible')) {
// 折叠
$content.slideUp(300);
$icon.css('transform', 'rotate(-90deg)');
localStorage.setItem('tierlist-panel-collapsed', 'true');
} else {
// 展开
$content.slideDown(300);
$icon.css('transform', 'rotate(0deg)');
localStorage.setItem('tierlist-panel-collapsed', 'false');
}
}
function hidePanel() {
var $panel = $('#tierlist-control-panel');
var $minimizeBtn = $('#tierlist-minimize-btn');
$panel.fadeOut(300);
$minimizeBtn.fadeIn(300);
localStorage.setItem('tierlist-panel-hidden', 'true');
}
function showPanel() {
var $panel = $('#tierlist-control-panel');
var $minimizeBtn = $('#tierlist-minimize-btn');
$minimizeBtn.fadeOut(300);
$panel.fadeIn(300);
localStorage.setItem('tierlist-panel-hidden', 'false');
}
function restorePanelState() {
var isCollapsed = localStorage.getItem('tierlist-panel-collapsed') === 'true';
var isHidden = localStorage.getItem('tierlist-panel-hidden') === 'true';
if (isCollapsed) {
$('#tierlist-panel-content').hide();
$('#tierlist-toggle-icon').css('transform', 'rotate(-90deg)');
}
if (isHidden) {
$('#tierlist-control-panel').hide();
$('#tierlist-minimize-btn').show();
}
}
function makeCardsDraggable() {
$('.战斗员卡片').each(function() {
var $card = $(this);
// 如果已经是可拖动的,跳过
if ($card.attr('data-draggable-init')) {
return;
}
$card.attr('draggable', 'true')
.attr('data-draggable-init', 'true')
.css('cursor', 'move')
.on('dragstart', function(e) {
// 克隆卡片HTML,确保包含所有结构
var $clone = $card.clone();
$clone.find('*').each(function() {
// 移除可能导致样式问题的内联样式
var $el = $(this);
var style = $el.attr('style');
if (style) {
// 保留关键样式,移除 opacity 等
style = style.replace(/opacity\s*:\s*[^;]+;?/gi, '');
$el.attr('style', style);
}
});
var cardHTML = $clone[0].outerHTML;
e.originalEvent.dataTransfer.setData('text/html', cardHTML);
e.originalEvent.dataTransfer.effectAllowed = 'copy';
// 只让原始卡片变透明,不影响拖动的副本
$card.css('opacity', '0.5');
})
.on('dragend', function() {
$card.css('opacity', '1');
});
});
}
function makeTableDroppable() {
$('.wikitable td').each(function() {
var $cell = $(this);
$cell.addClass('tierlist-dropzone')
.css({
'min-height': '280px',
'vertical-align': 'top',
'padding': '10px',
'position': 'relative'
})
.on('dragover', function(e) {
e.preventDefault();
e.originalEvent.dataTransfer.dropEffect = 'copy';
$cell.addClass('drag-over');
})
.on('dragleave', function() {
$cell.removeClass('drag-over');
})
.on('drop', function(e) {
e.preventDefault();
$cell.removeClass('drag-over');
var cardHTML = e.originalEvent.dataTransfer.getData('text/html');
if (cardHTML) {
var $newCard = $(cardHTML);
// 确保新卡片的样式正确
$newCard.addClass('placed-card')
.css({
'margin': '5px',
'opacity': '1', // 明确设置为不透明
'filter': 'none' // 移除任何滤镜
})
.attr('draggable', 'true')
.removeAttr('data-draggable-init') // 允许重新初始化
.on('contextmenu', function(e) {
e.preventDefault();
if (confirm('确定要删除这张卡片吗?')) {
$newCard.remove();
}
})
.on('dblclick', function() {
if (confirm('确定要删除这张卡片吗?')) {
$newCard.remove();
}
});
// 确保内部元素也没有 opacity 问题
$newCard.find('*').css('opacity', '');
$cell.append($newCard);
// 重新使新卡片可拖动
makeCardsDraggable();
}
});
});
}
function toggleEditMode() {
$('body').toggleClass('tierlist-preview-mode');
var isPreview = $('body').hasClass('tierlist-preview-mode');
$('#toggle-edit-mode').text(isPreview ? '✏️ 切换编辑模式' : '👁️ 切换预览模式');
if (isPreview) {
$('.placed-card').css('pointer-events', 'none');
} else {
$('.placed-card').css('pointer-events', 'auto');
}
}
function clearTable() {
if (confirm('确定要清空表格中的所有卡片吗?此操作不可撤销!')) {
$('.wikitable .placed-card').remove();
mw.notify('表格已清空', { type: 'success' });
}
}
function exportToPNG() {
var $btn = $(event.target);
$btn.prop('disabled', true).text('⏳ 正在生成...');
// 加载 html2canvas 库
if (typeof html2canvas === 'undefined') {
$.getScript('https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.min.js')
.done(function() {
performExport($btn);
})
.fail(function() {
mw.notify('加载导出库失败,请检查网络连接', { type: 'error' });
$btn.prop('disabled', false).text('📸 导出为PNG');
});
} else {
performExport($btn);
}
}
function performExport($btn) {
var $table = $('.wikitable').first();
// 临时隐藏控制面板和最小化按钮
var $panel = $('#tierlist-control-panel');
var $minimizeBtn = $('#tierlist-minimize-btn');
var panelVisible = $panel.is(':visible');
var btnVisible = $minimizeBtn.is(':visible');
$panel.hide();
$minimizeBtn.hide();
// 进入预览模式
var wasPreview = $('body').hasClass('tierlist-preview-mode');
if (!wasPreview) {
$('body').addClass('tierlist-preview-mode');
}
// 确保所有卡片都是完全不透明的
var $cards = $('.placed-card');
$cards.css({
'opacity': '1',
'filter': 'none'
});
html2canvas($table[0], {
backgroundColor: '#ffffff',
scale: 2,
logging: false,
useCORS: true,
allowTaint: true,
imageTimeout: 0,
removeContainer: true
}).then(function(canvas) {
// 恢复界面
if (panelVisible) $panel.show();
if (btnVisible) $minimizeBtn.show();
if (!wasPreview) {
$('body').removeClass('tierlist-preview-mode');
}
// 下载图片
var link = document.createElement('a');
var timestamp = new Date().toISOString().slice(0, 19).replace(/:/g, '-');
link.download = '战斗员分级表_' + timestamp + '.png';
link.href = canvas.toDataURL('image/png');
link.click();
$btn.prop('disabled', false).text('📸 导出为PNG');
mw.notify('分级表已成功导出!', { type: 'success' });
}).catch(function(error) {
console.error('导出失败:', error);
if (panelVisible) $panel.show();
if (btnVisible) $minimizeBtn.show();
$btn.prop('disabled', false).text('📸 导出为PNG');
mw.notify('导出失败: ' + error.message, { type: 'error' });
});
}
function addStyles() {
var styles = `
.tierlist-dropzone {
transition: background-color 0.3s, border 0.3s;
}
.tierlist-dropzone.drag-over {
background-color: #e6f3ff !important;
border: 2px dashed #0645ad !important;
}
.placed-card {
transition: transform 0.2s, box-shadow 0.2s;
opacity: 1 !important;
filter: none !important;
}
.placed-card * {
opacity: 1 !important;
filter: none !important;
}
body:not(.tierlist-preview-mode) .placed-card:hover {
transform: scale(1.05);
box-shadow: 0 4px 8px rgba(0,0,0,0.2);
z-index: 10;
}
.tierlist-preview-mode .placed-card {
pointer-events: none;
}
.tierlist-preview-mode .placed-card:hover {
transform: none;
box-shadow: none;
}
#tierlist-control-panel button:active {
transform: scale(0.95);
}
#tierlist-panel-header {
position: relative;
}
/* 添加一个关闭按钮到标题栏 */
#tierlist-panel-header::after {
content: '✕';
position: absolute;
right: 40px;
top: 50%;
transform: translateY(-50%);
cursor: pointer;
font-size: 18px;
opacity: 0.8;
transition: opacity 0.2s;
}
#tierlist-panel-header:hover::after {
opacity: 1;
}
@media print {
#tierlist-control-panel,
#tierlist-minimize-btn {
display: none !important;
}
}
`;
$('<style>').text(styles).appendTo('head');
}
// 为标题栏添加关闭功能
$(document).on('click', '#tierlist-panel-header', function(e) {
var $header = $(this);
var clickX = e.pageX - $header.offset().left;
var headerWidth = $header.outerWidth();
// 如果点击的是右侧的关闭区域(最右边40px)
if (clickX > headerWidth - 40 && clickX < headerWidth - 10) {
e.stopPropagation();
hidePanel();
}
});
})();