MediaWiki

Common.js:修订间差异

来自卡厄思梦境WIKI

律Rhyme留言 | 贡献
无编辑摘要
律Rhyme留言 | 贡献
无编辑摘要
 
(未显示同一用户的30个中间版本)
第1行: 第1行:
/* 这里的任何JavaScript将为所有用户在每次页面加载时加载。 */
/* 这里的任何JavaScript将为所有用户在每次页面加载时加载。 */
// 等待 mw 对象加载完成
mw.loader.using(['mediawiki.util'], function() {
   
    // 动态加载 PIXI.js
    function loadScript(url) {
        return new Promise(function(resolve, reject) {
            var script = document.createElement('script');
            script.src = url;
            script.onload = resolve;
            script.onerror = reject;
            document.head.appendChild(script);
        });
    }
   
    // 按顺序加载库
    loadScript('https://cdn.jsdelivr.net/npm/pixi.js@5.3.12/dist/pixi.min.js')
        .then(function() {
            return loadScript('https://cdn.jsdelivr.net/npm/pixi-spine@3.0.12/dist/pixi-spine.js');
        })
        .then(function() {
            console.log('Spine libraries loaded successfully');
            initSpinePlayers();
        })
        .catch(function(error) {
            console.error('Failed to load Spine libraries:', error);
        });
   
    function initSpinePlayers() {
        var containers = document.querySelectorAll('.spine-player-container');
       
        if (containers.length === 0) {
            console.log('No spine containers found');
            return;
        }
       
        containers.forEach(function(container) {
            var skelUrl = container.getAttribute('data-skel');
            var atlasUrl = container.getAttribute('data-atlas');
            var animationName = container.getAttribute('data-animation') || 'idle';
            var skinName = container.getAttribute('data-skin') || 'default';
           
            if (!skelUrl || !atlasUrl) {
                console.error('Missing skel or atlas URL');
                return;
            }
           
            // 创建 PIXI 应用
            var app = new PIXI.Application({
                width: container.clientWidth || 800,
                height: container.clientHeight || 600,
                backgroundColor: 0x2c3e50,
                transparent: false
            });
           
            container.innerHTML = '';
            container.appendChild(app.view);
           
            // 加载 Spine 资源
            app.loader
                .add('spineData', skelUrl)
                .load(function(loader, resources) {
                    try {
                        var animation = new PIXI.spine.Spine(resources.spineData.spineData);
                       
                        // 设置位置和缩放
                        animation.x = app.screen.width / 2;
                        animation.y = app.screen.height / 2;
                        animation.scale.set(0.5);
                       
                        // 播放动画
                        if (animation.state.hasAnimation(animationName)) {
                            animation.state.setAnimation(0, animationName, true);
                        }
                       
                        app.stage.addChild(animation);
                        console.log('Spine animation loaded successfully');
                    } catch(e) {
                        console.error('Error creating spine animation:', e);
                    }
                });
        });
    }
});
/* 卡牌 */
(function () {
    'use strict';
    var initialized = false;
    function show(el) {
        if (el) el.style.display = 'flex';
    }
    function hide(el) {
        if (el) el.style.display = 'none';
    }
    function resetModalView(modal) {
        var originalView = modal.querySelector('.original-card-view');
        var inspirationView = modal.querySelector('.inspiration-view');
        var godView = modal.querySelector('.god-inspiration-view');
        var subcardsView = modal.querySelector('.subcards-view');
        var nestedSubcardsViews = modal.querySelectorAll('.nested-subcards-view');
        var inspirationNestedViews = modal.querySelectorAll('.inspiration-subcards-view');
        var inspirationDeeperNestedViews = modal.querySelectorAll('.inspiration-nested-subcards-view');
        if (originalView) show(originalView);
        if (inspirationView) hide(inspirationView);
        if (godView) hide(godView);
        if (subcardsView) hide(subcardsView);
        nestedSubcardsViews.forEach(hide);
        inspirationNestedViews.forEach(hide);
        inspirationDeeperNestedViews.forEach(hide);
    }
    function closeModal(modal) {
        modal.style.display = 'none';
        document.body.style.overflow = 'auto';
        resetModalView(modal);
    }
    function openModalFromCard(cardWrapper) {
        var cardId = cardWrapper.getAttribute('data-card-id');
        if (!cardId) return;
        var modal = document.getElementById(cardId + '-modal');
        if (!modal) return;
        resetModalView(modal);
        modal.style.display = 'block';
        document.body.style.overflow = 'hidden';
    }
    function handleBackToCard(button) {
        var modal = button.closest('.card-modal');
        if (modal) {
            resetModalView(modal);
        }
    }
    function handleBackToSubcards(button) {
        var modal = button.closest('.card-modal');
        if (!modal) return;
        var nestedView = button.closest('.nested-subcards-view');
        var subcardsView = modal.querySelector('.subcards-view');
        if (nestedView && subcardsView) {
            hide(nestedView);
            show(subcardsView);
        }
    }
    function handleInspirationClick(button) {
        var modal = button.closest('.card-modal');
        if (!modal) return;
        var originalView = modal.querySelector('.original-card-view');
        var inspirationView = modal.querySelector('.inspiration-view');
        if (!originalView || !inspirationView) return;
        hide(originalView);
        show(inspirationView);
    }
    function handleGodInspirationClick(button) {
        var modal = button.closest('.card-modal');
        if (!modal) return;
        var originalView = modal.querySelector('.original-card-view');
        var godView = modal.querySelector('.god-inspiration-view');
        if (!originalView || !godView) return;
        hide(originalView);
        show(godView);
    }
    function handleSubcardsClick(button) {
        var modal = button.closest('.card-modal');
        if (!modal) return;
        var originalView = modal.querySelector('.original-card-view');
        var subcardsView = modal.querySelector('.subcards-view');
        if (!originalView || !subcardsView) return;
        hide(originalView);
        show(subcardsView);
    }
    function handleViewNestedSubcardsClick(button) {
        var modal = button.closest('.card-modal');
        if (!modal) return;
        var subcardIndex = button.getAttribute('data-subcard-index');
        if (!subcardIndex) return;
        var subcardsView = modal.querySelector('.subcards-view');
        var nestedView = modal.querySelector('.nested-subcards-view[data-subcard-index="' + subcardIndex + '"]');
        if (!subcardsView || !nestedView) return;
        hide(subcardsView);
        show(nestedView);
    }
    function handleInspirationSubcardsClick(button) {
        var modal = button.closest('.card-modal');
        if (!modal) return;
        var idx = button.getAttribute('data-variant-index');
        if (!idx) return;
        var inspirationView = modal.querySelector('.inspiration-view');
        var nestedView = modal.querySelector('.inspiration-subcards-view[data-variant-index="' + idx + '"]');
        if (!inspirationView || !nestedView) return;
        hide(inspirationView);
        show(nestedView);
    }
    function handleBackToInspiration(button) {
        var modal = button.closest('.card-modal');
        if (!modal) return;
        var nestedView = button.closest('.inspiration-subcards-view');
        var inspirationView = modal.querySelector('.inspiration-view');
        if (nestedView && inspirationView) {
            hide(nestedView);
            show(inspirationView);
        }
    }
    function handleViewInspirationNestedSubcardsClick(button) {
        var modal = button.closest('.card-modal');
        if (!modal) return;
        var vIdx = button.getAttribute('data-variant-index');
        var sIdx = button.getAttribute('data-subcard-index');
        if (!vIdx || !sIdx) return;
        var subcardsView = modal.querySelector('.inspiration-subcards-view[data-variant-index="' + vIdx + '"]');
        var deeperView = modal.querySelector('.inspiration-nested-subcards-view[data-variant-index="' + vIdx + '"][data-subcard-index="' + sIdx + '"]');
        if (!subcardsView || !deeperView) return;
        hide(subcardsView);
        show(deeperView);
    }
    function handleBackToInspirationSubcards(button) {
        var modal = button.closest('.card-modal');
        if (!modal) return;
        var deeperView = button.closest('.inspiration-nested-subcards-view');
        var vIdx = button.getAttribute('data-variant-index');
        var subcardsView = modal.querySelector('.inspiration-subcards-view[data-variant-index="' + vIdx + '"]');
        if (deeperView && subcardsView) {
            hide(deeperView);
            show(subcardsView);
        }
    }
    function onKeydown(event) {
        if (event.key === 'Escape' || event.keyCode === 27) {
            var modals = document.querySelectorAll('.card-modal');
            modals.forEach(function (modal) {
                if (modal.style.display === 'block') {
                    var inspirationView = modal.querySelector('.inspiration-view');
                    var godView = modal.querySelector('.god-inspiration-view');
                    var subcardsView = modal.querySelector('.subcards-view');
                    var nestedSubcardsViews = modal.querySelectorAll('.nested-subcards-view');
                    var inspirationNestedViews = modal.querySelectorAll('.inspiration-subcards-view');
                    var inspirationDeeperNestedViews = modal.querySelectorAll('.inspiration-nested-subcards-view');
                    var inNestedView = false;
                    nestedSubcardsViews.forEach(function (view) {
                        if (view.style.display !== 'none') {
                            inNestedView = true;
                            hide(view);
                            if (subcardsView) show(subcardsView);
                        }
                    });
                    var inInspirationNested = false;
                    inspirationNestedViews.forEach(function (view) {
                        if (view.style.display !== 'none') {
                            inInspirationNested = true;
                            hide(view);
                            if (inspirationView) show(inspirationView);
                        }
                    });
                    var inInspirationDeeperNested = false;
                    inspirationDeeperNestedViews.forEach(function (view) {
                        if (view.style.display !== 'none') {
                            inInspirationDeeperNested = true;
                            var vIdx = view.getAttribute('data-variant-index');
                            hide(view);
                            var parentSubcardsView = modal.querySelector('.inspiration-subcards-view[data-variant-index="' + vIdx + '"]');
                            if (parentSubcardsView) show(parentSubcardsView);
                        }
                    });
                    if (!inNestedView && !inInspirationNested && !inInspirationDeeperNested) {
                        if ((inspirationView && inspirationView.style.display !== 'none') ||
                            (subcardsView && subcardsView.style.display !== 'none') ||
                            (godView && godView.style.display !== 'none')) {
                            resetModalView(modal);
                        } else {
                            closeModal(modal);
                        }
                    }
                }
            });
        }
    }
    function onDocumentClick(e) {
        // 打开模态:点击卡片缩略图区域
        var cardWrapper = e.target.closest('.card-small-wrapper');
        if (cardWrapper) {
            e.preventDefault();
            e.stopPropagation();
            openModalFromCard(cardWrapper);
            return;
        }
        // 变体/衍生/返回/关闭
        if (e.target.classList.contains('inspiration-button')) {
            e.stopPropagation();
            handleInspirationClick(e.target);
            return;
        }
        if (e.target.classList.contains('god-inspiration-button')) {
            e.stopPropagation();
            handleGodInspirationClick(e.target);
            return;
        }
        if (e.target.classList.contains('subcards-button')) {
            e.stopPropagation();
            handleSubcardsClick(e.target);
            return;
        }
        if (e.target.classList.contains('view-nested-subcards-button')) {
            e.stopPropagation();
            handleViewNestedSubcardsClick(e.target);
            return;
        }
        if (e.target.classList.contains('back-to-card-button')) {
            e.stopPropagation();
            handleBackToCard(e.target);
            return;
        }
        if (e.target.classList.contains('back-to-subcards-button')) {
            e.stopPropagation();
            handleBackToSubcards(e.target);
            return;
        }
        if (e.target.classList.contains('view-insp-subcards-button')) {
            e.stopPropagation();
            handleInspirationSubcardsClick(e.target);
            return;
        }
        if (e.target.classList.contains('back-to-inspiration-button')) {
            e.stopPropagation();
            handleBackToInspiration(e.target);
            return;
        }
        if (e.target.classList.contains('view-insp-nested-subcards-button')) {
            e.stopPropagation();
            handleViewInspirationNestedSubcardsClick(e.target);
            return;
        }
        if (e.target.classList.contains('back-to-insp-subcards-button')) {
            e.stopPropagation();
            handleBackToInspirationSubcards(e.target);
            return;
        }
        // 关闭按钮
        var closeBtn = e.target.classList.contains('modal-close-button')
            ? e.target
            : (e.target.parentElement && e.target.parentElement.classList.contains('modal-close-button') ? e.target.parentElement : null);
        if (closeBtn) {
            var modal = closeBtn.closest('.card-modal');
            if (modal) closeModal(modal);
        }
    }
    function init() {
        if (initialized) return;
        initialized = true;
        document.addEventListener('click', onDocumentClick);
        document.addEventListener('keydown', onKeydown);
    }
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }
    if (typeof mw !== 'undefined' && mw.hook) {
        // 页面增量渲染时确保已初始化(事件委托只需一次)
        mw.hook('wikipage.content').add(function () { init(); });
    }
})();
// 卡牌悬停显示功能
(function () {
    'use strict';
    var hoverTimeout;
    function showCardPopup(linkElement) {
        // 清除之前的超时
        if (hoverTimeout) {
            clearTimeout(hoverTimeout);
        }
        // 检查是否已有弹出框
        var existingPopup = linkElement.querySelector('.card-hover-popup');
        if (existingPopup) {
            return;
        }
        // 查找紧邻的隐藏数据容器
        var dataContainer = linkElement.nextElementSibling;
        if (!dataContainer || !dataContainer.classList.contains('card-link-data')) {
            return;
        }
        // 在隐藏容器中查找卡牌
        var cardWrapper = dataContainer.querySelector('.card-small-wrapper');
        if (!cardWrapper) {
            return;
        }
        // 克隆卡牌
        var clonedCard = cardWrapper.cloneNode(true);
        clonedCard.style.cursor = 'default';
       
        // 移除可能触发模态框的属性和类
        clonedCard.removeAttribute('data-card-id');
        var originalClass = clonedCard.className;
        clonedCard.className = originalClass.replace('card-small-wrapper', 'card-hover-preview');
        // 创建弹出框
        var popup = document.createElement('div');
        popup.className = 'card-hover-popup';
        popup.appendChild(clonedCard);
        // 添加到链接中
        linkElement.appendChild(popup);
    }
    function hideCardPopup(linkElement) {
        hoverTimeout = setTimeout(function () {
            var popup = linkElement.querySelector('.card-hover-popup');
            if (popup) {
                popup.remove();
            }
        }, 100);
    }
    function initCardLinks() {
        var cardLinks = document.querySelectorAll('.card-link');
        cardLinks.forEach(function (link) {
            // 避免重复绑定
            if (link.hasAttribute('data-card-hover-init')) {
                return;
            }
            link.setAttribute('data-card-hover-init', 'true');
            // 添加事件监听器
            link.addEventListener('mouseenter', function () {
                showCardPopup(link);
            });
            link.addEventListener('mouseleave', function () {
                hideCardPopup(link);
            });
        });
    }
    // 初始化
    function init() {
        initCardLinks();
    }
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }
    // MediaWiki 钩子支持
    if (typeof mw !== 'undefined' && mw.hook) {
        mw.hook('wikipage.content').add(init);
    }
})();


