This commit is contained in:
koplenov 2026-05-10 02:58:44 +03:00
parent 1c288a9b47
commit 360f8aebd5

View file

@ -102,6 +102,7 @@
on_marker: ((kind: 'received' | 'displayed' | 'acknowledged', msg_id: string, from: string) => void) | null = null
on_avatar_meta: ((from: string, info: { id: string; mime: string } | null) => void) | null = null
on_presence: ((jid: string, show: string, status: string) => void) | null = null
on_muc_presence: ((room_jid: string, nick: string, real_bare?: string) => void) | null = null
on_error: ((err: string) => void) | null = null
on_room_error: ((err: string) => void) | null = null
on_close: (() => void) | null = null
@ -693,7 +694,17 @@ private _handle_message(el: Element) {
// MUC room presence — from contains resource (nick)
const slash = from_full.indexOf('/')
if (slash >= 0) return // ignore occupant presence updates for now
if (slash >= 0) {
const room_jid = from_full.slice(0, slash)
const nick = from_full.slice(slash + 1)
// Extract real JID from MUC presence
const muc_x = el.querySelector('x[xmlns="http://jabber.org/protocol/muc#user"]')
const item = muc_x?.querySelector('item')
const real_jid_full = item?.getAttribute('jid') || ''
const real_bare = real_jid_full.split('/')[0]
this.on_muc_presence?.(room_jid, nick, real_bare || undefined)
return
}
const from = from_full || ''
if (!from) return
@ -717,6 +728,7 @@ private _handle_message(el: Element) {
private _fin_count = new Map<string, number>()
private _scroll_setup = new Set<string>() // scroll listener installed
private _rooms = new Map<string, Xmpp_room>()
private _room_occupants = new Map<string, Map<string, string>>() // room_jid → nick → real_bare_jid
private _oldest_time = new Map<string, number>() // room_jid → oldest msg timestamp
private _poll_timer: number | null = null
private _poll_count: number = 0
@ -809,8 +821,10 @@ private _handle_message(el: Element) {
contact_avatar_uri(jid: string) {
const room = this._rooms.get(jid)
const avatar = this.avatar_uri(jid)
if (avatar) return avatar
if (room) return this._default_avatar(jid, room.name || jid.split('@')[0])
return this.avatar_uri(jid) || this._default_avatar(jid)
return this._default_avatar(jid)
}
chat_avatar_uri(jid: string) { return this.contact_avatar_uri(jid) }
@ -819,7 +833,18 @@ private _handle_message(el: Element) {
msg_avatar_uri(id: string) {
const msg = this._msg_by_id.get(id)
if (!msg) return ''
if (msg.nick !== undefined) return this._default_avatar(`${ msg.from }/${ msg.nick }`, msg.nick)
if (msg.nick !== undefined) {
const room = this._rooms.get(msg.from)
if (room?.nick === msg.nick) return this.my_avatar_uri()
// Try to get real JID for the nick
const occupants = this._room_occupants.get(msg.from)
const real_bare = occupants?.get(msg.nick)
if (real_bare) {
const avatar = this.avatar_uri(real_bare)
if (avatar) return avatar
}
return this._default_avatar(`${ msg.from }/${ msg.nick }`, msg.nick)
}
return this.avatar_uri(msg.from) || this._default_avatar(msg.from)
}
@ -1242,6 +1267,7 @@ private _handle_message(el: Element) {
const nick = b.nick || my_nick
const room: Xmpp_room = { jid: b.jid, name: b.name || b.jid.split('@')[0], nick }
this._rooms.set(b.jid, room)
void this._load_avatar(b.jid)
if (b.autojoin) this._conn?.join_room(b.jid, nick)
}
this.rooms([ ...this._rooms.values() ])
@ -1259,6 +1285,17 @@ private _handle_message(el: Element) {
}
void this._fetch_avatar_with(from, info.id, info.mime)
}
conn.on_muc_presence = (room_jid, nick, real_bare) => {
if (real_bare) {
let occupants = this._room_occupants.get(room_jid)
if (!occupants) {
occupants = new Map()
this._room_occupants.set(room_jid, occupants)
}
occupants.set(nick, real_bare)
void this._load_avatar(real_bare)
}
}
conn.on_message = msg => {
if (this._msg_by_id.has(msg.id)) return // ← FIX: skip duplicates
this._add_message(msg)
@ -1431,6 +1468,7 @@ private _handle_message(el: Element) {
this._conn.join_room(jid, nick)
const room: Xmpp_room = { jid, name: jid.split('@')[0], nick }
this._rooms.set(jid, room)
void this._load_avatar(jid)
this.rooms([ ...this._rooms.values() ])
this.search_query('')
this.$.$mol_state_arg.value('chat', jid)
@ -1466,6 +1504,7 @@ private _handle_message(el: Element) {
this._conn.join_room(jid, nick)
const room: Xmpp_room = { jid, name: jid.split('@')[0], nick }
this._rooms.set(jid, room)
void this._load_avatar(jid)
this.rooms([ ...this._rooms.values() ])
this.room_jid('')
this.$.$mol_state_arg.value('chat', jid)
@ -1476,6 +1515,7 @@ private _handle_message(el: Element) {
if (!room) return
this._conn?.leave_room(jid, room.nick)
this._rooms.delete(jid)
this._room_occupants.delete(jid)
this.rooms([ ...this._rooms.values() ])
this._msgs = this._msgs.filter(m => m.from !== jid && m.to !== jid)
this._msg_by_id.forEach((m, k) => { if (m.from === jid || m.to === jid) this._msg_by_id.delete(k) })
@ -1629,9 +1669,9 @@ private _handle_message(el: Element) {
if (this._rooms.has(jid)) {
this.compose(jid, '')
this._conn.send_groupchat(jid, text)
this._scroll_to_bottom(jid)
return
const id = `l${ Date.now() }_${ Math.random().toString(36).slice(2) }`
this._conn.send_groupchat(jid, text, id)
this._add_message({ id, from: this.my_jid().split('/')[0], to: jid, body: text, time: Date.now() })
}
this.compose(jid, '')