clay-server 2.26.0-beta.9 → 2.26.1-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/browser-mcp-server.js +4 -4
- package/lib/debate-mcp-server.js +94 -0
- package/lib/mates.js +12 -24
- package/lib/project-debate.js +304 -166
- package/lib/project-mate-interaction.js +10 -5
- package/lib/project.js +108 -39
- package/lib/public/app.js +388 -129
- package/lib/public/css/debate.css +230 -2
- package/lib/public/css/filebrowser.css +41 -4
- package/lib/public/css/icon-strip.css +10 -10
- package/lib/public/css/input.css +33 -0
- package/lib/public/css/mates.css +17 -38
- package/lib/public/css/messages.css +17 -0
- package/lib/public/css/mobile-nav.css +3 -1
- package/lib/public/css/rewind.css +17 -4
- package/lib/public/index.html +23 -15
- package/lib/public/modules/context-sources.js +21 -6
- package/lib/public/modules/debate.js +298 -97
- package/lib/public/modules/input.js +15 -0
- package/lib/public/modules/mate-knowledge.js +11 -11
- package/lib/public/modules/mate-memory.js +5 -5
- package/lib/public/modules/mate-sidebar.js +13 -9
- package/lib/public/modules/sidebar.js +105 -26
- package/lib/public/modules/terminal.js +62 -6
- package/lib/public/modules/tools.js +2 -2
- package/lib/sdk-bridge.js +123 -22
- package/lib/sessions.js +2 -2
- package/package.json +1 -1
package/lib/public/app.js
CHANGED
|
@@ -2,7 +2,7 @@ import { avatarUrl, userAvatarUrl, mateAvatarUrl } from './modules/avatar.js';
|
|
|
2
2
|
import { showToast, copyToClipboard, escapeHtml } from './modules/utils.js';
|
|
3
3
|
import { refreshIcons, iconHtml } from './modules/icons.js';
|
|
4
4
|
import { renderMarkdown, highlightCodeBlocks, renderMermaidBlocks, closeMermaidModal, parseEmojis } from './modules/markdown.js';
|
|
5
|
-
import { initSidebar, renderSessionList, handleSearchResults, updateSessionPresence, updatePageTitle, populateCliSessionList, renderIconStrip, renderSidebarPresence, initIconStrip, getEmojiCategories, renderUserStrip, setCurrentDmUser, updateDmBadge, updateSessionBadge, updateProjectBadge, closeDmUserPicker, spawnDustParticles, openMobileSheet, setMobileSheetMateData } from './modules/sidebar.js';
|
|
5
|
+
import { initSidebar, renderSessionList, handleSearchResults, updateSessionPresence, updatePageTitle, populateCliSessionList, renderIconStrip, renderSidebarPresence, initIconStrip, getEmojiCategories, renderUserStrip, setCurrentDmUser, updateDmBadge, updateSessionBadge, updateProjectBadge, closeDmUserPicker, spawnDustParticles, openMobileSheet, setMobileSheetMateData, refreshMobileChatSheet } from './modules/sidebar.js';
|
|
6
6
|
import { initMateSidebar, showMateSidebar, hideMateSidebar, renderMateSessionList, updateMateSidebarProfile, handleMateSearchResults } from './modules/mate-sidebar.js';
|
|
7
7
|
import { initMateKnowledge, requestKnowledgeList, renderKnowledgeList, handleKnowledgeContent, hideKnowledge } from './modules/mate-knowledge.js';
|
|
8
8
|
import { initMateMemory, renderMemoryList, hideMemory } from './modules/mate-memory.js';
|
|
@@ -32,7 +32,7 @@ import { initMateWizard, openMateWizard, closeMateWizard, handleMateCreated } fr
|
|
|
32
32
|
import { initCommandPalette, handlePaletteSessionSwitch, setPaletteVersion } from './modules/command-palette.js';
|
|
33
33
|
import { initLongPress } from './modules/longpress.js';
|
|
34
34
|
import { initMention, handleMentionStart, handleMentionStream, handleMentionDone, handleMentionError, handleMentionActivity, renderMentionUser, renderMentionResponse } from './modules/mention.js';
|
|
35
|
-
import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateResumed, handleDebateTurn, handleDebateActivity, handleDebateStream, handleDebateTurnDone, handleDebateCommentQueued, handleDebateCommentInjected, handleDebateEnded, handleDebateError, renderDebateStarted, renderDebateTurnDone, renderDebateEnded, renderDebateCommentInjected, renderDebateUserResume, openDebateModal, closeDebateModal, handleDebateBriefReady, renderDebateBriefReady, isDebateActive, resetDebateState } from './modules/debate.js';
|
|
35
|
+
import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateResumed, handleDebateTurn, handleDebateActivity, handleDebateStream, handleDebateTurnDone, handleDebateCommentQueued, handleDebateCommentInjected, handleDebateEnded, handleDebateError, renderDebateStarted, renderDebateTurnDone, renderDebateEnded, renderDebateCommentInjected, renderDebateUserResume, openDebateModal, closeDebateModal, handleDebateBriefReady, renderDebateBriefReady, isDebateActive, resetDebateState, exportDebateAsPdf, renderMcpDebateProposal } from './modules/debate.js';
|
|
36
36
|
|
|
37
37
|
// --- Base path for multi-project routing ---
|
|
38
38
|
var slugMatch = location.pathname.match(/^\/p\/([a-z0-9_-]+)/);
|
|
@@ -565,6 +565,8 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
565
565
|
// --- DM Mode Functions ---
|
|
566
566
|
function openDm(targetUserId) {
|
|
567
567
|
if (!ws || ws.readyState !== 1) return;
|
|
568
|
+
// Persist DM state for refresh recovery
|
|
569
|
+
try { localStorage.setItem("clay-active-dm", targetUserId); } catch (e) {}
|
|
568
570
|
// Check mate skill updates before opening mate DM
|
|
569
571
|
if (typeof targetUserId === "string" && targetUserId.indexOf("mate_") === 0) {
|
|
570
572
|
showMateOnboarding(function () {
|
|
@@ -816,6 +818,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
816
818
|
dmMode = false;
|
|
817
819
|
dmKey = null;
|
|
818
820
|
dmTargetUser = null;
|
|
821
|
+
try { localStorage.removeItem("clay-active-dm"); } catch (e) {}
|
|
819
822
|
setCurrentDmUser(null);
|
|
820
823
|
|
|
821
824
|
var mainCol = document.getElementById("main-column");
|
|
@@ -1798,9 +1801,10 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
1798
1801
|
};
|
|
1799
1802
|
initSidebar(sidebarCtx);
|
|
1800
1803
|
initIconStrip(sidebarCtx);
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
+
var wsGetter = function () { return ws; };
|
|
1805
|
+
initMateSidebar(wsGetter);
|
|
1806
|
+
initMateKnowledge(wsGetter);
|
|
1807
|
+
initMateMemory(wsGetter, { onShow: function () { hideKnowledge(); hideNotes(); } });
|
|
1804
1808
|
initMateWizard(
|
|
1805
1809
|
function (msg) { if (ws && ws.readyState === 1) ws.send(JSON.stringify(msg)); },
|
|
1806
1810
|
function (mate) { handleMateCreatedInApp(mate); }
|
|
@@ -3040,6 +3044,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
3040
3044
|
var div = document.createElement("div");
|
|
3041
3045
|
div.className = "msg-user" + (isOtherUser ? " msg-user-other" : "");
|
|
3042
3046
|
div.dataset.turn = ++turnCounter;
|
|
3047
|
+
if (shouldGroupMessage("msg-user")) div.classList.add("grouped");
|
|
3043
3048
|
var bubble = document.createElement("div");
|
|
3044
3049
|
bubble.className = "bubble";
|
|
3045
3050
|
bubble.dir = "auto";
|
|
@@ -3130,8 +3135,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
3130
3135
|
header.appendChild(nameSpan);
|
|
3131
3136
|
var timeSpan = document.createElement("span");
|
|
3132
3137
|
timeSpan.className = "dm-bubble-time";
|
|
3133
|
-
|
|
3134
|
-
timeSpan.textContent = String(nowH.getHours()).padStart(2, "0") + ":" + String(nowH.getMinutes()).padStart(2, "0");
|
|
3138
|
+
timeSpan.textContent = getMsgTime();
|
|
3135
3139
|
header.appendChild(timeSpan);
|
|
3136
3140
|
contentWrap.appendChild(header);
|
|
3137
3141
|
contentWrap.appendChild(bubble);
|
|
@@ -3140,10 +3144,8 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
3140
3144
|
// Action bar below bubble (icons visible on hover)
|
|
3141
3145
|
var actions = document.createElement("div");
|
|
3142
3146
|
actions.className = "msg-actions";
|
|
3143
|
-
var now = new Date();
|
|
3144
|
-
var timeStr = String(now.getHours()).padStart(2, "0") + ":" + String(now.getMinutes()).padStart(2, "0");
|
|
3145
3147
|
actions.innerHTML =
|
|
3146
|
-
'<span class="msg-action-time">' +
|
|
3148
|
+
'<span class="msg-action-time">' + getMsgTime() + '</span>' +
|
|
3147
3149
|
'<button class="msg-action-btn msg-action-copy" type="button" title="Copy">' + iconHtml("copy") + '</button>' +
|
|
3148
3150
|
'<button class="msg-action-btn msg-action-fork" type="button" title="Fork">' + iconHtml("git-branch") + '</button>' +
|
|
3149
3151
|
'<button class="msg-action-btn msg-action-rewind msg-user-rewind-btn" type="button" title="Rewind">' + iconHtml("rotate-ccw") + '</button>' +
|
|
@@ -3164,11 +3166,33 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
3164
3166
|
forceScrollToBottom();
|
|
3165
3167
|
}
|
|
3166
3168
|
|
|
3169
|
+
// Track the timestamp of the current message being processed (from history _ts or now)
|
|
3170
|
+
var currentMsgTs = null;
|
|
3171
|
+
|
|
3172
|
+
function getMsgTime() {
|
|
3173
|
+
var d = currentMsgTs ? new Date(currentMsgTs) : new Date();
|
|
3174
|
+
return String(d.getHours()).padStart(2, "0") + ":" + String(d.getMinutes()).padStart(2, "0");
|
|
3175
|
+
}
|
|
3176
|
+
|
|
3177
|
+
function shouldGroupMessage(senderClass) {
|
|
3178
|
+
// Skip grouping during history replay if no timestamp data
|
|
3179
|
+
if (replayingHistory && !currentMsgTs) return false;
|
|
3180
|
+
var prev = messagesEl.lastElementChild;
|
|
3181
|
+
if (!prev || !prev.classList.contains(senderClass)) return false;
|
|
3182
|
+
var prevTime = prev.querySelector(".dm-bubble-time");
|
|
3183
|
+
if (!prevTime) return false;
|
|
3184
|
+
return prevTime.textContent === getMsgTime();
|
|
3185
|
+
}
|
|
3186
|
+
|
|
3167
3187
|
function ensureAssistantBlock() {
|
|
3168
3188
|
if (!currentMsgEl) {
|
|
3169
3189
|
currentMsgEl = document.createElement("div");
|
|
3170
3190
|
currentMsgEl.className = "msg-assistant";
|
|
3171
3191
|
currentMsgEl.dataset.turn = turnCounter;
|
|
3192
|
+
|
|
3193
|
+
var grouped = shouldGroupMessage("msg-assistant");
|
|
3194
|
+
if (grouped) currentMsgEl.classList.add("grouped");
|
|
3195
|
+
|
|
3172
3196
|
// Always render avatar + header structure (CSS controls visibility)
|
|
3173
3197
|
var _isDm2 = document.body.classList.contains("mate-dm-active") && document.body.dataset.mateAvatarUrl;
|
|
3174
3198
|
var avi = document.createElement("img");
|
|
@@ -3187,8 +3211,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
3187
3211
|
header.appendChild(nameSpan);
|
|
3188
3212
|
var timeSpan = document.createElement("span");
|
|
3189
3213
|
timeSpan.className = "dm-bubble-time";
|
|
3190
|
-
|
|
3191
|
-
timeSpan.textContent = String(nowA.getHours()).padStart(2, "0") + ":" + String(nowA.getMinutes()).padStart(2, "0");
|
|
3214
|
+
timeSpan.textContent = getMsgTime();
|
|
3192
3215
|
header.appendChild(timeSpan);
|
|
3193
3216
|
contentWrap.appendChild(header);
|
|
3194
3217
|
|
|
@@ -3692,7 +3715,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
3692
3715
|
// Auto-switch input to schedule mode: any message typed will be queued for after reset
|
|
3693
3716
|
var delayUntilReset = msg.resetsAt - Date.now();
|
|
3694
3717
|
if (delayUntilReset > 0) {
|
|
3695
|
-
setScheduleDelayMs(delayUntilReset +
|
|
3718
|
+
setScheduleDelayMs(delayUntilReset + 60000); // +1min buffer after reset
|
|
3696
3719
|
}
|
|
3697
3720
|
rateLimitResetTimer = setTimeout(function () {
|
|
3698
3721
|
rateLimitResetsAt = null;
|
|
@@ -4120,6 +4143,31 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
4120
4143
|
|
|
4121
4144
|
// Session restore is now server-driven (user-presence.json).
|
|
4122
4145
|
// Mate DM restore is also server-driven via "restore_mate_dm" message.
|
|
4146
|
+
// Fallback: if server doesn't restore DM within 2s, try localStorage
|
|
4147
|
+
var savedDm = null;
|
|
4148
|
+
try { savedDm = localStorage.getItem("clay-active-dm"); } catch (e) {}
|
|
4149
|
+
if (savedDm && !dmMode && !mateProjectSlug) {
|
|
4150
|
+
var dmFallbackTimer = setTimeout(function () {
|
|
4151
|
+
if (!dmMode && savedDm) {
|
|
4152
|
+
console.log("[dm-restore] Server did not restore DM, using localStorage fallback:", savedDm);
|
|
4153
|
+
openDm(savedDm);
|
|
4154
|
+
}
|
|
4155
|
+
}, 2000);
|
|
4156
|
+
// Cancel fallback if server restores DM first
|
|
4157
|
+
var origHandler = ws.onmessage;
|
|
4158
|
+
var patchedOnce = false;
|
|
4159
|
+
var checkRestore = function (evt) {
|
|
4160
|
+
try {
|
|
4161
|
+
var d = JSON.parse(evt.data);
|
|
4162
|
+
if (d.type === "restore_mate_dm" && !patchedOnce) {
|
|
4163
|
+
patchedOnce = true;
|
|
4164
|
+
clearTimeout(dmFallbackTimer);
|
|
4165
|
+
}
|
|
4166
|
+
} catch (e) {}
|
|
4167
|
+
};
|
|
4168
|
+
ws.addEventListener("message", checkRestore);
|
|
4169
|
+
setTimeout(function () { ws.removeEventListener("message", checkRestore); }, 3000);
|
|
4170
|
+
}
|
|
4123
4171
|
// Safety: clear returningFromMateDm after initial messages settle
|
|
4124
4172
|
// (handles case where we connect to a non-main project that won't send restore_mate_dm)
|
|
4125
4173
|
if (returningFromMateDm) {
|
|
@@ -4218,6 +4266,8 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
4218
4266
|
}
|
|
4219
4267
|
|
|
4220
4268
|
function processMessage(msg) {
|
|
4269
|
+
// Preserve original timestamp from history replay
|
|
4270
|
+
currentMsgTs = msg._ts || null;
|
|
4221
4271
|
var isMateDm = dmMode && dmTargetUser && dmTargetUser.isMate;
|
|
4222
4272
|
|
|
4223
4273
|
// DEBUG: trace session/history loading
|
|
@@ -4232,6 +4282,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
4232
4282
|
if (isMateDm) {
|
|
4233
4283
|
if (msg.type === "session_list") {
|
|
4234
4284
|
renderMateSessionList(msg.sessions || []);
|
|
4285
|
+
refreshMobileChatSheet();
|
|
4235
4286
|
// Override title bar with mate name and re-apply color
|
|
4236
4287
|
var _mdn = (dmTargetUser.displayName || "New Mate");
|
|
4237
4288
|
if (headerTitleEl) headerTitleEl.textContent = _mdn;
|
|
@@ -4337,6 +4388,12 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
4337
4388
|
if (dhBar) dhBar.remove();
|
|
4338
4389
|
var dbBadges = document.querySelectorAll(".debate-header-badge");
|
|
4339
4390
|
for (var dbi = 0; dbi < dbBadges.length; dbi++) dbBadges[dbi].remove();
|
|
4391
|
+
// Clean up all debate mode banners if debate is not active on this session
|
|
4392
|
+
if (debateFloorMode) exitDebateFloorMode();
|
|
4393
|
+
if (debateConcludeMode) exitDebateConcludeMode();
|
|
4394
|
+
if (debateEndedMode) exitDebateEndedMode();
|
|
4395
|
+
var dbBanner = document.getElementById("debate-floor-banner");
|
|
4396
|
+
if (dbBanner) dbBanner.remove();
|
|
4340
4397
|
}
|
|
4341
4398
|
scrollToBottom();
|
|
4342
4399
|
// Scroll to tool element if navigating from file edit history
|
|
@@ -4577,9 +4634,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
4577
4634
|
break;
|
|
4578
4635
|
|
|
4579
4636
|
case "session_list":
|
|
4580
|
-
|
|
4581
|
-
renderMateSessionList(msg.sessions || []);
|
|
4582
|
-
}
|
|
4637
|
+
renderMateSessionList(msg.sessions || []);
|
|
4583
4638
|
renderSessionList(msg.sessions || []);
|
|
4584
4639
|
handlePaletteSessionSwitch();
|
|
4585
4640
|
break;
|
|
@@ -4670,6 +4725,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
4670
4725
|
break;
|
|
4671
4726
|
|
|
4672
4727
|
case "user_message":
|
|
4728
|
+
if (msg._internal) break;
|
|
4673
4729
|
resetThinkingGroup();
|
|
4674
4730
|
if (msg.planContent) {
|
|
4675
4731
|
setPlanContent(msg.planContent);
|
|
@@ -4691,7 +4747,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
4691
4747
|
header.className = "context-card-header";
|
|
4692
4748
|
var icon = document.createElement("span");
|
|
4693
4749
|
icon.className = "context-card-icon";
|
|
4694
|
-
icon.
|
|
4750
|
+
icon.innerHTML = iconHtml("globe");
|
|
4695
4751
|
header.appendChild(icon);
|
|
4696
4752
|
var label = document.createElement("span");
|
|
4697
4753
|
label.textContent = "Viewing tab";
|
|
@@ -4715,6 +4771,15 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
4715
4771
|
if (tabTitle || tabDomain) {
|
|
4716
4772
|
var meta = document.createElement("div");
|
|
4717
4773
|
meta.className = "context-card-meta";
|
|
4774
|
+
if (msg.tab.favIconUrl) {
|
|
4775
|
+
var fav = document.createElement("img");
|
|
4776
|
+
fav.className = "context-card-favicon";
|
|
4777
|
+
fav.src = msg.tab.favIconUrl;
|
|
4778
|
+
fav.width = 14;
|
|
4779
|
+
fav.height = 14;
|
|
4780
|
+
fav.onerror = function () { this.style.display = "none"; };
|
|
4781
|
+
meta.appendChild(fav);
|
|
4782
|
+
}
|
|
4718
4783
|
var titleEl = document.createElement("span");
|
|
4719
4784
|
titleEl.className = "context-card-title";
|
|
4720
4785
|
titleEl.textContent = tabTitle;
|
|
@@ -4788,6 +4853,8 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
4788
4853
|
}
|
|
4789
4854
|
renderPlanBanner("exit");
|
|
4790
4855
|
getTools()[msg.id] = { el: null, name: msg.name, input: null, done: true, hidden: true };
|
|
4856
|
+
} else if (msg.name === "propose_debate" || (msg.name && msg.name.indexOf("propose_debate") !== -1)) {
|
|
4857
|
+
getTools()[msg.id] = { el: null, name: msg.name, input: null, done: true, hidden: true };
|
|
4791
4858
|
} else if (getTodoTools()[msg.name]) {
|
|
4792
4859
|
getTools()[msg.id] = { el: null, name: msg.name, input: null, done: true, hidden: true };
|
|
4793
4860
|
} else {
|
|
@@ -4796,7 +4863,18 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
4796
4863
|
break;
|
|
4797
4864
|
|
|
4798
4865
|
case "tool_executing":
|
|
4799
|
-
if (msg.name === "
|
|
4866
|
+
if ((msg.name === "propose_debate" || (msg.name && msg.name.indexOf("propose_debate") !== -1)) && msg.input) {
|
|
4867
|
+
var _dpTool = getTools()[msg.id];
|
|
4868
|
+
if (_dpTool) {
|
|
4869
|
+
if (_dpTool.el) _dpTool.el.style.display = "none";
|
|
4870
|
+
_dpTool.done = true;
|
|
4871
|
+
_dpTool.hidden = true;
|
|
4872
|
+
removeToolFromGroup(msg.id);
|
|
4873
|
+
}
|
|
4874
|
+
finalizeAssistantBlock();
|
|
4875
|
+
renderMcpDebateProposal(msg.id, msg.input);
|
|
4876
|
+
startUrgentBlink();
|
|
4877
|
+
} else if (msg.name === "AskUserQuestion" && msg.input && msg.input.questions) {
|
|
4800
4878
|
var askTool = getTools()[msg.id];
|
|
4801
4879
|
if (askTool) {
|
|
4802
4880
|
if (askTool.el) askTool.el.style.display = "none";
|
|
@@ -5353,6 +5431,23 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
5353
5431
|
break;
|
|
5354
5432
|
|
|
5355
5433
|
// --- @Mention ---
|
|
5434
|
+
case "mention_processing":
|
|
5435
|
+
// Broadcast: show/hide activity dot on mate avatar across all tabs
|
|
5436
|
+
if (msg.mateId) {
|
|
5437
|
+
var mateContainers = document.querySelectorAll('.icon-strip-mate[data-user-id="' + msg.mateId + '"]');
|
|
5438
|
+
for (var mi = 0; mi < mateContainers.length; mi++) {
|
|
5439
|
+
var dot = mateContainers[mi].querySelector(".icon-strip-status");
|
|
5440
|
+
if (msg.active) {
|
|
5441
|
+
if (dot) dot.classList.add("processing");
|
|
5442
|
+
mateContainers[mi].classList.add("mention-active");
|
|
5443
|
+
} else {
|
|
5444
|
+
if (dot) dot.classList.remove("processing");
|
|
5445
|
+
mateContainers[mi].classList.remove("mention-active");
|
|
5446
|
+
}
|
|
5447
|
+
}
|
|
5448
|
+
}
|
|
5449
|
+
break;
|
|
5450
|
+
|
|
5356
5451
|
case "mention_start":
|
|
5357
5452
|
handleMentionStart(msg);
|
|
5358
5453
|
break;
|
|
@@ -5387,7 +5482,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
5387
5482
|
|
|
5388
5483
|
// --- Debate ---
|
|
5389
5484
|
case "debate_preparing":
|
|
5390
|
-
showDebateSticky("preparing", msg);
|
|
5485
|
+
if (!replayingHistory) showDebateSticky("preparing", msg);
|
|
5391
5486
|
handleDebatePreparing(msg);
|
|
5392
5487
|
break;
|
|
5393
5488
|
|
|
@@ -5400,7 +5495,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
5400
5495
|
break;
|
|
5401
5496
|
|
|
5402
5497
|
case "debate_started":
|
|
5403
|
-
showDebateSticky("live", msg);
|
|
5498
|
+
if (!replayingHistory) showDebateSticky("live", msg);
|
|
5404
5499
|
if (replayingHistory) {
|
|
5405
5500
|
renderDebateStarted(msg);
|
|
5406
5501
|
} else {
|
|
@@ -5430,6 +5525,10 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
5430
5525
|
}
|
|
5431
5526
|
break;
|
|
5432
5527
|
|
|
5528
|
+
case "debate_hand_raised":
|
|
5529
|
+
// Visual feedback: hand is raised, waiting for floor
|
|
5530
|
+
break;
|
|
5531
|
+
|
|
5433
5532
|
case "debate_comment_queued":
|
|
5434
5533
|
handleDebateCommentQueued(msg);
|
|
5435
5534
|
break;
|
|
@@ -5443,7 +5542,15 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
5443
5542
|
break;
|
|
5444
5543
|
|
|
5445
5544
|
case "debate_conclude_confirm":
|
|
5446
|
-
showDebateConcludeConfirm(msg);
|
|
5545
|
+
if (!replayingHistory) showDebateConcludeConfirm(msg);
|
|
5546
|
+
break;
|
|
5547
|
+
|
|
5548
|
+
case "debate_user_floor":
|
|
5549
|
+
if (!replayingHistory) showDebateUserFloor(msg);
|
|
5550
|
+
break;
|
|
5551
|
+
|
|
5552
|
+
case "debate_user_floor_done":
|
|
5553
|
+
renderDebateUserFloorDone(msg);
|
|
5447
5554
|
break;
|
|
5448
5555
|
|
|
5449
5556
|
case "debate_user_resume":
|
|
@@ -5452,11 +5559,11 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
5452
5559
|
|
|
5453
5560
|
case "debate_resumed":
|
|
5454
5561
|
handleDebateResumed(msg);
|
|
5455
|
-
showDebateSticky("live", msg);
|
|
5562
|
+
if (!replayingHistory) showDebateSticky("live", msg);
|
|
5456
5563
|
break;
|
|
5457
5564
|
|
|
5458
5565
|
case "debate_ended":
|
|
5459
|
-
showDebateSticky("ended", msg);
|
|
5566
|
+
if (!replayingHistory) showDebateSticky("ended", msg);
|
|
5460
5567
|
if (replayingHistory) {
|
|
5461
5568
|
renderDebateEnded(msg);
|
|
5462
5569
|
} else {
|
|
@@ -5791,6 +5898,12 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
5791
5898
|
isDmMode: function () { return dmMode && !(dmTargetUser && dmTargetUser.isMate); },
|
|
5792
5899
|
getDmKey: function () { return dmKey; },
|
|
5793
5900
|
handleDmSend: function () { handleDmSend(); },
|
|
5901
|
+
isDebateEndedMode: function () { return debateEndedMode; },
|
|
5902
|
+
handleDebateEndedSend: function () { handleDebateEndedSend(); },
|
|
5903
|
+
isDebateConcludeMode: function () { return debateConcludeMode; },
|
|
5904
|
+
handleDebateConcludeSend: function () { handleDebateConcludeSend(); },
|
|
5905
|
+
isDebateFloorMode: function () { return debateFloorMode; },
|
|
5906
|
+
handleDebateFloorSend: function () { handleDebateFloorSend(); },
|
|
5794
5907
|
isMateDm: function () { return dmMode && dmTargetUser && dmTargetUser.isMate; },
|
|
5795
5908
|
getMateName: function () { return dmTargetUser ? (dmTargetUser.displayName || "Mate") : "Mate"; },
|
|
5796
5909
|
getMateAvatarUrl: function () { return document.body.dataset.mateAvatarUrl || ""; },
|
|
@@ -5817,13 +5930,16 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
5817
5930
|
// --- Debate module ---
|
|
5818
5931
|
initDebate({
|
|
5819
5932
|
get ws() { return ws; },
|
|
5933
|
+
sendWs: function (obj) { if (ws && ws.readyState === 1) ws.send(JSON.stringify(obj)); },
|
|
5820
5934
|
messagesEl: messagesEl,
|
|
5935
|
+
addToMessages: function (el) { addToMessages(el); },
|
|
5821
5936
|
scrollToBottom: scrollToBottom,
|
|
5822
5937
|
addCopyHandler: addCopyHandler,
|
|
5823
5938
|
matesList: function () { return cachedMatesList || []; },
|
|
5824
5939
|
availableBuiltins: function () { return cachedAvailableBuiltins || []; },
|
|
5825
5940
|
currentMateId: function () { return (dmTargetUser && dmTargetUser.isMate) ? dmTargetUser.id : null; },
|
|
5826
5941
|
requireSkills: requireSkills,
|
|
5942
|
+
showDebateEndedMode: function (msg) { showDebateEndedMode(msg); },
|
|
5827
5943
|
});
|
|
5828
5944
|
|
|
5829
5945
|
// --- STT module (voice input via Web Speech API) ---
|
|
@@ -7110,7 +7226,220 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
7110
7226
|
var debateHandRaiseOpen = false;
|
|
7111
7227
|
|
|
7112
7228
|
function showDebateConcludeConfirm(msg) {
|
|
7113
|
-
|
|
7229
|
+
showDebateConcludeMode();
|
|
7230
|
+
}
|
|
7231
|
+
|
|
7232
|
+
var debateFloorMode = false;
|
|
7233
|
+
var debateConcludeMode = false;
|
|
7234
|
+
|
|
7235
|
+
function showDebateConcludeMode() {
|
|
7236
|
+
removeDebateBottomBar();
|
|
7237
|
+
debateConcludeMode = true;
|
|
7238
|
+
var inputArea = document.getElementById("input-area");
|
|
7239
|
+
if (inputArea) {
|
|
7240
|
+
inputArea.classList.add("debate-floor-mode");
|
|
7241
|
+
inputArea.style.display = "";
|
|
7242
|
+
}
|
|
7243
|
+
var existingBanner = document.getElementById("debate-floor-banner");
|
|
7244
|
+
if (existingBanner) existingBanner.remove();
|
|
7245
|
+
var banner = document.createElement("div");
|
|
7246
|
+
banner.id = "debate-floor-banner";
|
|
7247
|
+
banner.className = "debate-floor-banner";
|
|
7248
|
+
banner.innerHTML = iconHtml("check-circle") + " <span>The moderator is ready to conclude</span>" +
|
|
7249
|
+
'<button class="debate-floor-done-btn debate-floor-end-btn" id="debate-floor-end-btn">End Debate</button>';
|
|
7250
|
+
if (inputArea && inputArea.parentNode) {
|
|
7251
|
+
inputArea.parentNode.insertBefore(banner, inputArea);
|
|
7252
|
+
}
|
|
7253
|
+
refreshIcons();
|
|
7254
|
+
var endBtn = document.getElementById("debate-floor-end-btn");
|
|
7255
|
+
if (endBtn) {
|
|
7256
|
+
endBtn.addEventListener("click", function () {
|
|
7257
|
+
if (ws && ws.readyState === 1) {
|
|
7258
|
+
ws.send(JSON.stringify({ type: "debate_conclude_response", action: "end" }));
|
|
7259
|
+
}
|
|
7260
|
+
exitDebateConcludeMode();
|
|
7261
|
+
});
|
|
7262
|
+
}
|
|
7263
|
+
var inputEl = document.getElementById("input");
|
|
7264
|
+
if (inputEl) {
|
|
7265
|
+
inputEl._origPlaceholder = inputEl._origPlaceholder || inputEl.placeholder;
|
|
7266
|
+
inputEl.placeholder = "Add a direction to continue the debate...";
|
|
7267
|
+
inputEl.focus();
|
|
7268
|
+
}
|
|
7269
|
+
scrollToBottom();
|
|
7270
|
+
}
|
|
7271
|
+
|
|
7272
|
+
function exitDebateConcludeMode() {
|
|
7273
|
+
debateConcludeMode = false;
|
|
7274
|
+
var inputArea = document.getElementById("input-area");
|
|
7275
|
+
if (inputArea) inputArea.classList.remove("debate-floor-mode");
|
|
7276
|
+
var banner = document.getElementById("debate-floor-banner");
|
|
7277
|
+
if (banner) banner.remove();
|
|
7278
|
+
var inputEl = document.getElementById("input");
|
|
7279
|
+
if (inputEl && inputEl._origPlaceholder) {
|
|
7280
|
+
inputEl.placeholder = inputEl._origPlaceholder;
|
|
7281
|
+
delete inputEl._origPlaceholder;
|
|
7282
|
+
}
|
|
7283
|
+
}
|
|
7284
|
+
|
|
7285
|
+
function handleDebateConcludeSend() {
|
|
7286
|
+
var text = inputEl.value.trim();
|
|
7287
|
+
if (ws && ws.readyState === 1) {
|
|
7288
|
+
ws.send(JSON.stringify({ type: "debate_conclude_response", action: "continue", text: text }));
|
|
7289
|
+
}
|
|
7290
|
+
inputEl.value = "";
|
|
7291
|
+
exitDebateConcludeMode();
|
|
7292
|
+
showDebateBottomBar("live");
|
|
7293
|
+
}
|
|
7294
|
+
|
|
7295
|
+
var debateEndedMode = false;
|
|
7296
|
+
|
|
7297
|
+
function showDebateEndedMode(msg) {
|
|
7298
|
+
removeDebateBottomBar();
|
|
7299
|
+
debateEndedMode = true;
|
|
7300
|
+
var inputArea = document.getElementById("input-area");
|
|
7301
|
+
if (inputArea) {
|
|
7302
|
+
inputArea.classList.add("debate-floor-mode");
|
|
7303
|
+
inputArea.style.display = "";
|
|
7304
|
+
}
|
|
7305
|
+
var existingBanner = document.getElementById("debate-floor-banner");
|
|
7306
|
+
if (existingBanner) existingBanner.remove();
|
|
7307
|
+
var banner = document.createElement("div");
|
|
7308
|
+
banner.id = "debate-floor-banner";
|
|
7309
|
+
banner.className = "debate-floor-banner";
|
|
7310
|
+
banner.innerHTML = iconHtml("check-circle") + " <span>Debate ended</span>" +
|
|
7311
|
+
'<button class="debate-floor-done-btn" id="debate-ended-resume-btn">Resume</button>' +
|
|
7312
|
+
'<button class="debate-floor-done-btn" id="debate-ended-pdf-btn">' + iconHtml("download") + ' PDF</button>';
|
|
7313
|
+
if (inputArea && inputArea.parentNode) {
|
|
7314
|
+
inputArea.parentNode.insertBefore(banner, inputArea);
|
|
7315
|
+
}
|
|
7316
|
+
refreshIcons();
|
|
7317
|
+
// Resume button
|
|
7318
|
+
var resumeBtn = document.getElementById("debate-ended-resume-btn");
|
|
7319
|
+
if (resumeBtn) {
|
|
7320
|
+
resumeBtn.addEventListener("click", function () {
|
|
7321
|
+
handleDebateEndedSend();
|
|
7322
|
+
});
|
|
7323
|
+
}
|
|
7324
|
+
// PDF button
|
|
7325
|
+
var pdfBtn = document.getElementById("debate-ended-pdf-btn");
|
|
7326
|
+
if (pdfBtn) {
|
|
7327
|
+
pdfBtn.addEventListener("click", function () {
|
|
7328
|
+
pdfBtn.disabled = true;
|
|
7329
|
+
exportDebateAsPdf().then(function () { pdfBtn.disabled = false; }).catch(function () { pdfBtn.disabled = false; });
|
|
7330
|
+
});
|
|
7331
|
+
}
|
|
7332
|
+
var inputEl2 = document.getElementById("input");
|
|
7333
|
+
if (inputEl2) {
|
|
7334
|
+
inputEl2._origPlaceholder = inputEl2._origPlaceholder || inputEl2.placeholder;
|
|
7335
|
+
inputEl2.placeholder = "Continue with a new direction...";
|
|
7336
|
+
}
|
|
7337
|
+
scrollToBottom();
|
|
7338
|
+
}
|
|
7339
|
+
|
|
7340
|
+
function exitDebateEndedMode() {
|
|
7341
|
+
debateEndedMode = false;
|
|
7342
|
+
var inputArea = document.getElementById("input-area");
|
|
7343
|
+
if (inputArea) inputArea.classList.remove("debate-floor-mode");
|
|
7344
|
+
var banner = document.getElementById("debate-floor-banner");
|
|
7345
|
+
if (banner) banner.remove();
|
|
7346
|
+
var inputEl2 = document.getElementById("input");
|
|
7347
|
+
if (inputEl2 && inputEl2._origPlaceholder) {
|
|
7348
|
+
inputEl2.placeholder = inputEl2._origPlaceholder;
|
|
7349
|
+
delete inputEl2._origPlaceholder;
|
|
7350
|
+
}
|
|
7351
|
+
}
|
|
7352
|
+
|
|
7353
|
+
function handleDebateEndedSend() {
|
|
7354
|
+
var text = inputEl.value.trim();
|
|
7355
|
+
if (ws && ws.readyState === 1) {
|
|
7356
|
+
ws.send(JSON.stringify({ type: "debate_conclude_response", action: "continue", text: text }));
|
|
7357
|
+
}
|
|
7358
|
+
inputEl.value = "";
|
|
7359
|
+
exitDebateEndedMode();
|
|
7360
|
+
}
|
|
7361
|
+
|
|
7362
|
+
function showDebateUserFloor(msg) {
|
|
7363
|
+
// Remove debate bottom bar and show input area in floor mode
|
|
7364
|
+
removeDebateBottomBar();
|
|
7365
|
+
debateFloorMode = true;
|
|
7366
|
+
var inputArea = document.getElementById("input-area");
|
|
7367
|
+
if (inputArea) {
|
|
7368
|
+
inputArea.classList.add("debate-floor-mode");
|
|
7369
|
+
inputArea.style.display = "";
|
|
7370
|
+
}
|
|
7371
|
+
// Add floor banner above input
|
|
7372
|
+
var existingBanner = document.getElementById("debate-floor-banner");
|
|
7373
|
+
if (existingBanner) existingBanner.remove();
|
|
7374
|
+
var banner = document.createElement("div");
|
|
7375
|
+
banner.id = "debate-floor-banner";
|
|
7376
|
+
banner.className = "debate-floor-banner";
|
|
7377
|
+
banner.innerHTML = iconHtml("mic") + " <span>You have the floor</span>" +
|
|
7378
|
+
'<button class="debate-floor-done-btn" id="debate-floor-done-btn">Pass</button>';
|
|
7379
|
+
if (inputArea && inputArea.parentNode) {
|
|
7380
|
+
inputArea.parentNode.insertBefore(banner, inputArea);
|
|
7381
|
+
}
|
|
7382
|
+
refreshIcons();
|
|
7383
|
+
// Done button: exit floor mode without sending
|
|
7384
|
+
var doneBtn = document.getElementById("debate-floor-done-btn");
|
|
7385
|
+
if (doneBtn) {
|
|
7386
|
+
doneBtn.addEventListener("click", function () {
|
|
7387
|
+
// Pass without speaking: resume debate
|
|
7388
|
+
if (ws && ws.readyState === 1) {
|
|
7389
|
+
ws.send(JSON.stringify({ type: "debate_user_floor_response", text: "(The user passed without speaking)" }));
|
|
7390
|
+
}
|
|
7391
|
+
exitDebateFloorMode();
|
|
7392
|
+
showDebateBottomBar("live");
|
|
7393
|
+
});
|
|
7394
|
+
}
|
|
7395
|
+
// Update placeholder
|
|
7396
|
+
var inputEl = document.getElementById("input");
|
|
7397
|
+
if (inputEl) {
|
|
7398
|
+
inputEl._origPlaceholder = inputEl.placeholder;
|
|
7399
|
+
inputEl.placeholder = "Share your thoughts with the panel...";
|
|
7400
|
+
inputEl.focus();
|
|
7401
|
+
}
|
|
7402
|
+
scrollToBottom();
|
|
7403
|
+
}
|
|
7404
|
+
|
|
7405
|
+
function exitDebateFloorMode() {
|
|
7406
|
+
debateFloorMode = false;
|
|
7407
|
+
var inputArea = document.getElementById("input-area");
|
|
7408
|
+
if (inputArea) inputArea.classList.remove("debate-floor-mode");
|
|
7409
|
+
var banner = document.getElementById("debate-floor-banner");
|
|
7410
|
+
if (banner) banner.remove();
|
|
7411
|
+
var inputEl = document.getElementById("input");
|
|
7412
|
+
if (inputEl && inputEl._origPlaceholder) {
|
|
7413
|
+
inputEl.placeholder = inputEl._origPlaceholder;
|
|
7414
|
+
delete inputEl._origPlaceholder;
|
|
7415
|
+
}
|
|
7416
|
+
}
|
|
7417
|
+
|
|
7418
|
+
function handleDebateFloorSend() {
|
|
7419
|
+
var text = inputEl.value.trim();
|
|
7420
|
+
if (!text) return;
|
|
7421
|
+
if (ws && ws.readyState === 1) {
|
|
7422
|
+
ws.send(JSON.stringify({ type: "debate_user_floor_response", text: text }));
|
|
7423
|
+
}
|
|
7424
|
+
inputEl.value = "";
|
|
7425
|
+
exitDebateFloorMode();
|
|
7426
|
+
showDebateBottomBar("live");
|
|
7427
|
+
}
|
|
7428
|
+
|
|
7429
|
+
function renderDebateUserFloorDone(msg) {
|
|
7430
|
+
if (!messagesEl) return;
|
|
7431
|
+
var el = document.createElement("div");
|
|
7432
|
+
el.className = "debate-user-comment";
|
|
7433
|
+
var label = document.createElement("span");
|
|
7434
|
+
label.className = "debate-comment-label";
|
|
7435
|
+
label.innerHTML = iconHtml("mic") + " User:";
|
|
7436
|
+
var textEl = document.createElement("div");
|
|
7437
|
+
textEl.className = "debate-comment-text";
|
|
7438
|
+
textEl.textContent = msg.text || "";
|
|
7439
|
+
el.appendChild(label);
|
|
7440
|
+
el.appendChild(textEl);
|
|
7441
|
+
messagesEl.appendChild(el);
|
|
7442
|
+
refreshIcons();
|
|
7114
7443
|
scrollToBottom();
|
|
7115
7444
|
}
|
|
7116
7445
|
|
|
@@ -7136,7 +7465,13 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
7136
7465
|
return;
|
|
7137
7466
|
}
|
|
7138
7467
|
|
|
7139
|
-
//
|
|
7468
|
+
// Show bottom bar regardless of header availability
|
|
7469
|
+
if (phase === "live") {
|
|
7470
|
+
debateHandRaiseOpen = false;
|
|
7471
|
+
showDebateBottomBar("live");
|
|
7472
|
+
}
|
|
7473
|
+
|
|
7474
|
+
// Add badges next to header title (optional, may not exist on mobile)
|
|
7140
7475
|
var headerTitle = document.getElementById("header-title");
|
|
7141
7476
|
if (!headerTitle) return;
|
|
7142
7477
|
|
|
@@ -7156,9 +7491,6 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
7156
7491
|
roundBadge.id = "debate-header-round";
|
|
7157
7492
|
roundBadge.textContent = "R" + ((msg && msg.round) || 1);
|
|
7158
7493
|
liveBadge.after(roundBadge);
|
|
7159
|
-
|
|
7160
|
-
debateHandRaiseOpen = false;
|
|
7161
|
-
showDebateBottomBar("live");
|
|
7162
7494
|
}
|
|
7163
7495
|
}
|
|
7164
7496
|
|
|
@@ -7177,6 +7509,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
7177
7509
|
bar.innerHTML =
|
|
7178
7510
|
'<div class="debate-bottom-inner">' +
|
|
7179
7511
|
'<button class="debate-bottom-hand" id="debate-bottom-hand">' + iconHtml("hand") + ' Raise hand</button>' +
|
|
7512
|
+
'<span class="debate-bottom-waiting hidden" id="debate-bottom-waiting">' + iconHtml("loader") + ' You will get the floor after the current speaker</span>' +
|
|
7180
7513
|
'<button class="debate-bottom-stop" id="debate-bottom-stop">' + iconHtml("square") + ' Stop</button>' +
|
|
7181
7514
|
'</div>';
|
|
7182
7515
|
|
|
@@ -7184,6 +7517,14 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
7184
7517
|
inputArea.style.display = "none";
|
|
7185
7518
|
refreshIcons();
|
|
7186
7519
|
|
|
7520
|
+
// Restore raised state if hand was already raised
|
|
7521
|
+
if (debateHandRaiseOpen) {
|
|
7522
|
+
var handBtn = document.getElementById("debate-bottom-hand");
|
|
7523
|
+
var waitingEl = document.getElementById("debate-bottom-waiting");
|
|
7524
|
+
if (handBtn) { handBtn.classList.add("raised"); handBtn.classList.add("hidden"); }
|
|
7525
|
+
if (waitingEl) waitingEl.classList.remove("hidden");
|
|
7526
|
+
}
|
|
7527
|
+
|
|
7187
7528
|
document.getElementById("debate-bottom-hand").addEventListener("click", function () {
|
|
7188
7529
|
toggleDebateHandRaise();
|
|
7189
7530
|
});
|
|
@@ -7192,48 +7533,6 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
7192
7533
|
ws.send(JSON.stringify({ type: "debate_stop" }));
|
|
7193
7534
|
}
|
|
7194
7535
|
});
|
|
7195
|
-
} else if (mode === "conclude") {
|
|
7196
|
-
bar.innerHTML =
|
|
7197
|
-
'<div class="debate-bottom-inner debate-bottom-conclude">' +
|
|
7198
|
-
'<div class="debate-bottom-conclude-label">' + iconHtml("check-circle") + ' The moderator is ready to conclude. End the debate?</div>' +
|
|
7199
|
-
'<textarea class="debate-bottom-conclude-input" id="debate-bottom-conclude-input" rows="3" placeholder="Or add a direction to continue..."></textarea>' +
|
|
7200
|
-
'<div class="debate-bottom-conclude-actions">' +
|
|
7201
|
-
'<button class="debate-bottom-continue" id="debate-bottom-continue">Continue</button>' +
|
|
7202
|
-
'<button class="debate-bottom-end" id="debate-bottom-end">End Debate</button>' +
|
|
7203
|
-
'</div>' +
|
|
7204
|
-
'</div>';
|
|
7205
|
-
|
|
7206
|
-
inputArea.parentNode.insertBefore(bar, inputArea);
|
|
7207
|
-
inputArea.style.display = "none";
|
|
7208
|
-
refreshIcons();
|
|
7209
|
-
|
|
7210
|
-
var textArea = document.getElementById("debate-bottom-conclude-input");
|
|
7211
|
-
document.getElementById("debate-bottom-end").addEventListener("click", function () {
|
|
7212
|
-
if (ws && ws.readyState === 1) {
|
|
7213
|
-
ws.send(JSON.stringify({ type: "debate_conclude_response", action: "end" }));
|
|
7214
|
-
}
|
|
7215
|
-
removeDebateBottomBar();
|
|
7216
|
-
});
|
|
7217
|
-
document.getElementById("debate-bottom-continue").addEventListener("click", function () {
|
|
7218
|
-
var text = textArea ? textArea.value.trim() : "";
|
|
7219
|
-
if (ws && ws.readyState === 1) {
|
|
7220
|
-
ws.send(JSON.stringify({ type: "debate_conclude_response", action: "continue", text: text }));
|
|
7221
|
-
}
|
|
7222
|
-
removeDebateBottomBar();
|
|
7223
|
-
showDebateBottomBar("live");
|
|
7224
|
-
});
|
|
7225
|
-
if (textArea) {
|
|
7226
|
-
textArea.focus();
|
|
7227
|
-
textArea.addEventListener("keydown", function (e) {
|
|
7228
|
-
if (e.key === "Enter" && !e.shiftKey) {
|
|
7229
|
-
e.preventDefault();
|
|
7230
|
-
document.getElementById("debate-bottom-continue").click();
|
|
7231
|
-
}
|
|
7232
|
-
});
|
|
7233
|
-
textArea.addEventListener("input", function () {
|
|
7234
|
-
debateAutoResize(textArea, 12);
|
|
7235
|
-
});
|
|
7236
|
-
}
|
|
7237
7536
|
}
|
|
7238
7537
|
}
|
|
7239
7538
|
|
|
@@ -7253,74 +7552,34 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
7253
7552
|
var handBar = document.getElementById("debate-hand-raise-bar");
|
|
7254
7553
|
if (handBar) handBar.remove();
|
|
7255
7554
|
debateHandRaiseOpen = false;
|
|
7555
|
+
// Clean up floor/conclude/ended modes
|
|
7556
|
+
if (debateFloorMode) exitDebateFloorMode();
|
|
7557
|
+
if (debateConcludeMode) exitDebateConcludeMode();
|
|
7558
|
+
if (debateEndedMode) exitDebateEndedMode();
|
|
7256
7559
|
// Restore input area
|
|
7257
7560
|
var inputArea = document.getElementById("input-area");
|
|
7258
7561
|
if (inputArea) inputArea.style.display = "";
|
|
7259
7562
|
}
|
|
7260
7563
|
|
|
7261
7564
|
function toggleDebateHandRaise(forceState) {
|
|
7262
|
-
var
|
|
7263
|
-
debateHandRaiseOpen =
|
|
7264
|
-
|
|
7265
|
-
|
|
7266
|
-
|
|
7267
|
-
|
|
7268
|
-
|
|
7269
|
-
|
|
7270
|
-
|
|
7271
|
-
|
|
7272
|
-
if (
|
|
7273
|
-
|
|
7274
|
-
}
|
|
7275
|
-
|
|
7276
|
-
// Create hand raise bar above input area
|
|
7277
|
-
var bar = document.createElement("div");
|
|
7278
|
-
bar.id = "debate-hand-raise-bar";
|
|
7279
|
-
bar.className = "debate-hand-raise-bar";
|
|
7280
|
-
bar.innerHTML =
|
|
7281
|
-
'<div class="debate-hand-raise-inner">' +
|
|
7282
|
-
'<span class="debate-hand-raise-label">' + iconHtml("hand") + ' Your comment:</span>' +
|
|
7283
|
-
'<textarea class="debate-hand-input" rows="1" placeholder="Type your comment..."></textarea>' +
|
|
7284
|
-
'<button class="debate-hand-send">Send</button>' +
|
|
7285
|
-
'<button class="debate-hand-cancel">Cancel</button>' +
|
|
7286
|
-
'</div>';
|
|
7287
|
-
|
|
7288
|
-
var inputArea = document.getElementById("input-area");
|
|
7289
|
-
if (inputArea && inputArea.parentNode) {
|
|
7290
|
-
inputArea.parentNode.insertBefore(bar, inputArea);
|
|
7291
|
-
}
|
|
7292
|
-
refreshIcons();
|
|
7293
|
-
|
|
7294
|
-
var textarea = bar.querySelector(".debate-hand-input");
|
|
7295
|
-
var sendBtn = bar.querySelector(".debate-hand-send");
|
|
7296
|
-
var cancelBtn = bar.querySelector(".debate-hand-cancel");
|
|
7297
|
-
|
|
7298
|
-
if (textarea) {
|
|
7299
|
-
textarea.focus();
|
|
7300
|
-
textarea.addEventListener("input", function () {
|
|
7301
|
-
debateAutoResize(textarea, 12);
|
|
7302
|
-
});
|
|
7565
|
+
var raise = typeof forceState === "boolean" ? forceState : !debateHandRaiseOpen;
|
|
7566
|
+
debateHandRaiseOpen = raise;
|
|
7567
|
+
|
|
7568
|
+
// Update UI: hide hand button, show waiting message
|
|
7569
|
+
var handBtn = document.getElementById("debate-bottom-hand");
|
|
7570
|
+
var waitingEl = document.getElementById("debate-bottom-waiting");
|
|
7571
|
+
if (raise) {
|
|
7572
|
+
if (handBtn) { handBtn.classList.add("raised"); handBtn.classList.add("hidden"); }
|
|
7573
|
+
if (waitingEl) waitingEl.classList.remove("hidden");
|
|
7574
|
+
} else {
|
|
7575
|
+
if (handBtn) { handBtn.classList.remove("raised"); handBtn.classList.remove("hidden"); }
|
|
7576
|
+
if (waitingEl) waitingEl.classList.add("hidden");
|
|
7303
7577
|
}
|
|
7304
7578
|
|
|
7305
|
-
|
|
7306
|
-
|
|
7307
|
-
if (!text) return;
|
|
7308
|
-
if (ws && ws.readyState === 1) {
|
|
7309
|
-
ws.send(JSON.stringify({ type: "debate_comment", text: text }));
|
|
7310
|
-
}
|
|
7311
|
-
toggleDebateHandRaise(false);
|
|
7312
|
-
});
|
|
7313
|
-
|
|
7314
|
-
cancelBtn.addEventListener("click", function () {
|
|
7315
|
-
toggleDebateHandRaise(false);
|
|
7316
|
-
});
|
|
7317
|
-
|
|
7318
|
-
if (textarea) {
|
|
7319
|
-
textarea.addEventListener("keydown", function (e) {
|
|
7320
|
-
if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); sendBtn.click(); }
|
|
7321
|
-
if (e.key === "Escape") { toggleDebateHandRaise(false); }
|
|
7322
|
-
});
|
|
7579
|
+
if (raise && ws && ws.readyState === 1) {
|
|
7580
|
+
ws.send(JSON.stringify({ type: "debate_hand_raise" }));
|
|
7323
7581
|
}
|
|
7582
|
+
// Floor mode will be activated when server sends debate_user_floor
|
|
7324
7583
|
}
|
|
7325
7584
|
|
|
7326
7585
|
function sendDebateStickyComment() {
|