Files
im_webapp/umd/src_views_messages-view_jsx.dev.js
T
Your NameandClaude Sonnet 5 93b856aec8 第三轮深度测试:修复7个并行agent发现的前端问题,含REASON_MESSAGES系统性补全
派了Ch1-2/3-4/5-6/7/8/9/10-11共7个agent对全部11章重新深度测试。后端问题已核实追加进
docs/IM-后端问题清单-2026-09-04.md(新增6-9条,发给用户);本次是前端问题的修复。

**REASON_MESSAGES系统性补全(最高优先级,多个agent独立发现同一个缺口)**
im-api.js的REASON_MESSAGES表新增22个条目,最重要的是PERMISSION_DENIED——后端
server/im_http.go里403响应统一用这个reason(30余处调用),但表里原来只有一个从未
被后端实际发送过的死条目FORBIDDEN,导致全站几乎每一个403从工程一开始就在展示原始
英文"permission denied"。一并补上VERSION_CONFLICT/MALFORMED_REQUEST(Ch9 agent实测
命中)、NOT_FOUND、VERIFICATION_RATE_LIMITED(动态文案,同TOO_MANY_ATTEMPTS模式)等。
新增translateReason()导出函数并用于send-message.jsx的sendFavorite——favorites/forward
等几个批量接口恒定200、真实成败包在items[].reason里,imRequest的自动翻译够不到这种
per-item场景,之前直接显示原始reason字符串。tinode-web.jsx同理补了CTRL_ERROR_TEXT_CN
(原生WS {ctrl}协议错误,同样绕开REASON_MESSAGES)并修了原表从未真正匹配过的bug——
CommError会把状态码拼进message变成"authentication failed (401)",原表按裸文本精确
匹配,看着正常纯粹是因为401/403兜底文案凑巧一样,一旦命中"unknown authentication
scheme"这类会被兜底文案误导、"policy violation"这类会直接漏出英文。uploadLargeFile/
createChatUploader/createFileDownloader同样绕开REASON_MESSAGES(走原生{ctrl}协议),
补了UPLOAD_CTRL_TEXT_CN小词典。已用真实账号端到端验证:favorites/forward到P2P目标
触发的PERMISSION_DENIED现在正确显示"没有权限执行此操作";draft接口版本冲突正确显示
"内容已被修改,请刷新后重试"。

**编辑消息时打开附件面板会静默覆盖被编辑消息(Ch3-4 agent发现,数据损坏级别)**
sendMessage对editing状态一律用head.replace,但onAttachFile/onAttachImage/onAttachAudio
原来只在forwardMessage时置空,编辑态没有同款门禁——编辑一条消息不改文字、点"+"选张图片
或名片,会直接把附件内容替换掉被编辑消息的原文,无任何确认。messages-view.jsx新增
editingMessage门禁,和forwardMessage一样把三个attach回调置空(等价于隐藏整个"+"按钮)。
已用真实浏览器验证:编辑态下"+"按钮消失,取消编辑后正常恢复。

**草稿防抖单一共享定时器丢字(Ch1-2、Ch3-4两个agent独立发现)**
handleComposerChange用单个this.draftSaveTimer,话题A打字触发600ms保存后300ms内切到
话题B,会把A的定时器clearTimeout掉,那次输入永久丢失;version也在定时器触发时才重新
读state,此时可能已经在别的话题上,退化成硬编码0——叠加后端draft接口对version=0"无条件
跳过乐观锁"的行为(已记入后端清单新增6),可能静默覆盖别的标签页写入的更新草稿。改为
按话题分开的定时器map,version在调用的当下(保证仍在该话题)同步捕获进闭包。

**呼叫状态机两处真实bug(Ch8 agent此前发现,本次重新核实live代码后确认+修复)**
1. 通话中导航离开messages-view.jsx整个组件树(切到工作台/个人设置,或移动端切回会话
   列表)时,没有任何hangup清理——componentSetup已有的"切换话题时正确挂断"逻辑只在
   componentDidUpdate里,组件真正卸载时不会触发。CallPanel自己的componentWillUnmount
   只做本地清理,不通知对方也不重置tinode-web.jsx顶层callState,导致下次切回通话话题
   时remount出一个callState卡在CALL_STATE_IN_PROGRESS的"僵尸"面板——start()走"我们刚
   接听"分支直接return,从不调getUserMedia,本地媒体永久拿不到。补了对称的
   componentWillUnmount挂断逻辑。
2. this.callTimeoutTimer声明后从未被真正setTimeout赋值——呼出无人接听或accept信令
   (fire-and-forget的{note}包)被丢会永久卡在"呼叫中"。补了armCallRingTimeout(),
   60秒未接通按跟手动取消完全一样的路径挂断(不发明新的通话结果语义),在收到对方
   accept信号的两处分支都正确清timer。

**其余前端修复(按文件)**
- messages-view.jsx: @提醒mentionedUsers只在切话题时清空,同一话题内后续消息里字面
  文本"@张三"会被静默解析成真实提醒(发送后清空);jumpToMessage点开已撤回/删除的
  搜索结果原来只console.error静默失败,补了用户可见的错误提示;批量收藏对
  favorites/batch共享Idempotency-Key导致的静默丢失(已知后端问题)不再照单全收
  "收藏成功",改为发送后重新拉取真实收藏列表核对每条是否真的落地。
- audio-recorder.jsx: getUserMedia权限弹窗未决出结果时组件被卸载,补_unmounted
  标记避免在死实例上继续跑mediaRecorder.start()。
- send-message.jsx: disabled变为true时(对方拉黑/被禁言等实时ACS变化)没有强制结束
  正在进行的按住录音,可能remount出无用户手势的"自动录音";mouseup/touchend覆盖不到
  拖出窗口/切换标签页/权限弹窗抢焦点的释放场景,补了blur/visibilitychange兜底。
- tinode-web.jsx: messages-menu视图和messages-home共用MessageCenterView实例无key,
  从messages-home以非整体刷新方式切到messages-menu时菜单打不开,补key={view}。
- message-center-view.jsx: 实名认证驳回提醒的dismiss key只按用户+状态区分,同一状态
  的两次独立驳回会互相误压制,改按submission_id区分。
- contact-management-view.jsx: Profile/Settings靠getUserProfile刷新拉黑状态,但该
  接口对被拉黑对象直接403,导致"之前会话就已拉黑"的场景完全感知不到——叠加
  getConversationContext兜底(该接口对拉黑目标正确返回200+relationship)。
- group-management-view.jsx: AdminList显示群主/管理员姓名漏了group_nickname兜底;
  JoinRequests从聊天页横幅进入时返回按钮硬编码回group-settings(应回聊天本身),
  从Governance进入时返回group-settings而非group-governance(与AdminList/Muted不一致)。
- workplace-collaboration-view.jsx: OrganizationDirectory/DeptNode的部门树加载失败
  被无条件当成"暂无数据"渲染,补loadError区分+重试链接。
- personal-settings-view.jsx: CacheClear对navigator.storage/caches整个不存在的情况
  只有react出了范围的.catch()覆盖不到的同步抛错,加了特性检测+try/catch;
  YouthModeVerify触发TOO_MANY_ATTEMPTS锁定后确定按钮没有禁用/倒计时,会继续发出
  注定失败的请求。
- security-support-view.jsx: 意见反馈category字段在config未加载完成前可为空但没有
  提交前校验,会打到后端400。
- use-cached-data.js: bootstrap等首次拉取失败且无缓存兜底时永久停在undefined,加了
  一次3秒后重试(仅在完全没有缓存值时触发,已有缓存值维持原"显示旧数据"行为不变)。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-04 23:29:52 +08:00

