8 Commits

Author SHA1 Message Date
MoonLeeeaf
1a5afc8ad0 chore: rename symbols, add "原文" menu 2024-06-14 19:31:42 +08:00
MoonLeeeaf
4bdfad340f fix: image 2024-06-12 22:07:50 +08:00
MoonLeeeaf
6ac1b460bb feat: Markdown Code Dialog 2024-06-12 21:48:39 +08:00
MoonLeeeaf
29e224f87a test 2024-06-12 21:05:24 +08:00
MoonLeeeaf
a39973bb5c feat: markdown support 2024-06-11 22:03:41 +08:00
MoonLeeeaf
47afacbba3 chore: make limit happy 2024-06-01 14:33:40 +08:00
MoonLeeeaf
3a4d733c13 chore: 修改哈希输出(Base64改为Hex) 2024-06-01 14:33:26 +08:00
MoonLeeeaf
89263e6e2a chore: 命名 2024-06-01 14:09:45 +08:00
8 changed files with 331 additions and 108 deletions

View File

@@ -82,4 +82,10 @@
width: 50px;
height: 50px;
border-radius: 50%;
}
}
.message-image {
max-width: 40%;
max-height: 40%;
border-radius: 15px;
}

View File

@@ -0,0 +1,97 @@
/*
* ©2024 满月叶
* Github: MoonLeeeaf
* 最终执行的杂项
*/
// 感觉 window.attr 比那一堆 import 好用多了
// ================================
// 正文开始
// ================================
// 没有刷新令牌需要重新登录 或者初始化
if (!localStorage.refreshToken || localStorage.refreshToken === "")
localStorage.isSignIn = false
if (!localStorage.server || localStorage.server === "")
setUpClient()
else
setUpClient(localStorage.server)
// 登录到账号
let dialogSignIn
// 谨防 localStorage 字符串数据大坑
if (localStorage.isSignIn == "false")
dialogSignIn = new mdui.Dialog(viewBinding.dialogSignIn.get(0), {
modal: true,
closeOnEsc: false,
history: false,
}).open()
else {
(async () => viewBinding.userNick.text(await NickCache.getNick(localStorage.userName)))()
let hello
let nowHour = new Date().getHours()
if (nowHour >= 6 && nowHour <= 11) hello = "早安"
else if (nowHour == 12) hello = "中午好"
else if (nowHour >= 13 && nowHour <= 18) hello = "下午好"
else if (nowHour >= 19 && nowHour < 22) hello = "晚上好"
else hello = "晚安"
viewBinding.helloText.text(hello)
viewBinding.userHead.attr("src", CurrentUser.getUserHeadUrl(localStorage.userName))
ContactsList.reloadList()
CurrentUser.registerCallback()
}
// 感谢AI的力量
Stickyfill.add($("*").filter((a, b) => $(b).css('position') === 'sticky'))
ChatMsgAdapter.initMsgElementEvents()
ChatMsgAdapter.initInputResizer()
const showLinkDialog = (link) => mdui.alert(decodeURI(link) + "<br/>如果你确认此链接是安全的, 那么请<a class=\"mdui-text-color-theme-accent\" href=\"" + link + "\">点我</a>", '链接', () => { }, { confirmText: "关闭" })
const showImageDialog = (link, id, alt) => mdui.alert(`此图片链接来源未知: ${decodeURI(link)}<br/>如果你希望加载, 请<a class="mdui-text-color-theme-accent" mdui-dialog-close onclick="$('#${id}').html('<img src=\\'${link}\\' alt=\\'${decodeURI(alt)}\\' class=\\'message-image\\'></img>')">点我</a>`, '外部图片', () => { }, { confirmText: "关闭" })
const showCodeDialog = (code) => mdui.alert(`<pre><code>${decodeURI(code)}</code></pre>`, '代码块', () => { }, { confirmText: "关闭" })
const renderer = {
heading(text, level) {
return text
},
paragraph(text) {
return text
},
blockquote(text) {
return text
},
link(href, title, text) {
return `<a class="mdui-text-color-theme-accent" onclick="showLinkDialog('${encodeURI(href)}')">[链接] ${text}</a>`
},
image(href, title, text) {
let h = Hash.sha256(href)
let out = true
try {
out = new URL(href).hostname === new URL(location.href)
} catch(e) {}
if (out)
return `<img src="${encodeURI(href)}" alt="${text}" class="message-image"></img>`
else
return `<div id="${h}"><a class="mdui-text-color-theme-accent" onclick="showImageDialog('${encodeURI(href)}', '${h}', '${encodeURI(text)}')">[外部图片] ${text}</a></div>`
},
code(src) {
return `<a class="mdui-text-color-theme-accent" onclick="showCodeDialog(\`${encodeURI(src)}\`)">[代码块]</a>`
},
}
marked.use({
gfm: true,
renderer: renderer,
async: true,
})

