+ style="position: sticky;max-width: 100%;margin-bottom: -30px;bottom: 0;z-index: 101;">
-
插入图片
diff --git a/ling_chair_http/index.js b/ling_chair_http/index.js
index ae3f0e7..50e4ae9 100644
--- a/ling_chair_http/index.js
+++ b/ling_chair_http/index.js
@@ -21,6 +21,28 @@
const UrlArgs = new URL(location.href).searchParams
+function setOnRightClick(e, cb) {
+ if (!(e instanceof jQuery))
+ e = $(e)
+
+ let longPressTimer
+ if (!cb) throw new Error("定义回调!!!!")
+ e.on('contextmenu', function (e) {
+ e.preventDefault() // 阻止默认右键菜单
+ cb()
+ })
+
+ e.on('mousedown', function () {
+ longPressTimer = setTimeout(function () {
+ cb()
+ }, 1000)
+ })
+
+ e.on('mouseup', function () {
+ clearTimeout(longPressTimer)
+ });
+}
+
if (UrlArgs.get("debug")) {
let script = document.createElement('script')
script.src = "//cdn.jsdelivr.net/npm/eruda"
@@ -130,10 +152,7 @@ viewBinding.drawerChangeServer.click(() => {
viewBinding.drawerSignOut.click(() => {
mdui.confirm('确定要登出账号吗', () => {
- localStorage.refreshToken = ""
- localStorage.isSignIn = false
-
- setTimeout(() => location.reload(), 300)
+ User.signOutAndReload()
}, () => { }, {
confirmText: "确定",
cancelText: "取消"
@@ -157,17 +176,26 @@ viewBinding.dialogSignInPasswd.keydown((e) => {
})
viewBinding.switchNotifications.click((a) => {
- if (localStorage.useNotifications === "true" || localStorage.useNotifications != null) {
- localStorage.useNotifications = false
+ if ((localStorage.useNotifications == "true" || localStorage.useNotifications != null) && localStorage.useNotifications != "false") {
+ localStorage.useNotifications = "false"
viewBinding.switchNotificationsIcon.text("notifications_off")
} else {
- localStorage.useNotifications = true
+ localStorage.useNotifications = "true"
viewBinding.switchNotificationsIcon.text("notifications")
}
})
-if (localStorage.useNotifications === "true")
+if (localStorage.useNotifications == "true")
viewBinding.switchNotificationsIcon.text("notifications")
+// https://www.runoob.com/w3cnote/javascript-copy-clipboard.html
+function copyText(t) {
+ let cp = viewBinding.textCopier.get(0)
+ cp.value = t
+ cp.select()
+ cp.setSelectionRange(0, 99999)
+ navigator.clipboard.writeText(cp.value)
+}
+
// https://zhuanlan.zhihu.com/p/162910462
Date.prototype.format = function (tms, format) {
let tmd = new Date(tms)
@@ -335,7 +363,7 @@ class ChatMsgAdapter {
// 错了 应该是客户端少发条才对 不然不能多设备同步
if (ChatMsgAdapter.target !== localStorage.userName && ChatMsgAdapter.type === "single") {
let i = ChatMsgAdapter.isAtBottom()
- await ChatMsgAdapter.addMsg(localStorage.userName, msg, re.data.time)
+ await ChatMsgAdapter.addMsg(localStorage.userName, msg, re.data.time, re.data.msgid)
if (i) ChatMsgAdapter.scrollToBottom()
}
})
@@ -367,9 +395,9 @@ class ChatMsgAdapter {
if (re) histroy = histroy.reverse()
for (let index in histroy) {
let i = histroy[index]
- let e = await this.addMsg(i.name, i.msg, i.time, re, true)
+ let e = await this.addMsg(i.name, i.msg, i.time, re, i.msgid)
// 因为某些因素直接DEBUG到吐血 断点继续都不报错 原因不明
- sc = sc + (e == null ? 20 : e.get(0).offsetTop)
+ sc = sc + (e == null ? 25 : e.get(0).offsetTop)
}
window.scrollBy({
top: sc,
@@ -385,11 +413,11 @@ class ChatMsgAdapter {
return e
}
static isAtBottom() {
- let elementRect = viewBinding.pageChatSeesion.get(0).getBoundingClientRect();
- return (elementRect.bottom <= window.innerHeight);
+ let elementRect = viewBinding.pageChatSeesion.get(0).getBoundingClientRect()
+ return (elementRect.bottom <= window.innerHeight)
}
// 不会压栈 只添加消息 返回消息的JQ对象
- static async addMsg(name, m, t, re) {
+ static async addMsg(name, m, t, re, msgid) {
let nick = await NickCache.getNick(name) // re.data == null ? name : re.data.nick
@@ -400,8 +428,8 @@ class ChatMsgAdapter {
temp = `` + nick + ` -- ` + msg + ` ++ ` + msg + `
@@ -411,8 +439,8 @@ class ChatMsgAdapter {
` + nick + ` -` @@ -477,6 +505,58 @@ class ChatMsgAdapter { static saveToLocal() { localStorage["chat_msg_" + this.target] = JSON.stringify(this.msgList) }*/ + // 为消息设置长按/右键事件 + 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) + let menuHtml = $.parseHTML(``) + let $menu = $(menuHtml) + e.before($menu) + menu = new mdui.Menu(e.get(0), menuHtml, { + position: "bottom", + align: "right", + // covered: true, + }) + $menu.on('closed.mdui.menu', () => { + $(menuHtml).remove() + }) + menu.open() + } + viewBinding.pageChatSeesion.on('contextmenu mousedown mouseup', '.message-content', (e) => { + let eventType = e.type + let self = $(e.target) + + // 根据事件类型执行不同操作 + switch (eventType) { + case 'contextmenu': + e.preventDefault() // 阻止默认行为 + callback(self) + break + case 'mousedown': + listeners[self + ""] = setTimeout(() => { + callback(self) + }, 300) // 300颗够吗 应该够吧 + break + case 'mouseup': + clearTimeout(listeners[self + ""]) + listeners[self + ""] = null + break + } + }) + } } class Hash { @@ -562,10 +642,24 @@ class User { client.emit("user.auth", { name: localStorage.userName, refreshToken: localStorage.refreshToken }, (re) => { if (re.code !== 0) { console.error(re) - return mdui.snackbar("验证用户失败!") + if (!re.invalid) + return mdui.snackbar("验证用户失败!") + + mdui.alert("账号刷新令牌已过期, 请重新登录哦", "提示", () => User.signOutAndReload(), { + confirmText: "确定", + closeOnConfirm: false, + closeOnEsc: false, + modal: true, + }) } }) } + 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])) @@ -579,7 +673,7 @@ class User { let n = new 通知().setTitle("新消息 - " + await NickCache.getNick(a.target)).setMessage(a.msg.msg).setIcon(User.getUserHeadUrl(a.target)).show(async () => { await ChatMsgAdapter.switchTo(a.target, a.type) - ChatMsgAdapter.scrollToBottom() + location.replace("#msgid_" + a.msg.msgid) n.close() }) }) @@ -642,3 +736,5 @@ else { // 感谢AI的力量 Stickyfill.add($("*").filter((a, b) => $(b).css('position') === 'sticky')) + +ChatMsgAdapter.initMsgElementEvents() diff --git a/ling_chair_http/mdui-prettier.css b/ling_chair_http/mdui-prettier.css index b1bec10..e3009e7 100644 --- a/ling_chair_http/mdui-prettier.css +++ b/ling_chair_http/mdui-prettier.css @@ -21,16 +21,19 @@ body { .mdui-menu-item > a { padding-right: 3px; } -.mdui-dialog-actions a, -.mdui-dialog-actions button { - border-radius: 40px; -} -.mdui-btn { +.mdui-btn:not(.mdui-btn-icon, .mdui-dialog-actions button, .mdui-dialog-actions a) { padding-left: 20px; padding-right: 20px; height: 40px; border-radius: 10px; } +.mdui-dialog-actions a, +.mdui-dialog-actions button { + padding-left: 20px; + padding-right: 20px; + height: 40px; + border-radius: 40px; +} /* 配色方案 */ diff --git a/server_src/val.js b/server_src/val.js index a75ff26..9ba2fa3 100644 --- a/server_src/val.js +++ b/server_src/val.js @@ -9,7 +9,7 @@ const io = require("./iolib") let vals = {} // 配置目录 -vals.LINGCHAIR_CONFIG_DIR = "ling_chair_config" +vals.LINGCHAIR_CONFIG_DIR = "ling_chair_data" // HTTP 服务器资源目录 vals.LINGCHAIR_HTTP_DIR = "ling_chair_http" // 服务端配置 diff --git a/server_src/wsApi.js b/server_src/wsApi.js index cec1c23..834f070 100644 --- a/server_src/wsApi.js +++ b/server_src/wsApi.js @@ -46,7 +46,7 @@ let api = { return cb({ msg: "参数缺失", code: -1 }) if (!users.checkRefreshToken(a.name, a.refreshToken)) - return cb({ code: -1, msg: "刷新令牌错误" }) + return cb({ code: -1, msg: "刷新令牌错误", invalid: true }) log(color.yellow + "客户端 " + client.handshake.address + " 完成了用户 " + a.name + " 的验证" + color.none) @@ -193,7 +193,7 @@ let api = { log("尝试向客户端 " + v.handshake.address + " 发送事件 [msg.receive], 参数为 " + JSON.stringify(args)) }) - cb({ msg: msg, code: 0, data: { time: time } }) + cb({ msg: msg, code: 0, data: { time: time, msgid: msgid } }) }, // 单聊获取历史记录- ` + msg + ` ++ ` + msg + `