微件:Card:修订间差异

来自卡厄思梦境WIKI
跳转到导航 跳转到搜索
律Rhyme留言 | 贡献
功能测试
律Rhyme留言 | 贡献
功能测试
第1行: 第1行:
<includeonly>
<noinclude>
此Widget为卡牌显示提供交互功能,包括悬停动画、点击放大和闪光卡牌列表显示。
[[分类:Widget]]
</noinclude><includeonly>
<style>
<style>
.card-wrapper {
/* 卡牌悬停和点击动画 */
    display: inline-block;
}
 
/* 卡牌悬停动画 */
.card-deck-trans {
.card-deck-trans {
     cursor: pointer;
     cursor: pointer;
     transition: transform 0.3s ease, box-shadow 0.3s ease, filter 0.3s ease;
     transition: transform 0.2s ease, box-shadow 0.2s ease;
}
}


.card-deck-trans:hover {
.card-deck-trans:hover {
     transform: translateY(-8px);
     transform: translateY(-5px);
     filter: brightness(1.1);
     filter: brightness(1.1);
}
}


.card-deck-trans:active {
.card-deck-trans:active {
     transform: translateY(-4px) scale(0.98);
     transform: translateY(-2px) scale(0.98);
}
}


/* 模态框通用样式 */
/* 模态框基础样式 */
.card-modal-overlay,
.card-modal-overlay {
.spark-modal-overlay {
     display: none;
     display: none;
     position: fixed;
     position: fixed;
第33行: 第31行:
     justify-content: center;
     justify-content: center;
     align-items: center;
     align-items: center;
     opacity: 0;
     flex-direction: column;
    transition: opacity 0.3s ease;
}
}


.spark-modal-overlay {
.card-modal-overlay.active {
    z-index: 10010;
    background-color: rgba(0, 0, 0, 0.9);
}
 
.card-modal-overlay.active,
.spark-modal-overlay.active {
     display: flex;
     display: flex;
    opacity: 1;
}
.card-modal-overlay.fade-in,
.spark-modal-overlay.fade-in {
    opacity: 1;
}
.card-modal-overlay.fade-out,
.spark-modal-overlay.fade-out {
    opacity: 0;
}
}


/* 关闭按钮 */
/* 关闭按钮 */
.card-modal-close,
.card-modal-close {
.spark-modal-close {
     position: absolute;
     position: fixed;
     top: 20px;
     top: 20px;
     right: 30px;
     right: 30px;
     font-size: 48px;
     font-size: 40px;
    font-weight: bold;
     color: #fff;
     color: #ffffff;
     cursor: pointer;
     cursor: pointer;
     z-index: 10001;
     z-index: 10001;
    transition: color 0.2s ease, transform 0.2s ease;
    font-family: Arial, sans-serif;
     line-height: 1;
     line-height: 1;
    transition: color 0.2s ease, transform 0.2s ease;
    text-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);
}
}


.spark-modal-close {
.card-modal-close:hover {
    z-index: 10012;
}
 
.card-modal-close:hover,
.spark-modal-close:hover {
     color: #ff6b6b;
     color: #ff6b6b;
     transform: scale(1.1);
     transform: scale(1.2);
}
}


/* 模态框中的卡牌容器 */
/* 模态框内容容器 */
.card-modal-content {
.card-modal-content {
    position: relative;
    z-index: 10000;
     display: flex;
     display: flex;
     flex-direction: column;
     flex-direction: column;
     align-items: center;
     align-items: center;
     animation: cardZoomIn 0.3s ease;
     justify-content: center;
    gap: 20px;
}
}


.spark-modal-content {
/* 放大后的卡牌容器 */
.card-modal-card {
     position: relative;
     position: relative;
    z-index: 10011;
     width: 270px;
    max-width: 90vw;
     height: 384px;
    max-height: 85vh;
     display: inline-block;
    overflow-y: auto;
    padding: 20px;
    animation: cardZoomIn 0.3s ease;
}
 
@keyframes cardZoomIn {
    from {
        transform: scale(0.8);
        opacity: 0;
    }
    to {
        transform: scale(1);
        opacity: 1;
    }
}
 
/* 放大后的卡牌样式 */
.card-modal-content > .card-deck-trans,
.card-modal-content > .card-wrapper > .card-deck-trans {
     width: 270px !important;
     height: 384px !important;
    transform: none !important;
    filter: none !important;
     cursor: default;
}
 
.card-modal-content > .card-deck-trans:hover,
.card-modal-content > .card-wrapper > .card-deck-trans:hover {
    transform: none !important;
    filter: none !important;
}
}


.card-modal-content > .card-deck-trans > .card-deck,
.card-modal-card .card-deck {
.card-modal-content > .card-wrapper > .card-deck-trans > .card-deck {
    position: absolute;
     transform: scale(0.6) !important;
    width: 450px;
    height: 640px;
     transform: scale(0.6);
    transform-origin: top left;
}
}