/* 切换标签 */
/* 切换标签 */
第172行: 第655行:
         });
         });
     }
     }
});
/* 卡牌 */
(function() {
    // 防止重复初始化
    if (window.cardSystemInitialized) return;
    window.cardSystemInitialized = true;
   
    // 缓存DOM元素
    var overlayCache = null;
    var containerCache = null;
   
    // 保存当前卡牌信息,用于返回
    var currentCardInfo = null;
   
    // 添加历史栈来记录浏览历史
    var viewHistory = [];
   
    // API缓存
    var apiCache = {};
   
    // 预加载队列
    var preloadQueue = new Set();
    var preloadWorker = null;
   
    // 智能缓存管理器
    var cacheManager = {
        maxSize: 100, // 最大缓存数量
        accessTime: {}, // 记录访问时间
       
        set: function(key, value) {
            apiCache[key] = value;
            this.accessTime[key] = Date.now();
           
            // 检查缓存大小
            var keys = Object.keys(apiCache);
            if (keys.length > this.maxSize) {
                // 删除最久未使用的缓存
                var oldestKey = keys[0];
                var oldestTime = this.accessTime[oldestKey] || 0;
               
                for (var i = 1; i < keys.length; i++) {
                    var time = this.accessTime[keys[i]] || 0;
                    if (time < oldestTime) {
                        oldestKey = keys[i];
                        oldestTime = time;
                    }
                }
               
                delete apiCache[oldestKey];
                delete this.accessTime[oldestKey];
            }
        },
       
        get: function(key) {
            if (apiCache[key]) {
                this.accessTime[key] = Date.now();
                return apiCache[key];
            }
            return null;
        }
    };
   
    // 添加Loading动画CSS
    function addLoadingStyles() {
        if (!document.getElementById('card-loading-styles')) {
            var style = document.createElement('style');
            style.id = 'card-loading-styles';
            style.textContent = `
                @keyframes spin {
                    0% { transform: rotate(0deg); }
                    100% { transform: rotate(360deg); }
                }
                @keyframes fadeIn {
                    from { opacity: 0; }
                    to { opacity: 1; }
                }
                .card-fade-in {
                    animation: fadeIn 0.3s ease-in;
                }
            `;
            document.head.appendChild(style);
        }
    }
   
    // 创建loading占位符
    function createLoadingPlaceholder(text, scale) {
        var placeholder = document.createElement('div');
        placeholder.className = 'card-loading';
       
        var baseStyle = 'width: 168px; height: 230px; background: rgba(255,255,255,0.1); border: 2px dashed rgba(255,255,255,0.3); border-radius: 8px; display: flex; align-items: center; justify-content: center; color: white;';
       
        if (scale) {
            baseStyle += ' transform: scale(' + scale + '); transform-origin: center center;';
        }
       
        placeholder.style.cssText = baseStyle;
        placeholder.innerHTML = '<div style="text-align: center;">' +
            '<div class="loading-spinner" style="border: 3px solid rgba(255,255,255,0.3); border-top: 3px solid white; border-radius: 50%; width: 30px; height: 30px; animation: spin 1s linear infinite; margin: 0 auto 10px;"></div>' +
            '<div style="font-size: 12px;">' + (text || '加载中...') + '</div>' +
            '</div>';
        return placeholder;
    }
   
    // 预加载管理器
    function preloadCardData(character, cardName, deckType) {
        var cacheKey = character + '|' + cardName + '|' + (deckType || '');
       
        if (!cacheManager.get(cacheKey) && !preloadQueue.has(cacheKey)) {
            preloadQueue.add(cacheKey);
           
            if (!preloadWorker) {
                preloadWorker = setTimeout(processPreloadQueue, 100);
            }
        }
    }
   
    // 批量处理预加载队列
    function processPreloadQueue() {
        preloadWorker = null;
       
        if (preloadQueue.size === 0) return;
       
        var batch = Array.from(preloadQueue).slice(0, 5); // 每批处理5个
        batch.forEach(function(key) {
            preloadQueue.delete(key);
        });
       
        batch.forEach(function(cacheKey) {
            var parts = cacheKey.split('|');
            fetchCardHTML(parts[0], parts[1], parts[2], function() {
                // 预加载完成,数据已缓存
            });
        });
       
        // 如果还有剩余,继续处理
        if (preloadQueue.size > 0) {
            preloadWorker = setTimeout(processPreloadQueue, 200);
        }
    }
   
    // 创建遮罩层和容器
    function createCardOverlay() {
        if (overlayCache && containerCache) {
            return { overlay: overlayCache, container: containerCache };
        }
       
        // 创建遮罩
        var overlay = document.createElement('div');
        overlay.id = 'card-overlay';
        overlay.style.cssText = 'display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.8); z-index: 9999; overflow-y: auto;';
       
        // 创建容器
        var container = document.createElement('div');
        container.id = 'card-display-container';
        container.style.cssText = 'position: relative; min-height: 100vh; padding: 40px 20px; display: flex; align-items: center; justify-content: center;';
        overlay.appendChild(container);
        document.body.appendChild(overlay);
       
        // 点击遮罩关闭
        overlay.addEventListener('click', function(e) {
            if (e.target === overlay) {
                closeCardDisplay();
            }
        });
       
        overlayCache = overlay;
        containerCache = container;
       
        return { overlay: overlay, container: container };
    }
   
    // 创建关闭按钮
    function createCloseButton() {
        var closeBtn = document.createElement('div');
        closeBtn.style.cssText = 'position: fixed; top: 20px; right: 20px; width: 40px; height: 40px; background: rgba(255,255,255,0.1); border: 2px solid white; border-radius: 50%; cursor: pointer; display: flex; align-items: center; justify-content: center; z-index: 10001; transition: all 0.3s;';
        closeBtn.innerHTML = '<span style="color: white; font-size: 24px; font-weight: bold; line-height: 1;">×</span>';
        closeBtn.onmouseover = function() {
            this.style.background = 'rgba(255,255,255,0.2)';
            this.style.transform = 'scale(1.1)';
        };
        closeBtn.onmouseout = function() {
            this.style.background = 'rgba(255,255,255,0.1)';
            this.style.transform = 'scale(1)';
        };
        closeBtn.onclick = function() {
            closeCardDisplay();
        };
        return closeBtn;
    }
   
    // 关闭卡牌展示
    function closeCardDisplay() {
        var overlay = document.getElementById('card-overlay');
        if (overlay) {
            overlay.style.display = 'none';
            var container = overlay.querySelector('#card-display-container');
            if (container) {
                container.innerHTML = '';
            }
        }
        currentCardInfo = null;
        viewHistory = []; // 清空历史栈
    }
   
    // 返回上一层
    function goBack() {
        if (viewHistory.length > 1) {
            // 移除当前视图
            viewHistory.pop();
            // 获取上一个视图
            var previousView = viewHistory.pop();
            // 根据视图类型重新渲染
            if (previousView.type === 'enlarged') {
                showEnlargedCard(previousView.data.element, false); // false 表示不添加到历史
            } else if (previousView.type === 'derivedCards') {
                showAllDerivedCards(previousView.data.character, previousView.data.derivedCardsList, false);
            } else if (previousView.type === 'variantCards') {
                showVariantCards(previousView.data.character, previousView.data.cardName, previousView.data.variantType, false);
            }
        } else if (viewHistory.length === 1) {
            // 只剩一层,关闭弹窗
            closeCardDisplay();
        }
    }
   
    // 获取卡牌HTML
    function fetchCardHTML(character, cardName, deckType, callback) {
        var cacheKey = character + '|' + cardName + '|' + (deckType || '');
       
        // 检查缓存
        var cached = cacheManager.get(cacheKey);
        if (cached) {
            callback(cached);
            return;
        }
       
        var api = new mw.Api();
        var wikitext = '{{#invoke:卡牌|main|' + character + '|' + cardName + '|' + (deckType || '') + '}}';
       
        api.parse(wikitext).done(function(html) {
            cacheManager.set(cacheKey, html);
            callback(html);
        }).fail(function() {
            callback('<div style="color: white;">加载失败</div>');
        });
    }
   
    // 批量获取卡牌HTML
    function fetchCardHTMLBatch(requests, callback) {
        var results = {};
        var pending = [];
       
        // 先检查缓存
        requests.forEach(function(req) {
            var cacheKey = req.character + '|' + req.cardName + '|' + (req.deckType || '');
            var cached = cacheManager.get(cacheKey);
           
            if (cached) {
                results[cacheKey] = cached;
            } else {
                pending.push(req);
            }
        });
       
        // 如果全部都有缓存,直接返回
        if (pending.length === 0) {
            callback(results);
            return;
        }
       
        // 批量请求未缓存的
        var completed = 0;
        pending.forEach(function(req) {
            fetchCardHTML(req.character, req.cardName, req.deckType, function(html) {
                var cacheKey = req.character + '|' + req.cardName + '|' + (req.deckType || '');
                results[cacheKey] = html;
                completed++;
               
                if (completed === pending.length) {
                    callback(results);
                }
            });
        });
    }
   
    // 检查卡牌变体
    function checkCardVariants(character, cardName, callback) {
        var variants = { lingguang: false, shenguang: false };
        var checkCount = 0;
        var totalChecks = 2;
       
        function checkComplete() {
            checkCount++;
            if (checkCount === totalChecks) {
                callback(variants);
            }
        }
       
        // 并行检查两种变体
        fetchCardHTML(character, cardName, '灵光一闪', function(html) {
            if (html && !html.includes('找不到卡组')) {
                variants.lingguang = true;
            }
            checkComplete();
        });
       
        fetchCardHTML(character, cardName, '神之一闪', function(html) {
            if (html && !html.includes('找不到卡组')) {
                variants.shenguang = true;
            }
            checkComplete();
        });
    }
   
    // 放大显示卡牌
    function showEnlargedCard(cardElement, addToHistory) {
        if (addToHistory !== false) {
            addToHistory = true;
        }
       
        var elements = createCardOverlay();
        var container = elements.container;
        var cardName = cardElement.dataset.cardName;
        var character = cardElement.dataset.character;
        var deckType = cardElement.dataset.deckType;
        var derivedCards = cardElement.dataset.derivedCards;
        var hasMechanism = cardElement.dataset.hasMechanism === 'true';
       
        // 添加Loading样式
        addLoadingStyles();
       
        // 保存当前卡牌信息
        currentCardInfo = {
            element: cardElement,
            cardName: cardName,
            character: character,
            deckType: deckType,
            derivedCards: derivedCards
        };
       
        // 添加到历史栈
        if (addToHistory) {
            viewHistory.push({
                type: 'enlarged',
                data: currentCardInfo
            });
        }
       
        // 重置容器样式
        container.style.cssText = 'position: relative; min-height: 100vh; padding: 40px 20px; display: flex; align-items: center; justify-content: center;';
       
        // 创建内容包装器
        var contentWrapper = document.createElement('div');
        contentWrapper.style.cssText = 'display: flex; align-items: flex-start; gap: 0px; position: relative;';
       
        // 立即显示主卡牌(从已有元素克隆)
        var centerContainer = document.createElement('div');
        centerContainer.style.cssText = 'display: flex; flex-direction: column; align-items: center; gap: 0px;';
       
        var mainCardContainer = document.createElement('div');
        mainCardContainer.style.cssText = 'width: 336px; height: 460px; display: flex; align-items: center; justify-content: center; position: relative;';
       
        var cardInner = document.createElement('div');
        cardInner.style.cssText = 'transform: scale(2); position: relative;';
       
        var enlargedCard = cardElement.cloneNode(true);
        enlargedCard.style.width = '168px';
        enlargedCard.style.height = '230px';
        enlargedCard.style.cursor = 'default';
        enlargedCard.style.position = 'relative';
        enlargedCard.style.display = 'block';
        enlargedCard.onclick = null;
        enlargedCard.classList.add('card-fade-in');
       
        cardInner.appendChild(enlargedCard);
        mainCardContainer.appendChild(cardInner);
        centerContainer.appendChild(mainCardContainer);
       
        // 处理衍生卡牌(左侧)
        if (derivedCards && derivedCards.trim() !== '') {
            var leftContainer = document.createElement('div');
            leftContainer.style.cssText = 'display: flex; flex-direction: column; gap: 0px; align-items: center;';
           
            var derivedCardsList = derivedCards.split('、');
           
            var derivedCardWrapper = document.createElement('div');
            derivedCardWrapper.style.cssText = 'width: 252px; height: 345px; display: flex; align-items: center; justify-content: center;';
           
            // 先显示占位符
            var placeholder = createLoadingPlaceholder('加载衍生卡牌...', 1.5);
            derivedCardWrapper.appendChild(placeholder);
            leftContainer.appendChild(derivedCardWrapper);
           
            // 异步加载衍生卡牌
            fetchCardHTML(character, derivedCardsList[0].trim(), '', function(html) {
                var firstDerivedCard = document.createElement('div');
                firstDerivedCard.id = 'derived-cards-display';
                firstDerivedCard.style.cssText = 'transform: scale(1.5); transform-origin: center center; opacity: 0;';
                firstDerivedCard.innerHTML = html;
               
                var cards = firstDerivedCard.querySelectorAll('.game-card');
                cards.forEach(function(card) {
                    card.style.cursor = 'default';
                    card.onclick = function(e) {
                        e.stopPropagation();
                        e.preventDefault();
                    };
                });
               
                derivedCardWrapper.removeChild(placeholder);
                derivedCardWrapper.appendChild(firstDerivedCard);
               
                // 淡入动画
                setTimeout(function() {
                    firstDerivedCard.style.transition = 'opacity 0.3s';
                    firstDerivedCard.style.opacity = '1';
                }, 10);
            });
           
            // 如果有多个衍生卡牌,添加查看全部按钮
            if (derivedCardsList.length > 1) {
                var viewAllBtn = document.createElement('div');
                viewAllBtn.style.cssText = 'padding: 10px 20px; background: linear-gradient(135deg, #4a90e2, #357abd); color: white; border-radius: 6px; cursor: pointer; white-space: nowrap; font-weight: bold; box-shadow: 0 2px 8px rgba(0,0,0,0.3); transition: transform 0.2s; margin-top: 0px;';
                viewAllBtn.textContent = '查看所有衍生卡牌';
                viewAllBtn.onmouseover = function() { this.style.transform = 'scale(1.05)'; };
                viewAllBtn.onmouseout = function() { this.style.transform = 'scale(1)'; };
                viewAllBtn.onclick = function() {
                    showAllDerivedCards(character, derivedCardsList);
                };
                leftContainer.appendChild(viewAllBtn);
            }
           
            contentWrapper.appendChild(leftContainer);
        }
       
        // 创建按钮容器(异步检查变体)
        var buttonsContainer = document.createElement('div');
        buttonsContainer.style.cssText = 'display: flex; gap: 15px; white-space: nowrap; min-height: 50px; align-items: center; justify-content: center;';
       
        // 添加loading指示器
        var checkingVariants = document.createElement('div');
        checkingVariants.style.cssText = 'color: rgba(255,255,255,0.5); font-size: 12px;';
        checkingVariants.textContent = '检查变体卡牌...';
        buttonsContainer.appendChild(checkingVariants);
        centerContainer.appendChild(buttonsContainer);
       
        // 异步检查变体
        checkCardVariants(character, cardName, function(variants) {
            buttonsContainer.removeChild(checkingVariants);
           
            if (variants.lingguang) {
                var lingguangBtn = document.createElement('div');
                lingguangBtn.style.cssText = 'padding: 10px 30px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; border-radius: 6px; cursor: pointer; font-weight: bold; box-shadow: 0 2px 8px rgba(0,0,0,0.3); transition: transform 0.2s; white-space: nowrap; min-width: 120px; text-align: center; opacity: 0;';
                lingguangBtn.textContent = '灵光一闪';
                lingguangBtn.onmouseover = function() { this.style.transform = 'scale(1.05)'; };
                lingguangBtn.onmouseout = function() { this.style.transform = 'scale(1)'; };
                lingguangBtn.onclick = function() {
                    showVariantCards(character, cardName, '灵光一闪');
                };
                buttonsContainer.appendChild(lingguangBtn);
               
                // 淡入动画
                setTimeout(function() {
                    lingguangBtn.style.transition = 'opacity 0.3s';
                    lingguangBtn.style.opacity = '1';
                }, 10);
            }
           
            if (variants.shenguang) {
                var shenguangBtn = document.createElement('div');
                shenguangBtn.style.cssText = 'padding: 10px 30px; background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); color: white; border-radius: 6px; cursor: pointer; font-weight: bold; box-shadow: 0 2px 8px rgba(0,0,0,0.3); transition: transform 0.2s; white-space: nowrap; min-width: 120px; text-align: center; opacity: 0;';
                shenguangBtn.textContent = '神之一闪';
                shenguangBtn.onmouseover = function() { this.style.transform = 'scale(1.05)'; };
                shenguangBtn.onmouseout = function() { this.style.transform = 'scale(1)'; };
                shenguangBtn.onclick = function() {
                    showVariantCards(character, cardName, '神之一闪');
                };
                buttonsContainer.appendChild(shenguangBtn);
               
                // 淡入动画
                setTimeout(function() {
                    shenguangBtn.style.transition = 'opacity 0.3s';
                    shenguangBtn.style.opacity = '1';
                }, 10);
            }
           
            // 如果没有变体,移除按钮容器
            if (!variants.lingguang && !variants.shenguang) {
                centerContainer.removeChild(buttonsContainer);
            }
        });
       
        contentWrapper.appendChild(centerContainer);
       
        // 添加右侧机制说明
        if (hasMechanism) {
            var mechanismContainer = cardElement.nextElementSibling;
            if (mechanismContainer && mechanismContainer.classList.contains('mechanism-container')) {
                var mechanismDisplay = document.createElement('div');
                mechanismDisplay.style.cssText = 'display: flex; flex-direction: column; gap: 0px; max-width: 320px; min-width: 280px;';
                mechanismDisplay.innerHTML = mechanismContainer.innerHTML;
                mechanismDisplay.style.display = 'flex';
               
                contentWrapper.appendChild(mechanismDisplay);
            }
        }
       
        container.innerHTML = '';
        container.appendChild(contentWrapper);
        container.appendChild(createCloseButton());
       
        elements.overlay.style.display = 'block';
    }
   
    // 显示所有衍生卡牌
    function showAllDerivedCards(character, derivedCardsList, addToHistory) {
        if (addToHistory !== false) {
            addToHistory = true;
        }
       
        var overlay = document.getElementById('card-overlay');
        var container = document.getElementById('card-display-container');
       
        // 添加到历史栈
        if (addToHistory) {
            viewHistory.push({
                type: 'derivedCards',
                data: {
                    character: character,
                    derivedCardsList: derivedCardsList
                }
            });
        }
       
        // 清空当前内容
        container.innerHTML = '';
        container.style.cssText = 'position: relative; padding: 40px; min-height: 100vh; display: flex; flex-direction: column; align-items: center; justify-content: center;';
       
        // 创建标题
        var title = document.createElement('div');
        title.style.cssText = 'color: white; font-size: 28px; font-weight: bold; margin-bottom: 30px; text-align: center;';
        title.textContent = '衍生卡牌';
        container.appendChild(title);
       
        // 创建卡牌容器
        var cardsContainer = document.createElement('div');
        cardsContainer.style.cssText = 'display: flex; flex-wrap: wrap; gap: 30px; justify-content: center; max-width: 1400px; transform: scale(1.5); transform-origin: center center; padding: 40px;';
       
        // 先添加占位符
        var uniqueCards = [...new Set(derivedCardsList.map(function(name) { return name.trim(); }))];
        var placeholders = [];
       
        uniqueCards.forEach(function() {
            var placeholder = createLoadingPlaceholder('加载中...', null);
            placeholders.push(placeholder);
            cardsContainer.appendChild(placeholder);
        });
       
        container.appendChild(cardsContainer);
       
        // 批量加载卡牌
        var requests = uniqueCards.map(function(cardName) {
            return { character: character, cardName: cardName, deckType: '' };
        });
       
        fetchCardHTMLBatch(requests, function(results) {
            uniqueCards.forEach(function(cardName, index) {
                var cacheKey = character + '|' + cardName + '|';
                var html = results[cacheKey];
               
                if (html) {
                    var cardWrapper = document.createElement('div');
                    cardWrapper.style.cssText = 'opacity: 0;';
                    cardWrapper.innerHTML = html;
                   
                    var cards = cardWrapper.querySelectorAll('.game-card');
                    cards.forEach(function(card) {
                        card.style.cursor = 'default';
                        card.onclick = function(e) {
                            e.stopPropagation();
                            e.preventDefault();
                        };
                       
                        // 检查是否有衍生卡牌
                        var derivedCards = card.dataset.derivedCards;
                        if (derivedCards && derivedCards.trim() !== '') {
                            var buttonContainer = document.createElement('div');
                            buttonContainer.style.cssText = 'display: flex; flex-direction: column; align-items: center; gap: 10px;';
                           
                            var cardContainer = document.createElement('div');
                            cardContainer.appendChild(card.cloneNode(true));
                            buttonContainer.appendChild(cardContainer);
                           
                            var viewDerivedBtn = document.createElement('div');
                            viewDerivedBtn.style.cssText = 'padding: 8px 15px; background: linear-gradient(135deg, #4a90e2, #357abd); color: white; border-radius: 6px; cursor: pointer; white-space: nowrap; font-weight: bold; box-shadow: 0 2px 8px rgba(0,0,0,0.3); transition: transform 0.2s; font-size: 12px;';
                            viewDerivedBtn.textContent = '查看衍生卡牌';
                            viewDerivedBtn.onmouseover = function() { this.style.transform = 'scale(1.05)'; };
                            viewDerivedBtn.onmouseout = function() { this.style.transform = 'scale(1)'; };
                            viewDerivedBtn.onclick = function(e) {
                                e.stopPropagation();
                                showAllDerivedCards(character, derivedCards.split('、'));
                            };
                           
                            buttonContainer.appendChild(viewDerivedBtn);
                           
                            // 替换占位符
                            cardsContainer.replaceChild(buttonContainer, placeholders[index]);
                           
                            // 淡入动画
                            setTimeout(function() {
                                buttonContainer.style.transition = 'opacity 0.3s';
                                buttonContainer.style.opacity = '1';
                            }, 10);
                        } else {
                            // 替换占位符
                            cardsContainer.replaceChild(card, placeholders[index]);
                           
                            // 淡入动画
                            setTimeout(function() {
                                card.style.transition = 'opacity 0.3s';
                                card.style.opacity = '1';
                            }, 10);
                        }
                    });
                }
            });
        });
       
        // 添加返回按钮
        var backBtn = document.createElement('div');
        backBtn.style.cssText = 'position: fixed; top: 20px; left: 20px; padding: 10px 20px; background: linear-gradient(135deg, #4a90e2, #357abd); color: white; border-radius: 6px; cursor: pointer; font-weight: bold; box-shadow: 0 2px 8px rgba(0,0,0,0.3); z-index: 10001; transition: transform 0.2s;';
        backBtn.textContent = '← 返回';
        backBtn.onmouseover = function() { this.style.transform = 'scale(1.05)'; };
        backBtn.onmouseout = function() { this.style.transform = 'scale(1)'; };
        backBtn.onclick = function() {
            goBack();
        };
        container.appendChild(backBtn);
       
        // 添加关闭按钮
        container.appendChild(createCloseButton());
    }
   
    // 显示变体卡牌
    function showVariantCards(character, cardName, variantType, addToHistory) {
        if (addToHistory !== false) {
            addToHistory = true;
        }
       
        var overlay = document.getElementById('card-overlay');
        var container = document.getElementById('card-display-container');
       
        // 添加到历史栈
        if (addToHistory) {
            viewHistory.push({
                type: 'variantCards',
                data: {
                    character: character,
                    cardName: cardName,
                    variantType: variantType
                }
            });
        }
       
        // 重置容器样式
        container.style.cssText = 'position: relative; padding: 40px; min-height: 100vh; display: flex; flex-direction: column; align-items: center; justify-content: center;';
        container.innerHTML = '';
       
        // 创建标题
        var title = document.createElement('div');
        title.style.cssText = 'color: white; font-size: 28px; font-weight: bold; margin-bottom: 30px; text-align: center; background: linear-gradient(135deg, #667eea, #764ba2); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text;';
        title.textContent = cardName + ' - ' + variantType;
        container.appendChild(title);
        // 创建卡牌容器
        var cardsContainer = document.createElement('div');
        cardsContainer.style.cssText = 'display: flex; flex-wrap: nowrap; gap: 0px; justify-content: center; max-width: 1400px; overflow-x: auto; padding: 40px; transform: scale(1.5); transform-origin: center center;';
       
        // 先添加loading占位符
        var loadingPlaceholder = createLoadingPlaceholder('加载变体卡牌...', null);
        cardsContainer.appendChild(loadingPlaceholder);
        container.appendChild(cardsContainer);
       
        // 加载变体卡牌
        fetchCardHTML(character, cardName, variantType, function(html) {
            var tempContainer = document.createElement('div');
            tempContainer.innerHTML = html;
           
            // 移除loading占位符
            cardsContainer.removeChild(loadingPlaceholder);
           
            // 处理所有卡牌
            var cards = tempContainer.querySelectorAll('.game-card');
           
            cards.forEach(function(card, index) {
                card.style.cursor = 'default';
                card.onclick = null;
                card.style.flexShrink = '0';
                card.style.opacity = '0';
               
                // 获取衍生卡牌数据
                var derivedCards = card.getAttribute('data-derived-cards');
               
                // 更严格的检查
                var hasDerivedCards = false;
                if (derivedCards !== null && derivedCards !== undefined) {
                    var trimmedValue = String(derivedCards).trim();
                    if (trimmedValue.length > 0 &&
                        trimmedValue !== 'undefined' &&
                        trimmedValue !== 'null' &&
                        trimmedValue !== 'false' &&
                        trimmedValue !== '0') {
                        hasDerivedCards = true;
                    }
                }
               
                if (hasDerivedCards) {
                    // 创建包装器,包含卡牌和按钮
                    var cardWrapper = document.createElement('div');
                    cardWrapper.style.cssText = 'display: flex; flex-direction: column; align-items: center; gap: 10px; flex-shrink: 0; opacity: 0;';
                   
                    // 添加卡牌
                    var cardClone = card.cloneNode(true);
                    cardClone.style.cursor = 'default';
                    cardClone.onclick = null;
                    cardClone.style.opacity = '1';
                    cardWrapper.appendChild(cardClone);
                   
                    // 创建查看衍生卡牌按钮
                    var viewDerivedBtn = document.createElement('div');
                    viewDerivedBtn.style.cssText = 'padding: 8px 15px; background: linear-gradient(135deg, #4a90e2, #357abd); color: white; border-radius: 6px; cursor: pointer; white-space: nowrap; font-weight: bold; box-shadow: 0 2px 8px rgba(0,0,0,0.3); transition: transform 0.2s; font-size: 12px;';
                    viewDerivedBtn.textContent = '查看衍生卡牌';
                    viewDerivedBtn.onmouseover = function() { this.style.transform = 'scale(1.05)'; };
                    viewDerivedBtn.onmouseout = function() { this.style.transform = 'scale(1)'; };
                   
                    // 保存衍生卡牌信息
                    viewDerivedBtn.setAttribute('data-derived-list', derivedCards);
                    viewDerivedBtn.onclick = function(e) {
                        e.stopPropagation();
                        var derivedList = this.getAttribute('data-derived-list');
                        showAllDerivedCards(character, derivedList.split('、'));
                    };
                   
                    cardWrapper.appendChild(viewDerivedBtn);
                    cardsContainer.appendChild(cardWrapper);
                   
                    // 淡入动画
                    setTimeout(function() {
                        cardWrapper.style.transition = 'opacity 0.3s';
                        cardWrapper.style.opacity = '1';
                    }, 50 * index);
                } else {
                    // 没有衍生卡牌,直接添加卡牌
                    cardsContainer.appendChild(card);
                   
                    // 淡入动画
                    setTimeout(function() {
                        card.style.transition = 'opacity 0.3s';
                        card.style.opacity = '1';
                    }, 50 * index);
                }
            });
        });
       
        // 添加返回按钮
        var backBtn = document.createElement('div');
        backBtn.style.cssText = 'position: fixed; top: 20px; left: 20px; padding: 10px 20px; background: linear-gradient(135deg, #4a90e2, #357abd); color: white; border-radius: 6px; cursor: pointer; font-weight: bold; box-shadow: 0 2px 8px rgba(0,0,0,0.3); z-index: 10001; transition: transform 0.2s;';
        backBtn.textContent = '← 返回';
        backBtn.onmouseover = function() { this.style.transform = 'scale(1.05)'; };
        backBtn.onmouseout = function() { this.style.transform = 'scale(1)'; };
        backBtn.onclick = function() {
            goBack();
        };
        container.appendChild(backBtn);
       
        // 添加关闭按钮
        container.appendChild(createCloseButton());
    }
   
    // 鼠标悬停时预加载
    function initPreloadEvents() {
        var preloadTimeout = null;
       
        document.addEventListener('mouseover', function(e) {
            var card = e.target.closest('.game-card');
            if (card && !card.closest('#card-overlay')) {
                // 延迟200ms开始预加载,避免快速移动时的无效预加载
                clearTimeout(preloadTimeout);
                preloadTimeout = setTimeout(function() {
                    var character = card.dataset.character;
                    var cardName = card.dataset.cardName;
                    var derivedCards = card.dataset.derivedCards;
                   
                    if (!character || !cardName) return;
                   
                    // 预加载变体
                    preloadCardData(character, cardName, '灵光一闪');
                    preloadCardData(character, cardName, '神之一闪');
                   
                    // 预加载衍生卡牌(最多预加载前3张)
                    if (derivedCards && derivedCards.trim() !== '') {
                        var cardsList = derivedCards.split('、');
                        var preloadCount = Math.min(3, cardsList.length);
                        for (var i = 0; i < preloadCount; i++) {
                            preloadCardData(character, cardsList[i].trim(), '');
                        }
                    }
                }, 200);
            }
        });
       
        document.addEventListener('mouseout', function(e) {
            var card = e.target.closest('.game-card');
            if (card && !card.closest('#card-overlay')) {
                clearTimeout(preloadTimeout);
            }
        });
    }
   
    // 初始化卡牌点击事件
    function initCardClickEvents() {
        // 使用事件委托
        document.addEventListener('click', function(e) {
            var card = e.target.closest('.game-card');
            if (card && !card.closest('#card-overlay')) {
                e.preventDefault();
                showEnlargedCard(card);
            }
        });
       
        // 添加预加载事件
        initPreloadEvents();
       
        // 添加Loading样式
        addLoadingStyles();
       
        // 页面加载完成后,预加载可见卡牌的相关数据
        setTimeout(function() {
            var visibleCards = document.querySelectorAll('.game-card:not(#card-overlay .game-card)');
            var preloadList = [];
           
            visibleCards.forEach(function(card, index) {
                // 只预加载前10张可见卡牌
                if (index >= 10) return;
               
                var character = card.dataset.character;
                var cardName = card.dataset.cardName;
               
                if (character && cardName) {
                    preloadList.push({ character: character, cardName: cardName });
                }
            });
           
            // 分批预加载
            preloadList.forEach(function(item, index) {
                setTimeout(function() {
                    preloadCardData(item.character, item.cardName, '灵光一闪');
                    preloadCardData(item.character, item.cardName, '神之一闪');
                }, index * 100); // 每100ms预加载一个
            });
        }, 2000); // 页面加载2秒后开始预加载
    }
   
    // 添加键盘快捷键支持
    function initKeyboardShortcuts() {
        document.addEventListener('keydown', function(e) {
            var overlay = document.getElementById('card-overlay');
            if (overlay && overlay.style.display !== 'none') {
                if (e.key === 'Escape') {
                    e.preventDefault();
                    closeCardDisplay();
                } else if (e.key === 'Backspace' || e.key === 'ArrowLeft') {
                    e.preventDefault();
                    goBack();
                }
            }
        });
    }
   
    // 优化滚动性能
    function optimizeScrollPerformance() {
        var scrollTimeout;
        var overlay = document.getElementById('card-overlay');
       
        if (overlay) {
            overlay.addEventListener('scroll', function() {
                if (!overlay.classList.contains('is-scrolling')) {
                    overlay.classList.add('is-scrolling');
                }
               
                clearTimeout(scrollTimeout);
                scrollTimeout = setTimeout(function() {
                    overlay.classList.remove('is-scrolling');
                }, 150);
            });
        }
    }
   
    // 添加性能监控
    function addPerformanceMonitoring() {
        if (window.performance && window.performance.mark) {
            // 监控API调用时间
            var originalFetch = fetchCardHTML;
            fetchCardHTML = function(character, cardName, deckType, callback) {
                var startMark = 'fetch-start-' + Date.now();
                var endMark = 'fetch-end-' + Date.now();
               
                performance.mark(startMark);
               
                originalFetch(character, cardName, deckType, function(result) {
                    performance.mark(endMark);
                    performance.measure('API Call: ' + cardName, startMark, endMark);
                    callback(result);
                });
            };
        }
    }
   
    // 清理函数
    function cleanup() {
        // 清理大型缓存
        if (Object.keys(apiCache).length > cacheManager.maxSize * 1.5) {
            var keys = Object.keys(apiCache);
            var toDelete = keys.length - cacheManager.maxSize;
           
            // 根据访问时间排序
            keys.sort(function(a, b) {
                return (cacheManager.accessTime[a] || 0) - (cacheManager.accessTime[b] || 0);
            });
           
            // 删除最旧的条目
            for (var i = 0; i < toDelete; i++) {
                delete apiCache[keys[i]];
                delete cacheManager.accessTime[keys[i]];
            }
        }
    }
   
    // 定期清理(每5分钟)
    setInterval(cleanup, 5 * 60 * 1000);
   
    // 页面加载完成后初始化
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', function() {
            initCardClickEvents();
            initKeyboardShortcuts();
            optimizeScrollPerformance();
           
            // 仅在开发环境启用性能监控
            if (window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1') {
                addPerformanceMonitoring();
            }
        });
    } else {
        initCardClickEvents();
        initKeyboardShortcuts();
        optimizeScrollPerformance();
       
        // 仅在开发环境启用性能监控
        if (window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1') {
            addPerformanceMonitoring();
        }
    }
})();
/* 卡牌文字滚动 */
(function() {
    'use strict';
   
    function initCardScroll() {
        var cards = document.querySelectorAll('.game-card.card-description-scrollable');
       
        cards.forEach(function(card) {
            var scrollContainer = card.querySelector('.card-description-scroll');
            var scrollInner = card.querySelector('.card-description-scroll-inner');
            var scrollText = card.querySelector('.card-description-text');
           
            if (!scrollContainer || !scrollInner || !scrollText) {
                return;
            }
           
            // 强制触发重绘
            scrollInner.style.display = 'none';
            scrollInner.offsetHeight; // 触发重排
            scrollInner.style.display = 'block';
        });
    }
   
    // 延迟初始化,确保DOM完全加载
    function delayedInit() {
        setTimeout(initCardScroll, 100);
        setTimeout(initCardScroll, 500);
        setTimeout(initCardScroll, 1000);
    }
   
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', delayedInit);
    } else {
        delayedInit();
    }
   
})();
/* 卡牌Tooltip */
$(function() {
  // 初始化所有卡牌悬浮
  function initCardHoverElements() {
    $('.card-hover-container').each(function() {
      var $container = $(this);
     
      // 只初始化尚未处理的元素
      if ($container.data('initialized')) return;
     
      $container.data('initialized', true);
     
      // 获取卡牌数据
      var character = $container.data('character');
      var cardName = $container.data('card');
      var deckType = $container.data('deck') || '';
      var index = $container.data('index') || 0;
      var $popup = $container.find('.card-popup');
     
      // 预加载卡牌数据
      $container.on('mouseenter', function() {
        // 如果卡牌数据已经加载过,直接显示
        if ($popup.data('loaded')) {
          // 调整位置到右下方
          positionCardPopup($container);
          return;
        }
       
        // 加载卡牌数据
        var params = {
          action: 'parse',
          text: '{{#invoke:卡牌|main|' + character + '|' + cardName + '|' + deckType + '|' + index + '}}',
          prop: 'text',
          disablelimitreport: true,
          format: 'json'
        };
       
        $.ajax({
          url: mw.util.wikiScript('api'),
          data: params,
          dataType: 'json',
          success: function(data) {
            if (data && data.parse && data.parse.text) {
              var cardHtml = data.parse.text['*'];
              $popup.html(cardHtml).data('loaded', true);
             
              // 调整位置到右下方
              positionCardPopup($container);
            }
          },
          error: function() {
            $popup.html('<div style="color: #721c24;">无法加载卡牌数据</div>').data('loaded', true);
          }
        });
      });
    });
  }
 
  // 调整卡牌弹出位置到右下方
  function positionCardPopup($container) {
    var $popupContainer = $container.find('.card-popup-container');
    var containerWidth = $container.width();
    var windowWidth = $(window).width();
    var containerOffset = $container.offset();
    var rightSpace = windowWidth - containerOffset.left - containerWidth;
   
    // 重置位置
    $popupContainer.css({
      'left': 'auto',
      'right': 'auto',
      'top': '100%',
      'margin-top': '5px'
    });
   
    // 如果右侧空间足够,放在右下方
    if (rightSpace >= 168) { // 卡牌宽度大约168px
      $popupContainer.css({
        'left': '0',
      });
    }
    // 如果右侧空间不够,但左侧空间足够,放在左下方
    else if (containerOffset.left >= 168) {
      $popupContainer.css({
        'right': '0',
      });
    }
    // 如果两侧都不够,尝试居中并确保完全可见
    else {
      var leftPosition = Math.max(0, Math.min(containerOffset.left - (168/2), windowWidth - 168));
      $popupContainer.css({
        'left': (leftPosition - containerOffset.left) + 'px'
      });
    }
  }
 
  // 初次加载页面时初始化
  $(document).ready(function() {
    initCardHoverElements();
  });
 
  // 使用 MutationObserver 监听 DOM 变化,处理动态加载的内容
  if (window.MutationObserver) {
    var observer = new MutationObserver(function(mutations) {
      var shouldInit = false;
      mutations.forEach(function(mutation) {
        if (mutation.addedNodes && mutation.addedNodes.length) {
          shouldInit = true;
        }
      });
     
      if (shouldInit) {
        initCardHoverElements();
      }
    });
   
    observer.observe(document.body, {
      childList: true,
      subtree: true
    });
  }
});
});


