243 lines
9.1 KiB
JavaScript
243 lines
9.1 KiB
JavaScript
window.initSearch = function() {
|
|
initSearchModal();
|
|
initInlineSearch();
|
|
};
|
|
|
|
function loadSearchIndex() {
|
|
if (!window.searchIndex) {
|
|
return fetch('/index.json')
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
window.searchIndex = data;
|
|
return data;
|
|
})
|
|
.catch(err => console.error('Failed to load search index:', err));
|
|
}
|
|
return Promise.resolve(window.searchIndex);
|
|
}
|
|
|
|
function initSearchModal() {
|
|
var searchBtn = document.getElementById('search-btn');
|
|
var searchModal = document.getElementById('search-modal');
|
|
|
|
if (searchBtn && searchModal) {
|
|
// Clone to remove old listeners
|
|
var newSearchBtn = searchBtn.cloneNode(true);
|
|
searchBtn.parentNode.replaceChild(newSearchBtn, searchBtn);
|
|
searchBtn = newSearchBtn;
|
|
|
|
searchBtn.addEventListener('click', function() {
|
|
searchModal.classList.add('show');
|
|
var input = document.getElementById('search-input');
|
|
if (input) setTimeout(function() { input.focus(); }, 100);
|
|
|
|
loadSearchIndex();
|
|
});
|
|
|
|
// Close logic
|
|
var closeBtn = searchModal.querySelector('.close-search');
|
|
if (closeBtn) {
|
|
closeBtn.onclick = function() {
|
|
searchModal.classList.remove('show');
|
|
};
|
|
}
|
|
|
|
// Click outside to close
|
|
searchModal.onclick = function(e) {
|
|
if (e.target === searchModal) {
|
|
searchModal.classList.remove('show');
|
|
}
|
|
};
|
|
|
|
// Search Input Logic
|
|
var searchInput = document.getElementById('search-input');
|
|
var searchResults = document.getElementById('search-results');
|
|
|
|
if (searchInput && searchResults) {
|
|
// Clone input to remove old listeners
|
|
var newInput = searchInput.cloneNode(true);
|
|
searchInput.parentNode.replaceChild(newInput, searchInput);
|
|
searchInput = newInput;
|
|
|
|
// Clone results to remove old listeners
|
|
var newResults = searchResults.cloneNode(true);
|
|
searchResults.parentNode.replaceChild(newResults, searchResults);
|
|
searchResults = newResults;
|
|
|
|
// Close modal when a result is clicked
|
|
searchResults.addEventListener('click', function(e) {
|
|
if (e.target.closest('a')) {
|
|
searchModal.classList.remove('show');
|
|
}
|
|
});
|
|
|
|
searchInput.addEventListener('input', function() {
|
|
var query = this.value.trim().toLowerCase();
|
|
if (!window.searchIndex || query.length === 0) {
|
|
searchResults.innerHTML = '<p class="search-tip">输入关键词并回车进行搜索</p>';
|
|
return;
|
|
}
|
|
|
|
var results = window.searchIndex.filter(function(item) {
|
|
return (item.title && item.title.toLowerCase().includes(query)) ||
|
|
(item.summary && item.summary.toLowerCase().includes(query));
|
|
});
|
|
|
|
if (results.length > 0) {
|
|
var html = results.map(function(item) {
|
|
return `
|
|
<div class="search-result-item">
|
|
<a href="${item.permalink}" class="search-result-title">${item.title}</a>
|
|
<span class="search-result-date">${item.date}</span>
|
|
<div class="search-result-summary">${item.summary || ''}</div>
|
|
</div>
|
|
`;
|
|
}).join('');
|
|
searchResults.innerHTML = html;
|
|
|
|
// Refresh PJAX to recognize new links
|
|
if (window.pjax) {
|
|
window.pjax.refresh(searchResults);
|
|
}
|
|
} else {
|
|
searchResults.innerHTML = '<p class="search-tip">未找到相关文章</p>';
|
|
}
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
function initInlineSearch() {
|
|
var header = document.getElementById('essay-header');
|
|
var searchContainer = document.getElementById('search-container');
|
|
var input = document.getElementById('inline-search-input');
|
|
var resultsContainer = document.getElementById('inline-search-results');
|
|
|
|
window.toggleSearchMode = function(show) {
|
|
if (!header || !searchContainer || !input || !resultsContainer) return;
|
|
|
|
if (show) {
|
|
header.style.display = 'none';
|
|
searchContainer.style.display = 'block';
|
|
input.focus();
|
|
loadSearchIndex();
|
|
// Add Esc key listener
|
|
document.addEventListener('keydown', escListener);
|
|
} else {
|
|
header.style.display = 'inline-flex';
|
|
searchContainer.style.display = 'none';
|
|
input.value = '';
|
|
// Remove .has-value class
|
|
searchContainer.querySelector('.search-input-group').classList.remove('has-value');
|
|
resultsContainer.classList.remove('show');
|
|
resultsContainer.innerHTML = '';
|
|
// Remove Esc key listener
|
|
document.removeEventListener('keydown', escListener);
|
|
}
|
|
};
|
|
|
|
var escListener = function(e) {
|
|
if (e.key === 'Escape') {
|
|
window.toggleSearchMode(false);
|
|
}
|
|
};
|
|
|
|
if (!header || !searchContainer || !input || !resultsContainer) return;
|
|
|
|
// Input Event
|
|
var newInput = input.cloneNode(true);
|
|
input.parentNode.replaceChild(newInput, input);
|
|
input = newInput;
|
|
|
|
// Handle Close Icon Logic
|
|
var closeIcon = searchContainer.querySelector('.close-icon');
|
|
if (closeIcon) {
|
|
// Remove inline onclick handler if present
|
|
closeIcon.onclick = null;
|
|
closeIcon.removeAttribute('onclick');
|
|
|
|
// Add new custom handler
|
|
closeIcon.addEventListener('click', function(e) {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
|
|
if (input.value.trim().length > 0) {
|
|
// Clear input
|
|
input.value = '';
|
|
input.focus();
|
|
// Trigger input event to update UI
|
|
input.dispatchEvent(new Event('input'));
|
|
} else {
|
|
// Close search
|
|
window.toggleSearchMode(false);
|
|
}
|
|
});
|
|
}
|
|
|
|
input.addEventListener('input', function() {
|
|
var query = this.value.trim().toLowerCase();
|
|
var inputGroup = this.closest('.search-input-group');
|
|
|
|
// Toggle has-value class
|
|
if (this.value.length > 0) {
|
|
inputGroup.classList.add('has-value');
|
|
} else {
|
|
inputGroup.classList.remove('has-value');
|
|
}
|
|
|
|
if (query.length === 0) {
|
|
resultsContainer.classList.remove('show');
|
|
resultsContainer.innerHTML = '';
|
|
return;
|
|
}
|
|
|
|
if (!window.searchIndex) return;
|
|
|
|
var results = window.searchIndex.filter(function(item) {
|
|
return (item.title && item.title.toLowerCase().includes(query)) ||
|
|
(item.summary && item.summary.toLowerCase().includes(query));
|
|
});
|
|
|
|
if (results.length > 0) {
|
|
var html = results.slice(0, 5).map(function(item) {
|
|
return `
|
|
<a href="${item.permalink}" class="search-result-item" onclick="window.toggleSearchMode(false)">
|
|
<span class="search-result-title">${item.title}</span>
|
|
<div class="search-result-meta">
|
|
<span class="search-result-date">${item.date}</span>
|
|
<span class="search-result-summary-text">${item.summary || ''}</span>
|
|
</div>
|
|
</a>
|
|
`;
|
|
}).join('');
|
|
|
|
resultsContainer.innerHTML = html;
|
|
resultsContainer.classList.add('show');
|
|
|
|
// PJAX Refresh
|
|
if (window.pjax) {
|
|
window.pjax.refresh(resultsContainer);
|
|
}
|
|
} else {
|
|
resultsContainer.innerHTML = '<div class="search-result-item no-result">暂无相关内容</div>';
|
|
resultsContainer.classList.add('show');
|
|
}
|
|
});
|
|
|
|
// Close on click outside
|
|
if (!window.inlineSearchClickOutside) {
|
|
window.inlineSearchClickOutside = function(e) {
|
|
var header = document.getElementById('essay-header');
|
|
var searchContainer = document.getElementById('search-container');
|
|
var resultsContainer = document.getElementById('inline-search-results');
|
|
|
|
if (header && searchContainer && resultsContainer && searchContainer.style.display === 'block') {
|
|
if (!searchContainer.contains(e.target) && !header.contains(e.target) && !resultsContainer.contains(e.target)) {
|
|
window.toggleSearchMode(false);
|
|
}
|
|
}
|
|
};
|
|
document.addEventListener('click', window.inlineSearchClickOutside);
|
|
}
|
|
}
|