/* 闪光按钮 */
/* 闪光按钮 */
.spark-button {
.card-spark-button {
    margin-top: 20px;
     padding: 12px 30px;
     padding: 12px 36px;
     font-size: 18px;
     font-size: 18px;
     font-weight: bold;
     font-weight: bold;
     color: #fff;
     color: #fff;
     background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
     background: linear-gradient(135deg, #f5af19 0%, #f12711 100%);
     border: 2px solid #a78bfa;
     border: none;
     border-radius: 8px;
     border-radius: 25px;
     cursor: pointer;
     cursor: pointer;
     transition: all 0.3s ease;
     transition: all 0.3s ease;
     box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4);
     box-shadow: 0 4px 15px rgba(245, 175, 25, 0.4);
     text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
     margin-top: 10px;
}
}


.spark-button:hover {
.card-spark-button:hover {
     background: linear-gradient(135deg, #764ba2 0%, #667eea 100%);
     transform: scale(1.05);
     box-shadow: 0 6px 20px rgba(102, 126, 234, 0.6);
     box-shadow: 0 6px 20px rgba(245, 175, 25, 0.6);
    transform: translateY(-2px);
}
}


.spark-button:active {
.card-spark-button:active {
     transform: translateY(0);
     transform: scale(0.98);
    box-shadow: 0 2px 10px rgba(102, 126, 234, 0.4);
}
}


/* 闪光按钮状态 */
/* 闪光卡牌模态框 */
.spark-button.loading {
.spark-modal-overlay {
     opacity: 0.7;
     display: none;
     cursor: wait;
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.9);
    z-index: 10002;
    justify-content: center;
    align-items: flex-start;
    overflow-y: auto;
     padding: 60px 20px 20px;
}
}


.spark-button.cached::after {
.spark-modal-overlay.active {
     content: " ✓";
    display: flex;
     color: #90EE90;
}
 
.spark-modal-close {
    position: fixed;
    top: 20px;
    right: 30px;
     font-size: 40px;
     color: #fff;
    cursor: pointer;
    z-index: 10003;
    transition: color 0.2s ease, transform 0.2s ease;
    font-family: Arial, sans-serif;
    line-height: 1;
}
}


/* 闪光图标动画 */
.spark-modal-close:hover {
.spark-button:not(.loading)::before {
     color: #ff6b6b;
     content: "✦ ";
     transform: scale(1.2);
     animation: sparkle 1.5s ease-in-out infinite;
}
}


@keyframes sparkle {
/* 闪光卡牌列表容器 */
     0%, 100% { opacity: 0.5; }
.spark-modal-content {
     50% { opacity: 1; }
     display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 20px;
    max-width: 1200px;
     padding: 20px;
}
}


/* 闪光卡牌列表样式 */
.spark-modal-title {
.spark-modal-title {
    width: 100%;
     text-align: center;
     text-align: center;
     color: #fff;
     color: #f5af19;
     font-size: 24px;
     font-size: 28px;
     font-weight: bold;
     font-weight: bold;
     margin-bottom: 20px;
     margin-bottom: 20px;
     text-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);
     text-shadow: 0 0 10px rgba(245, 175, 25, 0.5);
}
 
.spark-modal-title::before {
    content: "✦ ";
    color: #a78bfa;
}
 
.spark-modal-title::after {
    content: " ✦";
    color: #a78bfa;
}
}


/* 闪光卡牌列表内的卡牌样式 */
.spark-card-list {
.spark-card-list {
     display: flex;
     display: flex;
第210行: 第170行:
     justify-content: center;
     justify-content: center;
     gap: 15px;
     gap: 15px;
}
.spark-card-list .card-wrapper {
    display: inline-block;
}
}


.spark-card-list .card-deck-trans {
.spark-card-list .card-deck-trans {
     cursor: pointer;
     cursor: default;
}
}


.spark-card-list .card-deck-trans:hover {
.spark-card-list .card-deck-trans:hover {
     transform: translateY(-8px);
     transform: none;
     filter: brightness(1.1);
     filter: none;
}
}


/* 加载提示 */
/* 加载动画 */
.spark-loading {
.spark-loading {
     color: #fff;
     color: #fff;
     font-size: 18px;
     font-size: 20px;
     text-align: center;
     text-align: center;
     padding: 40px;
     padding: 50px;
}
}


.spark-loading::after {
.spark-loading::after {
     content: "";
     content: '';
     animation: loadingDots 1.5s infinite;
     animation: dots 1.5s infinite;
}
 
@keyframes loadingDots {
    0% { content: ""; }
    25% { content: "."; }
    50% { content: ".."; }
    75% { content: "..."; }
}
 
/* 加载进度 */
.spark-loading-progress {
    color: #aaa;
    font-size: 14px;
    margin-top: 10px;
}
 
/* 空列表提示 */
.spark-empty {
    color: #999;
    font-size: 16px;
    text-align: center;
    padding: 40px;
}
 
/* 缓存状态提示 */
.spark-cache-hint {
    color: #666;
    font-size: 12px;
    text-align: center;
    margin-top: 15px;
}
 
/* 放大的闪光卡牌 */
.spark-enlarged-container {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
    background: rgba(0, 0, 0, 0.95);
    z-index: 10015;
    animation: cardZoomIn 0.3s ease;
}
}