第1,405行: 第764行:
     }
     }
})();
})();
/* 轮播图 */
(function () {
  'use strict';
  function initCarousel(root) {
    if (!root || root.__inited) return;
    root.__inited = true;
    const wrapper = root.querySelector('.carousel-wrapper');
    const slides = Array.from(root.querySelectorAll('.carousel-slide'));
    const titles = Array.from(root.querySelectorAll('.carousel-title-item'));
    const btnPrev = root.querySelector('.carousel-prev');
    const btnNext = root.querySelector('.carousel-next');
    if (!wrapper || !slides.length) {
      root.style.display = 'none';
      return;
    }
    // 单张图隐藏按钮
    if (slides.length === 1) {
      root.classList.add('single');
    }
    // 标题索引与幻灯索引对齐
    titles.forEach((t, i) => {
      t.dataset.slide = String(i);
    });
    let index = 0;
    let timer = null;
    const autoplay = (root.getAttribute('data-autoplay') || '1') !== '0';
    const interval = Math.max(1500, parseInt(root.getAttribute('data-interval') || '4000', 10) || 4000);
    function update() {
      wrapper.style.transform = 'translateX(' + (-index * 100) + '%)';
      titles.forEach((t, i) => {
        if (i === index) t.classList.add('active');
        else t.classList.remove('active');
        const text = t.querySelector('.title-text');
        const ind = t.querySelector('.title-indicator');
        if (text) text.style.opacity = i === index ? '1' : '0.75';
        if (ind) ind.style.background = i === index ? '#ff6600' : 'transparent';
      });
    }
    function next() {
      index = (index + 1) % slides.length;
      update();
    }
    function prev() {
      index = (index - 1 + slides.length) % slides.length;
      update();
    }
    // 标题点击
    titles.forEach((t) => {
      t.addEventListener('click', function () {
        const i = parseInt(t.dataset.slide || '0', 10) || 0;
        index = Math.min(Math.max(i, 0), slides.length - 1);
        update();
        restartAutoplay();
      });
    });
    // 按钮点击
    if (btnPrev) {
      btnPrev.addEventListener('click', function () {
        prev();
        restartAutoplay();
      });
    }
    if (btnNext) {
      btnNext.addEventListener('click', function () {
        next();
        restartAutoplay();
      });
    }
    // 自动播放控制
    function startAutoplay() {
      if (!autoplay || slides.length <= 1) return;
      stopAutoplay();
      timer = setInterval(next, interval);
    }
    function stopAutoplay() {
      if (timer) {
        clearInterval(timer);
        timer = null;
      }
    }
    function restartAutoplay() {
      stopAutoplay();
      startAutoplay();
    }
    // 悬停/聚焦暂停
    root.addEventListener('mouseenter', stopAutoplay);
    root.addEventListener('mouseleave', startAutoplay);
    root.addEventListener('focusin', stopAutoplay);
    root.addEventListener('focusout', startAutoplay);
    // 触摸滑动
    let startX = 0;
    let curX = 0;
    let dragging = false;
    const threshold = 30;
    root.addEventListener(
      'touchstart',
      function (e) {
        if (!e.touches || !e.touches.length) return;
        startX = e.touches[0].clientX;
        curX = startX;
        dragging = true;
        root.classList.add('grabbing');
        stopAutoplay();
      },
      { passive: true }
    );
    root.addEventListener(
      'touchmove',
      function (e) {
        if (!dragging || !e.touches || !e.touches.length) return;
        curX = e.touches[0].clientX;
        const dx = curX - startX;
        wrapper.style.transform = 'translateX(calc(' + (-index * 100) + '% + ' + dx + 'px))';
      },
      { passive: true }
    );
    root.addEventListener('touchend', function () {
      if (!dragging) return;
      const dx = curX - startX;
      root.classList.remove('grabbing');
      dragging = false;
      if (Math.abs(dx) > threshold) {
        if (dx < 0) next();
        else prev();
      } else {
        update();
      }
      startAutoplay();
    });
    // 鼠标拖动(可选)
    let mouseDown = false;
    let mStartX = 0;
    root.addEventListener('mousedown', function (e) {
      mouseDown = true;
      mStartX = e.clientX;
      root.classList.add('grab');
      stopAutoplay();
    });
    window.addEventListener('mouseup', function (e) {
      if (!mouseDown) return;
      const dx = e.clientX - mStartX;
      mouseDown = false;
      root.classList.remove('grab');
      if (Math.abs(dx) > threshold) {
        if (dx < 0) next();
        else prev();
      } else {
        update();
      }
      startAutoplay();
    });
    // 初始化
    update();
    startAutoplay();
  } // <- 确保此处仅关闭 initCarousel 函数
  function initAll(context) {
    const scope = context && context.querySelectorAll ? context : document;
    scope.querySelectorAll('.carousel-container').forEach(initCarousel);
  }
  // 初次加载
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', function () {
      initAll();
    });
  } else {
    initAll();
  }
  // 动态内容(如可视化编辑器或AJAX)再次初始化
  if (window.mw && mw.hook) {
    mw.hook('wikipage.content').add(function (content) {
      // content 可能是 jQuery 对象,也可能是原生节点
      if (content && content[0] && content.find) {
        // jQuery 对象
        content.find('.carousel-container').each(function () {
          initCarousel(this);
        });
      } else if (content && content.querySelectorAll) {
        // 原生节点
        initAll(content);
      } else {
        initAll();
      }
    });
  }
})();
/* 装备 */
$(function() {
    // 创建遮罩层
    if ($('.equipment-wrapper').length > 0 && $('#equipment-overlay').length === 0) {
        $('body').append('<div id="equipment-overlay" class="equipment-overlay"></div>');
    }
   
    // 点击装备卡片显示弹窗
    $(document).on('click', '.equipment-card', function(e) {
        e.stopPropagation();
       
        var equipName = $(this).attr('data-equipment');
        var level = $(this).attr('data-level');
        var popup = $(this).closest('.equipment-wrapper').find('.equipment-popup');
       
        if (popup.length > 0) {
            $('#equipment-overlay').fadeIn(200);
            popup.fadeIn(200);
        }
    });
   
    // 防止点击装备名称链接时触发其他事件
    $(document).on('click', '.equipment-name-link a', function(e) {
        e.stopPropagation();
        // 允许默认的链接跳转行为
    });
   
    // 点击关闭按钮关闭弹窗
    $(document).on('click', '.equipment-popup-close', function(e) {
        e.stopPropagation();
        $(this).parent('.equipment-popup').fadeOut(200);
        $('#equipment-overlay').fadeOut(200);
    });
   
    // 点击遮罩层关闭弹窗
    $(document).on('click', '#equipment-overlay', function() {
        $('.equipment-popup:visible').fadeOut(200);
        $(this).fadeOut(200);
    });
   
    // 点击弹窗内容不关闭
    $(document).on('click', '.equipment-popup', function(e) {
        e.stopPropagation();
    });
});