View File

@@ -3,9 +3,19 @@
* Github: MoonLeeeaf
* 业务逻辑
*/
class User {
// ================================
// 当前用户
// ================================
class CurrentUser {
static myAccessToken
// 登录账号 通过回调函数返回刷新令牌
/**
* 登录账号
* @param {String} name
* @param {String} passwd
* @param {Function} callback
*/
static signIn(name, passwd, cb) {
client.emit("user.signIn", {
name: name,
@@ -17,6 +27,12 @@ class User {
cb(re)
})
}
/**
* 注册账号
* @param {String} name
* @param {String} passwd
* @param {Function} callback
*/
static signUp(name, passwd, cb) {
client.emit("user.signUp", {
name: name,
@@ -28,7 +44,11 @@ class User {
cb(re)
})
}
// 为登录对话框编写的
/**
* 登录对话框中的登录逻辑
* @param {String} name
* @param {String} passwd
*/
static signInWithDialog(name, passwd) {
this.signIn(name, passwd, (re) => {
localStorage.refreshToken = re.data.refreshToken
@@ -37,6 +57,11 @@ class User {
location.reload()
})
}
/**
* 设置昵称
* @param {String} nick
* @param {Function} callback
*/
static async setNick(nick, cb) {
client.emit("user.setNick", {
name: localStorage.userName,
@@ -48,10 +73,19 @@ class User {
if (cb) cb()
})
}
// 获取头像链接
/**
* 获取用户头像的链接
* @param {String} name
* @returns {String} headImageUrl
*/
static getUserHeadUrl(name) {
return client.io.uri + "/users_head/" + name + ".png"
}
/**
* 获取访问密钥
* @param {String} name
* @returns {Promise<String>} accessToken
*/
static async getAccessToken(er) {
if (this.myAccessToken == null)
this.myAccessToken = await new Promise((res) => {
@@ -62,17 +96,27 @@ class User {
})
return this.myAccessToken
}
/**
* 请求上传头像
*/
static uploadHeadImage() {
viewBinding.uploadHeadImage.click()
}
/**
* 上传头像回调事件
* @param {Element} element
*/
static async uploadHeadImageCallback(self) {
let img = self.files[0]
client.emit("user.setHeadImage", {
name: localStorage.userName,
accessToken: await User.getAccessToken(),
accessToken: await CurrentUser.getAccessToken(),
headImage: img,
}, (re) => mdui.snackbar(re.msg))
}
/**
* 验证用户
*/
static auth() {
client.emit("user.auth", { name: localStorage.userName, refreshToken: localStorage.refreshToken }, (re) => {
if (re.code !== 0) {
@@ -80,7 +124,7 @@ class User {
if (!re.invalid)
return mdui.snackbar("验证用户失败!")
mdui.alert("账号刷新令牌已过期, 请重新登录哦", "提示", () => User.signOutAndReload(), {
mdui.alert("账号刷新令牌已过期, 请重新登录哦", "提示", () => CurrentUser.signOutAndReload(), {
confirmText: "确定",
closeOnConfirm: false,
closeOnEsc: false,
@@ -89,12 +133,18 @@ class User {
}
})
}
/**
* 登出并重载页面
*/
static signOutAndReload() {
localStorage.refreshToken = ""
localStorage.isSignIn = false
setTimeout(() => location.reload(), 300)
}
/**
* 注册客户端回调事件
*/
static registerCallback() {
client.on("msg.receive", async (a) => {
if (checkEmpty([a.target, a.msg, a.type]))
@@ -107,7 +157,7 @@ class User {
}
if (ChatMsgAdapter.target !== localStorage.userName) {
let n = new 通知().setTitle("" + await NickCache.getNick(a.target)).setMessage(a.msg.msg).setIcon(User.getUserHeadUrl(a.target)).show(async () => {
let n = new 通知().setTitle("" + await NickCache.getNick(a.target)).setMessage(a.msg.msg).setIcon(CurrentUser.getUserHeadUrl(a.target)).show(async () => {
await ChatMsgAdapter.switchTo(a.target, a.type)
location.replace("#msgid_" + a.msg.msgid)
n.close()
@@ -115,15 +165,28 @@ class User {
}
})
}
/**
* 打开资料卡
* @param {String} name
*/
static async openProfileDialog(name) {
viewBinding.dialogProfileHead.attr("src", User.getUserHeadUrl(name))
viewBinding.dialogProfileHead.attr("src", CurrentUser.getUserHeadUrl(name))
viewBinding.dialogProfileNick.text(await NickCache.getNick(name))
new mdui.Dialog(viewBinding.dialogProfile).open()
}
}
// ================================
// 昵称缓存
// ================================
class NickCache {
static data = {}
/**
* 获取昵称
* @param {String} name
* @returns {String} nick
*/
static async getNick(name) {
return await new Promise((res, rej) => {
// 这个this别摆着不放啊 不然两下就会去世
@@ -142,10 +205,13 @@ class NickCache {
}
class ContactsList {
/**
* 重载联系人列表
*/
static async reloadList() {
client.emit("user.getFriends", {
name: localStorage.userName,
accessToken: await User.getAccessToken(),
accessToken: await CurrentUser.getAccessToken(),
}, async (re) => {
if (re.code !== 0)
return mdui.snackbar(re.msg)
@@ -155,19 +221,25 @@ class ContactsList {
for (let index in ls) {
let name = ls[index]
let dick = await NickCache.getNick(name)
$($.parseHTML(`<li class="mdui-list-item mdui-ripple" mdui-drawer-close><div class="mdui-list-item-avatar"><img src="` + User.getUserHeadUrl(name) + `" onerror="this.src='res/default_head.png'" /></div><div class="mdui-list-item-content">` + dick + `</div></li>`)).appendTo(viewBinding.contactsList).click(() => {
$($.parseHTML(`<li class="mdui-list-item mdui-ripple" mdui-drawer-close><div class="mdui-list-item-avatar"><img src="` + CurrentUser.getUserHeadUrl(name) + `" onerror="this.src='res/default_head.png'" /></div><div class="mdui-list-item-content">` + dick + `</div></li>`)).appendTo(viewBinding.contactsList).click(() => {
ChatMsgAdapter.switchTo(name, "single")
})
}
})
}
// 添加联系人,好友或者群聊
/**
* 添加联系人/群峦
* @param {String} nameOrId
*/
static add(name, type) {
if (type == "single") {
}
}
/**
* 打开添加联系人的对话框
*/
static openAddDialog() {
new mdui.Dialog(viewBinding.dialogNewContact.get(0)).open()
}
@@ -180,6 +252,11 @@ class ChatPage {
constructor(name, type) {
}
/**
* 切换到某一个聊天对象
* @param {String} name
* @param {String} type
*/
static switchTo(name, type) {
if (!this.cached[name])
this.cached[name] = new ChatPage(name, type)
@@ -191,9 +268,13 @@ class ChatMsgAdapter {
static target
static minMsgId
static time
static bbn
static minutesCache
static resizeDick
// 切换聊天对象
/**
* 切换到某一个聊天对象
* @param {String} name
* @param {String} type
*/
static async switchTo(name, type) {
viewBinding.tabChatSeesion.show()
viewBinding.tabChatSeesion.text(await NickCache.getNick(name))
@@ -208,13 +289,16 @@ class ChatMsgAdapter {
await this.loadMore()
this.scrollToBottom()
}
// 发送消息
/**
* 发送消息
* @param {String} msg
*/
static async send(msg) {
client.emit("user.sendSingleMsg", {
name: localStorage.userName,
target: this.target,
msg: msg,
accessToken: await User.getAccessToken(),
accessToken: await CurrentUser.getAccessToken(),
}, async (re) => {
if (re.code !== 0)
return mdui.snackbar(re.msg)
@@ -231,13 +315,18 @@ class ChatMsgAdapter {
}
})
}
/**
* 获取聊天消息记录
* @param {int} 起始点
* @param {int} 获取数量
*/
static async getHistroy(start, limit) {
return new Promise(async (res, rej) => {
client.emit("user.getSingleChatHistroy", {
name: localStorage.userName,
target: this.target,
limit: limit,
accessToken: await User.getAccessToken(),
accessToken: await CurrentUser.getAccessToken(),
startId: start,
}, (re) => {
if (re.code !== 0)
@@ -246,6 +335,10 @@ class ChatMsgAdapter {
})
})
}
/**
* 加载更多聊天记录
* @param {int}} 加载数量
*/
static async loadMore(limit) {
let histroy = await this.getHistroy(this.minMsgId, limit == null ? 13 : limit)
@@ -267,6 +360,12 @@ class ChatMsgAdapter {
behavior: 'smooth'
})
}
/**
* 添加系统消息
* @param {String} 消息
* @param {String} 是否加到顶部
* @returns {jQuery} 消息元素
*/
static addSystemMsg(m, re) {
let e
if (re)
@@ -277,65 +376,93 @@ class ChatMsgAdapter {
e = $($.parseHTML(m)).appendTo(viewBinding.pageChatSeesion)
return e
}
/**
* 是否在底部
* @returns {Boolean} 是否在底部
*/
static isAtBottom() {
let elementRect = viewBinding.pageChatSeesion.get(0).getBoundingClientRect()
return (elementRect.bottom <= window.innerHeight)
}
// 添加消息 返回消息的JQ对象
// name: 用户id m: 消息 t: 时间戳 re: 默认加到尾部 msgid: 消息id
static async addMsg(name, m, t, re, msgid) {
/**
* 添加聊天记录
* @param {String} name
* @param {String} msg
* @param {String} type
* @param {String} 是否加到头部
* @param {String || int} 消息id
* @returns {jQuery} 消息元素
*/
static async addMsg(name, preMsg, time, addToTop, msgid) {
let nick = await NickCache.getNick(name) // re.data == null ? name : re.data.nick
let msg = escapeHTML(m)
let msg
try {
msg = await marked.parse(preMsg)
} catch(error) {
console.log("解析消息失败: " + error)
msg = escapeHTML(preMsg)
}
let temp
if (name === localStorage.userName)
temp = `<div class="chat-message-right">
<div class="message-content-with-nickname-right">
<span class="nickname">` + nick + `</span>
<div class="message-content mdui-card" id="msgid_` + msgid + `">
<span id="msg-content">` + msg + `</span>
<span class="nickname">${ nick }</span>
<div class="message-content mdui-card" tag="msg-card" id="msgid_${ msgid }">
<span id="msg-content">${ msg }</span>
<pre class="mdui-hidden" id="raw-msg-content">${ preMsg }</pre>
</div>
</div>
<img class="avatar" src="` + User.getUserHeadUrl(name) + `" onerror="this.src='res/default_head.png'" />
<img class="avatar" src="${ CurrentUser.getUserHeadUrl(name) }" onerror="this.src='res/default_head.png'" />
</div>`
else
temp = `<div class="chat-message-left">
<img class="avatar" src="` + User.getUserHeadUrl(name) + `" onerror="this.src='res/default_head.png'" />
<img class="avatar" src="${ CurrentUser.getUserHeadUrl(name) }" onerror="this.src='res/default_head.png'" />
<div class="message-content-with-nickname-left">
<span class="nickname">` + nick + `</span>
<div class="message-content mdui-card" id="msgid_` + msgid + `">
<span id="msg-content">` + msg + `</span>
<span class="nickname">${ nick }</span>
<div class="message-content mdui-card" tag="msg-card" id="msgid_${ msgid }">
<span id="msg-content">${ msg }</span>
<pre class="mdui-hidden" id="raw-msg-content">${ preMsg }</pre>
</div>
</div>
</div>`
let bn = new Date(t).getMinutes()
let e
if (re) {
this.addSystemMsg(temp, re)
if (this.bbn != bn) {
e = this.addSystemMsg(`<div class="mdui-center">` + new Date().format(t == null ? Date.parse("1000-1-1 00:00:00") : t, "yyyy年MM月dd日 hh:mm:ss") + `</div>`, re)
this.time = bn
let nowMinutes = new Date(time).getMinutes()
let msgElement
if (addToTop) {
this.addSystemMsg(temp, addToTop)
if (this.minutesCache != nowMinutes) {
msgElement = this.addSystemMsg(`<div class="mdui-center">` + new Date().format(time == null ? Date.parse("1000-1-1 00:00:00") : time, "yyyy年MM月dd日 hh:mm:ss") + `</div>`, addToTop)
this.time = nowMinutes
}
} else {
if (this.bbn != bn) {
e = this.addSystemMsg(`<div class="mdui-center">` + new Date().format(t == null ? Date.parse("1000-1-1 00:00:00") : t, "yyyy年MM月dd日 hh:mm:ss") + `</div>`, re)
this.time = bn
if (this.minutesCache != nowMinutes) {
msgElement = this.addSystemMsg(`<div class="mdui-center">` + new Date().format(time == null ? Date.parse("1000-1-1 00:00:00") : time, "yyyy年MM月dd日 hh:mm:ss") + `</div>`, addToTop)
this.time = nowMinutes
}
this.addSystemMsg(temp, re)
this.addSystemMsg(temp, addToTop)
}
this.bbn = new Date(t).getMinutes()
this.minutesCache = new Date(time).getMinutes()
return e
return msgElement
}
// 从服务器加载一些聊天记录, limit默认=13
/**
* 从服务器加载一些聊天记录
* @param {int} 数量
*/
static async loadMsgs(limit) {
let histroy = await this.getHistroy(this.msgList[0] == null ? null : this.msgList[0].msgid - 1, limit == null ? 13 : limit)
this.msgList = histroy
}
/**
* 滑到底部
*/
static scrollToBottom() {
// 吐了啊 原来这样就行了 我何必在子element去整啊
viewBinding.chatPager.get(0).scrollBy({
@@ -343,7 +470,9 @@ class ChatMsgAdapter {
behavior: 'smooth'
})
}
// 自动调整使输入框置底 CSS真tm靠不住啊
/**
* 初始化输入框位置调整器
*/
static initInputResizer() {
// 实验表面移动端切出输入法时会触发1-2次resize事件
// 可以利用这个特性来实现自动滚动文本
@@ -365,19 +494,25 @@ class ChatMsgAdapter {
window.addEventListener("resize", resize)
resize()
}
// 为消息设置长按/右键事件
/**
* 初始化消息框右击事件
*/
static initMsgElementEvents() {
let listeners = {}
let menu
let callback = (e) => {
if (menu) menu.close()
// 从 span 切到 div
if (e.get(0).tagName.toLowerCase() != "div") e = $(e.get(0).parentNode)
// 从 消息框 切到 更上层
e = $(e.get(0).parentNode)
// 切到 div.message-content
let ele = e.get(0)
while ($(ele).attr("tag") != "msg-card")
ele = ele.parentNode
e = $(ele)
let menuHtml = $.parseHTML(`<ul class="mdui-menu menu-on-message">
<li class="mdui-menu-item">
<a onclick="copyText(\`` + e.find("#msg-content").text() + `\`)" class="mdui-ripple">复制</a>
<a onclick="copyText(\`${ e.find("#msg-content").text() }\`)" class="mdui-ripple">复制</a>
</li>
<li class="mdui-menu-item">
<a onclick="mdui.alert(\`${ e.find("#raw-msg-content").text() }\`, '消息原文', () => { }, { confirmText: '关闭' })" class="mdui-ripple">原文</a>
</li>
<li class="mdui-menu-item">
<a onclick="mdui.alert('未制作功能', '提示', () => { }, { confirmText: '关闭' })" class="mdui-ripple">转发</a>
@@ -421,13 +556,16 @@ class ChatMsgAdapter {
}
}
/**
* 刷新联系人列表以及昵称缓存
*/
function refreshAll() {
ContactsList.reloadList()
delete NickCache.data
NickCache.data = {}
}
window.User = User
window.User = CurrentUser
window.ContactsList = ContactsList
window.NickCache = NickCache
window.ChatPage = ChatPage

View File

@@ -25,6 +25,7 @@
<script src="https://cdn.jsdelivr.net/gh/wilddeer/stickyfill@2.1.0/dist/stickyfill.min.js"></script>
<script src="https://unpkg.com/jquery@3.7.1/dist/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/clipboard@2.0.11/dist/clipboard.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<link rel="icon" href="res/icon.ico" />
<title>铃之椅</title>
</head>
@@ -184,9 +185,9 @@
</div>
<div class="mdui-dialog-actions">
<button class="mdui-btn mdui-ripple"
onclick="User.signUp(viewBinding.dialogSignInName.val(), viewBinding.dialogSignInPasswd.val(), () => mdui.snackbar('注册成功, 请直接点击登录即可~'))">注册</button>
onclick="CurrentUser.signUp(viewBinding.dialogSignInName.val(), viewBinding.dialogSignInPasswd.val(), () => mdui.snackbar('注册成功, 请直接点击登录即可~'))">注册</button>
<button class="mdui-btn mdui-ripple" n-id="dialogSignInEnter"
onclick="User.signInWithDialog(viewBinding.dialogSignInName.val(), viewBinding.dialogSignInPasswd.val())">登录</button>
onclick="CurrentUser.signInWithDialog(viewBinding.dialogSignInName.val(), viewBinding.dialogSignInPasswd.val())">登录</button>
</div>
</div>
</div>
@@ -221,7 +222,7 @@
<button class="mdui-btn mdui-ripple" n-id="dialogEditNickClose" mdui-dialog-close
onclick="new mdui.Dialog(viewBinding.dialogSettings.get(0)).open()">关闭</button>
<button class="mdui-btn mdui-ripple"
onclick="User.setNick(viewBinding.dialogEditNickNick.val(), () => {mdui.snackbar('已保存, 刷新页面生效');viewBinding.dialogEditNickClose.click()})">保存</button>
onclick="CurrentUser.setNick(viewBinding.dialogEditNickNick.val(), () => {mdui.snackbar('已保存, 刷新页面生效');viewBinding.dialogEditNickClose.click()})">保存</button>
</div>
</div>
@@ -276,7 +277,7 @@
<i class="mdui-list-item-icon mdui-icon material-icons">edit</i>
<div class="mdui-list-item-content">修改昵称</div>
</li>
<li class="mdui-list-item mdui-ripple" onclick="User.uploadHeadImage()">
<li class="mdui-list-item mdui-ripple" onclick="CurrentUser.uploadHeadImage()">
<i class="mdui-list-item-icon mdui-icon material-icons">account_circle</i>
<div class="mdui-list-item-content">上传头像</div>
</li>
@@ -289,7 +290,7 @@
</div>
<div class="mdui-hidden">
<input type="file" n-id="uploadHeadImage" name="选择头像" onchange="User.uploadHeadImageCallback(this)"
<input type="file" n-id="uploadHeadImage" name="选择头像" onchange="CurrentUser.uploadHeadImageCallback(this)"
accept="image/png, image/jpeg" />
</div>
@@ -302,7 +303,7 @@
<script src="manager.js"></script>
<script src="ui.js"></script>
<script src="handler.js"></script>
<script src="index.js"></script>
<script src="finally.js"></script>
</body>
</html>

View File

@@ -1,50 +0,0 @@
/*
* ©2024 满月叶
* Github: MoonLeeeaf
* 最终执行的杂项
*/
// 感觉 window.attr 比那一堆 import 好用多了
// 没有刷新令牌需要重新登录 或者初始化
if (!localStorage.refreshToken || localStorage.refreshToken === "")
localStorage.isSignIn = false
if (!localStorage.server || localStorage.server === "")
setUpClient()
else
setUpClient(localStorage.server)
// 登录到账号
let dialogSignIn
// 谨防 localStorage 字符串数据大坑
if (localStorage.isSignIn == "false")
dialogSignIn = new mdui.Dialog(viewBinding.dialogSignIn.get(0), {
modal: true,
closeOnEsc: false,
history: false,
}).open()
else {
(async () => viewBinding.userNick.text(await NickCache.getNick(localStorage.userName)))()
let hello
let nowHour = new Date().getHours()
if (nowHour >= 6 && nowHour <= 11) hello = "早安"
else if (nowHour == 12) hello = "中午好"
else if (nowHour >= 13 && nowHour <= 18) hello = "下午好"
else if (nowHour >= 19 && nowHour < 22) hello = "晚上好"
else hello = "晚安"
viewBinding.helloText.text(hello)
viewBinding.userHead.attr("src", User.getUserHeadUrl(localStorage.userName))
ContactsList.reloadList()
User.registerCallback()
}
// 感谢AI的力量
Stickyfill.add($("*").filter((a, b) => $(b).css('position') === 'sticky'))
ChatMsgAdapter.initMsgElementEvents()
ChatMsgAdapter.initInputResizer()

View File

@@ -8,6 +8,10 @@ const viewBinding = NData.mount($("#app").get(0))
let client
/**
* 初始化客户端
* @param {String} 服务器地址
*/
function setUpClient(server) {
if (server && server !== "")
client = new io(server, {

View File

@@ -62,6 +62,10 @@ function escapeHTML(str) {
}
class NData {
/**
* 获取 MD5sum
* @param {String} 数据
*/
static mount(node) {
// 便捷获得指定组件
let es = node.querySelectorAll("[n-id]")
@@ -80,6 +84,11 @@ class NData {
}
// https://www.runoob.com/w3cnote/javascript-copy-clipboard.html
/**
* 复制文字
* @param {String} 欲复制的文本
*/
function copyText(t) {
let btn = $("[n-id=textCopierBtn]")
btn.attr("data-clipboard-text", t)
@@ -90,6 +99,13 @@ function copyText(t) {
}
// https://zhuanlan.zhihu.com/p/162910462
/**
* 格式化日期
* @param {int} 时间戳
* @param {String} 欲格式化的文本
* @returns {String} 格式后的文本
*/
Date.prototype.format = function (tms, format) {
let tmd = new Date(tms)
/*
@@ -164,11 +180,21 @@ class 通知 {
}
class Hash {
/**
* 获取 MD5sum
* @param {String} 数据
* @returns {String} Hex化的哈希值
*/
static md5(data) {
return CryptoJS.MD5(data).toString(CryptoJS.enc.Base64)
return CryptoJS.MD5(data).toString(CryptoJS.enc.Hex)
}
/**
* 获取 SHA256sum
* @param {String} 数据
* @returns {String} Hex化的哈希值
*/
static sha256(data) {
return CryptoJS.SHA256(data).toString(CryptoJS.enc.Base64)
return CryptoJS.SHA256(data).toString(CryptoJS.enc.Hex)
}
}

View File

@@ -48,7 +48,8 @@ if (!io.exists(vals.LINGCHAIR_SERVER_CONFIG_FILE)) io.open(vals.LINGCHAIR_SERVER
cert: "",
},
})).close()
if (!io.exists(vals.LINGCHAIR_USERS_COUNT_FILE)) io.open(vals.LINGCHAIR_USERS_COUNT_FILE, "w").write("10000").close()
if (!io.exists(vals.LINGCHAIR_USERS_COUNT_FILE))
io.open(vals.LINGCHAIR_USERS_COUNT_FILE, "w").write("10000").close()
// 加载服务端配置文件
vals.LINGCHAIR_SERVER_CONFIG = JSON.parse(io.open(vals.LINGCHAIR_SERVER_CONFIG_FILE, "r").read("*a"))