4377 lines
234 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use strict";
(self["webpackChunktinode_webapp"] = self["webpackChunktinode_webapp"] || []).push([["src_views_messages-view_jsx"],{
/***/ "./src/views/logo-view.jsx":
/*!*********************************!*\
!*** ./src/views/logo-view.jsx ***!
\*********************************/
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": function() { return /* binding */ LogoView; }
/* harmony export */ });
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react");
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl");
/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk");
/* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../config.js */ "./src/config.js");
/* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js");
class LogoView extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) {
render() {
const version = _config_js__WEBPACK_IMPORTED_MODULE_3__.APP_NAME + ' (' + tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.getLibrary() + ')';
return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", {
id: "dummy-view",
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("div", {
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("a", {
href: "https://github.com/tinode/chat/",
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("img", {
id: "logo",
alt: "logo",
src: "img/logo.svg"
}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("h2", {
children: "Tinode Web"
}, void 0, false)]
}, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("p", {
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, {
id: "label_client",
defaultMessage: "Client:",
description: "Label for a client version"
}, void 0, false), " ", version]
}, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("p", {
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, {
id: "label_server",
defaultMessage: "Server:",
description: "Label for a server version"
}, void 0, false), " ", this.props.serverVersion, " (", this.props.serverAddress, ")"]
}, void 0, true)]
}, void 0, true)
}, void 0, false);
}
}
;
/***/ }),
/***/ "./src/views/messages-view.jsx":
/*!*************************************!*\
!*** ./src/views/messages-view.jsx ***!
\*************************************/
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react");
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl");
/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk");
/* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var _widgets_chat_message_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../widgets/chat-message.jsx */ "./src/widgets/chat-message.jsx");
/* harmony import */ var _widgets_contact_badges_jsx__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../widgets/contact-badges.jsx */ "./src/widgets/contact-badges.jsx");
/* harmony import */ var _widgets_error_panel_jsx__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../widgets/error-panel.jsx */ "./src/widgets/error-panel.jsx");
/* harmony import */ var _widgets_group_subs_jsx__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../widgets/group-subs.jsx */ "./src/widgets/group-subs.jsx");
/* harmony import */ var _widgets_invitation_jsx__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../widgets/invitation.jsx */ "./src/widgets/invitation.jsx");
/* harmony import */ var _widgets_letter_tile_jsx__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../widgets/letter-tile.jsx */ "./src/widgets/letter-tile.jsx");
/* harmony import */ var _widgets_load_spinner_jsx__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ../widgets/load-spinner.jsx */ "./src/widgets/load-spinner.jsx");
/* harmony import */ var _logo_view_jsx__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./logo-view.jsx */ "./src/views/logo-view.jsx");
/* harmony import */ var _widgets_meta_message_jsx__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ../widgets/meta-message.jsx */ "./src/widgets/meta-message.jsx");
/* harmony import */ var _widgets_pinned_messages_jsx__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ../widgets/pinned-messages.jsx */ "./src/widgets/pinned-messages.jsx");
/* harmony import */ var _security_support_view_jsx__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./security-support-view.jsx */ "./src/views/security-support-view.jsx");
/* harmony import */ var _widgets_send_message_jsx__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ../widgets/send-message.jsx */ "./src/widgets/send-message.jsx");
/* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ../config.js */ "./src/config.js");
/* harmony import */ var _constants_js__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ../constants.js */ "./src/constants.js");
/* harmony import */ var _lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ../lib/blob-helpers.js */ "./src/lib/blob-helpers.js");
/* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js");
/* harmony import */ var _lib_im_api_js__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! ../lib/im-api.js */ "./src/lib/im-api.js");
/* harmony import */ var _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! ../lib/navigation.js */ "./src/lib/navigation.js");
/* harmony import */ var _lib_strformat_js__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(/*! ../lib/strformat.js */ "./src/lib/strformat.js");
/* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js");
const CallPanel = react__WEBPACK_IMPORTED_MODULE_0___default().lazy(_ => __webpack_require__.e(/*! import() */ "src_widgets_call-panel_jsx").then(__webpack_require__.bind(__webpack_require__, /*! ../widgets/call-panel.jsx */ "./src/widgets/call-panel.jsx")));
const DocPreview = react__WEBPACK_IMPORTED_MODULE_0___default().lazy(_ => __webpack_require__.e(/*! import() */ "src_widgets_doc-preview_jsx").then(__webpack_require__.bind(__webpack_require__, /*! ../widgets/doc-preview.jsx */ "./src/widgets/doc-preview.jsx")));
const ImagePreview = react__WEBPACK_IMPORTED_MODULE_0___default().lazy(_ => __webpack_require__.e(/*! import() */ "src_widgets_image-preview_jsx").then(__webpack_require__.bind(__webpack_require__, /*! ../widgets/image-preview.jsx */ "./src/widgets/image-preview.jsx")));
const TheCardPreview = react__WEBPACK_IMPORTED_MODULE_0___default().lazy(_ => Promise.all(/*! import() */[__webpack_require__.e("vendors-node_modules_libphonenumber-js_mobile_exports_parsePhoneNumberWithError_js"), __webpack_require__.e("src_widgets_the-card-preview_jsx")]).then(__webpack_require__.bind(__webpack_require__, /*! ../widgets/the-card-preview.jsx */ "./src/widgets/the-card-preview.jsx")));
const VideoPreview = react__WEBPACK_IMPORTED_MODULE_0___default().lazy(_ => __webpack_require__.e(/*! import() */ "src_widgets_video-preview_jsx").then(__webpack_require__.bind(__webpack_require__, /*! ../widgets/video-preview.jsx */ "./src/widgets/video-preview.jsx")));
const NOTIFICATION_EXEC_INTERVAL = 300;
const SHOW_GO_TO_LAST_DIST = 100;
const FETCH_PAGE_TRIGGER = 40;
const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({
message_deleted: {
id: 'message_deleted',
defaultMessage: 'message deleted',
description: 'Placeholder shown in the timeline where a message was recalled or deleted'
},
online_now: {
id: 'online_now',
defaultMessage: 'online now',
description: 'Indicator that the user or topic is currently online'
},
last_seen: {
id: 'last_seen_timestamp',
defaultMessage: 'Last seen: {timestamp}',
description: 'Label for the timestamp of when the user or topic was last online'
},
not_found: {
id: 'title_not_found',
defaultMessage: 'Not found',
description: 'Title shown when topic is not found'
},
channel: {
id: 'channel',
defaultMessage: 'channel',
description: 'Subtitle shown for channels in MessagesView instead of last seen'
},
file_attachment_too_large: {
id: 'file_attachment_too_large',
defaultMessage: 'The file size {size} exceeds the {limit} limit.',
description: 'Error message when attachment is too large'
},
invalid_content: {
id: 'invalid_content',
defaultMessage: 'invalid content',
description: 'Shown when the message is unreadable'
},
editing_message: {
id: 'editing_message',
defaultMessage: 'Editing',
description: 'Title over message editing preview'
},
drag_file: {
id: 'drag_file',
defaultMessage: 'Drag file here',
description: 'Prompt on the file drag-n-drop overlay banner'
},
self_topic_name: {
id: 'self_topic_name',
defaultMessage: 'Saved messages',
description: 'Name of self topic for UI'
},
subscriber_count: {
id: 'subscriber_count',
defaultMessage: '{count, plural, ' + 'one {{count, number} subscriber} ' + 'two {{count, number} subscribers} ' + 'three {{count, number} subscribers} ' + 'few {{count, number} subscribers} ' + 'many {{count, number} subscribers} ' + 'other {{count, number} subscribers}}',
description: 'Count of channel subscribers'
},
member_count: {
id: 'member_count',
defaultMessage: '{count, plural, ' + 'one {{count, number} member} ' + 'two {{count, number} members} ' + 'three {{count, number} members} ' + 'few {{count, number} members} ' + 'many {{count, number} members} ' + 'other {{count, number} members}}',
description: 'Count of group topic members'
},
cannot_parse_vcard: {
id: 'cannot_parse_vcard',
defaultMessage: 'Cannot parse vCard file.',
description: 'Error message when vCard file cannot be parsed'
}
});
function isUnconfirmed(acs) {
if (acs) {
const ex = acs.getExcessive() || '';
return acs.isJoiner('given') && (ex.includes('R') || ex.includes('W'));
}
return false;
}
function isPeerRestricted(acs) {
if (acs) {
const ms = acs.getMissing() || '';
return acs.isJoiner('want') && (ms.includes('R') || ms.includes('W'));
}
return false;
}
function shouldPresentCallPanel(callState) {
return callState == _constants_js__WEBPACK_IMPORTED_MODULE_16__.CALL_STATE_OUTGOING_INITATED || callState == _constants_js__WEBPACK_IMPORTED_MODULE_16__.CALL_STATE_IN_PROGRESS;
}
class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) {
constructor(props) {
super(props);
this.state = MessagesView.getDerivedStateFromProps(props, {});
this.state.messagePolicy = null;
this.state.toast = null;
this.state.riskDialog = null;
this.mentionedUsers = [];
this.componentSetup = this.componentSetup.bind(this);
this.leave = this.leave.bind(this);
this.sendMessage = this.sendMessage.bind(this);
this.handleRiskConfirm = this.handleRiskConfirm.bind(this);
this.handleRiskCancel = this.handleRiskCancel.bind(this);
this.retrySend = this.retrySend.bind(this);
this.sendImageAttachment = this.sendImageAttachment.bind(this);
this.sendVideoAttachment = this.sendVideoAttachment.bind(this);
this.sendFileAttachment = this.sendFileAttachment.bind(this);
this.sendAudioAttachment = this.sendAudioAttachment.bind(this);
this.sendTheCardAttachment = this.sendTheCardAttachment.bind(this);
this.sendKeyPress = this.sendKeyPress.bind(this);
this.subscribe = this.subscribe.bind(this);
this.handleScrollReference = this.handleScrollReference.bind(this);
this.mountDnDEvents = this.mountDnDEvents.bind(this);
this.handleScrollEvent = this.handleScrollEvent.bind(this);
this.handleDescChange = this.handleDescChange.bind(this);
this.handleSubsUpdated = this.handleSubsUpdated.bind(this);
this.handleMessageUpdate = this.handleMessageUpdate.bind(this);
this.handleAuxUpdate = this.handleAuxUpdate.bind(this);
this.handleAllMessagesReceived = this.handleAllMessagesReceived.bind(this);
this.handleInfoReceipt = this.handleInfoReceipt.bind(this);
this.handleExpandMedia = this.handleExpandMedia.bind(this);
this.handleClosePreview = this.handleClosePreview.bind(this);
this.handleCallPanelToggle = this.handleCallPanelToggle.bind(this);
this.handleFormResponse = this.handleFormResponse.bind(this);
this.handleContextClick = this.handleContextClick.bind(this);
this.handleShowMessageContextMenu = this.handleShowMessageContextMenu.bind(this);
this.handleNewChatAcceptance = this.handleNewChatAcceptance.bind(this);
this.handleEnablePeer = this.handleEnablePeer.bind(this);
this.loadRelationshipContext = this.loadRelationshipContext.bind(this);
this.loadGroupContext = this.loadGroupContext.bind(this);
this.loadDraft = this.loadDraft.bind(this);
this.handleComposerChange = this.handleComposerChange.bind(this);
this.clearDraft = this.clearDraft.bind(this);
this.mentionSearch = this.mentionSearch.bind(this);
this.mentionSelected = this.mentionSelected.bind(this);
this.handleShowAnnouncement = this.handleShowAnnouncement.bind(this);
this.handleShowJoinRequests = this.handleShowJoinRequests.bind(this);
this.handleSendFriendVerification = this.handleSendFriendVerification.bind(this);
this.handleBatchDelete = this.handleBatchDelete.bind(this);
this.handleBatchFavorite = this.handleBatchFavorite.bind(this);
this.handleAttachFile = this.handleAttachFile.bind(this);
this.handleAttachImageOrVideo = this.handleAttachImageOrVideo.bind(this);
this.handleCancelUpload = this.handleCancelUpload.bind(this);
this.postReadNotification = this.postReadNotification.bind(this);
this.clearNotificationQueue = this.clearNotificationQueue.bind(this);
this.goToLatestMessage = this.goToLatestMessage.bind(this);
this.handleFileDrop = this.handleFileDrop.bind(this);
this.handlePickReply = this.handlePickReply.bind(this);
this.handleEditMessage = this.handleEditMessage.bind(this);
this.handleCancelReply = this.handleCancelReply.bind(this);
this.handleQuoteClick = this.handleQuoteClick.bind(this);
this.jumpToMessage = this.jumpToMessage.bind(this);
this.handleUnpinMessage = this.handleUnpinMessage.bind(this);
this.handleCallHangup = this.handleCallHangup.bind(this);
this.isDragEnabled = this.isDragEnabled.bind(this);
this.handleDragStart = this.handleDragStart.bind(this);
this.handleDragIn = this.handleDragIn.bind(this);
this.handleDragOut = this.handleDragOut.bind(this);
this.handleDrag = this.handleDrag.bind(this);
this.handleDrop = this.handleDrop.bind(this);
this.chatMessageRefs = [];
this.getOrCreateMessageRef = this.getOrCreateMessageRef.bind(this);
this.getVisibleMessageRange = this.getVisibleMessageRange.bind(this);
this.dragCounter = 0;
this.dndRef = null;
this.readNotificationQueue = [];
this.readNotificationTimer = null;
this.keyPressTimer = null;
}
getOrCreateMessageRef(seqId) {
if (this.chatMessageRefs[seqId]) {
return this.chatMessageRefs[seqId];
}
const ref = react__WEBPACK_IMPORTED_MODULE_0___default().createRef();
this.chatMessageRefs[seqId] = ref;
return ref;
}
getVisibleMessageRange(holderRect) {
let min = Number.MAX_SAFE_INTEGER,
max = -1;
let visibilityStatus = false;
this.chatMessageRefs.every((ref, seq) => {
if (ref.current) {
const {
top,
bottom,
height
} = ref.current.getBoundingClientRect();
const visible = top <= holderRect.top ? holderRect.top - top <= height : bottom - holderRect.bottom <= height;
if (visible) {
visibilityStatus = true;
min = Math.min(min, seq);
max = Math.max(max, seq);
} else if (visibilityStatus) {
return false;
}
}
return true;
});
return max >= min ? {
min: min,
max: max
} : {
min: 0,
max: 0
};
}
componentDidMount() {
if (this.messagesScroller) {
this.messagesScroller.addEventListener('scroll', this.handleScrollEvent);
}
this.mountDnDEvents(this.dndRef);
this.componentSetup({}, {});
(0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_19__.getBootstrap)().then(data => {
this.setState({
messagePolicy: data.message_policy || null
});
}).catch(_ => {});
}
componentWillUnmount() {
if (this.state.rtcPanel) {
this.handleCallHangup(this.state.topic, this.props.callSeq);
}
if (this.messagesScroller) {
this.messagesScroller.removeEventListener('scroll', this.handleScrollEvent);
}
window.clearTimeout(this.toastTimer);
this.clearNotificationQueue();
if (this.dndRef) {
this.dndRef.removeEventListener('dragstart', this.handleDragStart);
this.dndRef.removeEventListener('dragenter', this.handleDragIn);
this.dndRef.removeEventListener('dragleave', this.handleDragOut);
this.dndRef.removeEventListener('dragover', this.handleDrag);
this.dndRef.removeEventListener('drop', this.handleDrop);
}
}
componentDidUpdate(prevProps, prevState) {
if (this.messagesScroller && (prevState.topic != this.state.topic || prevState.maxSeqId != this.state.maxSeqId || prevState.minSeqId != this.state.minSeqId)) {
if (this.state.scrollPosition < SHOW_GO_TO_LAST_DIST) {
this.messagesScroller.scrollTop = this.messagesScroller.scrollHeight - this.state.scrollPosition - this.messagesScroller.offsetHeight;
}
}
if (!this.props.applicationVisible) {
this.clearNotificationQueue();
} else {
this.postReadNotification(0);
}
if (this.props.jumpToSeq && this.props.jumpToSeq != prevProps.jumpToSeq) {
this.jumpToMessage(parseInt(this.props.jumpToSeq, 10));
}
this.componentSetup(prevProps, prevState);
}
componentSetup(prevProps, prevState) {
const topic = this.props.tinode ? this.props.tinode.getTopic(this.state.topic) : undefined;
if (this.state.topic != prevState.topic) {
if (prevState.topic && !tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.isNewGroupTopicName(prevState.topic)) {
this.leave(prevState.topic);
if (prevState.rtcPanel) {
this.handleCallHangup(prevState.topic, prevProps.callSeq);
}
}
if (topic) {
topic.onData = this.handleMessageUpdate;
topic.onAllMessagesReceived = this.handleAllMessagesReceived;
topic.onInfo = this.handleInfoReceipt;
topic.onMetaDesc = this.handleDescChange;
topic.onSubsUpdated = this.handleSubsUpdated;
topic.onPres = this.handleSubsUpdated;
topic.onAuxUpdated = this.handleAuxUpdate;
}
this.mentionedUsers = [];
this.loadRelationshipContext(topic);
this.loadGroupContext(topic);
this.loadDraft(topic);
}
if (topic) {
if (this.state.topic != prevState.topic || this.props.myUserId && !prevProps.myUserId) {
const newTopic = this.props.newTopicParams && this.props.newTopicParams._topicName == this.props.topic;
if (topic.isP2PType() && newTopic && !_config_js__WEBPACK_IMPORTED_MODULE_15__.IMMEDIATE_P2P_SUBSCRIPTION) {
topic.getMeta(topic.startMetaQuery().withDesc().build());
} else if (this.props.myUserId) {
this.subscribe(topic);
}
} else if (topic.isSubscribed() && this.state.isReader && !prevState.isReader) {
topic.getMeta(topic.startMetaQuery().withLaterData().build());
} else if (!topic.isSubscribed() && this.props.ready && !prevProps.ready) {
this.subscribe(topic);
}
}
}
static getDerivedStateFromProps(nextProps, prevState) {
let nextState = {};
if (!nextProps.topic) {
nextState = {
minSeqId: -1,
maxSeqId: -1,
latestClearId: -1,
onlineSubs: [],
topic: null,
title: '',
avatar: null,
isVerified: false,
isStaff: false,
isDangerous: false,
deleted: false,
docPreview: null,
imagePreview: null,
imagePostview: null,
videoPreview: null,
videoPostview: null,
rtcPanel: null,
minimizedCallPanel: false,
typingIndicator: false,
scrollPosition: 0,
fetchingMessages: false,
peerMessagingDisabled: false,
channel: false,
reply: null,
contentToEdit: null,
showGoToLastButton: false,
dragging: false,
pins: [],
pinsLoaded: false,
selectedPin: 0,
subsVersion: 0,
relationshipContext: null,
groupRoles: null,
myGroupRole: null,
groupAnnouncement: null,
pendingJoinRequests: 0,
draftText: null,
draftVersion: 0
};
} else if (nextProps.topic != prevState.topic) {
const topic = nextProps.tinode.getTopic(nextProps.topic);
nextState = {
topic: nextProps.topic,
deleted: topic._deleted,
docPreview: null,
imagePreview: null,
imagePostview: null,
videoPreview: null,
videoPostview: null,
rtcPanel: null,
minimizedCallPanel: false,
typingIndicator: false,
scrollPosition: 0,
fetchingMessages: false,
showGoToLastButton: false,
contentToEdit: null,
dragging: false,
selectedPin: 0,
relationshipContext: null,
groupRoles: null,
myGroupRole: null,
groupAnnouncement: null,
pendingJoinRequests: 0,
draftText: null,
draftVersion: 0,
riskDialog: null
};
if (nextProps.forwardMessage) {
if (nextProps.forwardMessage.content) {
const content = nextProps.forwardMessage.content;
const size = content?.length || content?.size || 0;
nextState.docPreview = {
object: content,
type: nextProps.forwardMessage.type,
size: size
};
} else {
nextState.reply = {
content: nextProps.forwardMessage.preview,
seq: null
};
}
} else {
nextState.reply = null;
}
if (topic) {
const subs = [];
if (nextProps.connected) {
topic.subscribers(sub => {
if (sub.online && sub.user != nextProps.myUserId) {
subs.push(sub);
}
});
}
Object.assign(nextState, {
onlineSubs: subs
});
if (topic.isSelfType()) {
Object.assign(nextState, {
title: nextProps.intl.formatMessage(messages.self_topic_name),
avatar: true
});
} else if (topic.public) {
Object.assign(nextState, {
title: (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_18__.topicDisplayName)(topic.name, topic.public, ''),
avatar: (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_17__.makeImageUrl)(topic.public.photo)
});
} else {
Object.assign(nextState, {
title: '',
avatar: null
});
}
const peer = topic.p2pPeerDesc();
if (peer) {
Object.assign(nextState, {
peerMessagingDisabled: isPeerRestricted(peer.acs)
});
} else if (prevState.peerMessagingDisabled) {
Object.assign(nextState, {
peerMessagingDisabled: false
});
}
Object.assign(nextState, {
minSeqId: topic.minMsgSeq(),
maxSeqId: topic.maxMsgSeq(),
latestClearId: topic.maxClearId(),
channel: topic.isChannelType(),
pins: (topic.aux('pins') || []).slice(),
pinsLoaded: false
});
if (nextProps.callTopic == topic.name && shouldPresentCallPanel(nextProps.callState)) {
nextState.rtcPanel = nextProps.callTopic;
}
} else {
Object.assign(nextState, {
minSeqId: -1,
maxSeqId: -1,
latestClearId: -1,
onlineSubs: [],
title: '',
avatar: null,
peerMessagingDisabled: false,
channel: false,
pins: [],
pinsLoaded: false
});
}
} else {
if (nextProps.callTopic == prevState.topic && !prevState.rtcPanel && shouldPresentCallPanel(nextProps.callState)) {
nextState.rtcPanel = nextProps.callTopic;
}
}
if (nextProps.acs) {
if (nextProps.acs.isWriter() != prevState.isWriter) {
nextState.isWriter = !prevState.isWriter;
}
if (nextProps.acs.isReader() != prevState.isReader) {
nextState.isReader = !prevState.isReader;
}
if (nextProps.acs.isAdmin() != prevState.isAdmin) {
nextState.isAdmin = !prevState.isAdmin;
}
if (!nextProps.acs.isReader('given') != prevState.readingBlocked) {
nextState.readingBlocked = !prevState.readingBlocked;
}
if (nextProps.acs.isSharer() != prevState.isSharer) {
nextState.isSharer = !prevState.isSharer;
}
} else {
if (prevState.isWriter) {
nextState.isWriter = false;
}
if (prevState.isReader) {
nextState.isReader = false;
}
if (prevState.isAdmin) {
nextState.isAdmin = false;
}
if (!prevState.readingBlocked) {
nextState.readingBlocked = true;
}
if (prevState.isSharer) {
nextState.isSharer = false;
}
}
if (isUnconfirmed(nextProps.acs) == !prevState.unconformed) {
nextState.unconfirmed = !prevState.unconformed;
}
if (!nextProps.connected && prevState.onlineSubs && prevState.onlineSubs.length > 0) {
nextState.onlineSubs = [];
}
return nextState;
}
subscribe(topic) {
if (topic.isSubscribed() || !this.props.ready) {
return;
}
const newTopic = this.props.newTopicParams && this.props.newTopicParams._topicName == this.props.topic;
let getQuery = topic.startMetaQuery().withLaterDesc().withLaterSub().withAux();
if (this.state.isReader || newTopic) {
getQuery = getQuery.withLaterData(_config_js__WEBPACK_IMPORTED_MODULE_15__.MESSAGES_PAGE);
if (this.state.isReader) {
getQuery = getQuery.withLaterDel();
}
this.setState({
fetchingMessages: true
});
}
const setQuery = newTopic ? this.props.newTopicParams : undefined;
topic.subscribe(getQuery.build(), setQuery).then(ctrl => {
if (ctrl.code == 303) {
_lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].setUrlTopic('', ctrl.params.topic));
return;
}
if (this.state.topic != ctrl.topic) {
this.setState({
topic: ctrl.topic
});
}
if (this.state.deleted) {
this.setState({
deleted: false
});
}
this.props.onNewTopicCreated(this.props.topic, ctrl.topic);
let discard = [];
topic.queuedMessages(pub => {
if (pub._sending) {
return;
}
if (pub._fatal || pub.head && pub.head.webrtc) {
discard.push(pub.seq);
return;
}
if (topic.isSubscribed()) {
this.retrySend(pub);
}
});
if (discard.length > 0) {
topic.delMessagesList(discard, true);
}
}).catch(err => {
console.error("Failed subscription to", this.state.topic, err);
this.props.onError(err.message, 'err');
const blankState = MessagesView.getDerivedStateFromProps({}, {});
blankState.title = this.props.intl.formatMessage(messages.not_found);
this.setState(blankState);
});
}
leave(oldTopicName) {
if (!oldTopicName || !this.props.tinode.isTopicCached(oldTopicName)) {
return;
}
const oldTopic = this.props.tinode.getTopic(oldTopicName);
if (oldTopic && oldTopic.isSubscribed()) {
oldTopic.leave(false).catch(_ => {}).finally(_ => {
this.setState({
fetchingMessages: false
});
oldTopic.onData = undefined;
oldTopic.onAllMessagesReceived = undefined;
oldTopic.onInfo = undefined;
oldTopic.onMetaDesc = undefined;
oldTopic.onSubsUpdated = undefined;
oldTopic.onPres = undefined;
oldTopic.onAuxUpdated = undefined;
});
}
}
handleScrollReference(node) {
if (node) {
node.addEventListener('scroll', this.handleScrollEvent);
this.messagesScroller = node;
this.messagesScroller.scrollTop = this.messagesScroller.scrollHeight - this.state.scrollPosition - this.messagesScroller.offsetHeight;
}
}
handleScrollEvent(event) {
const pos = event.target.scrollHeight - event.target.scrollTop - event.target.offsetHeight;
this.setState({
scrollPosition: pos,
showGoToLastButton: pos > SHOW_GO_TO_LAST_DIST && pos < this.state.scrollPosition
});
if (this.state.fetchingMessages || this.processingScrollEvent) {
return;
}
if (event.target.scrollTop <= FETCH_PAGE_TRIGGER) {
const topic = this.props.tinode.getTopic(this.state.topic);
if (topic && topic.isSubscribed()) {
this.processingScrollEvent = true;
const {
min,
max
} = this.getVisibleMessageRange(event.target.getBoundingClientRect());
const gaps = topic.msgHasMoreMessages(min, max, false);
if (gaps.length > 0) {
this.setState({
fetchingMessages: true
}, _ => {
topic.getMessagesPage(_config_js__WEBPACK_IMPORTED_MODULE_15__.MESSAGES_PAGE, gaps, min, max).catch(err => this.props.onError(err.message, 'err')).finally(_ => this.setState({
fetchingMessages: false
}));
});
}
}
}
this.processingScrollEvent = false;
}
mountDnDEvents(dnd) {
if (dnd) {
dnd.addEventListener('dragstart', this.handleDragStart);
dnd.addEventListener('dragenter', this.handleDragIn);
dnd.addEventListener('dragleave', this.handleDragOut);
dnd.addEventListener('dragover', this.handleDrag);
dnd.addEventListener('drop', this.handleDrop);
this.dndRef = dnd;
}
}
goToLatestMessage() {
this.setState({
scrollPosition: 0
});
if (this.messagesScroller) {
this.messagesScroller.scrollTop = this.messagesScroller.scrollHeight - this.messagesScroller.offsetHeight;
}
}
handleDescChange(desc) {
if (tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.isSelfTopicName(this.props.topic)) {
this.setState({
title: this.props.intl.formatMessage(messages.self_topic_name),
avatar: true
});
} else if (desc.public) {
this.setState({
title: (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_18__.topicDisplayName)(this.props.topic, desc.public, ''),
avatar: (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_17__.makeImageUrl)(desc.public.photo)
});
} else {
this.setState({
title: '',
avatar: null
});
}
if (desc.acs) {
this.setState({
isWriter: desc.acs.isWriter(),
isReader: desc.acs.isReader(),
isAdmin: desc.acs.isAdmin(),
readingBlocked: !desc.acs.isReader('given'),
unconfirmed: isUnconfirmed(desc.acs)
});
}
}
postReadNotification(seq) {
if (!this.props.applicationVisible || !this.state.topic) {
return;
}
if (!this.readNotificationTimer) {
this.readNotificationTimer = setInterval(_ => {
if (this.readNotificationQueue.length == 0) {
clearInterval(this.readNotificationTimer);
this.readNotificationTimer = null;
return;
}
let seq = -1;
while (this.readNotificationQueue.length > 0) {
const n = this.readNotificationQueue[0];
if (n.topicName != this.state.topic) {
this.readNotificationQueue.shift();
continue;
}
const now = new Date();
if (n.sendAt <= now) {
this.readNotificationQueue.shift();
if (n.seq == 0 || tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.isServerAssignedSeq(n.seq)) {
seq = Math.max(seq, n.seq);
}
} else {
break;
}
}
if (seq >= 0) {
const topic = this.props.tinode.getTopic(this.state.topic);
if (topic) {
try {
topic.noteRead(seq);
} catch (err) {
console.error("Failed to send read notification", err);
}
}
}
}, NOTIFICATION_EXEC_INTERVAL);
}
const now = new Date();
this.readNotificationQueue.push({
topicName: this.state.topic,
seq: seq,
sendAt: now.setMilliseconds(now.getMilliseconds() + _config_js__WEBPACK_IMPORTED_MODULE_15__.READ_DELAY)
});
}
clearNotificationQueue() {
this.readNotificationQueue = [];
if (this.readNotificationTimer) {
clearInterval(this.readNotificationTimer);
this.readNotificationTimer = null;
}
}
handleSubsUpdated() {
if (this.state.topic) {
const subs = [];
const topic = this.props.tinode.getTopic(this.state.topic);
topic.subscribers(sub => {
if (sub.online && sub.user != this.props.myUserId) {
subs.push(sub);
}
});
const newState = {
onlineSubs: subs,
subsVersion: this.state.subsVersion + 1
};
const peer = topic.p2pPeerDesc();
if (peer) {
Object.assign(newState, {
peerMessagingDisabled: isPeerRestricted(peer.acs)
});
} else if (this.state.peerMessagingDisabled) {
Object.assign(newState, {
peerMessagingDisabled: false
});
}
this.setState(newState);
}
}
handleMessageUpdate(msg) {
if (!this.state.topic) {
return;
}
const topic = this.props.tinode.getTopic(this.state.topic);
if (!msg) {
this.setState({
latestClearId: topic.maxClearId()
});
return;
}
clearTimeout(this.keyPressTimer);
this.setState({
maxSeqId: topic.maxMsgSeq(),
minSeqId: topic.minMsgSeq(),
typingIndicator: false
}, _ => {
if (topic.isNewMessage(msg.seq)) {
if (this.state.scrollPosition > SHOW_GO_TO_LAST_DIST) {
this.setState({
showGoToLastButton: true
});
} else {
this.goToLatestMessage();
}
} else {
if (this.messagesScroller) {
this.messagesScroller.scrollTop = this.messagesScroller.scrollHeight - this.state.scrollPosition - this.messagesScroller.offsetHeight;
}
}
});
const status = topic.msgStatus(msg, true);
if (status >= tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.MESSAGE_STATUS_SENT && msg.from != this.props.myUserId) {
this.postReadNotification(msg.seq);
}
}
handleAllMessagesReceived(count) {
this.setState({
fetchingMessages: false
});
if (!count) {
const topic = this.props.tinode.getTopic(this.state.topic);
if (topic) {
this.postReadNotification(topic.seq);
}
return;
}
if (!this.state.pinsLoaded) {
const topic = this.props.tinode.getTopic(this.state.topic);
this.setState({
pinsLoaded: true
}, _ => {
topic.getPinnedMessages();
});
} else {
this.setState({
pinsLoaded: false
});
}
}
handleAuxUpdate(aux) {
const pins = (aux['pins'] || []).slice();
let selectedPin = this.state.selectedPin;
if (pins.length > this.state.pins.length) {
selectedPin = 0;
} else if (selectedPin >= pins.length) {
selectedPin = Math.max(0, pins.length - 1);
}
this.setState({
pins: pins,
selectedPin: selectedPin
});
}
handleInfoReceipt(info) {
switch (info.what) {
case 'kp':
{
clearTimeout(this.keyPressTimer);
this.keyPressTimer = setTimeout(_ => this.setState({
typingIndicator: false
}), _config_js__WEBPACK_IMPORTED_MODULE_15__.KEYPRESS_DELAY + 1000);
if (!this.state.typingIndicator) {
this.setState({
typingIndicator: true
});
}
break;
}
case 'read':
case 'recv':
this.forceUpdate();
break;
default:
console.info("Other change in topic: ", info.what);
}
}
handleExpandMedia(content) {
if (!content) {
return;
}
if (content.video) {
this.setState({
videoPostview: content
});
} else {
this.setState({
imagePostview: content
});
}
}
handleClosePreview() {
if (this.state.imagePreview && this.state.imagePreview.url) {
URL.revokeObjectURL(this.state.imagePreview.url);
}
if (this.state.videoPreview && this.state.videoPreview.url) {
URL.revokeObjectURL(this.state.videoPreview.url);
}
this.setState({
imagePostview: null,
imagePreview: null,
docPreview: null,
videoPreview: null,
videoPostview: null
});
this.props.onCancelForwardMessage();
}
handleFormResponse(action, text, data) {
if (action == 'pub') {
this.sendMessage(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.attachJSON(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.parse(text), data));
} else if (action == 'url') {
const url = new URL(data.ref);
const params = url.searchParams;
for (let key in data.resp) {
if (data.resp.hasOwnProperty(key)) {
params.set(key, data.resp[key]);
}
}
['name', 'seq'].forEach(key => {
if (data[key]) {
params.set(key, data[key]);
}
});
params.set('uid', this.props.myUserId);
params.set('topic', this.state.topic);
url.search = params;
window.open(url, '_blank');
} else {
console.info("Unknown action in form", action);
}
}
handleContextClick(e) {
e.preventDefault();
e.stopPropagation();
this.props.showContextMenu({
topicName: this.state.topic,
y: e.pageY,
x: e.pageX
});
}
handleShowMessageContextMenu(params, messageSpecificMenuItems) {
if (params.userFrom == 'chan') {
params.userFrom = this.state.topic;
params.userName = this.state.title;
}
params.topicName = this.state.topic;
let menuItems = messageSpecificMenuItems || [];
const topic = this.props.tinode.getTopic(params.topicName);
if (topic) {
const editWindow = this.state.messagePolicy ? this.state.messagePolicy.edit_window_seconds : 0;
if (menuItems.includes('menu_item_edit') && !(editWindow > 0 && params.timestamp && params.timestamp.getTime() > new Date().getTime() - editWindow * 1000)) {
menuItems = menuItems.filter(item => item !== 'menu_item_edit');
}
menuItems.push('menu_item_copy', 'menu_item_favorite');
const recallWindow = this.state.messagePolicy ? this.state.messagePolicy.recall_window_seconds : 0;
if (params.userFrom == this.props.myUserId && params.seq > 0 && recallWindow > 0 && params.timestamp && params.timestamp.getTime() > new Date().getTime() - recallWindow * 1000) {
menuItems.push('menu_item_recall');
}
if (topic.isSelfType()) {
menuItems.push('message_delete_generic');
} else {
if (!topic.isChannelType()) {
menuItems.push('message_delete');
}
const acs = topic.getAccessMode();
if (acs && acs.isDeleter()) {
let canDelete = acs.isOwner();
if (!canDelete) {
const maxDelAge = this.props.tinode.getServerParam(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.MSG_DELETE_AGE, 0) | 0;
canDelete = maxDelAge == 0 || (maxDelAge > 0 && params.timestamp ? params.timestamp.getTime() > new Date().getTime() - maxDelAge * 1000 : false);
}
if (canDelete) {
menuItems.push('message_delete_hard');
}
}
}
}
menuItems.push('menu_item_select');
this.props.showContextMenu(params, menuItems);
}
handleNewChatAcceptance(action) {
this.props.onNewChat(this.state.topic, action);
}
handleEnablePeer(e) {
e.preventDefault();
this.props.onChangePermissions(this.state.topic, _config_js__WEBPACK_IMPORTED_MODULE_15__.DEFAULT_P2P_ACCESS_MODE, this.state.topic);
}
loadRelationshipContext(topic) {
if (!topic || !topic.isP2PType()) {
return;
}
const topicName = topic.name;
(0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_19__.getConversationContext)(topicName).then(data => {
if (this.state.topic == topicName) {
this.setState({
relationshipContext: data
});
}
}).catch(_ => {});
}
loadGroupContext(topic) {
if (!topic || !topic.isGroupType() || topic.isChannelType()) {
return;
}
const topicName = topic.name;
(0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_19__.getGroupMembers)(topicName).then(data => {
if (this.state.topic != topicName) {
return;
}
const roles = {};
(data.items || []).forEach(m => {
roles[m.user_id] = m.role;
});
this.setState({
groupRoles: roles,
myGroupRole: roles[this.props.myUserId] || null
});
if (roles[this.props.myUserId] == 'owner' || roles[this.props.myUserId] == 'admin') {
(0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_19__.getGroupJoinRequests)(topicName, 'pending').then(reqData => {
if (this.state.topic == topicName) {
this.setState({
pendingJoinRequests: (reqData.items || []).length
});
}
}).catch(_ => {});
}
}).catch(_ => {});
(0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_19__.getLatestGroupAnnouncement)(topicName).then(data => {
if (this.state.topic == topicName) {
this.setState({
groupAnnouncement: data && data.content ? data : null
});
}
}).catch(_ => {});
}
mentionSearch(query) {
const topic = this.props.tinode ? this.props.tinode.getTopic(this.state.topic) : null;
if (!topic || !topic.isGroupType()) {
return Promise.resolve([]);
}
return (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_19__.getGroupMembers)(this.state.topic, {
mentionable: true,
query
}).then(data => data.items || []);
}
mentionSelected(uid, name) {
this.mentionedUsers = (this.mentionedUsers || []).filter(m => m.name !== name);
this.mentionedUsers.push({
uid,
name
});
}
loadDraft(topic) {
if (!topic) {
return;
}
const topicName = topic.name;
(0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_19__.getTopicDraft)(topicName).then(data => {
if (this.state.topic != topicName) {
return;
}
this.setState({
draftText: data.content || '',
draftVersion: data.version || 0
});
}).catch(_ => {});
}
handleComposerChange(text) {
if (this.state.reply && this.state.reply.editing) {
return;
}
if (this.props.forwardMessage) {
return;
}
const topicName = this.state.topic;
if (!topicName) {
return;
}
const version = this.state.draftVersion || 0;
this.draftSaveTimers = this.draftSaveTimers || {};
if (this.draftSaveTimers[topicName]) {
window.clearTimeout(this.draftSaveTimers[topicName]);
}
this.draftSaveTimers[topicName] = window.setTimeout(() => {
delete this.draftSaveTimers[topicName];
(0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_19__.updateTopicDraft)(topicName, text, [], version).then(d => {
if (this.state.topic == topicName) {
this.setState({
draftVersion: d.version
});
}
}).catch(_ => {});
}, 600);
}
clearDraft(topicName, knownVersion) {
if (this.draftSaveTimers && this.draftSaveTimers[topicName]) {
window.clearTimeout(this.draftSaveTimers[topicName]);
delete this.draftSaveTimers[topicName];
}
const version = knownVersion != null ? knownVersion : this.state.topic == topicName ? this.state.draftVersion || 0 : 0;
(0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_19__.updateTopicDraft)(topicName, '', [], version).then(d => {
if (this.state.topic == topicName) {
this.setState({
draftText: '',
draftVersion: d.version
});
}
}).catch(_ => {});
}
handleShowAnnouncement(e) {
e.preventDefault();
let hash = _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].addUrlParam(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].setUrlSidePanel('', 'group-announcement-detail'), 'topic', this.state.topic);
hash = _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].addUrlParam(hash, 'from', 'chat');
_lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].navigateTo(hash);
}
handleShowJoinRequests(e) {
e.preventDefault();
let hash = _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].addUrlParam(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].setUrlSidePanel('', 'group-join-requests'), 'topic', this.state.topic);
hash = _lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].addUrlParam(hash, 'from', 'chat');
_lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].navigateTo(hash);
}
handleSendFriendVerification(e) {
e.preventDefault();
_lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].addUrlParam(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].setUrlSidePanel('', 'friend-verification'), 'uid', this.state.topic));
}
showToast(text) {
this.setState({
toast: text
});
window.clearTimeout(this.toastTimer);
this.toastTimer = window.setTimeout(() => this.setState({
toast: null
}), 3500);
}
handleBatchDelete() {
const topic = this.props.tinode.getTopic(this.state.topic);
if (!topic || !this.props.selectedSeqs.length) {
return;
}
topic.delMessagesList(this.props.selectedSeqs.slice(), true).then(_ => {
this.props.onExitSelectMode();
}).catch(err => {
this.props.onError(err.message, 'err');
});
}
handleBatchFavorite() {
if (!this.props.selectedSeqs.length) {
return;
}
const topicName = this.state.topic;
const seqs = this.props.selectedSeqs.slice();
(0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_19__.favoriteMessages)(seqs.map(seq => ({
topic: topicName,
seq
}))).then(() => {
return (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_19__.getFavorites)({
type: 'all',
limit: 100
}).then(data => {
const items = data && data.items || [];
const landed = new Set(items.filter(it => it.source && it.source.topic == topicName).map(it => String(it.source.seq)));
const missing = seqs.filter(seq => !landed.has(String(seq)));
if (missing.length === seqs.length) {
this.props.onError('收藏失败', 'err');
} else if (missing.length) {
this.showToast(`已收藏 ${seqs.length - missing.length}/${seqs.length} 条`);
} else {
this.showToast('收藏成功');
}
});
}).catch(err => {
this.props.onError(err.message, 'err');
});
}
sendKeyPress(audio) {
const topic = this.props.tinode.getTopic(this.state.topic);
if (!topic.isSubscribed()) {
return;
}
if (audio) {
return;
}
topic.noteKeyPress();
}
applyMentionResolution(parsed) {
if (!parsed || !Array.isArray(parsed.ent) || !this.mentionedUsers || !this.mentionedUsers.length) {
return;
}
parsed.ent.forEach(e => {
if (e.tp === 'MN' && e.data && typeof e.data.val === 'string') {
const match = this.mentionedUsers.find(m => m.name === e.data.val);
if (match) {
e.data.val = match.uid;
}
}
});
}
sendMessage(msg, uploadCompletionPromise, uploader, typeHint) {
const originalText = typeof msg === 'string' ? msg : null;
let head;
if (!msg && this.props.forwardMessage) {
msg = this.props.forwardMessage.msg;
head = this.props.forwardMessage.head;
this.handleCancelReply();
} else if (this.state.reply) {
if (this.state.reply.editing) {
if (msg == this.state.contentToEdit) {
this.handleCancelReply();
return;
}
head = {
replace: ':' + this.state.reply.seq
};
} else if (this.state.reply.content) {
head = {
reply: '' + this.state.reply.seq
};
if (typeof msg == 'string') {
msg = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.parse(msg);
this.applyMentionResolution(msg);
}
msg = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.append(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.sanitizeEntities(this.state.reply.content), msg);
}
this.handleCancelReply();
} else if (typeof msg == 'string' && this.mentionedUsers && this.mentionedUsers.length) {
const parsed = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.parse(msg);
this.applyMentionResolution(parsed);
msg = parsed;
}
this.mentionedUsers = [];
if (typeHint) {
head = {
...(head || {}),
'x-im-type': typeHint
};
}
const topicForDraft = this.state.topic;
const draftVersionAtSend = this.state.draftVersion || 0;
const doSend = () => {
const result = this.props.sendMessage(msg, uploadCompletionPromise, uploader, head);
if (originalText != null && result && typeof result.then == 'function' && topicForDraft) {
result.then(() => this.clearDraft(topicForDraft, draftVersionAtSend));
}
return result;
};
const urlMatch = originalText && originalText.match(/https?:\/\/\S+/);
if (urlMatch) {
return (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_19__.checkURL)(urlMatch[0], 'message_compose').then(result => {
if (result.decision === 'allow') {
return doSend();
}
return new Promise(resolve => {
if (this.state.riskDialog) this.state.riskDialog.resolve(false);
this.setState({
riskDialog: {
blocked: result.decision === 'block',
challengeId: result.risk_challenge_id,
send: doSend,
resolve
}
});
});
}).catch(_ => doSend());
}
return doSend();
}
handleRiskConfirm() {
const dialog = this.state.riskDialog;
if (!dialog) return;
this.setState({
riskDialog: null
});
const finish = () => dialog.resolve(dialog.send());
if (dialog.challengeId) {
(0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_19__.confirmRiskChallenge)(dialog.challengeId, 'continue').then(finish).catch(finish);
} else {
finish();
}
}
handleRiskCancel() {
const dialog = this.state.riskDialog;
if (!dialog) return;
this.setState({
riskDialog: null
});
if (dialog.challengeId && !dialog.blocked) {
(0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_19__.confirmRiskChallenge)(dialog.challengeId, 'cancel').catch(_ => {});
}
dialog.resolve(false);
}
retrySend(pub) {
this.props.sendMessage(pub.content, undefined, undefined, pub.head).then(_ => {
const topic = this.props.tinode.getTopic(this.state.topic);
topic.delMessagesList([pub.seq], true);
});
}
sendFileAttachment(file) {
const maxInbandAttachmentSize = this.props.tinode.getServerParam('maxMessageSize', _config_js__WEBPACK_IMPORTED_MODULE_15__.MAX_INBAND_ATTACHMENT_SIZE) * 0.75 - 1024 | 0;
if (tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.TheCard.isFileSupported(file.type, file.name) || file.type == tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.TheCard.contentType) {
if (this.sendTheCardAttachment(file, maxInbandAttachmentSize)) {
return;
}
}
const jsonMimeConverter = fileType => fileType === _config_js__WEBPACK_IMPORTED_MODULE_15__.DRAFTY_FR_MIME_TYPE_LEGACY ? 'application/octet-stream' : fileType;
if (file.size > maxInbandAttachmentSize) {
const uploader = (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_19__.createChatUploader)(this.props.tinode);
if (!uploader) {
this.props.onError(this.props.intl.formatMessage(messages.cannot_initiate_upload));
return;
}
const uploadCompletionPromise = uploader.upload(file);
const msg = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.attachFile(null, {
mime: jsonMimeConverter(file.type),
filename: file.name,
size: file.size,
urlPromise: uploadCompletionPromise
});
this.sendMessage(msg, uploadCompletionPromise, uploader, 'file');
} else {
(0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_17__.fileToBase64)(file).then(b64 => this.sendMessage(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.attachFile(null, {
mime: jsonMimeConverter(b64.mime),
data: b64.bits,
filename: b64.name,
size: file.size
}), undefined, undefined, 'file')).catch(err => this.props.onError(err.message, 'err'));
}
}
sendTheCardAttachment(file, maxInbandAttachmentSize) {
if (file.size > maxInbandAttachmentSize) {
return false;
}
if (file.type == tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.TheCard.contentType) {
this.sendMessage(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.appendTheCard(null, file.object));
return true;
}
(0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_17__.importVCard)(file).then(card => {
this.sendMessage(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.appendTheCard(null, card));
}).catch(err => {
this.props.onError(this.props.intl.formatMessage(messages.cannot_parse_vcard, {
error: err.message
}), 'err');
});
return true;
}
handleAttachFile(file) {
const maxExternAttachmentSize = this.props.tinode.getServerParam('maxFileUploadSize', _config_js__WEBPACK_IMPORTED_MODULE_15__.MAX_EXTERN_ATTACHMENT_SIZE);
if (file.size > maxExternAttachmentSize) {
this.props.onError(this.props.intl.formatMessage(messages.file_attachment_too_large, {
size: (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_21__.bytesToHumanSize)(file.size),
limit: (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_21__.bytesToHumanSize)(maxExternAttachmentSize)
}), 'err');
} else {
this.setState({
docPreview: {
file: file,
name: file.name,
size: file.size,
type: file.type
}
});
}
}
handleCallHangup(topic, seq) {
this.props.onVideoCallClosed();
this.setState({
rtcPanel: null
});
this.props.onCallHangup(topic, seq);
}
handleCallPanelToggle() {
this.setState({
minimizedCallPanel: !this.state.minimizedCallPanel
});
}
sendImageAttachment(caption, blob) {
const mime = this.state.imagePreview.mime;
const width = this.state.imagePreview.width;
const height = this.state.imagePreview.height;
const fname = this.state.imagePreview.filename;
const maxInbandAttachmentSize = this.props.tinode.getServerParam('maxMessageSize', _config_js__WEBPACK_IMPORTED_MODULE_15__.MAX_INBAND_ATTACHMENT_SIZE) * 0.75 - 1024 | 0;
if (blob.size > maxInbandAttachmentSize) {
const uploader = (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_19__.createChatUploader)(this.props.tinode);
if (!uploader) {
this.props.onError(this.props.intl.formatMessage(messages.cannot_initiate_upload));
return;
}
const uploadCompletionPromise = uploader.upload(blob);
(0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_17__.imageScaled)(blob, _config_js__WEBPACK_IMPORTED_MODULE_15__.IMAGE_PREVIEW_DIM, _config_js__WEBPACK_IMPORTED_MODULE_15__.IMAGE_PREVIEW_DIM, -1, false).then(scaled => (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_17__.blobToBase64)(scaled.blob)).then(b64 => {
let msg = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.insertImage(null, 0, {
mime: mime,
_tempPreview: b64.bits,
bits: b64.bits,
width: width,
height: height,
filename: fname,
size: blob.size,
urlPromise: uploadCompletionPromise
});
if (caption) {
msg = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.appendLineBreak(msg);
msg = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.append(msg, tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.parse(caption));
}
this.sendMessage(msg, uploadCompletionPromise, uploader, 'image');
}).catch(err => this.props.onError(err, 'err'));
return;
}
(0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_17__.blobToBase64)(blob).then(b64 => {
let msg = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.insertImage(null, 0, {
mime: b64.mime,
bits: b64.bits,
width: width,
height: height,
filename: fname,
size: blob.size
});
if (caption) {
msg = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.appendLineBreak(msg);
msg = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.append(msg, tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.parse(caption));
}
this.sendMessage(msg, undefined, undefined, 'image');
});
}
sendVideoAttachment(caption, videoBlob, previewBlob, params) {
const width = params.width;
const height = params.height;
const maxInbandAttachmentSize = this.props.tinode.getServerParam('maxMessageSize', _config_js__WEBPACK_IMPORTED_MODULE_15__.MAX_INBAND_ATTACHMENT_SIZE) * 0.75 - 1024 | 0;
const uploads = [];
let uploader;
if (videoBlob.size + previewBlob.size > maxInbandAttachmentSize) {
uploader = (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_19__.createChatUploader)(this.props.tinode);
if (!uploader) {
this.props.onError(this.props.intl.formatMessage(messages.cannot_initiate_upload));
return;
}
uploads[0] = videoBlob.size > maxInbandAttachmentSize * 0.675 ? uploader.upload(videoBlob) : null;
uploads[1] = previewBlob.size > maxInbandAttachmentSize * 0.275 ? uploader.upload(previewBlob) : null;
}
if (uploads.length == 0) {
Promise.all([(0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_17__.blobToBase64)(videoBlob), (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_17__.blobToBase64)(previewBlob)]).then(b64s => {
const [v64, i64] = b64s;
let msg = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.insertVideo(null, 0, {
mime: v64.mime,
bits: v64.bits,
preview: i64.bits,
premime: i64.mime,
width: width,
height: height,
duration: params.duration,
filename: params.name,
size: videoBlob.size
});
if (caption) {
msg = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.appendLineBreak(msg);
msg = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.append(msg, tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.parse(caption));
}
this.sendMessage(msg, undefined, undefined, 'video');
});
return;
}
const uploadCompletionPromise = Promise.all(uploads);
const b64conv = [];
b64conv[0] = uploads[0] ? null : (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_17__.blobToBase64)(videoBlob);
b64conv[1] = uploads[1] ? null : (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_17__.imageScaled)(previewBlob, _config_js__WEBPACK_IMPORTED_MODULE_15__.MAX_IMAGE_DIM, _config_js__WEBPACK_IMPORTED_MODULE_15__.MAX_IMAGE_DIM, -1, false).then(scaled => (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_17__.blobToBase64)(scaled.blob));
b64conv[2] = (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_17__.imageScaled)(previewBlob, _config_js__WEBPACK_IMPORTED_MODULE_15__.VIDEO_PREVIEW_DIM, _config_js__WEBPACK_IMPORTED_MODULE_15__.VIDEO_PREVIEW_DIM, -1, false).then(scaled => (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_17__.blobToBase64)(scaled.blob));
Promise.all(b64conv).then(b64s => {
const [video, img, preview] = b64s;
let msg = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.insertVideo(null, 0, {
mime: params.mime,
bits: video ? video.bits : null,
_tempPreview: preview.bits,
preview: img ? img.bits : preview.bits,
premime: img ? img.mime : preview.mime,
width: width,
height: height,
duration: params.duration,
filename: params.name,
size: videoBlob.size,
urlPromise: uploadCompletionPromise
});
if (caption) {
msg = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.appendLineBreak(msg);
msg = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.append(msg, tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.parse(caption));
}
this.sendMessage(msg, uploadCompletionPromise, uploader, 'video');
}).catch(err => this.props.onError(err.message, 'err'));
}
handleAttachImageOrVideo(file) {
const maxExternAttachmentSize = this.props.tinode.getServerParam('maxFileUploadSize', _config_js__WEBPACK_IMPORTED_MODULE_15__.MAX_EXTERN_ATTACHMENT_SIZE);
if (file.type.startsWith('video/')) {
this.setState({
videoPreview: {
url: URL.createObjectURL(file),
blob: file,
filename: file.name,
size: file.size,
mime: file.type
}
});
return;
}
(0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_17__.imageScaled)(file, _config_js__WEBPACK_IMPORTED_MODULE_15__.MAX_IMAGE_DIM, _config_js__WEBPACK_IMPORTED_MODULE_15__.MAX_IMAGE_DIM, maxExternAttachmentSize, false).then(scaled => {
this.setState({
imagePreview: {
url: URL.createObjectURL(scaled.blob),
blob: scaled.blob,
filename: scaled.name,
width: scaled.width,
height: scaled.height,
size: scaled.blob.size,
mime: scaled.mime
}
});
}).catch(err => {
this.props.onError(err.message, 'err');
});
}
handleFileDrop(files) {
if (!files || files.length == 0) {
return;
}
const file = files[0];
if (file.type && file.type.startsWith('image/')) {
this.handleAttachImageOrVideo(file);
} else {
this.handleAttachFile(file);
}
}
sendAudioAttachment(url, preview, duration) {
fetch(url).then(result => result.blob()).then(blob => {
const maxInbandAttachmentSize = this.props.tinode.getServerParam('maxMessageSize', _config_js__WEBPACK_IMPORTED_MODULE_15__.MAX_INBAND_ATTACHMENT_SIZE) * 0.75 - 1024;
if (blob.size > maxInbandAttachmentSize) {
const uploader = (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_19__.createChatUploader)(this.props.tinode);
if (!uploader) {
this.props.onError(this.props.intl.formatMessage(messages.cannot_initiate_upload));
return;
}
const uploadCompletionPromise = uploader.upload(blob);
const msg = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.appendAudio(null, {
mime: blob.type,
size: blob.size,
duration: duration,
preview: preview,
urlPromise: uploadCompletionPromise
});
this.sendMessage(msg, uploadCompletionPromise, uploader, 'voice');
} else {
(0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_17__.blobToBase64)(blob).then(b64 => {
this.sendMessage(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.appendAudio(null, {
mime: b64.mime,
bits: b64.bits,
size: blob.size,
duration: duration,
preview: preview
}), undefined, undefined, 'voice');
});
}
}).catch(err => {
this.props.onError(err.message, 'err');
});
;
}
handleCancelUpload(seq, uploader) {
const topic = this.props.tinode.getTopic(this.state.topic);
const found = topic.findMessage(seq);
if (found) {
found._cancelled = true;
}
uploader.cancel();
}
handlePickReply(seq, content, senderId, senderName) {
if (!seq || !content) {
this.setState({
reply: null
});
return;
}
content = typeof content == 'string' ? tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.init(content) : content;
if (tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.isValid(content)) {
content = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.replyContent(content, _config_js__WEBPACK_IMPORTED_MODULE_15__.QUOTED_REPLY_LENGTH);
} else {
content = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.append(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.init('\u26A0 '), tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.wrapInto(this.props.intl.formatMessage(messages.invalid_content), 'EM'));
}
this.setState({
reply: {
content: tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.quote(senderName, senderId, content),
seq: seq
}
});
this.props.onCancelForwardMessage();
}
handleEditMessage(seq, content) {
if (!seq || !content) {
this.setState({
reply: null
});
return;
}
content = typeof content == 'string' ? tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.init(content) : content;
const editable = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.toMarkdown(content);
if (tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.isValid(content)) {
content = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.replyContent(content, _config_js__WEBPACK_IMPORTED_MODULE_15__.EDIT_PREVIEW_LENGTH);
} else {
content = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.append(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.init('\u26A0 '), tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.wrapInto(this.props.intl.formatMessage(messages.invalid_content), 'EM'));
}
this.setState({
reply: {
content: tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.quote(this.props.intl.formatMessage(messages.editing_message), null, content),
seq: seq,
editing: true
},
contentToEdit: editable
});
this.props.onCancelForwardMessage();
}
handleCancelReply() {
this.setState({
reply: null,
contentToEdit: null
});
this.props.onCancelForwardMessage();
}
handleQuoteClick(replyToSeq) {
const ref = this.getOrCreateMessageRef(replyToSeq);
if (ref && ref.current) {
ref.current.scrollIntoView({
block: "center",
behavior: "smooth"
});
ref.current.classList.add('flash');
setTimeout(_ => {
ref.current.classList.remove('flash');
}, 1000);
} else {
console.error("Unresolved message ref", replyToSeq);
if (this.props.onError) {
this.props.onError('该消息已被删除或撤回', 'err');
}
}
}
jumpToMessage(seq) {
const topic = this.props.tinode && this.props.topic ? this.props.tinode.getTopic(this.props.topic) : null;
if (!topic || !seq || isNaN(seq)) {
return;
}
_lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_20__["default"].removeUrlParam(window.location.hash, 'jumpseq'));
const jump = () => window.setTimeout(() => this.handleQuoteClick(seq), 150);
if (topic.findMessage(seq)) {
jump();
} else {
topic.getMeta(topic.startMetaQuery().withData(Math.max(1, seq - 20), seq + 21, 41).build()).then(jump).catch(err => this.props.onError(err.message, 'err'));
}
}
handleUnpinMessage(seq) {
const topic = this.props.tinode.getTopic(this.state.topic);
topic.pinMessage(seq, false);
}
isDragEnabled() {
return this.state.isWriter && !this.state.unconfirmed && !this.props.forwardMessage && !this.state.peerMessagingDisabled;
}
handleDragStart(e) {
e.preventDefault();
e.stopPropagation();
e.dataTransfer.clearData();
}
handleDragIn(e) {
e.preventDefault();
e.stopPropagation();
this.dragCounter++;
if (e.dataTransfer.items && e.dataTransfer.items.length > 0) {
this.setState({
dragging: true
});
}
}
handleDragOut(e) {
e.preventDefault();
e.stopPropagation();
this.dragCounter--;
if (this.dragCounter <= 0) {
this.setState({
dragging: false
});
}
}
handleDrag(e) {
e.preventDefault();
e.stopPropagation();
}
handleDrop(e) {
e.preventDefault();
e.stopPropagation();
this.setState({
dragging: false
});
if (this.isDragEnabled() && e.dataTransfer.files && e.dataTransfer.files.length > 0) {
this.handleFileDrop(e.dataTransfer.files);
this.dragCounter = 0;
}
}
render() {
const {
formatMessage
} = this.props.intl;
const overlay = this.state.rtcPanel && (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)(react__WEBPACK_IMPORTED_MODULE_0__.Suspense, {
fallback: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("div", {
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, {
id: "loading_note",
defaultMessage: "Loading...",
description: "Message shown when component is loading"
}, void 0, false)
}, void 0, false),
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)(CallPanel, {
topic: this.state.topic,
seq: this.props.callSeq,
callState: this.props.callState,
callAudioOnly: this.props.callAudioOnly,
tinode: this.props.tinode,
title: this.state.title,
avatar: this.state.avatar || true,
minimized: this.state.minimizedCallPanel,
onError: this.props.onError,
onHangup: this.handleCallHangup,
onToggleMinimize: this.handleCallPanelToggle,
onInvite: this.props.onCallInvite,
onSendOffer: this.props.onCallSendOffer,
onIceCandidate: this.props.onCallIceCandidate,
onSendAnswer: this.props.onCallSendAnswer
}, void 0, false)
}, void 0, false);
const riskDialog = this.state.riskDialog && (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)(_security_support_view_jsx__WEBPACK_IMPORTED_MODULE_13__.RiskConfirmDialog, {
blocked: this.state.riskDialog.blocked,
onConfirm: this.handleRiskConfirm,
onCancel: this.handleRiskCancel
}, void 0, false);
let component;
if (!this.state.topic) {
component = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)(_logo_view_jsx__WEBPACK_IMPORTED_MODULE_10__["default"], {
serverVersion: this.props.serverVersion,
serverAddress: this.props.serverAddress
}, void 0, false);
} else {
let component2;
if (this.state.imagePreview) {
component2 = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)(react__WEBPACK_IMPORTED_MODULE_0__.Suspense, {
fallback: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("div", {
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, {
id: "loading_note",
defaultMessage: "Loading...",
description: "Message shown when component is loading"
}, void 0, false)
}, void 0, false),
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)(ImagePreview, {
content: this.state.imagePreview,
tinode: this.props.tinode,
reply: this.state.reply,
onCancelReply: this.handleCancelReply,
onClose: this.handleClosePreview,
onSendMessage: this.sendImageAttachment
}, void 0, false)
}, void 0, false);
} else if (this.state.videoPreview) {
component2 = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)(react__WEBPACK_IMPORTED_MODULE_0__.Suspense, {
fallback: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("div", {
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, {
id: "loading_note",
defaultMessage: "Loading...",
description: "Message shown when component is loading"
}, void 0, false)
}, void 0, false),
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)(VideoPreview, {
content: this.state.videoPreview,
tinode: this.props.tinode,
reply: this.state.reply,
onError: this.props.onError,
onCancelReply: this.handleCancelReply,
onClose: this.handleClosePreview,
onSendMessage: this.sendVideoAttachment
}, void 0, false)
}, void 0, false);
} else if (this.state.imagePostview) {
component2 = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)(react__WEBPACK_IMPORTED_MODULE_0__.Suspense, {
fallback: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("div", {
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, {
id: "loading_note",
defaultMessage: "Loading...",
description: "Message shown when component is loading"
}, void 0, false)
}, void 0, false),
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)(ImagePreview, {
content: this.state.imagePostview,
onClose: this.handleClosePreview
}, void 0, false)
}, void 0, false);
} else if (this.state.videoPostview) {
component2 = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)(react__WEBPACK_IMPORTED_MODULE_0__.Suspense, {
fallback: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("div", {
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, {
id: "loading_note",
defaultMessage: "Loading...",
description: "Message shown when component is loading"
}, void 0, false)
}, void 0, false),
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)(VideoPreview, {
content: this.state.videoPostview,
tinode: this.props.tinode,
onError: this.props.onError,
onClose: this.handleClosePreview
}, void 0, false)
}, void 0, false);
} else if (this.state.docPreview) {
if (tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.TheCard.isFileSupported(this.state.docPreview.type, this.state.docPreview.name) || this.state.docPreview.type == tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.TheCard.contentType) {
component2 = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)(react__WEBPACK_IMPORTED_MODULE_0__.Suspense, {
fallback: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("div", {
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, {
id: "loading_note",
defaultMessage: "Loading...",
description: "Message shown when component is loading"
}, void 0, false)
}, void 0, false),
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)(TheCardPreview, {
content: this.state.docPreview,
tinode: this.props.tinode,
reply: this.state.reply,
onCancelReply: this.handleCancelReply,
onClose: this.handleClosePreview,
onSendMessage: this.sendFileAttachment
}, void 0, false)
}, void 0, false);
} else {
component2 = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)(react__WEBPACK_IMPORTED_MODULE_0__.Suspense, {
fallback: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("div", {
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, {
id: "loading_note",
defaultMessage: "Loading...",
description: "Message shown when component is loading"
}, void 0, false)
}, void 0, false),
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)(DocPreview, {
content: this.state.docPreview,
tinode: this.props.tinode,
reply: this.state.reply,
onCancelReply: this.handleCancelReply,
onClose: this.handleClosePreview,
onSendMessage: this.sendFileAttachment
}, void 0, false)
}, void 0, false);
}
} else {
const topic = this.props.tinode.getTopic(this.state.topic);
const isChannel = topic.isChannelType() || topic.chan;
const groupTopic = topic.isGroupType() && !isChannel;
const icon_badges = [];
if (topic.trusted) {
if (topic.trusted.verified) {
icon_badges.push({
icon: 'verified',
color: 'badge-inv'
});
}
if (topic.trusted.staff) {
icon_badges.push({
icon: 'staff',
color: 'badge-inv'
});
}
if (topic.trusted.danger) {
icon_badges.push({
icon: 'dangerous',
color: 'badge-inv'
});
}
}
const pinnedMessages = [];
this.state.pins.forEach(seq => pinnedMessages.push(topic.latestMsgVersion(seq) || topic.findMessage(seq)));
const messageNodes = [];
let previousFrom = null;
let prevDate = null;
let chatBoxClass = null;
topic.messages((msg, prev, next, i) => {
let nextFrom = next ? next.from || 'chan' : null;
let sequence = 'single';
let thisFrom = msg.from || 'chan';
if (thisFrom == previousFrom) {
if (thisFrom == nextFrom) {
sequence = 'middle';
} else {
sequence = 'last';
}
} else if (thisFrom == nextFrom) {
sequence = 'first';
}
previousFrom = thisFrom;
const isReply = !(thisFrom == this.props.myUserId);
const deliveryStatus = topic.msgStatus(msg, true);
let userFrom = thisFrom,
userName,
userAvatar;
const user = topic.userDesc(thisFrom);
if (user && user.public) {
userName = user.public.fn;
userAvatar = (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_17__.makeImageUrl)(user.public.photo);
}
chatBoxClass = groupTopic ? 'chat-box group' : 'chat-box';
const ref = this.getOrCreateMessageRef(msg.seq);
let replyToSeq = msg.head ? parseInt(msg.head.reply) : null;
if (!replyToSeq || isNaN(replyToSeq)) {
replyToSeq = null;
}
if (msg.hi) {
messageNodes.push((0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)(_widgets_meta_message_jsx__WEBPACK_IMPORTED_MODULE_11__["default"], {
deleted: true,
deletedText: this.props.intl.formatMessage(messages.message_deleted)
}, msg.seq, false));
} else {
const thisDate = new Date(msg.ts);
if (!prevDate || prevDate.toDateString() != thisDate.toDateString()) {
messageNodes.push((0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)(_widgets_meta_message_jsx__WEBPACK_IMPORTED_MODULE_11__["default"], {
date: (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_21__.relativeDateFormat)(msg.ts),
locale: this.props.intl.locale
}, 'date-' + msg.seq, false));
prevDate = thisDate;
}
messageNodes.push((0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)(_widgets_chat_message_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], {
tinode: this.props.tinode,
topic: this.state.topic,
content: msg.content,
mimeType: msg.head && msg.head.mime,
head: msg.head,
replyToSeq: replyToSeq,
edited: msg.head && !msg.head.webrtc && msg.head.replace,
timestamp: msg.ts,
response: isReply,
seq: msg.seq,
isGroup: groupTopic,
isChan: this.state.channel,
userFrom: userFrom,
userName: userName,
userAvatar: userAvatar,
senderRole: groupTopic && this.state.groupRoles ? this.state.groupRoles[thisFrom] : null,
sequence: sequence,
received: deliveryStatus,
uploader: msg._uploader,
userIsWriter: this.state.isWriter,
userIsAdmin: this.state.isAdmin,
relationship: this.state.relationshipContext ? this.state.relationshipContext.relationship : null,
onSendFriendVerification: this.handleSendFriendVerification,
selectMode: this.props.selectMode,
selected: this.props.selectedSeqs && this.props.selectedSeqs.includes(msg.seq),
onToggleSelect: this.props.onToggleMessageSelect,
pinned: this.state.pins.includes(msg.seq),
viewportWidth: this.props.viewportWidth,
showContextMenu: this.handleShowMessageContextMenu,
onExpandMedia: this.handleExpandMedia,
onFormResponse: this.handleFormResponse,
onCancelUpload: this.handleCancelUpload,
pickReply: this.handlePickReply,
editMessage: this.handleEditMessage,
onQuoteClick: this.handleQuoteClick,
onAcceptCall: this.props.onAcceptCall,
onError: this.props.onError,
ref: ref
}, msg.seq, false));
}
});
let lastSeen = null;
if (isChannel) {
if (topic.subcnt) {
lastSeen = formatMessage(messages.subscriber_count, {
count: topic.subcnt
});
}
} else {
const cont = this.props.tinode.getMeTopic().getContact(this.state.topic);
if (cont) {
if (tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.isP2PTopicName(cont.topic)) {
if (cont.online) {
lastSeen = formatMessage(messages.online_now);
} else if (cont.seen) {
lastSeen = formatMessage(messages.last_seen, {
timestamp: (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_21__.shortDateFormat)(cont.seen.when, this.props.intl.locale)
});
}
} else if (tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.isGroupTopicName(cont.topic)) {
if (topic.subcnt) {
lastSeen = formatMessage(messages.member_count, {
count: topic.subcnt
});
}
}
}
}
const avatar = this.state.avatar || true;
const online = this.state.deleted || topic.isSelfType() ? null : this.props.online ? 'online' + (this.state.typingIndicator ? ' typing' : '') : 'offline';
const titleClass = 'panel-title' + (this.state.deleted ? ' deleted' : '');
const darkModeClass = this.props.colorSchema == 'dark' ? 'dark' : '';
const editingMessage = !!(this.state.reply && this.state.reply.editing);
let messagesComponent = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.Fragment, {
children: [this.state.groupAnnouncement ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("a", {
href: "#",
id: "group-announcement-banner",
onClick: this.handleShowAnnouncement,
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("i", {
className: "material-icons",
children: "campaign"
}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("span", {
children: this.state.groupAnnouncement.content
}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("i", {
className: "material-icons",
children: "chevron_right"
}, void 0, false)]
}, void 0, true) : null, this.state.pendingJoinRequests > 0 ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("a", {
href: "#",
id: "group-join-request-banner",
onClick: this.handleShowJoinRequests,
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("i", {
className: "material-icons",
children: "person_add_alt"
}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("span", {
children: ["新邀请进群申请(", this.state.pendingJoinRequests, ")"]
}, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("i", {
className: "material-icons",
children: "chevron_right"
}, void 0, false)]
}, void 0, true) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("div", {
id: "messages-container",
className: darkModeClass,
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("button", {
id: "go-to-latest",
className: 'action-button' + (this.state.showGoToLastButton ? '' : ' hidden'),
onClick: this.goToLatestMessage,
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("i", {
className: "material-icons",
children: "arrow_downward"
}, void 0, false)
}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("div", {
id: "messages-panel",
ref: this.handleScrollReference,
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("ul", {
id: "scroller",
className: chatBoxClass,
children: messageNodes
}, void 0, false)
}, void 0, false), !this.state.isReader ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("div", {
id: "write-only-background",
children: this.state.readingBlocked ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("div", {
id: "write-only-note",
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, {
id: "messages_not_readable",
defaultMessage: "no access to messages",
description: "Message shown in topic without the read access"
}, void 0, false)
}, void 0, false) : null
}, void 0, false) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("div", {
className: 'toast' + (this.state.toast ? ' show' : ''),
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("i", {
className: "material-icons",
children: "check"
}, void 0, false), "\xA0", this.state.toast]
}, void 0, true)]
}, void 0, true), this.state.peerMessagingDisabled && !this.state.unconfirmed ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("div", {
id: "peer-messaging-disabled-note",
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("i", {
className: "material-icons secondary",
children: "block"
}, void 0, false), " ", (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, {
id: "peers_messaging_disabled",
defaultMessage: "Peer's messaging is disabled.",
description: "Shown when the p2p peer's messaging is disabled"
}, void 0, false), " ", (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("a", {
href: "#",
onClick: this.handleEnablePeer,
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, {
id: "enable_peers_messaging",
defaultMessage: "Enable",
description: "Call to action to enable peer's messaging"
}, void 0, false)
}, void 0, false), "."]
}, void 0, true) : null, !this.state.unconfirmed && this.state.relationshipContext && this.state.relationshipContext.relationship == 'pending_inbound' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("div", {
id: "relationship-status-note",
children: "以上是打招呼的消息"
}, void 0, false) : null, !this.state.unconfirmed && this.state.relationshipContext && this.state.relationshipContext.relationship == 'pending_outbound' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("div", {
id: "relationship-status-note",
children: "好友申请正在等待处理"
}, void 0, false) : null, !this.state.unconfirmed && this.state.relationshipContext && this.state.relationshipContext.relationship == 'none' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("div", {
id: "relationship-status-note",
children: ["你们还不是好友,发送消息前需先验证 ", (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("a", {
href: "#",
onClick: this.handleSendFriendVerification,
children: "发送朋友验证"
}, void 0, false)]
}, void 0, true) : null, this.props.selectMode ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("div", {
id: "batch-action-bar",
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("div", {
id: "batch-action-count",
children: ["已选 ", this.props.selectedSeqs.length, " 个"]
}, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("div", {
id: "batch-action-buttons",
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("a", {
href: "#",
onClick: e => {
e.preventDefault();
this.props.selectedSeqs.length && this.props.onShowBatchForward();
},
className: this.props.selectedSeqs.length ? '' : 'disabled',
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("i", {
className: "material-icons",
children: "forward"
}, void 0, false), "转发"]
}, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("a", {
href: "#",
onClick: e => {
e.preventDefault();
this.handleBatchFavorite();
},
className: this.props.selectedSeqs.length ? '' : 'disabled',
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("i", {
className: "material-icons",
children: "star_border"
}, void 0, false), "收藏"]
}, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("a", {
href: "#",
onClick: e => {
e.preventDefault();
this.handleBatchDelete();
},
className: this.props.selectedSeqs.length ? '' : 'disabled',
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("i", {
className: "material-icons",
children: "delete_outline"
}, void 0, false), "删除"]
}, void 0, true)]
}, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("a", {
href: "#",
id: "batch-action-cancel",
onClick: e => {
e.preventDefault();
this.props.onExitSelectMode();
},
children: "取消"
}, void 0, false)]
}, void 0, true) : this.state.unconfirmed ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)(_widgets_invitation_jsx__WEBPACK_IMPORTED_MODULE_7__["default"], {
onAction: this.handleNewChatAcceptance
}, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)(_widgets_send_message_jsx__WEBPACK_IMPORTED_MODULE_14__["default"], {
tinode: this.props.tinode,
topicName: this.state.topic,
noInput: !!this.props.forwardMessage,
disabled: !this.state.isWriter || this.state.deleted,
reply: this.state.reply,
initMessage: this.state.contentToEdit != null ? this.state.contentToEdit : this.state.draftText,
sendOnEnter: this.props.sendOnEnter,
onKeyPress: this.sendKeyPress,
onRecordingProgress: this.sendKeyPress,
onMessageChange: this.props.forwardMessage ? null : this.handleComposerChange,
onMentionSearch: this.props.forwardMessage || !groupTopic ? null : this.mentionSearch,
onMentionSelected: this.mentionSelected,
onSendMessage: this.sendMessage,
onAttachFile: this.props.forwardMessage || editingMessage ? null : this.handleAttachFile,
onAttachImage: this.props.forwardMessage || editingMessage ? null : this.handleAttachImageOrVideo,
onAttachAudio: this.props.forwardMessage || editingMessage ? null : this.sendAudioAttachment,
canStartCall: !this.props.forwardMessage && this.props.canStartCall,
onStartAudioCall: this.props.onStartAudioCall,
onStartVideoCall: this.props.onStartVideoCall,
onError: this.props.onError,
onQuoteClick: this.handleQuoteClick,
onCancelReply: this.handleCancelReply
}, void 0, false)]
}, void 0, true);
component2 = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.Fragment, {
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("div", {
id: "topic-caption-panel",
className: "caption-panel",
children: [this.props.displayMobile ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("a", {
href: "#",
id: "hide-message-view",
onClick: e => {
e.preventDefault();
this.leave(this.state.topic);
this.props.onHideMessagesView();
},
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("i", {
className: "material-icons",
children: "arrow_back"
}, void 0, false)
}, void 0, false) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("div", {
className: "avatar-box",
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)(_widgets_letter_tile_jsx__WEBPACK_IMPORTED_MODULE_8__["default"], {
authorizeURL: this.props.tinode.authorizeURL,
avatar: avatar,
topic: this.state.topic,
title: this.state.title,
deleted: this.state.deleted
}, void 0, false), !isChannel ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("span", {
className: online
}, void 0, false) : null]
}, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("div", {
id: "topic-title-group",
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("div", {
id: "topic-title",
className: titleClass,
children: [this.state.title || (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("i", {
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, {
id: "unnamed_topic",
defaultMessage: "Unnamed",
description: "Title shown when the topic has no name"
}, void 0, false)
}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)(_widgets_contact_badges_jsx__WEBPACK_IMPORTED_MODULE_4__["default"], {
badges: icon_badges
}, void 0, false)]
}, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("div", {
id: "topic-last-seen",
children: lastSeen
}, void 0, false)]
}, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("div", {
style: {
marginLeft: 'auto'
}
}, void 0, false), !this.props.displayMobile && this.state.pins.length > 0 ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)(_widgets_pinned_messages_jsx__WEBPACK_IMPORTED_MODULE_12__["default"], {
tinode: this.props.tinode,
pins: this.state.pins,
messages: pinnedMessages,
selected: this.state.selectedPin,
isAdmin: this.state.isAdmin,
setSelected: index => this.setState({
selectedPin: index
}),
onSelected: this.handleQuoteClick,
onCancel: this.handleUnpinMessage
}, void 0, false) : null, groupTopic ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)(_widgets_group_subs_jsx__WEBPACK_IMPORTED_MODULE_6__["default"], {
tinode: this.props.tinode,
subscribers: this.state.onlineSubs
}, void 0, false) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("div", {
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("a", {
href: "#",
onClick: this.handleContextClick,
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("i", {
className: "material-icons",
children: "more_vert"
}, void 0, false)
}, void 0, false)
}, void 0, false)]
}, void 0, true), this.props.displayMobile ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.Fragment, {
children: [this.state.pins.length > 0 ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)(_widgets_pinned_messages_jsx__WEBPACK_IMPORTED_MODULE_12__["default"], {
tinode: this.props.tinode,
pins: this.state.pins,
messages: pinnedMessages,
selected: this.state.selectedPin,
isAdmin: this.state.isAdmin,
setSelected: index => this.setState({
selectedPin: index
}),
onSelected: this.handleQuoteClick,
onCancel: this.handleUnpinMessage
}, void 0, false) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)(_widgets_error_panel_jsx__WEBPACK_IMPORTED_MODULE_5__["default"], {
level: this.props.errorLevel,
text: this.props.errorText,
onClearError: this.props.onError
}, void 0, false)]
}, void 0, true) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)(_widgets_load_spinner_jsx__WEBPACK_IMPORTED_MODULE_9__["default"], {
show: this.state.fetchingMessages
}, void 0, false), messagesComponent, this.state.dragging && this.isDragEnabled() ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("div", {
className: "drag-n-drop",
children: formatMessage(messages.drag_file)
}, void 0, false) : null]
}, void 0, true);
}
component = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_22__.jsxDEV)("div", {
id: "topic-view",
ref: this.mountDnDEvents,
children: [component2, overlay, riskDialog]
}, void 0, true);
}
return component;
}
}
;
/* harmony default export */ __webpack_exports__["default"] = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(MessagesView));
/***/ }),
/***/ "./src/widgets/attachment.jsx":
/*!************************************!*\
!*** ./src/widgets/attachment.jsx ***!
\************************************/
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": function() { return /* binding */ Attachment; }
/* harmony export */ });
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react");
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl");
/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var _file_progress_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./file-progress.jsx */ "./src/widgets/file-progress.jsx");
/* harmony import */ var _lib_im_api_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../lib/im-api.js */ "./src/lib/im-api.js");
/* harmony import */ var _lib_strformat_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../lib/strformat.js */ "./src/lib/strformat.js");
/* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js");
/* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js");
class Attachment extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) {
constructor(props) {
super(props);
this.state = {
downloader: null,
progress: 0
};
this.downloadFile = this.downloadFile.bind(this);
this.handleCancel = this.handleCancel.bind(this);
}
downloadFile(url, filename, mimetype) {
if (!url) {
this.props.onError("Invalid download URL '" + url + "'");
return;
}
const downloader = (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_3__.createFileDownloader)(this.props.tinode);
this.setState({
downloader: downloader
});
downloader.download(url, filename, mimetype, loaded => this.setState({
progress: loaded / this.props.size
}), err => this.props.onError(err, 'err')).then(_ => this.setState({
downloader: null,
progress: 0
})).catch(err => {
if (err) {
this.props.onError("Error downloading file: " + err.message, 'err');
}
this.setState({
downloader: null,
progress: 0
});
});
}
handleCancel() {
if (this.props.uploading) {
this.props.onCancelUpload();
} else if (this.state.downloader) {
this.state.downloader.cancel();
}
}
render() {
let filename = this.props.filename || 'file_attachment';
if (filename.length > 36) {
filename = filename.substr(0, 16) + '...' + filename.substr(-16);
}
let size = this.props.size > 0 ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", {
className: "small gray",
children: ["(", (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_4__.bytesToHumanSize)(this.props.size), ")"]
}, void 0, true) : null;
let url, helperFunc;
if (!this.props.uploading && !this.state.downloader && (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_5__.isUrlRelative)(this.props.downloadUrl)) {
url = '#';
helperFunc = e => {
e.preventDefault();
this.downloadFile(this.props.downloadUrl, this.props.filename, this.props.mimetype);
};
} else {
url = (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_5__.sanitizeUrl)(this.props.downloadUrl);
helperFunc = null;
}
const downloadWidget = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.Fragment, {
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("i", {
className: "material-icons",
children: "file_download"
}, void 0, false), " ", (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, {
id: "save_attachment",
defaultMessage: "save",
description: "Call to save an attachment"
}, void 0, false)]
}, void 0, true);
return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", {
className: "attachment",
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", {
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("i", {
className: "material-icons big gray",
children: "insert_drive_file"
}, void 0, false)
}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", {
className: "flex-column",
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", {
children: [filename, " ", size]
}, void 0, true), this.props.uploading || this.state.downloader ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(_file_progress_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], {
progress: this.props.uploading ? this.props.progress : this.state.progress,
onCancel: this.handleCancel
}, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", {
children: url ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("a", {
href: url,
download: this.props.filename,
onClick: helperFunc,
children: downloadWidget
}, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", {
className: "light-gray",
children: downloadWidget
}, void 0, false)
}, void 0, false)]
}, void 0, true)]
}, void 0, true);
}
}
;
/***/ }),
/***/ "./src/widgets/chat-message.jsx":
/*!**************************************!*\
!*** ./src/widgets/chat-message.jsx ***!
\**************************************/
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react");
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl");
/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk");
/* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var _attachment_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./attachment.jsx */ "./src/widgets/attachment.jsx");
/* harmony import */ var _forward_bundle_jsx__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./forward-bundle.jsx */ "./src/widgets/forward-bundle.jsx");
/* harmony import */ var _letter_tile_jsx__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./letter-tile.jsx */ "./src/widgets/letter-tile.jsx");
/* harmony import */ var _received_marker_jsx__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./received-marker.jsx */ "./src/widgets/received-marker.jsx");
/* harmony import */ var _lib_formatters_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../lib/formatters.js */ "./src/lib/formatters.js");
/* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js");
/* harmony import */ var _lib_navigation_js__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ../lib/navigation.js */ "./src/lib/navigation.js");
/* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js");
const VOICE_PLAYED_KEY_PREFIX = 'im-voice-played:';
function isVoicePlayed(myUid, topic, seq) {
try {
const list = JSON.parse(localStorage.getItem(VOICE_PLAYED_KEY_PREFIX + myUid + ':' + topic) || '[]');
return Array.isArray(list) && list.includes(seq);
} catch (_) {
return false;
}
}
function markVoicePlayed(myUid, topic, seq) {
try {
const key = VOICE_PLAYED_KEY_PREFIX + myUid + ':' + topic;
const list = JSON.parse(localStorage.getItem(key) || '[]');
const set = Array.isArray(list) ? list : [];
if (!set.includes(seq)) {
localStorage.setItem(key, JSON.stringify(set.concat(seq).slice(-500)));
}
} catch (_) {}
}
class BaseChatMessage extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) {
constructor(props) {
super(props);
this.state = {
progress: 0,
voicePlayed: isVoicePlayed(props.tinode.getCurrentUserID(), props.topic, props.seq)
};
if (props.uploader) {
props.uploader.onProgress = this.handleProgress.bind(this);
}
this.handleExpandImage = this.handleExpandImage.bind(this);
this.handlePlayVideo = this.handlePlayVideo.bind(this);
this.handleFormButtonClick = this.handleFormButtonClick.bind(this);
this.handleQuoteClick = this.handleQuoteClick.bind(this);
this.handleContextClick = this.handleContextClick.bind(this);
this.handleCancelUpload = this.handleCancelUpload.bind(this);
this.handleDraftyClick = this.handleDraftyClick.bind(this);
this.handleVoicePlayed = this.handleVoicePlayed.bind(this);
this.formatterContext = {
formatMessage: props.intl.formatMessage.bind(props.intl),
viewportWidth: props.viewportWidth,
authorizeURL: props.tinode.authorizeURL.bind(props.tinode),
onHandleClick: this.handleDraftyClick,
onVoicePlayed: this.handleVoicePlayed
};
}
handleDraftyClick = (e, action) => {
switch (action) {
case 'image':
this.handleExpandImage(e);
break;
case 'video':
this.handlePlayVideo(e);
break;
case 'form_button':
this.handleFormButtonClick(e);
break;
case 'quote':
this.handleQuoteClick(e);
break;
case 'contact_chat':
e.preventDefault();
try {
const pathname = new URL(e.target.dataset.val)?.pathname;
const parts = pathname.split('/').filter(Boolean);
_lib_navigation_js__WEBPACK_IMPORTED_MODULE_9__["default"].navigateTo(_lib_navigation_js__WEBPACK_IMPORTED_MODULE_9__["default"].setUrlTopic('', parts.pop() || ''));
} catch (error) {
console.error("Invalid URL:", error);
}
break;
case 'contact_find':
e.preventDefault();
let hashUrl = _lib_navigation_js__WEBPACK_IMPORTED_MODULE_9__["default"].setUrlSidePanel(window.location.hash, 'newtpk');
hashUrl = _lib_navigation_js__WEBPACK_IMPORTED_MODULE_9__["default"].addUrlParam(hashUrl, 'q', e.target.dataset.val);
hashUrl = _lib_navigation_js__WEBPACK_IMPORTED_MODULE_9__["default"].addUrlParam(hashUrl, 'tab', 'find');
_lib_navigation_js__WEBPACK_IMPORTED_MODULE_9__["default"].navigateTo(hashUrl);
break;
default:
console.info('Unhandled drafty action.', action, e.target.dataset);
break;
}
};
handleExpandImage(e) {
e.preventDefault();
this.props.onExpandMedia({
url: e.target.src,
filename: e.target.dataset.name,
width: e.target.dataset.width,
height: e.target.dataset.height,
size: e.target.dataset.size,
type: e.target.dataset.mime
});
}
handlePlayVideo(e) {
e.preventDefault();
this.props.onExpandMedia({
video: true,
url: e.target.dataset.src,
preview: e.target.src,
filename: e.target.dataset.name,
width: e.target.dataset.width,
height: e.target.dataset.height,
duration: e.target.dataset.duration,
size: e.target.dataset.size,
type: e.target.dataset.mime
});
}
handleFormButtonClick(e) {
e.preventDefault();
const data = {
seq: this.props.seq
};
data.resp = {};
if (e.target.dataset.name) {
data.resp[e.target.dataset.name] = e.target.dataset.val ? e.target.dataset.val : e.target.dataset.val === undefined ? 1 : '' + e.target.dataset.val;
}
if (e.target.dataset.act == 'url') {
data.ref = (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_8__.sanitizeUrl)(e.target.dataset.ref) || 'about:blank';
}
const text = e.target.dataset.title || 'unknown';
this.props.onFormResponse(e.target.dataset.act, text, data);
}
handleContextClick(e) {
e.preventDefault();
e.stopPropagation();
const menuItems = [];
if (this.props.received == tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.MESSAGE_STATUS_FAILED) {
menuItems.push('menu_item_send_retry');
}
if (this.props.received > tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.MESSAGE_STATUS_FATAL) {
if (this.props.userIsWriter) {
menuItems.push('menu_item_reply');
if (!this.props.response) {
let immutable = false;
tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.entities(this.props.content, (_0, _1, tp) => {
immutable = ['AU', 'EX', 'FM', 'IM', 'TC', 'VC', 'VD'].includes(tp);
return immutable;
});
if (!immutable) {
tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.styles(this.props.content, tp => {
immutable = ['QQ'].includes(tp);
return immutable;
});
}
if (!immutable) {
menuItems.push('menu_item_edit');
}
}
}
if (this.props.userIsAdmin) {
menuItems.push(this.props.pinned ? 'menu_item_unpin' : 'menu_item_pin');
}
}
menuItems.push('menu_item_forward');
this.props.showContextMenu({
seq: this.props.seq,
replace: this.props.edited ? parseInt(this.props.edited.split(':')[1]) : 0,
content: this.props.content,
userFrom: this.props.userFrom,
userName: this.props.userName,
y: e.pageY,
x: e.pageX,
pickReply: this.props.pickReply,
editMessage: this.props.editMessage,
timestamp: this.props.timestamp
}, menuItems);
}
handleProgress(ratio) {
this.setState({
progress: ratio
});
}
handleCancelUpload() {
this.props.onCancelUpload(this.props.seq, this.props.uploader);
}
handleVoicePlayed() {
if (this.state.voicePlayed) {
return;
}
markVoicePlayed(this.props.tinode.getCurrentUserID(), this.props.topic, this.props.seq);
this.setState({
voicePlayed: true
});
}
handleQuoteClick(e) {
e.preventDefault();
e.stopPropagation();
const replyToSeq = this.props.replyToSeq;
if (replyToSeq) {
this.props.onQuoteClick(replyToSeq);
}
}
renderFailReason() {
if (this.props.response || this.props.received != tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.MESSAGE_STATUS_FAILED && this.props.received != tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.MESSAGE_STATUS_FATAL) {
return null;
}
if (this.props.relationship == 'blocked_by_peer' || this.props.relationship == 'blocked_by_me') {
return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)("div", {
className: "message-fail-reason",
children: "消息已发送,但被对方拒收了"
}, void 0, false);
}
if (this.props.relationship == 'none') {
return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)("div", {
className: "message-fail-reason",
children: ["你还不是他(她)朋友。", (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)("a", {
href: "#",
onClick: this.props.onSendFriendVerification,
children: "发送朋友验证"
}, void 0, false)]
}, void 0, true);
}
return null;
}
render() {
const sideClass = this.props.sequence + ' ' + (this.props.response ? 'left' : 'right');
const bubbleClass = this.props.sequence == 'single' || this.props.sequence == 'last' ? 'bubble tip' : 'bubble';
const avatar = this.props.userAvatar || true;
const isFailed = !this.props.response && (this.props.received == tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.MESSAGE_STATUS_FAILED || this.props.received == tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.MESSAGE_STATUS_FATAL);
const failReason = this.renderFailReason();
let isVoiceMessage = false;
if (this.props.response && this.props.mimeType == tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.getContentType() && tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.isValid(this.props.content)) {
tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.entities(this.props.content, (_0, _1, tp) => {
if (tp === 'AU') {
isVoiceMessage = true;
}
return isVoiceMessage;
});
}
const showVoiceUnreadDot = isVoiceMessage && !this.state.voicePlayed;
let textSizeClass = 'message-content';
const fullDisplay = this.props.isGroup && this.props.response && (this.props.sequence == 'single' || this.props.sequence == 'last');
let content = this.props.content;
if (this.props.head && this.props.head['x-im-type'] === 'system_notice' && content && typeof content == 'object' && typeof content.text == 'string') {
content = content.text;
}
let bundleCard = null;
if (this.props.head && this.props.head['x-im-type'] === 'forward_bundle' && content && typeof content == 'object' && (content.items || content.preview)) {
bundleCard = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)(_forward_bundle_jsx__WEBPACK_IMPORTED_MODULE_4__["default"], {
content: content,
tinode: this.props.tinode
}, void 0, false);
}
const attachments = [];
if (this.props.mimeType == tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.getContentType() && tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.isValid(content)) {
tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.attachments(content, (att, i) => {
if (tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.isFormResponseType(att.mime)) {
return;
}
attachments.push((0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)(_attachment_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], {
tinode: this.props.tinode,
downloadUrl: tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.getDownloadUrl(att),
filename: att.name,
uploading: tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.isProcessing(att),
mimetype: att.mime,
size: tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.getEntitySize(att),
progress: this.state.progress,
onCancelUpload: this.handleCancelUpload,
onError: this.props.onError
}, i, false));
}, this);
const tree = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.format(content, _lib_formatters_js__WEBPACK_IMPORTED_MODULE_7__.fullFormatter, this.formatterContext);
content = react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, tree);
} else if (typeof content == 'string') {
if (new RegExp('^\\p{RGI_Emoji}{1,5}$', 'v').test(content || '')) {
textSizeClass += ' emoji-' + (content || '').match(/(?:👨🏻‍❤️‍💋‍👨🏻|👨🏻‍❤️‍💋‍👨🏼|👨🏻‍❤️‍💋‍👨🏽|👨🏻‍❤️‍💋‍👨🏾|👨🏻‍❤️‍💋‍👨🏿|👨🏼‍❤️‍💋‍👨🏻|👨🏼‍❤️‍💋‍👨🏼|👨🏼‍❤️‍💋‍👨🏽|👨🏼‍❤️‍💋‍👨🏾|👨🏼‍❤️‍💋‍👨🏿|👨🏽‍❤️‍💋‍👨🏻|👨🏽‍❤️‍💋‍👨🏼|👨🏽‍❤️‍💋‍👨🏽|👨🏽‍❤️‍💋‍👨🏾|👨🏽‍❤️‍💋‍👨🏿|👨🏾‍❤️‍💋‍👨🏻|👨🏾‍❤️‍💋‍👨🏼|👨🏾‍❤️‍💋‍👨🏽|👨🏾‍❤️‍💋‍👨🏾|👨🏾‍❤️‍💋‍👨🏿|👨🏿‍❤️‍💋‍👨🏻|👨🏿‍❤️‍💋‍👨🏼|👨🏿‍❤️‍💋‍👨🏽|👨🏿‍❤️‍💋‍👨🏾|👨🏿‍❤️‍💋‍👨🏿|👩🏻‍❤️‍💋‍👨🏻|👩🏻‍❤️‍💋‍👨🏼|👩🏻‍❤️‍💋‍👨🏽|👩🏻‍❤️‍💋‍👨🏾|👩🏻‍❤️‍💋‍👨🏿|👩🏻‍❤️‍💋‍👩🏻|👩🏻‍❤️‍💋‍👩🏼|👩🏻‍❤️‍💋‍👩🏽|👩🏻‍❤️‍💋‍👩🏾|👩🏻‍❤️‍💋‍👩🏿|👩🏼‍❤️‍💋‍👨🏻|👩🏼‍❤️‍💋‍👨🏼|👩🏼‍❤️‍💋‍👨🏽|👩🏼‍❤️‍💋‍👨🏾|👩🏼‍❤️‍💋‍👨🏿|👩🏼‍❤️‍💋‍👩🏻|👩🏼‍❤️‍💋‍👩🏼|👩🏼‍❤️‍💋‍👩🏽|👩🏼‍❤️‍💋‍👩🏾|👩🏼‍❤️‍💋‍👩🏿|👩🏽‍❤️‍💋‍👨🏻|👩🏽‍❤️‍💋‍👨🏼|👩🏽‍❤️‍💋‍👨🏽|👩🏽‍❤️‍💋‍👨🏾|👩🏽‍❤️‍💋‍👨🏿|👩🏽‍❤️‍💋‍👩🏻|👩🏽‍❤️‍💋‍👩🏼|👩🏽‍❤️‍💋‍👩🏽|👩🏽‍❤️‍💋‍👩🏾|👩🏽‍❤️‍💋‍👩🏿|👩🏾‍❤️‍💋‍👨🏻|👩🏾‍❤️‍💋‍👨🏼|👩🏾‍❤️‍💋‍👨🏽|👩🏾‍❤️‍💋‍👨🏾|👩🏾‍❤️‍💋‍👨🏿|👩🏾‍❤️‍💋‍👩🏻|👩🏾‍❤️‍💋‍👩🏼|👩🏾‍❤️‍💋‍👩🏽|👩🏾‍❤️‍💋‍👩🏾|👩🏾‍❤️‍💋‍👩🏿|👩🏿‍❤️‍💋‍👨🏻|👩🏿‍❤️‍💋‍👨🏼|👩🏿‍❤️‍💋‍👨🏽|👩🏿‍❤️‍💋‍👨🏾|👩🏿‍❤️‍💋‍👨🏿|👩🏿‍❤️‍💋‍👩🏻|👩🏿‍❤️‍💋‍👩🏼|👩🏿‍❤️‍💋‍👩🏽|👩🏿‍❤️‍💋‍👩🏾|👩🏿‍❤️‍💋‍👩🏿|🧑🏻‍❤️‍💋‍🧑🏼|🧑🏻‍❤️‍💋‍🧑🏽|🧑🏻‍❤️‍💋‍🧑🏾|🧑🏻‍❤️‍💋‍🧑🏿|🧑🏼‍❤️‍💋‍🧑🏻|🧑🏼‍❤️‍💋‍🧑🏽|🧑🏼‍❤️‍💋‍🧑🏾|🧑🏼‍❤️‍💋‍🧑🏿|🧑🏽‍❤️‍💋‍🧑🏻|🧑🏽‍❤️‍💋‍🧑🏼|🧑🏽‍❤️‍💋‍🧑🏾|🧑🏽‍❤️‍💋‍🧑🏿|🧑🏾‍❤️‍💋‍🧑🏻|🧑🏾‍❤️‍💋‍🧑🏼|🧑🏾‍❤️‍💋‍🧑🏽|🧑🏾‍❤️‍💋‍🧑🏿|🧑🏿‍❤️‍💋‍🧑🏻|🧑🏿‍❤️‍💋‍🧑🏼|🧑🏿‍❤️‍💋‍🧑🏽|🧑🏿‍❤️‍💋‍🧑🏾|🏴󠁧󠁢󠁥󠁮󠁧󠁿|🏴󠁧󠁢󠁳󠁣󠁴󠁿|🏴󠁧󠁢󠁷󠁬󠁳󠁿|👨🏻‍❤️‍👨🏻|👨🏻‍❤️‍👨🏼|👨🏻‍❤️‍👨🏽|👨🏻‍❤️‍👨🏾|👨🏻‍❤️‍👨🏿|👨🏻‍🐰‍👨🏼|👨🏻‍🐰‍👨🏽|👨🏻‍🐰‍👨🏾|👨🏻‍🐰‍👨🏿|👨🏻‍🤝‍👨🏼|👨🏻‍🤝‍👨🏽|👨🏻‍🤝‍👨🏾|👨🏻‍🤝‍👨🏿|👨🏻‍🫯‍👨🏼|👨🏻‍🫯‍👨🏽|👨🏻‍🫯‍👨🏾|👨🏻‍🫯‍👨🏿|👨🏼‍❤️‍👨🏻|👨🏼‍❤️‍👨🏼|👨🏼‍❤️‍👨🏽|👨🏼‍❤️‍👨🏾|👨🏼‍❤️‍👨🏿|👨🏼‍🐰‍👨🏻|👨🏼‍🐰‍👨🏽|👨🏼‍🐰‍👨🏾|👨🏼‍🐰‍👨🏿|👨🏼‍🤝‍👨🏻|👨🏼‍🤝‍👨🏽|👨🏼‍🤝‍👨🏾|👨🏼‍🤝‍👨🏿|👨🏼‍🫯‍👨🏻|👨🏼‍🫯‍👨🏽|👨🏼‍🫯‍👨🏾|👨🏼‍🫯‍👨🏿|👨🏽‍❤️‍👨🏻|👨🏽‍❤️‍👨🏼|👨🏽‍❤️‍👨🏽|👨🏽‍❤️‍👨🏾|👨🏽‍❤️‍👨🏿|👨🏽‍🐰‍👨🏻|👨🏽‍🐰‍👨🏼|👨🏽‍🐰‍👨🏾|👨🏽‍🐰‍👨🏿|👨🏽‍🤝‍👨🏻|👨🏽‍🤝‍👨🏼|👨🏽‍🤝‍👨🏾|👨🏽‍🤝‍👨🏿|👨🏽‍🫯‍👨🏻|👨🏽‍🫯‍👨🏼|👨🏽‍🫯‍👨🏾|👨🏽‍🫯‍👨🏿|👨🏾‍❤️‍👨🏻|👨🏾‍❤️‍👨🏼|👨🏾‍❤️‍👨🏽|👨🏾‍❤️‍👨🏾|👨🏾‍❤️‍👨🏿|👨🏾‍🐰‍👨🏻|👨🏾‍🐰‍👨🏼|👨🏾‍🐰‍👨🏽|👨🏾‍🐰‍👨🏿|👨🏾‍🤝‍👨🏻|👨🏾‍🤝‍👨🏼|👨🏾‍🤝‍👨🏽|👨🏾‍🤝‍👨🏿|👨🏾‍🫯‍👨🏻|👨🏾‍🫯‍👨🏼|👨🏾‍🫯‍👨🏽|👨🏾‍🫯‍👨🏿|👨🏿‍❤️‍👨🏻|👨🏿‍❤️‍👨🏼|👨🏿‍❤️‍👨🏽|👨🏿‍❤️‍👨🏾|👨🏿‍❤️‍👨🏿|👨🏿‍🐰‍👨🏻|👨🏿‍🐰‍👨🏼|👨🏿‍🐰‍👨🏽|👨🏿‍🐰‍👨🏾|👨🏿‍🤝‍👨🏻|👨🏿‍🤝‍👨🏼|👨🏿‍🤝‍👨🏽|👨🏿‍🤝‍👨🏾|👨🏿‍🫯‍👨🏻|👨🏿‍🫯‍👨🏼|👨🏿‍🫯‍👨🏽|👨🏿‍🫯‍👨🏾|👩🏻‍❤️‍👨🏻|👩🏻‍❤️‍👨🏼|👩🏻‍❤️‍👨🏽|👩🏻‍❤️‍👨🏾|👩🏻‍❤️‍👨🏿|👩🏻‍❤️‍👩🏻|👩🏻‍❤️‍👩🏼|👩🏻‍❤️‍👩🏽|👩🏻‍❤️‍👩🏾|👩🏻‍❤️‍👩🏿|👩🏻‍🐰‍👩🏼|👩🏻‍🐰‍👩🏽|👩🏻‍🐰‍👩🏾|👩🏻‍🐰‍👩🏿|👩🏻‍🤝‍👨🏼|👩🏻‍🤝‍👨🏽|👩🏻‍🤝‍👨🏾|👩🏻‍🤝‍👨🏿|👩🏻‍🤝‍👩🏼|👩🏻‍🤝‍👩🏽|👩🏻‍🤝‍👩🏾|👩🏻‍🤝‍👩🏿|👩🏻‍🫯‍👩🏼|👩🏻‍🫯‍👩🏽|👩🏻‍🫯‍👩🏾|👩🏻‍🫯‍👩🏿|👩🏼‍❤️‍👨🏻|👩🏼‍❤️‍👨🏼|👩🏼‍❤️‍👨🏽|👩🏼‍❤️‍👨🏾|👩🏼‍❤️‍👨🏿|👩🏼‍❤️‍👩🏻|👩🏼‍❤️‍👩🏼|👩🏼‍❤️‍👩🏽|👩🏼‍❤️‍👩🏾|👩🏼‍❤️‍👩🏿|👩🏼‍🐰‍👩🏻|👩🏼‍🐰‍👩🏽|👩🏼‍🐰‍👩🏾|👩🏼‍🐰‍👩🏿|👩🏼‍🤝‍👨🏻|👩🏼‍🤝‍👨🏽|👩🏼‍🤝‍👨🏾|👩🏼‍🤝‍👨🏿|👩🏼‍🤝‍👩🏻|👩🏼‍🤝‍👩🏽|👩🏼‍🤝‍👩🏾|👩🏼‍🤝‍👩🏿|👩🏼‍🫯‍👩🏻|👩🏼‍🫯‍👩🏽|👩🏼‍🫯‍👩🏾|👩🏼‍🫯‍👩🏿|👩🏽‍❤️‍👨🏻|👩🏽‍❤️‍👨🏼|👩🏽‍❤️‍👨🏽|👩🏽‍❤️‍👨🏾|👩🏽‍❤️‍👨🏿|👩🏽‍❤️‍👩🏻|👩🏽‍❤️‍👩🏼|👩🏽‍❤️‍👩🏽|👩🏽‍❤️‍👩🏾|👩🏽‍❤️‍👩🏿|👩🏽‍🐰‍👩🏻|👩🏽‍🐰‍👩🏼|👩🏽‍🐰‍👩🏾|👩🏽‍🐰‍👩🏿|👩🏽‍🤝‍👨🏻|👩🏽‍🤝‍👨🏼|👩🏽‍🤝‍👨🏾|👩🏽‍🤝‍👨🏿|👩🏽‍🤝‍👩🏻|👩🏽‍🤝‍👩🏼|👩🏽‍🤝‍👩🏾|👩🏽‍🤝‍👩🏿|👩🏽‍🫯‍👩🏻|👩🏽‍🫯‍👩🏼|👩🏽‍🫯‍👩🏾|👩🏽‍🫯‍👩🏿|👩🏾‍❤️‍👨🏻|👩🏾‍❤️‍👨🏼|👩🏾‍❤️‍👨🏽|👩🏾‍❤️‍👨🏾|👩🏾‍❤️‍👨🏿|👩🏾‍❤️‍👩🏻|👩🏾‍❤️‍👩🏼|👩🏾‍❤️‍👩🏽|👩🏾‍❤️‍👩🏾|👩🏾‍❤️‍👩🏿|👩🏾‍🐰‍👩🏻|👩🏾‍🐰‍👩🏼|👩🏾‍🐰‍👩🏽|👩🏾‍🐰‍👩🏿|👩🏾‍🤝‍👨🏻|👩🏾‍🤝‍👨🏼|👩🏾‍🤝‍👨🏽|👩🏾‍🤝‍👨🏿|👩🏾‍🤝‍👩🏻|👩🏾‍🤝‍👩🏼|👩🏾‍🤝‍👩🏽|👩🏾‍🤝‍👩🏿|👩🏾‍🫯‍👩🏻|👩🏾‍🫯‍👩🏼|👩🏾‍🫯‍👩🏽|👩🏾‍🫯‍👩🏿|👩🏿‍❤️‍👨🏻|👩🏿‍❤️‍👨🏼|👩🏿‍❤️‍👨🏽|👩🏿‍❤️‍👨🏾|👩🏿‍❤️‍👨🏿|👩🏿‍❤️‍👩🏻|👩🏿‍❤️‍👩🏼|👩🏿‍❤️‍👩🏽|👩🏿‍❤️‍👩🏾|👩🏿‍❤️‍👩🏿|👩🏿‍🐰‍👩🏻|👩🏿‍🐰‍👩🏼|👩🏿‍🐰‍👩🏽|👩🏿‍🐰‍👩🏾|👩🏿‍🤝‍👨🏻|👩🏿‍🤝‍👨🏼|👩🏿‍🤝‍👨🏽|👩🏿‍🤝‍👨🏾|👩🏿‍🤝‍👩🏻|👩🏿‍🤝‍👩🏼|👩🏿‍🤝‍👩🏽|👩🏿‍🤝‍👩🏾|👩🏿‍🫯‍👩🏻|👩🏿‍🫯‍👩🏼|👩🏿‍🫯‍👩🏽|👩🏿‍🫯‍👩🏾|🧑🏻‍❤️‍🧑🏼|🧑🏻‍❤️‍🧑🏽|🧑🏻‍❤️‍🧑🏾|🧑🏻‍❤️‍🧑🏿|🧑🏻‍🐰‍🧑🏼|🧑🏻‍🐰‍🧑🏽|🧑🏻‍🐰‍🧑🏾|🧑🏻‍🐰‍🧑🏿|🧑🏻‍🤝‍🧑🏻|🧑🏻‍🤝‍🧑🏼|🧑🏻‍🤝‍🧑🏽|🧑🏻‍🤝‍🧑🏾|🧑🏻‍🤝‍🧑🏿|🧑🏻‍🫯‍🧑🏼|🧑🏻‍🫯‍🧑🏽|🧑🏻‍🫯‍🧑🏾|🧑🏻‍🫯‍🧑🏿|🧑🏼‍❤️‍🧑🏻|🧑🏼‍❤️‍🧑🏽|🧑🏼‍❤️‍🧑🏾|🧑🏼‍❤️‍🧑🏿|🧑🏼‍🐰‍🧑🏻|🧑🏼‍🐰‍🧑🏽|🧑🏼‍🐰‍🧑🏾|🧑🏼‍🐰‍🧑🏿|🧑🏼‍🤝‍🧑🏻|🧑🏼‍🤝‍🧑🏼|🧑🏼‍🤝‍🧑🏽|🧑🏼‍🤝‍🧑🏾|🧑🏼‍🤝‍🧑🏿|🧑🏼‍🫯‍🧑🏻|🧑🏼‍🫯‍🧑🏽|🧑🏼‍🫯‍🧑🏾|🧑🏼‍🫯‍🧑🏿|🧑🏽‍❤️‍🧑🏻|🧑🏽‍❤️‍🧑🏼|🧑🏽‍❤️‍🧑🏾|🧑🏽‍❤️‍🧑🏿|🧑🏽‍🐰‍🧑🏻|🧑🏽‍🐰‍🧑🏼|🧑🏽‍🐰‍🧑🏾|🧑🏽‍🐰‍🧑🏿|🧑🏽‍🤝‍🧑🏻|🧑🏽‍🤝‍🧑🏼|🧑🏽‍🤝‍🧑🏽|🧑🏽‍🤝‍🧑🏾|🧑🏽‍🤝‍🧑🏿|🧑🏽‍🫯‍🧑🏻|🧑🏽‍🫯‍🧑🏼|🧑🏽‍🫯‍🧑🏾|🧑🏽‍🫯‍🧑🏿|🧑🏾‍❤️‍🧑🏻|🧑🏾‍❤️‍🧑🏼|🧑🏾‍❤️‍🧑🏽|🧑🏾‍❤️‍🧑🏿|🧑🏾‍🐰‍🧑🏻|🧑🏾‍🐰‍🧑🏼|🧑🏾‍🐰‍🧑🏽|🧑🏾‍🐰‍🧑🏿|🧑🏾‍🤝‍🧑🏻|🧑🏾‍🤝‍🧑🏼|🧑🏾‍🤝‍🧑🏽|🧑🏾‍🤝‍🧑🏾|🧑🏾‍🤝‍🧑🏿|🧑🏾‍🫯‍🧑🏻|🧑🏾‍🫯‍🧑🏼|🧑🏾‍🫯‍🧑🏽|🧑🏾‍🫯‍🧑🏿|🧑🏿‍❤️‍🧑🏻|🧑🏿‍❤️‍🧑🏼|🧑🏿‍❤️‍🧑🏽|🧑🏿‍❤️‍🧑🏾|🧑🏿‍🐰‍🧑🏻|🧑🏿‍🐰‍🧑🏼|🧑🏿‍🐰‍🧑🏽|🧑🏿‍🐰‍🧑🏾|🧑🏿‍🤝‍🧑🏻|🧑🏿‍🤝‍🧑🏼|🧑🏿‍🤝‍🧑🏽|🧑🏿‍🤝‍🧑🏾|🧑🏿‍🤝‍🧑🏿|🧑🏿‍🫯‍🧑🏻|🧑🏿‍🫯‍🧑🏼|🧑🏿‍🫯‍🧑🏽|🧑🏿‍🫯‍🧑🏾|👨‍❤️‍💋‍👨|👨‍👨‍👦‍👦|👨‍👨‍👧‍👦|👨‍👨‍👧‍👧|👨‍👩‍👦‍👦|👨‍👩‍👧‍👦|👨‍👩‍👧‍👧|👩‍❤️‍💋‍👨|👩‍❤️‍💋‍👩|👩‍👩‍👦‍👦|👩‍👩‍👧‍👦|👩‍👩‍👧‍👧|🧑‍🧑‍🧒‍🧒|🏃🏻‍♀️‍➡️|🏃🏻‍♂️‍➡️|🏃🏼‍♀️‍➡️|🏃🏼‍♂️‍➡️|🏃🏽‍♀️‍➡️|🏃🏽‍♂️‍➡️|🏃🏾‍♀️‍➡️|🏃🏾‍♂️‍➡️|🏃🏿‍♀️‍➡️|🏃🏿‍♂️‍➡️|👨🏻‍🦯‍➡️|👨🏻‍🦼‍➡️|👨🏻‍🦽‍➡️|👨🏼‍🦯‍➡️|👨🏼‍🦼‍➡️|👨🏼‍🦽‍➡️|👨🏽‍🦯‍➡️|👨🏽‍🦼‍➡️|👨🏽‍🦽‍➡️|👨🏾‍🦯‍➡️|👨🏾‍🦼‍➡️|👨🏾‍🦽‍➡️|👨🏿‍🦯‍➡️|👨🏿‍🦼‍➡️|👨🏿‍🦽‍➡️|👩🏻‍🦯‍➡️|👩🏻‍🦼‍➡️|👩🏻‍🦽‍➡️|👩🏼‍🦯‍➡️|👩🏼‍🦼‍➡️|👩🏼‍🦽‍➡️|👩🏽‍🦯‍➡️|👩🏽‍🦼‍➡️|👩🏽‍🦽‍➡️|👩🏾‍🦯‍➡️|👩🏾‍🦼‍➡️|👩🏾‍🦽‍➡️|👩🏿‍🦯‍➡️|👩🏿‍🦼‍➡️|👩🏿‍🦽‍➡️|🚶🏻‍♀️‍➡️|🚶🏻‍♂️‍➡️|🚶🏼‍♀️‍➡️|🚶🏼‍♂️‍➡️|🚶🏽‍♀️‍➡️|🚶🏽‍♂️‍➡️|🚶🏾‍♀️‍➡️|🚶🏾‍♂️‍➡️|🚶🏿‍♀️‍➡️|🚶🏿‍♂️‍➡️|🧎🏻‍♀️‍➡️|🧎🏻‍♂️‍➡️|🧎🏼‍♀️‍➡️|🧎🏼‍♂️‍➡️|🧎🏽‍♀️‍➡️|🧎🏽‍♂️‍➡️|🧎🏾‍♀️‍➡️|🧎🏾‍♂️‍➡️|🧎🏿‍♀️‍➡️|🧎🏿‍♂️‍➡️|🧑🏻‍🦯‍➡️|🧑🏻‍🦼‍➡️|🧑🏻‍🦽‍➡️|🧑🏼‍🦯‍➡️|🧑🏼‍🦼‍➡️|🧑🏼‍🦽‍➡️|🧑🏽‍🦯‍➡️|🧑🏽‍🦼‍➡️|🧑🏽‍🦽‍➡️|🧑🏾‍🦯‍➡️|🧑🏾‍🦼‍➡️|🧑🏾‍🦽‍➡️|🧑🏿‍🦯‍➡️|🧑🏿‍🦼‍➡️|🧑🏿‍🦽‍➡️|🫱🏻‍🫲🏼|🫱🏻‍🫲🏽|🫱🏻‍🫲🏾|🫱🏻‍🫲🏿|🫱🏼‍🫲🏻|🫱🏼‍🫲🏽|🫱🏼‍🫲🏾|🫱🏼‍🫲🏿|🫱🏽‍🫲🏻|🫱🏽‍🫲🏼|🫱🏽‍🫲🏾|🫱🏽‍🫲🏿|🫱🏾‍🫲🏻|🫱🏾‍🫲🏼|🫱🏾‍🫲🏽|🫱🏾‍🫲🏿|🫱🏿‍🫲🏻|🫱🏿‍🫲🏼|🫱🏿‍🫲🏽|🫱🏿‍🫲🏾|🏃‍♀️‍➡️|🏃‍♂️‍➡️|👨‍❤️‍👨|👨‍👦‍👦|👨‍👧‍👦|👨‍👧‍👧|👨‍👨‍👦|👨‍👨‍👧|👨‍👩‍👦|👨‍👩‍👧|👨‍🦯‍➡️|👨‍🦼‍➡️|👨‍🦽‍➡️|👩‍❤️‍👨|👩‍❤️‍👩|👩‍👦‍👦|👩‍👧‍👦|👩‍👧‍👧|👩‍👩‍👦|👩‍👩‍👧|👩‍🦯‍➡️|👩‍🦼‍➡️|👩‍🦽‍➡️|🚶‍♀️‍➡️|🚶‍♂️‍➡️|🧎‍♀️‍➡️|🧎‍♂️‍➡️|🧑‍🤝‍🧑|🧑‍🦯‍➡️|🧑‍🦼‍➡️|🧑‍🦽‍➡️|🧑‍🧑‍🧒|🧑‍🧒‍🧒|🏃🏻‍♀️|🏃🏻‍♂️|🏃🏻‍➡️|🏃🏼‍♀️|🏃🏼‍♂️|🏃🏼‍➡️|🏃🏽‍♀️|🏃🏽‍♂️|🏃🏽‍➡️|🏃🏾‍♀️|🏃🏾‍♂️|🏃🏾‍➡️|🏃🏿‍♀️|🏃🏿‍♂️|🏃🏿‍➡️|🏄🏻‍♀️|🏄🏻‍♂️|🏄🏼‍♀️|🏄🏼‍♂️|🏄🏽‍♀️|🏄🏽‍♂️|🏄🏾‍♀️|🏄🏾‍♂️|🏄🏿‍♀️|🏄🏿‍♂️|🏊🏻‍♀️|🏊🏻‍♂️|🏊🏼‍♀️|🏊🏼‍♂️|🏊🏽‍♀️|🏊🏽‍♂️|🏊🏾‍♀️|🏊🏾‍♂️|🏊🏿‍♀️|🏊🏿‍♂️|🏋🏻‍♀️|🏋🏻‍♂️|🏋🏼‍♀️|🏋🏼‍♂️|🏋🏽‍♀️|🏋🏽‍♂️|🏋🏾‍♀️|🏋🏾‍♂️|🏋🏿‍♀️|🏋🏿‍♂️|🏌🏻‍♀️|🏌🏻‍♂️|🏌🏼‍♀️|🏌🏼‍♂️|🏌🏽‍♀️|🏌🏽‍♂️|🏌🏾‍♀️|🏌🏾‍♂️|🏌🏿‍♀️|🏌🏿‍♂️|👁️‍🗨️|👨🏻‍⚕️|👨🏻‍⚖️|👨🏻‍✈️|👨🏻‍🌾|👨🏻‍🍳|👨🏻‍🍼|👨🏻‍🎓|👨🏻‍🎤|👨🏻‍🎨|👨🏻‍🏫|👨🏻‍🏭|👨🏻‍💻|👨🏻‍💼|👨🏻‍🔧|👨🏻‍🔬|👨🏻‍🚀|👨🏻‍🚒|👨🏻‍🦯|👨🏻‍🦰|👨🏻‍🦱|👨🏻‍🦲|👨🏻‍🦳|👨🏻‍🦼|👨🏻‍🦽|👨🏼‍⚕️|👨🏼‍⚖️|👨🏼‍✈️|👨🏼‍🌾|👨🏼‍🍳|👨🏼‍🍼|👨🏼‍🎓|👨🏼‍🎤|👨🏼‍🎨|👨🏼‍🏫|👨🏼‍🏭|👨🏼‍💻|👨🏼‍💼|👨🏼‍🔧|👨🏼‍🔬|👨🏼‍🚀|👨🏼‍🚒|👨🏼‍🦯|👨🏼‍🦰|👨🏼‍🦱|👨🏼‍🦲|👨🏼‍🦳|👨🏼‍🦼|👨🏼‍🦽|👨🏽‍⚕️|👨🏽‍⚖️|👨🏽‍✈️|👨🏽‍🌾|👨🏽‍🍳|👨🏽‍🍼|👨🏽‍🎓|👨🏽‍🎤|👨🏽‍🎨|👨🏽‍🏫|👨🏽‍🏭|👨🏽‍💻|👨🏽‍💼|👨🏽‍🔧|👨🏽‍🔬|👨🏽‍🚀|👨🏽‍🚒|👨🏽‍🦯|👨🏽‍🦰|👨🏽‍🦱|👨🏽‍🦲|👨🏽‍🦳|👨🏽‍🦼|👨🏽‍🦽|👨🏾‍⚕️|👨🏾‍⚖️|👨🏾‍✈️|👨🏾‍🌾|👨🏾‍🍳|👨🏾‍🍼|👨🏾‍🎓|👨🏾‍🎤|👨🏾‍🎨|👨🏾‍🏫|👨🏾‍🏭|👨🏾‍💻|👨🏾‍💼|👨🏾‍🔧|👨🏾‍🔬|👨🏾‍🚀|👨🏾‍🚒|👨🏾‍🦯|👨🏾‍🦰|👨🏾‍🦱|👨🏾‍🦲|👨🏾‍🦳|👨🏾‍🦼|👨🏾‍🦽|👨🏿‍⚕️|👨🏿‍⚖️|👨🏿‍✈️|👨🏿‍🌾|👨🏿‍🍳|👨🏿‍🍼|👨🏿‍🎓|👨🏿‍🎤|👨🏿‍🎨|👨🏿‍🏫|👨🏿‍🏭|👨🏿‍💻|👨🏿‍💼|👨🏿‍🔧|👨🏿‍🔬|👨🏿‍🚀|👨🏿‍🚒|👨🏿‍🦯|👨🏿‍🦰|👨🏿‍🦱|👨🏿‍🦲|👨🏿‍🦳|👨🏿‍🦼|👨🏿‍🦽|👩🏻‍⚕️|👩🏻‍⚖️|👩🏻‍✈️|👩🏻‍🌾|👩🏻‍🍳|👩🏻‍🍼|👩🏻‍🎓|👩🏻‍🎤|👩🏻‍🎨|👩🏻‍🏫|👩🏻‍🏭|👩🏻‍💻|👩🏻‍💼|👩🏻‍🔧|👩🏻‍🔬|👩🏻‍🚀|👩🏻‍🚒|👩🏻‍🦯|👩🏻‍🦰|👩🏻‍🦱|👩🏻‍🦲|👩🏻‍🦳|👩🏻‍🦼|👩🏻‍🦽|👩🏼‍⚕️|👩🏼‍⚖️|👩🏼‍✈️|👩🏼‍🌾|👩🏼‍🍳|👩🏼‍🍼|👩🏼‍🎓|👩🏼‍🎤|👩🏼‍🎨|👩🏼‍🏫|👩🏼‍🏭|👩🏼‍💻|👩🏼‍💼|👩🏼‍🔧|👩🏼‍🔬|👩🏼‍🚀|👩🏼‍🚒|👩🏼‍🦯|👩🏼‍🦰|👩🏼‍🦱|👩🏼‍🦲|👩🏼‍🦳|👩🏼‍🦼|👩🏼‍🦽|👩🏽‍⚕️|👩🏽‍⚖️|👩🏽‍✈️|👩🏽‍🌾|👩🏽‍🍳|👩🏽‍🍼|👩🏽‍🎓|👩🏽‍🎤|👩🏽‍🎨|👩🏽‍🏫|👩🏽‍🏭|👩🏽‍💻|👩🏽‍💼|👩🏽‍🔧|👩🏽‍🔬|👩🏽‍🚀|👩🏽‍🚒|👩🏽‍🦯|👩🏽‍🦰|👩🏽‍🦱|👩🏽‍🦲|👩🏽‍🦳|👩🏽‍🦼|👩🏽‍🦽|👩🏾‍⚕️|👩🏾‍⚖️|👩🏾‍✈️|👩🏾‍🌾|👩🏾‍🍳|👩🏾‍🍼|👩🏾‍🎓|👩🏾‍🎤|👩🏾‍🎨|👩🏾‍🏫|👩🏾‍🏭|👩🏾‍💻|👩🏾‍💼|👩🏾‍🔧|👩🏾‍🔬|👩🏾‍🚀|👩🏾‍🚒|👩🏾‍🦯|👩🏾‍🦰|👩🏾‍🦱|👩🏾‍🦲|👩🏾‍🦳|👩🏾‍🦼|👩🏾‍🦽|👩🏿‍⚕️|👩🏿‍⚖️|👩🏿‍✈️|👩🏿‍🌾|👩🏿‍🍳|👩🏿‍🍼|👩🏿‍🎓|👩🏿‍🎤|👩🏿‍🎨|👩🏿‍🏫|👩🏿‍🏭|👩🏿‍💻|👩🏿‍💼|👩🏿‍🔧|👩🏿‍🔬|👩🏿‍🚀|👩🏿‍🚒|👩🏿‍🦯|👩🏿‍🦰|👩🏿‍🦱|👩🏿‍🦲|👩🏿‍🦳|👩🏿‍🦼|👩🏿‍🦽|👮🏻‍♀️|👮🏻‍♂️|👮🏼‍♀️|👮🏼‍♂️|👮🏽‍♀️|👮🏽‍♂️|👮🏾‍♀️|👮🏾‍♂️|👮🏿‍♀️|👮🏿‍♂️|👯🏻‍♀️|👯🏻‍♂️|👯🏼‍♀️|👯🏼‍♂️|👯🏽‍♀️|👯🏽‍♂️|👯🏾‍♀️|👯🏾‍♂️|👯🏿‍♀️|👯🏿‍♂️|👰🏻‍♀️|👰🏻‍♂️|👰🏼‍♀️|👰🏼‍♂️|👰🏽‍♀️|👰🏽‍♂️|👰🏾‍♀️|👰🏾‍♂️|👰🏿‍♀️|👰🏿‍♂️|👱🏻‍♀️|👱🏻‍♂️|👱🏼‍♀️|👱🏼‍♂️|👱🏽‍♀️|👱🏽‍♂️|👱🏾‍♀️|👱🏾‍♂️|👱🏿‍♀️|👱🏿‍♂️|👳🏻‍♀️|👳🏻‍♂️|👳🏼‍♀️|👳🏼‍♂️|👳🏽‍♀️|👳🏽‍♂️|👳🏾‍♀️|👳🏾‍♂️|👳🏿‍♀️|👳🏿‍♂️|👷🏻‍♀️|👷🏻‍♂️|👷🏼‍♀️|👷🏼‍♂️|👷🏽‍♀️|👷🏽‍♂️|👷🏾‍♀️|👷🏾‍♂️|👷🏿‍♀️|👷🏿‍♂️|💁🏻‍♀️|💁🏻‍♂️|💁🏼‍♀️|💁🏼‍♂️|💁🏽‍♀️|💁🏽‍♂️|💁🏾‍♀️|💁🏾‍♂️|💁🏿‍♀️|💁🏿‍♂️|💂🏻‍♀️|💂🏻‍♂️|💂🏼‍♀️|💂🏼‍♂️|💂🏽‍♀️|💂🏽‍♂️|💂🏾‍♀️|💂🏾‍♂️|💂🏿‍♀️|💂🏿‍♂️|💆🏻‍♀️|💆🏻‍♂️|💆🏼‍♀️|💆🏼‍♂️|💆🏽‍♀️|💆🏽‍♂️|💆🏾‍♀️|💆🏾‍♂️|💆🏿‍♀️|💆🏿‍♂️|💇🏻‍♀️|💇🏻‍♂️|💇🏼‍♀️|💇🏼‍♂️|💇🏽‍♀️|💇🏽‍♂️|💇🏾‍♀️|💇🏾‍♂️|💇🏿‍♀️|💇🏿‍♂️|🕵🏻‍♀️|🕵🏻‍♂️|🕵🏼‍♀️|🕵🏼‍♂️|🕵🏽‍♀️|🕵🏽‍♂️|🕵🏾‍♀️|🕵🏾‍♂️|🕵🏿‍♀️|🕵🏿‍♂️|🙅🏻‍♀️|🙅🏻‍♂️|🙅🏼‍♀️|🙅🏼‍♂️|🙅🏽‍♀️|🙅🏽‍♂️|🙅🏾‍♀️|🙅🏾‍♂️|🙅🏿‍♀️|🙅🏿‍♂️|🙆🏻‍♀️|🙆🏻‍♂️|🙆🏼‍♀️|🙆🏼‍♂️|🙆🏽‍♀️|🙆🏽‍♂️|🙆🏾‍♀️|🙆🏾‍♂️|🙆🏿‍♀️|🙆🏿‍♂️|🙇🏻‍♀️|🙇🏻‍♂️|🙇🏼‍♀️|🙇🏼‍♂️|🙇🏽‍♀️|🙇🏽‍♂️|🙇🏾‍♀️|🙇🏾‍♂️|🙇🏿‍♀️|🙇🏿‍♂️|🙋🏻‍♀️|🙋🏻‍♂️|🙋🏼‍♀️|🙋🏼‍♂️|🙋🏽‍♀️|🙋🏽‍♂️|🙋🏾‍♀️|🙋🏾‍♂️|🙋🏿‍♀️|🙋🏿‍♂️|🙍🏻‍♀️|🙍🏻‍♂️|🙍🏼‍♀️|🙍🏼‍♂️|🙍🏽‍♀️|🙍🏽‍♂️|🙍🏾‍♀️|🙍🏾‍♂️|🙍🏿‍♀️|🙍🏿‍♂️|🙎🏻‍♀️|🙎🏻‍♂️|🙎🏼‍♀️|🙎🏼‍♂️|🙎🏽‍♀️|🙎🏽‍♂️|🙎🏾‍♀️|🙎🏾‍♂️|🙎🏿‍♀️|🙎🏿‍♂️|🚣🏻‍♀️|🚣🏻‍♂️|🚣🏼‍♀️|🚣🏼‍♂️|🚣🏽‍♀️|🚣🏽‍♂️|🚣🏾‍♀️|🚣🏾‍♂️|🚣🏿‍♀️|🚣🏿‍♂️|🚴🏻‍♀️|🚴🏻‍♂️|🚴🏼‍♀️|🚴🏼‍♂️|🚴🏽‍♀️|🚴🏽‍♂️|🚴🏾‍♀️|🚴🏾‍♂️|🚴🏿‍♀️|🚴🏿‍♂️|🚵🏻‍♀️|🚵🏻‍♂️|🚵🏼‍♀️|🚵🏼‍♂️|🚵🏽‍♀️|🚵🏽‍♂️|🚵🏾‍♀️|🚵🏾‍♂️|🚵🏿‍♀️|🚵🏿‍♂️|🚶🏻‍♀️|🚶🏻‍♂️|🚶🏻‍➡️|🚶🏼‍♀️|🚶🏼‍♂️|🚶🏼‍➡️|🚶🏽‍♀️|🚶🏽‍♂️|🚶🏽‍➡️|🚶🏾‍♀️|🚶🏾‍♂️|🚶🏾‍➡️|🚶🏿‍♀️|🚶🏿‍♂️|🚶🏿‍➡️|🤦🏻‍♀️|🤦🏻‍♂️|🤦🏼‍♀️|🤦🏼‍♂️|🤦🏽‍♀️|🤦🏽‍♂️|🤦🏾‍♀️|🤦🏾‍♂️|🤦🏿‍♀️|🤦🏿‍♂️|🤵🏻‍♀️|🤵🏻‍♂️|🤵🏼‍♀️|🤵🏼‍♂️|🤵🏽‍♀️|🤵🏽‍♂️|🤵🏾‍♀️|🤵🏾‍♂️|🤵🏿‍♀️|🤵🏿‍♂️|🤷🏻‍♀️|🤷🏻‍♂️|🤷🏼‍♀️|🤷🏼‍♂️|🤷🏽‍♀️|🤷🏽‍♂️|🤷🏾‍♀️|🤷🏾‍♂️|🤷🏿‍♀️|🤷🏿‍♂️|🤸🏻‍♀️|🤸🏻‍♂️|🤸🏼‍♀️|🤸🏼‍♂️|🤸🏽‍♀️|🤸🏽‍♂️|🤸🏾‍♀️|🤸🏾‍♂️|🤸🏿‍♀️|🤸🏿‍♂️|🤹🏻‍♀️|🤹🏻‍♂️|🤹🏼‍♀️|🤹🏼‍♂️|🤹🏽‍♀️|🤹🏽‍♂️|🤹🏾‍♀️|🤹🏾‍♂️|🤹🏿‍♀️|🤹🏿‍♂️|🤼🏻‍♀️|🤼🏻‍♂️|🤼🏼‍♀️|🤼🏼‍♂️|🤼🏽‍♀️|🤼🏽‍♂️|🤼🏾‍♀️|🤼🏾‍♂️|🤼🏿‍♀️|🤼🏿‍♂️|🤽🏻‍♀️|🤽🏻‍♂️|🤽🏼‍♀️|🤽🏼‍♂️|🤽🏽‍♀️|🤽🏽‍♂️|🤽🏾‍♀️|🤽🏾‍♂️|🤽🏿‍♀️|🤽🏿‍♂️|🤾🏻‍♀️|🤾🏻‍♂️|🤾🏼‍♀️|🤾🏼‍♂️|🤾🏽‍♀️|🤾🏽‍♂️|🤾🏾‍♀️|🤾🏾‍♂️|🤾🏿‍♀️|🤾🏿‍♂️|🦸🏻‍♀️|🦸🏻‍♂️|🦸🏼‍♀️|🦸🏼‍♂️|🦸🏽‍♀️|🦸🏽‍♂️|🦸🏾‍♀️|🦸🏾‍♂️|🦸🏿‍♀️|🦸🏿‍♂️|🦹🏻‍♀️|🦹🏻‍♂️|🦹🏼‍♀️|🦹🏼‍♂️|🦹🏽‍♀️|🦹🏽‍♂️|🦹🏾‍♀️|🦹🏾‍♂️|🦹🏿‍♀️|🦹🏿‍♂️|🧍🏻‍♀️|🧍🏻‍♂️|🧍🏼‍♀️|🧍🏼‍♂️|🧍🏽‍♀️|🧍🏽‍♂️|🧍🏾‍♀️|🧍🏾‍♂️|🧍🏿‍♀️|🧍🏿‍♂️|🧎🏻‍♀️|🧎🏻‍♂️|🧎🏻‍➡️|🧎🏼‍♀️|🧎🏼‍♂️|🧎🏼‍➡️|🧎🏽‍♀️|🧎🏽‍♂️|🧎🏽‍➡️|🧎🏾‍♀️|🧎🏾‍♂️|🧎🏾‍➡️|🧎🏿‍♀️|🧎🏿‍♂️|🧎🏿‍➡️|🧏🏻‍♀️|🧏🏻‍♂️|🧏🏼‍♀️|🧏🏼‍♂️|🧏🏽‍♀️|🧏🏽‍♂️|🧏🏾‍♀️|🧏🏾‍♂️|🧏🏿‍♀️|🧏🏿‍♂️|🧑🏻‍⚕️|🧑🏻‍⚖️|🧑🏻‍✈️|🧑🏻‍🌾|🧑🏻‍🍳|🧑🏻‍🍼|🧑🏻‍🎄|🧑🏻‍🎓|🧑🏻‍🎤|🧑🏻‍🎨|🧑🏻‍🏫|🧑🏻‍🏭|🧑🏻‍💻|🧑🏻‍💼|🧑🏻‍🔧|🧑🏻‍🔬|🧑🏻‍🚀|🧑🏻‍🚒|🧑🏻‍🦯|🧑🏻‍🦰|🧑🏻‍🦱|🧑🏻‍🦲|🧑🏻‍🦳|🧑🏻‍🦼|🧑🏻‍🦽|🧑🏻‍🩰|🧑🏼‍⚕️|🧑🏼‍⚖️|🧑🏼‍✈️|🧑🏼‍🌾|🧑🏼‍🍳|🧑🏼‍🍼|🧑🏼‍🎄|🧑🏼‍🎓|🧑🏼‍🎤|🧑🏼‍🎨|🧑🏼‍🏫|🧑🏼‍🏭|🧑🏼‍💻|🧑🏼‍💼|🧑🏼‍🔧|🧑🏼‍🔬|🧑🏼‍🚀|🧑🏼‍🚒|🧑🏼‍🦯|🧑🏼‍🦰|🧑🏼‍🦱|🧑🏼‍🦲|🧑🏼‍🦳|🧑🏼‍🦼|🧑🏼‍🦽|🧑🏼‍🩰|🧑🏽‍⚕️|🧑🏽‍⚖️|🧑🏽‍✈️|🧑🏽‍🌾|🧑🏽‍🍳|🧑🏽‍🍼|🧑🏽‍🎄|🧑🏽‍🎓|🧑🏽‍🎤|🧑🏽‍🎨|🧑🏽‍🏫|🧑🏽‍🏭|🧑🏽‍💻|🧑🏽‍💼|🧑🏽‍🔧|🧑🏽‍🔬|🧑🏽‍🚀|🧑🏽‍🚒|🧑🏽‍🦯|🧑🏽‍🦰|🧑🏽‍🦱|🧑🏽‍🦲|🧑🏽‍🦳|🧑🏽‍🦼|🧑🏽‍🦽|🧑🏽‍🩰|🧑🏾‍⚕️|🧑🏾‍⚖️|🧑🏾‍✈️|🧑🏾‍🌾|🧑🏾‍🍳|🧑🏾‍🍼|🧑🏾‍🎄|🧑🏾‍🎓|🧑🏾‍🎤|🧑🏾‍🎨|🧑🏾‍🏫|🧑🏾‍🏭|🧑🏾‍💻|🧑🏾‍💼|🧑🏾‍🔧|🧑🏾‍🔬|🧑🏾‍🚀|🧑🏾‍🚒|🧑🏾‍🦯|🧑🏾‍🦰|🧑🏾‍🦱|🧑🏾‍🦲|🧑🏾‍🦳|🧑🏾‍🦼|🧑🏾‍🦽|🧑🏾‍🩰|🧑🏿‍⚕️|🧑🏿‍⚖️|🧑🏿‍✈️|🧑🏿‍🌾|🧑🏿‍🍳|🧑🏿‍🍼|🧑🏿‍🎄|🧑🏿‍🎓|🧑🏿‍🎤|🧑🏿‍🎨|🧑🏿‍🏫|🧑🏿‍🏭|🧑🏿‍💻|🧑🏿‍💼|🧑🏿‍🔧|🧑🏿‍🔬|🧑🏿‍🚀|🧑🏿‍🚒|🧑🏿‍🦯|🧑🏿‍🦰|🧑🏿‍🦱|🧑🏿‍🦲|🧑🏿‍🦳|🧑🏿‍🦼|🧑🏿‍🦽|🧑🏿‍🩰|🧔🏻‍♀️|🧔🏻‍♂️|🧔🏼‍♀️|🧔🏼‍♂️|🧔🏽‍♀️|🧔🏽‍♂️|🧔🏾‍♀️|🧔🏾‍♂️|🧔🏿‍♀️|🧔🏿‍♂️|🧖🏻‍♀️|🧖🏻‍♂️|🧖🏼‍♀️|🧖🏼‍♂️|🧖🏽‍♀️|🧖🏽‍♂️|🧖🏾‍♀️|🧖🏾‍♂️|🧖🏿‍♀️|🧖🏿‍♂️|🧗🏻‍♀️|🧗🏻‍♂️|🧗🏼‍♀️|🧗🏼‍♂️|🧗🏽‍♀️|🧗🏽‍♂️|🧗🏾‍♀️|🧗🏾‍♂️|🧗🏿‍♀️|🧗🏿‍♂️|🧘🏻‍♀️|🧘🏻‍♂️|🧘🏼‍♀️|🧘🏼‍♂️|🧘🏽‍♀️|🧘🏽‍♂️|🧘🏾‍♀️|🧘🏾‍♂️|🧘🏿‍♀️|🧘🏿‍♂️|🧙🏻‍♀️|🧙🏻‍♂️|🧙🏼‍♀️|🧙🏼‍♂️|🧙🏽‍♀️|🧙🏽‍♂️|🧙🏾‍♀️|🧙🏾‍♂️|🧙🏿‍♀️|🧙🏿‍♂️|🧚🏻‍♀️|🧚🏻‍♂️|🧚🏼‍♀️|🧚🏼‍♂️|🧚🏽‍♀️|🧚🏽‍♂️|🧚🏾‍♀️|🧚🏾‍♂️|🧚🏿‍♀️|🧚🏿‍♂️|🧛🏻‍♀️|🧛🏻‍♂️|🧛🏼‍♀️|🧛🏼‍♂️|🧛🏽‍♀️|🧛🏽‍♂️|🧛🏾‍♀️|🧛🏾‍♂️|🧛🏿‍♀️|🧛🏿‍♂️|🧜🏻‍♀️|🧜🏻‍♂️|🧜🏼‍♀️|🧜🏼‍♂️|🧜🏽‍♀️|🧜🏽‍♂️|🧜🏾‍♀️|🧜🏾‍♂️|🧜🏿‍♀️|🧜🏿‍♂️|🧝🏻‍♀️|🧝🏻‍♂️|🧝🏼‍♀️|🧝🏼‍♂️|🧝🏽‍♀️|🧝🏽‍♂️|🧝🏾‍♀️|🧝🏾‍♂️|🧝🏿‍♀️|🧝🏿‍♂️|⛹🏻‍♀️|⛹🏻‍♂️|⛹🏼‍♀️|⛹🏼‍♂️|⛹🏽‍♀️|⛹🏽‍♂️|⛹🏾‍♀️|⛹🏾‍♂️|⛹🏿‍♀️|⛹🏿‍♂️|🏋️‍♀️|🏋️‍♂️|🏌️‍♀️|🏌️‍♂️|🏳️‍⚧️|🏳️‍🌈|🕵️‍♀️|🕵️‍♂️|😶‍🌫️|⛓️‍💥|⛹️‍♀️|⛹️‍♂️|❤️‍🔥|❤️‍🩹|🍄‍🟫|🍋‍🟩|🏃‍♀️|🏃‍♂️|🏃‍➡️|🏄‍♀️|🏄‍♂️|🏊‍♀️|🏊‍♂️|🏴‍☠️|🐕‍🦺|🐦‍🔥|🐻‍❄️|👨‍⚕️|👨‍⚖️|👨‍✈️|👨‍🌾|👨‍🍳|👨‍🍼|👨‍🎓|👨‍🎤|👨‍🎨|👨‍🏫|👨‍🏭|👨‍👦|👨‍👧|👨‍💻|👨‍💼|👨‍🔧|👨‍🔬|👨‍🚀|👨‍🚒|👨‍🦯|👨‍🦰|👨‍🦱|👨‍🦲|👨‍🦳|👨‍🦼|👨‍🦽|👩‍⚕️|👩‍⚖️|👩‍✈️|👩‍🌾|👩‍🍳|👩‍🍼|👩‍🎓|👩‍🎤|👩‍🎨|👩‍🏫|👩‍🏭|👩‍👦|👩‍👧|👩‍💻|👩‍💼|👩‍🔧|👩‍🔬|👩‍🚀|👩‍🚒|👩‍🦯|👩‍🦰|👩‍🦱|👩‍🦲|👩‍🦳|👩‍🦼|👩‍🦽|👮‍♀️|👮‍♂️|👯‍♀️|👯‍♂️|👰‍♀️|👰‍♂️|👱‍♀️|👱‍♂️|👳‍♀️|👳‍♂️|👷‍♀️|👷‍♂️|💁‍♀️|💁‍♂️|💂‍♀️|💂‍♂️|💆‍♀️|💆‍♂️|💇‍♀️|💇‍♂️|😮‍💨|😵‍💫|🙂‍↔️|🙂‍↕️|🙅‍♀️|🙅‍♂️|🙆‍♀️|🙆‍♂️|🙇‍♀️|🙇‍♂️|🙋‍♀️|🙋‍♂️|🙍‍♀️|🙍‍♂️|🙎‍♀️|🙎‍♂️|🚣‍♀️|🚣‍♂️|🚴‍♀️|🚴‍♂️|🚵‍♀️|🚵‍♂️|🚶‍♀️|🚶‍♂️|🚶‍➡️|🤦‍♀️|🤦‍♂️|🤵‍♀️|🤵‍♂️|🤷‍♀️|🤷‍♂️|🤸‍♀️|🤸‍♂️|🤹‍♀️|🤹‍♂️|🤼‍♀️|🤼‍♂️|🤽‍♀️|🤽‍♂️|🤾‍♀️|🤾‍♂️|🦸‍♀️|🦸‍♂️|🦹‍♀️|🦹‍♂️|🧍‍♀️|🧍‍♂️|🧎‍♀️|🧎‍♂️|🧎‍➡️|🧏‍♀️|🧏‍♂️|🧑‍⚕️|🧑‍⚖️|🧑‍✈️|🧑‍🌾|🧑‍🍳|🧑‍🍼|🧑‍🎄|🧑‍🎓|🧑‍🎤|🧑‍🎨|🧑‍🏫|🧑‍🏭|🧑‍💻|🧑‍💼|🧑‍🔧|🧑‍🔬|🧑‍🚀|🧑‍🚒|🧑‍🦯|🧑‍🦰|🧑‍🦱|🧑‍🦲|🧑‍🦳|🧑‍🦼|🧑‍🦽|🧑‍🧒|🧑‍🩰|🧔‍♀️|🧔‍♂️|🧖‍♀️|🧖‍♂️|🧗‍♀️|🧗‍♂️|🧘‍♀️|🧘‍♂️|🧙‍♀️|🧙‍♂️|🧚‍♀️|🧚‍♂️|🧛‍♀️|🧛‍♂️|🧜‍♀️|🧜‍♂️|🧝‍♀️|🧝‍♂️|🧞‍♀️|🧞‍♂️|🧟‍♀️|🧟‍♂️|\*️⃣|🇦🇨|🇦🇩|🇦🇪|🇦🇫|🇦🇬|🇦🇮|🇦🇱|🇦🇲|🇦🇴|🇦🇶|🇦🇷|🇦🇸|🇦🇹|🇦🇺|🇦🇼|🇦🇽|🇦🇿|🇧🇦|🇧🇧|🇧🇩|🇧🇪|🇧🇫|🇧🇬|🇧🇭|🇧🇮|🇧🇯|🇧🇱|🇧🇲|🇧🇳|🇧🇴|🇧🇶|🇧🇷|🇧🇸|🇧🇹|🇧🇻|🇧🇼|🇧🇾|🇧🇿|🇨🇦|🇨🇨|🇨🇩|🇨🇫|🇨🇬|🇨🇭|🇨🇮|🇨🇰|🇨🇱|🇨🇲|🇨🇳|🇨🇴|🇨🇵|🇨🇶|🇨🇷|🇨🇺|🇨🇻|🇨🇼|🇨🇽|🇨🇾|🇨🇿|🇩🇪|🇩🇬|🇩🇯|🇩🇰|🇩🇲|🇩🇴|🇩🇿|🇪🇦|🇪🇨|🇪🇪|🇪🇬|🇪🇭|🇪🇷|🇪🇸|🇪🇹|🇪🇺|🇫🇮|🇫🇯|🇫🇰|🇫🇲|🇫🇴|🇫🇷|🇬🇦|🇬🇧|🇬🇩|🇬🇪|🇬🇫|🇬🇬|🇬🇭|🇬🇮|🇬🇱|🇬🇲|🇬🇳|🇬🇵|🇬🇶|🇬🇷|🇬🇸|🇬🇹|🇬🇺|🇬🇼|🇬🇾|🇭🇰|🇭🇲|🇭🇳|🇭🇷|🇭🇹|🇭🇺|🇮🇨|🇮🇩|🇮🇪|🇮🇱|🇮🇲|🇮🇳|🇮🇴|🇮🇶|🇮🇷|🇮🇸|🇮🇹|🇯🇪|🇯🇲|🇯🇴|🇯🇵|🇰🇪|🇰🇬|🇰🇭|🇰🇮|🇰🇲|🇰🇳|🇰🇵|🇰🇷|🇰🇼|🇰🇾|🇰🇿|🇱🇦|🇱🇧|🇱🇨|🇱🇮|🇱🇰|🇱🇷|🇱🇸|🇱🇹|🇱🇺|🇱🇻|🇱🇾|🇲🇦|🇲🇨|🇲🇩|🇲🇪|🇲🇫|🇲🇬|🇲🇭|🇲🇰|🇲🇱|🇲🇲|🇲🇳|🇲🇴|🇲🇵|🇲🇶|🇲🇷|🇲🇸|🇲🇹|🇲🇺|🇲🇻|🇲🇼|🇲🇽|🇲🇾|🇲🇿|🇳🇦|🇳🇨|🇳🇪|🇳🇫|🇳🇬|🇳🇮|🇳🇱|🇳🇴|🇳🇵|🇳🇷|🇳🇺|🇳🇿|🇴🇲|🇵🇦|🇵🇪|🇵🇫|🇵🇬|🇵🇭|🇵🇰|🇵🇱|🇵🇲|🇵🇳|🇵🇷|🇵🇸|🇵🇹|🇵🇼|🇵🇾|🇶🇦|🇷🇪|🇷🇴|🇷🇸|🇷🇺|🇷🇼|🇸🇦|🇸🇧|🇸🇨|🇸🇩|🇸🇪|🇸🇬|🇸🇭|🇸🇮|🇸🇯|🇸🇰|🇸🇱|🇸🇲|🇸🇳|🇸🇴|🇸🇷|🇸🇸|🇸🇹|🇸🇻|🇸🇽|🇸🇾|🇸🇿|🇹🇦|🇹🇨|🇹🇩|🇹🇫|🇹🇬|🇹🇭|🇹🇯|🇹🇰|🇹🇱|🇹🇲|🇹🇳|🇹🇴|🇹🇷|🇹🇹|🇹🇻|🇹🇼|🇹🇿|🇺🇦|🇺🇬|🇺🇲|🇺🇳|🇺🇸|🇺🇾|🇺🇿|🇻🇦|🇻🇨|🇻🇪|🇻🇬|🇻🇮|🇻🇳|🇻🇺|🇼🇫|🇼🇸|🇽🇰|🇾🇪|🇾🇹|🇿🇦|🇿🇲|🇿🇼|🎅🏻|🎅🏼|🎅🏽|🎅🏾|🎅🏿|🏂🏻|🏂🏼|🏂🏽|🏂🏾|🏂🏿|🏃🏻|🏃🏼|🏃🏽|🏃🏾|🏃🏿|🏄🏻|🏄🏼|🏄🏽|🏄🏾|🏄🏿|🏇🏻|🏇🏼|🏇🏽|🏇🏾|🏇🏿|🏊🏻|🏊🏼|🏊🏽|🏊🏾|🏊🏿|🏋🏻|🏋🏼|🏋🏽|🏋🏾|🏋🏿|🏌🏻|🏌🏼|🏌🏽|🏌🏾|🏌🏿|🐈‍⬛|🐦‍⬛|👂🏻|👂🏼|👂🏽|👂🏾|👂🏿|👃🏻|👃🏼|👃🏽|👃🏾|👃🏿|👆🏻|👆🏼|👆🏽|👆🏾|👆🏿|👇🏻|👇🏼|👇🏽|👇🏾|👇🏿|👈🏻|👈🏼|👈🏽|👈🏾|👈🏿|👉🏻|👉🏼|👉🏽|👉🏾|👉🏿|👊🏻|👊🏼|👊🏽|👊🏾|👊🏿|👋🏻|👋🏼|👋🏽|👋🏾|👋🏿|👌🏻|👌🏼|👌🏽|👌🏾|👌🏿|👍🏻|👍🏼|👍🏽|👍🏾|👍🏿|👎🏻|👎🏼|👎🏽|👎🏾|👎🏿|👏🏻|👏🏼|👏🏽|👏🏾|👏🏿|👐🏻|👐🏼|👐🏽|👐🏾|👐🏿|👦🏻|👦🏼|👦🏽|👦🏾|👦🏿|👧🏻|👧🏼|👧🏽|👧🏾|👧🏿|👨🏻|👨🏼|👨🏽|👨🏾|👨🏿|👩🏻|👩🏼|👩🏽|👩🏾|👩🏿|👫🏻|👫🏼|👫🏽|👫🏾|👫🏿|👬🏻|👬🏼|👬🏽|👬🏾|👬🏿|👭🏻|👭🏼|👭🏽|👭🏾|👭🏿|👮🏻|👮🏼|👮🏽|👮🏾|👮🏿|👯🏻|👯🏼|👯🏽|👯🏾|👯🏿|👰🏻|👰🏼|👰🏽|👰🏾|👰🏿|👱🏻|👱🏼|👱🏽|👱🏾|👱🏿|👲🏻|👲🏼|👲🏽|👲🏾|👲🏿|👳🏻|👳🏼|👳🏽|👳🏾|👳🏿|👴🏻|👴🏼|👴🏽|👴🏾|👴🏿|👵🏻|👵🏼|👵🏽|👵🏾|👵🏿|👶🏻|👶🏼|👶🏽|👶🏾|👶🏿|👷🏻|👷🏼|👷🏽|👷🏾|👷🏿|👸🏻|👸🏼|👸🏽|👸🏾|👸🏿|👼🏻|👼🏼|👼🏽|👼🏾|👼🏿|💁🏻|💁🏼|💁🏽|💁🏾|💁🏿|💂🏻|💂🏼|💂🏽|💂🏾|💂🏿|💃🏻|💃🏼|💃🏽|💃🏾|💃🏿|💅🏻|💅🏼|💅🏽|💅🏾|💅🏿|💆🏻|💆🏼|💆🏽|💆🏾|💆🏿|💇🏻|💇🏼|💇🏽|💇🏾|💇🏿|💏🏻|💏🏼|💏🏽|💏🏾|💏🏿|💑🏻|💑🏼|💑🏽|💑🏾|💑🏿|💪🏻|💪🏼|💪🏽|💪🏾|💪🏿|🕴🏻|🕴🏼|🕴🏽|🕴🏾|🕴🏿|🕵🏻|🕵🏼|🕵🏽|🕵🏾|🕵🏿|🕺🏻|🕺🏼|🕺🏽|🕺🏾|🕺🏿|🖐🏻|🖐🏼|🖐🏽|🖐🏾|🖐🏿|🖕🏻|🖕🏼|🖕🏽|🖕🏾|🖕🏿|🖖🏻|🖖🏼|🖖🏽|🖖🏾|🖖🏿|🙅🏻|🙅🏼|🙅🏽|🙅🏾|🙅🏿|🙆🏻|🙆🏼|🙆🏽|🙆🏾|🙆🏿|🙇🏻|🙇🏼|🙇🏽|🙇🏾|🙇🏿|🙋🏻|🙋🏼|🙋🏽|🙋🏾|🙋🏿|🙌🏻|🙌🏼|🙌🏽|🙌🏾|🙌🏿|🙍🏻|🙍🏼|🙍🏽|🙍🏾|🙍🏿|🙎🏻|🙎🏼|🙎🏽|🙎🏾|🙎🏿|🙏🏻|🙏🏼|🙏🏽|🙏🏾|🙏🏿|🚣🏻|🚣🏼|🚣🏽|🚣🏾|🚣🏿|🚴🏻|🚴🏼|🚴🏽|🚴🏾|🚴🏿|🚵🏻|🚵🏼|🚵🏽|🚵🏾|🚵🏿|🚶🏻|🚶🏼|🚶🏽|🚶🏾|🚶🏿|🛀🏻|🛀🏼|🛀🏽|🛀🏾|🛀🏿|🛌🏻|🛌🏼|🛌🏽|🛌🏾|🛌🏿|🤌🏻|🤌🏼|🤌🏽|🤌🏾|🤌🏿|🤏🏻|🤏🏼|🤏🏽|🤏🏾|🤏🏿|🤘🏻|🤘🏼|🤘🏽|🤘🏾|🤘🏿|🤙🏻|🤙🏼|🤙🏽|🤙🏾|🤙🏿|🤚🏻|🤚🏼|🤚🏽|🤚🏾|🤚🏿|🤛🏻|🤛🏼|🤛🏽|🤛🏾|🤛🏿|🤜🏻|🤜🏼|🤜🏽|🤜🏾|🤜🏿|🤝🏻|🤝🏼|🤝🏽|🤝🏾|🤝🏿|🤞🏻|🤞🏼|🤞🏽|🤞🏾|🤞🏿|🤟🏻|🤟🏼|🤟🏽|🤟🏾|🤟🏿|🤦🏻|🤦🏼|🤦🏽|🤦🏾|🤦🏿|🤰🏻|🤰🏼|🤰🏽|🤰🏾|🤰🏿|🤱🏻|🤱🏼|🤱🏽|🤱🏾|🤱🏿|🤲🏻|🤲🏼|🤲🏽|🤲🏾|🤲🏿|🤳🏻|🤳🏼|🤳🏽|🤳🏾|🤳🏿|🤴🏻|🤴🏼|🤴🏽|🤴🏾|🤴🏿|🤵🏻|🤵🏼|🤵🏽|🤵🏾|🤵🏿|🤶🏻|🤶🏼|🤶🏽|🤶🏾|🤶🏿|🤷🏻|🤷🏼|🤷🏽|🤷🏾|🤷🏿|🤸🏻|🤸🏼|🤸🏽|🤸🏾|🤸🏿|🤹🏻|🤹🏼|🤹🏽|🤹🏾|🤹🏿|🤼🏻|🤼🏼|🤼🏽|🤼🏾|🤼🏿|🤽🏻|🤽🏼|🤽🏽|🤽🏾|🤽🏿|🤾🏻|🤾🏼|🤾🏽|🤾🏾|🤾🏿|🥷🏻|🥷🏼|🥷🏽|🥷🏾|🥷🏿|🦵🏻|🦵🏼|🦵🏽|🦵🏾|🦵🏿|🦶🏻|🦶🏼|🦶🏽|🦶🏾|🦶🏿|🦸🏻|🦸🏼|🦸🏽|🦸🏾|🦸🏿|🦹🏻|🦹🏼|🦹🏽|🦹🏾|🦹🏿|🦻🏻|🦻🏼|🦻🏽|🦻🏾|🦻🏿|🧍🏻|🧍🏼|🧍🏽|🧍🏾|🧍🏿|🧎🏻|🧎🏼|🧎🏽|🧎🏾|🧎🏿|🧏🏻|🧏🏼|🧏🏽|🧏🏾|🧏🏿|🧑🏻|🧑🏼|🧑🏽|🧑🏾|🧑🏿|🧒🏻|🧒🏼|🧒🏽|🧒🏾|🧒🏿|🧓🏻|🧓🏼|🧓🏽|🧓🏾|🧓🏿|🧔🏻|🧔🏼|🧔🏽|🧔🏾|🧔🏿|🧕🏻|🧕🏼|🧕🏽|🧕🏾|🧕🏿|🧖🏻|🧖🏼|🧖🏽|🧖🏾|🧖🏿|🧗🏻|🧗🏼|🧗🏽|🧗🏾|🧗🏿|🧘🏻|🧘🏼|🧘🏽|🧘🏾|🧘🏿|🧙🏻|🧙🏼|🧙🏽|🧙🏾|🧙🏿|🧚🏻|🧚🏼|🧚🏽|🧚🏾|🧚🏿|🧛🏻|🧛🏼|🧛🏽|🧛🏾|🧛🏿|🧜🏻|🧜🏼|🧜🏽|🧜🏾|🧜🏿|🧝🏻|🧝🏼|🧝🏽|🧝🏾|🧝🏿|🫃🏻|🫃🏼|🫃🏽|🫃🏾|🫃🏿|🫄🏻|🫄🏼|🫄🏽|🫄🏾|🫄🏿|🫅🏻|🫅🏼|🫅🏽|🫅🏾|🫅🏿|🫰🏻|🫰🏼|🫰🏽|🫰🏾|🫰🏿|🫱🏻|🫱🏼|🫱🏽|🫱🏾|🫱🏿|🫲🏻|🫲🏼|🫲🏽|🫲🏾|🫲🏿|🫳🏻|🫳🏼|🫳🏽|🫳🏾|🫳🏿|🫴🏻|🫴🏼|🫴🏽|🫴🏾|🫴🏿|🫵🏻|🫵🏼|🫵🏽|🫵🏾|🫵🏿|🫶🏻|🫶🏼|🫶🏽|🫶🏾|🫶🏿|🫷🏻|🫷🏼|🫷🏽|🫷🏾|🫷🏿|🫸🏻|🫸🏼|🫸🏽|🫸🏾|🫸🏿|#️⃣|0️⃣|1️⃣|2️⃣|3️⃣|4️⃣|5️⃣|6️⃣|7️⃣|8️⃣|9️⃣|☝🏻|☝🏼|☝🏽|☝🏾|☝🏿|⛹🏻|⛹🏼|⛹🏽|⛹🏾|⛹🏿|✊🏻|✊🏼|✊🏽|✊🏾|✊🏿|✋🏻|✋🏼|✋🏽|✋🏾|✋🏿|✌🏻|✌🏼|✌🏽|✌🏾|✌🏿|✍🏻|✍🏼|✍🏽|✍🏾|✍🏿|🅰️|🅱️|🅾️|🅿️|🈂️|🈷️|🌡️|🌤️|🌥️|🌦️|🌧️|🌨️|🌩️|🌪️|🌫️|🌬️|🌶️|🍽️|🎖️|🎗️|🎙️|🎚️|🎛️|🎞️|🎟️|🏋️|🏌️|🏍️|🏎️|🏔️|🏕️|🏖️|🏗️|🏘️|🏙️|🏚️|🏛️|🏜️|🏝️|🏞️|🏟️|🏳️|🏵️|🏷️|🐿️|👁️|📽️|🕉️|🕊️|🕯️|🕰️|🕳️|🕴️|🕵️|🕶️|🕷️|🕸️|🕹️|🖇️|🖊️|🖋️|🖌️|🖍️|🖐️|🖥️|🖨️|🖱️|🖲️|🖼️|🗂️|🗃️|🗄️|🗑️|🗒️|🗓️|🗜️|🗝️|🗞️|🗡️|🗣️|🗨️|🗯️|🗳️|🗺️|🛋️|🛍️|🛎️|🛏️|🛠️|🛡️|🛢️|🛣️|🛤️|🛥️|🛩️|🛰️|🛳️|©️|®️|‼️|⁉️|™️|ℹ️|↔️|↕️|↖️|↗️|↘️|↙️|↩️|↪️|⌨️|⏏️|⏭️|⏮️|⏯️|⏱️|⏲️|⏸️|⏹️|⏺️|Ⓜ️|▪️|▫️|▶️|◀️|◻️|◼️|☀️|☁️|☂️|☃️|☄️|☎️|☑️|☘️|☝️|☠️|☢️|☣️|☦️|☪️|☮️|☯️|☸️|☹️|☺️|♀️|♂️|♟️|♠️|♣️|♥️|♦️|♨️|♻️|♾️|⚒️|⚔️|⚕️|⚖️|⚗️|⚙️|⚛️|⚜️|⚠️|⚧️|⚰️|⚱️|⛈️|⛏️|⛑️|⛓️|⛩️|⛰️|⛱️|⛴️|⛷️|⛸️|⛹️|✂️|✈️|✉️|✌️|✍️|✏️|✒️|✔️|✖️|✝️|✡️|✳️|✴️|❄️|❇️|❣️|❤️|➡️|⤴️|⤵️|⬅️|⬆️|⬇️|〰️|〽️|㊗️|㊙️|[\u231A\u231B\u23E9-\u23EC\u23F0\u23F3\u25FD\u25FE\u2614\u2615\u2648-\u2653\u267F\u2693\u26A1\u26AA\u26AB\u26BD\u26BE\u26C4\u26C5\u26CE\u26D4\u26EA\u26F2\u26F3\u26F5\u26FA\u26FD\u2705\u270A\u270B\u2728\u274C\u274E\u2753-\u2755\u2757\u2795-\u2797\u27B0\u27BF\u2B1B\u2B1C\u2B50\u2B55\u{1F004}\u{1F0CF}\u{1F18E}\u{1F191}-\u{1F19A}\u{1F201}\u{1F21A}\u{1F22F}\u{1F232}-\u{1F236}\u{1F238}-\u{1F23A}\u{1F250}\u{1F251}\u{1F300}-\u{1F320}\u{1F32D}-\u{1F335}\u{1F337}-\u{1F37C}\u{1F37E}-\u{1F393}\u{1F3A0}-\u{1F3CA}\u{1F3CF}-\u{1F3D3}\u{1F3E0}-\u{1F3F0}\u{1F3F4}\u{1F3F8}-\u{1F43E}\u{1F440}\u{1F442}-\u{1F4FC}\u{1F4FF}-\u{1F53D}\u{1F54B}-\u{1F54E}\u{1F550}-\u{1F567}\u{1F57A}\u{1F595}\u{1F596}\u{1F5A4}\u{1F5FB}-\u{1F64F}\u{1F680}-\u{1F6C5}\u{1F6CC}\u{1F6D0}-\u{1F6D2}\u{1F6D5}-\u{1F6D8}\u{1F6DC}-\u{1F6DF}\u{1F6EB}\u{1F6EC}\u{1F6F4}-\u{1F6FC}\u{1F7E0}-\u{1F7EB}\u{1F7F0}\u{1F90C}-\u{1F93A}\u{1F93C}-\u{1F945}\u{1F947}-\u{1F9FF}\u{1FA70}-\u{1FA7C}\u{1FA80}-\u{1FA8A}\u{1FA8E}-\u{1FAC6}\u{1FAC8}\u{1FACD}-\u{1FADC}\u{1FADF}-\u{1FAEA}\u{1FAEF}-\u{1FAF8}])/ug).length;
}
} else {
content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.Fragment, {
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)("i", {
className: "material-icons gray",
children: "warning_amber"
}, void 0, false), " ", (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)("i", {
className: "gray",
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, {
id: "invalid_content",
defaultMessage: "invalid content",
description: "Shown when the message is unreadable"
}, void 0, false)
}, void 0, false)]
}, void 0, true);
}
return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)("li", {
ref: this.props.innerRef,
className: sideClass,
children: [this.props.selectMode ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)("i", {
className: 'material-icons select-checkbox' + (this.props.selected ? ' blue' : ''),
onClick: () => this.props.onToggleSelect(this.props.seq),
children: this.props.selected ? 'check_circle' : 'radio_button_unchecked'
}, void 0, false) : null, this.props.isGroup && this.props.response ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)("div", {
className: "avatar-box",
children: fullDisplay ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)(_letter_tile_jsx__WEBPACK_IMPORTED_MODULE_5__["default"], {
authorizeURL: this.props.tinode.authorizeURL,
topic: this.props.userFrom,
title: this.props.userName,
avatar: avatar
}, void 0, false) : null
}, void 0, false) : null, isFailed && failReason ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)("i", {
className: "material-icons red message-fail-icon",
children: "error"
}, void 0, false) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)("div", {
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)("div", {
className: bubbleClass,
children: [showVoiceUnreadDot ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)("i", {
className: "voice-unread-dot"
}, void 0, false) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)("div", {
className: "content-meta",
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)("div", {
className: textSizeClass,
children: [bundleCard || content, attachments]
}, void 0, true), this.props.timestamp ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)(_received_marker_jsx__WEBPACK_IMPORTED_MODULE_6__["default"], {
edited: this.props.edited,
timestamp: this.props.timestamp,
received: this.props.received
}, void 0, false) : null]
}, void 0, true), this.props.showContextMenu && !this.props.selectMode ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)("span", {
className: "menuTrigger",
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)("a", {
href: "#",
onClick: this.handleContextClick,
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)("i", {
className: "material-icons",
children: "expand_more"
}, void 0, false)
}, void 0, false)
}, void 0, false) : null]
}, void 0, true), failReason, fullDisplay ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)("div", {
className: "author",
children: [this.props.userName || (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)("i", {
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, {
id: "user_not_found",
defaultMessage: "Not found",
description: "In place of a user's full name when the user is not found."
}, void 0, false)
}, void 0, false), this.props.senderRole == 'owner' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)("em", {
className: "role-badge owner",
children: "群主"
}, void 0, false) : this.props.senderRole == 'admin' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)("em", {
className: "role-badge admin",
children: "管理员"
}, void 0, false) : null]
}, void 0, true) : null]
}, void 0, true)]
}, void 0, true);
}
}
;
const IntlChatMessage = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(BaseChatMessage);
const ChatMessage = react__WEBPACK_IMPORTED_MODULE_0___default().forwardRef((props, ref) => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxDEV)(IntlChatMessage, {
innerRef: ref,
...props
}, void 0, false));
/* harmony default export */ __webpack_exports__["default"] = (ChatMessage);
/***/ }),
/***/ "./src/widgets/forward-bundle.jsx":
/*!****************************************!*\
!*** ./src/widgets/forward-bundle.jsx ***!
\****************************************/
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": function() { return /* binding */ ForwardBundle; }
/* harmony export */ });
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react");
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js");
function senderName(tinode, from) {
const raw = (from || '').trim();
if (!raw) return '';
const uid = raw.startsWith('usr') ? raw : 'usr' + raw;
const topic = tinode && tinode.getTopic ? tinode.getTopic(uid) : null;
const pub = topic && topic.public;
return pub && (pub.fn || pub.name) || '';
}
const TYPE_LABEL = {
image: '[图片]',
video: '[视频]',
voice: '[语音]',
file: '[文件]',
link: '[链接]'
};
function lineText(entry) {
if (!entry) return '';
const summary = (entry.summary || entry.text || '').trim();
if (summary) return summary;
return TYPE_LABEL[entry.type] || '';
}
class ForwardBundle extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) {
constructor(props) {
super(props);
this.state = {
expanded: false
};
this.handleToggle = this.handleToggle.bind(this);
}
handleToggle(e) {
e.preventDefault();
e.stopPropagation();
this.setState(s => ({
expanded: !s.expanded
}));
}
render() {
const c = this.props.content || {};
const count = Number(c.item_count) || (Array.isArray(c.items) ? c.items.length : 0);
const rows = this.state.expanded ? c.items || [] : c.preview || [];
const comment = (c.comment || '').trim();
return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxDEV)("div", {
className: "forward-bundle",
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxDEV)("div", {
className: "forward-bundle-title",
children: c.title || '聊天记录'
}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxDEV)("ul", {
className: "forward-bundle-lines",
children: rows.map((entry, i) => {
const who = senderName(this.props.tinode, entry.from);
return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxDEV)("li", {
children: [who ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxDEV)("b", {
children: [who, ":"]
}, void 0, true) : null, lineText(entry)]
}, (entry.seq != null ? entry.seq : i) + ':' + i, true);
})
}, void 0, false), count > rows.length || this.state.expanded ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxDEV)("button", {
type: "button",
className: "forward-bundle-more",
onClick: this.handleToggle,
children: this.state.expanded ? '收起' : `查看完整记录(共 ${count} 条)`
}, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxDEV)("div", {
className: "forward-bundle-count",
children: ["共 ", count, " 条消息"]
}, void 0, true), comment ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxDEV)("div", {
className: "forward-bundle-comment",
children: comment
}, void 0, false) : null]
}, void 0, true);
}
}
/***/ }),
/***/ "./src/widgets/group-subs.jsx":
/*!************************************!*\
!*** ./src/widgets/group-subs.jsx ***!
\************************************/
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": function() { return /* binding */ GroupSubs; }
/* harmony export */ });
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react");
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl");
/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../config.js */ "./src/config.js");
/* harmony import */ var _letter_tile_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./letter-tile.jsx */ "./src/widgets/letter-tile.jsx");
/* harmony import */ var _lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../lib/blob-helpers.js */ "./src/lib/blob-helpers.js");
/* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js");
class GroupSubs extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) {
constructor(props) {
super(props);
}
render() {
const usersOnline = [];
const totalCount = (this.props.subscribers || []).length;
const countToShow = Math.min(_config_js__WEBPACK_IMPORTED_MODULE_2__.MAX_ONLINE_IN_TOPIC, totalCount);
(this.props.subscribers || []).some(sub => {
usersOnline.push((0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", {
className: "avatar-box",
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(_letter_tile_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], {
authorizeURL: this.props.tinode.authorizeURL,
topic: sub.user,
avatar: (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_4__.makeImageUrl)(sub.public ? sub.public.photo : null) || true,
title: sub.public ? sub.public.fn : null
}, void 0, false)
}, sub.user, false));
return usersOnline.length == countToShow;
});
if (usersOnline.length == 0) {
return null;
}
return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", {
id: "topic-users",
children: [usersOnline, " ", totalCount > countToShow ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("span", {
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, {
id: "more_online_members",
defaultMessage: "+{overflow} more",
description: "Shown in MessagesView title bar when the number of online subscribers exceeds MAX_ONLINE_IN_TOPIC",
values: {
overflow: totalCount - countToShow
}
}, void 0, false)
}, void 0, false) : null]
}, void 0, true);
}
}
;
/***/ }),
/***/ "./src/widgets/invitation.jsx":
/*!************************************!*\
!*** ./src/widgets/invitation.jsx ***!
\************************************/
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": function() { return /* binding */ Invitation; }
/* harmony export */ });
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react");
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl");
/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js");
class Invitation extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) {
constructor(props) {
super(props);
this.handleButtonAction = this.handleButtonAction.bind(this);
}
handleButtonAction(evt, data) {
evt.preventDefault();
this.props.onAction(data);
}
render() {
return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", {
className: "accept-invite-panel",
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", {
className: "title",
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, {
id: "chat_invitation",
defaultMessage: "You are invited to start a new chat. What would you like to do?",
description: "New chat invitation message: [Accept] [Ignore] [Block]."
}, void 0, false)
}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("div", {
className: "footer",
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", {
className: "primary",
onClick: event => {
this.handleButtonAction(event, "accept");
},
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, {
id: "chat_invitation_accept",
defaultMessage: "Accept",
description: "Action [Accept] for chat invitation."
}, void 0, false)
}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", {
className: "secondary",
onClick: event => {
this.handleButtonAction(event, "delete");
},
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, {
id: "chat_invitation_ignore",
defaultMessage: "Ignore",
description: "Action [Ignore] for chat invitation."
}, void 0, false)
}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)("button", {
className: "secondary",
onClick: event => {
this.handleButtonAction(event, "block");
},
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_2__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, {
id: "chat_invitation_block",
defaultMessage: "Block",
description: "Action [Block] for chat invitation."
}, void 0, false)
}, void 0, false)]
}, void 0, true)]
}, void 0, true);
}
}
;
/***/ }),
/***/ "./src/widgets/meta-message.jsx":
/*!**************************************!*\
!*** ./src/widgets/meta-message.jsx ***!
\**************************************/
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": function() { return /* binding */ MetaMessage; }
/* harmony export */ });
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react");
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js");
class MetaMessage extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) {
constructor(props) {
super(props);
}
render() {
let content = null;
let bubbleClass = 'bubble';
if (this.props.date) {
content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.Fragment, {
children: this.props.date
}, void 0, false);
bubbleClass += ' date';
} else if (this.props.deleted) {
content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxDEV)("i", {
className: "gray",
children: this.props.deletedText || '消息已删除'
}, void 0, false);
bubbleClass += ' date';
}
if (!content) {
return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.Fragment, {
children: null
}, void 0, false);
}
return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxDEV)("li", {
className: "meta",
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxDEV)("div", {
className: bubbleClass,
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxDEV)("div", {
className: "message-content",
children: content
}, void 0, false)
}, void 0, false)
}, void 0, false);
}
}
;
/***/ }),
/***/ "./src/widgets/pinned-messages.jsx":
/*!*****************************************!*\
!*** ./src/widgets/pinned-messages.jsx ***!
\*****************************************/
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react");
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl");
/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk");
/* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var _lib_formatters_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../lib/formatters.js */ "./src/lib/formatters.js");
/* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../config.js */ "./src/config.js");
/* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js");
const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({
message_not_found: {
id: 'message_not_found',
defaultMessage: 'message not found',
description: 'Pinned message is not found'
},
message_deleted: {
id: 'message_deleted',
defaultMessage: 'message deleted',
description: 'Pinned message is deleted'
}
});
class PinnedMessages extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) {
constructor(props) {
super(props);
this.touchX = null;
this.touchY = null;
this.touchSurface = react__WEBPACK_IMPORTED_MODULE_0___default().createRef();
this.getSelectedIndex = this.getSelectedIndex.bind(this);
this.handleCancel = this.handleCancel.bind(this);
this.handleSelected = this.handleSelected.bind(this);
this.handleMoveNext = this.handleMoveNext.bind(this);
this.handleMovePrev = this.handleMovePrev.bind(this);
this.handleTouchEventStart = this.handleTouchEventStart.bind(this);
this.handleTouchEventEnd = this.handleTouchEventEnd.bind(this);
this.handleTouchCancel = this.handleTouchCancel.bind(this);
}
componentDidMount() {
this.touchSurface.current.addEventListener('touchstart', this.handleTouchEventStart, {
passive: true
});
this.touchSurface.current.addEventListener('touchend', this.handleTouchEventEnd, {
passive: true
});
this.touchSurface.current.addEventListener('touchcancel', this.handleTouchCancel, {
passive: true
});
}
componentWillUnmount() {
this.touchSurface.current.removeEventListener('touchstart', this.handleTouchEventStart);
this.touchSurface.current.removeEventListener('touchend', this.handleTouchEventEnd);
this.touchSurface.current.removeEventListener('touchcancel', this.handleTouchCancel);
}
getSelectedIndex() {
const list = this.props.pins || [];
return list.length - this.props.selected - 1;
}
handleCancel(e) {
e.preventDefault();
this.props.onCancel(this.props.pins[this.getSelectedIndex()]);
}
handleSelected(e) {
e.preventDefault();
this.props.onSelected(this.props.pins[this.getSelectedIndex()]);
}
handleMoveNext(e, isTouch) {
isTouch || e.preventDefault();
e.stopPropagation();
const idx = Math.max(this.props.selected - 1, 0);
if (idx != this.props.selected) {
this.props.setSelected(idx);
}
}
handleMovePrev(e, isTouch) {
isTouch || e.preventDefault();
e.stopPropagation();
const idx = Math.min(this.props.selected + 1, (this.props.pins || []).length - 1);
if (idx != this.props.selected) {
this.props.setSelected(idx);
}
}
handleTouchEventStart(e) {
if (e.touches.length == 1) {
this.touchX = e.touches[0].clientX;
this.touchY = e.touches[0].clientY;
}
}
handleTouchEventEnd(e) {
if (this.touchX === null || e.changedTouches.length != 1) {
this.touchX = null;
return;
}
const dX = this.touchX - e.changedTouches[0].clientX;
const dY = this.touchY - e.changedTouches[0].clientY;
this.touchX = null;
if (Math.abs(dX) > Math.abs(dY) || Math.abs(dY) < _config_js__WEBPACK_IMPORTED_MODULE_4__.MIN_SWIPE_DISTANCE) {
return;
}
if (dY > 0) {
this.handleMovePrev(e, true);
} else {
this.handleMoveNext(e, true);
}
}
handleTouchCancel() {
this.touchX = null;
}
render() {
const selected = this.getSelectedIndex();
let messageShown = (this.props.messages || [])[selected];
messageShown = messageShown ? messageShown._deleted ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("i", {
className: "gray",
children: this.props.intl.formatMessage(messages.message_deleted)
}, void 0, false) : tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.format(messageShown.content, _lib_formatters_js__WEBPACK_IMPORTED_MODULE_3__.previewFormatter, {
formatMessage: this.props.intl.formatMessage.bind(this.props.intl),
authorizeURL: this.props.tinode.authorizeURL.bind(this.props.tinode)
}) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("i", {
className: "gray",
children: this.props.intl.formatMessage(messages.message_not_found)
}, void 0, false);
const dots = [];
this.props.pins.forEach(seq => {
const cn = dots.length == selected ? 'adot' : 'dot';
dots.push((0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", {
className: cn
}, seq, false));
});
return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", {
id: "pinned-wrapper",
ref: this.touchSurface,
children: [this.props.isAdmin ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", {
className: "cancel",
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("a", {
href: "#",
onClick: this.handleCancel,
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("i", {
className: "material-icons gray",
children: "close"
}, void 0, false)
}, void 0, false)
}, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", {
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("i", {
className: "material-icons gray",
children: "push_pin"
}, void 0, false)
}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", {
className: "pinned-scroll",
children: dots
}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", {
className: "pinned",
onClick: this.handleSelected,
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("p", {
children: messageShown
}, void 0, false)
}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", {
className: "pinned-menu",
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("span", {
className: "menuTrigger upper",
children: selected > 0 ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("a", {
href: "#",
onClick: this.handleMovePrev,
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("i", {
className: "material-icons",
children: "expand_less"
}, void 0, false)
}, void 0, false) : null
}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("span", {
className: "menuTrigger lower",
children: this.props.selected > 0 ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("a", {
href: "#",
onClick: this.handleMoveNext,
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("i", {
className: "material-icons",
children: "expand_more"
}, void 0, false)
}, void 0, false) : null
}, void 0, false)]
}, void 0, true)]
}, void 0, true);
}
}
/* harmony default export */ __webpack_exports__["default"] = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(PinnedMessages));
/***/ }),
/***/ "./src/widgets/received-marker.jsx":
/*!*****************************************!*\
!*** ./src/widgets/received-marker.jsx ***!
\*****************************************/
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react");
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl");
/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk");
/* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js");
/* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js");
const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({
message_sending: {
id: 'message_sending',
defaultMessage: 'sending...',
description: 'Message being sent, in place of time stamp'
},
message_sending_failed: {
id: 'message_sending_failed',
defaultMessage: 'failed',
description: 'Failed to send message, in place of time stamp'
},
message_edited_marker: {
id: 'message_edited_marker',
defaultMessage: ', edited',
description: 'Marker indicating that the message was edited'
}
});
class ReceivedMarker extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) {
render() {
const {
formatMessage
} = this.props.intl;
let timestamp;
if (this.props.received <= tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.MESSAGE_STATUS_SENDING) {
timestamp = formatMessage(messages.message_sending);
} else if (this.props.received == tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.MESSAGE_STATUS_FAILED || this.props.received == tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.MESSAGE_STATUS_FATAL) {
timestamp = formatMessage(messages.message_sending_failed);
} else {
timestamp = this.props.timestamp.toLocaleTimeString(this.props.intl.locale, {
timeStyle: 'short'
});
}
const icon = (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_3__.deliveryMarker)(this.props.received);
const marker = icon ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("i", {
className: 'material-icons small ' + icon.color,
children: icon.name
}, void 0, false) : null;
const edited = this.props.edited ? formatMessage(messages.message_edited_marker) : null;
return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("span", {
className: "timestamp",
children: [timestamp, edited, '\u00a0', marker]
}, void 0, true);
}
}
;
/* harmony default export */ __webpack_exports__["default"] = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(ReceivedMarker));
/***/ }),
/***/ "./src/widgets/send-message.jsx":
/*!**************************************!*\
!*** ./src/widgets/send-message.jsx ***!
\**************************************/
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react");
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl");
/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk");
/* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../config.js */ "./src/config.js");
/* harmony import */ var _lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../lib/blob-helpers.js */ "./src/lib/blob-helpers.js");
/* harmony import */ var _lib_formatters_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../lib/formatters.js */ "./src/lib/formatters.js");
/* harmony import */ var _lib_im_api_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../lib/im-api.js */ "./src/lib/im-api.js");
/* harmony import */ var react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! react/jsx-dev-runtime */ "./node_modules/react/jsx-dev-runtime.js");
const AudioRecorder = react__WEBPACK_IMPORTED_MODULE_0___default().lazy(_ => Promise.all(/*! import() */[__webpack_require__.e("vendors-node_modules_webm-duration-fix_lib_index_js"), __webpack_require__.e("src_widgets_audio-recorder_jsx")]).then(__webpack_require__.bind(__webpack_require__, /*! ./audio-recorder.jsx */ "./src/widgets/audio-recorder.jsx")));
const EMOJI_LIST = ['😀', '😁', '😂', '🤣', '😃', '😄', '😅', '😆', '😉', '😊', '😋', '😎', '😍', '😘', '🥰', '😗', '😙', '😚', '🙂', '🤗', '🤩', '🤔', '🤨', '😐', '😑', '😶', '🙄', '😏', '😣', '😥', '😮', '🤐', '😯', '😪', '😫', '🥱', '😴', '😌', '😛', '😜', '😝', '🤤', '😒', '😓', '😔', '😕', '🙃', '🤑', '😲', '☹️', '🙁', '😖', '😞', '😟', '😤', '😢', '😭', '😦', '😧', '😨', '😩', '🤯', '😬', '😰', '😱', '🥵', '🥶', '😳', '🤪', '😵', '😡', '😠', '🤬', '😷', '🤒', '🤕', '🤢', '🤮', '🥳', '🥴', '🥺', '🤫', '🤭', '🧐', '🤓', '😈', '👿', '👍', '👎', '👏', '🙌', '🤝', '🙏', '💪', '❤️', '🧡', '💛', '💚', '💙', '💜', '🖤', '💔', '💕', '💯', '🔥', '🎉', '🎂', '🌹', '☀️', '🌙', '⭐'];
const FAVORITE_TYPE_LABEL = {
image: '[图片]',
video: '[视频]',
voice: '[语音]',
file: '[文件]',
link: '[链接]'
};
function favoriteSummary(item) {
const content = item.snapshot && item.snapshot.content;
if (content && typeof content.txt === 'string' && content.txt) {
return content.txt;
}
return FAVORITE_TYPE_LABEL[item.type] || item.type || item.favorite_id;
}
const RECENT_EMOJI_KEY = 'im-recent-emoji';
const MAX_RECENT_EMOJI = 30;
function loadRecentEmoji() {
try {
const raw = JSON.parse(localStorage.getItem(RECENT_EMOJI_KEY) || '[]');
return Array.isArray(raw) ? raw : [];
} catch (_) {
return [];
}
}
function pushRecentEmoji(emoji) {
try {
const list = [emoji].concat(loadRecentEmoji().filter(e => e !== emoji)).slice(0, MAX_RECENT_EMOJI);
localStorage.setItem(RECENT_EMOJI_KEY, JSON.stringify(list));
} catch (_) {}
}
const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({
messaging_disabled: {
id: 'messaging_disabled_prompt',
defaultMessage: 'Messaging disabled',
description: 'Prompt in SendMessage in read-only topic'
},
type_new_message: {
id: 'new_message_prompt',
defaultMessage: 'New message',
description: 'Prompt in send message field'
},
add_image_caption: {
id: 'image_caption_prompt',
defaultMessage: 'Image caption',
description: 'Prompt in SendMessage for attached image'
},
file_attachment_too_large: {
id: 'file_attachment_too_large',
defaultMessage: 'The file size {size} exceeds the {limit} limit.',
description: 'Error message when attachment is too large'
},
cannot_initiate_upload: {
id: 'cannot_initiate_file_upload',
defaultMessage: 'Cannot initiate file upload.',
description: 'Generic error messagewhen attachment fails'
},
icon_title_record_voice: {
id: 'icon_title_record_voice',
defaultMessage: 'Record voice message',
description: 'Icon tool tip for recording a voice message'
},
icon_title_attach_file: {
id: 'icon_title_attach_file',
defaultMessage: 'Attach file',
description: 'Icon tool tip for attaching a file'
},
icon_title_add_image: {
id: 'icon_title_add_image',
defaultMessage: 'Add image',
description: 'Icon tool tip for attaching an image'
},
icon_title_send: {
id: 'icon_title_send',
defaultMessage: 'Send message',
description: 'Icon tool tip for sending a message'
}
});
class SendMessage extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) {
constructor(props) {
super(props);
this.state = {
quote: null,
message: '',
audioRec: false,
audioAvailable: !!(navigator.mediaDevices && navigator.mediaDevices.getUserMedia),
mentionQuery: null,
mentionResults: [],
mentionHighlight: 0,
emojiOpen: false,
emojiTab: 'emoji',
recentEmoji: loadRecentEmoji(),
attachOpen: false,
cardPicker: null,
favPicker: null,
audioCancelling: false
};
this.keypressTimestamp = 0;
this.handlePasteEvent = this.handlePasteEvent.bind(this);
this.handleAttachImage = this.handleAttachImage.bind(this);
this.handleAttachFile = this.handleAttachFile.bind(this);
this.handleAttachAudio = this.handleAttachAudio.bind(this);
this.handleSend = this.handleSend.bind(this);
this.handleKeyPress = this.handleKeyPress.bind(this);
this.handleMessageTyping = this.handleMessageTyping.bind(this);
this.handleDropAttach = this.handleDropAttach.bind(this);
this.handleQuoteClick = this.handleQuoteClick.bind(this);
this.selectMention = this.selectMention.bind(this);
this.startHoldRecording = this.startHoldRecording.bind(this);
this.handleHoldMove = this.handleHoldMove.bind(this);
this.endHoldRecording = this.endHoldRecording.bind(this);
this.handleHoldVisibilityChange = this.handleHoldVisibilityChange.bind(this);
this.toggleEmojiPanel = this.toggleEmojiPanel.bind(this);
this.insertEmoji = this.insertEmoji.bind(this);
this.toggleAttachPanel = this.toggleAttachPanel.bind(this);
this.openCardPicker = this.openCardPicker.bind(this);
this.openFavPicker = this.openFavPicker.bind(this);
this.sendCard = this.sendCard.bind(this);
this.sendFavorite = this.sendFavorite.bind(this);
this.formatReply = this.formatReply.bind(this);
}
componentDidMount() {
if (this.messageEditArea) {
this.messageEditArea.addEventListener('paste', this.handlePasteEvent, false);
if (window.getComputedStyle(this.messageEditArea).getPropertyValue('transition-property') == 'all') {
this.messageEditArea.focus();
}
}
this.setState({
quote: this.formatReply()
});
}
componentWillUnmount() {
if (this.messageEditArea) {
this.messageEditArea.removeEventListener('paste', this.handlePasteEvent, false);
}
if (this.mentionSearchTimer) {
window.clearTimeout(this.mentionSearchTimer);
}
window.removeEventListener('mousemove', this.handleHoldMove);
window.removeEventListener('mouseup', this.endHoldRecording);
window.removeEventListener('touchmove', this.handleHoldMove);
window.removeEventListener('touchend', this.endHoldRecording);
window.removeEventListener('blur', this.endHoldRecording);
document.removeEventListener('visibilitychange', this.handleHoldVisibilityChange);
}
componentDidUpdate(prevProps) {
if (this.messageEditArea) {
if (window.getComputedStyle(this.messageEditArea).getPropertyValue('transition-property') == 'all') {
this.messageEditArea.focus();
}
this.messageEditArea.style.height = '0px';
this.messageEditArea.style.height = this.messageEditArea.scrollHeight + 'px';
}
if (prevProps.topicName != this.props.topicName) {
this.setState({
message: this.props.initMessage || '',
audioRec: false,
quote: null,
mentionQuery: null,
mentionResults: [],
emojiOpen: false,
attachOpen: false,
cardPicker: null,
favPicker: null
});
} else if (!prevProps.disabled && this.props.disabled && this.state.audioRec) {
this.setState({
audioRec: false
});
} else if (prevProps.initMessage != this.props.initMessage) {
const msg = this.props.initMessage || '';
this.setState({
message: msg
}, _ => {
this.messageEditArea.scrollTop = this.messageEditArea.scrollHeight;
this.messageEditArea.setSelectionRange(msg.length, msg.length);
});
}
if (prevProps.reply != this.props.reply) {
this.setState({
quote: this.formatReply()
});
}
}
formatReply() {
return this.props.reply ? tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.format(this.props.reply.content, _lib_formatters_js__WEBPACK_IMPORTED_MODULE_5__.replyFormatter, {
formatMessage: this.props.intl.formatMessage.bind(this.props.intl),
authorizeURL: this.props.tinode.authorizeURL.bind(this.props.tinode)
}) : null;
}
handlePasteEvent(e) {
if (this.props.disabled) {
return;
}
if ((0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_4__.filePasted)(e, file => {
if (this.props.onAttachImage) {
this.props.onAttachImage(file);
}
}, file => {
if (this.props.onAttachFile) {
this.props.onAttachFile(file);
}
}, this.props.onError)) {
e.preventDefault();
}
}
handleAttachImage(e) {
if (e.target.files && e.target.files.length > 0 && this.props.onAttachImage) {
this.props.onAttachImage(e.target.files[0]);
}
e.target.value = '';
}
handleAttachFile(e) {
if (e.target.files && e.target.files.length > 0 && this.props.onAttachFile) {
this.props.onAttachFile(e.target.files[0]);
}
e.target.value = '';
}
handleDropAttach(files) {
if (files && files.length > 0 && this.props.onAttachFile) {
this.props.onAttachFile(files[0]);
}
}
handleAttachAudio(url, preview, duration) {
this.setState({
audioRec: false
});
if (this.props.onAttachAudio) {
this.props.onAttachAudio(url, preview, duration);
}
}
handleSend(e) {
e.preventDefault();
const message = this.state.message.trim();
if (message || this.props.acceptBlank || this.props.noInput) {
const result = this.props.onSendMessage(message);
if (result && typeof result.then == 'function') {
result.then(sent => {
if (sent !== false) this.setState({
message: ''
});
});
} else {
this.setState({
message: ''
});
}
}
}
handleKeyPress(e) {
if (this.state.audioRec) {
e.preventDefault();
e.stopPropagation();
return;
}
if (this.state.mentionQuery != null) {
if (e.key === 'Escape') {
e.preventDefault();
this.setState({
mentionQuery: null,
mentionResults: []
});
return;
}
if (this.state.mentionResults.length > 0 && (e.key === 'ArrowDown' || e.key === 'ArrowUp')) {
e.preventDefault();
const delta = e.key === 'ArrowDown' ? 1 : -1;
const count = this.state.mentionResults.length;
this.setState({
mentionHighlight: (this.state.mentionHighlight + delta + count) % count
});
return;
}
if (e.key === 'Enter' && this.state.mentionResults.length > 0) {
e.preventDefault();
e.stopPropagation();
this.selectMention(this.state.mentionResults[this.state.mentionHighlight]);
return;
}
}
if (e.key === 'Enter') {
if (this.props.sendOnEnter == 'plain') {
if (!e.shiftKey) {
e.preventDefault();
e.stopPropagation();
this.handleSend(e);
}
} else {
if (e.ctrlKey || e.metaKey) {
e.preventDefault();
e.stopPropagation();
this.handleSend(e);
}
}
}
}
handleMessageTyping(e) {
this.setState({
message: e.target.value
});
this.updateMentionState(e.target.value, e.target.selectionStart);
if (this.props.onMessageChange) {
this.props.onMessageChange(e.target.value);
}
if (this.props.onKeyPress) {
const now = new Date().getTime();
if (now - this.keypressTimestamp > _config_js__WEBPACK_IMPORTED_MODULE_3__.KEYPRESS_DELAY) {
this.props.onKeyPress();
this.keypressTimestamp = now;
}
}
}
updateMentionState(text, caret) {
if (!this.props.onMentionSearch || caret == null) {
return;
}
const before = text.slice(0, caret);
const match = /(?:^|\s)@([^\s@]*)$/.exec(before);
if (!match) {
if (this.state.mentionQuery != null) {
this.setState({
mentionQuery: null,
mentionResults: []
});
}
return;
}
const query = match[1];
const start = caret - query.length - 1;
this.setState({
mentionQuery: query,
mentionStart: start,
mentionHighlight: 0
});
if (this.mentionSearchTimer) {
window.clearTimeout(this.mentionSearchTimer);
}
this.mentionSearchTimer = window.setTimeout(() => {
this.props.onMentionSearch(query).then(results => {
if (this.state.mentionQuery != null) {
this.setState({
mentionResults: results || []
});
}
}).catch(() => {});
}, 200);
}
selectMention(item) {
const {
message,
mentionStart,
mentionQuery
} = this.state;
if (mentionStart == null || mentionQuery == null) {
return;
}
const name = item.group_nickname || item.display_name || item.user_id;
const insertion = '@' + name + ' ';
const end = mentionStart + 1 + mentionQuery.length;
const newMessage = message.slice(0, mentionStart) + insertion + message.slice(end);
const caretPos = mentionStart + insertion.length;
this.setState({
message: newMessage,
mentionQuery: null,
mentionResults: []
});
if (this.props.onMentionSelected) {
this.props.onMentionSelected(item.user_id, name);
}
if (this.props.onMessageChange) {
this.props.onMessageChange(newMessage);
}
requestAnimationFrame(() => {
if (this.messageEditArea) {
this.messageEditArea.focus();
this.messageEditArea.setSelectionRange(caretPos, caretPos);
}
});
}
handleQuoteClick(e) {
e.preventDefault();
e.stopPropagation();
if (this.props.reply && this.props.onQuoteClick) {
const replyToSeq = this.props.reply.seq;
this.props.onQuoteClick(replyToSeq);
}
}
toggleEmojiPanel(e) {
e.preventDefault();
this.setState(s => ({
emojiOpen: !s.emojiOpen,
attachOpen: false,
audioRec: false
}));
}
insertEmoji(emoji) {
const ta = this.messageEditArea;
const start = ta ? ta.selectionStart : this.state.message.length;
const end = ta ? ta.selectionEnd : this.state.message.length;
const newMessage = this.state.message.slice(0, start) + emoji + this.state.message.slice(end);
pushRecentEmoji(emoji);
this.setState({
message: newMessage,
recentEmoji: loadRecentEmoji()
});
if (this.props.onMessageChange) {
this.props.onMessageChange(newMessage);
}
const caretPosEmoji = start + emoji.length;
requestAnimationFrame(() => {
if (this.messageEditArea) {
this.messageEditArea.focus();
this.messageEditArea.setSelectionRange(caretPosEmoji, caretPosEmoji);
}
});
}
toggleAttachPanel(e) {
e.preventDefault();
this.setState(s => ({
attachOpen: !s.attachOpen,
emojiOpen: false
}));
}
openCardPicker(e) {
e.preventDefault();
this.setState({
attachOpen: false,
cardPicker: {
loading: true
}
});
(0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_6__.getFriends)().then(data => {
this.setState({
cardPicker: {
loading: false,
items: data.items || []
}
});
}).catch(() => this.setState({
cardPicker: {
loading: false,
items: [],
error: true
}
}));
}
sendCard(item) {
this.setState({
cardPicker: null
});
const build = avatarUrl => {
const card = new tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.TheCard(item.display_name || item.user_id, avatarUrl);
tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.TheCard.setTinodeID(card, item.user_id);
this.props.onSendMessage(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.appendTheCard(null, card));
};
if (item.avatar_file_id) {
(0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_6__.getFileUrl)(item.avatar_file_id).then(build).catch(() => build(undefined));
} else {
build(undefined);
}
}
openFavPicker(e) {
e.preventDefault();
this.setState({
attachOpen: false,
favPicker: {
loading: true
}
});
(0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_6__.getFavorites)({
type: 'all'
}).then(data => {
this.setState({
favPicker: {
loading: false,
items: data.items || []
}
});
}).catch(() => this.setState({
favPicker: {
loading: false,
items: [],
error: true
}
}));
}
sendFavorite(item) {
this.setState({
favPicker: null
});
if (!this.props.topicName) {
return;
}
(0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_6__.forwardFavorites)([item.favorite_id], [this.props.topicName]).then(result => {
const failed = (result && result.items || []).filter(r => r.status === 'failed');
if (failed.length && this.props.onError) {
this.props.onError('发送失败:' + ((0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_6__.translateReason)(failed[0].reason) || failed[0].reason || '未知原因'), 'err');
}
}).catch(err => {
if (this.props.onError) {
this.props.onError(err && err.message || '发送失败', 'err');
}
});
}
startHoldRecording(e) {
e.preventDefault();
if (this.state.audioRec) {
return;
}
this.holdStartY = 'touches' in e ? e.touches[0] && e.touches[0].clientY : e.clientY;
this.setState({
audioRec: true,
audioCancelling: false,
emojiOpen: false,
attachOpen: false
});
window.addEventListener('mousemove', this.handleHoldMove);
window.addEventListener('mouseup', this.endHoldRecording);
window.addEventListener('touchmove', this.handleHoldMove, {
passive: false
});
window.addEventListener('touchend', this.endHoldRecording);
window.addEventListener('blur', this.endHoldRecording);
document.addEventListener('visibilitychange', this.handleHoldVisibilityChange);
}
handleHoldVisibilityChange() {
if (document.hidden) {
this.endHoldRecording();
}
}
handleHoldMove(e) {
const y = 'touches' in e ? e.touches[0] && e.touches[0].clientY : e.clientY;
if (y == null || this.holdStartY == null) {
return;
}
const cancelling = this.holdStartY - y > 80;
if (cancelling !== this.state.audioCancelling) {
this.setState({
audioCancelling: cancelling
});
}
}
endHoldRecording() {
window.removeEventListener('mousemove', this.handleHoldMove);
window.removeEventListener('mouseup', this.endHoldRecording);
window.removeEventListener('touchmove', this.handleHoldMove);
window.removeEventListener('touchend', this.endHoldRecording);
window.removeEventListener('blur', this.endHoldRecording);
document.removeEventListener('visibilitychange', this.handleHoldVisibilityChange);
this.holdStartY = null;
const fakeEvent = {
preventDefault: () => {}
};
if (this.audioRecorderInstance) {
if (this.state.audioCancelling) {
this.audioRecorderInstance.handleDelete(fakeEvent);
} else {
this.audioRecorderInstance.handleDone(fakeEvent);
}
}
}
render() {
const {
formatMessage
} = this.props.intl;
const prompt = this.props.disabled ? formatMessage(messages.messaging_disabled) : this.props.messagePrompt ? formatMessage(messages[this.props.messagePrompt]) : formatMessage(messages.type_new_message);
const sendIcon = this.props.reply && this.props.reply.editing ? 'check_circle' : 'send';
const quote = this.state.quote ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", {
id: "reply-quote-preview",
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", {
className: "cancel",
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("a", {
href: "#",
onClick: e => {
e.preventDefault();
this.props.onCancelReply();
},
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("i", {
className: "material-icons gray",
children: "close"
}, void 0, false)
}, void 0, false)
}, void 0, false), this.state.quote]
}, void 0, true) : null;
const audioEnabled = this.state.audioAvailable && this.props.onAttachAudio;
const mentionPanel = this.state.mentionQuery != null ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", {
id: "mention-picker",
children: this.state.mentionResults.length === 0 ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", {
className: "mention-picker-empty",
children: "无匹配成员"
}, void 0, false) : this.state.mentionResults.map((item, i) => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", {
className: 'mention-picker-row' + (i === this.state.mentionHighlight ? ' active' : ''),
onMouseDown: e => {
e.preventDefault();
this.selectMention(item);
},
onMouseEnter: () => this.setState({
mentionHighlight: i
}),
children: item.group_nickname || item.display_name || item.user_id
}, item.user_id, false))
}, void 0, false) : null;
return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", {
id: "send-message-wrapper",
children: [!this.props.noInput ? quote : null, mentionPanel, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", {
id: "send-message-panel",
children: !this.props.disabled ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.Fragment, {
children: [this.props.noInput ? quote || (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", {
className: "hr thin"
}, void 0, false) : this.state.audioRec ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(react__WEBPACK_IMPORTED_MODULE_0__.Suspense, {
fallback: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", {
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, {
id: "loading_note",
defaultMessage: "Loading...",
description: "Message shown when component is loading"
}, void 0, false)
}, void 0, false),
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(AudioRecorder, {
ref: ref => {
this.audioRecorderInstance = ref;
},
holdMode: true,
cancelling: this.state.audioCancelling,
onRecordingProgress: _ => this.props.onKeyPress(true),
onDeleted: _ => this.setState({
audioRec: false
}),
onFinished: this.handleAttachAudio
}, void 0, false)
}, void 0, false) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("textarea", {
id: "send-message-input",
placeholder: prompt,
value: this.state.message,
onChange: this.handleMessageTyping,
onKeyDown: this.handleKeyPress,
ref: ref => {
this.messageEditArea = ref;
}
}, void 0, false), !this.props.noInput && !this.state.audioRec ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("a", {
href: "#",
onClick: this.toggleEmojiPanel,
title: "表情",
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("i", {
className: "material-icons secondary",
children: this.state.emojiOpen ? 'keyboard' : 'insert_emoticon'
}, void 0, false)
}, void 0, false) : null, this.props.onAttachFile && !this.state.audioRec ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("a", {
href: "#",
onClick: this.toggleAttachPanel,
title: formatMessage(messages.icon_title_attach_file),
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("i", {
className: "material-icons secondary",
children: this.state.attachOpen ? 'keyboard' : 'add_circle_outline'
}, void 0, false)
}, void 0, false) : null, this.state.message || !audioEnabled ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("a", {
href: "#",
onClick: this.handleSend,
title: formatMessage(messages.icon_title_send),
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("i", {
className: "material-icons",
children: sendIcon
}, void 0, false)
}, void 0, false) : !this.state.audioRec ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("a", {
href: "#",
onMouseDown: this.startHoldRecording,
onTouchStart: this.startHoldRecording,
onClick: e => e.preventDefault(),
title: formatMessage(messages.icon_title_record_voice),
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("i", {
className: "material-icons",
children: "mic"
}, void 0, false)
}, void 0, false) : null, (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("input", {
type: "file",
ref: ref => {
this.attachFile = ref;
},
onChange: this.handleAttachFile,
style: {
display: 'none'
}
}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("input", {
type: "file",
ref: ref => {
this.attachImage = ref;
},
accept: "image/*, video/*",
onChange: this.handleAttachImage,
style: {
display: 'none'
}
}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("input", {
type: "file",
ref: ref => {
this.attachCamera = ref;
},
accept: "image/*",
capture: "environment",
onChange: this.handleAttachImage,
style: {
display: 'none'
}
}, void 0, false)]
}, void 0, true) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", {
id: "writing-disabled",
children: prompt
}, void 0, false)
}, void 0, false), this.state.emojiOpen ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", {
id: "emoji-panel",
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", {
id: "emoji-panel-tabs",
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("a", {
href: "#",
className: this.state.emojiTab === 'emoji' ? 'active' : '',
onClick: e => {
e.preventDefault();
this.setState({
emojiTab: 'emoji'
});
},
children: "😊"
}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("a", {
href: "#",
className: this.state.emojiTab === 'recent' ? 'active' : '',
onClick: e => {
e.preventDefault();
this.setState({
emojiTab: 'recent'
});
},
children: "♡"
}, void 0, false)]
}, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", {
id: "emoji-panel-grid",
children: (this.state.emojiTab === 'emoji' ? EMOJI_LIST : this.state.recentEmoji).length === 0 ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", {
className: "emoji-panel-empty",
children: "还没有常用表情"
}, void 0, false) : (this.state.emojiTab === 'emoji' ? EMOJI_LIST : this.state.recentEmoji).map((emoji, i) => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("a", {
href: "#",
onClick: e => {
e.preventDefault();
this.insertEmoji(emoji);
},
children: emoji
}, emoji + i, false))
}, void 0, false)]
}, void 0, true) : null, this.state.attachOpen ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", {
id: "attach-panel",
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("a", {
href: "#",
onClick: e => {
e.preventDefault();
this.setState({
attachOpen: false
});
this.attachImage.click();
},
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("i", {
className: "material-icons",
children: "photo"
}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("span", {
children: "照片"
}, void 0, false)]
}, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("a", {
href: "#",
onClick: e => {
e.preventDefault();
this.setState({
attachOpen: false
});
this.attachCamera.click();
},
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("i", {
className: "material-icons",
children: "photo_camera"
}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("span", {
children: "拍摄"
}, void 0, false)]
}, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("a", {
href: "#",
className: this.props.canStartCall ? '' : 'disabled',
onClick: e => {
e.preventDefault();
this.setState({
attachOpen: false
});
if (this.props.canStartCall && this.props.onStartAudioCall) this.props.onStartAudioCall();
},
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("i", {
className: "material-icons",
children: "call"
}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("span", {
children: "语音通话"
}, void 0, false)]
}, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("a", {
href: "#",
onClick: this.openCardPicker,
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("i", {
className: "material-icons",
children: "badge"
}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("span", {
children: "名片"
}, void 0, false)]
}, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("a", {
href: "#",
onClick: e => {
e.preventDefault();
this.setState({
attachOpen: false
});
this.attachFile.click();
},
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("i", {
className: "material-icons",
children: "attach_file"
}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("span", {
children: "文件"
}, void 0, false)]
}, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("a", {
href: "#",
onClick: this.openFavPicker,
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("i", {
className: "material-icons",
children: "star_border"
}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("span", {
children: "收藏"
}, void 0, false)]
}, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("a", {
href: "#",
className: this.props.canStartCall ? '' : 'disabled',
onClick: e => {
e.preventDefault();
this.setState({
attachOpen: false
});
if (this.props.canStartCall && this.props.onStartVideoCall) this.props.onStartVideoCall();
},
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("i", {
className: "material-icons",
children: "videocam"
}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("span", {
children: "视频通话"
}, void 0, false)]
}, void 0, true)]
}, void 0, true) : null, this.state.cardPicker ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", {
className: "send-message-picker-backdrop",
onClick: () => this.setState({
cardPicker: null
}),
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("section", {
onClick: e => e.stopPropagation(),
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("header", {
children: ["选择联系人", (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("a", {
href: "#",
onClick: e => {
e.preventDefault();
this.setState({
cardPicker: null
});
},
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("i", {
className: "material-icons",
children: "close"
}, void 0, false)
}, void 0, false)]
}, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", {
className: "send-message-picker-list",
children: this.state.cardPicker.loading ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("p", {
className: "send-message-picker-empty",
children: "加载中…"
}, void 0, false) : this.state.cardPicker.items.length === 0 ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("p", {
className: "send-message-picker-empty",
children: this.state.cardPicker.error ? '加载失败' : '暂无好友'
}, void 0, false) : this.state.cardPicker.items.map(item => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("a", {
href: "#",
onClick: e => {
e.preventDefault();
this.sendCard(item);
},
children: item.display_name || item.user_id
}, item.user_id, false))
}, void 0, false)]
}, void 0, true)
}, void 0, false) : null, this.state.favPicker ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", {
className: "send-message-picker-backdrop",
onClick: () => this.setState({
favPicker: null
}),
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("section", {
onClick: e => e.stopPropagation(),
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("header", {
children: ["我的收藏", (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("a", {
href: "#",
onClick: e => {
e.preventDefault();
this.setState({
favPicker: null
});
},
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("i", {
className: "material-icons",
children: "close"
}, void 0, false)
}, void 0, false)]
}, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", {
className: "send-message-picker-list",
children: this.state.favPicker.loading ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("p", {
className: "send-message-picker-empty",
children: "加载中…"
}, void 0, false) : this.state.favPicker.items.length === 0 ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("p", {
className: "send-message-picker-empty",
children: this.state.favPicker.error ? '加载失败' : '暂无收藏'
}, void 0, false) : this.state.favPicker.items.map(item => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("a", {
href: "#",
onClick: e => {
e.preventDefault();
this.sendFavorite(item);
},
children: favoriteSummary(item)
}, item.favorite_id, false))
}, void 0, false)]
}, void 0, true)
}, void 0, false) : null]
}, void 0, true);
}
}
;
/* harmony default export */ __webpack_exports__["default"] = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(SendMessage));
/***/ })
}]);
//# sourceMappingURL=src_views_messages-view_jsx.dev.js.map