2025年11月5日 (三) 21:34的最新版本

/* 这里的任何JavaScript将为所有用户在每次页面加载时加载。 */

// 等待 mw 对象加载完成
mw.loader.using(['mediawiki.util'], function() {
    
    // 动态加载 PIXI.js
    function loadScript(url) {
        return new Promise(function(resolve, reject) {
            var script = document.createElement('script');
            script.src = url;
            script.onload = resolve;
            script.onerror = reject;
            document.head.appendChild(script);
        });
    }
    
    // 按顺序加载库
    loadScript('https://cdn.jsdelivr.net/npm/pixi.js@5.3.12/dist/pixi.min.js')
        .then(function() {
            return loadScript('https://cdn.jsdelivr.net/npm/pixi-spine@3.0.12/dist/pixi-spine.js');
        })
        .then(function() {
            console.log('Spine libraries loaded successfully');
            initSpinePlayers();
        })
        .catch(function(error) {
            console.error('Failed to load Spine libraries:', error);
        });
    
    function initSpinePlayers() {
        var containers = document.querySelectorAll('.spine-player-container');
        
        if (containers.length === 0) {
            console.log('No spine containers found');
            return;
        }
        
        containers.forEach(function(container) {
            var skelUrl = container.getAttribute('data-skel');
            var atlasUrl = container.getAttribute('data-atlas');
            var animationName = container.getAttribute('data-animation') || 'idle';
            var skinName = container.getAttribute('data-skin') || 'default';
            
            if (!skelUrl || !atlasUrl) {
                console.error('Missing skel or atlas URL');
                return;
            }
            
            // 创建 PIXI 应用
            var app = new PIXI.Application({
                width: container.clientWidth || 800,
                height: container.clientHeight || 600,
                backgroundColor: 0x2c3e50,
                transparent: false
            });
            
            container.innerHTML = '';
            container.appendChild(app.view);
            
            // 加载 Spine 资源
            app.loader
                .add('spineData', skelUrl)
                .load(function(loader, resources) {
                    try {
                        var animation = new PIXI.spine.Spine(resources.spineData.spineData);
                        
                        // 设置位置和缩放
                        animation.x = app.screen.width / 2;
                        animation.y = app.screen.height / 2;
                        animation.scale.set(0.5);
                        
                        // 播放动画
                        if (animation.state.hasAnimation(animationName)) {
                            animation.state.setAnimation(0, animationName, true);
                        }
                        
                        app.stage.addChild(animation);
                        console.log('Spine animation loaded successfully');
                    } catch(e) {
                        console.error('Error creating spine animation:', e);
                    }
                });
        });
    }
});

