微件:Card:修订间差异

来自卡厄思梦境WIKI
跳转到导航 跳转到搜索
律Rhyme留言 | 贡献
功能测试
律Rhyme留言 | 贡献
功能测试
第1行: 第1行:
<noinclude>
<includeonly>
此Widget为卡牌显示添加交互效果:
* 鼠标悬停时的动画效果
* 点击后显示放大的模态框
* 自动检测spark_enable属性显示闪光按钮
* 支持闪光卡牌列表显示
 
使用方法:在页面底部添加 <code>{{#widget:Card}}</code>
</noinclude><includeonly>
<style>
<style>
/* 卡牌容器 */
/* 卡牌容器 */
第170行: 第162行:
     transform: translateY(0);
     transform: translateY(0);
     box-shadow: 0 2px 10px rgba(102, 126, 234, 0.4);
     box-shadow: 0 2px 10px rgba(102, 126, 234, 0.4);
}
/* 闪光按钮状态 */
.spark-button.loading {
    opacity: 0.7;
    cursor: wait;
}
.spark-button.cached::after {
    content: " ✓";
    color: #90EE90;
}
}


/* 闪光图标动画 */
/* 闪光图标动画 */
.spark-button::before {
.spark-button:not(.loading)::before {
     content: "✦ ";
     content: "✦ ";
     animation: sparkle 1.5s ease-in-out infinite;
     animation: sparkle 1.5s ease-in-out infinite;
}
.spark-button::after {
    content: " ✦";
    animation: sparkle 1.5s ease-in-out infinite 0.75s;
}
}


第246行: 第244行:
     50% { content: ".."; }
     50% { content: ".."; }
     75% { content: "..."; }
     75% { content: "..."; }
}
/* 加载进度 */
.spark-loading-progress {
    color: #aaa;
    font-size: 14px;
    margin-top: 10px;
}
}


第254行: 第259行:
     text-align: center;
     text-align: center;
     padding: 40px;
     padding: 40px;
}
/* 缓存状态提示 */
.spark-cache-hint {
    color: #666;
    font-size: 12px;
    text-align: center;
    margin-top: 15px;
}
}


