/* ============================================================
* lib/components/group-chat.js · 仿企业微信电脑端群聊窗
* 用法:
*
*
* JSON:{ group, subtitle, members:[{name,avatar,role}],
* msgs:[{name,avatar,type:'text'|'card', text, at:[names], title, sub, tag}], footer }
* 消息文本内 @成员名 自动高亮为提及标签。
* 颜色全部来自 tokens.css 的 --chat-* / --brand-*(双主题自适应)。
* ============================================================ */
(function () {
function esc(s) {
return String(s == null ? '' : s)
.replace(/&/g, '&').replace(//g, '>');
}
function nl(s) {
return esc(s).replace(/\n/g, '
');
}
function parse(el) {
if (el.dataset.chat) { try { return JSON.parse(el.dataset.chat); } catch (e) { return null; } }
if (el.dataset.ref) {
var src = document.querySelector(el.dataset.ref);
if (src) { try { return JSON.parse(src.textContent); } catch (e) { return null; } }
}
return null;
}
// 把文本里的 @成员名 渲染成高亮提及
function mention(text, members) {
var s = esc(text);
members.forEach(function (m) {
var name = esc(m.name);
if (!name) return;
var re = new RegExp('(@' + name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + ')(?![^<]*>)', 'g');
s = s.replace(re, '$1');
});
return s;
}
function renderMsg(m, members) {
var text = '';
if (m.type === 'card') {
text = '
'
+ (m.title ? '
' + esc(m.title) + '
' : '')
+ (m.sub ? '
' + esc(m.sub) + '
' : '')
+ (m.tag ? '
' + esc(m.tag) + '
' : '')
+ '
';
} else {
text = '' + mention(m.text, members) + '
';
}
return ''
+ '
' + esc(m.avatar || (m.name || '?').slice(0, 1)) + ''
+ '
'
+ '
' + esc(m.name || '') + '
'
+ text
+ '
'
+ '
';
}
function render(el, d) {
if (!d) { el.innerHTML = '数据缺失
'; return; }
var members = d.members || [];
var memHTML = members.map(function (m) {
return ''
+ '
' + esc(m.avatar || (m.name || '?').slice(0, 1)) + ''
+ '
'
+ '
' + esc(m.name || '') + '
'
+ (m.role ? '
' + esc(m.role) + '
' : '')
+ '
'
+ '
';
}).join('');
var msgs = (d.msgs || []).map(function (m) { return renderMsg(m, members); }).join('');
el.innerHTML =
'' +
'
' + esc(d.group || '') +
(d.subtitle ? '' + esc(d.subtitle) + '' : '') +
'
' +
'
' +
'
' + memHTML + '
' +
'
' + msgs + '
' +
'
' +
(d.footer ? '' : '') +
'
';
}
var GroupChat = function () {
return Reflect.construct(HTMLElement, [], GroupChat);
};
GroupChat.prototype = Object.create(HTMLElement.prototype);
GroupChat.prototype.constructor = GroupChat;
GroupChat.prototype.connectedCallback = function () {
var self = this;
var d = parse(this);
if (!d && this.dataset.ref) {
setTimeout(function () { render(self, parse(self)); }, 0);
} else {
render(this, d);
}
};
if (!customElements.get('group-chat')) {
customElements.define('group-chat', GroupChat);
}
})();