/* 卡牌 */
(function () {
    'use strict';

    var initialized = false;

    function show(el) {
        if (el) el.style.display = 'flex';
    }
    function hide(el) {
        if (el) el.style.display = 'none';
    }

    function resetModalView(modal) {
        var originalView = modal.querySelector('.original-card-view');
        var inspirationView = modal.querySelector('.inspiration-view');
        var godView = modal.querySelector('.god-inspiration-view');
        var subcardsView = modal.querySelector('.subcards-view');
        var nestedSubcardsViews = modal.querySelectorAll('.nested-subcards-view');
        var inspirationNestedViews = modal.querySelectorAll('.inspiration-subcards-view');
        var inspirationDeeperNestedViews = modal.querySelectorAll('.inspiration-nested-subcards-view');

        if (originalView) show(originalView);
        if (inspirationView) hide(inspirationView);
        if (godView) hide(godView);
        if (subcardsView) hide(subcardsView);

        nestedSubcardsViews.forEach(hide);
        inspirationNestedViews.forEach(hide);
        inspirationDeeperNestedViews.forEach(hide);
    }

    function closeModal(modal) {
        modal.style.display = 'none';
        document.body.style.overflow = 'auto';
        resetModalView(modal);
    }

    function openModalFromCard(cardWrapper) {
        var cardId = cardWrapper.getAttribute('data-card-id');
        if (!cardId) return;
        var modal = document.getElementById(cardId + '-modal');
        if (!modal) return;
        resetModalView(modal);
        modal.style.display = 'block';
        document.body.style.overflow = 'hidden';
    }

    function handleBackToCard(button) {
        var modal = button.closest('.card-modal');
        if (modal) {
            resetModalView(modal);
        }
    }

    function handleBackToSubcards(button) {
        var modal = button.closest('.card-modal');
        if (!modal) return;
        var nestedView = button.closest('.nested-subcards-view');
        var subcardsView = modal.querySelector('.subcards-view');
        if (nestedView && subcardsView) {
            hide(nestedView);
            show(subcardsView);
        }
    }

    function handleInspirationClick(button) {
        var modal = button.closest('.card-modal');
        if (!modal) return;
        var originalView = modal.querySelector('.original-card-view');
        var inspirationView = modal.querySelector('.inspiration-view');
        if (!originalView || !inspirationView) return;
        hide(originalView);
        show(inspirationView);
    }

    function handleGodInspirationClick(button) {
        var modal = button.closest('.card-modal');
        if (!modal) return;
        var originalView = modal.querySelector('.original-card-view');
        var godView = modal.querySelector('.god-inspiration-view');
        if (!originalView || !godView) return;
        hide(originalView);
        show(godView);
    }

    function handleSubcardsClick(button) {
        var modal = button.closest('.card-modal');
        if (!modal) return;
        var originalView = modal.querySelector('.original-card-view');
        var subcardsView = modal.querySelector('.subcards-view');
        if (!originalView || !subcardsView) return;
        hide(originalView);
        show(subcardsView);
    }

    function handleViewNestedSubcardsClick(button) {
        var modal = button.closest('.card-modal');
        if (!modal) return;
        var subcardIndex = button.getAttribute('data-subcard-index');
        if (!subcardIndex) return;
        var subcardsView = modal.querySelector('.subcards-view');
        var nestedView = modal.querySelector('.nested-subcards-view[data-subcard-index="' + subcardIndex + '"]');
        if (!subcardsView || !nestedView) return;
        hide(subcardsView);
        show(nestedView);
    }

    function handleInspirationSubcardsClick(button) {
        var modal = button.closest('.card-modal');
        if (!modal) return;
        var idx = button.getAttribute('data-variant-index');
        if (!idx) return;
        var inspirationView = modal.querySelector('.inspiration-view');
        var nestedView = modal.querySelector('.inspiration-subcards-view[data-variant-index="' + idx + '"]');
        if (!inspirationView || !nestedView) return;
        hide(inspirationView);
        show(nestedView);
    }

    function handleBackToInspiration(button) {
        var modal = button.closest('.card-modal');
        if (!modal) return;
        var nestedView = button.closest('.inspiration-subcards-view');
        var inspirationView = modal.querySelector('.inspiration-view');
        if (nestedView && inspirationView) {
            hide(nestedView);
            show(inspirationView);
        }
    }

    function handleViewInspirationNestedSubcardsClick(button) {
        var modal = button.closest('.card-modal');
        if (!modal) return;
        var vIdx = button.getAttribute('data-variant-index');
        var sIdx = button.getAttribute('data-subcard-index');
        if (!vIdx || !sIdx) return;
        var subcardsView = modal.querySelector('.inspiration-subcards-view[data-variant-index="' + vIdx + '"]');
        var deeperView = modal.querySelector('.inspiration-nested-subcards-view[data-variant-index="' + vIdx + '"][data-subcard-index="' + sIdx + '"]');
        if (!subcardsView || !deeperView) return;
        hide(subcardsView);
        show(deeperView);
    }

    function handleBackToInspirationSubcards(button) {
        var modal = button.closest('.card-modal');
        if (!modal) return;
        var deeperView = button.closest('.inspiration-nested-subcards-view');
        var vIdx = button.getAttribute('data-variant-index');
        var subcardsView = modal.querySelector('.inspiration-subcards-view[data-variant-index="' + vIdx + '"]');
        if (deeperView && subcardsView) {
            hide(deeperView);
            show(subcardsView);
        }
    }

    function onKeydown(event) {
        if (event.key === 'Escape' || event.keyCode === 27) {
            var modals = document.querySelectorAll('.card-modal');
            modals.forEach(function (modal) {
                if (modal.style.display === 'block') {
                    var inspirationView = modal.querySelector('.inspiration-view');
                    var godView = modal.querySelector('.god-inspiration-view');
                    var subcardsView = modal.querySelector('.subcards-view');
                    var nestedSubcardsViews = modal.querySelectorAll('.nested-subcards-view');
                    var inspirationNestedViews = modal.querySelectorAll('.inspiration-subcards-view');
                    var inspirationDeeperNestedViews = modal.querySelectorAll('.inspiration-nested-subcards-view');

                    var inNestedView = false;
                    nestedSubcardsViews.forEach(function (view) {
                        if (view.style.display !== 'none') {
                            inNestedView = true;
                            hide(view);
                            if (subcardsView) show(subcardsView);
                        }
                    });

                    var inInspirationNested = false;
                    inspirationNestedViews.forEach(function (view) {
                        if (view.style.display !== 'none') {
                            inInspirationNested = true;
                            hide(view);
                            if (inspirationView) show(inspirationView);
                        }
                    });

                    var inInspirationDeeperNested = false;
                    inspirationDeeperNestedViews.forEach(function (view) {
                        if (view.style.display !== 'none') {
                            inInspirationDeeperNested = true;
                            var vIdx = view.getAttribute('data-variant-index');
                            hide(view);
                            var parentSubcardsView = modal.querySelector('.inspiration-subcards-view[data-variant-index="' + vIdx + '"]');
                            if (parentSubcardsView) show(parentSubcardsView);
                        }
                    });

                    if (!inNestedView && !inInspirationNested && !inInspirationDeeperNested) {
                        if ((inspirationView && inspirationView.style.display !== 'none') ||
                            (subcardsView && subcardsView.style.display !== 'none') ||
                            (godView && godView.style.display !== 'none')) {
                            resetModalView(modal);
                        } else {
                            closeModal(modal);
                        }
                    }
                }
            });
        }
    }

    function onDocumentClick(e) {
        // 打开模态:点击卡片缩略图区域
        var cardWrapper = e.target.closest('.card-small-wrapper');
        if (cardWrapper) {
            e.preventDefault();
            e.stopPropagation();
            openModalFromCard(cardWrapper);
            return;
        }

        // 变体/衍生/返回/关闭
        if (e.target.classList.contains('inspiration-button')) {
            e.stopPropagation();
            handleInspirationClick(e.target);
            return;
        }
        if (e.target.classList.contains('god-inspiration-button')) {
            e.stopPropagation();
            handleGodInspirationClick(e.target);
            return;
        }
        if (e.target.classList.contains('subcards-button')) {
            e.stopPropagation();
            handleSubcardsClick(e.target);
            return;
        }
        if (e.target.classList.contains('view-nested-subcards-button')) {
            e.stopPropagation();
            handleViewNestedSubcardsClick(e.target);
            return;
        }
        if (e.target.classList.contains('back-to-card-button')) {
            e.stopPropagation();
            handleBackToCard(e.target);
            return;
        }
        if (e.target.classList.contains('back-to-subcards-button')) {
            e.stopPropagation();
            handleBackToSubcards(e.target);
            return;
        }
        if (e.target.classList.contains('view-insp-subcards-button')) {
            e.stopPropagation();
            handleInspirationSubcardsClick(e.target);
            return;
        }
        if (e.target.classList.contains('back-to-inspiration-button')) {
            e.stopPropagation();
            handleBackToInspiration(e.target);
            return;
        }
        if (e.target.classList.contains('view-insp-nested-subcards-button')) {
            e.stopPropagation();
            handleViewInspirationNestedSubcardsClick(e.target);
            return;
        }
        if (e.target.classList.contains('back-to-insp-subcards-button')) {
            e.stopPropagation();
            handleBackToInspirationSubcards(e.target);
            return;
        }

        // 关闭按钮
        var closeBtn = e.target.classList.contains('modal-close-button')
            ? e.target
            : (e.target.parentElement && e.target.parentElement.classList.contains('modal-close-button') ? e.target.parentElement : null);

        if (closeBtn) {
            var modal = closeBtn.closest('.card-modal');
            if (modal) closeModal(modal);
        }
    }

    function init() {
        if (initialized) return;
        initialized = true;

        document.addEventListener('click', onDocumentClick);
        document.addEventListener('keydown', onKeydown);
    }

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }

    if (typeof mw !== 'undefined' && mw.hook) {
        // 页面增量渲染时确保已初始化(事件委托只需一次)
        mw.hook('wikipage.content').add(function () { init(); });
    }
})();

