Files
nodecrypt/web/main.js
T

253 lines
7.8 KiB
JavaScript

/**
* NodeCrypt 聊天应用主入口文件
* 负责初始化界面、绑定事件及协调各模块功能
*/
// === 工具模块导入 ===
import { processImage, setupImageSend } from './util.image.js';
import { setupEmojiPicker } from './util.emoji.js';
import { openSettingsPanel, closeSettingsPanel, initSettings, notifyMessage } from './util.settings.js';
import { escapeHTML, textToHTML } from './util.string.js';
import { $, $$, $id, on, off, addClass, removeClass } from './util.dom.js';
//import './NodeCrypt.js';
// === 核心功能模块导入 ===
import {
roomsData,
activeRoomIndex,
getNewRoomData,
joinRoom,
togglePrivateChat,
setStatus
} from './room.js';
import {
renderChatArea,
addMsg,
addSystemMsg,
setupImagePreview,
updateChatInputStyle,
setupInputPlaceholder
} from './chat.js';
// === 界面相关模块导入 ===
import {
renderUserList,
renderMainHeader,
setupMoreBtnMenu,
preventSpaceInput,
loginFormHandler,
openLoginModal,
setupTabs,
autofillRoomPwd
} from './ui.js';
// === 全局配置 ===
/**
* 应用全局配置
* rsaPublic: RSA公钥,用于加密通信
* wsAddress: WebSocket服务器地址
* debug: 是否开启调试模式
*/
/*
const config = {
rsaPublic: window.NODECRYPT_PUBLIC_KEY,
wsAddress: '/ws',
debug: true
};
*/
window.config = {
rsaPublic: 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAj56XR23fVMeETZtH96QcVjWiOaPzDtqqJoEdb+hde2Iv4QlZBauyMjQXS8YIfytym7RA9Y/iQ20Q4DdL9/HKBPb9+frYcY+icYMX6/kdeAIxH0/2TP0lbxQQHbjx1k2AXEjq3n/srnUUKduyji8ZtnyBCgpkCaaWkNepW3M1lskJASfYLZFE56llZsHwkq+CNqcAiTJU2dL9WVNbJmEHS27++L5a2zWPyIsnmsw1f1hGKNqY2ksCmVQGLiLQhB3DATtDv/lPiqQWf//EXsTQ7j6S1cVyiJwqE0IEa0ikUOmmBu6dplL/EgQDeyNJ2BgIvKMn5IcXk86zxnOB6qpTnwIDAQAB',
wsAddress: 'wss://crypt.works/ws',
debug: true
};
window.config = config;
// === 全局函数导出 ===
/**
* 将核心函数暴露给全局作用域,便于跨模块调用
*/
window.addSystemMsg = addSystemMsg;
window.joinRoom = joinRoom;
window.notifyMessage = notifyMessage;
window.setupEmojiPicker = setupEmojiPicker;
// 页面初始化
window.addEventListener('DOMContentLoaded', () => {
// 获取主要UI元素
const loginContainer = $id('login-container');
const chatContainer = $id('chat-container');
const loginForm = $id('login-form');
// === 登录相关初始化 ===
// 绑定初始登录表单
if (loginForm) {
loginForm.addEventListener('submit', loginFormHandler(null));
}
// 绑定"进入新房间"按钮
const joinBtn = $('.join-room');
if (joinBtn) {
joinBtn.onclick = openLoginModal;
}
// 禁止主登录页输入框输入空格
preventSpaceInput($id('userName'));
preventSpaceInput($id('roomName'));
preventSpaceInput($id('password'));
// 自动填充URL参数中的房间信息
autofillRoomPwd();
// === 界面组件初始化 ===
// 设置各种UI组件
setupInputPlaceholder();
setupMoreBtnMenu();
setupImagePreview();
setupEmojiPicker();
// 初始化设置
initSettings();
// 设置按钮点击事件
const settingsBtn = $id('settings-btn');
if (settingsBtn) {
settingsBtn.onclick = (e) => {
e.stopPropagation();
openSettingsPanel();
};
}
// 点击其它区域关闭设置面板
document.addEventListener('click', (ev) => {
const panel = $id('settings-panel');
if (panel && panel.style.display === 'block') {
const card = panel.querySelector('.settings-panel-card');
if (card && !card.contains(ev.target) && ev.target.id !== 'settings-btn') {
closeSettingsPanel();
}
}
});
// === 消息收发功能 ===
// 自动聚焦到输入框并设置消息发送逻辑
const input = document.querySelector('.input-message-input');
if (input) {
input.focus();
input.addEventListener('keydown', (e) => {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
const text = input.innerText.trim();
const rd = roomsData[activeRoomIndex];
if (text && rd && rd.chat) {
if (rd.privateChatTargetId) {
const targetClient = rd.chat.channel[rd.privateChatTargetId];
if (targetClient && targetClient.shared) {
const clientMessagePayload = { a: 'm', t: 'text_private', d: text };
const encryptedClientMessage = rd.chat.encryptClientMessage(clientMessagePayload, targetClient.shared);
const serverRelayPayload = { a: 'c', p: encryptedClientMessage, c: rd.privateChatTargetId };
const encryptedMessageForServer = rd.chat.encryptServerMessage(serverRelayPayload, rd.chat.serverShared);
rd.chat.sendMessage(encryptedMessageForServer);
addMsg(text, false, 'text_private');
} else {
addSystemMsg(`Cannot send private message to ${rd.privateChatTargetName}. User might not be fully connected.`);
}
} else {
rd.chat.sendChannelMessage('text', text);
addMsg(text);
}
input.innerText = '';
input.dispatchEvent(new Event('input')); // To update placeholder
}
}
});
}
// 图片发送功能
setupImageSend({
inputSelector: '.input-message-input',
attachBtnSelector: '.chat-attach-btn',
fileInputSelector: '.new-message-wrapper input[type="file"]',
onSend: (dataUrl) => {
const rd = roomsData[activeRoomIndex];
if (rd && rd.chat) {
if (rd.privateChatTargetId) {
const targetClient = rd.chat.channel[rd.privateChatTargetId];
if (targetClient && targetClient.shared) {
const clientMessagePayload = { a: 'm', t: 'image_private', d: dataUrl };
const encryptedClientMessage = rd.chat.encryptClientMessage(clientMessagePayload, targetClient.shared);
const serverRelayPayload = { a: 'c', p: encryptedClientMessage, c: rd.privateChatTargetId };
const encryptedMessageForServer = rd.chat.encryptServerMessage(serverRelayPayload, rd.chat.serverShared);
rd.chat.sendMessage(encryptedMessageForServer);
addMsg(dataUrl, false, 'image_private');
} else {
addSystemMsg(`Cannot send private image to ${rd.privateChatTargetName}. User might not be fully connected.`);
}
} else {
rd.chat.sendChannelMessage('image', dataUrl);
addMsg(dataUrl, false, 'image');
}
}
}
});
// 移动端适配辅助函数
const isMobile = () => {
return window.innerWidth <= 768;
};
// 初始化UI组件
renderMainHeader();
renderUserList();
setupTabs();
// 移动端侧边栏处理
const roomList = $id('room-list');
const sidebar = $id('sidebar');
const rightbar = $id('rightbar');
const sidebarMask = $id('mobile-sidebar-mask');
const rightbarMask = $id('mobile-rightbar-mask');
// 监听房间列表点击(移动端)
if (roomList) {
roomList.addEventListener('click', () => {
if (isMobile()) {
if (sidebar) sidebar.classList.remove('mobile-open');
if (sidebarMask) sidebarMask.classList.remove('active');
}
});
}
// 监听成员标签点击(移动端)
const memberTabs = $id('member-tabs');
if (memberTabs) {
memberTabs.addEventListener('click', () => {
if (isMobile()) {
if (rightbar) removeClass(rightbar, 'mobile-open');
if (rightbarMask) removeClass(rightbarMask, 'active');
}
});
}
});
// === 辅助函数 ===
/**
* 清空消息区域
* 用于UI重置或切换房间
*/
function clearChat() {
$id("chat-area").innerHTML = "";
}
/**
* Telegram风格输入框自动增高
* 随着用户输入内容增加,输入框自动调整高度
*/
function autoGrowInput() {
const input = $('.input-message-input');
if (!input) return;
input.style.height = 'auto';
input.style.height = input.scrollHeight + 'px';
}