/* ============================================================
* lib/components/chat-window.js · 仿微信一对一聊天窗
* 用法:
*
* // 短数据
*
* // 长数据
* 消息类型:text / transfer(转账卡) / time(时间) / divider(分隔) / image / quote
* 全部颜色来自 tokens.css 的 --chat-*(双主题自适应)。
* ============================================================ */
(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 renderMsg(m) {
var side = m.side === 'out' ? 'out' : 'in';
if (m.type === 'time') {
return '
' + esc(m.text) + '
';
}
if (m.type === 'divider') {
return '' + esc(m.text) + '
';
}
// 带气泡的消息
var ava = '' + esc(m.avatar || (side === 'out' ? '我' : '')) + '
';
var inner = '';
if (m.type === 'transfer') {
inner = ''
+ '' + esc(m.text || '微信转账') + ''
+ '' + esc(m.amount || '') + ''
+ '
';
} else if (m.type === 'image') {
inner = ' + ')
'
+ (m.caption ? '
' + esc(m.caption) + '
' : '')
+ '
';
} else if (m.type === 'quote') {
inner = '' + nl(m.text)
+ (m.source ? '
' + esc(m.source) + '
' : '')
+ '
';
} else {
var body = nl(m.text);
if (m.bold) body = '' + body + '';
inner = '' + body + '
';
}
return '' + (side === 'in' ? ava + inner : inner + ava) + '
';
}
function render(el, d) {
if (!d) { el.innerHTML = '数据缺失
'; return; }
var msgs = (d.msgs || []).map(renderMsg).join('');
el.innerHTML =
'' +
(d.title || d.subtitle ? (
'
' + esc(d.title || '') +
(d.subtitle ? '' + esc(d.subtitle) + '' : '') +
'
'
) : '') +
'
' + msgs + '
' +
(d.footer ? '' : '') +
'
';
}
var ChatWindow = function () {
return Reflect.construct(HTMLElement, [], ChatWindow);
};
ChatWindow.prototype = Object.create(HTMLElement.prototype);
ChatWindow.prototype.constructor = ChatWindow;
ChatWindow.prototype.connectedCallback = function () {
var self = this;
var d = parse(this);
if (!d && this.dataset.ref) {
// ref 指向的 JSON 可能晚于组件加载,延时再读一次
setTimeout(function () { render(self, parse(self)); }, 0);
} else {
render(this, d);
}
};
if (!customElements.get('chat-window')) {
customElements.define('chat-window', ChatWindow);
}
})();