// 卡牌悬停显示功能
(function () {
    'use strict';

    var hoverTimeout;

    function showCardPopup(linkElement) {
        // 清除之前的超时
        if (hoverTimeout) {
            clearTimeout(hoverTimeout);
        }

        // 检查是否已有弹出框
        var existingPopup = linkElement.querySelector('.card-hover-popup');
        if (existingPopup) {
            return;
        }

        // 查找紧邻的隐藏数据容器
        var dataContainer = linkElement.nextElementSibling;
        if (!dataContainer || !dataContainer.classList.contains('card-link-data')) {
            return;
        }

        // 在隐藏容器中查找卡牌
        var cardWrapper = dataContainer.querySelector('.card-small-wrapper');
        if (!cardWrapper) {
            return;
        }

        // 克隆卡牌
        var clonedCard = cardWrapper.cloneNode(true);
        clonedCard.style.cursor = 'default';
        
        // 移除可能触发模态框的属性和类
        clonedCard.removeAttribute('data-card-id');
        var originalClass = clonedCard.className;
        clonedCard.className = originalClass.replace('card-small-wrapper', 'card-hover-preview');

        // 创建弹出框
        var popup = document.createElement('div');
        popup.className = 'card-hover-popup';
        popup.appendChild(clonedCard);

        // 添加到链接中
        linkElement.appendChild(popup);
    }

    function hideCardPopup(linkElement) {
        hoverTimeout = setTimeout(function () {
            var popup = linkElement.querySelector('.card-hover-popup');
            if (popup) {
                popup.remove();
            }
        }, 100);
    }

    function initCardLinks() {
        var cardLinks = document.querySelectorAll('.card-link');

        cardLinks.forEach(function (link) {
            // 避免重复绑定
            if (link.hasAttribute('data-card-hover-init')) {
                return;
            }
            link.setAttribute('data-card-hover-init', 'true');

            // 添加事件监听器
            link.addEventListener('mouseenter', function () {
                showCardPopup(link);
            });

            link.addEventListener('mouseleave', function () {
                hideCardPopup(link);
            });
        });
    }

    // 初始化
    function init() {
        initCardLinks();
    }

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }

    // MediaWiki 钩子支持
    if (typeof mw !== 'undefined' && mw.hook) {
        mw.hook('wikipage.content').add(init);
    }
})();

