2026-05-26 04:17:52 +08:00
|
|
|
|
export function createSidebarPageSettingsRuntime(context) {
|
|
|
|
|
|
const {
|
|
|
|
|
|
currentDocumentId,
|
|
|
|
|
|
currentPageAggregate,
|
|
|
|
|
|
currentRootUri,
|
|
|
|
|
|
currentSourceKind,
|
|
|
|
|
|
currentWorkspaceSourcePayload,
|
|
|
|
|
|
escapeHtml,
|
|
|
|
|
|
pageUiState,
|
|
|
|
|
|
resolveWorkspaceId,
|
|
|
|
|
|
searchText,
|
|
|
|
|
|
} = context;
|
|
|
|
|
|
const MNOTE_GLOBAL_SHOW_HEADING_NUMBERS_KEY = context.globalShowHeadingNumbersKey || 'mnote.global.showHeadingNumbers';
|
2026-05-28 22:01:44 +08:00
|
|
|
|
const PAGE_WIDTH_TYPES = ['default', 'markdown', 'word', 'pdf', 'excel', 'ppt', 'mindmap'];
|
|
|
|
|
|
const PAGE_WIDTH_LABELS = {
|
|
|
|
|
|
default: '默认',
|
|
|
|
|
|
markdown: 'Markdown',
|
|
|
|
|
|
word: 'Word',
|
|
|
|
|
|
pdf: 'PDF',
|
|
|
|
|
|
excel: 'Excel',
|
|
|
|
|
|
ppt: 'PPT',
|
|
|
|
|
|
mindmap: 'Mindmap'
|
|
|
|
|
|
};
|
|
|
|
|
|
const DEFAULT_PAGE_WIDTH_PREFERENCES = {
|
|
|
|
|
|
default: { mode: 'comfortable', resolvedMode: 'comfortable', cssMaxWidth: '980px', source: 'system' },
|
|
|
|
|
|
markdown: { mode: 'readable', resolvedMode: 'readable', cssMaxWidth: '760px', source: 'system' },
|
|
|
|
|
|
word: { mode: 'wide', resolvedMode: 'wide', cssMaxWidth: '1180px', source: 'system' },
|
|
|
|
|
|
pdf: { mode: 'wide', resolvedMode: 'wide', cssMaxWidth: '1180px', source: 'system' },
|
|
|
|
|
|
excel: { mode: 'full', resolvedMode: 'full', cssMaxWidth: 'none', source: 'system' },
|
|
|
|
|
|
ppt: { mode: 'wide', resolvedMode: 'wide', cssMaxWidth: '1180px', source: 'system' },
|
|
|
|
|
|
mindmap: { mode: 'full', resolvedMode: 'full', cssMaxWidth: 'none', source: 'system' }
|
|
|
|
|
|
};
|
2026-05-26 04:17:52 +08:00
|
|
|
|
|
|
|
|
|
|
function defaultPageOptions() {
|
|
|
|
|
|
return {
|
|
|
|
|
|
wideLayout: false,
|
|
|
|
|
|
smallText: false,
|
|
|
|
|
|
layoutDensity: 'normal',
|
|
|
|
|
|
showHeadingNumbers: false,
|
|
|
|
|
|
showToc: false,
|
|
|
|
|
|
showStructure: false,
|
|
|
|
|
|
protectEditing: false,
|
|
|
|
|
|
showWordCount: true,
|
|
|
|
|
|
collapseBacklinks: false,
|
|
|
|
|
|
pageFont: 'default',
|
|
|
|
|
|
hideChildPages: false,
|
|
|
|
|
|
showBlockRefCount: false,
|
|
|
|
|
|
hideTitleHeader: false,
|
|
|
|
|
|
embedDefaultBlockId: null
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function currentPageOptions() {
|
|
|
|
|
|
if (pageUiState.pageOptions) return pageUiState.pageOptions;
|
|
|
|
|
|
var aggregate = currentPageAggregate();
|
|
|
|
|
|
var current = aggregate && aggregate.layout && aggregate.layout.pageOptions && typeof aggregate.layout.pageOptions === 'object'
|
|
|
|
|
|
? aggregate.layout.pageOptions
|
|
|
|
|
|
: null;
|
|
|
|
|
|
if (!current) {
|
|
|
|
|
|
return defaultPageOptions();
|
|
|
|
|
|
}
|
|
|
|
|
|
pageUiState.pageOptions = Object.assign(defaultPageOptions(), current);
|
|
|
|
|
|
return pageUiState.pageOptions;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-28 22:01:44 +08:00
|
|
|
|
function currentPageWidthPreferences() {
|
|
|
|
|
|
return Object.assign({}, DEFAULT_PAGE_WIDTH_PREFERENCES, pageUiState.pageWidthPreferences || {});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-02 17:17:49 +08:00
|
|
|
|
function currentLocalOcrPreferences() {
|
|
|
|
|
|
return Object.assign({ 'localOcr.autoEnabled': false }, pageUiState.localOcrPreferences || {});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-28 22:01:44 +08:00
|
|
|
|
function pageWidthModeLabel(mode) {
|
|
|
|
|
|
if (mode === 'inherit') return '继承默认';
|
|
|
|
|
|
if (mode === 'readable') return '阅读';
|
|
|
|
|
|
if (mode === 'comfortable') return '舒适';
|
|
|
|
|
|
if (mode === 'wide') return '宽版';
|
|
|
|
|
|
if (mode === 'full') return '全宽';
|
|
|
|
|
|
return '舒适';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function normalizePageWidthPreferences(value) {
|
|
|
|
|
|
var input = value && typeof value === 'object' ? value : {};
|
|
|
|
|
|
var output = {};
|
|
|
|
|
|
PAGE_WIDTH_TYPES.forEach(function(type) {
|
|
|
|
|
|
var base = DEFAULT_PAGE_WIDTH_PREFERENCES[type];
|
|
|
|
|
|
var current = input[type] && typeof input[type] === 'object' ? input[type] : {};
|
|
|
|
|
|
var mode = String(current.mode || base.mode || 'comfortable');
|
|
|
|
|
|
var resolvedMode = String(current.resolvedMode || current.resolved_mode || (mode === 'inherit' ? (input.default && input.default.resolvedMode) || 'comfortable' : mode));
|
|
|
|
|
|
output[type] = {
|
|
|
|
|
|
mode: mode,
|
|
|
|
|
|
custom: current.custom || null,
|
|
|
|
|
|
resolvedMode: resolvedMode,
|
|
|
|
|
|
resolvedCustom: current.resolvedCustom || current.resolved_custom || null,
|
|
|
|
|
|
cssMaxWidth: String(current.cssMaxWidth || current.css_max_width || pageWidthCssMaxWidth(resolvedMode)),
|
|
|
|
|
|
source: String(current.source || base.source || 'system')
|
|
|
|
|
|
};
|
|
|
|
|
|
});
|
|
|
|
|
|
return output;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function pageWidthCssMaxWidth(mode) {
|
|
|
|
|
|
if (mode === 'readable') return '760px';
|
|
|
|
|
|
if (mode === 'comfortable') return '980px';
|
|
|
|
|
|
if (mode === 'wide') return '1180px';
|
|
|
|
|
|
if (mode === 'full') return 'none';
|
|
|
|
|
|
return '980px';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function markdownPageWidthPreference(options) {
|
|
|
|
|
|
var preferences = currentPageWidthPreferences();
|
|
|
|
|
|
var markdown = preferences.markdown || DEFAULT_PAGE_WIDTH_PREFERENCES.markdown;
|
|
|
|
|
|
if (markdown.source === 'system' && options && options.wideLayout) {
|
|
|
|
|
|
return {
|
|
|
|
|
|
mode: 'comfortable',
|
|
|
|
|
|
resolvedMode: 'comfortable',
|
|
|
|
|
|
cssMaxWidth: '980px',
|
|
|
|
|
|
source: 'wideLayout'
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
return markdown;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function activeResourceWidthType() {
|
|
|
|
|
|
var raw = document.documentElement.getAttribute('data-mnote-active-resource-width-type') || '';
|
|
|
|
|
|
var type = String(raw).trim();
|
|
|
|
|
|
if (type === 'sheet') return 'excel';
|
|
|
|
|
|
if (PAGE_WIDTH_TYPES.indexOf(type) >= 0 && type !== 'default') return type;
|
|
|
|
|
|
return '';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function activeResourceWidthPreference(options) {
|
|
|
|
|
|
var type = activeResourceWidthType();
|
|
|
|
|
|
if (!type || type === 'markdown') return markdownPageWidthPreference(options);
|
|
|
|
|
|
var preferences = currentPageWidthPreferences();
|
|
|
|
|
|
return preferences[type] || DEFAULT_PAGE_WIDTH_PREFERENCES[type] || DEFAULT_PAGE_WIDTH_PREFERENCES.default;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function notifyPageWidthPreferenceChanged(type) {
|
|
|
|
|
|
var detail = {
|
|
|
|
|
|
type: String(type || ''),
|
|
|
|
|
|
preferences: currentPageWidthPreferences()
|
|
|
|
|
|
};
|
|
|
|
|
|
window.dispatchEvent(new CustomEvent('mnote:page-width-preference-changed', { detail: detail }));
|
|
|
|
|
|
document.querySelectorAll('iframe.mnote-resource-tab-frame').forEach(function(frame) {
|
|
|
|
|
|
if (!(frame instanceof HTMLIFrameElement) || !frame.contentWindow) return;
|
|
|
|
|
|
try {
|
|
|
|
|
|
frame.contentWindow.postMessage({
|
|
|
|
|
|
type: 'mnote:page-width-preference-changed',
|
|
|
|
|
|
contentType: detail.type
|
|
|
|
|
|
}, window.location.origin);
|
|
|
|
|
|
} catch (_) {}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-26 04:17:52 +08:00
|
|
|
|
function readGlobalShowHeadingNumbers() {
|
2026-05-27 11:31:12 +08:00
|
|
|
|
return Boolean(currentPageOptions().showHeadingNumbers);
|
2026-05-26 04:17:52 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function writeGlobalShowHeadingNumbers(value) {
|
2026-05-27 11:31:12 +08:00
|
|
|
|
void persistPageOptionsPatch({ showHeadingNumbers: Boolean(value) });
|
2026-05-26 04:17:52 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function effectiveShowHeadingNumbers(options) {
|
2026-05-27 11:31:12 +08:00
|
|
|
|
return Boolean(options && options.showHeadingNumbers);
|
2026-05-26 04:17:52 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function pageOptionIsSupported(name) {
|
|
|
|
|
|
return name === 'wideLayout'
|
|
|
|
|
|
|| name === 'smallText'
|
|
|
|
|
|
|| name === 'layoutDensity'
|
|
|
|
|
|
|| name === 'pageFont'
|
|
|
|
|
|
|| name === 'showHeadingNumbers'
|
|
|
|
|
|
|| (name === 'hideTitleHeader' && currentSourceKind() === 'local_folder');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function pageOptionDescription(name) {
|
|
|
|
|
|
if (name === 'wideLayout') return '自适应宽度';
|
|
|
|
|
|
if (name === 'smallText') return '小字体';
|
|
|
|
|
|
if (name === 'hideTitleHeader') return '隐藏本地 Markdown 文件标题';
|
|
|
|
|
|
if (name === 'showToc') return '标题目录';
|
|
|
|
|
|
if (name === 'showHeadingNumbers') return '标题自动编号';
|
|
|
|
|
|
if (name === 'protectEditing') return '编辑保护';
|
|
|
|
|
|
if (name === 'collapseBacklinks') return '折叠反向引用';
|
|
|
|
|
|
if (name === 'hideChildPages') return '隐藏子页面';
|
|
|
|
|
|
if (name === 'showBlockRefCount') return '显示块引用数字';
|
|
|
|
|
|
return name;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function pageOptionHint(name) {
|
|
|
|
|
|
if (name === 'wideLayout') return '已接通:主内容列宽度立即变化';
|
|
|
|
|
|
if (name === 'smallText') return '已接通:正文排版会更紧凑';
|
|
|
|
|
|
if (name === 'showHeadingNumbers') return '已接通:标题前显示顺序编号';
|
|
|
|
|
|
if (name === 'hideTitleHeader') return '已接通:本地 Markdown 页头标题立即隐藏或显示';
|
|
|
|
|
|
if (name === 'layoutDensity') return '已接通:段落与列表间距会变化';
|
|
|
|
|
|
if (name === 'pageFont') return '已接通:当前页面字体会切换';
|
|
|
|
|
|
if (name === 'showToc') return '待接线:当前 Rust 壳还没有正式目录面板';
|
|
|
|
|
|
if (name === 'protectEditing') return '待接线:当前主编辑器只显示降级说明';
|
|
|
|
|
|
if (name === 'collapseBacklinks') return '待接线:当前 Rust 壳未挂回链面板';
|
|
|
|
|
|
if (name === 'hideChildPages') return '待接线:当前页面壳还没有子页面块显隐';
|
|
|
|
|
|
if (name === 'showBlockRefCount') return '待接线:当前页面壳未显示块引用计数';
|
|
|
|
|
|
return '待接线';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function ensureHistorySnapshotsSeeded() {
|
|
|
|
|
|
if (pageUiState.historySnapshots.length > 0) return;
|
|
|
|
|
|
var aggregate = currentPageAggregate();
|
|
|
|
|
|
var stats = aggregate && aggregate.stats && typeof aggregate.stats === 'object' ? aggregate.stats : {};
|
|
|
|
|
|
pageUiState.historySnapshots = [{
|
|
|
|
|
|
id: 'snapshot-initial',
|
|
|
|
|
|
timestamp: Date.now(),
|
|
|
|
|
|
stats: {
|
|
|
|
|
|
wordCount: Number(stats.wordCount || 0),
|
|
|
|
|
|
characterCount: Number(stats.characterCount || 0),
|
|
|
|
|
|
blockCount: Number(stats.blockCount || 0),
|
|
|
|
|
|
todoTotal: Number(stats.todoTotal || 0),
|
|
|
|
|
|
todoDone: Number(stats.todoDone || 0)
|
|
|
|
|
|
}
|
|
|
|
|
|
}];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function computeLivePageStats() {
|
|
|
|
|
|
var aggregate = currentPageAggregate();
|
|
|
|
|
|
var fallbackStats = aggregate && aggregate.stats && typeof aggregate.stats === 'object' ? aggregate.stats : {};
|
|
|
|
|
|
var editor = document.querySelector('[data-testid="mnote-leptos-tiptap-island-editor-root"] .editor-surface .ProseMirror');
|
|
|
|
|
|
if (!(editor instanceof HTMLElement)) {
|
|
|
|
|
|
return {
|
|
|
|
|
|
wordCount: Number(fallbackStats.wordCount || 0),
|
|
|
|
|
|
characterCount: Number(fallbackStats.characterCount || 0),
|
|
|
|
|
|
blockCount: Number(fallbackStats.blockCount || 0),
|
|
|
|
|
|
todoTotal: Number(fallbackStats.todoTotal || 0),
|
|
|
|
|
|
todoDone: Number(fallbackStats.todoDone || 0)
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
var text = (editor.textContent || '').trim();
|
|
|
|
|
|
var compact = text.replace(/\s+/g, ' ').trim();
|
|
|
|
|
|
var wordCount = compact ? compact.split(' ').filter(Boolean).length : 0;
|
|
|
|
|
|
var characterCount = text.replace(/\s/g, '').length;
|
|
|
|
|
|
var blockCount = editor.querySelectorAll(':scope > *').length;
|
|
|
|
|
|
var todos = Array.from(editor.querySelectorAll('input[type="checkbox"]'));
|
|
|
|
|
|
return {
|
|
|
|
|
|
wordCount: wordCount || Number(fallbackStats.wordCount || 0),
|
|
|
|
|
|
characterCount: characterCount || Number(fallbackStats.characterCount || 0),
|
|
|
|
|
|
blockCount: blockCount || Number(fallbackStats.blockCount || 0),
|
|
|
|
|
|
todoTotal: todos.length || Number(fallbackStats.todoTotal || 0),
|
|
|
|
|
|
todoDone: todos.filter(function(node){ return node.checked; }).length || Number(fallbackStats.todoDone || 0)
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function recordPageHistorySnapshot(reason, stats) {
|
|
|
|
|
|
ensureHistorySnapshotsSeeded();
|
|
|
|
|
|
pageUiState.historySnapshots = [{
|
|
|
|
|
|
id: 'snapshot-' + Date.now(),
|
|
|
|
|
|
timestamp: Date.now(),
|
|
|
|
|
|
reason: reason || 'save',
|
|
|
|
|
|
stats: stats || computeLivePageStats()
|
|
|
|
|
|
}].concat(pageUiState.historySnapshots).slice(0, 15);
|
|
|
|
|
|
renderPageHistoryDrawer();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function applyPageOptionsToShell() {
|
|
|
|
|
|
var options = currentPageOptions();
|
2026-05-27 11:31:12 +08:00
|
|
|
|
var globalShowHeadingNumbers = Boolean(options.showHeadingNumbers);
|
2026-05-26 04:17:52 +08:00
|
|
|
|
var showHeadingNumbers = effectiveShowHeadingNumbers(options);
|
|
|
|
|
|
var shell = document.querySelector('.document-shell');
|
|
|
|
|
|
var editorRoot = document.querySelector('[data-testid="mnote-leptos-tiptap-island-editor-root"]');
|
|
|
|
|
|
var editorSurface = editorRoot && editorRoot.querySelector('.editor-surface');
|
2026-06-01 09:29:12 +08:00
|
|
|
|
var mindmapWidthPreference = currentPageWidthPreferences().mindmap || DEFAULT_PAGE_WIDTH_PREFERENCES.mindmap;
|
|
|
|
|
|
var mindmapMaxWidth = String(mindmapWidthPreference.cssMaxWidth || pageWidthCssMaxWidth(mindmapWidthPreference.resolvedMode));
|
|
|
|
|
|
var mindmapMaxWidthValue = mindmapMaxWidth === 'none' ? 'none' : mindmapMaxWidth;
|
2026-05-26 04:17:52 +08:00
|
|
|
|
if (shell instanceof HTMLElement) {
|
2026-05-28 22:01:44 +08:00
|
|
|
|
var widthPreference = activeResourceWidthPreference(options);
|
|
|
|
|
|
var cssMaxWidth = String(widthPreference.cssMaxWidth || pageWidthCssMaxWidth(widthPreference.resolvedMode));
|
2026-05-26 04:17:52 +08:00
|
|
|
|
shell.setAttribute('data-page-wide-layout', String(Boolean(options.wideLayout)));
|
2026-05-28 22:01:44 +08:00
|
|
|
|
shell.setAttribute('data-page-width-content-type', activeResourceWidthType() || 'markdown');
|
|
|
|
|
|
shell.setAttribute('data-page-width-mode', String(widthPreference.mode || 'readable'));
|
|
|
|
|
|
shell.setAttribute('data-page-width-resolved-mode', String(widthPreference.resolvedMode || widthPreference.mode || 'readable'));
|
|
|
|
|
|
shell.setAttribute('data-page-width-source', String(widthPreference.source || 'system'));
|
2026-05-26 04:17:52 +08:00
|
|
|
|
shell.setAttribute('data-page-small-text', String(Boolean(options.smallText)));
|
|
|
|
|
|
shell.setAttribute('data-layout-density', String(options.layoutDensity || 'normal'));
|
|
|
|
|
|
shell.setAttribute('data-page-font', String(options.pageFont || 'default'));
|
|
|
|
|
|
shell.setAttribute('data-page-show-heading-numbers', String(showHeadingNumbers));
|
|
|
|
|
|
shell.style.width = '100%';
|
2026-05-28 22:01:44 +08:00
|
|
|
|
shell.style.maxWidth = cssMaxWidth === 'none' ? 'none' : cssMaxWidth;
|
2026-06-01 09:29:12 +08:00
|
|
|
|
shell.style.setProperty('--mnote-mindmap-block-max-width', mindmapMaxWidthValue);
|
2026-05-26 04:17:52 +08:00
|
|
|
|
}
|
|
|
|
|
|
if (editorRoot instanceof HTMLElement) {
|
|
|
|
|
|
editorRoot.setAttribute('data-page-wide-layout', String(Boolean(options.wideLayout)));
|
|
|
|
|
|
editorRoot.setAttribute('data-page-small-text', String(Boolean(options.smallText)));
|
|
|
|
|
|
editorRoot.setAttribute('data-page-show-heading-numbers', String(showHeadingNumbers));
|
|
|
|
|
|
editorRoot.setAttribute('data-page-embed-default-block-id', options.embedDefaultBlockId == null ? '' : String(options.embedDefaultBlockId));
|
2026-06-01 09:29:12 +08:00
|
|
|
|
editorRoot.style.setProperty('--mnote-mindmap-block-max-width', mindmapMaxWidthValue);
|
2026-05-26 04:17:52 +08:00
|
|
|
|
}
|
|
|
|
|
|
if (editorSurface instanceof HTMLElement) {
|
|
|
|
|
|
editorSurface.setAttribute('data-layout-density', String(options.layoutDensity || 'normal'));
|
|
|
|
|
|
editorSurface.setAttribute('data-page-font', String(options.pageFont || 'default'));
|
|
|
|
|
|
editorSurface.setAttribute('data-show-heading-numbers', String(showHeadingNumbers));
|
|
|
|
|
|
}
|
|
|
|
|
|
document.documentElement.setAttribute('data-page-wide-layout', String(Boolean(options.wideLayout)));
|
2026-05-28 22:01:44 +08:00
|
|
|
|
var rootWidthPreference = activeResourceWidthPreference(options);
|
|
|
|
|
|
document.documentElement.setAttribute('data-page-width-content-type', activeResourceWidthType() || 'markdown');
|
|
|
|
|
|
document.documentElement.setAttribute('data-page-width-mode', String(rootWidthPreference.mode || 'readable'));
|
|
|
|
|
|
document.documentElement.setAttribute('data-page-width-resolved-mode', String(rootWidthPreference.resolvedMode || rootWidthPreference.mode || 'readable'));
|
2026-05-26 04:17:52 +08:00
|
|
|
|
document.documentElement.setAttribute('data-page-small-text', String(Boolean(options.smallText)));
|
|
|
|
|
|
document.documentElement.setAttribute('data-layout-density', String(options.layoutDensity || 'normal'));
|
|
|
|
|
|
document.documentElement.setAttribute('data-page-font', String(options.pageFont || 'default'));
|
|
|
|
|
|
document.documentElement.setAttribute('data-global-show-heading-numbers', String(globalShowHeadingNumbers));
|
|
|
|
|
|
document.documentElement.setAttribute('data-page-show-heading-numbers', String(showHeadingNumbers));
|
|
|
|
|
|
document.documentElement.setAttribute('data-page-hide-title-header', String(Boolean(options.hideTitleHeader)));
|
2026-06-01 09:29:12 +08:00
|
|
|
|
document.documentElement.style.setProperty('--mnote-mindmap-block-max-width', mindmapMaxWidthValue);
|
2026-05-26 04:17:52 +08:00
|
|
|
|
var titleHeader = document.querySelector('.document-pane[data-pane-role="primary"] .document-shell-header') || document.querySelector('.document-shell-header');
|
|
|
|
|
|
if (titleHeader instanceof HTMLElement) {
|
|
|
|
|
|
var hidden = Boolean(options.hideTitleHeader);
|
|
|
|
|
|
titleHeader.hidden = hidden;
|
|
|
|
|
|
titleHeader.setAttribute('data-page-title-hidden', String(hidden));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function updatePageSettingsTriggerState() {
|
|
|
|
|
|
var trigger = document.querySelector('[data-testid="wolai-page-settings-trigger"]');
|
|
|
|
|
|
if (!(trigger instanceof HTMLElement)) return;
|
|
|
|
|
|
trigger.setAttribute('data-state', pageUiState.pageSettingsOpen ? 'open' : 'closed');
|
|
|
|
|
|
trigger.setAttribute('aria-expanded', pageUiState.pageSettingsOpen ? 'true' : 'false');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-04 18:51:16 +08:00
|
|
|
|
function updateStandaloneSettingsTriggerState() {
|
|
|
|
|
|
var indexTrigger = document.querySelector('[data-testid="mnote-local-index-settings-toggle"]');
|
|
|
|
|
|
var indexOpen = isLocalIndexSettingsOpen();
|
|
|
|
|
|
if (indexTrigger instanceof HTMLElement) {
|
|
|
|
|
|
indexTrigger.setAttribute('data-state', indexOpen ? 'open' : 'closed');
|
|
|
|
|
|
indexTrigger.setAttribute('aria-expanded', indexOpen ? 'true' : 'false');
|
|
|
|
|
|
}
|
|
|
|
|
|
var ocrTrigger = document.querySelector('[data-testid="mnote-local-ocr-task-toggle"]');
|
|
|
|
|
|
var ocrOpen = isLocalOcrSettingsOpen();
|
|
|
|
|
|
if (ocrTrigger instanceof HTMLElement) {
|
|
|
|
|
|
ocrTrigger.setAttribute('data-state', ocrOpen ? 'open' : 'closed');
|
|
|
|
|
|
ocrTrigger.setAttribute('aria-expanded', ocrOpen ? 'true' : 'false');
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-26 04:17:52 +08:00
|
|
|
|
function createPageOptionRow(key, type) {
|
|
|
|
|
|
var inputType = type || 'checkbox';
|
|
|
|
|
|
var supported = pageOptionIsSupported(key);
|
|
|
|
|
|
if (inputType === 'checkbox') {
|
|
|
|
|
|
return '' +
|
|
|
|
|
|
'<label class="wolai-page-setting-row' + (supported ? '' : ' is-pending') + '" data-page-setting-row="' + key + '">' +
|
|
|
|
|
|
'<span class="wolai-page-setting-copy">' +
|
|
|
|
|
|
'<span class="wolai-page-setting-label">' + escapeHtml(pageOptionDescription(key)) + '</span>' +
|
|
|
|
|
|
'<span class="wolai-page-setting-hint">' + escapeHtml(pageOptionHint(key)) + '</span>' +
|
|
|
|
|
|
'</span>' +
|
|
|
|
|
|
'<input type="checkbox" class="wolai-page-setting-checkbox" data-page-option-checkbox="' + key + '"' + (supported ? '' : ' data-setting-pending="true"') + ' />' +
|
|
|
|
|
|
'</label>';
|
|
|
|
|
|
}
|
|
|
|
|
|
return '' +
|
|
|
|
|
|
'<label class="wolai-page-setting-row" data-page-setting-row="' + key + '">' +
|
|
|
|
|
|
'<span class="wolai-page-setting-copy">' +
|
|
|
|
|
|
'<span class="wolai-page-setting-label">' + escapeHtml(pageOptionDescription(key)) + '</span>' +
|
|
|
|
|
|
'<span class="wolai-page-setting-hint">' + escapeHtml(pageOptionHint(key)) + '</span>' +
|
|
|
|
|
|
'</span>' +
|
|
|
|
|
|
'<select class="wolai-page-setting-select" data-page-option-select="' + key + '">' +
|
|
|
|
|
|
'<option value="compact">紧凑</option>' +
|
|
|
|
|
|
'<option value="normal">默认</option>' +
|
|
|
|
|
|
'<option value="spacious">宽松</option>' +
|
|
|
|
|
|
'</select>' +
|
|
|
|
|
|
'</label>';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function createGlobalHeadingNumbersRow() {
|
|
|
|
|
|
return '' +
|
|
|
|
|
|
'<label class="wolai-page-setting-row" data-page-setting-row="globalShowHeadingNumbers">' +
|
|
|
|
|
|
'<span class="wolai-page-setting-copy">' +
|
|
|
|
|
|
'<span class="wolai-page-setting-label">标题自动编号</span>' +
|
|
|
|
|
|
'</span>' +
|
|
|
|
|
|
'<input type="checkbox" class="wolai-page-setting-checkbox" data-global-option-checkbox="showHeadingNumbers" />' +
|
|
|
|
|
|
'</label>';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-02 17:17:49 +08:00
|
|
|
|
function createLocalOcrAutoRow() {
|
|
|
|
|
|
return '' +
|
|
|
|
|
|
'<label class="wolai-page-setting-row" data-page-setting-row="localOcrAutoEnabled">' +
|
|
|
|
|
|
'<span class="wolai-page-setting-copy">' +
|
|
|
|
|
|
'<span class="wolai-page-setting-label">自动 OCR</span>' +
|
|
|
|
|
|
'<span class="wolai-page-setting-hint">默认关闭;仅作为搜索和 AI 索引补充处理图片与图片型 PDF</span>' +
|
|
|
|
|
|
'</span>' +
|
|
|
|
|
|
'<input type="checkbox" class="wolai-page-setting-checkbox" data-local-ocr-option-checkbox="autoEnabled" />' +
|
|
|
|
|
|
'</label>';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-28 22:01:44 +08:00
|
|
|
|
function createPageWidthSelectRow(type) {
|
|
|
|
|
|
var options = type === 'default'
|
|
|
|
|
|
? [
|
|
|
|
|
|
['readable', '阅读'],
|
|
|
|
|
|
['comfortable', '舒适'],
|
|
|
|
|
|
['wide', '宽版'],
|
|
|
|
|
|
['full', '全宽']
|
|
|
|
|
|
]
|
|
|
|
|
|
: [
|
|
|
|
|
|
['inherit', '继承默认'],
|
|
|
|
|
|
['readable', '阅读'],
|
|
|
|
|
|
['comfortable', '舒适'],
|
|
|
|
|
|
['wide', '宽版'],
|
|
|
|
|
|
['full', '全宽']
|
|
|
|
|
|
];
|
|
|
|
|
|
return '' +
|
|
|
|
|
|
'<label class="wolai-page-setting-row" data-page-width-row="' + type + '">' +
|
|
|
|
|
|
'<span class="wolai-page-setting-copy">' +
|
|
|
|
|
|
'<span class="wolai-page-setting-label">' + escapeHtml(PAGE_WIDTH_LABELS[type] || type) + '</span>' +
|
|
|
|
|
|
'<span class="wolai-page-setting-hint" data-page-width-hint="' + type + '"></span>' +
|
|
|
|
|
|
'</span>' +
|
|
|
|
|
|
'<select class="wolai-page-setting-select" data-page-width-select="' + type + '">' +
|
|
|
|
|
|
options.map(function(option) {
|
|
|
|
|
|
return '<option value="' + option[0] + '">' + option[1] + '</option>';
|
|
|
|
|
|
}).join('') +
|
|
|
|
|
|
'</select>' +
|
|
|
|
|
|
'</label>';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function createPageWidthRows() {
|
|
|
|
|
|
return '' +
|
|
|
|
|
|
'<div class="wolai-page-settings-global-note">页面宽度</div>' +
|
|
|
|
|
|
PAGE_WIDTH_TYPES.map(createPageWidthSelectRow).join('');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-26 04:17:52 +08:00
|
|
|
|
function renderGlobalOptions(popover) {
|
|
|
|
|
|
var globalHeadingNumbers = readGlobalShowHeadingNumbers();
|
|
|
|
|
|
popover.querySelectorAll('[data-global-option-checkbox="showHeadingNumbers"]').forEach(function(input) {
|
|
|
|
|
|
input.checked = globalHeadingNumbers;
|
|
|
|
|
|
});
|
2026-05-28 22:01:44 +08:00
|
|
|
|
var preferences = currentPageWidthPreferences();
|
|
|
|
|
|
popover.querySelectorAll('[data-page-width-select]').forEach(function(select) {
|
|
|
|
|
|
var type = select.getAttribute('data-page-width-select') || '';
|
|
|
|
|
|
var preference = preferences[type] || DEFAULT_PAGE_WIDTH_PREFERENCES[type] || DEFAULT_PAGE_WIDTH_PREFERENCES.default;
|
|
|
|
|
|
select.value = String(preference.mode || 'comfortable');
|
|
|
|
|
|
});
|
|
|
|
|
|
popover.querySelectorAll('[data-page-width-hint]').forEach(function(node) {
|
|
|
|
|
|
var type = node.getAttribute('data-page-width-hint') || '';
|
|
|
|
|
|
var preference = preferences[type] || DEFAULT_PAGE_WIDTH_PREFERENCES[type] || DEFAULT_PAGE_WIDTH_PREFERENCES.default;
|
|
|
|
|
|
var resolvedMode = String(preference.resolvedMode || preference.mode || 'comfortable');
|
|
|
|
|
|
node.textContent = pageWidthModeLabel(resolvedMode) + ' · ' + String(preference.cssMaxWidth || pageWidthCssMaxWidth(resolvedMode));
|
|
|
|
|
|
});
|
2026-05-26 04:17:52 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-04 18:51:16 +08:00
|
|
|
|
function renderLocalOcrOptions(popover) {
|
|
|
|
|
|
var localOcrPreferences = currentLocalOcrPreferences();
|
|
|
|
|
|
popover.querySelectorAll('[data-local-ocr-option-checkbox="autoEnabled"]').forEach(function(input) {
|
|
|
|
|
|
input.checked = localOcrPreferences['localOcr.autoEnabled'] === true;
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-26 04:17:52 +08:00
|
|
|
|
function createPageFontRow() {
|
|
|
|
|
|
return '' +
|
|
|
|
|
|
'<label class="wolai-page-setting-row" data-page-setting-row="pageFont">' +
|
|
|
|
|
|
'<span class="wolai-page-setting-copy">' +
|
|
|
|
|
|
'<span class="wolai-page-setting-label">页面字体</span>' +
|
|
|
|
|
|
'<span class="wolai-page-setting-hint">已接通:仅对当前页面生效</span>' +
|
|
|
|
|
|
'</span>' +
|
|
|
|
|
|
'<select class="wolai-page-setting-select" data-page-option-select="pageFont">' +
|
|
|
|
|
|
'<option value="default">默认</option>' +
|
|
|
|
|
|
'<option value="song">宋体</option>' +
|
|
|
|
|
|
'<option value="kai">楷体</option>' +
|
|
|
|
|
|
'</select>' +
|
|
|
|
|
|
'</label>';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function ensurePageHistoryDrawer() {
|
|
|
|
|
|
var existing = document.querySelector('[data-testid="wolai-page-history-drawer"]');
|
|
|
|
|
|
if (existing instanceof HTMLElement) return existing;
|
|
|
|
|
|
var drawer = document.createElement('aside');
|
|
|
|
|
|
drawer.className = 'wolai-page-history-drawer';
|
|
|
|
|
|
drawer.setAttribute('data-testid', 'wolai-page-history-drawer');
|
|
|
|
|
|
drawer.setAttribute('data-mnote-surface', 'page-history');
|
|
|
|
|
|
drawer.hidden = true;
|
|
|
|
|
|
drawer.innerHTML = '' +
|
|
|
|
|
|
'<div class="wolai-page-history-panel">' +
|
|
|
|
|
|
'<div class="wolai-page-history-header">' +
|
|
|
|
|
|
'<div><div class="wolai-page-history-title">页面历史</div><div class="wolai-page-history-subtitle">当前会话内最近保存的 15 个快照。</div></div>' +
|
|
|
|
|
|
'<button type="button" class="wolai-surface-close" data-page-history-action="close" aria-label="关闭页面历史">×</button>' +
|
|
|
|
|
|
'</div>' +
|
|
|
|
|
|
'<div class="wolai-page-history-list" data-page-history-list></div>' +
|
|
|
|
|
|
'</div>';
|
|
|
|
|
|
drawer.addEventListener('click', function(event) {
|
|
|
|
|
|
if (event.target === drawer) closePageHistoryDrawer();
|
|
|
|
|
|
});
|
|
|
|
|
|
document.body.appendChild(drawer);
|
|
|
|
|
|
return drawer;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function renderPageHistoryDrawer() {
|
|
|
|
|
|
var drawer = ensurePageHistoryDrawer();
|
|
|
|
|
|
var list = drawer.querySelector('[data-page-history-list]');
|
|
|
|
|
|
if (!(list instanceof HTMLElement)) return;
|
|
|
|
|
|
ensureHistorySnapshotsSeeded();
|
|
|
|
|
|
list.innerHTML = pageUiState.historySnapshots.length
|
|
|
|
|
|
? pageUiState.historySnapshots.map(function(snapshot) {
|
|
|
|
|
|
var stats = snapshot.stats || {};
|
|
|
|
|
|
var label = new Date(snapshot.timestamp).toLocaleString('zh-CN', {
|
|
|
|
|
|
year: 'numeric',
|
|
|
|
|
|
month: '2-digit',
|
|
|
|
|
|
day: '2-digit',
|
|
|
|
|
|
hour: '2-digit',
|
|
|
|
|
|
minute: '2-digit'
|
|
|
|
|
|
});
|
|
|
|
|
|
return '' +
|
|
|
|
|
|
'<div class="wolai-page-history-item">' +
|
|
|
|
|
|
'<div class="wolai-page-history-item-copy">' +
|
|
|
|
|
|
'<div class="wolai-page-history-item-title">' + escapeHtml(label) + '</div>' +
|
|
|
|
|
|
'<div class="wolai-page-history-item-meta">字数 ' + Number(stats.wordCount || 0) + ' · 字符 ' + Number(stats.characterCount || 0) + ' · 块数 ' + Number(stats.blockCount || 0) + '</div>' +
|
|
|
|
|
|
'</div>' +
|
|
|
|
|
|
'<button type="button" class="wolai-page-history-item-ghost" data-page-history-action="noop">仅查看</button>' +
|
|
|
|
|
|
'</div>';
|
|
|
|
|
|
}).join('')
|
|
|
|
|
|
: '<div class="wolai-page-history-empty">尚未产生历史快照,编辑后会自动生成。</div>';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function openPageHistoryDrawer() {
|
|
|
|
|
|
renderPageHistoryDrawer();
|
|
|
|
|
|
var drawer = ensurePageHistoryDrawer();
|
|
|
|
|
|
drawer.hidden = false;
|
|
|
|
|
|
document.documentElement.setAttribute('data-mnote-page-history-open', 'true');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function closePageHistoryDrawer() {
|
|
|
|
|
|
var drawer = document.querySelector('[data-testid="wolai-page-history-drawer"]');
|
|
|
|
|
|
if (drawer instanceof HTMLElement) drawer.hidden = true;
|
|
|
|
|
|
document.documentElement.removeAttribute('data-mnote-page-history-open');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function ensurePageShareDialog() {
|
|
|
|
|
|
var existing = document.querySelector('[data-testid="wolai-page-share-dialog"]');
|
|
|
|
|
|
if (existing instanceof HTMLElement) return existing;
|
|
|
|
|
|
var dialog = document.createElement('div');
|
|
|
|
|
|
dialog.className = 'wolai-page-share-dialog';
|
|
|
|
|
|
dialog.setAttribute('data-testid', 'wolai-page-share-dialog');
|
|
|
|
|
|
dialog.setAttribute('data-mnote-surface', 'page-share');
|
|
|
|
|
|
dialog.hidden = true;
|
|
|
|
|
|
dialog.innerHTML = '' +
|
|
|
|
|
|
'<div class="wolai-page-share-card" role="dialog" aria-modal="true">' +
|
|
|
|
|
|
'<div class="wolai-page-share-header">' +
|
|
|
|
|
|
'<div><div class="wolai-page-share-title">公开分享页面</div><div class="wolai-page-share-subtitle">当前 3000 公开入口由 mnote-web 持有。</div></div>' +
|
|
|
|
|
|
'<button type="button" class="wolai-surface-close" data-page-share-action="close" aria-label="关闭公开分享页面">×</button>' +
|
|
|
|
|
|
'</div>' +
|
|
|
|
|
|
'<div class="wolai-page-share-state">' +
|
|
|
|
|
|
'<span class="wolai-public-pill wolai-public-pill--inline">全网公开</span>' +
|
|
|
|
|
|
'<span class="wolai-page-share-copy">任何拥有链接的人都可以访问当前页面。</span>' +
|
|
|
|
|
|
'</div>' +
|
|
|
|
|
|
'<div class="wolai-page-share-url-row">' +
|
|
|
|
|
|
'<input class="wolai-page-share-url" type="text" readonly data-page-share-url value="" />' +
|
|
|
|
|
|
'<button type="button" class="wolai-page-share-copy-button" data-page-share-action="copy-link">复制链接</button>' +
|
|
|
|
|
|
'</div>' +
|
|
|
|
|
|
'<div class="wolai-page-share-footer">更多共享者、群组公开和权限策略仍待接线。</div>' +
|
|
|
|
|
|
'</div>';
|
|
|
|
|
|
dialog.addEventListener('click', function(event) {
|
|
|
|
|
|
if (event.target === dialog) closePageShareDialog();
|
|
|
|
|
|
});
|
|
|
|
|
|
document.body.appendChild(dialog);
|
|
|
|
|
|
return dialog;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function openPageShareDialog() {
|
|
|
|
|
|
var dialog = ensurePageShareDialog();
|
|
|
|
|
|
var input = dialog.querySelector('[data-page-share-url]');
|
|
|
|
|
|
if (input instanceof HTMLInputElement) input.value = window.location.href;
|
|
|
|
|
|
dialog.hidden = false;
|
|
|
|
|
|
document.documentElement.setAttribute('data-mnote-page-share-open', 'true');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function closePageShareDialog() {
|
|
|
|
|
|
var dialog = document.querySelector('[data-testid="wolai-page-share-dialog"]');
|
|
|
|
|
|
if (dialog instanceof HTMLElement) dialog.hidden = true;
|
|
|
|
|
|
document.documentElement.removeAttribute('data-mnote-page-share-open');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function ensurePageSettingsPopover() {
|
|
|
|
|
|
var existing = document.querySelector('[data-testid="wolai-page-settings-popover"]');
|
|
|
|
|
|
if (existing instanceof HTMLElement) return existing;
|
|
|
|
|
|
var popover = document.createElement('div');
|
|
|
|
|
|
popover.className = 'wolai-page-settings-popover';
|
|
|
|
|
|
popover.setAttribute('data-testid', 'wolai-page-settings-popover');
|
|
|
|
|
|
popover.setAttribute('data-mnote-surface', 'page-settings');
|
|
|
|
|
|
popover.hidden = true;
|
|
|
|
|
|
popover.innerHTML = '' +
|
|
|
|
|
|
'<div class="wolai-page-settings-panel" role="dialog" aria-modal="false">' +
|
|
|
|
|
|
'<div class="wolai-page-settings-tabs" data-testid="wolai-page-settings-tabs" role="tablist" aria-label="页面设置分组">' +
|
|
|
|
|
|
'<button type="button" class="wolai-page-settings-tab is-active" role="tab" aria-selected="true" data-page-settings-tab="page">页面选项</button>' +
|
|
|
|
|
|
'<button type="button" class="wolai-page-settings-tab" role="tab" aria-selected="false" data-page-settings-tab="custom">自定义页面</button>' +
|
|
|
|
|
|
'<button type="button" class="wolai-page-settings-tab" role="tab" aria-selected="false" data-page-settings-tab="global">全局选项</button>' +
|
|
|
|
|
|
'</div>' +
|
|
|
|
|
|
'<div class="wolai-page-settings-section" data-page-settings-panel="page">' +
|
|
|
|
|
|
createPageOptionRow('wideLayout', 'checkbox') +
|
|
|
|
|
|
createPageOptionRow('smallText', 'checkbox') +
|
|
|
|
|
|
createPageOptionRow('showToc', 'checkbox') +
|
|
|
|
|
|
createPageOptionRow('protectEditing', 'checkbox') +
|
|
|
|
|
|
createPageOptionRow('hideTitleHeader', 'checkbox') +
|
|
|
|
|
|
'</div>' +
|
|
|
|
|
|
'<div class="wolai-page-settings-section" data-page-settings-panel="custom" hidden>' +
|
|
|
|
|
|
createPageFontRow() +
|
|
|
|
|
|
createPageOptionRow('layoutDensity', 'select') +
|
|
|
|
|
|
createPageOptionRow('collapseBacklinks', 'checkbox') +
|
|
|
|
|
|
createPageOptionRow('hideChildPages', 'checkbox') +
|
|
|
|
|
|
createPageOptionRow('showBlockRefCount', 'checkbox') +
|
|
|
|
|
|
'</div>' +
|
|
|
|
|
|
'<div class="wolai-page-settings-section" data-page-settings-panel="global" hidden>' +
|
|
|
|
|
|
createGlobalHeadingNumbersRow() +
|
2026-05-28 22:01:44 +08:00
|
|
|
|
createPageWidthRows() +
|
2026-05-26 04:17:52 +08:00
|
|
|
|
'</div>' +
|
|
|
|
|
|
'<div class="wolai-page-settings-actions">' +
|
|
|
|
|
|
'<button type="button" class="wolai-page-settings-action" data-page-settings-action="history">页面历史...</button>' +
|
|
|
|
|
|
'<button type="button" class="wolai-page-settings-action" data-page-settings-action="share">公开分享页面...</button>' +
|
|
|
|
|
|
'<button type="button" class="wolai-page-settings-action is-disabled" data-page-settings-action="move" disabled>移动到...</button>' +
|
|
|
|
|
|
'<button type="button" class="wolai-page-settings-action is-disabled" data-page-settings-action="embed" disabled>嵌入到...</button>' +
|
|
|
|
|
|
'<button type="button" class="wolai-page-settings-action is-danger is-disabled" data-page-settings-action="delete" disabled>删除页面</button>' +
|
|
|
|
|
|
'</div>' +
|
|
|
|
|
|
'<div class="wolai-page-settings-stats" data-testid="wolai-page-settings-stats"></div>' +
|
|
|
|
|
|
'</div>';
|
|
|
|
|
|
document.body.appendChild(popover);
|
|
|
|
|
|
return popover;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-04 18:51:16 +08:00
|
|
|
|
function createLocalIndexSettingsPanelHtml() {
|
|
|
|
|
|
return '' +
|
|
|
|
|
|
'<div class="wolai-page-settings-panel mnote-settings-panel mnote-local-index-settings-panel" role="dialog" aria-modal="false" aria-label="索引设置">' +
|
|
|
|
|
|
'<div class="mnote-settings-panel-head">' +
|
|
|
|
|
|
'<strong>索引设置</strong>' +
|
|
|
|
|
|
'<button type="button" class="mnote-settings-panel-close" data-settings-action="close" aria-label="关闭索引设置">×</button>' +
|
|
|
|
|
|
'</div>' +
|
|
|
|
|
|
'<div class="wolai-page-settings-index-panel" data-testid="wolai-page-settings-local-index-panel">' +
|
|
|
|
|
|
'<div class="wolai-page-settings-index-status" data-testid="wolai-page-settings-local-index-status"></div>' +
|
|
|
|
|
|
'<section class="wolai-page-settings-index-group">' +
|
|
|
|
|
|
'<div class="wolai-page-settings-index-title">索引范围</div>' +
|
|
|
|
|
|
'<div class="wolai-page-settings-index-range-list" data-testid="wolai-page-settings-local-index-ranges"></div>' +
|
|
|
|
|
|
'<button type="button" class="wolai-page-settings-index-add" data-local-index-action="add-path">新增范围</button>' +
|
|
|
|
|
|
'<div class="wolai-page-settings-index-schedule">' +
|
|
|
|
|
|
'<label><span>索引时间</span><select data-testid="wolai-page-settings-local-index-schedule-mode"><option value="daily">每日</option><option value="once">指定日期</option><option value="manual">手动</option></select></label>' +
|
|
|
|
|
|
'<label><span>时间</span><input type="time" data-testid="wolai-page-settings-local-index-schedule-time" value="02:00"></label>' +
|
|
|
|
|
|
'<label><span>日期</span><input type="date" data-testid="wolai-page-settings-local-index-schedule-date"></label>' +
|
|
|
|
|
|
'<label class="wolai-page-settings-index-inline"><input type="checkbox" data-testid="wolai-page-settings-local-index-run-on-change"><span>文档变化时立即索引</span></label>' +
|
|
|
|
|
|
'</div>' +
|
|
|
|
|
|
'<div class="wolai-page-settings-index-actions">' +
|
|
|
|
|
|
'<button type="button" data-local-index-action="save">保存设置</button>' +
|
|
|
|
|
|
'<button type="button" data-local-index-action="refresh">重建索引</button>' +
|
|
|
|
|
|
'</div>' +
|
|
|
|
|
|
'</section>' +
|
|
|
|
|
|
'</div>' +
|
|
|
|
|
|
'</div>';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function ensureLocalIndexSettingsPopover() {
|
|
|
|
|
|
var existing = document.querySelector('[data-testid="mnote-local-index-settings-popover"]');
|
|
|
|
|
|
if (existing instanceof HTMLElement) return existing;
|
|
|
|
|
|
var popover = document.createElement('div');
|
|
|
|
|
|
popover.className = 'wolai-page-settings-popover mnote-local-index-settings-popover';
|
|
|
|
|
|
popover.setAttribute('data-testid', 'mnote-local-index-settings-popover');
|
|
|
|
|
|
popover.setAttribute('data-mnote-surface', 'local-index-settings');
|
|
|
|
|
|
popover.hidden = true;
|
|
|
|
|
|
popover.innerHTML = createLocalIndexSettingsPanelHtml();
|
|
|
|
|
|
document.body.appendChild(popover);
|
|
|
|
|
|
return popover;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function ensureLocalOcrSettingsPopover() {
|
|
|
|
|
|
var existing = document.querySelector('[data-testid="mnote-local-ocr-settings-popover"]');
|
|
|
|
|
|
if (existing instanceof HTMLElement) return existing;
|
|
|
|
|
|
var popover = document.createElement('div');
|
|
|
|
|
|
popover.className = 'wolai-page-settings-popover mnote-local-ocr-settings-popover';
|
|
|
|
|
|
popover.setAttribute('data-testid', 'mnote-local-ocr-settings-popover');
|
|
|
|
|
|
popover.setAttribute('data-mnote-surface', 'local-ocr-settings');
|
|
|
|
|
|
popover.hidden = true;
|
|
|
|
|
|
popover.innerHTML = '' +
|
|
|
|
|
|
'<div class="wolai-page-settings-panel mnote-settings-panel mnote-local-ocr-settings-panel" role="dialog" aria-modal="false" aria-label="OCR 设置">' +
|
|
|
|
|
|
'<div class="mnote-settings-panel-head">' +
|
|
|
|
|
|
'<strong>OCR 设置</strong>' +
|
|
|
|
|
|
'<button type="button" class="mnote-settings-panel-close" data-settings-action="close" aria-label="关闭 OCR 设置">×</button>' +
|
|
|
|
|
|
'</div>' +
|
|
|
|
|
|
'<div class="wolai-page-settings-section">' +
|
|
|
|
|
|
createLocalOcrAutoRow() +
|
|
|
|
|
|
'<div class="wolai-page-settings-index-actions">' +
|
|
|
|
|
|
'<button type="button" data-local-ocr-settings-action="run-active">识别当前资源</button>' +
|
|
|
|
|
|
'<button type="button" data-local-ocr-settings-action="tasks">查看 OCR 任务</button>' +
|
|
|
|
|
|
'</div>' +
|
|
|
|
|
|
'</div>' +
|
|
|
|
|
|
'</div>';
|
|
|
|
|
|
document.body.appendChild(popover);
|
|
|
|
|
|
return popover;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-26 04:17:52 +08:00
|
|
|
|
function pageSettingsLocalIndexScopeKey() {
|
|
|
|
|
|
return [
|
|
|
|
|
|
currentSourceKind(),
|
|
|
|
|
|
currentRootUri(),
|
|
|
|
|
|
resolveWorkspaceId(document.body),
|
|
|
|
|
|
currentDocumentId()
|
|
|
|
|
|
].join('|');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function pageSettingsLocalIndexIsAvailable() {
|
2026-06-04 18:51:16 +08:00
|
|
|
|
return currentSourceKind() === 'local_folder' && Boolean(currentRootUri());
|
2026-05-26 04:17:52 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function pageSettingsLocalIndexEmpty(message) {
|
|
|
|
|
|
return '<div class="wolai-page-settings-index-empty">' + escapeHtml(message) + '</div>';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function renderPageSettingsLocalIndex(popover) {
|
2026-06-04 18:51:16 +08:00
|
|
|
|
popover = popover || ensureLocalIndexSettingsPopover();
|
2026-05-26 04:17:52 +08:00
|
|
|
|
var statusNode = popover.querySelector('[data-testid="wolai-page-settings-local-index-status"]');
|
2026-06-04 18:51:16 +08:00
|
|
|
|
var rangesNode = popover.querySelector('[data-testid="wolai-page-settings-local-index-ranges"]');
|
|
|
|
|
|
var scheduleModeNode = popover.querySelector('[data-testid="wolai-page-settings-local-index-schedule-mode"]');
|
|
|
|
|
|
var scheduleTimeNode = popover.querySelector('[data-testid="wolai-page-settings-local-index-schedule-time"]');
|
|
|
|
|
|
var scheduleDateNode = popover.querySelector('[data-testid="wolai-page-settings-local-index-schedule-date"]');
|
|
|
|
|
|
var runOnChangeNode = popover.querySelector('[data-testid="wolai-page-settings-local-index-run-on-change"]');
|
|
|
|
|
|
if (!(statusNode instanceof HTMLElement)) return;
|
2026-05-26 04:17:52 +08:00
|
|
|
|
|
|
|
|
|
|
if (!pageSettingsLocalIndexIsAvailable()) {
|
2026-06-04 18:51:16 +08:00
|
|
|
|
statusNode.textContent = '本地索引仅在本地工作区可用';
|
|
|
|
|
|
renderLocalIndexRangeRows(popover, [], 'fault', true, {});
|
|
|
|
|
|
setLocalIndexScheduleControlsDisabled(true);
|
2026-05-26 04:17:52 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var summary = pageUiState.localIndexSummary || {};
|
|
|
|
|
|
if (summary.loading) {
|
|
|
|
|
|
statusNode.textContent = '正在读取本地索引...';
|
2026-06-04 18:51:16 +08:00
|
|
|
|
renderLocalIndexRangeRows(popover, currentLocalIndexRangeValues(popover), 'indexing', true, summary.status || {});
|
|
|
|
|
|
setLocalIndexScheduleControlsDisabled(true);
|
2026-05-26 04:17:52 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (summary.error) {
|
|
|
|
|
|
statusNode.textContent = '本地索引读取失败';
|
2026-06-04 18:51:16 +08:00
|
|
|
|
renderLocalIndexRangeRows(popover, currentLocalIndexRangeValues(popover), 'fault', false, summary.status || {});
|
|
|
|
|
|
setLocalIndexScheduleControlsDisabled(false);
|
2026-05-26 04:17:52 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (summary.scopeKey !== pageSettingsLocalIndexScopeKey()) {
|
2026-06-04 18:51:16 +08:00
|
|
|
|
statusNode.textContent = '打开索引设置后读取本地索引';
|
|
|
|
|
|
renderLocalIndexRangeRows(popover, [], 'indexing', true, {});
|
|
|
|
|
|
setLocalIndexScheduleControlsDisabled(true);
|
2026-05-26 04:17:52 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-04 18:51:16 +08:00
|
|
|
|
var status = summary.status || {};
|
|
|
|
|
|
var settings = status.settings && typeof status.settings === 'object' ? status.settings : {};
|
|
|
|
|
|
var includePaths = Array.isArray(settings.includePaths) ? settings.includePaths : ['.'];
|
|
|
|
|
|
statusNode.textContent = '索引 ' + Number(status.documentCount || 0) + ' 个页面 / ' + Number(status.resourceCount || 0) + ' 个资源 / ' + Number(status.evidenceBlockCount || 0) + ' 个证据块' + (status.scheduledDue ? ',已到计划时间' : '');
|
|
|
|
|
|
if (!(rangesNode instanceof HTMLElement) || !rangesNode.contains(document.activeElement)) {
|
|
|
|
|
|
renderLocalIndexRangeRows(popover, includePaths, localIndexStatusKind(status), false, status);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (scheduleModeNode instanceof HTMLSelectElement && document.activeElement !== scheduleModeNode) {
|
|
|
|
|
|
scheduleModeNode.value = String(settings.scheduleMode || 'daily');
|
|
|
|
|
|
}
|
|
|
|
|
|
if (scheduleTimeNode instanceof HTMLInputElement && document.activeElement !== scheduleTimeNode) {
|
|
|
|
|
|
scheduleTimeNode.value = String(settings.scheduleTime || '02:00');
|
|
|
|
|
|
}
|
|
|
|
|
|
if (scheduleDateNode instanceof HTMLInputElement && document.activeElement !== scheduleDateNode) {
|
|
|
|
|
|
scheduleDateNode.value = String(settings.scheduleDate || '');
|
|
|
|
|
|
}
|
|
|
|
|
|
if (runOnChangeNode instanceof HTMLInputElement) {
|
|
|
|
|
|
runOnChangeNode.checked = settings.runOnChange === true;
|
|
|
|
|
|
}
|
|
|
|
|
|
setLocalIndexScheduleControlsDisabled(false);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function localIndexStatusKind(status) {
|
|
|
|
|
|
if (!status || typeof status !== 'object') return 'fault';
|
|
|
|
|
|
if (status.indexExists !== true) return 'fault';
|
|
|
|
|
|
if (status.cacheMatchesSettings === true && status.scheduledDue !== true) return 'indexed';
|
|
|
|
|
|
return 'indexing';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function localIndexStatusLabel(kind) {
|
|
|
|
|
|
if (kind === 'indexed') return '已索引';
|
|
|
|
|
|
if (kind === 'indexing') return '索引中';
|
|
|
|
|
|
return '索引故障';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function localIndexPathStatusKind(path, status, fallbackKind) {
|
|
|
|
|
|
if (fallbackKind === 'fault' || fallbackKind === 'indexing') return fallbackKind;
|
|
|
|
|
|
var indexedPaths = Array.isArray(status && status.indexedPaths) ? status.indexedPaths : [];
|
|
|
|
|
|
var normalizedPath = String(path || '').trim() || '.';
|
|
|
|
|
|
if (indexedPaths.indexOf(normalizedPath) >= 0 && status.cacheMatchesSettings === true) return 'indexed';
|
|
|
|
|
|
if (status.indexExists === true) return 'indexing';
|
|
|
|
|
|
return 'fault';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function renderLocalIndexRangeRows(popover, includePaths, fallbackKind, disabled, status) {
|
|
|
|
|
|
var rangesNode = popover.querySelector('[data-testid="wolai-page-settings-local-index-ranges"]');
|
|
|
|
|
|
if (!(rangesNode instanceof HTMLElement)) return;
|
|
|
|
|
|
var rawPaths = Array.isArray(includePaths) ? includePaths.map(function(value) {
|
|
|
|
|
|
return String(value || '').trim();
|
|
|
|
|
|
}) : [];
|
|
|
|
|
|
var paths = disabled ? rawPaths.filter(Boolean) : rawPaths;
|
|
|
|
|
|
if (!paths.length && !disabled) paths = ['.'];
|
|
|
|
|
|
rangesNode.innerHTML = paths.map(function(path, index) {
|
|
|
|
|
|
var kind = localIndexPathStatusKind(path, status || {}, fallbackKind || 'fault');
|
|
|
|
|
|
return '' +
|
|
|
|
|
|
'<div class="wolai-page-settings-index-range-row" data-local-index-range-row="true">' +
|
|
|
|
|
|
'<span class="wolai-page-settings-index-status-dot" data-index-status="' + kind + '" title="' + escapeHtml(localIndexStatusLabel(kind)) + '"></span>' +
|
|
|
|
|
|
'<input type="text" class="wolai-page-settings-index-path" data-local-index-range-input="true" value="' + escapeHtml(path) + '" spellcheck="false"' + (disabled ? ' disabled' : '') + ' />' +
|
|
|
|
|
|
'<button type="button" class="wolai-page-settings-index-remove" data-local-index-action="remove-path" data-local-index-path-index="' + String(index) + '"' + (disabled ? ' disabled' : '') + ' aria-label="删除索引范围">×</button>' +
|
|
|
|
|
|
'</div>';
|
|
|
|
|
|
}).join('');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function setLocalIndexScheduleControlsDisabled(disabled) {
|
|
|
|
|
|
var popover = ensureLocalIndexSettingsPopover();
|
|
|
|
|
|
[
|
|
|
|
|
|
'[data-testid="wolai-page-settings-local-index-schedule-mode"]',
|
|
|
|
|
|
'[data-testid="wolai-page-settings-local-index-schedule-time"]',
|
|
|
|
|
|
'[data-testid="wolai-page-settings-local-index-schedule-date"]',
|
|
|
|
|
|
'[data-testid="wolai-page-settings-local-index-run-on-change"]'
|
|
|
|
|
|
].forEach(function(selector) {
|
|
|
|
|
|
var node = popover.querySelector(selector);
|
|
|
|
|
|
if (node instanceof HTMLInputElement || node instanceof HTMLSelectElement) node.disabled = disabled;
|
|
|
|
|
|
});
|
2026-05-26 04:17:52 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async function loadPageSettingsLocalIndex(force) {
|
|
|
|
|
|
if (!pageSettingsLocalIndexIsAvailable()) {
|
|
|
|
|
|
renderPageSettingsLocalIndex();
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
var scopeKey = pageSettingsLocalIndexScopeKey();
|
|
|
|
|
|
var current = pageUiState.localIndexSummary || {};
|
|
|
|
|
|
if (!force && current.scopeKey === scopeKey && !current.error && !current.loading) {
|
|
|
|
|
|
renderPageSettingsLocalIndex();
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
pageUiState.localIndexSummary = {
|
|
|
|
|
|
scopeKey: scopeKey,
|
|
|
|
|
|
loading: true,
|
2026-06-04 18:51:16 +08:00
|
|
|
|
error: ''
|
2026-05-26 04:17:52 +08:00
|
|
|
|
};
|
|
|
|
|
|
renderPageSettingsLocalIndex();
|
|
|
|
|
|
try {
|
|
|
|
|
|
var baseParams = new URLSearchParams();
|
|
|
|
|
|
baseParams.set('workspaceId', resolveWorkspaceId(document.body));
|
|
|
|
|
|
baseParams.set('rootUri', currentRootUri());
|
2026-06-04 18:51:16 +08:00
|
|
|
|
var statusUrl = '/api/search/local-index/status?' + baseParams.toString();
|
|
|
|
|
|
var response = await fetch(statusUrl, { headers: { accept: 'application/json' } });
|
|
|
|
|
|
var statusPayload = await response.json().catch(function(){ return null; });
|
|
|
|
|
|
if (!response.ok || !statusPayload || statusPayload.ok !== true) {
|
|
|
|
|
|
throw new Error('status_' + response.status);
|
2026-05-26 04:17:52 +08:00
|
|
|
|
}
|
|
|
|
|
|
pageUiState.localIndexSummary = {
|
|
|
|
|
|
scopeKey: scopeKey,
|
|
|
|
|
|
loading: false,
|
|
|
|
|
|
error: '',
|
2026-06-04 18:51:16 +08:00
|
|
|
|
status: statusPayload.result || {}
|
2026-05-26 04:17:52 +08:00
|
|
|
|
};
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
pageUiState.localIndexSummary = {
|
|
|
|
|
|
scopeKey: scopeKey,
|
|
|
|
|
|
loading: false,
|
|
|
|
|
|
error: error instanceof Error ? error.message : String(error),
|
2026-06-04 18:51:16 +08:00
|
|
|
|
status: {}
|
2026-05-26 04:17:52 +08:00
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
renderPageSettingsLocalIndex();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-04 18:51:16 +08:00
|
|
|
|
function localIndexIncludePathsFromForm() {
|
|
|
|
|
|
var popover = ensureLocalIndexSettingsPopover();
|
|
|
|
|
|
var values = currentLocalIndexRangeValues(popover).map(function(value) {
|
|
|
|
|
|
return value.trim();
|
|
|
|
|
|
}).filter(Boolean);
|
|
|
|
|
|
return values.length ? values : ['.'];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function currentLocalIndexRangeValues(popover) {
|
|
|
|
|
|
var root = popover || ensureLocalIndexSettingsPopover();
|
|
|
|
|
|
return Array.from(root.querySelectorAll('[data-local-index-range-input]')).map(function(input) {
|
|
|
|
|
|
return input instanceof HTMLInputElement ? input.value : '';
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function localIndexSchedulePayloadFromForm() {
|
|
|
|
|
|
var popover = ensureLocalIndexSettingsPopover();
|
|
|
|
|
|
var modeNode = popover.querySelector('[data-testid="wolai-page-settings-local-index-schedule-mode"]');
|
|
|
|
|
|
var timeNode = popover.querySelector('[data-testid="wolai-page-settings-local-index-schedule-time"]');
|
|
|
|
|
|
var dateNode = popover.querySelector('[data-testid="wolai-page-settings-local-index-schedule-date"]');
|
|
|
|
|
|
var runOnChangeNode = popover.querySelector('[data-testid="wolai-page-settings-local-index-run-on-change"]');
|
|
|
|
|
|
return {
|
|
|
|
|
|
scheduleMode: modeNode instanceof HTMLSelectElement ? modeNode.value : 'daily',
|
|
|
|
|
|
scheduleTime: timeNode instanceof HTMLInputElement ? (timeNode.value || '02:00') : '02:00',
|
|
|
|
|
|
scheduleDate: dateNode instanceof HTMLInputElement ? dateNode.value : '',
|
|
|
|
|
|
runOnChange: runOnChangeNode instanceof HTMLInputElement ? runOnChangeNode.checked : false
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function addLocalIndexRange() {
|
|
|
|
|
|
var popover = ensureLocalIndexSettingsPopover();
|
|
|
|
|
|
var summary = pageUiState.localIndexSummary || {};
|
|
|
|
|
|
renderLocalIndexRangeRows(popover, currentLocalIndexRangeValues(popover).concat(['']), localIndexStatusKind(summary.status || {}), false, summary.status || {});
|
|
|
|
|
|
var inputs = Array.from(popover.querySelectorAll('[data-local-index-range-input]'));
|
|
|
|
|
|
var last = inputs[inputs.length - 1];
|
|
|
|
|
|
if (last instanceof HTMLInputElement) last.focus();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function removeLocalIndexRange(index) {
|
|
|
|
|
|
var popover = ensureLocalIndexSettingsPopover();
|
|
|
|
|
|
var summary = pageUiState.localIndexSummary || {};
|
|
|
|
|
|
var values = currentLocalIndexRangeValues(popover);
|
|
|
|
|
|
values.splice(Number(index || 0), 1);
|
|
|
|
|
|
if (!values.length) values = [''];
|
|
|
|
|
|
renderLocalIndexRangeRows(popover, values, localIndexStatusKind(summary.status || {}), false, summary.status || {});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async function persistLocalIndexSettings() {
|
|
|
|
|
|
if (!pageSettingsLocalIndexIsAvailable()) return;
|
|
|
|
|
|
pageUiState.localIndexSummary = Object.assign({}, pageUiState.localIndexSummary || {}, {
|
|
|
|
|
|
scopeKey: pageSettingsLocalIndexScopeKey(),
|
|
|
|
|
|
loading: true,
|
|
|
|
|
|
error: ''
|
|
|
|
|
|
});
|
|
|
|
|
|
renderPageSettingsLocalIndex();
|
|
|
|
|
|
try {
|
|
|
|
|
|
var response = await fetch('/api/search/local-index/settings', {
|
|
|
|
|
|
method: 'PUT',
|
|
|
|
|
|
headers: { 'content-type': 'application/json', accept: 'application/json' },
|
|
|
|
|
|
body: JSON.stringify(Object.assign({
|
|
|
|
|
|
workspaceId: resolveWorkspaceId(document.body),
|
|
|
|
|
|
rootUri: currentRootUri(),
|
|
|
|
|
|
includePaths: localIndexIncludePathsFromForm()
|
|
|
|
|
|
}, localIndexSchedulePayloadFromForm()))
|
|
|
|
|
|
});
|
|
|
|
|
|
var payload = await response.json().catch(function(){ return null; });
|
|
|
|
|
|
if (!response.ok || !payload || payload.ok !== true) {
|
|
|
|
|
|
throw new Error(payload && payload.error && payload.error.message ? payload.error.message : 'local_index_settings_' + response.status);
|
|
|
|
|
|
}
|
|
|
|
|
|
await loadPageSettingsLocalIndex(true);
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
pageUiState.localIndexSummary = Object.assign({}, pageUiState.localIndexSummary || {}, {
|
|
|
|
|
|
scopeKey: pageSettingsLocalIndexScopeKey(),
|
|
|
|
|
|
loading: false,
|
|
|
|
|
|
error: error instanceof Error ? error.message : String(error)
|
|
|
|
|
|
});
|
|
|
|
|
|
renderPageSettingsLocalIndex();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async function refreshLocalIndex() {
|
|
|
|
|
|
if (!pageSettingsLocalIndexIsAvailable()) return;
|
|
|
|
|
|
pageUiState.localIndexSummary = Object.assign({}, pageUiState.localIndexSummary || {}, {
|
|
|
|
|
|
scopeKey: pageSettingsLocalIndexScopeKey(),
|
|
|
|
|
|
loading: true,
|
|
|
|
|
|
error: ''
|
|
|
|
|
|
});
|
|
|
|
|
|
renderPageSettingsLocalIndex();
|
|
|
|
|
|
try {
|
|
|
|
|
|
var response = await fetch('/api/search/local-index/refresh', {
|
|
|
|
|
|
method: 'POST',
|
|
|
|
|
|
headers: { 'content-type': 'application/json', accept: 'application/json' },
|
|
|
|
|
|
body: JSON.stringify({
|
|
|
|
|
|
workspaceId: resolveWorkspaceId(document.body),
|
|
|
|
|
|
rootUri: currentRootUri()
|
|
|
|
|
|
})
|
|
|
|
|
|
});
|
|
|
|
|
|
var payload = await response.json().catch(function(){ return null; });
|
|
|
|
|
|
if (!response.ok || !payload || payload.ok !== true) {
|
|
|
|
|
|
throw new Error(payload && payload.error && payload.error.message ? payload.error.message : 'local_index_refresh_' + response.status);
|
|
|
|
|
|
}
|
|
|
|
|
|
await loadPageSettingsLocalIndex(true);
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
pageUiState.localIndexSummary = Object.assign({}, pageUiState.localIndexSummary || {}, {
|
|
|
|
|
|
scopeKey: pageSettingsLocalIndexScopeKey(),
|
|
|
|
|
|
loading: false,
|
|
|
|
|
|
error: error instanceof Error ? error.message : String(error)
|
|
|
|
|
|
});
|
|
|
|
|
|
renderPageSettingsLocalIndex();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-26 04:17:52 +08:00
|
|
|
|
function renderPageSettingsPopover() {
|
|
|
|
|
|
var popover = ensurePageSettingsPopover();
|
|
|
|
|
|
var options = currentPageOptions();
|
|
|
|
|
|
popover.querySelectorAll('[data-page-option-checkbox]').forEach(function(input) {
|
|
|
|
|
|
var key = input.getAttribute('data-page-option-checkbox');
|
|
|
|
|
|
input.checked = Boolean(options[key]);
|
|
|
|
|
|
input.disabled = !pageOptionIsSupported(key);
|
|
|
|
|
|
});
|
|
|
|
|
|
popover.querySelectorAll('[data-page-option-select]').forEach(function(select) {
|
|
|
|
|
|
var key = select.getAttribute('data-page-option-select');
|
|
|
|
|
|
var value = key === 'layoutDensity' ? String(options.layoutDensity || 'normal') : String(options.pageFont || 'default');
|
|
|
|
|
|
select.value = value;
|
|
|
|
|
|
});
|
|
|
|
|
|
renderGlobalOptions(popover);
|
|
|
|
|
|
var statsNode = popover.querySelector('[data-testid="wolai-page-settings-stats"]');
|
|
|
|
|
|
if (statsNode instanceof HTMLElement) {
|
|
|
|
|
|
var stats = computeLivePageStats();
|
|
|
|
|
|
statsNode.innerHTML = '' +
|
|
|
|
|
|
'<span>字数 ' + Number(stats.wordCount || 0) + '</span>' +
|
|
|
|
|
|
'<span>字符 ' + Number(stats.characterCount || 0) + '</span>' +
|
|
|
|
|
|
'<span>块数 ' + Number(stats.blockCount || 0) + '</span>' +
|
|
|
|
|
|
'<span>待办 ' + Number(stats.todoDone || 0) + '/' + Number(stats.todoTotal || 0) + '</span>';
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function setActivePageSettingsTab(tabName) {
|
|
|
|
|
|
var popover = ensurePageSettingsPopover();
|
|
|
|
|
|
popover.querySelectorAll('[data-page-settings-tab]').forEach(function(tab) {
|
|
|
|
|
|
var active = tab.getAttribute('data-page-settings-tab') === tabName;
|
|
|
|
|
|
tab.classList.toggle('is-active', active);
|
|
|
|
|
|
tab.setAttribute('aria-selected', active ? 'true' : 'false');
|
|
|
|
|
|
});
|
|
|
|
|
|
popover.querySelectorAll('[data-page-settings-panel]').forEach(function(panel) {
|
|
|
|
|
|
panel.hidden = panel.getAttribute('data-page-settings-panel') !== tabName;
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async function persistPageOptionsPatch(patch) {
|
|
|
|
|
|
var previous = Object.assign({}, currentPageOptions());
|
|
|
|
|
|
pageUiState.pageOptions = Object.assign({}, previous, patch);
|
|
|
|
|
|
var nextOptions = Object.assign({}, pageUiState.pageOptions);
|
|
|
|
|
|
applyPageOptionsToShell();
|
|
|
|
|
|
renderPageSettingsPopover();
|
|
|
|
|
|
try {
|
2026-05-27 11:31:12 +08:00
|
|
|
|
var response = await fetch('/api/ui/preferences', {
|
|
|
|
|
|
method: 'PUT',
|
2026-05-26 04:17:52 +08:00
|
|
|
|
headers: { 'content-type': 'application/json' },
|
|
|
|
|
|
body: JSON.stringify({
|
|
|
|
|
|
documentId: currentDocumentId(),
|
|
|
|
|
|
workspaceId: resolveWorkspaceId(document.body),
|
|
|
|
|
|
...currentWorkspaceSourcePayload(),
|
2026-05-27 11:31:12 +08:00
|
|
|
|
updates: nextOptions
|
2026-05-26 04:17:52 +08:00
|
|
|
|
})
|
|
|
|
|
|
});
|
|
|
|
|
|
var payload = await response.json().catch(function(){ return null; });
|
|
|
|
|
|
if (!response.ok || !payload || payload.ok !== true) {
|
|
|
|
|
|
throw new Error(payload && payload.error && payload.error.message ? payload.error.message : 'page_settings_save_failed_' + response.status);
|
|
|
|
|
|
}
|
2026-05-27 11:31:12 +08:00
|
|
|
|
var savedOptions = payload && payload.result && payload.result.pageOptions && typeof payload.result.pageOptions === 'object'
|
|
|
|
|
|
? Object.assign(defaultPageOptions(), payload.result.pageOptions)
|
|
|
|
|
|
: nextOptions;
|
|
|
|
|
|
pageUiState.pageOptions = Object.assign({}, savedOptions);
|
|
|
|
|
|
nextOptions = Object.assign({}, pageUiState.pageOptions);
|
|
|
|
|
|
applyPageOptionsToShell();
|
|
|
|
|
|
renderPageSettingsPopover();
|
2026-05-26 16:47:03 +08:00
|
|
|
|
var script = document.getElementById('__MNOTE_PAGE_AGGREGATE__');
|
|
|
|
|
|
if (script) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
var aggregate = JSON.parse(script.textContent || 'null');
|
|
|
|
|
|
if (aggregate && typeof aggregate === 'object') {
|
|
|
|
|
|
aggregate.layout = aggregate.layout && typeof aggregate.layout === 'object' ? aggregate.layout : {};
|
|
|
|
|
|
aggregate.layout.pageOptions = Object.assign({}, nextOptions);
|
|
|
|
|
|
aggregate.layout_options = Object.assign({}, nextOptions);
|
|
|
|
|
|
script.textContent = JSON.stringify(aggregate);
|
|
|
|
|
|
script.setAttribute('data-mnote-page-options-synced-at', String(Date.now()));
|
2026-05-26 17:24:05 +08:00
|
|
|
|
script.setAttribute('data-mnote-page-options-local-write-at', String(Date.now()));
|
2026-05-26 16:47:03 +08:00
|
|
|
|
}
|
|
|
|
|
|
} catch (_) {}
|
|
|
|
|
|
}
|
2026-05-26 04:17:52 +08:00
|
|
|
|
document.documentElement.setAttribute('data-mnote-page-options-saved', 'true');
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
pageUiState.pageOptions = previous;
|
|
|
|
|
|
applyPageOptionsToShell();
|
|
|
|
|
|
renderPageSettingsPopover();
|
|
|
|
|
|
document.documentElement.setAttribute('data-mnote-page-options-error', error instanceof Error ? error.message : String(error));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-28 22:01:44 +08:00
|
|
|
|
async function loadPageWidthPreferences() {
|
|
|
|
|
|
var params = new URLSearchParams();
|
2026-06-04 18:51:16 +08:00
|
|
|
|
if (currentDocumentId()) params.set('documentId', currentDocumentId());
|
2026-05-28 22:01:44 +08:00
|
|
|
|
params.set('workspaceId', resolveWorkspaceId(document.body));
|
|
|
|
|
|
var sourcePayload = currentWorkspaceSourcePayload();
|
|
|
|
|
|
Object.keys(sourcePayload || {}).forEach(function(key) {
|
|
|
|
|
|
if (sourcePayload[key] != null && sourcePayload[key] !== '') params.set(key, sourcePayload[key]);
|
|
|
|
|
|
});
|
|
|
|
|
|
try {
|
|
|
|
|
|
var response = await fetch('/api/ui/preferences/effective?' + params.toString(), {
|
|
|
|
|
|
headers: { accept: 'application/json' }
|
|
|
|
|
|
});
|
|
|
|
|
|
var payload = await response.json().catch(function(){ return null; });
|
|
|
|
|
|
if (!response.ok || !payload || payload.ok !== true) return;
|
|
|
|
|
|
pageUiState.pageWidthPreferences = normalizePageWidthPreferences(payload.result && payload.result.pageWidthPreferences);
|
2026-06-02 17:17:49 +08:00
|
|
|
|
pageUiState.localOcrPreferences = Object.assign({ 'localOcr.autoEnabled': false }, payload.result && payload.result.localOcrPreferences || {});
|
|
|
|
|
|
window.__MNOTE_LOCAL_OCR_PREFERENCES = Object.assign({}, pageUiState.localOcrPreferences);
|
|
|
|
|
|
document.documentElement.setAttribute('data-mnote-local-ocr-auto-enabled', String(pageUiState.localOcrPreferences['localOcr.autoEnabled'] === true));
|
2026-05-28 22:01:44 +08:00
|
|
|
|
applyPageOptionsToShell();
|
|
|
|
|
|
if (isPageSettingsOpen()) renderPageSettingsPopover();
|
2026-06-04 18:51:16 +08:00
|
|
|
|
if (isLocalOcrSettingsOpen()) renderLocalOcrOptions(ensureLocalOcrSettingsPopover());
|
2026-05-28 22:01:44 +08:00
|
|
|
|
} catch (_) {}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-02 17:17:49 +08:00
|
|
|
|
async function persistLocalOcrAutoPreference(enabled) {
|
|
|
|
|
|
var previous = currentLocalOcrPreferences();
|
|
|
|
|
|
var next = Object.assign({}, previous, { 'localOcr.autoEnabled': Boolean(enabled) });
|
|
|
|
|
|
pageUiState.localOcrPreferences = next;
|
|
|
|
|
|
window.__MNOTE_LOCAL_OCR_PREFERENCES = Object.assign({}, next);
|
2026-06-04 18:51:16 +08:00
|
|
|
|
if (isPageSettingsOpen()) renderPageSettingsPopover();
|
|
|
|
|
|
if (isLocalOcrSettingsOpen()) renderLocalOcrOptions(ensureLocalOcrSettingsPopover());
|
2026-06-02 17:17:49 +08:00
|
|
|
|
try {
|
|
|
|
|
|
var response = await fetch('/api/ui/preferences', {
|
|
|
|
|
|
method: 'PUT',
|
|
|
|
|
|
headers: { 'content-type': 'application/json' },
|
|
|
|
|
|
body: JSON.stringify({
|
|
|
|
|
|
documentId: currentDocumentId(),
|
|
|
|
|
|
workspaceId: resolveWorkspaceId(document.body),
|
|
|
|
|
|
...currentWorkspaceSourcePayload(),
|
|
|
|
|
|
updates: { 'localOcr.autoEnabled': Boolean(enabled) }
|
|
|
|
|
|
})
|
|
|
|
|
|
});
|
|
|
|
|
|
var payload = await response.json().catch(function(){ return null; });
|
|
|
|
|
|
if (!response.ok || !payload || payload.ok !== true) {
|
|
|
|
|
|
throw new Error(payload && payload.error && payload.error.message ? payload.error.message : 'local_ocr_preference_save_failed_' + response.status);
|
|
|
|
|
|
}
|
|
|
|
|
|
pageUiState.localOcrPreferences = Object.assign({ 'localOcr.autoEnabled': false }, payload.result && payload.result.localOcrPreferences || {});
|
|
|
|
|
|
window.__MNOTE_LOCAL_OCR_PREFERENCES = Object.assign({}, pageUiState.localOcrPreferences);
|
|
|
|
|
|
document.documentElement.setAttribute('data-mnote-local-ocr-auto-enabled', String(pageUiState.localOcrPreferences['localOcr.autoEnabled'] === true));
|
2026-06-04 18:51:16 +08:00
|
|
|
|
if (isPageSettingsOpen()) renderPageSettingsPopover();
|
|
|
|
|
|
if (isLocalOcrSettingsOpen()) renderLocalOcrOptions(ensureLocalOcrSettingsPopover());
|
2026-06-02 17:17:49 +08:00
|
|
|
|
} catch (error) {
|
|
|
|
|
|
pageUiState.localOcrPreferences = previous;
|
|
|
|
|
|
window.__MNOTE_LOCAL_OCR_PREFERENCES = Object.assign({}, previous);
|
2026-06-04 18:51:16 +08:00
|
|
|
|
if (isPageSettingsOpen()) renderPageSettingsPopover();
|
|
|
|
|
|
if (isLocalOcrSettingsOpen()) renderLocalOcrOptions(ensureLocalOcrSettingsPopover());
|
2026-06-02 17:17:49 +08:00
|
|
|
|
document.documentElement.setAttribute('data-mnote-local-ocr-preference-error', error instanceof Error ? error.message : String(error));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-28 22:01:44 +08:00
|
|
|
|
async function persistPageWidthPreference(type, mode) {
|
|
|
|
|
|
if (PAGE_WIDTH_TYPES.indexOf(type) < 0) return;
|
|
|
|
|
|
var previous = pageUiState.pageWidthPreferences;
|
|
|
|
|
|
var next = normalizePageWidthPreferences(previous);
|
|
|
|
|
|
next[type] = Object.assign({}, next[type], {
|
|
|
|
|
|
mode: mode,
|
|
|
|
|
|
resolvedMode: mode === 'inherit' ? next.default.resolvedMode : mode,
|
|
|
|
|
|
cssMaxWidth: pageWidthCssMaxWidth(mode === 'inherit' ? next.default.resolvedMode : mode),
|
|
|
|
|
|
source: 'optimistic'
|
|
|
|
|
|
});
|
|
|
|
|
|
pageUiState.pageWidthPreferences = next;
|
|
|
|
|
|
applyPageOptionsToShell();
|
|
|
|
|
|
renderPageSettingsPopover();
|
|
|
|
|
|
notifyPageWidthPreferenceChanged(type);
|
|
|
|
|
|
try {
|
|
|
|
|
|
var updates = {};
|
|
|
|
|
|
updates['pageWidth.' + type] = { mode: mode, custom: null };
|
|
|
|
|
|
var response = await fetch('/api/ui/preferences', {
|
|
|
|
|
|
method: 'PUT',
|
|
|
|
|
|
headers: { 'content-type': 'application/json' },
|
|
|
|
|
|
body: JSON.stringify({
|
|
|
|
|
|
documentId: currentDocumentId(),
|
|
|
|
|
|
workspaceId: resolveWorkspaceId(document.body),
|
|
|
|
|
|
...currentWorkspaceSourcePayload(),
|
|
|
|
|
|
updates: updates
|
|
|
|
|
|
})
|
|
|
|
|
|
});
|
|
|
|
|
|
var payload = await response.json().catch(function(){ return null; });
|
|
|
|
|
|
if (!response.ok || !payload || payload.ok !== true) {
|
|
|
|
|
|
throw new Error(payload && payload.error && payload.error.message ? payload.error.message : 'page_width_save_failed_' + response.status);
|
|
|
|
|
|
}
|
|
|
|
|
|
pageUiState.pageWidthPreferences = normalizePageWidthPreferences(payload.result && payload.result.pageWidthPreferences);
|
|
|
|
|
|
applyPageOptionsToShell();
|
|
|
|
|
|
renderPageSettingsPopover();
|
|
|
|
|
|
notifyPageWidthPreferenceChanged(type);
|
|
|
|
|
|
document.documentElement.setAttribute('data-mnote-page-width-saved', 'true');
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
pageUiState.pageWidthPreferences = previous;
|
|
|
|
|
|
applyPageOptionsToShell();
|
|
|
|
|
|
renderPageSettingsPopover();
|
|
|
|
|
|
document.documentElement.setAttribute('data-mnote-page-width-error', error instanceof Error ? error.message : String(error));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-26 04:17:52 +08:00
|
|
|
|
function isPageSettingsOpen() {
|
|
|
|
|
|
var popover = document.querySelector('[data-testid="wolai-page-settings-popover"]');
|
|
|
|
|
|
return popover instanceof HTMLElement && !popover.hidden;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-04 18:51:16 +08:00
|
|
|
|
function isLocalIndexSettingsOpen() {
|
|
|
|
|
|
var popover = document.querySelector('[data-testid="mnote-local-index-settings-popover"]');
|
|
|
|
|
|
return popover instanceof HTMLElement && !popover.hidden;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function isLocalOcrSettingsOpen() {
|
|
|
|
|
|
var popover = document.querySelector('[data-testid="mnote-local-ocr-settings-popover"]');
|
|
|
|
|
|
return popover instanceof HTMLElement && !popover.hidden;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function isAnySettingsOpen() {
|
|
|
|
|
|
return isPageSettingsOpen() || isLocalIndexSettingsOpen() || isLocalOcrSettingsOpen();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function openPageSettingsPopover(initialTab) {
|
2026-05-26 04:17:52 +08:00
|
|
|
|
if (!currentDocumentId()) return;
|
2026-06-04 18:51:16 +08:00
|
|
|
|
closeLocalIndexSettingsPopover();
|
|
|
|
|
|
closeLocalOcrSettingsPopover();
|
2026-05-26 04:17:52 +08:00
|
|
|
|
var popover = ensurePageSettingsPopover();
|
|
|
|
|
|
renderPageSettingsPopover();
|
2026-06-04 18:51:16 +08:00
|
|
|
|
setActivePageSettingsTab(initialTab || 'page');
|
2026-05-26 04:17:52 +08:00
|
|
|
|
popover.hidden = false;
|
|
|
|
|
|
pageUiState.pageSettingsOpen = true;
|
|
|
|
|
|
updatePageSettingsTriggerState();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-04 18:51:16 +08:00
|
|
|
|
function openPageIndexSettingsPopover() {
|
|
|
|
|
|
closePageSettingsPopover();
|
|
|
|
|
|
closeLocalOcrSettingsPopover();
|
|
|
|
|
|
var popover = ensureLocalIndexSettingsPopover();
|
|
|
|
|
|
renderPageSettingsLocalIndex(popover);
|
|
|
|
|
|
popover.hidden = false;
|
|
|
|
|
|
void loadPageSettingsLocalIndex(false);
|
|
|
|
|
|
updateStandaloneSettingsTriggerState();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function openLocalOcrSettingsPopover() {
|
|
|
|
|
|
closePageSettingsPopover();
|
|
|
|
|
|
closeLocalIndexSettingsPopover();
|
|
|
|
|
|
var popover = ensureLocalOcrSettingsPopover();
|
|
|
|
|
|
renderLocalOcrOptions(popover);
|
|
|
|
|
|
popover.hidden = false;
|
|
|
|
|
|
updateStandaloneSettingsTriggerState();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-26 04:17:52 +08:00
|
|
|
|
function closePageSettingsPopover() {
|
|
|
|
|
|
var popover = document.querySelector('[data-testid="wolai-page-settings-popover"]');
|
|
|
|
|
|
if (popover instanceof HTMLElement) popover.hidden = true;
|
|
|
|
|
|
pageUiState.pageSettingsOpen = false;
|
|
|
|
|
|
updatePageSettingsTriggerState();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-04 18:51:16 +08:00
|
|
|
|
function closeLocalIndexSettingsPopover() {
|
|
|
|
|
|
var popover = document.querySelector('[data-testid="mnote-local-index-settings-popover"]');
|
|
|
|
|
|
if (popover instanceof HTMLElement) popover.hidden = true;
|
|
|
|
|
|
updateStandaloneSettingsTriggerState();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function closeLocalOcrSettingsPopover() {
|
|
|
|
|
|
var popover = document.querySelector('[data-testid="mnote-local-ocr-settings-popover"]');
|
|
|
|
|
|
if (popover instanceof HTMLElement) popover.hidden = true;
|
|
|
|
|
|
updateStandaloneSettingsTriggerState();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function closeAllSettingsPopovers() {
|
|
|
|
|
|
closePageSettingsPopover();
|
|
|
|
|
|
closeLocalIndexSettingsPopover();
|
|
|
|
|
|
closeLocalOcrSettingsPopover();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-26 04:17:52 +08:00
|
|
|
|
function togglePageSettingsPopover() {
|
|
|
|
|
|
if (isPageSettingsOpen()) closePageSettingsPopover();
|
|
|
|
|
|
else openPageSettingsPopover();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-28 22:01:44 +08:00
|
|
|
|
window.addEventListener('mnote:active-resource-tab-changed', function() {
|
|
|
|
|
|
applyPageOptionsToShell();
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2026-06-04 18:51:16 +08:00
|
|
|
|
window.addEventListener('mnote:open-local-ocr-settings', function() {
|
|
|
|
|
|
openLocalOcrSettingsPopover();
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2026-05-26 04:17:52 +08:00
|
|
|
|
return {
|
2026-06-04 18:51:16 +08:00
|
|
|
|
addLocalIndexRange,
|
2026-05-26 04:17:52 +08:00
|
|
|
|
applyPageOptionsToShell,
|
2026-06-04 18:51:16 +08:00
|
|
|
|
closeAllSettingsPopovers,
|
2026-05-26 04:17:52 +08:00
|
|
|
|
closePageHistoryDrawer,
|
2026-06-04 18:51:16 +08:00
|
|
|
|
closeLocalIndexSettingsPopover,
|
|
|
|
|
|
closeLocalOcrSettingsPopover,
|
2026-05-26 04:17:52 +08:00
|
|
|
|
closePageSettingsPopover,
|
|
|
|
|
|
closePageShareDialog,
|
2026-06-02 17:17:49 +08:00
|
|
|
|
currentLocalOcrPreferences,
|
2026-05-26 04:17:52 +08:00
|
|
|
|
currentPageOptions,
|
|
|
|
|
|
ensureHistorySnapshotsSeeded,
|
2026-06-04 18:51:16 +08:00
|
|
|
|
ensureLocalIndexSettingsPopover,
|
|
|
|
|
|
ensureLocalOcrSettingsPopover,
|
2026-05-26 04:17:52 +08:00
|
|
|
|
ensurePageHistoryDrawer,
|
|
|
|
|
|
ensurePageSettingsPopover,
|
|
|
|
|
|
ensurePageShareDialog,
|
2026-06-04 18:51:16 +08:00
|
|
|
|
isAnySettingsOpen,
|
|
|
|
|
|
isLocalIndexSettingsOpen,
|
|
|
|
|
|
isLocalOcrSettingsOpen,
|
2026-05-26 04:17:52 +08:00
|
|
|
|
isPageSettingsOpen,
|
|
|
|
|
|
openPageHistoryDrawer,
|
2026-06-04 18:51:16 +08:00
|
|
|
|
openLocalOcrSettingsPopover,
|
2026-05-26 04:17:52 +08:00
|
|
|
|
openPageSettingsPopover,
|
2026-06-04 18:51:16 +08:00
|
|
|
|
openPageIndexSettingsPopover,
|
2026-05-26 04:17:52 +08:00
|
|
|
|
openPageShareDialog,
|
|
|
|
|
|
pageOptionIsSupported,
|
2026-06-02 17:17:49 +08:00
|
|
|
|
persistLocalOcrAutoPreference,
|
2026-06-04 18:51:16 +08:00
|
|
|
|
persistLocalIndexSettings,
|
2026-05-26 04:17:52 +08:00
|
|
|
|
persistPageOptionsPatch,
|
2026-05-28 22:01:44 +08:00
|
|
|
|
persistPageWidthPreference,
|
2026-05-26 04:17:52 +08:00
|
|
|
|
recordPageHistorySnapshot,
|
2026-06-04 18:51:16 +08:00
|
|
|
|
removeLocalIndexRange,
|
2026-05-26 04:17:52 +08:00
|
|
|
|
renderPageSettingsPopover,
|
|
|
|
|
|
setActivePageSettingsTab,
|
2026-06-04 18:51:16 +08:00
|
|
|
|
refreshLocalIndex,
|
2026-05-26 04:17:52 +08:00
|
|
|
|
togglePageSettingsPopover,
|
|
|
|
|
|
updatePageSettingsTriggerState,
|
|
|
|
|
|
writeGlobalShowHeadingNumbers,
|
2026-05-28 22:01:44 +08:00
|
|
|
|
loadPageWidthPreferences,
|
2026-05-26 04:17:52 +08:00
|
|
|
|
};
|
|
|
|
|
|
}
|