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'; 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' } }; 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; } function currentPageWidthPreferences() { return Object.assign({}, DEFAULT_PAGE_WIDTH_PREFERENCES, pageUiState.pageWidthPreferences || {}); } function currentLocalOcrPreferences() { return Object.assign({ 'localOcr.autoEnabled': false }, pageUiState.localOcrPreferences || {}); } 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 (_) {} }); } function readGlobalShowHeadingNumbers() { return Boolean(currentPageOptions().showHeadingNumbers); } function writeGlobalShowHeadingNumbers(value) { void persistPageOptionsPatch({ showHeadingNumbers: Boolean(value) }); } function effectiveShowHeadingNumbers(options) { return Boolean(options && options.showHeadingNumbers); } 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(); var globalShowHeadingNumbers = Boolean(options.showHeadingNumbers); 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'); var mindmapWidthPreference = currentPageWidthPreferences().mindmap || DEFAULT_PAGE_WIDTH_PREFERENCES.mindmap; var mindmapMaxWidth = String(mindmapWidthPreference.cssMaxWidth || pageWidthCssMaxWidth(mindmapWidthPreference.resolvedMode)); var mindmapMaxWidthValue = mindmapMaxWidth === 'none' ? 'none' : mindmapMaxWidth; if (shell instanceof HTMLElement) { var widthPreference = activeResourceWidthPreference(options); var cssMaxWidth = String(widthPreference.cssMaxWidth || pageWidthCssMaxWidth(widthPreference.resolvedMode)); shell.setAttribute('data-page-wide-layout', String(Boolean(options.wideLayout))); 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')); 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%'; shell.style.maxWidth = cssMaxWidth === 'none' ? 'none' : cssMaxWidth; shell.style.setProperty('--mnote-mindmap-block-max-width', mindmapMaxWidthValue); } 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)); editorRoot.style.setProperty('--mnote-mindmap-block-max-width', mindmapMaxWidthValue); } 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))); 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')); 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))); document.documentElement.style.setProperty('--mnote-mindmap-block-max-width', mindmapMaxWidthValue); 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'); } 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'); } } function createPageOptionRow(key, type) { var inputType = type || 'checkbox'; var supported = pageOptionIsSupported(key); if (inputType === 'checkbox') { return '' + ''; } return '' + ''; } function createGlobalHeadingNumbersRow() { return '' + ''; } function createLocalOcrAutoRow() { return '' + ''; } function createPageWidthSelectRow(type) { var options = type === 'default' ? [ ['readable', '阅读'], ['comfortable', '舒适'], ['wide', '宽版'], ['full', '全宽'] ] : [ ['inherit', '继承默认'], ['readable', '阅读'], ['comfortable', '舒适'], ['wide', '宽版'], ['full', '全宽'] ]; return '' + ''; } function createPageWidthRows() { return '' + '
页面宽度
' + PAGE_WIDTH_TYPES.map(createPageWidthSelectRow).join(''); } function renderGlobalOptions(popover) { var globalHeadingNumbers = readGlobalShowHeadingNumbers(); popover.querySelectorAll('[data-global-option-checkbox="showHeadingNumbers"]').forEach(function(input) { input.checked = globalHeadingNumbers; }); 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)); }); } function renderLocalOcrOptions(popover) { var localOcrPreferences = currentLocalOcrPreferences(); popover.querySelectorAll('[data-local-ocr-option-checkbox="autoEnabled"]').forEach(function(input) { input.checked = localOcrPreferences['localOcr.autoEnabled'] === true; }); } function createPageFontRow() { return '' + ''; } 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 = '' + '
' + '
' + '
页面历史
当前会话内最近保存的 15 个快照。
' + '' + '
' + '
' + '
'; 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 '' + '
' + '
' + '
' + escapeHtml(label) + '
' + '
字数 ' + Number(stats.wordCount || 0) + ' · 字符 ' + Number(stats.characterCount || 0) + ' · 块数 ' + Number(stats.blockCount || 0) + '
' + '
' + '' + '
'; }).join('') : '
尚未产生历史快照,编辑后会自动生成。
'; } 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 = '' + ''; 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 = '' + ''; document.body.appendChild(popover); return popover; } function createLocalIndexSettingsPanelHtml() { return '' + ''; } 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 = '' + ''; document.body.appendChild(popover); return popover; } function pageSettingsLocalIndexScopeKey() { return [ currentSourceKind(), currentRootUri(), resolveWorkspaceId(document.body), currentDocumentId() ].join('|'); } function pageSettingsLocalIndexIsAvailable() { return currentSourceKind() === 'local_folder' && Boolean(currentRootUri()); } function pageSettingsLocalIndexEmpty(message) { return '
' + escapeHtml(message) + '
'; } function renderPageSettingsLocalIndex(popover) { popover = popover || ensureLocalIndexSettingsPopover(); var statusNode = popover.querySelector('[data-testid="wolai-page-settings-local-index-status"]'); 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; if (!pageSettingsLocalIndexIsAvailable()) { statusNode.textContent = '本地索引仅在本地工作区可用'; renderLocalIndexRangeRows(popover, [], 'fault', true, {}); setLocalIndexScheduleControlsDisabled(true); return; } var summary = pageUiState.localIndexSummary || {}; if (summary.loading) { statusNode.textContent = '正在读取本地索引...'; renderLocalIndexRangeRows(popover, currentLocalIndexRangeValues(popover), 'indexing', true, summary.status || {}); setLocalIndexScheduleControlsDisabled(true); return; } if (summary.error) { statusNode.textContent = '本地索引读取失败'; renderLocalIndexRangeRows(popover, currentLocalIndexRangeValues(popover), 'fault', false, summary.status || {}); setLocalIndexScheduleControlsDisabled(false); return; } if (summary.scopeKey !== pageSettingsLocalIndexScopeKey()) { statusNode.textContent = '打开索引设置后读取本地索引'; renderLocalIndexRangeRows(popover, [], 'indexing', true, {}); setLocalIndexScheduleControlsDisabled(true); return; } var status = summary.status || {}; var settings = status.settings && typeof status.settings === 'object' ? status.settings : {}; var savedIncludePaths = Array.isArray(settings.includePaths) ? settings.includePaths : []; var indexedPaths = Array.isArray(status.indexedPaths) ? status.indexedPaths : []; var includePaths = savedIncludePaths.length ? savedIncludePaths : indexedPaths; var hasIndexCache = status.indexExists === true || status.evidenceIndexExists === true; if (!savedIncludePaths.length && !hasIndexCache) { statusNode.textContent = '未设置索引范围'; } else { 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'; var settings = status.settings && typeof status.settings === 'object' ? status.settings : {}; var includePaths = Array.isArray(settings.includePaths) ? settings.includePaths : []; if (!includePaths.length && status.indexExists !== true && status.evidenceIndexExists !== true) return 'indexed'; 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) { var indexedPaths = Array.isArray(status && status.indexedPaths) ? status.indexedPaths : []; var normalizedPath = String(path || '').trim() || '.'; if (indexedPaths.indexOf(normalizedPath) >= 0 && status.indexExists === true) return 'indexed'; if (fallbackKind === 'fault' || fallbackKind === 'indexing') return fallbackKind; 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; var savedPaths = Array.isArray(status && status.settings && status.settings.includePaths) ? status.settings.includePaths.map(function(value) { return String(value || '').trim(); }).filter(Boolean) : []; var indexedPaths = Array.isArray(status && status.indexedPaths) ? status.indexedPaths.map(function(value) { return String(value || '').trim(); }).filter(Boolean) : []; rangesNode.innerHTML = paths.map(function(path, index) { var isPersisted = savedPaths.indexOf(path) >= 0 || indexedPaths.indexOf(path) >= 0; var inputDisabled = disabled || isPersisted; var kind = localIndexPathStatusKind(path, status || {}, fallbackKind || 'fault'); var normalizedPath = String(path || '').trim() || '.'; var displayPath = inputDisabled && normalizedPath === '.' ? '工作区根目录(全部)' : path; var rootScopeHint = normalizedPath === '.' ? '当前工作区全部' : ''; return '' + '
' + '' + '' + rootScopeHint + '' + '
'; }).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; }); } 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, error: '' }; renderPageSettingsLocalIndex(); try { var baseParams = new URLSearchParams(); baseParams.set('workspaceId', resolveWorkspaceId(document.body)); baseParams.set('rootUri', currentRootUri()); 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); } pageUiState.localIndexSummary = { scopeKey: scopeKey, loading: false, error: '', status: statusPayload.result || {} }; } catch (error) { pageUiState.localIndexSummary = { scopeKey: scopeKey, loading: false, error: error instanceof Error ? error.message : String(error), status: {} }; } renderPageSettingsLocalIndex(); } function localIndexIncludePathsFromForm() { var popover = ensureLocalIndexSettingsPopover(); return currentLocalIndexRangeValues(popover).map(function(value) { return value.trim(); }).filter(Boolean); } function currentLocalIndexRangeValues(popover) { var root = popover || ensureLocalIndexSettingsPopover(); return Array.from(root.querySelectorAll('[data-local-index-range-input]')).map(function(input) { if (!(input instanceof HTMLInputElement)) return ''; if (input.disabled && input.dataset.localIndexValue) return input.dataset.localIndexValue; return 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); 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(); } } function emitLocalIndexBackgroundTask(status, label, error) { var now = Date.now(); window.dispatchEvent(new CustomEvent('mnote:local-background-task-updated', { detail: { task: { taskKind: 'local_index', taskId: 'local-index', sourceRootRelativePath: '本地索引', rootUri: currentRootUri(), status: status, stageLabel: label, updatedAtMs: now, finishedAtMs: status === 'running' ? null : now, error: error || null } } })); } async function refreshLocalIndex() { if (!pageSettingsLocalIndexIsAvailable()) return; emitLocalIndexBackgroundTask('running', '本地索引重建中', null); 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); } emitLocalIndexBackgroundTask('done', '本地索引已完成', null); await loadPageSettingsLocalIndex(true); } catch (error) { emitLocalIndexBackgroundTask('failed', '本地索引失败', error instanceof Error ? error.message : String(error)); pageUiState.localIndexSummary = Object.assign({}, pageUiState.localIndexSummary || {}, { scopeKey: pageSettingsLocalIndexScopeKey(), loading: false, error: error instanceof Error ? error.message : String(error) }); renderPageSettingsLocalIndex(); } } 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 = '' + '字数 ' + Number(stats.wordCount || 0) + '' + '字符 ' + Number(stats.characterCount || 0) + '' + '块数 ' + Number(stats.blockCount || 0) + '' + '待办 ' + Number(stats.todoDone || 0) + '/' + Number(stats.todoTotal || 0) + ''; } } 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 { 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: nextOptions }) }); 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); } 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(); 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())); script.setAttribute('data-mnote-page-options-local-write-at', String(Date.now())); } } catch (_) {} } 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)); } } async function loadPageWidthPreferences() { var params = new URLSearchParams(); if (currentDocumentId()) params.set('documentId', currentDocumentId()); 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); 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)); applyPageOptionsToShell(); if (isPageSettingsOpen()) renderPageSettingsPopover(); if (isLocalOcrSettingsOpen()) renderLocalOcrOptions(ensureLocalOcrSettingsPopover()); } catch (_) {} } 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); if (isPageSettingsOpen()) renderPageSettingsPopover(); if (isLocalOcrSettingsOpen()) renderLocalOcrOptions(ensureLocalOcrSettingsPopover()); 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)); if (isPageSettingsOpen()) renderPageSettingsPopover(); if (isLocalOcrSettingsOpen()) renderLocalOcrOptions(ensureLocalOcrSettingsPopover()); } catch (error) { pageUiState.localOcrPreferences = previous; window.__MNOTE_LOCAL_OCR_PREFERENCES = Object.assign({}, previous); if (isPageSettingsOpen()) renderPageSettingsPopover(); if (isLocalOcrSettingsOpen()) renderLocalOcrOptions(ensureLocalOcrSettingsPopover()); document.documentElement.setAttribute('data-mnote-local-ocr-preference-error', error instanceof Error ? error.message : String(error)); } } 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)); } } function isPageSettingsOpen() { var popover = document.querySelector('[data-testid="wolai-page-settings-popover"]'); return popover instanceof HTMLElement && !popover.hidden; } 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) { if (!currentDocumentId()) return; closeLocalIndexSettingsPopover(); closeLocalOcrSettingsPopover(); var popover = ensurePageSettingsPopover(); renderPageSettingsPopover(); setActivePageSettingsTab(initialTab || 'page'); popover.hidden = false; pageUiState.pageSettingsOpen = true; updatePageSettingsTriggerState(); } 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(); } function closePageSettingsPopover() { var popover = document.querySelector('[data-testid="wolai-page-settings-popover"]'); if (popover instanceof HTMLElement) popover.hidden = true; pageUiState.pageSettingsOpen = false; updatePageSettingsTriggerState(); } 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(); } function togglePageSettingsPopover() { if (isPageSettingsOpen()) closePageSettingsPopover(); else openPageSettingsPopover(); } window.addEventListener('mnote:active-resource-tab-changed', function() { applyPageOptionsToShell(); }); window.addEventListener('mnote:open-local-ocr-settings', function() { openLocalOcrSettingsPopover(); }); return { addLocalIndexRange, applyPageOptionsToShell, closeAllSettingsPopovers, closePageHistoryDrawer, closeLocalIndexSettingsPopover, closeLocalOcrSettingsPopover, closePageSettingsPopover, closePageShareDialog, currentLocalOcrPreferences, currentPageOptions, ensureHistorySnapshotsSeeded, ensureLocalIndexSettingsPopover, ensureLocalOcrSettingsPopover, ensurePageHistoryDrawer, ensurePageSettingsPopover, ensurePageShareDialog, isAnySettingsOpen, isLocalIndexSettingsOpen, isLocalOcrSettingsOpen, isPageSettingsOpen, openPageHistoryDrawer, openLocalOcrSettingsPopover, openPageSettingsPopover, openPageIndexSettingsPopover, openPageShareDialog, pageOptionIsSupported, persistLocalOcrAutoPreference, persistLocalIndexSettings, persistPageOptionsPatch, persistPageWidthPreference, recordPageHistorySnapshot, removeLocalIndexRange, renderPageSettingsPopover, setActivePageSettingsTab, refreshLocalIndex, togglePageSettingsPopover, updatePageSettingsTriggerState, writeGlobalShowHeadingNumbers, loadPageWidthPreferences, }; }