/* 切换标签 */
(function() {
    'use strict';
    
    function initTabSwitcher() {
        var tabContainers = document.querySelectorAll('.resp-tabs');
        
        tabContainers.forEach(function(container) {
            var tabButtons = container.querySelectorAll('.czn-list-style');
            if (tabButtons.length === 0) return;
            
            var tabContents = container.querySelectorAll('.resp-tab-content');
            
            // 初始化
            tabButtons.forEach(function(button, index) {
                button.classList.toggle('active', index === 0);
            });
            
            if (tabContents.length > 0) {
                tabContents.forEach(function(content, index) {
                    content.style.display = index === 0 ? 'block' : 'none';
                });
            }
            
            // 点击事件
            tabButtons.forEach(function(button, index) {
                button.addEventListener('click', function(e) {
                    e.preventDefault();
                    
                    // 更新标签状态
                    tabButtons.forEach(function(btn, i) {
                        btn.classList.toggle('active', i === index);
                    });
                    
                    // 切换内容
                    if (tabContents.length > 0) {
                        tabContents.forEach(function(content, i) {
                            content.style.display = i === index ? 'block' : 'none';
                        });
                    }
                });
            });
        });
    }
    
    // 初始化
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', initTabSwitcher);
    } else {
        initTabSwitcher();
    }
})();

/* 角色立绘切换 */
$(document).ready(function() {
    // 使用事件委托来确保动态内容也能响应
    $(document).on('click', '.character-switch-btn', function() {
        // 如果点击的是已经激活的按钮,不执行任何操作
        if ($(this).hasClass('active')) {
            return;
        }
        
        var targetType = $(this).attr('data-target');
        var container = $(this).closest('#character-container');
        var imageWrapper = container.find('.character-image-wrapper');
        var allImages = imageWrapper.find('.character-image');
        
        // 先将所有图片淡出
        allImages.each(function() {
            $(this).css('opacity', '0');
        });
        
        // 延迟后切换显示状态
        setTimeout(function() {
            allImages.each(function() {
                $(this).css('display', 'none');
            });
            
            // 显示目标图片
            imageWrapper.find('[data-image-type="' + targetType + '"]').each(function() {
                $(this).css('display', 'block');
                // 强制重绘
                $(this)[0].offsetHeight;
                $(this).css('opacity', '1');
            });
        }, 300);
        
        // 更新按钮样式
        container.find('.character-switch-btn').each(function() {
            $(this).removeClass('active');
            $(this).css({
                'background': 'rgba(0,0,0,0.5)',
                'cursor': 'pointer'
            });
        });
        
        // 设置当前按钮为激活状态
        $(this).addClass('active');
        $(this).css({
            'background': 'rgba(70, 130, 255, 0.8)',
            'cursor': 'default'
        });
    });
    
    // 鼠标悬停效果(仅对非激活按钮有效)
    $(document).on('mouseenter', '.character-switch-btn:not(.active)', function() {
        $(this).css('background', 'rgba(70, 130, 255, 0.5)');
    });
    
    $(document).on('mouseleave', '.character-switch-btn:not(.active)', function() {
        $(this).css('background', 'rgba(0,0,0,0.5)');
    });
});

