diff --git a/ui/table-bindings.js b/ui/table-bindings.js index 6c05894..de86979 100644 --- a/ui/table-bindings.js +++ b/ui/table-bindings.js @@ -6,6 +6,7 @@ import { extension_settings, getContext } from '/scripts/extensions.js'; import { extensionName } from '../utils/settings.js'; import { saveSettingsDebounced } from '/script.js'; import { startBatchFilling } from '../core/table-system/batch-filler.js'; +import { showHtmlModal } from './page-window.js'; import { DEFAULT_AI_RULE_TEMPLATE, DEFAULT_AI_FLOW_TEMPLATE } from '../core/table-system/settings.js'; import { world_names, loadWorldInfo } from '/scripts/world-info.js'; import { safeCharLorebooks, safeLorebookEntries } from '../core/tavernhelper-compatibility.js'; @@ -490,6 +491,74 @@ export function renderTables() { } +function openTableRuleEditor() { + const settings = extension_settings[extensionName]; + const tags = settings.table_tags_to_extract || ''; + const exclusionRules = settings.table_exclusion_rules || []; + + const rulesHtml = exclusionRules.map((rule, index) => ` +
+ + - + + +
+ `).join(''); + + const modalHtml = ` +
+
+ + + 仅提取指定XML标签的内容,例如填“content”,即提取...中的内容。 +
+
+ +
${rulesHtml}
+ + 移除所有被起始和结束标记包裹的内容(例如 OOC 部分)。 +
+
+ `; + + const dialog = showHtmlModal('配置独立提取规则', modalHtml, { + onOk: () => { + const newTags = document.getElementById('table-tags-input').value; + updateAndSaveTableSetting('table_tags_to_extract', newTags); + + const newExclusionRules = []; + document.querySelectorAll('#exclusion-rules-list .exclusion-rule-item').forEach(item => { + const start = item.querySelector('.rule-start').value.trim(); + const end = item.querySelector('.rule-end').value.trim(); + if (start && end) { + newExclusionRules.push({ start, end }); + } + }); + updateAndSaveTableSetting('table_exclusion_rules', newExclusionRules); + toastr.success('独立提取规则已保存。'); + }, + onShow: (dialogElement) => { + const rulesList = dialogElement.find('#exclusion-rules-list'); + + dialogElement.find('#add-exclusion-rule-btn').on('click', () => { + const newIndex = rulesList.children().length; + const newItemHtml = ` +
+ + - + + +
`; + rulesList.append(newItemHtml); + }); + + rulesList.on('click', '.remove-rule-btn', function() { + $(this).closest('.exclusion-rule-item').remove(); + }); + } + }); +} + function openRuleEditor(tableIndex) { const tables = TableManager.getMemoryState(); if (!tables || !tables[tableIndex]) return; @@ -884,6 +953,9 @@ export function bindTableEvents() { const contextSliderContainer = document.getElementById('context-reading-slider-container'); const contextSlider = document.getElementById('context-reading-slider'); const contextValueSpan = document.getElementById('context-reading-value'); + const independentRulesContainer = document.getElementById('table-independent-rules-container'); + const independentRulesToggle = document.getElementById('table-independent-rules-enabled'); + const configureRulesBtn = document.getElementById('table-configure-rules-btn'); const updateFillingModeUI = () => { const currentMode = extension_settings[extensionName]?.filling_mode || 'main-api'; @@ -891,12 +963,18 @@ export function bindTableEvents() { radio.checked = (radio.value === currentMode); }); + const isSecondaryMode = currentMode === 'secondary-api'; + if (contextSliderContainer) { - if (currentMode === 'secondary-api') { - contextSliderContainer.style.display = 'block'; - } else { - contextSliderContainer.style.display = 'none'; - } + contextSliderContainer.style.display = isSecondaryMode ? 'block' : 'none'; + } + + if (independentRulesContainer) { + independentRulesContainer.style.display = 'flex'; + } + + if (independentRulesToggle && configureRulesBtn) { + configureRulesBtn.style.display = independentRulesToggle.checked ? 'block' : 'none'; } }; @@ -929,8 +1007,20 @@ export function bindTableEvents() { }); } + if (independentRulesToggle) { + independentRulesToggle.checked = extension_settings[extensionName]?.table_independent_rules_enabled ?? false; + independentRulesToggle.addEventListener('change', () => { + updateAndSaveTableSetting('table_independent_rules_enabled', independentRulesToggle.checked); + updateFillingModeUI(); + }); + } + updateFillingModeUI(); + if (configureRulesBtn) { + configureRulesBtn.addEventListener('click', openTableRuleEditor); + } + const renderAll = () => { renderTables(); bindInjectionSettings(); @@ -944,6 +1034,7 @@ export function bindTableEvents() { bindReorganizeButton(); // 【新增】绑定重新整理按钮 bindTemplateEditors(); // 【新增】为新的指令模板编辑器绑定事件 bindNccsApiEvents(); // 【新增】绑定Nccs API系统事件 + bindChatTableDisplaySetting(); // 【新增】绑定聊天内表格显示开关 const navDeck = document.querySelector('#amily2_memorisation_forms_panel .sinan-navigation-deck'); if (navDeck) { @@ -1121,12 +1212,24 @@ export function bindTableEvents() { const colIndex = parseInt(target.dataset.colIndex, 10); const newValue = target.textContent; + const hScroll = tableElement.scrollLeft; + const scrollContainer = allTablesContainer.closest('.hly-scroll'); + const vScroll = scrollContainer ? scrollContainer.scrollTop : 0; + TableManager.addHighlight(tableIndex, rowIndex, colIndex); const dataToUpdate = { [colIndex]: newValue }; TableManager.updateRow(tableIndex, rowIndex, dataToUpdate); renderAll(); + const newTableElement = document.getElementById(`amily2-table-${tableIndex}`); + if (newTableElement) { + newTableElement.scrollLeft = hScroll; + } + if (scrollContainer) { + scrollContainer.scrollTop = vScroll; + } + }, true); } @@ -1602,3 +1705,23 @@ function bindNccsApiEvents() { log('Nccs API事件绑定完成', 'success'); } + +function bindChatTableDisplaySetting() { + const settings = extension_settings[extensionName]; + const toggle = document.getElementById('show-table-in-chat-toggle'); + + if (!toggle) { + log('找不到“聊天内显示表格”的开关,绑定失败。', 'warn'); + return; + } + + toggle.checked = settings.show_table_in_chat === true; + + toggle.addEventListener('change', () => { + settings.show_table_in_chat = toggle.checked; + saveSettingsDebounced(); + toastr.info(`聊天内表格显示已${toggle.checked ? '开启' : '关闭'}。`); + }); + + log('“聊天内显示表格”开关已成功绑定。', 'success'); +}