第343行: 第356行:
     'use strict';
     'use strict';
      
      
     // 确保DOM加载完成
     // ==================== 缓存管理器(优化版) ====================
     if (document.readyState === 'loading') {
     var SparkCache = (function() {
        document.addEventListener('DOMContentLoaded', initCardWidget);
        var CACHE_KEY = 'spark_card_cache_v2';
    } else {
        var CACHE_EXPIRE = 24 * 60 * 60 * 1000; // 24小时
        initCardWidget();
       
    }
        // 内存缓存层
   
        var memoryCache = null;
    function initCardWidget() {
        var isDirty = false;
         // 创建主模态框元素(如果不存在)
        var saveTimer = null;
         var modalOverlay = document.querySelector('.card-modal-overlay');
       
        // 从 localStorage 加载到内存
        function loadFromStorage() {
            if (memoryCache !== null) return memoryCache;
           
            try {
                var data = localStorage.getItem(CACHE_KEY);
                memoryCache = data ? JSON.parse(data) : {};
            } catch (e) {
                memoryCache = {};
            }
            return memoryCache;
        }
       
         // 延迟批量写入 localStorage
         function scheduleSave() {
            if (saveTimer) return;
           
            saveTimer = setTimeout(function() {
                saveTimer = null;
                if (isDirty && memoryCache) {
                    try {
                        localStorage.setItem(CACHE_KEY, JSON.stringify(memoryCache));
                        isDirty = false;
                    } catch (e) {
                        // 存储空间不足,清理旧数据
                        cleanup(true);
                    }
                }
            }, 1000); // 1秒后批量写入
        }
          
          
         if (!modalOverlay) {
         // 清理过期缓存
             modalOverlay = document.createElement('div');
        function cleanup(force) {
             modalOverlay.className = 'card-modal-overlay';
             var cache = loadFromStorage();
            modalOverlay.innerHTML = '<span class="card-modal-close">&times;</span><div class="card-modal-content"></div>';
            var now = Date.now();
             document.body.appendChild(modalOverlay);
             var hasChanges = false;
            var keys = Object.keys(cache);
           
            // 强制清理时,删除最旧的一半
            if (force && keys.length > 10) {
                var items = keys.map(function(k) {
                    return { key: k, time: cache[k].timestamp };
                }).sort(function(a, b) {
                    return a.time - b.time;
                });
               
                var deleteCount = Math.floor(items.length / 2);
                for (var i = 0; i < deleteCount; i++) {
                    delete cache[items[i].key];
                    hasChanges = true;
                }
            } else {
                // 正常清理过期数据
                for (var cardId in cache) {
                    if (cache.hasOwnProperty(cardId) && now - cache[cardId].timestamp > CACHE_EXPIRE) {
                        delete cache[cardId];
                        hasChanges = true;
                    }
                }
            }
           
             if (hasChanges) {
                isDirty = true;
                scheduleSave();
            }
         }
         }
          
          
         // 创建闪光卡牌模态框(如果不存在)
         return {
        var sparkModalOverlay = document.querySelector('.spark-modal-overlay');
            get: function(cardId) {
                var cache = loadFromStorage();
                var item = cache[cardId];
               
                if (!item) return null;
                if (Date.now() - item.timestamp > CACHE_EXPIRE) {
                    delete cache[cardId];
                    isDirty = true;
                    scheduleSave();
                    return null;
                }
               
                return item.html;
            },
           
            set: function(cardId, html) {
                var cache = loadFromStorage();
                cache[cardId] = {
                    html: html,
                    timestamp: Date.now()
                };
                isDirty = true;
                scheduleSave();
            },
           
            has: function(cardId) {
                var cache = loadFromStorage();
                var item = cache[cardId];
                return item && (Date.now() - item.timestamp <= CACHE_EXPIRE);
            },
           
            // 批量获取
            getMultiple: function(cardIds) {
                var cache = loadFromStorage();
                var now = Date.now();
                var result = {};
                var hasExpired = false;
               
                cardIds.forEach(function(cardId) {
                    var item = cache[cardId];
                    if (item) {
                        if (now - item.timestamp <= CACHE_EXPIRE) {
                            result[cardId] = item.html;
                        } else {
                            delete cache[cardId];
                            hasExpired = true;
                        }
                    }
                });
               
                if (hasExpired) {
                    isDirty = true;
                    scheduleSave();
                }
               
                return result;
            },
           
            // 批量设置
            setMultiple: function(dataMap) {
                var cache = loadFromStorage();
                var now = Date.now();
               
                for (var cardId in dataMap) {
                    if (dataMap.hasOwnProperty(cardId)) {
                        cache[cardId] = {
                            html: dataMap[cardId],
                            timestamp: now
                        };
                    }
                }
               
                isDirty = true;
                scheduleSave();
            },
           
            cleanup: cleanup,
           
            // 页面卸载时立即保存
            flush: function() {
                if (saveTimer) {
                    clearTimeout(saveTimer);
                    saveTimer = null;
                }
                if (isDirty && memoryCache) {
                    try {
                        localStorage.setItem(CACHE_KEY, JSON.stringify(memoryCache));
                        isDirty = false;
                    } catch (e) {}
                }
            }
        };
    })();
   
    // ==================== 批量API请求管理器 ====================
    var BatchRequestManager = (function() {
        var pendingRequests = {};  // cardId -> [resolve, reject][]
        var requestQueue = [];
        var isProcessing = false;
        var batchSize = 5;  // 每批并行请求数
        var batchDelay = 50; // 批次间延迟
          
          
         if (!sparkModalOverlay) {
         function processBatch() {
             sparkModalOverlay = document.createElement('div');
            if (isProcessing || requestQueue.length === 0) return;
             sparkModalOverlay.className = 'spark-modal-overlay';
           
             sparkModalOverlay.innerHTML = '<span class="spark-modal-close">&times;</span><div class="spark-modal-content"></div>';
            isProcessing = true;
             document.body.appendChild(sparkModalOverlay);
           
            // 取出一批
             var batch = requestQueue.splice(0, batchSize);
             var promises = batch.map(function(cardId) {
                return fetchSparkList(cardId);
            });
              
            Promise.all(promises).then(function() {
                isProcessing = false;
                if (requestQueue.length > 0) {
                    setTimeout(processBatch, batchDelay);
                }
             });
         }
         }
          
          
         var modalContent = modalOverlay.querySelector('.card-modal-content');
         function fetchSparkList(cardId) {
        var closeButton = modalOverlay.querySelector('.card-modal-close');
            return new Promise(function(resolve) {
        var sparkModalContent = sparkModalOverlay.querySelector('.spark-modal-content');
                var api = new mw.Api();
        var sparkCloseButton = sparkModalOverlay.querySelector('.spark-modal-close');
                api.get({
                    action: 'parse',
                    text: '{{Card/spark/list|' + cardId + '}}',
                    prop: 'text',
                    disablelimitreport: true,
                    format: 'json'
                }).done(function(data) {
                    var html = '';
                    if (data.parse && data.parse.text) {
                        html = data.parse.text['*'];
                        SparkCache.set(cardId, html);
                    }
                   
                    // 通知所有等待者
                    var callbacks = pendingRequests[cardId] || [];
                    delete pendingRequests[cardId];
                    callbacks.forEach(function(cb) {
                        cb.resolve(html);
                    });
                   
                    resolve();
                }).fail(function(error) {
                    var callbacks = pendingRequests[cardId] || [];
                    delete pendingRequests[cardId];
                    callbacks.forEach(function(cb) {
                        cb.reject(error);
                    });
                   
                    resolve();
                });
            });
        }
          
          
         // 当前放大的闪光卡牌容器
         return {
            // 请求单个卡牌(会自动合并到批量请求)
            request: function(cardId) {
                return new Promise(function(resolve, reject) {
                    // 先检查缓存
                    var cached = SparkCache.get(cardId);
                    if (cached !== null) {
                        resolve(cached);
                        return;
                    }
                   
                    // 检查是否已在请求中
                    if (pendingRequests[cardId]) {
                        pendingRequests[cardId].push({ resolve: resolve, reject: reject });
                        return;
                    }
                   
                    // 新请求
                    pendingRequests[cardId] = [{ resolve: resolve, reject: reject }];
                    requestQueue.push(cardId);
                   
                    // 启动处理
                    if (!isProcessing) {
                        setTimeout(processBatch, 10);
                    }
                });
            },
           
            // 预加载多个卡牌(低优先级)
            preload: function(cardIds) {
                // 过滤掉已缓存和已在队列中的
                var toLoad = cardIds.filter(function(cardId) {
                    return !SparkCache.has(cardId) &&
                          !pendingRequests[cardId] &&
                          requestQueue.indexOf(cardId) === -1;
                });
               
                if (toLoad.length === 0) return;
               
                // 添加到队列末尾
                toLoad.forEach(function(cardId) {
                    pendingRequests[cardId] = [];
                    requestQueue.push(cardId);
                });
               
                // 启动处理
                if (!isProcessing) {
                    setTimeout(processBatch, 100);
                }
            },
           
            // 提升优先级
            prioritize: function(cardId) {
                var idx = requestQueue.indexOf(cardId);
                if (idx > 0) {
                    requestQueue.splice(idx, 1);
                    requestQueue.unshift(cardId);
                }
            }
        };
    })();
   
    // ==================== DOM 管理器 ====================
    var DOMManager = (function() {
        var modalOverlay = null;
        var sparkModalOverlay = null;
        var modalContent = null;
        var sparkModalContent = null;
         var currentEnlargedContainer = null;
         var currentEnlargedContainer = null;
        var processedCards = new WeakSet();  // 使用 WeakSet 跟踪已处理的卡牌
          
          
         // 关闭主模态框函数
         // 创建模态框
        function createModals() {
            if (!modalOverlay) {
                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);
                modalContent = modalOverlay.querySelector('.card-modal-content');
            }
           
            if (!sparkModalOverlay) {
                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);
                sparkModalContent = sparkModalOverlay.querySelector('.spark-modal-content');
            }
        }
       
        // 关闭主模态框
         function closeModal() {
         function closeModal() {
            if (!modalOverlay) return;
           
             modalOverlay.classList.add('fade-out');
             modalOverlay.classList.add('fade-out');
             setTimeout(function() {
             setTimeout(function() {
第389行: 第693行:
         }
         }
          
          
         // 关闭闪光模态框函数
         // 关闭闪光模态框
         function closeSparkModal() {
         function closeSparkModal() {
             // 先关闭放大的卡牌
             closeEnlargedCard();
             if (currentEnlargedContainer) {
           
                currentEnlargedContainer.remove();
             if (!sparkModalOverlay) return;
                currentEnlargedContainer = null;
            }
              
              
             sparkModalOverlay.classList.add('fade-out');
             sparkModalOverlay.classList.add('fade-out');
第412行: 第714行:
         }
         }
          
          
         // 打开主模态框函数
         // 打开主模态框
         function openModal(cardElement, cardId, sparkEnable) {
         function openModal(cardElement, cardId, sparkEnable) {
            createModals();
           
             var cardClone = cardElement.cloneNode(true);
             var cardClone = cardElement.cloneNode(true);
            // 移除克隆卡牌的点击事件标记
            delete cardClone.dataset.cardBound;
           
             modalContent.innerHTML = '';
             modalContent.innerHTML = '';
             modalContent.appendChild(cardClone);
             modalContent.appendChild(cardClone);
              
              
             // 如果启用了闪光功能,添加闪光按钮
             // 如果启用了闪光功能
             if (sparkEnable && sparkEnable.trim() !== '') {
             if (sparkEnable && sparkEnable.trim() !== '') {
                 var sparkButton = document.createElement('button');
                 var sparkButton = document.createElement('button');
第427行: 第728行:
                 sparkButton.textContent = '闪光';
                 sparkButton.textContent = '闪光';
                 sparkButton.dataset.cardId = cardId;
                 sparkButton.dataset.cardId = cardId;
                 sparkButton.addEventListener('click', function() {
                  
                     openSparkModal(cardId);
                if (SparkCache.has(cardId)) {
                 });
                    sparkButton.classList.add('cached');
                } else {
                     BatchRequestManager.prioritize(cardId);
                 }
               
                 modalContent.appendChild(sparkButton);
                 modalContent.appendChild(sparkButton);
             }
             }
第436行: 第741行:
             document.body.classList.add('card-modal-open');
             document.body.classList.add('card-modal-open');
              
              
            // 强制重绘后添加fade-in
             requestAnimationFrame(function() {
             requestAnimationFrame(function() {
                 modalOverlay.classList.add('fade-in');
                 modalOverlay.classList.add('fade-in');
第444行: 第748行:
         // 打开闪光卡牌模态框
         // 打开闪光卡牌模态框
         function openSparkModal(cardId) {
         function openSparkModal(cardId) {
             sparkModalContent.innerHTML = '<div class="spark-modal-title">闪光卡牌列表</div><div class="spark-loading">加载中</div>';
             createModals();
           
            var cachedHtml = SparkCache.get(cardId);
              
              
             sparkModalOverlay.classList.add('active');
             if (cachedHtml) {
             requestAnimationFrame(function() {
                showSparkContent(cachedHtml, true);
                sparkModalOverlay.classList.add('fade-in');
            } else {
             });
                sparkModalContent.innerHTML = '<div class="spark-modal-title">闪光卡牌列表</div><div class="spark-loading">加载中</div>';
               
                sparkModalOverlay.classList.add('active');
                requestAnimationFrame(function() {
                    sparkModalOverlay.classList.add('fade-in');
                });
               
                BatchRequestManager.request(cardId).then(function(html) {
                    showSparkContent(html, false);
                }).catch(function() {
                    sparkModalContent.innerHTML = '<div class="spark-modal-title">闪光卡牌列表</div><div class="spark-empty">加载失败,请重试</div>';
                });
            }
        }
       
        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;
            } 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 showEnlargedCard(cardElement) {
            closeEnlargedCard();
           
            var enlargedContainer = document.createElement('div');
            enlargedContainer.className = 'spark-enlarged-container';
           
            var closeBtn = document.createElement('span');
            closeBtn.className = 'spark-enlarged-close';
            closeBtn.innerHTML = '&times;';
            enlargedContainer.appendChild(closeBtn);
           
            var cardContent = document.createElement('div');
            cardContent.className = 'spark-enlarged-card';
            cardContent.appendChild(cardElement.cloneNode(true));
            enlargedContainer.appendChild(cardContent);
           
            document.body.appendChild(enlargedContainer);
            currentEnlargedContainer = enlargedContainer;
        }
       
        // 处理新添加的卡牌节点
        function processNewCards(nodes) {
            var sparkCardIds = [];
              
              
             // 通过API获取闪光卡牌列表
             nodes.forEach(function(node) {
            var api = new mw.Api();
                 if (node.nodeType !== 1) return;
            api.get({
                  
                 action: 'parse',
                 var cards = [];
                 text: '{{Card/display/spark|' + cardId + '}}',
                 if (node.classList && node.classList.contains('card-deck-trans')) {
                 prop: 'text',
                     cards.push(node);
                disablelimitreport: true,
                }
                format: 'json'
                if (node.querySelectorAll) {
            }).done(function(data) {
                     var found = node.querySelectorAll('.card-deck-trans');
                 if (data.parse && data.parse.text) {
                     for (var i = 0; i < found.length; i++) {
                     var html = data.parse.text['*'];
                         cards.push(found[i]);
                   
                    // 检查是否有卡牌
                    var tempDiv = document.createElement('div');
                    tempDiv.innerHTML = html;
                     var cards = tempDiv.querySelectorAll('.card-deck-trans');
                      
                    if (cards.length > 0) {
                         sparkModalContent.innerHTML = '<div class="spark-modal-title">闪光卡牌列表</div>' + html;
                        // 为闪光列表中的卡牌绑定事件
                        bindSparkListCardEvents();
                    } else {
                        sparkModalContent.innerHTML = '<div class="spark-modal-title">闪光卡牌列表</div><div class="spark-empty">暂无闪光卡牌</div>';
                     }
                     }
                 }
                 }
            }).fail(function() {
                sparkModalContent.innerHTML = '<div class="spark-modal-title">闪光卡牌列表</div><div class="spark-empty">加载失败,请重试</div>';
            });
        }
       
        // 为闪光列表中的卡牌绑定点击事件
        function bindSparkListCardEvents() {
            var sparkCards = sparkModalContent.querySelectorAll('.card-deck-trans');
            sparkCards.forEach(function(card) {
                if (card.dataset.sparkBound) return;
                card.dataset.sparkBound = 'true';
                  
                  
                 card.addEventListener('click', function(e) {
                 cards.forEach(function(card) {
                     e.preventDefault();
                     // 跳过已处理的和模态框内的
                     e.stopPropagation();
                     if (processedCards.has(card)) return;
                      
                     if (card.closest('.card-modal-overlay') ||
                    // 关闭之前放大的卡牌
                        card.closest('.spark-modal-overlay') ||
                    closeEnlargedCard();
                         card.closest('.spark-enlarged-container')) return;
                   
                    // 创建放大容器
                    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);
                     processedCards.add(card);
                      
                      
                     // 点击背景关闭
                     // 收集需要预加载的卡牌ID
                     enlargedContainer.addEventListener('click', function(e) {
                     var sparkEnable = card.dataset.sparkEnable;
                         if (e.target === enlargedContainer) {
                    if (sparkEnable && sparkEnable.trim() !== '') {
                             closeEnlargedCard();
                        var wrapper = card.closest('.card-wrapper');
                        var cardId = wrapper ? wrapper.dataset.cardId : '';
                         if (cardId && sparkCardIds.indexOf(cardId) === -1) {
                             sparkCardIds.push(cardId);
                         }
                         }
                     });
                     }
                   
                    document.body.appendChild(enlargedContainer);
                    currentEnlargedContainer = enlargedContainer;
                 });
                 });
             });
             });
           
            // 延迟预加载
            if (sparkCardIds.length > 0) {
                setTimeout(function() {
                    BatchRequestManager.preload(sparkCardIds);
                }, 2000);
            }
         }
         }
          
          
         // 绑定关闭按钮事件
         // 初始化页面上已有的卡牌
         closeButton.addEventListener('click', function(e) {
         function initExistingCards() {
            e.stopPropagation();
            var cards = document.querySelectorAll('.card-deck-trans');
             closeModal();
            var nodeArray = [];
         });
            cards.forEach(function(card) {
                nodeArray.push(card);
            });
             processNewCards(nodeArray);
         }
          
          
         sparkCloseButton.addEventListener('click', function(e) {
         return {
             e.stopPropagation();
            createModals: createModals,
            closeSparkModal();
            closeModal: closeModal,
         });
            closeSparkModal: closeSparkModal,
            closeEnlargedCard: closeEnlargedCard,
            openModal: openModal,
            openSparkModal: openSparkModal,
            showEnlargedCard: showEnlargedCard,
            processNewCards: processNewCards,
            initExistingCards: initExistingCards,
            getModalOverlay: function() { return modalOverlay; },
             getSparkModalOverlay: function() { return sparkModalOverlay; }
        };
    })();
   
    // ==================== 事件委托管理器 ====================
    var EventManager = (function() {
         var hoverTimer = null;
          
          
         // 点击遮罩关闭
         // 获取卡牌信息
         modalOverlay.addEventListener('click', function(e) {
         function getCardInfo(cardElement) {
             if (e.target === modalOverlay) {
             var wrapper = cardElement.closest('.card-wrapper');
                 closeModal();
            return {
             }
                 cardId: wrapper ? wrapper.dataset.cardId : '',
         });
                sparkEnable: cardElement.dataset.sparkEnable || ''
             };
         }
          
          
         sparkModalOverlay.addEventListener('click', function(e) {
         // 检查是否是有效的卡牌点击
             if (e.target === sparkModalOverlay) {
        function isValidCardClick(target) {
                closeSparkModal();
            var card = target.closest('.card-deck-trans');
             }
            if (!card) return null;
         });
           
            // 排除模态框内的卡牌(除了闪光列表中的)
             var inMainModal = card.closest('.card-modal-content');
            var inSparkList = card.closest('.spark-card-list');
            var inEnlarged = card.closest('.spark-enlarged-container');
           
            if (inMainModal && !inSparkList) return null;
            if (inEnlarged) return null;
              
            return card;
         }
          
          
         // ESC键关闭
         // 初始化事件监听
         document.addEventListener('keydown', function(e) {
         function init() {
            if (e.key === 'Escape') {
            // 使用事件委托处理所有点击事件
                 // 优先关闭放大的闪光卡牌
            document.addEventListener('click', function(e) {
                if (currentEnlargedContainer) {
                var target = e.target;
                    closeEnlargedCard();
               
                 } else if (sparkModalOverlay.classList.contains('active')) {
                 // 关闭按钮
                     closeSparkModal();
                 if (target.classList.contains('card-modal-close')) {
                } else if (modalOverlay.classList.contains('active')) {
                     e.stopPropagation();
                     closeModal();
                    DOMManager.closeModal();
                     return;
                 }
                 }
            }
               
        });
                if (target.classList.contains('spark-modal-close')) {
       
                    e.stopPropagation();
        // 为所有卡牌绑定点击事件
                    DOMManager.closeSparkModal();
        function bindCardEvents() {
                    return;
            var cards = document.querySelectorAll('.card-deck-trans');
                }
               
                if (target.classList.contains('spark-enlarged-close')) {
                    e.stopPropagation();
                    DOMManager.closeEnlargedCard();
                    return;
                }
               
                // 闪光按钮
                if (target.classList.contains('spark-button')) {
                    e.preventDefault();
                    var cardId = target.dataset.cardId;
                    if (cardId) {
                        DOMManager.openSparkModal(cardId);
                    }
                    return;
                }
               
                // 点击遮罩关闭
                if (target.classList.contains('card-modal-overlay')) {
                    DOMManager.closeModal();
                    return;
                }
               
                if (target.classList.contains('spark-modal-overlay')) {
                    DOMManager.closeSparkModal();
                    return;
                }
               
                if (target.classList.contains('spark-enlarged-container')) {
                    DOMManager.closeEnlargedCard();
                    return;
                }
               
                // 卡牌点击
                var card = isValidCardClick(target);
                if (card) {
                    e.preventDefault();
                   
                    var inSparkList = card.closest('.spark-card-list');
                    var info = getCardInfo(card);
                   
                    if (inSparkList) {
                        // 闪光列表中的卡牌 - 显示放大
                        DOMManager.showEnlargedCard(card);
                    } else {
                        // 普通卡牌 - 打开模态框
                        DOMManager.openModal(card, info.cardId, info.sparkEnable);
                    }
                }
            }, true);
              
              
             cards.forEach(function(card) {
             // 使用事件委托处理鼠标悬停
                 // 避免重复绑定
            document.addEventListener('mouseenter', function(e) {
                if (card.dataset.cardBound) return;
                 var card = e.target.closest && e.target.closest('.card-deck-trans');
                 card.dataset.cardBound = 'true';
                 if (!card) return;
                  
                  
                 // 排除模态框内的卡牌
                 // 排除模态框内的卡牌
                 if (card.closest('.card-modal-overlay') || card.closest('.spark-modal-overlay') || card.closest('.spark-enlarged-container')) return;
                 if (card.closest('.card-modal-overlay') ||  
                    card.closest('.spark-modal-overlay') ||  
                    card.closest('.spark-enlarged-container')) return;
                  
                  
                 card.addEventListener('click', function(e) {
                 var info = getCardInfo(card);
                    e.preventDefault();
                if (info.sparkEnable && info.sparkEnable.trim() !== '' && info.cardId) {
                    // 清除之前的定时器
                    if (hoverTimer) {
                        clearTimeout(hoverTimer);
                    }
                      
                      
                     // 从card-deck-trans元素获取spark_enable
                     // 延迟触发预加载,避免快速滑过时的无效请求
                     var sparkEnable = this.dataset.sparkEnable || '';
                    hoverTimer = setTimeout(function() {
                        BatchRequestManager.prioritize(info.cardId);
                        if (!SparkCache.has(info.cardId)) {
                            BatchRequestManager.request(info.cardId);
                        }
                    }, 150);
                }
            }, true);
           
            document.addEventListener('mouseleave', function(e) {
                var card = e.target.closest && e.target.closest('.card-deck-trans');
                if (card && hoverTimer) {
                     clearTimeout(hoverTimer);
                    hoverTimer = null;
                }
            }, true);
           
            // ESC键关闭
            document.addEventListener('keydown', function(e) {
                if (e.key === 'Escape') {
                    var sparkModal = DOMManager.getSparkModalOverlay();
                    var mainModal = DOMManager.getModalOverlay();
                      
                      
                     // 获取card-id从父级card-wrapper
                     // 按层级关闭
                     var wrapper = this.closest('.card-wrapper');
                     if (document.querySelector('.spark-enlarged-container')) {
                     var cardId = wrapper ? wrapper.dataset.cardId : '';
                        DOMManager.closeEnlargedCard();
                      
                     } else if (sparkModal && sparkModal.classList.contains('active')) {
                     openModal(this, cardId, sparkEnable);
                        DOMManager.closeSparkModal();
                 });
                     } else if (mainModal && mainModal.classList.contains('active')) {
                        DOMManager.closeModal();
                     }
                }
            });
           
            // 页面卸载时保存缓存
            window.addEventListener('beforeunload', function() {
                SparkCache.flush();
            });
           
            // 页面可见性变化
            document.addEventListener('visibilitychange', function() {
                if (document.hidden) {
                    SparkCache.flush();
                 }
             });
             });
         }
         }
          
          
         // 初始绑定
        return {
         bindCardEvents();
            init: init
        };
    })();
   
    // ==================== 初始化 ====================
    function init() {
        // 清理过期缓存
        SparkCache.cleanup();
       
        // 创建模态框
        DOMManager.createModals();
       
         // 初始化事件监听(事件委托)
         EventManager.init();
          
          
         // 监听DOM变化,为动态加载的卡牌绑定事件
         // 处理已有卡牌
        DOMManager.initExistingCards();
       
        // 监听DOM变化 - 只处理新添加的节点
         var observer = new MutationObserver(function(mutations) {
         var observer = new MutationObserver(function(mutations) {
             var shouldBind = false;
             var newNodes = [];
           
             mutations.forEach(function(mutation) {
             mutations.forEach(function(mutation) {
                 if (mutation.addedNodes.length > 0) {
                 if (mutation.addedNodes.length > 0) {
                     mutation.addedNodes.forEach(function(node) {
                     for (var i = 0; i < mutation.addedNodes.length; i++) {
                         if (node.nodeType === 1) {
                         newNodes.push(mutation.addedNodes[i]);
                            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();
             if (newNodes.length > 0) {
                // 使用 requestIdleCallback 或 setTimeout 延迟处理
                if (window.requestIdleCallback) {
                    requestIdleCallback(function() {
                        DOMManager.processNewCards(newNodes);
                    }, { timeout: 500 });
                 } else {
                    setTimeout(function() {
                        DOMManager.processNewCards(newNodes);
                    }, 100);
                }
             }
             }
         });
         });
第625行: 第1,096行:
             subtree: true
             subtree: true
         });
         });
    }
   
    // 启动
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
     }
     }
})();
})();
</script>
</script>
</includeonly>
</includeonly>

2026年1月17日 (六) 10:22的版本