refactor(js): dritte Refactoring-Iteration – weitere Duplikate eliminiert
Zusammengeführt/dedupliziert: - renderMessages() nutzt jetzt _renderMessagesIntoFragment() statt eigenen switch/case - addChoiceBubble() + addChoiceBubbleStatic() → _createChoiceBubble() Helper - addErrorBubble() + addWarningBubble() → _addSystemBubble() Helper - Chain-Meta-Erstellung (3x) → _createChainMetaDiv() Helper - Agent-Picker-Setup (4x) → setupAgentPicker() Helper in session-page - more-Click-Handler (2x) → initMoreButton() Helper in ui-helpers - showLoginLinkModal() nutzt jetzt _createModal() - showMessage() in server-settings → showToast() Verwaiste Funktionen entfernt: - addAssistantBubble(), addReviewBubbleStatic(), addChoiceBubbleStatic() - addAttachmentIndicator(), addToolBoxStatic(), appendToolResult() - serverSettingsMessage HTML-Element Netto: -261 Zeilen
This commit is contained in:
1 parent
1a2c407538
commit
e4ccaf9dee
11 files changed
+96
-357
No files matched your search
+26
-102
@@ -106,11 +106,7 @@ async function loadOlderMessages() {
|
||||
for (const entry of entries) {
|
||||
_renderMessagesIntoFragment(fragment, _mergeConsecutiveAssistantTexts(entry.messages), imageMessageIds);
|
||||
if (entry.chain && isChainMetaVisible(entry.chain)) {
|
||||
const badges = buildMetaBadges(entry.chain);
|
||||
const metaDiv = document.createElement('div');
|
||||
metaDiv.className = 'chain-meta';
|
||||
metaDiv.innerHTML = badges.map(b => '<span class="chain-meta-badge">' + esc(b) + '</span>').join('');
|
||||
fragment.appendChild(metaDiv);
|
||||
fragment.appendChild(_createChainMetaDiv(entry.chain));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -274,6 +270,14 @@ function _isReviewMessage(content) {
|
||||
return content && (content.startsWith('[Review:') || content.startsWith('[Review-Feedback') || content.startsWith('[Finalizer:') || content.startsWith('[Preparer:'));
|
||||
}
|
||||
|
||||
function _createChainMetaDiv(chain, extraClass) {
|
||||
const badges = buildMetaBadges(chain);
|
||||
const div = document.createElement('div');
|
||||
div.className = 'chain-meta' + (extraClass ? ' ' + extraClass : '');
|
||||
div.innerHTML = badges.map(b => '<span class="chain-meta-badge">' + esc(b) + '</span>').join('');
|
||||
return div;
|
||||
}
|
||||
|
||||
function _renderChoiceBubbleInFragment(fragment, msgs, msgIdx) {
|
||||
var msg = msgs[msgIdx];
|
||||
try {
|
||||
@@ -288,36 +292,14 @@ function _renderChoiceBubbleInFragment(fragment, msgs, msgIdx) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
var choiceDiv = document.createElement('div');
|
||||
choiceDiv.className = 'msg choice-bubble' + (selectedChoice ? ' choice-answered' : '');
|
||||
choiceDiv.dataset.toolCallId = msg.toolCallId || '';
|
||||
if (msg.id) choiceDiv.dataset.messageId = msg.id;
|
||||
|
||||
var qDiv = document.createElement('div');
|
||||
qDiv.className = 'choice-question';
|
||||
qDiv.innerHTML = renderMarkdown(choiceQuestion);
|
||||
parseFluentEmojis(qDiv);
|
||||
choiceDiv.appendChild(qDiv);
|
||||
|
||||
var btnsDiv = document.createElement('div');
|
||||
btnsDiv.className = 'choice-buttons';
|
||||
for (var co of choiceOptions) {
|
||||
var cbtn = document.createElement('button');
|
||||
cbtn.className = 'choice-btn';
|
||||
cbtn.textContent = co;
|
||||
if (selectedChoice) {
|
||||
cbtn.disabled = true;
|
||||
cbtn.classList.add(co === selectedChoice ? 'choice-selected' : 'choice-unselected');
|
||||
} else {
|
||||
(function(toolCallId, choice, bubble) {
|
||||
cbtn.addEventListener('click', function() { handleChoiceClick(toolCallId, choice, bubble); });
|
||||
})(msg.toolCallId, co, choiceDiv);
|
||||
}
|
||||
btnsDiv.appendChild(cbtn);
|
||||
}
|
||||
choiceDiv.appendChild(btnsDiv);
|
||||
|
||||
if (msg.createdAt) _addTimestamp(choiceDiv, msg.createdAt);
|
||||
var choiceDiv = _createChoiceBubble({
|
||||
toolCallId: msg.toolCallId,
|
||||
question: choiceQuestion,
|
||||
choices: choiceOptions,
|
||||
selectedChoice: selectedChoice,
|
||||
timestamp: msg.createdAt,
|
||||
messageId: msg.id
|
||||
});
|
||||
fragment.appendChild(choiceDiv);
|
||||
} catch(e) {
|
||||
console.error('Choice-Bubble Rendering fehlgeschlagen:', e);
|
||||
@@ -328,75 +310,17 @@ function _renderChoiceBubbleInFragment(fragment, msgs, msgIdx) {
|
||||
|
||||
function renderMessages(msgs, addToConversation) {
|
||||
msgs = _mergeConsecutiveAssistantTexts(msgs);
|
||||
for (var _rmIdx = 0; _rmIdx < msgs.length; _rmIdx++) {
|
||||
const msg = msgs[_rmIdx];
|
||||
const fragment = document.createDocumentFragment();
|
||||
const imageMessageIds = [];
|
||||
_renderMessagesIntoFragment(fragment, msgs, imageMessageIds);
|
||||
chatEl().appendChild(fragment);
|
||||
// Track lastKnownMessageId
|
||||
for (const msg of msgs) {
|
||||
if (msg.id > lastKnownMessageId) lastKnownMessageId = msg.id;
|
||||
|
||||
switch (msg.type) {
|
||||
case 'text':
|
||||
if (_isReviewMessage(msg.content)) {
|
||||
addReviewBubbleStatic(msg.content, msg.createdAt, msg.id, msg.isMarked, msg.deletedOn);
|
||||
} else if (msg.role === 'user') {
|
||||
addUserBubble(msg.content, false, msg.createdAt, msg.id, msg.isMarked, msg.deletedOn);
|
||||
if (msg.attachmentCount > 0) {
|
||||
_autoLoadImageAttachments(msg.id);
|
||||
addAttachmentIndicator(msg.id, msg.attachmentCount, msg.attachmentNames);
|
||||
}
|
||||
} else if (msg.role === 'assistant') {
|
||||
addAssistantBubble(msg.content, msg.createdAt, msg.id, msg.isMarked, msg.deletedOn);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'tool_use':
|
||||
if (msg.toolName === 'ask_user_choice') {
|
||||
try {
|
||||
var choiceInput2 = typeof msg.content === 'string' ? JSON.parse(msg.content) : msg.content;
|
||||
var choiceQ2 = choiceInput2.question || '';
|
||||
var choiceOpts2 = Array.isArray(choiceInput2.choices) ? choiceInput2.choices : [String(choiceInput2.choices || '')];
|
||||
// Voraus-Suche nach zugehörigem tool_result
|
||||
var selectedChoice2 = null;
|
||||
for (var ci2 = _rmIdx + 1; ci2 < msgs.length; ci2++) {
|
||||
if (msgs[ci2].type === 'tool_result' && msgs[ci2].toolCallId === msg.toolCallId) {
|
||||
selectedChoice2 = msgs[ci2].content;
|
||||
msgs[ci2]._choiceHandled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (selectedChoice2) {
|
||||
addChoiceBubbleStatic(msg.toolCallId, choiceQ2, choiceOpts2, selectedChoice2, msg.createdAt, msg.id);
|
||||
} else {
|
||||
addChoiceBubble(msg.toolCallId, choiceQ2, choiceOpts2, false);
|
||||
}
|
||||
} catch(e) {
|
||||
console.error('Choice-Bubble Rendering fehlgeschlagen:', e);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (isToolVisible(msg.toolName)) {
|
||||
addToolBoxStatic(msg.toolName, msg.content, null, false);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'web_search_result': {
|
||||
if (isToolVisible('web_search')) {
|
||||
var wsSrc = [];
|
||||
try { wsSrc = JSON.parse(msg.content || '[]'); } catch(e) {}
|
||||
if (wsSrc.length > 0) addToolBoxStatic('web_search', null, null, false, wsSrc);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'tool_result':
|
||||
if (msg._choiceHandled) break;
|
||||
// tool_result wird dem vorherigen tool_use-Box angehängt wenn möglich
|
||||
appendToolResult(msg.content, msg.isError);
|
||||
break;
|
||||
|
||||
case 'error':
|
||||
addErrorBubble(msg.content);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Auto-load image attachments
|
||||
for (const mid of imageMessageIds) _autoLoadImageAttachments(mid);
|
||||
scrollDown();
|
||||
}
|
||||
|
||||
// ── Polling ──
|
||||
|
||||
Reference in new issue
Block a user