.spark-enlarged-card {
@keyframes dots {
    position: relative;
     0%, 20% { content: '.'; }
    display: flex;
     40% { content: '..'; }
    flex-direction: column;
     60%, 100% { content: '...'; }
    align-items: center;
}
 
.spark-enlarged-card .card-deck-trans {
    width: 270px !important;
    height: 384px !important;
    transform: none !important;
    filter: none !important;
    cursor: default;
}
 
.spark-enlarged-card .card-deck-trans:hover {
     transform: none !important;
    filter: none !important;
}
 
.spark-enlarged-card .card-deck {
    transform: scale(0.6) !important;
}
 
.spark-enlarged-close {
    position: fixed;
    top: 20px;
    right: 30px;
    font-size: 48px;
    font-weight: bold;
    color: #ffffff;
    cursor: pointer;
    z-index: 10016;
    line-height: 1;
    transition: color 0.2s ease, transform 0.2s ease;
    text-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);
}
 
.spark-enlarged-close:hover {
     color: #ff6b6b;
    transform: scale(1.1);
}
 
/* 防止模态框打开时页面滚动 */
body.card-modal-open {
    overflow: hidden;
}
 
/* 滚动条样式 */
.spark-modal-content::-webkit-scrollbar {
    width: 8px;
}
 
.spark-modal-content::-webkit-scrollbar-track {
    background: rgba(255, 255, 255, 0.1);
    border-radius: 4px;
}
 
.spark-modal-content::-webkit-scrollbar-thumb {
     background: rgba(255, 255, 255, 0.3);
    border-radius: 4px;
}
 
.spark-modal-content::-webkit-scrollbar-thumb:hover {
    background: rgba(255, 255, 255, 0.5);
}
 
/* 预加载指示器 */
.preload-indicator {
    position: fixed;
    bottom: 10px;
    right: 10px;
    background: rgba(0, 0, 0, 0.7);
    color: #fff;
    padding: 5px 10px;
    border-radius: 4px;
    font-size: 12px;
    z-index: 9998;
    opacity: 0;
    transition: opacity 0.3s ease;
    pointer-events: none;
}
 
