diff --git a/WorldEditor/WorldEditor.js b/WorldEditor/WorldEditor.js index d042773..3bcb7a2 100644 --- a/WorldEditor/WorldEditor.js +++ b/WorldEditor/WorldEditor.js @@ -51,7 +51,7 @@ class WorldEditor { 'world-editor-select-all', 'world-editor-selected-count', 'world-editor-batch-actions', 'world-editor-entries-container', 'world-editor-enable-selected-btn', 'world-editor-disable-selected-btn', - 'world-editor-set-blue-btn', 'world-editor-set-green-btn', 'world-editor-delete-selected-btn', + 'world-editor-set-blue-btn', 'world-editor-set-green-btn', 'world-editor-copy-entries-btn', 'world-editor-delete-selected-btn', 'world-editor-set-disable-recursion-btn', 'world-editor-set-prevent-recursion-btn' ]; this.elements = {}; @@ -95,6 +95,7 @@ class WorldEditor { this.elements.worldEditorDisableSelectedBtn.addEventListener('click', () => this.batchUpdateEntries({ enabled: false })); this.elements.worldEditorSetBlueBtn.addEventListener('click', () => this.batchUpdateEntries({ type: 'constant' })); this.elements.worldEditorSetGreenBtn.addEventListener('click', () => this.batchUpdateEntries({ type: 'selective' })); + this.elements.worldEditorCopyEntriesBtn.addEventListener('click', () => this.copySelectedEntries()); this.elements.worldEditorDeleteSelectedBtn.addEventListener('click', () => this.batchDeleteEntries()); this.elements.worldEditorSetDisableRecursionBtn.addEventListener('click', () => this.toggleBatchRecursion('exclude_recursion', '不可递归')); this.elements.worldEditorSetPreventRecursionBtn.addEventListener('click', () => this.toggleBatchRecursion('prevent_recursion', '防止递归')); @@ -298,13 +299,37 @@ class WorldEditor { this.setLoading(true); this.currentWorldBook = worldBookName; try { - const rawEntries = await safeLorebookEntries(worldBookName); - this.entries = (rawEntries || []).map(e => ({ - uid: e.uid, enabled: e.enabled, type: e.type || (e.constant ? 'constant' : 'selective'), - keys: e.keys || [], content: e.content || '', position: e.position || 'before_character_definition', - depth: (String(e.position)?.startsWith('at_depth')) ? e.depth : null, order: e.order || 100, comment: e.comment || '', - exclude_recursion: e.exclude_recursion, prevent_recursion: e.prevent_recursion + const bookData = await loadWorldInfo(worldBookName); + if (!bookData || !bookData.entries) { + this.entries = []; + this.filteredEntries = []; + this.renderEntries(); + this.updateEntryCount(); + return; + } + + const positionMap = { + 0: 'before_character_definition', + 1: 'after_character_definition', + 2: 'before_author_note', + 3: 'after_author_note', + 4: 'at_depth' + }; + + this.entries = Object.entries(bookData.entries).map(([uid, e]) => ({ + uid: parseInt(uid), + enabled: !e.disable, + type: e.constant ? 'constant' : 'selective', + keys: e.key || [], + content: e.content || '', + position: positionMap[e.position] || 'at_depth', + depth: e.depth != null ? e.depth : 4, + order: e.order != null ? e.order : 100, + comment: e.comment || '', + exclude_recursion: e.excludeRecursion || false, + prevent_recursion: e.preventRecursion || false })); + this.filteredEntries = [...this.entries]; this.renderEntries(); this.updateEntryCount(); @@ -488,6 +513,114 @@ class WorldEditor { this.batchUpdateEntries({ [field]: shouldEnable }, confirmation); } + async copySelectedEntries() { + if (this.selectedEntries.size === 0) { + this.showError('请先选择要复制的条目'); + return; + } + + // 获取所有世界书列表(包括当前世界书,允许在同一世界书内复制) + const availableBooks = this.allWorldBooks.map(book => book.name); + + if (availableBooks.length === 0) { + this.showError('没有可用的世界书'); + return; + } + + console.log('[世界书编辑器] 准备复制条目,已选择:', this.selectedEntries.size, '个条目'); + console.log('[世界书编辑器] 选中的UID:', Array.from(this.selectedEntries)); + + // 创建选择对话框 + const selectHtml = ` + +