/* 悬浮目录 */
$(document).ready(function() {
    // 只在有目录的页面上执行
    if ($('.toc').length > 0) {
        // 创建侧边目录
        var $sidebar = $('<div id="toc-sidebar"><div id="toc-sidebar-trigger">展开目录</div><div id="toc-sidebar-content"></div></div>');
        $('body').append($sidebar);
        
        // 提取并修复目录内容
        var tocUl = $('<ul></ul>');
        
        // 避免重复的目录项
        var processedItems = new Set();
        
        // 从原始目录构建新目录
        $('.toc ul li').each(function() {
            var $link = $(this).find('a').first();
            var href = $link.attr('href');
            var $number = $link.find('.tocnumber').first();
            var $text = $link.find('.toctext').first();
            
            // 创建唯一标识符,避免重复添加
            var itemId = $number.text() + '-' + $text.text();
            
            if (!processedItems.has(itemId)) {
                processedItems.add(itemId);
                
                // 创建新的目录项
                var $li = $('<li></li>');
                var $newLink = $('').attr('href', href);
                
                // 如果有编号,则添加编号
                if ($number.length) {
                    $newLink.append($('<span class="tocnumber"></span>').text($number.text()));
                    $newLink.append(' ');
                }
                
                $newLink.append($('<span class="toctext"></span>').text($text.text()));
                $li.append($newLink);
                tocUl.append($li);
            }
        });
        
        $('#toc-sidebar-content').append(tocUl);
        
        // 点击展开/折叠事件处理
        $('#toc-sidebar-trigger').click(function() {
            $('#toc-sidebar').toggleClass('expanded');
            
            // 根据展开/折叠状态更改按钮文字
            if ($('#toc-sidebar').hasClass('expanded')) {
                $('#toc-sidebar-trigger').text('隐藏目录');
            } else {
                $('#toc-sidebar-trigger').text('展开目录');
            }
        });
    }
});

/* 词典Tooltip */
(function() {
    var tooltipContainer = null;
    var currentTerm = null;
    var hideTimeout = null;
    
    // 初始化
    $(function() {
        // 创建全局 tooltip 容器
        tooltipContainer = $('<div class="dictionary-tooltip-container"></div>');
        $('body').append(tooltipContainer);
        
        // 鼠标进入词条
        $(document).on('mouseenter', '.dictionary-term', function(e) {
            var $term = $(this);
            currentTerm = $term;
            
            // 清除隐藏定时器
            if (hideTimeout) {
                clearTimeout(hideTimeout);
                hideTimeout = null;
            }
            
            // 获取 tooltip 内容
            var content = $term.attr('data-tooltip-content');
            if (!content) return;
            
            // 设置内容
            tooltipContainer.html(content);
            
            // 计算位置
            updateTooltipPosition($term);
            
            // 显示 tooltip
            tooltipContainer.addClass('active');
        });
        
        // 鼠标离开词条
        $(document).on('mouseleave', '.dictionary-term', function() {
            hideTimeout = setTimeout(function() {
                tooltipContainer.removeClass('active');
                currentTerm = null;
            }, 100);
        });
        
        // 鼠标进入 tooltip(防止快速隐藏)
        tooltipContainer.on('mouseenter', function() {
            if (hideTimeout) {
                clearTimeout(hideTimeout);
                hideTimeout = null;
            }
        });
        
        // 鼠标离开 tooltip
        tooltipContainer.on('mouseleave', function() {
            hideTimeout = setTimeout(function() {
                tooltipContainer.removeClass('active');
                currentTerm = null;
            }, 100);
        });
        
        // 窗口滚动时更新位置
        $(window).on('scroll resize', function() {
            if (currentTerm && tooltipContainer.hasClass('active')) {
                updateTooltipPosition(currentTerm);
            }
        });
    });
    
    // 更新 tooltip 位置
    function updateTooltipPosition($term) {
        var rect = $term[0].getBoundingClientRect();
        var scrollTop = $(window).scrollTop();
        var scrollLeft = $(window).scrollLeft();
        
        // 基本位置:词条下方
        var top = rect.bottom + scrollTop + 2;
        var left = rect.left + scrollLeft;
        
        // 获取 tooltip 尺寸
        var tooltipWidth = 250; // 固定宽度
        var tooltipHeight = tooltipContainer.outerHeight();
        
        // 获取窗口尺寸
        var windowWidth = $(window).width();
        var windowHeight = $(window).height();
        
        // 检查右边界
        if (left + tooltipWidth > windowWidth + scrollLeft) {
            left = Math.max(scrollLeft, rect.right + scrollLeft - tooltipWidth);
        }
        
        // 检查下边界
        if (rect.bottom + tooltipHeight > windowHeight) {
            // 如果下方空间不足,显示在上方
            if (rect.top - tooltipHeight > 0) {
                top = rect.top + scrollTop - tooltipHeight - 2;
            }
        }
        
        // 设置位置
        tooltipContainer.css({
            top: top + 'px',
            left: left + 'px'
        });
    }
})();

/* 轮播图 */
(function () {
  'use strict';

  function initCarousel(root) {
    if (!root || root.__inited) return;
    root.__inited = true;

    const wrapper = root.querySelector('.carousel-wrapper');
    const slides = Array.from(root.querySelectorAll('.carousel-slide'));
    const titles = Array.from(root.querySelectorAll('.carousel-title-item'));
    const btnPrev = root.querySelector('.carousel-prev');
    const btnNext = root.querySelector('.carousel-next');

    if (!wrapper || !slides.length) {
      root.style.display = 'none';
      return;
    }

    // 单张图隐藏按钮
    if (slides.length === 1) {
      root.classList.add('single');
    }

    // 标题索引与幻灯索引对齐
    titles.forEach((t, i) => {
      t.dataset.slide = String(i);
    });

    let index = 0;
    let timer = null;
    const autoplay = (root.getAttribute('data-autoplay') || '1') !== '0';
    const interval = Math.max(1500, parseInt(root.getAttribute('data-interval') || '4000', 10) || 4000);

    function update() {
      wrapper.style.transform = 'translateX(' + (-index * 100) + '%)';
      titles.forEach((t, i) => {
        if (i === index) t.classList.add('active');
        else t.classList.remove('active');

        const text = t.querySelector('.title-text');
        const ind = t.querySelector('.title-indicator');
        if (text) text.style.opacity = i === index ? '1' : '0.75';
        if (ind) ind.style.background = i === index ? '#ff6600' : 'transparent';
      });
    }

    function next() {
      index = (index + 1) % slides.length;
      update();
    }

    function prev() {
      index = (index - 1 + slides.length) % slides.length;
      update();
    }

    // 标题点击
    titles.forEach((t) => {
      t.addEventListener('click', function () {
        const i = parseInt(t.dataset.slide || '0', 10) || 0;
        index = Math.min(Math.max(i, 0), slides.length - 1);
        update();
        restartAutoplay();
      });
    });

    // 按钮点击
    if (btnPrev) {
      btnPrev.addEventListener('click', function () {
        prev();
        restartAutoplay();
      });
    }
    if (btnNext) {
      btnNext.addEventListener('click', function () {
        next();
        restartAutoplay();
      });
    }

    // 自动播放控制
    function startAutoplay() {
      if (!autoplay || slides.length <= 1) return;
      stopAutoplay();
      timer = setInterval(next, interval);
    }

    function stopAutoplay() {
      if (timer) {
        clearInterval(timer);
        timer = null;
      }
    }

    function restartAutoplay() {
      stopAutoplay();
      startAutoplay();
    }

    // 悬停/聚焦暂停
    root.addEventListener('mouseenter', stopAutoplay);
    root.addEventListener('mouseleave', startAutoplay);
    root.addEventListener('focusin', stopAutoplay);
    root.addEventListener('focusout', startAutoplay);

    // 触摸滑动
    let startX = 0;
    let curX = 0;
    let dragging = false;
    const threshold = 30;

    root.addEventListener(
      'touchstart',
      function (e) {
        if (!e.touches || !e.touches.length) return;
        startX = e.touches[0].clientX;
        curX = startX;
        dragging = true;
        root.classList.add('grabbing');
        stopAutoplay();
      },
      { passive: true }
    );

    root.addEventListener(
      'touchmove',
      function (e) {
        if (!dragging || !e.touches || !e.touches.length) return;
        curX = e.touches[0].clientX;
        const dx = curX - startX;
        wrapper.style.transform = 'translateX(calc(' + (-index * 100) + '% + ' + dx + 'px))';
      },
      { passive: true }
    );

    root.addEventListener('touchend', function () {
      if (!dragging) return;
      const dx = curX - startX;
      root.classList.remove('grabbing');
      dragging = false;
      if (Math.abs(dx) > threshold) {
        if (dx < 0) next();
        else prev();
      } else {
        update();
      }
      startAutoplay();
    });

    // 鼠标拖动(可选)
    let mouseDown = false;
    let mStartX = 0;

    root.addEventListener('mousedown', function (e) {
      mouseDown = true;
      mStartX = e.clientX;
      root.classList.add('grab');
      stopAutoplay();
    });

    window.addEventListener('mouseup', function (e) {
      if (!mouseDown) return;
      const dx = e.clientX - mStartX;
      mouseDown = false;
      root.classList.remove('grab');
      if (Math.abs(dx) > threshold) {
        if (dx < 0) next();
        else prev();
      } else {
        update();
      }
      startAutoplay();
    });

    // 初始化
    update();
    startAutoplay();
  } // <- 确保此处仅关闭 initCarousel 函数

  function initAll(context) {
    const scope = context && context.querySelectorAll ? context : document;
    scope.querySelectorAll('.carousel-container').forEach(initCarousel);
  }

  // 初次加载
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', function () {
      initAll();
    });
  } else {
    initAll();
  }

  // 动态内容(如可视化编辑器或AJAX)再次初始化
  if (window.mw && mw.hook) {
    mw.hook('wikipage.content').add(function (content) {
      // content 可能是 jQuery 对象,也可能是原生节点
      if (content && content[0] && content.find) {
        // jQuery 对象
        content.find('.carousel-container').each(function () {
          initCarousel(this);
        });
      } else if (content && content.querySelectorAll) {
        // 原生节点
        initAll(content);
      } else {
        initAll();
      }
    });
  }
})();

/* 装备 */
$(function() {
    // 创建遮罩层
    if ($('.equipment-wrapper').length > 0 && $('#equipment-overlay').length === 0) {
        $('body').append('<div id="equipment-overlay" class="equipment-overlay"></div>');
    }
    
    // 点击装备卡片显示弹窗
    $(document).on('click', '.equipment-card', function(e) {
        e.stopPropagation();
        
        var equipName = $(this).attr('data-equipment');
        var level = $(this).attr('data-level');
        var popup = $(this).closest('.equipment-wrapper').find('.equipment-popup');
        
        if (popup.length > 0) {
            $('#equipment-overlay').fadeIn(200);
            popup.fadeIn(200);
        }
    });
    
    // 防止点击装备名称链接时触发其他事件
    $(document).on('click', '.equipment-name-link a', function(e) {
        e.stopPropagation();
        // 允许默认的链接跳转行为
    });
    
    // 点击关闭按钮关闭弹窗
    $(document).on('click', '.equipment-popup-close', function(e) {
        e.stopPropagation();
        $(this).parent('.equipment-popup').fadeOut(200);
        $('#equipment-overlay').fadeOut(200);
    });
    
    // 点击遮罩层关闭弹窗
    $(document).on('click', '#equipment-overlay', function() {
        $('.equipment-popup:visible').fadeOut(200);
        $(this).fadeOut(200);
    });
    
    // 点击弹窗内容不关闭
    $(document).on('click', '.equipment-popup', function(e) {
        e.stopPropagation();
    });
});