.preload-indicator.active {
    opacity: 1;
}
}
</style>
</style>
第375行: 第205行:
     'use strict';
     'use strict';
      
      
     // ==================== 缓存管理器 ====================
     // 等待DOM加载完成
     var SparkCache = {
    if (document.readyState === 'loading') {
         CACHE_KEY: 'spark_card_cache',
        document.addEventListener('DOMContentLoaded', initCardWidget);
         CACHE_VERSION: 'v1',
    } else {
         CACHE_EXPIRE: 24 * 60 * 60 * 1000, // 24小时过期
        initCardWidget();
    }
   
     function initCardWidget() {
        // 创建主模态框
        var mainModal = document.createElement('div');
         mainModal.className = 'card-modal-overlay';
         mainModal.id = 'cardMainModal';
         mainModal.innerHTML = '<span class="card-modal-close">&times;</span><div class="card-modal-content"></div>';
        document.body.appendChild(mainModal);
          
          
         // 获取完整的缓存键
         // 创建闪光模态框
         getFullKey: function() {
         var sparkModal = document.createElement('div');
            return this.CACHE_KEY + '_' + this.CACHE_VERSION;
        sparkModal.className = 'spark-modal-overlay';
         },
        sparkModal.id = 'cardSparkModal';
        sparkModal.innerHTML = '<span class="spark-modal-close">&times;</span><div class="spark-modal-content"><div class="spark-modal-title">✨ 闪光卡牌 ✨</div><div class="spark-card-container"></div></div>';
         document.body.appendChild(sparkModal);
          
          
         // 获取所有缓存
         // 获取所有卡牌元素
         getAll: function() {
         var cards = document.querySelectorAll('.card-deck-trans');
            try {
                var data = localStorage.getItem(this.getFullKey());
                if (!data) return {};
                return JSON.parse(data);
            } catch (e) {
                console.warn('SparkCache: 读取缓存失败', e);
                return {};
            }
        },
          
          
         // 保存所有缓存
         cards.forEach(function(card) {
        saveAll: function(data) {
             // 跳过闪光列表中的卡牌
             try {
            if (card.closest('.spark-card-list') || card.closest('.card-modal-content')) {
                localStorage.setItem(this.getFullKey(), JSON.stringify(data));
                 return;
            } catch (e) {
                console.warn('SparkCache: 保存缓存失败', e);
                // 存储空间不足时,清理过期缓存
                 this.cleanup();
             }
             }
        },
       
        // 获取单个卡牌的闪光列表缓存
        get: function(cardId) {
            var cache = this.getAll();
            var item = cache[cardId];
              
              
             if (!item) return null;
             card.addEventListener('click', function(e) {
           
                e.preventDefault();
            // 检查是否过期
                 e.stopPropagation();
            if (Date.now() - item.timestamp > this.CACHE_EXPIRE) {
                 openCardModal(this);
                delete cache[cardId];
             });
                 this.saveAll(cache);
         });
                 return null;
             }
           
            return item.html;
         },
          
          
         // 设置单个卡牌的闪光列表缓存
         // 关闭主模态框
         set: function(cardId, html) {
         mainModal.querySelector('.card-modal-close').addEventListener('click', function() {
            var cache = this.getAll();
             closeMainModal();
            cache[cardId] = {
         });
                html: html,
                timestamp: Date.now()
             };
            this.saveAll(cache);
         },
          
          
         // 检查是否有缓存
         mainModal.addEventListener('click', function(e) {
        has: function(cardId) {
             if (e.target === mainModal) {
            return this.get(cardId) !== null;
                 closeMainModal();
        },
       
        // 清理过期缓存
        cleanup: function() {
             var cache = this.getAll();
            var now = Date.now();
            var cleaned = false;
           
            for (var cardId in cache) {
                 if (cache.hasOwnProperty(cardId)) {
                    if (now - cache[cardId].timestamp > this.CACHE_EXPIRE) {
                        delete cache[cardId];
                        cleaned = true;
                    }
                }
             }
             }
           
        });
            if (cleaned) {
                this.saveAll(cache);
            }
        },
          
          
         // 清空所有缓存
         // 关闭闪光模态框
         clear: function() {
         sparkModal.querySelector('.spark-modal-close').addEventListener('click', function() {
            try {
             closeSparkModal();
                localStorage.removeItem(this.getFullKey());
         });
            } catch (e) {
                console.warn('SparkCache: 清空缓存失败', e);
             }
         }
    };
   
    // ==================== 预加载队列管理器 ====================
    var PreloadQueue = {
        queue: [],
        isProcessing: false,
        batchSize: 3, // 并发请求数
        activeRequests: 0,
        maxRetries: 2,
        retryDelay: 1000,
          
          
         // 预加载指示器
         sparkModal.addEventListener('click', function(e) {
        indicator: null,
             if (e.target === sparkModal) {
       
                 closeSparkModal();
        // 初始化指示器
        initIndicator: function() {
             if (!this.indicator) {
                this.indicator = document.createElement('div');
                this.indicator.className = 'preload-indicator';
                this.indicator.textContent = '预加载中...';
                 document.body.appendChild(this.indicator);
             }
             }
         },
         });
          
          
         // 显示/隐藏指示器
         // ESC键关闭
         showIndicator: function(show) {
         document.addEventListener('keydown', function(e) {
            this.initIndicator();
             if (e.key === 'Escape') {
             if (show) {
                 if (sparkModal.classList.contains('active')) {
                 this.indicator.classList.add('active');
                    closeSparkModal();
            } else {
                } else if (mainModal.classList.contains('active')) {
                this.indicator.classList.remove('active');
                    closeMainModal();
                }
             }
             }
         },
         });
    }
   
    function openCardModal(cardElement) {
        var modal = document.getElementById('cardMainModal');
        var content = modal.querySelector('.card-modal-content');
          
          
         // 更新指示器文本
         // 克隆卡牌
         updateIndicator: function(current, total) {
         var cardClone = cardElement.cloneNode(true);
            this.initIndicator();
            this.indicator.textContent = '预加载: ' + current + '/' + total;
        },
          
          
         // 添加到预加载队列
         // 创建放大容器
         add: function(cardId, priority) {
         var enlargedContainer = document.createElement('div');
            // 如果已缓存,跳过
        enlargedContainer.className = 'card-modal-card';
            if (SparkCache.has(cardId)) return;
           
            // 如果已在队列中,跳过
            for (var i = 0; i < this.queue.length; i++) {
                if (this.queue[i].cardId === cardId) return;
            }
           
            this.queue.push({
                cardId: cardId,
                priority: priority || 0,
                retries: 0
            });
           
            // 按优先级排序(高优先级在前)
            this.queue.sort(function(a, b) {
                return b.priority - a.priority;
            });
           
            this.process();
        },
          
          
         // 批量添加到预加载队列
         // 获取内部的card-deck
         addBatch: function(cardIds, priority) {
         var cardDeck = cardClone.querySelector('.card-deck');
            var self = this;
        if (cardDeck) {
            cardIds.forEach(function(cardId) {
            enlargedContainer.appendChild(cardDeck);
                self.add(cardId, priority);
        } else {
             });
             enlargedContainer.appendChild(cardClone);
         },
         }
          
          
         // 提升优先级(用于用户即将查看的卡牌)
         // 清空并添加新内容
         prioritize: function(cardId) {
         content.innerHTML = '';
            for (var i = 0; i < this.queue.length; i++) {
        content.appendChild(enlargedContainer);
                if (this.queue[i].cardId === cardId) {
                    this.queue[i].priority = 100;
                    break;
                }
            }
            this.queue.sort(function(a, b) {
                return b.priority - a.priority;
            });
        },
          
          
         // 处理队列
         // 检查是否需要显示闪光按钮
         process: function() {
         var sparkEnable = cardElement.getAttribute('data-spark-enable');
            var self = this;
        var sortType = cardElement.getAttribute('data-sort');
           
            if (this.queue.length === 0) {
                this.showIndicator(false);
                return;
            }
           
            // 控制并发数
            while (this.activeRequests < this.batchSize && this.queue.length > 0) {
                var item = this.queue.shift();
                this.loadSparkList(item);
            }
           
            if (this.activeRequests > 0) {
                this.showIndicator(true);
                this.updateIndicator(this.activeRequests, this.queue.length + this.activeRequests);
            }
        },
          
          
         // 加载闪光卡牌列表
         // 如果没有data属性,尝试从其他地方获取
         loadSparkList: function(item) {
         if (!sparkEnable || !sortType) {
             var self = this;
             // 尝试从页面数据或其他来源获取
            this.activeRequests++;
             var cardData = getCardDataFromElement(cardElement);
           
             sparkEnable = cardData.sparkEnable;
             var api = new mw.Api();
             sortType = cardData.sort;
             api.get({
         }
                action: 'parse',
                text: '{{Card/spark/list|' + item.cardId + '}}',
                prop: 'text',
                disablelimitreport: true,
                format: 'json'
            }).done(function(data) {
                self.activeRequests--;
               
                if (data.parse && data.parse.text) {
                    var html = data.parse.text['*'];
                    SparkCache.set(item.cardId, html);
                   
                    // 更新按钮状态
                    self.updateButtonState(item.cardId, true);
                }
               
                self.process();
             }).fail(function() {
                self.activeRequests--;
               
                // 重试逻辑
                if (item.retries < self.maxRetries) {
                    item.retries++;
                    setTimeout(function() {
                        self.queue.unshift(item);
                        self.process();
                    }, self.retryDelay * item.retries);
                }
               
                self.process();
            });
         },
          
          
         // 更新按钮缓存状态
         // 判断是否显示闪光按钮
         updateButtonState: function(cardId, cached) {
         if (sparkEnable === '1' && sortType !== '中立卡牌' && sortType !== '怪物卡牌') {
             var buttons = document.querySelectorAll('.spark-button[data-card-id="' + cardId + '"]');
             var sparkButton = document.createElement('button');
             buttons.forEach(function(btn) {
            sparkButton.className = 'card-spark-button';
                 if (cached) {
            sparkButton.innerHTML = '✨ 闪光 ✨';
                    btn.classList.add('cached');
             sparkButton.addEventListener('click', function() {
                    btn.classList.remove('loading');
                 openSparkModal(cardElement);
                }
             });
             });
            content.appendChild(sparkButton);
         }
         }
     };
       
        modal.classList.add('active');
        document.body.style.overflow = 'hidden';
     }
      
      
     // ==================== 主逻辑 ====================
     function closeMainModal() {
   
        var modal = document.getElementById('cardMainModal');
    // 确保DOM加载完成
         modal.classList.remove('active');
    if (document.readyState === 'loading') {
         document.body.style.overflow = '';
         document.addEventListener('DOMContentLoaded', initCardWidget);
    } else {
         initCardWidget();
     }
     }
      
      
     function initCardWidget() {
     function openSparkModal(cardElement) {
         // 清理过期缓存
         var modal = document.getElementById('cardSparkModal');
         SparkCache.cleanup();
         var container = modal.querySelector('.spark-card-container');
          
          
         // 创建主模态框元素(如果不存在)
         // 显示加载状态
         var modalOverlay = document.querySelector('.card-modal-overlay');
         container.innerHTML = '<div class="spark-loading">正在加载闪光卡牌</div>';
          
          
         if (!modalOverlay) {
         modal.classList.add('active');
            modalOverlay = document.createElement('div');
            modalOverlay.className = 'card-modal-overlay';
            modalOverlay.innerHTML = '<span class="card-modal-close">&times;</span><div class="card-modal-content"></div>';
            document.body.appendChild(modalOverlay);
        }
          
          
         // 创建闪光卡牌模态框(如果不存在)
         // 获取卡牌ID
         var sparkModalOverlay = document.querySelector('.spark-modal-overlay');
         var cardId = cardElement.getAttribute('data-card-id');
       
         if (!cardId) {
         if (!sparkModalOverlay) {
             cardId = getCardIdFromElement(cardElement);
             sparkModalOverlay = document.createElement('div');
            sparkModalOverlay.className = 'spark-modal-overlay';
            sparkModalOverlay.innerHTML = '<span class="spark-modal-close">&times;</span><div class="spark-modal-content"></div>';
            document.body.appendChild(sparkModalOverlay);
         }
         }
          
          
         var modalContent = modalOverlay.querySelector('.card-modal-content');
         if (cardId) {
        var closeButton = modalOverlay.querySelector('.card-modal-close');
            // 通过API加载闪光卡牌列表
        var sparkModalContent = sparkModalOverlay.querySelector('.spark-modal-content');
             loadSparkCards(cardId, container);
        var sparkCloseButton = sparkModalOverlay.querySelector('.spark-modal-close');
        } else {
       
            container.innerHTML = '<div style="color: #fff; text-align: center; padding: 50px;">无法获取卡牌信息</div>';
        // 当前放大的闪光卡牌容器
        var currentEnlargedContainer = null;
       
        // 关闭主模态框函数
        function closeModal() {
             modalOverlay.classList.add('fade-out');
            setTimeout(function() {
                modalOverlay.classList.remove('active', 'fade-in', 'fade-out');
                modalContent.innerHTML = '';
                document.body.classList.remove('card-modal-open');
            }, 300);
         }
         }
    }
   
    function closeSparkModal() {
        var modal = document.getElementById('cardSparkModal');
        modal.classList.remove('active');
    }
   
    function getCardDataFromElement(element) {
        // 尝试从元素的class或子元素中推断数据
        var data = {
            sparkEnable: '0',
            sort: ''
        };
          
          
         // 关闭闪光模态框函数
         // 检查是否有闪光标记
         function closeSparkModal() {
         if (element.querySelector('.card-spark-flag')) {
            // 先关闭放大的卡牌
             // 有闪光图标意味着spark_flag为真,但我们需要spark_enable
            if (currentEnlargedContainer) {
                currentEnlargedContainer.remove();
                currentEnlargedContainer = null;
            }
           
            sparkModalOverlay.classList.add('fade-out');
            setTimeout(function() {
                sparkModalOverlay.classList.remove('active', 'fade-in', 'fade-out');
                sparkModalContent.innerHTML = '';
             }, 300);
         }
         }
          
          
         // 关闭放大的闪光卡牌
         // 检查是否有禁忌装饰
         function closeEnlargedCard() {
         if (element.querySelector('.card-deco-taboo')) {
             if (currentEnlargedContainer) {
             data.sort = '禁忌卡牌';
                currentEnlargedContainer.remove();
                currentEnlargedContainer = null;
            }
         }
         }
          
          
         // 打开主模态框函数
         // 检查职业图标来判断是否为中立卡牌
         function openModal(cardElement, cardId, sparkEnable) {
         if (element.querySelector('.card-job1') && element.querySelector('.card-job2')) {
            var cardClone = cardElement.cloneNode(true);
            data.sort = '中立卡牌';
            // 移除克隆卡牌的点击事件标记
            delete cardClone.dataset.cardBound;
           
            modalContent.innerHTML = '';
            modalContent.appendChild(cardClone);
           
            // 如果启用了闪光功能,添加闪光按钮
            if (sparkEnable && sparkEnable.trim() !== '') {
                var sparkButton = document.createElement('button');
                sparkButton.className = 'spark-button';
                sparkButton.textContent = '闪光';
                sparkButton.dataset.cardId = cardId;
               
                // 检查是否已缓存
                if (SparkCache.has(cardId)) {
                    sparkButton.classList.add('cached');
                } else {
                    // 提升优先级预加载
                    PreloadQueue.prioritize(cardId);
                }
               
                sparkButton.addEventListener('click', function() {
                    openSparkModal(cardId);
                });
                modalContent.appendChild(sparkButton);
            }
           
            modalOverlay.classList.add('active');
            document.body.classList.add('card-modal-open');
           
            // 强制重绘后添加fade-in
            requestAnimationFrame(function() {
                modalOverlay.classList.add('fade-in');
            });
         }
         }
          
          
         // 打开闪光卡牌模态框
         return data;
        function openSparkModal(cardId) {
    }
            // 首先检查缓存
   
            var cachedHtml = SparkCache.get(cardId);
    function getCardIdFromElement(element) {
           
        // 尝试从图片名称获取卡牌ID
            if (cachedHtml) {
        var artImg = element.querySelector('.card-art img');
                // 使用缓存,立即显示
        if (artImg) {
                showSparkContent(cachedHtml, true);
            var src = artImg.getAttribute('src') || '';
            } else {
             var match = src.match(/\/([^\/]+)\.png/);
                // 无缓存,显示加载中并请求
            if (match) {
                sparkModalContent.innerHTML = '<div class="spark-modal-title">闪光卡牌列表</div><div class="spark-loading">加载中</div>';
                 return match[1];
               
                sparkModalOverlay.classList.add('active');
                requestAnimationFrame(function() {
                    sparkModalOverlay.classList.add('fade-in');
                });
               
                // 发起请求
                loadSparkListDirect(cardId);
            }
           
            function showSparkContent(html, fromCache) {
                // 检查是否有卡牌
                var tempDiv = document.createElement('div');
                tempDiv.innerHTML = html;
                var cards = tempDiv.querySelectorAll('.card-deck-trans');
               
                var cacheHint = fromCache ? '<div class="spark-cache-hint">已从缓存加载</div>' : '';
               
                if (cards.length > 0) {
                    sparkModalContent.innerHTML = '<div class="spark-modal-title">闪光卡牌列表</div>' + html + cacheHint;
                    // 为闪光列表中的卡牌绑定事件
                    bindSparkListCardEvents();
                } else {
                    sparkModalContent.innerHTML = '<div class="spark-modal-title">闪光卡牌列表</div><div class="spark-empty">暂无闪光卡牌</div>' + cacheHint;
                }
               
                if (!sparkModalOverlay.classList.contains('active')) {
                    sparkModalOverlay.classList.add('active');
                    requestAnimationFrame(function() {
                        sparkModalOverlay.classList.add('fade-in');
                    });
                }
            }
           
             function loadSparkListDirect(cardId) {
                var api = new mw.Api();
                api.get({
                    action: 'parse',
                    text: '{{Card/spark/list|' + cardId + '}}',
                    prop: 'text',
                    disablelimitreport: true,
                    format: 'json'
                }).done(function(data) {
                    if (data.parse && data.parse.text) {
                        var html = data.parse.text['*'];
                       
                        // 存入缓存
                        SparkCache.set(cardId, html);
                       
                        // 更新按钮状态
                        PreloadQueue.updateButtonState(cardId, true);
                       
                        // 显示内容
                        showSparkContent(html, false);
                    }
                }).fail(function() {
                    sparkModalContent.innerHTML = '<div class="spark-modal-title">闪光卡牌列表</div><div class="spark-empty">加载失败,请重试</div>';
                 });
             }
             }
         }
         }
        return null;
    }
   
    function loadSparkCards(cardId, container) {
        // 使用MediaWiki API进行解析
        var api = mw.config.get('wgScriptPath') + '/api.php';
        var wikitext = '{{Card/display/spark|' + cardId + '}}';
          
          
         // 为闪光列表中的卡牌绑定点击事件
         fetch(api + '?action=parse&text=' + encodeURIComponent(wikitext) + '&contentmodel=wikitext&format=json&disablelimitreport=1', {
        function bindSparkListCardEvents() {
             method: 'GET',
            var sparkCards = sparkModalContent.querySelectorAll('.card-deck-trans');
             headers: {
            sparkCards.forEach(function(card) {
                'Accept': 'application/json'
                if (card.dataset.sparkBound) return;
                card.dataset.sparkBound = 'true';
               
                card.addEventListener('click', function(e) {
                    e.preventDefault();
                    e.stopPropagation();
                   
                    // 关闭之前放大的卡牌
                    closeEnlargedCard();
                   
                    // 创建放大容器
                    var enlargedContainer = document.createElement('div');
                    enlargedContainer.className = 'spark-enlarged-container';
                   
                    // 添加关闭按钮
                    var closeBtn = document.createElement('span');
                    closeBtn.className = 'spark-enlarged-close';
                    closeBtn.innerHTML = '&times;';
                    closeBtn.addEventListener('click', function(e) {
                        e.stopPropagation();
                        closeEnlargedCard();
                    });
                    enlargedContainer.appendChild(closeBtn);
                   
                    // 创建卡牌内容区
                    var cardContent = document.createElement('div');
                    cardContent.className = 'spark-enlarged-card';
                   
                    var cardClone = this.cloneNode(true);
                    delete cardClone.dataset.sparkBound;
                    cardContent.appendChild(cardClone);
                   
                    enlargedContainer.appendChild(cardContent);
                   
                    // 点击背景关闭
                    enlargedContainer.addEventListener('click', function(e) {
                        if (e.target === enlargedContainer) {
                            closeEnlargedCard();
                        }
                    });
                   
                    document.body.appendChild(enlargedContainer);
                    currentEnlargedContainer = enlargedContainer;
                });
             });
        }
       
        // 绑定关闭按钮事件
        closeButton.addEventListener('click', function(e) {
             e.stopPropagation();
            closeModal();
        });
       
        sparkCloseButton.addEventListener('click', function(e) {
            e.stopPropagation();
            closeSparkModal();
        });
       
        // 点击遮罩关闭
        modalOverlay.addEventListener('click', function(e) {
            if (e.target === modalOverlay) {
                closeModal();
             }
             }
         });
         })
       
         .then(function(response) {
         sparkModalOverlay.addEventListener('click', function(e) {
             return response.json();
             if (e.target === sparkModalOverlay) {
         })
                closeSparkModal();
         .then(function(data) {
            }
             if (data.parse && data.parse.text) {
         });
                 var html = data.parse.text['*'];
       
                 container.innerHTML = html;
        // ESC键关闭
         document.addEventListener('keydown', function(e) {
             if (e.key === 'Escape') {
                // 优先关闭放大的闪光卡牌
                if (currentEnlargedContainer) {
                    closeEnlargedCard();
                } else if (sparkModalOverlay.classList.contains('active')) {
                    closeSparkModal();
                } else if (modalOverlay.classList.contains('active')) {
                    closeModal();
                }
            }
        });
       
        // 收集页面上所有启用闪光的卡牌ID
        function collectSparkCardIds() {
            var cardIds = [];
            var cards = document.querySelectorAll('.card-deck-trans[data-spark-enable]');
           
            cards.forEach(function(card) {
                var sparkEnable = card.dataset.sparkEnable;
                if (sparkEnable && sparkEnable.trim() !== '') {
                    var wrapper = card.closest('.card-wrapper');
                    var cardId = wrapper ? wrapper.dataset.cardId : '';
                    if (cardId && cardIds.indexOf(cardId) === -1) {
                        cardIds.push(cardId);
                    }
                 }
            });
           
            return cardIds;
        }
       
        // 为所有卡牌绑定点击事件
        function bindCardEvents() {
            var cards = document.querySelectorAll('.card-deck-trans');
            var sparkCardIds = [];
           
            cards.forEach(function(card) {
                // 避免重复绑定
                 if (card.dataset.cardBound) return;
                card.dataset.cardBound = 'true';
                  
                  
                 // 排除模态框内的卡牌
                 // 如果没有卡牌
                 if (card.closest('.card-modal-overlay') || card.closest('.spark-modal-overlay') || card.closest('.spark-enlarged-container')) return;
                 if (!container.querySelector('.card-deck-trans')) {
               
                     container.innerHTML = '<div style="color: #fff; text-align: center; padding: 50px;">暂无闪光卡牌</div>';
                // 收集启用闪光的卡牌ID用于预加载
                var sparkEnable = card.dataset.sparkEnable;
                if (sparkEnable && sparkEnable.trim() !== '') {
                     var wrapper = card.closest('.card-wrapper');
                    var cardId = wrapper ? wrapper.dataset.cardId : '';
                    if (cardId && sparkCardIds.indexOf(cardId) === -1) {
                        sparkCardIds.push(cardId);
                    }
                }
               
                card.addEventListener('click', function(e) {
                    e.preventDefault();
                   
                    // 从card-deck-trans元素获取spark_enable
                    var sparkEnable = this.dataset.sparkEnable || '';
                   
                    // 获取card-id从父级card-wrapper
                    var wrapper = this.closest('.card-wrapper');
                    var cardId = wrapper ? wrapper.dataset.cardId : '';
                   
                    openModal(this, cardId, sparkEnable);
                });
               
                // 鼠标悬停时预加载
                card.addEventListener('mouseenter', function() {
                    var sparkEnable = this.dataset.sparkEnable || '';
                    if (sparkEnable && sparkEnable.trim() !== '') {
                        var wrapper = this.closest('.card-wrapper');
                        var cardId = wrapper ? wrapper.dataset.cardId : '';
                        if (cardId) {
                            // 高优先级预加载
                            PreloadQueue.add(cardId, 50);
                        }
                    }
                });
            });
           
            // 延迟低优先级预加载页面上所有闪光卡牌
            if (sparkCardIds.length > 0) {
                setTimeout(function() {
                    PreloadQueue.addBatch(sparkCardIds, 1);
                }, 2000);
            }
        }
       
        // 初始绑定
        bindCardEvents();
       
        // 监听DOM变化,为动态加载的卡牌绑定事件
        var observer = new MutationObserver(function(mutations) {
            var shouldBind = false;
            mutations.forEach(function(mutation) {
                if (mutation.addedNodes.length > 0) {
                    mutation.addedNodes.forEach(function(node) {
                        if (node.nodeType === 1) {
                            if (node.classList && node.classList.contains('card-deck-trans')) {
                                shouldBind = true;
                            } else if (node.querySelector && node.querySelector('.card-deck-trans')) {
                                shouldBind = true;
                            }
                        }
                    });
                 }
                 }
            });
            if (shouldBind) {
                bindCardEvents();
            }
        });
       
        observer.observe(document.body, {
            childList: true,
            subtree: true
        });
       
        // 页面可见性变化时暂停/恢复预加载
        document.addEventListener('visibilitychange', function() {
            if (document.hidden) {
                // 页面不可见时,暂停预加载(通过不处理队列)
             } else {
             } else {
                 // 页面可见时,恢复预加载
                 container.innerHTML = '<div style="color: #fff; text-align: center; padding: 50px;">加载失败,请重试</div>';
                PreloadQueue.process();
             }
             }
        })
        .catch(function(error) {
            console.error('加载闪光卡牌失败:', error);
            container.innerHTML = '<div style="color: #fff; text-align: center; padding: 50px;">加载失败,请重试</div>';
         });
         });
     }
     }

2026年1月17日 (六) 16:47的版本

此Widget为卡牌显示提供交互功能,包括悬停动画、点击放大和闪光卡牌列表显示。