MediaWiki

TierListMaker.js:修订间差异

来自卡厄思梦境WIKI

律Rhyme留言 | 贡献
无编辑摘要
标签手工回退 已被回退
律Rhyme留言 | 贡献
无编辑摘要
标签撤销
 
第2行: 第2行:
     'use strict';
     'use strict';
      
      
     // 等待页面完全加载
     // 仅在 TierListMaker 页面运行
     $(document).ready(function() {
     if (mw.config.get('wgPageName') !== '节奏榜') {
        setTimeout(function() {
         return;
            if ($('.wikitable').length) {
                loadDragula(function() {
                    initTierList();
                });
            }
        }, 1000);
    });
   
    function loadDragula(callback) {
        if (!$('#dragula-css').length) {
            $('<link>')
                .attr('id', 'dragula-css')
                .attr('rel', 'stylesheet')
                .attr('href', 'https://cdn.jsdelivr.net/npm/dragula@3.7.3/dist/dragula.min.css')
                .appendTo('head');
        }
       
        if (typeof dragula === 'undefined') {
            $.getScript('https://cdn.jsdelivr.net/npm/dragula@3.7.3/dist/dragula.min.js')
                .done(callback)
                .fail(function() {
                    console.error('加载Dragula失败');
                });
         } else {
            callback();
        }
     }
     }
      
      
     function initTierList() {
     // 等待页面加载完成
         console.log('=== 初始化 Tier List ===');
    $(function() {
        addStyles();
         initTierListMaker();
        createAvatarPool();
    });
        processAvatars();
        setupDragAndDrop();
        addExportButton();
        addSaveLoadButtons();
        checkUrlForTierList();
    }
      
      
     function addStyles() {
     function initTierListMaker() {
         var css = `
         // 添加控制按钮
            #avatar-pool {
        addControlButtons();
                background: #f5f5f5;
                border: 2px dashed #ccc;
                border-radius: 8px;
                padding: 15px;
                margin: 20px 0;
                min-height: 120px;
                display: flex;
                flex-wrap: wrap;
                gap: 10px;
                align-items: flex-start;
            }
           
            #avatar-pool.gu-over {
                background: #e8f4f8;
                border-color: #4a9eff;
            }
           
            .avatar-frame {
                cursor: move;
                transition: all 0.2s;
                display: inline-block;
            }
           
            .avatar-frame:hover {
                transform: translateY(-2px);
                box-shadow: 0 4px 8px rgba(0,0,0,0.15);
            }
           
            .avatar-frame.gu-transit {
                opacity: 0.8;
                transform: scale(1.05);
            }
           
            .wikitable td {
                vertical-align: top;
                min-height: 100px;
            }
           
            .wikitable td:nth-child(2) {
                background: #fafafa !important;
                padding: 10px !important;
                display: flex;
                flex-wrap: wrap;
                gap: 8px;
                align-content: flex-start;
            }
           
            .wikitable td:nth-child(2).gu-over {
                background: #e8f4f8 !important;
            }
           
            .gu-mirror {
                cursor: grabbing !important;
                opacity: 0.9;
                z-index: 9999 !important;
            }
           
            /* 隐藏原始查询结果 */
            .smwask-query-result {
                display: none !important;
            }
           
            #export-tierlist-btn,
            #save-tierlist-btn,
            #load-tierlist-btn,
            #share-tierlist-btn {
                margin: 10px 5px;
                padding: 12px 24px;
                font-size: 16px;
                font-weight: bold;
                border: none;
                border-radius: 6px;
                cursor: pointer;
                transition: all 0.3s;
                color: white;
            }
           
            #export-tierlist-btn {
                background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            }
           
            #export-tierlist-btn:hover {
                transform: translateY(-2px);
                box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
            }
           
            #save-tierlist-btn {
                background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
            }
           
            #save-tierlist-btn:hover {
                transform: translateY(-2px);
                box-shadow: 0 4px 12px rgba(245, 87, 108, 0.4);
            }
           
            #load-tierlist-btn {
                background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
            }
           
            #load-tierlist-btn:hover {
                transform: translateY(-2px);
                box-shadow: 0 4px 12px rgba(79, 172, 254, 0.4);
            }
           
            #share-tierlist-btn {
                background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);
            }
           
            #share-tierlist-btn:hover {
                transform: translateY(-2px);
                box-shadow: 0 4px 12px rgba(67, 233, 123, 0.4);
            }
           
            .tier-dialog-overlay {
                position: fixed;
                top: 0;
                left: 0;
                right: 0;
                bottom: 0;
                background: rgba(0, 0, 0, 0.7);
                display: flex;
                justify-content: center;
                align-items: center;
                z-index: 10000;
                animation: fadeIn 0.3s;
            }
           
            @keyframes fadeIn {
                from { opacity: 0; }
                to { opacity: 1; }
            }
           
            .tier-dialog {
                background: white;
                border-radius: 12px;
                padding: 30px;
                max-width: 500px;
                width: 90%;
                max-height: 80vh;
                overflow-y: auto;
                box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3);
                animation: slideUp 0.3s;
            }
           
            @keyframes slideUp {
                from {
                    transform: translateY(50px);
                    opacity: 0;
                }
                to {
                    transform: translateY(0);
                    opacity: 1;
                }
            }
           
            .tier-dialog h3 {
                margin: 0 0 20px 0;
                color: #333;
                font-size: 24px;
            }
           
            .tier-dialog input {
                width: 100%;
                padding: 12px;
                border: 2px solid #ddd;
                border-radius: 6px;
                font-size: 16px;
                margin-bottom: 20px;
                box-sizing: border-box;
            }
           
            .tier-dialog input:focus {
                outline: none;
                border-color: #4a9eff;
            }
           
            .tier-dialog-buttons {
                display: flex;
                gap: 10px;
                justify-content: flex-end;
            }
           
            .tier-dialog-btn {
                padding: 10px 20px;
                border: none;
                border-radius: 6px;
                font-size: 16px;
                cursor: pointer;
                transition: all 0.3s;
            }
           
            .tier-dialog-btn-primary {
                background: #4a9eff;
                color: white;
            }
           
            .tier-dialog-btn-primary:hover {
                background: #3a8eef;
            }
           
            .tier-dialog-btn-secondary {
                background: #e0e0e0;
                color: #333;
            }
           
            .tier-dialog-btn-secondary:hover {
                background: #d0d0d0;
            }
           
            .tier-info-box {
                background: #f0f8ff;
                border: 2px solid #4a9eff;
                border-radius: 8px;
                padding: 15px;
                margin: 15px 0;
            }
           
            .tier-info-box p {
                margin: 8px 0;
                color: #333;
            }
           
            .tier-info-box strong {
                color: #4a9eff;
            }
           
            .saved-list-item {
                border: 1px solid #ddd;
                border-radius: 6px;
                padding: 10px;
                margin-bottom: 10px;
                cursor: pointer;
                transition: all 0.2s;
            }
           
            .saved-list-item:hover {
                background: #f0f8ff;
                border-color: #4a9eff;
            }
           
            .tier-notification {
                position: fixed;
                top: 20px;
                right: 20px;
                padding: 15px 25px;
                border-radius: 8px;
                color: white;
                font-size: 16px;
                z-index: 10001;
                animation: slideInRight 0.3s;
                box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
            }
           
            @keyframes slideInRight {
                from {
                    transform: translateX(100%);
                    opacity: 0;
                }
                to {
                    transform: translateX(0);
                    opacity: 1;
                }
            }
           
            .tier-notification.success {
                background: #4caf50;
            }
           
            .tier-notification.error {
                background: #f44336;
            }
           
            .tier-notification.info {
                background: #2196f3;
            }
        `;
          
          
         $('<style>').text(css).appendTo('head');
         // 初始化拖拽功能
    }
         initDragAndDrop();
   
    function createAvatarPool() {
         var $pool = $('<div>')
            .attr('id', 'avatar-pool')
            .html('<h3 style="width: 100%; margin: 0 0 10px 0; color: #666;">📦 角色池 - 拖拽角色到对应层级</h3>');
          
          
         var $table = $('.wikitable').first();
         // 添加样式
         if ($table.length) {
         addCustomStyles();
            $table.after($pool);
            console.log('✓ 角色池已创建');
        }
     }
     }
      
      
     function processAvatars() {
     function addControlButtons() {
        console.log('=== 开始处理角色 ===');
         var $buttonContainer = $('<div>')
       
            .attr('id', 'tier-list-controls')
         var $pool = $('#avatar-pool');
            .css({
        var processedCount = 0;
                'margin': '10px 0',
       
                'padding': '10px',
        // 方法1: 查找Ask查询结果
                'background': '#f0f0f0',
        var $askResults = $('.smw-ask, .smwask-query-result, [class*="ask"]');
                'border-radius': '5px'
        console.log('找到Ask结果容器:', $askResults.length);
       
        // 方法2: 查找表格之后的所有图片
        var $table = $('.wikitable').first();
        var $afterTable = $table.nextAll();
       
        console.log('表格后的元素数量:', $afterTable.length);
       
        // 收集所有可能包含角色的元素
        var $candidates = $();
       
        // 从Ask查询结果中查找
        $askResults.find('img').each(function() {
            $candidates = $candidates.add($(this).closest('a, div, span, td, li'));
        });
       
        // 从表格后的内容查找
        $afterTable.each(function() {
            var $elem = $(this);
            if ($elem.attr('id') === 'avatar-pool') return; // 跳过角色池本身
           
            // 查找所有图片
            $elem.find('img').each(function() {
                var $container = $(this).closest('a, div, span, td, li');
                if ($container.length === 0) {
                    $container = $(this).parent();
                }
                if ($container.length) {
                    $candidates = $candidates.add($container);
                }
             });
             });
           
            // 如果元素本身就包含图片
            if ($elem.find('img').length > 0 || $elem.is('img')) {
                $candidates = $candidates.add($elem);
            }
        });
          
          
         // 直接查找所有a标签包含的图片
         var $saveButton = $('<button>')
        $table.nextAll('a').each(function() {
            .text('保存为PNG')
             if ($(this).find('img').length > 0) {
             .addClass('tier-list-save-btn')
                $candidates = $candidates.add($(this));
            .click(saveTierListAsPNG);
            }
        });
          
          
         console.log('找到候选元素:', $candidates.length);
         var $clearButton = $('<button>')
            .text('清空所有')
            .addClass('tier-list-clear-btn')
            .click(clearAllTiers);
          
          
        // 去重并处理
         var $resetButton = $('<button>')
         var processed = new Set();
             .text('重置')
       
             .addClass('tier-list-reset-btn')
        $candidates.each(function() {
            var $elem = $(this);
            var $img = $elem.find('img').first();
           
            if (!$img.length) {
                $img = $elem.is('img') ? $elem : null;
             }
           
            if (!$img || !$img.length) return;
           
            var imgSrc = $img.attr('src');
            if (!imgSrc || processed.has(imgSrc)) return;
           
             processed.add(imgSrc);
           
            // 克隆整个容器元素
            var $avatar = $elem.clone(true);
           
            // 添加必要的属性和类
            $avatar.addClass('avatar-frame');
           
            var uniqueId = 'avatar_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
            $avatar.attr('data-tier-id', uniqueId);
            $avatar.attr('data-avatar-src', imgSrc);
            $avatar.attr('data-avatar-name', $img.attr('alt') || $img.attr('title') || '');
           
            // 添加到角色池
            $pool.append($avatar);
            processedCount++;
           
            console.log('✓ 处理角色:', $img.attr('alt') || imgSrc);
        });
       
        console.log('=== 角色处理完成 ===');
        console.log('总计处理:', processedCount, '个角色');
       
        // 隐藏原始显示区域
        $afterTable.each(function() {
            var $elem = $(this);
            if ($elem.attr('id') !== 'avatar-pool' &&
                !$elem.is('button') &&
                !$elem.hasClass('tier-dialog-overlay') &&
                !$elem.hasClass('tier-notification')) {
                $elem.hide();
            }
        });
       
        if (processedCount === 0) {
            console.error('❌ 未找到任何角色');
            showNotification('⚠️ 未找到角色图片,请检查页面内容', 'error');
           
            // 调试信息
            console.log('调试信息:');
            console.log('- 表格:', $table.length);
            console.log('- 表格后元素:', $afterTable.length);
            console.log('- Ask结果:', $askResults.length);
            console.log('- 所有图片数量:', $('img').length);
           
            // 显示所有图片的位置
            $('img').each(function(i) {
                var $img = $(this);
                console.log('图片' + i + ':', {
                    src: $img.attr('src'),
                    alt: $img.attr('alt'),
                    parent: $img.parent()[0].tagName,
                    parentClass: $img.parent().attr('class')
                });
            });
        }
    }
   
    function setupDragAndDrop() {
        var containers = [];
       
        // 添加角色池
        var poolElement = document.getElementById('avatar-pool');
        if (poolElement) {
            containers.push(poolElement);
        }
       
        // 添加所有tier单元格
        $('.wikitable td:nth-child(2)').each(function() {
            containers.push(this);
        });
       
        console.log('拖拽容器数量:', containers.length);
       
        if (containers.length === 0) {
            console.error('没有找到拖拽容器');
            return;
        }
       
        var drake = dragula(containers, {
            revertOnSpill: true,
            direction: 'horizontal',
            moves: function(el, container, handle) {
                return $(el).hasClass('avatar-frame');
            },
            accepts: function(el, target, source, sibling) {
                return true;
            }
        });
       
        drake.on('drag', function(el) {
            $(el).css('opacity', '0.5');
        });
       
        drake.on('drop', function(el, target, source) {
            $(el).css('opacity', '1');
            console.log('角色已移动');
        });
       
        drake.on('cancel', function(el, container, source) {
            $(el).css('opacity', '1');
        });
       
        console.log('✓ 拖拽功能已启用');
    }
   
    function addExportButton() {
        var $btn = $('<button>')
            .attr('id', 'export-tierlist-btn')
            .html('📸 导出为图片')
             .click(function() {
             .click(function() {
                 loadHtml2Canvas(function() {
                 location.reload();
                    captureTierList();
                });
             });
             });
          
          
         $('.wikitable').before($btn);
         $buttonContainer.append($saveButton, ' ', $clearButton, ' ', $resetButton);
         console.log('✓ 导出按钮已添加');
         $('.wikitable').before($buttonContainer);
     }
     }
      
      
     function addSaveLoadButtons() {
     function addCustomStyles() {
         var $saveBtn = $('<button>')
         var styles = `
            .attr('id', 'save-tierlist-btn')
            <style>
            .html('💾 保存榜单')
                .tier-list-save-btn, .tier-list-clear-btn, .tier-list-reset-btn {
            .click(function() {
                    padding: 8px 16px;
                saveTierListData();
                    margin: 0 5px;
            });
                    font-size: 14px;
       
                    font-weight: bold;
        var $loadBtn = $('<button>')
                    border: none;
            .attr('id', 'load-tierlist-btn')
                    border-radius: 4px;
            .html('📂 加载榜单')
                    cursor: pointer;
            .click(function() {
                    transition: all 0.3s;
                 showLoadDialog();
                 }
            });
               
       
                .tier-list-save-btn {
        var $shareBtn = $('<button>')
                    background: #4CAF50;
            .attr('id', 'share-tierlist-btn')
                    color: white;
            .html('🔗 分享榜单')
                 }
            .click(function() {
               
                 showShareDialog();
                .tier-list-save-btn:hover {
            });
                    background: #45a049;
       
                }
        $('#export-tierlist-btn').after($saveBtn).after($loadBtn).after($shareBtn);
               
    }
                .tier-list-clear-btn {
   
                    background: #f44336;
    function saveTierListData() {
                    color: white;
        console.log('开始保存榜单...');
                }
       
               
        var tierData = collectTierData();
                .tier-list-clear-btn:hover {
       
                    background: #da190b;
        console.log('收集到的数据:', tierData);
                }
       
               
        var totalAvatars = tierData.pool.length;
                .tier-list-reset-btn {
        tierData.tiers.forEach(function(tier) {
                    background: #2196F3;
            totalAvatars += tier.avatars.length;
                    color: white;
        });
                }
       
               
        console.log('总角色数:', totalAvatars);
                .tier-list-reset-btn:hover {
       
                    background: #0b7dda;
        if (totalAvatars === 0) {
                 }
            alert('没有检测到任何角色数据!');
               
            return;
                .wikitable td {
        }
                    min-height: 120px;
       
                    min-width: 300px;
        if (tierData.tiers.every(t => t.avatars.length === 0)) {
                    padding: 10px;
            var confirm = window.confirm('您还没有将任何角色放入层级中,确定要保存空榜单吗?');
                    vertical-align: top;
            if (!confirm) {
                    position: relative;
                 return;
                }
            }
               
        }
                .tier-row-drop-zone {
       
                    border: 2px dashed transparent;
        var listId = generateUniqueId();
                    transition: all 0.3s;
        var timestamp = new Date().toISOString();
                }
       
               
        var saveData = {
                .tier-row-drop-zone.drag-over {
            id: listId,
                    border-color: #2196F3;
            timestamp: timestamp,
                    background-color: rgba(33, 150, 243, 0.1);
            data: tierData
                }
        };
               
       
                .avatar-frame {
        try {
                    cursor: move;
            localStorage.setItem('tierlist_' + listId, JSON.stringify(saveData));
                    transition: transform 0.2s, opacity 0.2s;
            console.log('保存成功,ID:', listId);
                    user-select: none;
            showSaveSuccessDialog(listId);
                }
        } catch (e) {
               
            console.error('保存失败:', e);
                .avatar-frame:hover {
            alert('保存失败:' + e.message);
                    transform: scale(1.05);
        }
                 }
    }
   
    function collectTierData() {
        var data = {
            tiers: [],
            pool: []
        };
       
        // 收集各个tier中的数据
        $('.wikitable tr').each(function() {
            var $row = $(this);
            var $cells = $row.find('td, th');
           
            if ($cells.length >= 2) {
                 var $tierNameCell = $cells.eq(0);
                var tierName = $tierNameCell.text().trim();
                  
                  
                 var $tierCell = $cells.eq(1);
                 .avatar-frame.dragging {
                var $avatarsInTier = $tierCell.find('.avatar-frame');
                    opacity: 0.5;
                }
                  
                  
                 console.log('检查层级:', tierName, '包含', $avatarsInTier.length, '个角色');
                 .avatar-frame.in-tier {
                    margin: 5px;
                }
                  
                  
                 if ($avatarsInTier.length > 0) {
                 #avatar-pool {
                     var avatars = [];
                     border: 2px solid #ddd;
                      
                     padding: 10px;
                     $avatarsInTier.each(function() {
                     margin: 10px 0;
                        var avatarData = getAvatarData($(this));
                     border-radius: 5px;
                        if (avatarData) {
                     background: #fafafa;
                            avatars.push(avatarData);
                    min-height: 150px;
                            console.log('收集角色:', avatarData.name);
                        }
                     });
                      
                    if (avatars.length > 0) {
                        data.tiers.push({
                            name: tierName,
                            avatars: avatars
                        });
                        console.log('保存层级:', tierName, '共', avatars.length, '个角色');
                    }
                 }
                 }
            }
               
        });
                #avatar-pool-title {
       
                    font-size: 16px;
        // 收集头像池中的数据
                    font-weight: bold;
        $('#avatar-pool .avatar-frame').each(function() {
                    margin-bottom: 10px;
            var avatarData = getAvatarData($(this));
                     color: #333;
            if (avatarData) {
                data.pool.push(avatarData);
            }
        });
       
        console.log('最终数据:', data);
        return data;
    }
   
    function getAvatarData($avatar) {
        return {
            tierId: $avatar.attr('data-tier-id'),
            src: $avatar.attr('data-avatar-src') || $avatar.find('img').attr('src'),
            name: $avatar.attr('data-avatar-name') || $avatar.find('img').attr('alt') || '',
            html: $avatar.prop('outerHTML')
        };
    }
   
    function showSaveSuccessDialog(listId) {
        var pageUrl = window.location.origin + window.location.pathname;
        var fullUrl = pageUrl + '?tierlist=' + listId;
       
        var $overlay = $('<div>')
            .addClass('tier-dialog-overlay')
            .click(function(e) {
                if (e.target === this) {
                     $(this).remove();
                 }
                 }
             });
             </style>
       
         `;
        var $dialog = $('<div>').addClass('tier-dialog');
         $('head').append(styles);
       
        $dialog.html(`
            <h3>✅ 榜单保存成功!</h3>
            <div class="tier-info-box">
                <p><strong>榜单ID:</strong> ${listId}</p>
                <p><strong>分享链接:</strong></p>
                <input type="text" value="${fullUrl}" readonly style="margin-bottom: 10px;">
            </div>
            <p style="color: #666; font-size: 14px;">您可以通过以下方式访问这个榜单:</p>
            <ul style="color: #666; font-size: 14px; margin: 10px 0;">
                <li>点击"加载榜单"按钮,输入ID:<code style="background: #f0f0f0; padding: 2px 6px; border-radius: 3px;">${listId}</code></li>
                <li>复制分享链接发送给其他人</li>
            </ul>
            <div class="tier-dialog-buttons">
                <button class="tier-dialog-btn tier-dialog-btn-secondary" onclick="this.closest('.tier-dialog-overlay').remove()">关闭</button>
                <button class="tier-dialog-btn tier-dialog-btn-primary" id="copy-url-btn">复制链接</button>
            </div>
         `);
       
        $overlay.append($dialog);
         $('body').append($overlay);
       
        $('#copy-url-btn').click(function() {
            var $input = $dialog.find('input');
            $input.select();
            document.execCommand('copy');
            showNotification('链接已复制到剪贴板!', 'success');
        });
       
        setTimeout(function() {
            $dialog.find('input').select();
        }, 100);
     }
     }
      
      
     function showLoadDialog() {
     function initDragAndDrop() {
         var $overlay = $('<div>')
        // 创建头像池容器
             .addClass('tier-dialog-overlay')
         var $avatarPool = $('<div>')
             .click(function(e) {
             .attr('id', 'avatar-pool')
                if (e.target === this) {
             .addClass('tier-row-drop-zone');
                    $(this).remove();
                }
            });
          
          
         var $dialog = $('<div>').addClass('tier-dialog');
         var $poolTitle = $('<div>')
            .attr('id', 'avatar-pool-title')
            .text('角色池(拖动到上方表格)');
          
          
         // 获取所有保存的榜单
         $avatarPool.append($poolTitle);
        var savedLists = [];
        for (var i = 0; i < localStorage.length; i++) {
            var key = localStorage.key(i);
            if (key.startsWith('tierlist_')) {
                try {
                    var data = JSON.parse(localStorage.getItem(key));
                    savedLists.push(data);
                } catch (e) {
                    console.error('解析榜单失败:', key, e);
                }
            }
        }
          
          
         // 按时间排序
         // 将所有头像移动到头像池
         savedLists.sort(function(a, b) {
         var $avatars = $('.avatar-frame');
             return new Date(b.timestamp) - new Date(a.timestamp);
        $avatars.each(function() {
             $(this).addClass('avatar-item').appendTo($avatarPool);
         });
         });
          
          
         var listHtml = '';
         $('.wikitable').after($avatarPool);
        if (savedLists.length > 0) {
            listHtml = '<div style="max-height: 300px; overflow-y: auto; margin: 15px 0;">';
            savedLists.forEach(function(list) {
                var date = new Date(list.timestamp).toLocaleString('zh-CN');
                var tierCount = list.data.tiers.length;
                var avatarCount = list.data.pool.length;
                list.data.tiers.forEach(function(tier) {
                    avatarCount += tier.avatars.length;
                });
               
                listHtml += `
                    <div class="saved-list-item" data-list-id="${list.id}">
                        <div style="font-weight: bold; margin-bottom: 5px;">ID: ${list.id}</div>
                        <div style="font-size: 12px; color: #666;">保存时间: ${date}</div>
                        <div style="font-size: 12px; color: #666;">包含 ${tierCount} 个层级,${avatarCount} 个角色</div>
                    </div>
                `;
            });
            listHtml += '</div>';
        }
       
        $dialog.html(`
            <h3>📂 加载榜单</h3>
            <p style="color: #666; margin-bottom: 15px;">输入榜单ID或从下方选择:</p>
            <input type="text" id="tierlist-id-input" placeholder="输入榜单ID" style="margin-bottom: 15px;">
            ${listHtml || '<p style="color: #999; text-align: center; padding: 20px;">暂无保存的榜单</p>'}
            <div class="tier-dialog-buttons">
                <button class="tier-dialog-btn tier-dialog-btn-secondary" onclick="this.closest('.tier-dialog-overlay').remove()">取消</button>
                <button class="tier-dialog-btn tier-dialog-btn-primary" id="load-btn">加载</button>
            </div>
        `);
          
          
         $overlay.append($dialog);
         // 为表格单元格添加drop-zone类
         $('body').append($overlay);
         $('.wikitable td').addClass('tier-row-drop-zone');
          
          
         // 点击列表项选择
         // 初始化所有头像的拖拽
         $('.saved-list-item').click(function() {
         initAvatarDrag();
            $('.saved-list-item').css('background', 'white').css('border-color', '#ddd');
            $(this).css('background', '#e8f4f8').css('border-color', '#4a9eff');
            $('#tierlist-id-input').val($(this).data('list-id'));
        });
          
          
         // 加载按钮
         // 初始化所有drop zone
         $('#load-btn').click(function() {
         initDropZones();
            var listId = $('#tierlist-id-input').val().trim();
            if (!listId) {
                alert('请输入或选择榜单ID');
                return;
            }
           
            if (loadTierListData(listId)) {
                $overlay.remove();
            } else {
                alert('加载失败:未找到该榜单');
            }
        });
       
        // 回车加载
        $('#tierlist-id-input').keypress(function(e) {
            if (e.which === 13) {
                $('#load-btn').click();
            }
        });
     }
     }
      
      
     function loadTierListData(listId) {
     function initAvatarDrag() {
         var savedData = localStorage.getItem('tierlist_' + listId);
         $('.avatar-frame').each(function() {
       
             var $avatar = $(this);
        console.log('尝试加载榜单 ID:', listId);
              
       
             $avatar.attr('draggable', 'true');
        if (!savedData) {
             console.error('未找到榜单数据');
             return false;
        }
       
        try {
            var saveData = JSON.parse(savedData);
             console.log('解析后的数据:', saveData);
              
              
             applyTierData(saveData.data);
             $avatar.on('dragstart', function(e) {
                $(this).addClass('dragging');
                e.originalEvent.dataTransfer.effectAllowed = 'move';
                e.originalEvent.dataTransfer.setData('text/html', this.outerHTML);
            });
              
              
             showNotification('榜单加载成功!', 'success');
             $avatar.on('dragend', function(e) {
            return true;
                $(this).removeClass('dragging');
        } catch (e) {
             });
            console.error('加载榜单失败:', e);
         });
             return false;
         }
     }
     }
      
      
     function applyTierData(tierData) {
     function initDropZones() {
        console.log('应用榜单数据:', tierData);
         $('.tier-row-drop-zone').each(function() {
       
             var $zone = $(this);
        // 首先将所有角色移回池中
         $('.wikitable td .avatar-frame').each(function() {
             $('#avatar-pool').append($(this));
        });
       
        // 应用tier数据
        tierData.tiers.forEach(function(tier, index) {
            console.log('处理层级', index, ':', tier.name, '包含', tier.avatars.length, '个角色');
              
              
             // 找到对应的tier单元格
             $zone.on('dragover', function(e) {
            var $tierRow = $('.wikitable tr').eq(index);
                e.preventDefault();
            var $tierCell = $tierRow.find('td:nth-child(2)');
                e.originalEvent.dataTransfer.dropEffect = 'move';
                $(this).addClass('drag-over');
            });
              
              
             if ($tierCell.length === 0) {
             $zone.on('dragleave', function(e) {
                 console.warn('未找到层级单元格,跳过');
                 $(this).removeClass('drag-over');
                return;
             });
             }
           
            // 清空该单元格
            $tierCell.empty();
              
              
             // 添加角色到该层级
             $zone.on('drop', function(e) {
            tier.avatars.forEach(function(avatarData) {
                 e.preventDefault();
                 console.log('查找角色:', avatarData.name, 'ID:', avatarData.tierId);
                $(this).removeClass('drag-over');
                  
                  
                // 尝试在池中找到对应的角色
                 var $dragging = $('.avatar-frame.dragging');
                 var $avatar = $('#avatar-pool .avatar-frame[data-tier-id="' + avatarData.tierId + '"]');
                  
                  
                // 如果没找到,尝试通过src查找
                 if ($dragging.length) {
                 if ($avatar.length === 0) {
                     // 移动现有元素
                     $avatar = $('#avatar-pool .avatar-frame[data-avatar-src="' + avatarData.src + '"]');
                     $dragging.removeClass('dragging');
                }
               
                // 如果还是没找到,尝试通过img src查找
                if ($avatar.length === 0) {
                     $('#avatar-pool .avatar-frame').each(function() {
                        var $img = $(this).find('img');
                        if ($img.attr('src') === avatarData.src) {
                            $avatar = $(this);
                            return false;
                        }
                    });
                }
               
                // 如果找到了,移动到对应层级
                if ($avatar.length > 0) {
                    console.log('✓ 找到角色,移动到层级');
                    $tierCell.append($avatar);
                } else {
                    console.warn('✗ 未找到角色,尝试从HTML重建');
                      
                      
                     // 如果没找到,尝试从保存的HTML重建
                     // 如果是在tier中,添加样式
                     if (avatarData.html) {
                     if ($(this).hasClass('wikitable')) {
                         var $newAvatar = $(avatarData.html);
                         $dragging.addClass('in-tier');
                         $tierCell.append($newAvatar);
                    } else if ($(this).attr('id') === 'avatar-pool') {
                         console.log('✓ 从HTML重建角色');
                         $dragging.removeClass('in-tier');
                    } else {
                         $dragging.addClass('in-tier');
                     }
                     }
                   
                    $(this).append($dragging);
                 }
                 }
             });
             });
         });
         });
       
        // 应用池数据(确保顺序)
        if (tierData.pool && tierData.pool.length > 0) {
            var $pool = $('#avatar-pool');
           
            tierData.pool.forEach(function(avatarData) {
                var $avatar = $pool.find('.avatar-frame[data-tier-id="' + avatarData.tierId + '"]');
               
                if ($avatar.length === 0) {
                    $avatar = $pool.find('.avatar-frame[data-avatar-src="' + avatarData.src + '"]');
                }
               
                if ($avatar.length > 0) {
                    // 将角色移到池的末尾以保持顺序
                    $pool.append($avatar);
                }
            });
        }
       
        console.log('榜单数据应用完成');
     }
     }
      
      
     function showShareDialog() {
     function clearAllTiers() {
         console.log('准备分享榜单...');
         if (!confirm('确定要清空所有分级吗?')) {
       
        // 先保存当前榜单
        var tierData = collectTierData();
       
        var totalAvatars = tierData.pool.length;
        tierData.tiers.forEach(function(tier) {
            totalAvatars += tier.avatars.length;
        });
       
        if (totalAvatars === 0) {
            alert('没有检测到任何角色数据!');
             return;
             return;
         }
         }
          
          
        var listId = generateUniqueId();
         // 将所有tier中的头像移回头像池
        var timestamp = new Date().toISOString();
         $('.wikitable td .avatar-frame').each(function() {
       
            $(this).removeClass('in-tier');
        var saveData = {
             $('#avatar-pool').append($(this));
            id: listId,
            timestamp: timestamp,
            data: tierData
        };
       
        try {
            localStorage.setItem('tierlist_' + listId, JSON.stringify(saveData));
            console.log('榜单已保存,ID:', listId);
        } catch (e) {
            console.error('保存失败:', e);
            alert('保存失败:' + e.message);
            return;
        }
       
         // 生成分享链接
         var pageUrl = window.location.origin + window.location.pathname;
        var fullUrl = pageUrl + '?tierlist=' + listId;
       
        var $overlay = $('<div>')
            .addClass('tier-dialog-overlay')
            .click(function(e) {
                if (e.target === this) {
                    $(this).remove();
                }
            });
       
        var $dialog = $('<div>').addClass('tier-dialog');
       
        $dialog.html(`
            <h3>🔗 分享榜单</h3>
            <div class="tier-info-box">
                <p><strong>分享链接:</strong></p>
                <input type="text" value="${fullUrl}" readonly id="share-url-input">
                <p style="margin-top: 10px; font-size: 14px; color: #666;">
                    将此链接发送给好友,他们打开后可以看到您的榜单排序。
                </p>
            </div>
            <div class="tier-dialog-buttons">
                <button class="tier-dialog-btn tier-dialog-btn-secondary" onclick="this.closest('.tier-dialog-overlay').remove()">关闭</button>
                <button class="tier-dialog-btn tier-dialog-btn-primary" id="share-copy-btn">复制链接</button>
             </div>
        `);
       
        $overlay.append($dialog);
        $('body').append($overlay);
       
        $('#share-copy-btn').click(function() {
            var $input = $('#share-url-input');
            $input.select();
            document.execCommand('copy');
            showNotification('分享链接已复制!', 'success');
         });
         });
       
        setTimeout(function() {
            $('#share-url-input').select();
        }, 100);
     }
     }
      
      
     function checkUrlForTierList() {
     function saveTierListAsPNG() {
         var urlParams = new URLSearchParams(window.location.search);
         // 检查是否已加载html2canvas库
         var tierlistId = urlParams.get('tierlist');
         if (typeof html2canvas === 'undefined') {
       
             loadHtml2Canvas(function() {
        if (tierlistId) {
                 captureTierList();
             console.log('检测到URL中的榜单ID:', tierlistId);
            });
            setTimeout(function() {
        } else {
                 if (loadTierListData(tierlistId)) {
            captureTierList();
                    showNotification('✅ 已自动加载分享的榜单', 'success');
                } else {
                    showNotification('❌ 无法加载分享的榜单', 'error');
                }
            }, 1500);
         }
         }
    }
   
    function generateUniqueId() {
        return Date.now().toString(36) + Math.random().toString(36).substr(2, 9);
    }
   
    function showNotification(message, type) {
        var $notification = $('<div>')
            .addClass('tier-notification')
            .addClass(type || 'info')
            .text(message);
       
        $('body').append($notification);
       
        setTimeout(function() {
            $notification.fadeOut(300, function() {
                $(this).remove();
            });
        }, 3000);
     }
     }
      
      
     function loadHtml2Canvas(callback) {
     function loadHtml2Canvas(callback) {
         if (typeof html2canvas === 'undefined') {
         mw.loader.using('jquery', function() {
             $.getScript('https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.min.js')
             $.getScript('https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.min.js')
                 .done(function() {
                 .done(function() {
第1,035行: 第268行:
                 })
                 })
                 .fail(function() {
                 .fail(function() {
                     alert('加载html2canvas失败,请检查网络连接');
                     alert('加载截图库失败,请检查网络连接');
                 });
                 });
         } else {
         });
            callback();
        }
     }
     }
      
      
     function captureTierList() {
     function captureTierList() {
         var $table = $('.wikitable').first().clone();
         var $table = $('.wikitable');
          
          
         // 移除空的tier单元格中的占位内容
         if ($table.length === 0) {
        $table.find('td:nth-child(2)').each(function() {
            alert('未找到表格');
            if ($(this).find('.avatar-frame').length === 0) {
             return;
                $(this).empty().css({
         }
                    'min-height': '80px',
                    'background': '#fafafa'
                });
             }
         });
          
          
         // 优化表格样式
         // 显示加载提示
        $table.css({
         var $loading = $('<div>')
            'border-collapse': 'collapse',
            'width': '100%'
        });
       
        $table.find('th, td').css({
            'border': '2px solid #333',
            'padding': '10px'
        });
       
        // 创建临时容器
         var $container = $('<div>')
             .css({
             .css({
                 position: 'fixed',
                 'position': 'fixed',
                 left: '-9999px',
                 'top': '50%',
                 top: '0',
                'left': '50%',
                 background: 'white',
                'transform': 'translate(-50%, -50%)',
                 padding: '30px',
                 'background': 'rgba(0,0,0,0.8)',
                 minWidth: '900px',
                 'color': 'white',
                 fontFamily: 'Arial, sans-serif'
                 'padding': '20px 40px',
                 'border-radius': '10px',
                 'z-index': 9999,
                'font-size': '18px'
             })
             })
             .append($table);
             .text('正在生成图片...')
       
            .appendTo('body');
        $('body').append($container);
          
          
        // 添加标题
         html2canvas($table[0], {
        var $title = $('<h2>')
            .text('我的角色Tier榜单')
            .css({
                textAlign: 'center',
                marginBottom: '20px',
                color: '#333',
                fontSize: '28px',
                fontWeight: 'bold'
            });
       
        // 添加时间戳
        var $timestamp = $('<div>')
            .text('生成时间: ' + new Date().toLocaleString('zh-CN'))
            .css({
                textAlign: 'center',
                marginBottom: '15px',
                color: '#666',
                fontSize: '14px'
            });
       
        $container.prepend($timestamp).prepend($title);
       
         html2canvas($container[0], {
             backgroundColor: '#ffffff',
             backgroundColor: '#ffffff',
             scale: 2,
             scale: 2,
             logging: false,
             logging: false,
             useCORS: true,
             useCORS: true,
             allowTaint: true,
             allowTaint: true
            imageTimeout: 0
         }).then(function(canvas) {
         }).then(function(canvas) {
             $container.remove();
             $loading.remove();
              
              
            // 转换为blob并下载
             canvas.toBlob(function(blob) {
             canvas.toBlob(function(blob) {
                 var url = URL.createObjectURL(blob);
                 var url = URL.createObjectURL(blob);
                 var a = document.createElement('a');
                 var link = document.createElement('a');
                 a.href = url;
                 var timestamp = new Date().toISOString().slice(0,19).replace(/:/g,'-');
                 a.download = 'tierlist_' + Date.now() + '.png';
                 link.download = 'tier-list-' + timestamp + '.png';
                 document.body.appendChild(a);
                 link.href = url;
                 a.click();
                 link.click();
                document.body.removeChild(a);
                 URL.revokeObjectURL(url);
                 URL.revokeObjectURL(url);
               
                showNotification('📸 榜单图片已导出!', 'success');
             });
             });
         }).catch(function(error) {
         }).catch(function(error) {
             $container.remove();
             $loading.remove();
             console.error('导出失败:', error);
             console.error('截图失败:', error);
             alert('导出图片失败:' + error.message);
             alert('生成图片失败,请重试');
         });
         });
     }
     }
 
   
})();
})();

2025年10月8日 (三) 13:29的最新版本

(function() {
    'use strict';
    
    // 仅在 TierListMaker 页面运行
    if (mw.config.get('wgPageName') !== '节奏榜') {
        return;
    }
    
    // 等待页面加载完成
    $(function() {
        initTierListMaker();
    });
    
    function initTierListMaker() {
        // 添加控制按钮
        addControlButtons();
        
        // 初始化拖拽功能
        initDragAndDrop();
        
        // 添加样式
        addCustomStyles();
    }
    
    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();
            });
        
        $buttonContainer.append($saveButton, ' ', $clearButton, ' ', $resetButton);
        $('.wikitable').before($buttonContainer);
    }
    
    function addCustomStyles() {
        var styles = `
            <style>
                .tier-list-save-btn, .tier-list-clear-btn, .tier-list-reset-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;
                }
                
                .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;
                }
            </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 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('生成图片失败,请重试');
        });
    }
    
})();