{"version":3,"sources":["jsdelivr-header.js","/npm/hexo-theme-solitude@3.0.21/source/js/search/local.js"],"names":[],"mappings":"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","file":"/npm/hexo-theme-solitude@3.0.21/source/js/search/local.js","sourceRoot":"","sourcesContent":["/**\n * Minified by jsDelivr using Terser v5.39.0.\n * Original file: /npm/hexo-theme-solitude@3.0.21/source/js/search/local.js\n *\n * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files\n */\n","class LocalSearch {\n    constructor() {\n        this.store = [];\n        this.currentQuery = '';\n        this.currentPage = 0;\n        this.resultsPerPage = 10;\n        this.currentResults = [];\n        this.isLoading = false;\n        this.searchTimeout = null;\n        \n        // DOM 元素缓存\n        this.elements = this.cacheElements();\n        \n        // 初始化\n        this.init();\n    }\n\n    /**\n     * 缓存常用的DOM元素\n     */\n    cacheElements() {\n        return {\n            searchMask: document.getElementById(\"search-mask\"),\n            searchDialog: document.querySelector(\"#local-search .search-dialog\"),\n            searchInput: document.getElementById(\"search-input\"),\n            searchResults: document.getElementById(\"search-results\"),\n            searchPagination: document.getElementById(\"search-pagination\"),\n            searchTips: document.getElementById(\"search-tips\"),\n            searchButton: document.querySelector(\"#search-button > .search\"),\n            closeButton: document.querySelector(\"#local-search .search-close-button\"),\n            menuSearch: document.getElementById(\"menu-search\")\n        };\n    }\n\n    /**\n     * 初始化搜索功能\n     */\n    async init() {\n        try {\n            await this.loadSearchData();\n            this.bindEvents();\n            this.bindKeyboardShortcuts();\n        } catch (error) {\n            console.error('Search initialization failed:', error);\n        }\n    }\n\n    /**\n     * 加载搜索数据\n     */\n    async loadSearchData() {\n        if (!GLOBAL_CONFIG?.localsearch?.path) {\n            throw new Error('Search data path not configured');\n        }\n\n        this.isLoading = true;\n        try {\n            const response = await fetch(GLOBAL_CONFIG.localsearch.path);\n            if (!response.ok) {\n                throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n            }\n            \n            const data = await response.text();\n            this.parseSearchData(data);\n        } catch (error) {\n            throw new Error(`Failed to load search data: ${error.message}`);\n        } finally {\n            this.isLoading = false;\n        }\n    }\n\n    /**\n     * 解析搜索数据\n     */\n    parseSearchData(xmlData) {\n        try {\n            const parser = new DOMParser();\n            const xmlDoc = parser.parseFromString(xmlData, \"text/xml\");\n            const entries = xmlDoc.getElementsByTagName(\"entry\");\n            \n            this.store = Array.from(entries).map(entry => {\n                const getTextContent = (tagName) => {\n                    const element = entry.getElementsByTagName(tagName)[0];\n                    return element ? element.textContent.trim() : '';\n                };\n                \n                return {\n                    title: getTextContent(\"title\"),\n                    link: getTextContent(\"url\"),\n                    content: getTextContent(\"content\")\n                };\n            }).filter(item => item.title && item.link);\n        } catch (error) {\n            throw new Error(`Failed to parse search data: ${error.message}`);\n        }\n    }\n\n    /**\n     * 绑定事件监听器\n     */\n    bindEvents() {\n        // 搜索输入事件\n        this.elements.searchInput?.addEventListener('input', this.debounce((e) => {\n            this.handleSearchInput(e.target.value.trim());\n        }, 300));\n\n        // 打开/关闭搜索\n        this.elements.searchButton?.addEventListener('click', () => this.openSearch());\n        this.elements.closeButton?.addEventListener('click', () => this.closeSearch());\n        this.elements.searchMask?.addEventListener('click', () => this.closeSearch());\n\n        // 标签列表点击事件\n        this.bindTagListEvents();\n\n        // 右键菜单搜索\n        if (GLOBAL_CONFIG.right_menu && this.elements.menuSearch) {\n            this.elements.menuSearch.addEventListener('click', () => {\n                rm.hideRightMenu();\n                this.openSearch();\n                if (window.selectTextNow) {\n                    this.elements.searchInput.value = window.selectTextNow;\n                    this.handleSearchInput(window.selectTextNow);\n                }\n            });\n        }\n\n        // PJAX 兼容性\n        window.addEventListener('pjax:complete', () => {\n            this.elements = this.cacheElements();\n            this.bindEvents();\n        });\n    }\n\n    /**\n     * 绑定标签列表事件\n     */\n    bindTagListEvents() {\n        const tagLists = document.querySelectorAll(\"#local-search .tag-list\");\n        tagLists.forEach(el => {\n            el.addEventListener(\"click\", () => this.closeSearch());\n        });\n    }\n\n    /**\n     * 绑定键盘快捷键\n     */\n    bindKeyboardShortcuts() {\n        document.addEventListener(\"keydown\", (event) => {\n            // Ctrl+K 打开搜索\n            if (event.ctrlKey && event.key === \"k\") {\n                event.preventDefault();\n                this.openSearch();\n                return;\n            }\n\n            // ESC 关闭搜索\n            if (event.code === \"Escape\" && this.isSearchOpen()) {\n                this.closeSearch();\n            }\n        });\n    }\n\n    /**\n     * 打开搜索框\n     */\n    openSearch() {\n        if (!this.elements.searchMask || !this.elements.searchDialog) return;\n\n        utils.animateIn(this.elements.searchMask, \"to_show 0.5s\");\n        this.elements.searchDialog.style.display = \"flex\";\n        \n        // 延迟聚焦以确保动画完成\n        setTimeout(() => {\n            this.elements.searchInput?.focus();\n        }, 100);\n\n        this.fixSafariHeight();\n        window.addEventListener(\"resize\", this.fixSafariHeight);\n        \n        // 暴露到全局作用域以保持兼容性\n        window.openSearch = () => this.openSearch();\n    }\n\n    /**\n     * 关闭搜索框\n     */\n    closeSearch() {\n        if (!this.elements.searchMask || !this.elements.searchDialog) return;\n\n        utils.animateOut(this.elements.searchDialog, \"search_close .5s\");\n        utils.animateOut(this.elements.searchMask, \"to_hide 0.5s\");\n        window.removeEventListener(\"resize\", this.fixSafariHeight);\n        \n        // 清理搜索状态\n        this.currentQuery = '';\n        this.currentPage = 0;\n    }\n\n    /**\n     * 检查搜索框是否打开\n     */\n    isSearchOpen() {\n        return this.elements.searchDialog?.style.display === \"flex\";\n    }\n\n    /**\n     * 修复Safari高度问题\n     */\n    fixSafariHeight = () => {\n        if (window.innerWidth < 768 && this.elements.searchDialog) {\n            this.elements.searchDialog.style.setProperty(\"--search-height\", `${window.innerHeight}px`);\n        }\n    };\n\n    /**\n     * 处理搜索输入\n     */\n    handleSearchInput(query) {\n        if (this.isLoading) return;\n\n        this.currentQuery = query;\n        this.currentPage = 0;\n\n        if (query === '') {\n            this.clearSearchResults();\n            return;\n        }\n\n        try {\n            const startTime = performance.now();\n            this.currentResults = this.performSearch(query);\n            const endTime = performance.now();\n            const searchTime = (endTime - startTime).toFixed(2);\n            \n            this.renderResults(this.currentResults, this.currentPage, searchTime);\n            this.renderPagination(this.currentResults.length);\n        } catch (error) {\n            console.error('Search error:', error);\n            this.showErrorMessage('Search failed, please try again');\n        }\n    }\n\n    /**\n     * 执行搜索\n     */\n    performSearch(query) {\n        if (!query || !this.store.length) return [];\n\n        const keywords = query.toLowerCase().split(/\\s+/).filter(k => k.length > 0);\n        if (keywords.length === 0) return [];\n\n        return this.store.filter(item => {\n            const titleLower = item.title.toLowerCase();\n            const contentLower = item.content.toLowerCase();\n            \n            // 所有关键词都必须在标题或内容中找到\n            return keywords.every(keyword => \n                titleLower.includes(keyword) || contentLower.includes(keyword)\n            );\n        }).sort((a, b) => {\n            // 按标题匹配度排序\n            const aScore = this.calculateRelevanceScore(a, keywords);\n            const bScore = this.calculateRelevanceScore(b, keywords);\n            return bScore - aScore;\n        });\n    }\n\n    /**\n     * 计算相关性评分\n     */\n    calculateRelevanceScore(item, keywords) {\n        let score = 0;\n        const titleLower = item.title.toLowerCase();\n        \n        keywords.forEach(keyword => {\n            // 标题完全匹配加分更多\n            if (titleLower === keyword) score += 10;\n            else if (titleLower.includes(keyword)) score += 5;\n            // 内容匹配加分较少\n            else if (item.content.toLowerCase().includes(keyword)) score += 1;\n        });\n        \n        return score;\n    }\n\n    /**\n     * 渲染搜索结果\n     */\n    renderResults(results, page, searchTime = null) {\n        if (!this.elements.searchResults || !this.elements.searchTips) return;\n\n        this.elements.searchResults.innerHTML = '';\n        this.elements.searchTips.innerHTML = '';\n\n        const start = page * this.resultsPerPage;\n        const end = start + this.resultsPerPage;\n\n        if (!results.length) {\n            this.showEmptyMessage();\n            return;\n        }\n\n        // 创建结果列表\n        const fragment = document.createDocumentFragment();\n        results.slice(start, end).forEach(result => {\n            const resultElement = this.createResultElement(result);\n            fragment.appendChild(resultElement);\n        });\n        this.elements.searchResults.appendChild(fragment);\n\n        // 显示结果计数\n        this.showResultCount(results.length, searchTime);\n    }\n\n    /**\n     * 创建单个结果元素\n     */\n    createResultElement(result) {\n            const $result = document.createElement(\"li\");\n            $result.className = \"search-result-item\";\n        \n            const $link = document.createElement(\"a\");\n            $link.className = \"search-result-title\";\n            $link.href = result.link;\n        $link.innerHTML = this.highlightKeywords(result.title, this.currentQuery);\n        \n            $result.appendChild($link);\n        return $result;\n    }\n\n    /**\n     * 高亮关键词\n     */\n    highlightKeywords(text, query) {\n        if (!query) return text;\n        \n        const keywords = query.split(/\\s+/).filter(k => k.length > 0);\n        let highlightedText = text;\n        \n        keywords.forEach(keyword => {\n            const regex = new RegExp(`(${this.escapeRegExp(keyword)})`, 'gi');\n            highlightedText = highlightedText.replace(regex, '<em>$1</em>');\n        });\n        \n        return highlightedText;\n    }\n\n    /**\n     * 转义正则表达式特殊字符\n     */\n    escapeRegExp(string) {\n        return string.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n    }\n\n    /**\n     * 渲染分页\n     */\n    renderPagination(totalResults) {\n        if (!this.elements.searchPagination) return;\n\n        const totalPages = Math.ceil(totalResults / this.resultsPerPage);\n        this.elements.searchPagination.innerHTML = '';\n\n        if (totalPages <= 1) return;\n\n        const paginationList = document.createElement(\"ul\");\n        paginationList.className = \"pagination-list\";\n\n        for (let i = 0; i < totalPages; i++) {\n            const button = this.createPaginationButton(i + 1, i === this.currentPage);\n            button.addEventListener('click', () => this.goToPage(i));\n            paginationList.appendChild(button);\n        }\n\n        this.elements.searchPagination.appendChild(paginationList);\n    }\n\n    /**\n     * 创建分页按钮\n     */\n    createPaginationButton(pageNumber, isActive) {\n        const button = document.createElement(\"li\");\n        button.className = \"pagination-item\";\n        button.textContent = pageNumber;\n        \n        if (isActive) {\n            button.classList.add('select');\n        }\n        \n        return button;\n    }\n\n    /**\n     * 跳转到指定页面\n     */\n    goToPage(page) {\n        this.currentPage = page;\n        this.renderResults(this.currentResults, page);\n        \n        // 更新分页按钮状态\n        document.querySelectorAll(\".pagination-item\").forEach((btn, index) => {\n            btn.classList.toggle('select', index === page);\n        });\n    }\n\n    /**\n     * 显示空结果消息\n     */\n    showEmptyMessage() {\n        const $empty = document.createElement(\"span\");\n        $empty.className = \"search-result-empty\";\n        $empty.textContent = GLOBAL_CONFIG.lang?.search?.empty?.replace(/\\$\\{query}/, this.currentQuery) || \n                           `没有找到与 \"${this.currentQuery}\" 相关的内容`;\n        this.elements.searchResults.appendChild($empty);\n    }\n\n    /**\n     * 显示结果计数\n     */\n    showResultCount(count, time) {\n        const countElement = document.createElement(\"span\");\n        countElement.className = \"search-result-count\";\n        countElement.innerHTML = GLOBAL_CONFIG.lang?.search?.hit?.replace(/\\$\\{hits}/, count).replace(/\\$\\{time}/, time);\n        this.elements.searchTips.appendChild(countElement);\n    }\n\n    /**\n     * 显示错误消息\n     */\n    showErrorMessage(message) {\n        if (!this.elements.searchResults) return;\n        \n        this.elements.searchResults.innerHTML = '';\n        const $error = document.createElement(\"span\");\n        $error.className = \"search-result-error\";\n        $error.textContent = message;\n        this.elements.searchResults.appendChild($error);\n    }\n\n    /**\n     * 清空搜索结果\n     */\n    clearSearchResults() {\n        if (this.elements.searchResults) this.elements.searchResults.innerHTML = '';\n        if (this.elements.searchPagination) this.elements.searchPagination.innerHTML = '';\n        if (this.elements.searchTips) this.elements.searchTips.innerHTML = '';\n        \n        this.currentResults = [];\n        this.currentPage = 0;\n    }\n\n    /**\n     * 防抖函数\n     */\n    debounce(func, wait) {\n        return (...args) => {\n            clearTimeout(this.searchTimeout);\n            this.searchTimeout = setTimeout(() => func.apply(this, args), wait);\n        };\n    }\n}\n\n// 页面加载完成后初始化搜索功能\nwindow.addEventListener(\"load\", () => {\n    window.localSearch = new LocalSearch();\n});\n"]}