Improve LightRAG knowledge search locator alignment
This commit is contained in:
@@ -2139,7 +2139,9 @@ import { createSidebarPageSettingsRuntime } from './sidebar-page-settings-runtim
|
||||
'<span class="wolai-search-sort-control"><span>按创建时间</span><button type="button" class="wolai-search-sort-value" data-search-sort="created" aria-label="按创建时间范围">所有</button></span>' +
|
||||
'</div>' +
|
||||
'<div class="wolai-search-options-right">' +
|
||||
'<span class="wolai-search-switch-control"><span>全盘资料库</span><button type="button" class="wolai-search-switch" data-search-switch="knowledge" role="switch" aria-checked="false" aria-label="全盘资料库检索"></button></span>' +
|
||||
'<span class="wolai-search-switch-control"><span>页面内搜索</span><button type="button" class="wolai-search-switch" data-search-switch="page" role="switch" aria-checked="false" aria-label="页面内搜索"></button></span>' +
|
||||
'<span class="wolai-search-switch-control"><span>折叠同来源</span><button type="button" class="wolai-search-switch is-on" data-search-switch="collapseSource" role="switch" aria-checked="true" aria-label="默认折叠相同来源结果"></button></span>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="wolai-search-result-meta" data-testid="wolai-search-result-meta"></div>' +
|
||||
@@ -2149,12 +2151,22 @@ import { createSidebarPageSettingsRuntime } from './sidebar-page-settings-runtim
|
||||
document.body.appendChild(overlay);
|
||||
var input = overlay.querySelector('[data-testid="wolai-search-input"]');
|
||||
var closeButton = overlay.querySelector('[data-testid="wolai-search-close"]');
|
||||
if (input) input.addEventListener('input', scheduleSearchResultsRender);
|
||||
applySearchSwitchState(overlay, { collapseSource: readSearchCollapseSourcesDefault() });
|
||||
if (input) input.addEventListener('input', function() {
|
||||
searchUiState.hasRendered = false;
|
||||
scheduleSearchResultsRender();
|
||||
});
|
||||
overlay.querySelectorAll('[data-search-switch]').forEach(function(button) {
|
||||
button.addEventListener('click', function() {
|
||||
var switchName = searchText(button.getAttribute('data-search-switch'));
|
||||
var isOn = button.getAttribute('aria-checked') !== 'true';
|
||||
button.setAttribute('aria-checked', isOn ? 'true' : 'false');
|
||||
button.classList.toggle('is-on', isOn);
|
||||
if (switchName === 'collapseSource') {
|
||||
writeSearchCollapseSourcesDefault(isOn);
|
||||
searchUiState.sourceCollapsed = {};
|
||||
}
|
||||
searchUiState.hasRendered = false;
|
||||
scheduleSearchResultsRender();
|
||||
});
|
||||
});
|
||||
@@ -2167,11 +2179,27 @@ import { createSidebarPageSettingsRuntime } from './sidebar-page-settings-runtim
|
||||
|
||||
var activeSearchRequestId = 0;
|
||||
var searchRenderTimer = 0;
|
||||
var SEARCH_COLLAPSE_SOURCES_KEY = 'mnote.search.collapseSourcesDefault.v1';
|
||||
var searchUiState = {
|
||||
query: '',
|
||||
switches: {},
|
||||
metaHtml: '',
|
||||
resultsHtml: '',
|
||||
items: [],
|
||||
sourceCollapsed: {},
|
||||
scrollTop: 0,
|
||||
signature: '',
|
||||
hasRendered: false
|
||||
};
|
||||
|
||||
function searchText(value) {
|
||||
return String(value == null ? '' : value).replace(/\s+/g, ' ').trim();
|
||||
}
|
||||
|
||||
function searchNonWhitespaceCharCount(value) {
|
||||
return String(value == null ? '' : value).replace(/\s+/g, '').length;
|
||||
}
|
||||
|
||||
function currentWorkspaceName() {
|
||||
var name = document.querySelector('.sidebar-workspace-name');
|
||||
return searchText(name && name.textContent) || '当前工作区';
|
||||
@@ -2208,6 +2236,92 @@ import { createSidebarPageSettingsRuntime } from './sidebar-page-settings-runtim
|
||||
return button instanceof HTMLElement && button.getAttribute('aria-checked') === 'true';
|
||||
}
|
||||
|
||||
function readSearchCollapseSourcesDefault() {
|
||||
try {
|
||||
var stored = window.localStorage && window.localStorage.getItem(SEARCH_COLLAPSE_SOURCES_KEY);
|
||||
if (stored === '0') return false;
|
||||
if (stored === '1') return true;
|
||||
} catch (_) {}
|
||||
return true;
|
||||
}
|
||||
|
||||
function writeSearchCollapseSourcesDefault(value) {
|
||||
try {
|
||||
if (window.localStorage) window.localStorage.setItem(SEARCH_COLLAPSE_SOURCES_KEY, value ? '1' : '0');
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
function collectSearchSwitchState(overlay) {
|
||||
var state = {};
|
||||
if (!(overlay instanceof HTMLElement)) return state;
|
||||
overlay.querySelectorAll('[data-search-switch]').forEach(function(button) {
|
||||
if (!(button instanceof HTMLElement)) return;
|
||||
var name = searchText(button.getAttribute('data-search-switch'));
|
||||
if (!name) return;
|
||||
state[name] = button.getAttribute('aria-checked') === 'true';
|
||||
});
|
||||
return state;
|
||||
}
|
||||
|
||||
function applySearchSwitchState(overlay, switches) {
|
||||
if (!(overlay instanceof HTMLElement) || !switches || typeof switches !== 'object') return;
|
||||
overlay.querySelectorAll('[data-search-switch]').forEach(function(button) {
|
||||
if (!(button instanceof HTMLElement)) return;
|
||||
var name = searchText(button.getAttribute('data-search-switch'));
|
||||
if (!name || !Object.prototype.hasOwnProperty.call(switches, name)) return;
|
||||
var isOn = Boolean(switches[name]);
|
||||
button.setAttribute('aria-checked', isOn ? 'true' : 'false');
|
||||
button.classList.toggle('is-on', isOn);
|
||||
});
|
||||
}
|
||||
|
||||
function searchRequestSignature(overlay, query) {
|
||||
var switches = collectSearchSwitchState(overlay);
|
||||
return JSON.stringify({
|
||||
query: searchText(query),
|
||||
knowledge: Boolean(switches.knowledge),
|
||||
page: Boolean(switches.page),
|
||||
title: Boolean(switches.title),
|
||||
exact: Boolean(switches.exact),
|
||||
collapseSource: Boolean(switches.collapseSource),
|
||||
workspaceId: resolveWorkspaceId(document.body) || '',
|
||||
rootUri: currentRootUri() || ''
|
||||
});
|
||||
}
|
||||
|
||||
function saveSearchUiState(overlay) {
|
||||
if (!(overlay instanceof HTMLElement)) return;
|
||||
var input = overlay.querySelector('[data-testid="wolai-search-input"]');
|
||||
var meta = overlay.querySelector('[data-testid="wolai-search-result-meta"]');
|
||||
var results = overlay.querySelector('[data-testid="wolai-search-results"]');
|
||||
var query = input && 'value' in input ? searchText(input.value) : searchUiState.query;
|
||||
searchUiState.query = query;
|
||||
searchUiState.switches = collectSearchSwitchState(overlay);
|
||||
searchUiState.metaHtml = meta ? meta.innerHTML : searchUiState.metaHtml;
|
||||
searchUiState.resultsHtml = results ? results.innerHTML : searchUiState.resultsHtml;
|
||||
searchUiState.items = Array.isArray(window.__mnoteSearchResults) ? window.__mnoteSearchResults.slice() : searchUiState.items;
|
||||
searchUiState.scrollTop = results instanceof HTMLElement ? results.scrollTop : searchUiState.scrollTop;
|
||||
searchUiState.signature = query ? searchRequestSignature(overlay, query) : '';
|
||||
}
|
||||
|
||||
function restoreSearchUiState(overlay) {
|
||||
if (!(overlay instanceof HTMLElement) || !searchUiState.hasRendered) return false;
|
||||
var input = overlay.querySelector('[data-testid="wolai-search-input"]');
|
||||
var options = overlay.querySelector('[data-testid="wolai-search-options"]');
|
||||
var meta = overlay.querySelector('[data-testid="wolai-search-result-meta"]');
|
||||
var results = overlay.querySelector('[data-testid="wolai-search-results"]');
|
||||
if (input && 'value' in input) input.value = searchUiState.query || '';
|
||||
applySearchSwitchState(overlay, searchUiState.switches);
|
||||
if (options instanceof HTMLElement) options.hidden = !searchText(searchUiState.query);
|
||||
if (meta && searchUiState.metaHtml) meta.innerHTML = searchUiState.metaHtml;
|
||||
if (results && searchUiState.resultsHtml) {
|
||||
results.innerHTML = searchUiState.resultsHtml;
|
||||
results.scrollTop = Number(searchUiState.scrollTop || 0);
|
||||
}
|
||||
window.__mnoteSearchResults = Array.isArray(searchUiState.items) ? searchUiState.items.slice() : [];
|
||||
return true;
|
||||
}
|
||||
|
||||
function searchHighlightTerms(item, query) {
|
||||
var info = item && item.matchInfo || item && item.evidence && item.evidence.matchInfo || null;
|
||||
var terms = info && Array.isArray(info.matchedTerms) ? info.matchedTerms : [];
|
||||
@@ -2258,13 +2372,113 @@ import { createSidebarPageSettingsRuntime } from './sidebar-page-settings-runtim
|
||||
return html;
|
||||
}
|
||||
|
||||
function cleanSearchDisplayText(value) {
|
||||
var text = String(value == null ? '' : value);
|
||||
text = text.replace(/<drawing\b[^>]*\/?>/gi, ' ');
|
||||
text = text.replace(/<equation\b[^>]*>([\s\S]*?)<\/equation>/gi, '$1');
|
||||
text = text.replace(/<drawing\b[^<>]*$/gi, ' ');
|
||||
text = text.replace(/<\/?equat[^<>]*$/gi, ' ');
|
||||
text = text.replace(/<\/?e(?:q(?:uation)?)?[^<>]*$/gi, ' ');
|
||||
text = text.replace(/<[^>]+>/g, ' ');
|
||||
text = text
|
||||
.replace(/\b(?:equation|latex|drawing)\b(?:\s+[a-z_-]+=(?:"[^"]*"|'[^']*'|[^\s<>]+))*/gi, ' ')
|
||||
.replace(/\\left|\\right|\\mathrm|\\text|\\operatorname/g, '')
|
||||
.replace(/\\gt/g, '>')
|
||||
.replace(/\\lt/g, '<')
|
||||
.replace(/\\sim/g, '∼')
|
||||
.replace(/\\[a-zA-Z]+/g, ' ')
|
||||
.replace(/\{([^{}]*)\}/g, '$1')
|
||||
.replace(/\{([^{}]*)\}/g, '$1')
|
||||
.replace(/[_^]/g, '')
|
||||
.replace(/[<>]\/?(?:equation|eq)\b[^<>]*>?/gi, ' ')
|
||||
.replace(/<\/?e(?:q(?:uation)?)?[^<>\s]*>?/gi, ' ')
|
||||
.replace(/\s+(?:equation|latex|drawing)\s+/gi, ' ');
|
||||
return searchText(text);
|
||||
}
|
||||
|
||||
function searchResultEvidenceLocator(item) {
|
||||
if (item && item.locator && typeof item.locator === 'object') return item.locator;
|
||||
if (item && item.evidence && item.evidence.source && typeof item.evidence.source === 'object') return item.evidence.source;
|
||||
if (item && item.source && item.source.locator && typeof item.source.locator === 'object') return item.source.locator;
|
||||
if (item && Array.isArray(item.evidence) && item.evidence[0] && item.evidence[0].source && typeof item.evidence[0].source === 'object') return item.evidence[0].source;
|
||||
return null;
|
||||
}
|
||||
|
||||
function searchResultSourceKey(item) {
|
||||
var locator = searchResultEvidenceLocator(item);
|
||||
var locatorPath = locator ? searchText(locator.resourcePath || locator.resource_path || locator.ownerDocumentPath || locator.owner_document_path) : '';
|
||||
return locatorPath || searchText(item && (item.path || item.documentId || item.nodeId || item.id)) || 'unknown-source';
|
||||
}
|
||||
|
||||
function searchResultSourceTitle(item) {
|
||||
var key = searchResultSourceKey(item);
|
||||
var locator = searchResultEvidenceLocator(item);
|
||||
var path = locator ? searchText(locator.resourcePath || locator.resource_path || locator.ownerDocumentPath || locator.owner_document_path) : '';
|
||||
var sourcePath = path || searchText(item && item.path) || key;
|
||||
var title = searchText(item && (item.title || item.name || item.documentTitle));
|
||||
return title || sourcePath.split('/').filter(Boolean).pop() || sourcePath || '未知来源';
|
||||
}
|
||||
|
||||
function renderSearchResultButton(item, index, query, exact, grouped) {
|
||||
var title = searchText(item.title || item.name || item.documentTitle || '无标题');
|
||||
var snippet = cleanSearchDisplayText(item.snippet || item.evidence && item.evidence.quote || (Array.isArray(item.evidence) && item.evidence[0] && (item.evidence[0].quote || item.evidence[0].snippet)) || '');
|
||||
var path = searchText(item.path || item.parentTitle || item.workspaceName || currentWorkspaceName());
|
||||
var resourceType = searchText(item.resourceType || item.resourceKind || 'page');
|
||||
var locator = searchResultEvidenceLocator(item);
|
||||
var locatorAttr = locator ? escapeHtml(JSON.stringify(locator)) : '';
|
||||
var highlightTerms = searchHighlightTerms(item, query);
|
||||
var titleHtml = grouped && snippet ? '' : '<span class="wolai-search-result-title">' + highlightSearchText(title, query, exact, highlightTerms) + '</span>';
|
||||
var page = locator && locator.page != null && locator.page !== '' ? String(locator.page) : '';
|
||||
var metaParts = grouped ? [] : [escapeHtml(path)];
|
||||
if (page) metaParts.push('第 ' + escapeHtml(page) + ' 页');
|
||||
if (!grouped) metaParts.push('<span class="wolai-search-result-type">' + escapeHtml(resourceType) + '</span>');
|
||||
var metaHtml = metaParts.length ? '<span class="wolai-search-result-path"><span>' + metaParts.join('</span><span>') + '</span></span>' : '';
|
||||
return '<button type="button" class="wolai-search-result-row" data-testid="wolai-search-result-row" data-search-result-owner="' + escapeHtml(item.provider || 'rust-kernel') + '" data-search-result-index="' + String(index) + '" data-document-id="' + escapeHtml(item.documentId || item.nodeId || item.id || '') + '" data-resource-type="' + escapeHtml(resourceType) + '"' + (locatorAttr ? ' data-evidence-locator="' + locatorAttr + '"' : '') + '>' +
|
||||
'<span class="material-symbols-outlined wolai-search-result-icon" data-icon="article" aria-hidden="true"></span>' +
|
||||
'<span class="wolai-search-result-main">' + titleHtml +
|
||||
'<span class="wolai-search-result-snippet">' + (snippet ? highlightSearchText(snippet, query, exact, highlightTerms) : escapeHtml(path)) + '</span>' +
|
||||
metaHtml + '</span>' +
|
||||
'</button>';
|
||||
}
|
||||
|
||||
function renderSearchResultsHtml(items, overlay, query) {
|
||||
var exact = searchSwitchValue(overlay, 'exact');
|
||||
if (!searchSwitchValue(overlay, 'collapseSource')) {
|
||||
return items.map(function(item, index) {
|
||||
return renderSearchResultButton(item, index, query, exact, false);
|
||||
}).join('');
|
||||
}
|
||||
var groups = [];
|
||||
var groupByKey = {};
|
||||
items.forEach(function(item, index) {
|
||||
var key = searchResultSourceKey(item);
|
||||
var group = groupByKey[key];
|
||||
if (!group) {
|
||||
group = { key: key, title: searchResultSourceTitle(item), path: searchText(item.path || key), resourceType: searchText(item.resourceType || item.resourceKind || 'page'), rows: [] };
|
||||
groupByKey[key] = group;
|
||||
groups.push(group);
|
||||
}
|
||||
group.rows.push({ item: item, index: index });
|
||||
});
|
||||
return groups.map(function(group) {
|
||||
var collapsed = Object.prototype.hasOwnProperty.call(searchUiState.sourceCollapsed, group.key)
|
||||
? searchUiState.sourceCollapsed[group.key]
|
||||
: true;
|
||||
var children = group.rows.map(function(row) {
|
||||
return renderSearchResultButton(row.item, row.index, query, exact, true);
|
||||
}).join('');
|
||||
return '<section class="wolai-search-source-group" data-search-source-key="' + escapeHtml(group.key) + '">' +
|
||||
'<button type="button" class="wolai-search-source-header" data-search-source-toggle="true" aria-expanded="' + (collapsed ? 'false' : 'true') + '">' +
|
||||
'<span class="material-symbols-outlined wolai-search-result-icon" data-icon="article" aria-hidden="true"></span>' +
|
||||
'<span class="wolai-search-source-main"><span class="wolai-search-result-title">' + escapeHtml(group.title) + '</span>' +
|
||||
'<span class="wolai-search-result-path"><span class="wolai-search-result-type">' + escapeHtml(group.resourceType) + '</span><span>' + String(group.rows.length) + ' 处</span></span></span>' +
|
||||
'<span class="wolai-search-source-chevron" aria-hidden="true">' + (collapsed ? '展开' : '收起') + '</span>' +
|
||||
'</button>' +
|
||||
'<div class="wolai-search-source-results" data-search-source-results="true"' + (collapsed ? ' hidden' : '') + '>' + children + '</div>' +
|
||||
'</section>';
|
||||
}).join('');
|
||||
}
|
||||
|
||||
function evidenceLocatorResourceKind(locator, fallback) {
|
||||
return searchText(locator && (locator.resourceKind || locator.resource_kind) || fallback || '').toLowerCase();
|
||||
}
|
||||
@@ -2316,6 +2530,12 @@ import { createSidebarPageSettingsRuntime } from './sidebar-page-settings-runtim
|
||||
async function openEvidenceSearchResult(item, event) {
|
||||
var locator = searchResultEvidenceLocator(item);
|
||||
if (!locator) {
|
||||
var citationUrl = searchText(item && (item.citationUrl || item.publicPath));
|
||||
if (citationUrl) {
|
||||
closeSearchModal();
|
||||
window.location.assign(citationUrl);
|
||||
return;
|
||||
}
|
||||
var fallbackId = searchText(item && (item.documentId || item.nodeId || item.id));
|
||||
if (fallbackId) window.location.assign('/documents/' + encodeURIComponent(fallbackId));
|
||||
return;
|
||||
@@ -2323,6 +2543,12 @@ import { createSidebarPageSettingsRuntime } from './sidebar-page-settings-runtim
|
||||
var resourcePath = searchText(locator.resourcePath || locator.resource_path || locator.ownerDocumentPath || locator.owner_document_path);
|
||||
var ownerDocumentId = searchText(locator.ownerDocumentId || locator.owner_document_id || item.documentId || '');
|
||||
var resourceKind = evidenceLocatorResourceKind(locator, item && item.resourceType);
|
||||
var overlay = document.querySelector('[data-testid="wolai-search-modal"]');
|
||||
var searchInput = overlay instanceof HTMLElement ? overlay.querySelector('[data-testid="wolai-search-input"]') : null;
|
||||
var searchQueryText = searchText(item && (item.query || item.searchQuery))
|
||||
|| searchText(searchInput && 'value' in searchInput ? searchInput.value : '')
|
||||
|| searchText(searchUiState.query);
|
||||
var locatorEvidenceText = searchText(locator.evidenceText || locator.query || locator.openAction && locator.openAction.params && locator.openAction.params.query || '');
|
||||
var openTarget = event && event.altKey ? 'side' : 'active-tab';
|
||||
if (resourcePath && resourceKind) {
|
||||
var fileName = resourcePath.split('/').filter(Boolean).pop() || resourcePath;
|
||||
@@ -2347,6 +2573,9 @@ import { createSidebarPageSettingsRuntime } from './sidebar-page-settings-runtim
|
||||
bbox: locator.bbox,
|
||||
sourceMapPath: searchText(locator.sourceMapPath || locator.source_map_path),
|
||||
blockId: evidenceLocatorBlockId(locator),
|
||||
evidenceText: locatorEvidenceText,
|
||||
query: searchQueryText,
|
||||
searchQuery: searchQueryText,
|
||||
lineRange: evidenceLocatorLineRange(locator),
|
||||
charRange: evidenceLocatorCharRange(locator)
|
||||
});
|
||||
@@ -2379,6 +2608,8 @@ import { createSidebarPageSettingsRuntime } from './sidebar-page-settings-runtim
|
||||
if (results) {
|
||||
results.innerHTML = '<div class="wolai-search-recent" data-testid="wolai-search-recent">暂无最近浏览</div>';
|
||||
}
|
||||
saveSearchUiState(overlay);
|
||||
searchUiState.hasRendered = true;
|
||||
}
|
||||
|
||||
function scheduleSearchResultsRender() {
|
||||
@@ -2401,14 +2632,32 @@ import { createSidebarPageSettingsRuntime } from './sidebar-page-settings-runtim
|
||||
return;
|
||||
}
|
||||
if (options instanceof HTMLElement) options.hidden = false;
|
||||
var knowledgeMode = searchSwitchValue(overlay, 'knowledge');
|
||||
if (knowledgeMode && searchNonWhitespaceCharCount(query) < 2) {
|
||||
activeSearchRequestId += 1;
|
||||
meta.innerHTML = '<span>资料库检索</span><span>请输入至少 2 个字再搜索</span>';
|
||||
results.innerHTML = '<div class="wolai-search-empty" data-search-empty="true">请输入至少 2 个字再搜索</div>';
|
||||
window.__mnoteSearchResults = [];
|
||||
saveSearchUiState(overlay);
|
||||
searchUiState.hasRendered = true;
|
||||
return;
|
||||
}
|
||||
var requestId = ++activeSearchRequestId;
|
||||
meta.innerHTML = '<span>搜索中…</span><span>Ctrl + Enter 新窗口打开 / Alt + Enter 右侧边栏打开</span>';
|
||||
results.innerHTML = '<div class="wolai-search-empty" data-search-loading="true">搜索中…</div>';
|
||||
try {
|
||||
var response = await fetch('/api/search/documents', {
|
||||
var response = await fetch(knowledgeMode ? '/api/knowledge-rag/search' : '/api/search/documents', {
|
||||
method: 'POST',
|
||||
headers: { 'content-type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
body: JSON.stringify(knowledgeMode ? {
|
||||
workspaceId: resolveWorkspaceId(document.body),
|
||||
rootUri: currentRootUri() || null,
|
||||
query: query,
|
||||
mode: 'hybrid',
|
||||
topK: 12,
|
||||
chunkTopK: 24,
|
||||
includeChunkContent: true
|
||||
} : {
|
||||
workspaceId: resolveWorkspaceId(document.body),
|
||||
sourceKind: currentSourceKind() || null,
|
||||
rootUri: currentRootUri() || null,
|
||||
@@ -2418,7 +2667,7 @@ import { createSidebarPageSettingsRuntime } from './sidebar-page-settings-runtim
|
||||
filters: {
|
||||
titleOnly: searchSwitchValue(overlay, 'title'),
|
||||
exact: searchSwitchValue(overlay, 'exact'),
|
||||
includeOcr: true,
|
||||
includeOcr: false,
|
||||
onlyCurrentPage: searchSwitchValue(overlay, 'page'),
|
||||
timeRange: 'any',
|
||||
timeField: 'updated'
|
||||
@@ -2428,33 +2677,25 @@ import { createSidebarPageSettingsRuntime } from './sidebar-page-settings-runtim
|
||||
var payload = await response.json();
|
||||
if (requestId !== activeSearchRequestId) return;
|
||||
var items = Array.isArray(payload.results) ? payload.results : [];
|
||||
meta.innerHTML = '<span>共 ' + items.length + ' 条匹配结果</span><span>Ctrl + Enter 新窗口打开 / Alt + Enter 右侧边栏打开</span>';
|
||||
meta.innerHTML = '<span>' + (knowledgeMode ? '资料库检索' : '工作区搜索') + ' · 共 ' + items.length + ' 条匹配结果</span><span>Ctrl + Enter 新窗口打开 / Alt + Enter 右侧边栏打开</span>';
|
||||
if (!items.length) {
|
||||
results.innerHTML = '<div class="wolai-search-empty" data-search-empty="true">没有搜索结果</div>';
|
||||
window.__mnoteSearchResults = [];
|
||||
saveSearchUiState(overlay);
|
||||
searchUiState.hasRendered = true;
|
||||
return;
|
||||
}
|
||||
results.innerHTML = items.map(function(item) {
|
||||
var title = searchText(item.title || item.name || item.documentTitle || '无标题');
|
||||
var snippet = searchText(item.snippet || item.evidence && item.evidence.quote || (Array.isArray(item.evidence) && item.evidence[0] && (item.evidence[0].quote || item.evidence[0].snippet)) || '');
|
||||
var path = searchText(item.path || item.parentTitle || item.workspaceName || currentWorkspaceName());
|
||||
var resourceType = searchText(item.resourceType || item.resourceKind || 'page');
|
||||
var locator = searchResultEvidenceLocator(item);
|
||||
var locatorAttr = locator ? escapeHtml(JSON.stringify(locator)) : '';
|
||||
var index = items.indexOf(item);
|
||||
var exact = searchSwitchValue(overlay, 'exact');
|
||||
var highlightTerms = searchHighlightTerms(item, query);
|
||||
return '<button type="button" class="wolai-search-result-row" data-testid="wolai-search-result-row" data-search-result-owner="rust-kernel" data-search-result-index="' + String(index) + '" data-document-id="' + escapeHtml(item.documentId || item.nodeId || item.id || '') + '" data-resource-type="' + escapeHtml(resourceType) + '"' + (locatorAttr ? ' data-evidence-locator="' + locatorAttr + '"' : '') + '>' +
|
||||
'<span class="material-symbols-outlined wolai-search-result-icon" data-icon="article" aria-hidden="true"></span>' +
|
||||
'<span class="wolai-search-result-main"><span class="wolai-search-result-title">' + highlightSearchText(title, query, exact, highlightTerms) + '</span>' +
|
||||
'<span class="wolai-search-result-snippet">' + (snippet ? highlightSearchText(snippet, query, exact, highlightTerms) : escapeHtml(path)) + '</span>' +
|
||||
'<span class="wolai-search-result-path"><span>' + escapeHtml(path) + '</span><span class="wolai-search-result-type">' + escapeHtml(resourceType) + '</span></span></span>' +
|
||||
'</button>';
|
||||
}).join('');
|
||||
window.__mnoteSearchResults = items;
|
||||
results.innerHTML = renderSearchResultsHtml(items, overlay, query);
|
||||
saveSearchUiState(overlay);
|
||||
searchUiState.hasRendered = true;
|
||||
} catch (error) {
|
||||
if (requestId !== activeSearchRequestId) return;
|
||||
meta.innerHTML = '<span>共 0 条匹配结果</span><span>Ctrl + Enter 新窗口打开 / Alt + Enter 右侧边栏打开</span>';
|
||||
results.innerHTML = '<div class="wolai-search-empty" data-search-empty="true">没有搜索结果</div>';
|
||||
window.__mnoteSearchResults = [];
|
||||
saveSearchUiState(overlay);
|
||||
searchUiState.hasRendered = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2467,9 +2708,12 @@ import { createSidebarPageSettingsRuntime } from './sidebar-page-settings-runtim
|
||||
var overlay = ensureSearchModal();
|
||||
overlay.hidden = false;
|
||||
document.documentElement.setAttribute('data-mnote-search-modal-open', 'true');
|
||||
var restored = restoreSearchUiState(overlay);
|
||||
var input = overlay.querySelector('[data-testid="wolai-search-input"]');
|
||||
if (input) input.setAttribute('placeholder', '在 ' + currentWorkspaceName() + ' 中搜索');
|
||||
void renderSearchResults();
|
||||
var query = input && 'value' in input ? searchText(input.value) : '';
|
||||
var signature = query ? searchRequestSignature(overlay, query) : '';
|
||||
if (!restored || signature !== searchUiState.signature) void renderSearchResults();
|
||||
if (input) {
|
||||
setTimeout(function() { input.focus(); input.select(); }, 0);
|
||||
}
|
||||
@@ -2477,7 +2721,10 @@ import { createSidebarPageSettingsRuntime } from './sidebar-page-settings-runtim
|
||||
|
||||
function closeSearchModal() {
|
||||
var overlay = document.querySelector('[data-testid="wolai-search-modal"]');
|
||||
if (overlay instanceof HTMLElement) overlay.hidden = true;
|
||||
if (overlay instanceof HTMLElement) {
|
||||
saveSearchUiState(overlay);
|
||||
overlay.hidden = true;
|
||||
}
|
||||
document.documentElement.removeAttribute('data-mnote-search-modal-open');
|
||||
}
|
||||
|
||||
@@ -2486,6 +2733,17 @@ import { createSidebarPageSettingsRuntime } from './sidebar-page-settings-runtim
|
||||
else openSearchModal();
|
||||
}
|
||||
|
||||
function isSearchShortcutEvent(event) {
|
||||
return Boolean(event && (event.metaKey || event.ctrlKey) && !event.shiftKey && !event.altKey && event.key && event.key.toLowerCase() === 'p');
|
||||
}
|
||||
|
||||
document.addEventListener('keydown', function(event) {
|
||||
if (!isSearchShortcutEvent(event)) return;
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
openSearchModal();
|
||||
}, true);
|
||||
|
||||
const sidebarPageAi = createSidebarPageAiRuntime({
|
||||
buildLocalFileOpenUrl,
|
||||
currentDocumentId,
|
||||
@@ -2792,6 +3050,22 @@ import { createSidebarPageSettingsRuntime } from './sidebar-page-settings-runtim
|
||||
closeSearchModal();
|
||||
return;
|
||||
}
|
||||
var searchSourceToggle = closestAction(e.target, '[data-search-source-toggle]');
|
||||
if (searchSourceToggle) {
|
||||
e.preventDefault();
|
||||
var sourceGroup = searchSourceToggle.closest('.wolai-search-source-group');
|
||||
var sourceResults = sourceGroup && sourceGroup.querySelector('[data-search-source-results="true"]');
|
||||
var sourceKey = sourceGroup ? searchText(sourceGroup.getAttribute('data-search-source-key')) : '';
|
||||
var nextCollapsed = !(sourceResults instanceof HTMLElement && sourceResults.hidden);
|
||||
if (sourceResults instanceof HTMLElement) sourceResults.hidden = nextCollapsed;
|
||||
searchSourceToggle.setAttribute('aria-expanded', nextCollapsed ? 'false' : 'true');
|
||||
var chevron = searchSourceToggle.querySelector('.wolai-search-source-chevron');
|
||||
if (chevron) chevron.textContent = nextCollapsed ? '展开' : '收起';
|
||||
if (sourceKey) searchUiState.sourceCollapsed[sourceKey] = nextCollapsed;
|
||||
var overlay = document.querySelector('[data-testid="wolai-search-modal"]');
|
||||
if (overlay instanceof HTMLElement) saveSearchUiState(overlay);
|
||||
return;
|
||||
}
|
||||
var searchResultRow = closestAction(e.target, '[data-testid="wolai-search-result-row"]');
|
||||
if (searchResultRow) {
|
||||
e.preventDefault();
|
||||
@@ -3144,9 +3418,9 @@ import { createSidebarPageSettingsRuntime } from './sidebar-page-settings-runtim
|
||||
closeAllSettingsPopovers();
|
||||
return;
|
||||
}
|
||||
if ((event.metaKey || event.ctrlKey) && !event.shiftKey && event.key && event.key.toLowerCase() === 'p') {
|
||||
if (isSearchShortcutEvent(event)) {
|
||||
event.preventDefault();
|
||||
toggleSearchModal();
|
||||
openSearchModal();
|
||||
return;
|
||||
}
|
||||
if (event.key === 'Escape') {
|
||||
|
||||
Reference in New Issue
Block a user