diff --git a/.babelrc b/.babelrc
index 9805504795..aca0c79068 100644
--- a/.babelrc
+++ b/.babelrc
@@ -13,7 +13,6 @@
"env": {
"development": {
"plugins": [
- "react-hot-loader/babel",
"@babel/transform-react-display-name",
[
"@babel/plugin-proposal-decorators",
diff --git a/.eslintignore b/.eslintignore
index 1d3ce86a24..f03da7833e 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -21,7 +21,7 @@ karma.conf.js
nacl-fast.js
pdf.worker.js
js/cmsSnapshot.js
-js/chat/bundle.js
+js/chat/bundle*.js
js/transfers/meths/firefox-extension.js
contrib/Electron/main.js
*.sh
@@ -29,3 +29,4 @@ contrib/Electron/main.js
js/chat/emojidata/emojis.json
eslint-local-rules.js
Gruntfile.js
+webpack.config.js
diff --git a/.eslintrc.json b/.eslintrc.json
index 1f6ff91c30..9058fb77c4 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -297,6 +297,7 @@
],
"rules": {
"complexity": [2, 28],
+ "es/no-dynamic-import": "off",
"es/no-optional-chaining": "off",
"local-rules/classes": "off",
"no-negated-condition": "off",
diff --git a/.jscpd.json b/.jscpd.json
index 6417525d58..33e7aacd5c 100644
--- a/.jscpd.json
+++ b/.jscpd.json
@@ -5,7 +5,7 @@
"maxSize": "340kb",
"format": ["javascript", "jsx"],
"reporters": ["console", "badge"],
- "ignore": ["**/node_modules/**", "**/tests/**", "**/vendor/**", "**/**/bundle.js"],
+ "ignore": ["**/node_modules/**", "**/tests/**", "**/vendor/**", "**/**/bundle.js", "**/bundle.*.js"],
"tokensToSkip": ["comment", "empty", "new_line", "ignore"],
"gitignore": true
}
diff --git a/INSTALL.md b/INSTALL.md
index 2fbc1e5180..bbbc2b52aa 100755
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -35,20 +35,23 @@ Development Environment
-----------------------
Since adding React to our toolkit (because of the needs and
-requirements added by the MEGAchat), there is a new file
-(``js/chat/bundle.js``) to be generated to run the code (it is not
-available in the repository).
+requirements added by the MEGAchat), there are new files
+(``js/chat/bundle.js`` and ``js/chat/bundle.*.js`` chunks) to be
+generated to run the code (they are not available in the repository).
-This file is generated by ``webpack``, and depending on the
+These files are generated by ``webpack``, and depending on the
environment you may run the webclient in development in two different
methods.
A simple script watches for changes in React UI related files,
-generates required artifacts automatically (in memory, no files
-generated), serves them (via HTTP), and updates the UI with changes
-live (including relevant code reloads). This process is very fast,
-easy and efficient. You will get this convenience just by running the
-following:
+generates required artifacts automatically (in memory, with
+no files generated) and serves them (via HTTP).
+
+**Note:** Hot Module Replacement (HMR) is intentionally disabled to ensure
+the development environment strictly mirrors the production security model
+(`secureboot`). You will need to refresh the page to see your changes.
+
+You can run the development server with:
```
scripts/dev_server.sh
diff --git a/css/chat-bundle.css b/css/chat-bundle.css
index 2383510095..7a0f6fbed8 100644
--- a/css/chat-bundle.css
+++ b/css/chat-bundle.css
@@ -1600,6 +1600,33 @@ body.theme-dark .lhp-container .lhp-filter-tag {
margin-top: 24px;
}
+.meetings-error {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 100%;
+ height: 100%;
+ border: 1px solid tomato;
+}
+.meetings-error--content {
+ text-align: center;
+ color: var(--text-color-medium);
+}
+.meetings-error--content i {
+ display: block;
+ margin: 32px auto;
+ width: 195px;
+ height: 65px;
+}
+.meetings-error--content a {
+ text-decoration: underline;
+ color: var(--text-color-high);
+}
+.meetings-error--details {
+ margin: 58px 0;
+ font: var(--text-code1);
+}
+
.meetings-call {
position: fixed;
top: 0;
@@ -1609,9 +1636,6 @@ body.theme-dark .lhp-container .lhp-filter-tag {
background: #222;
z-index: 120;
transition: width 200ms ease-in-out;
- /**
- * Sidebar controls
- */
}
.meetings-call.minimized {
display: none;
@@ -1812,7 +1836,6 @@ body.theme-dark .lhp-container .lhp-filter-tag {
grid-template-columns: 1fr 1fr;
grid-gap: 8px;
width: 100%;
- /* TODO: look into `.video-node` re: replicate and unify */
}
@media only screen and (max-height: 760px) {
.meetings-call .stream .stream-participants-block .participants-container .participants-grid {
@@ -1854,6 +1877,9 @@ body.theme-dark .lhp-container .lhp-filter-tag {
.meetings-call .stream .stream-participants-block .participants-container .participants-grid .local-stream-node .node-menu-content button span {
padding: 0 0 0 10px;
}
+.meetings-call .stream .stream-participants-block .participants-container .participants-grid {
+ /* TODO: look into `.video-node` re: replicate and unify */
+}
.meetings-call .stream .stream-participants-block .participants-container .participants-grid .video-node {
width: 100%;
height: 100%;
@@ -2346,6 +2372,11 @@ body.theme-dark .lhp-container .lhp-filter-tag {
padding: 0;
margin-inline-start: 4px;
}
+.meetings-call {
+ /**
+ * Sidebar controls
+ */
+}
.meetings-call .sidebar-controls {
display: flex;
justify-content: flex-end;
@@ -2771,11 +2802,13 @@ body.theme-dark .lhp-container .lhp-filter-tag {
.meetings-call .sidebar-wrapper .sidebar .participants-empty {
margin: 20px;
text-align: center;
- /* TODO: move to sprite sheet */
}
.meetings-call .sidebar-wrapper .sidebar .participants-empty h3 {
margin: 8px 0 0 0;
}
+.meetings-call .sidebar-wrapper .sidebar .participants-empty {
+ /* TODO: move to sprite sheet */
+}
.meetings-call .sidebar-wrapper .sidebar .participants-empty span.empty-check-icon {
display: block;
width: 84px;
@@ -3895,9 +3928,6 @@ body.theme-dark .start-meeting-preview .preview-meeting {
height: 100%;
background: var(--surface-grey-1);
z-index: 141;
- /* --- */
- /* TODO: unify w/ `Join` */
- /* --- */
}
.waiting-room--await, .waiting-room--redirect {
justify-content: center;
@@ -3909,6 +3939,10 @@ body.theme-dark .start-meeting-preview .preview-meeting {
.waiting-room--chatlink-landing .waiting-room-head {
margin: 80px 0 0;
}
+.waiting-room {
+ /* --- */
+ /* TODO: unify w/ `Join` */
+}
.waiting-room-head {
/* [...] */
}
@@ -3932,6 +3966,9 @@ body.theme-dark .start-meeting-preview .preview-meeting {
margin-bottom: 18px;
}
}
+.waiting-room {
+ /* --- */
+}
.waiting-room .card {
/* [...] */
}
@@ -4576,8 +4613,6 @@ body.theme-dark .meetings-recurring-navigation .mega-button.recurring-nav-button
}
.meetings-recurring-content {
/* [...] */
- /* --- */
- /* --- */
}
.meetings-recurring-content .mega-button.recurring-toggle-button {
width: 36px;
@@ -4592,6 +4627,9 @@ body.theme-dark .meetings-recurring-navigation .mega-button.recurring-nav-button
body.theme-dark .meetings-recurring-content .mega-button.recurring-toggle-button.active {
color: black;
}
+.meetings-recurring-content {
+ /* --- */
+}
.meetings-recurring-content .recurring-field-row {
display: flex;
align-items: center;
@@ -4645,6 +4683,9 @@ body.theme-dark .meetings-recurring-content .mega-button.recurring-toggle-button
.meetings-recurring-content .recurring-field-row .recurring-radio-buttons .meetings-datepicker .datepicker-input {
margin-top: -8px;
}
+.meetings-recurring-content {
+ /* --- */
+}
.meetings-recurring-content .meetings-recurring-daily {
/* [...] */
}
diff --git a/css/chat-bundle.scss b/css/chat-bundle.scss
index dd4efb9aed..e8512517c5 100644
--- a/css/chat-bundle.scss
+++ b/css/chat-bundle.scss
@@ -8,6 +8,7 @@
@use 'meetings/_leftPanel.scss';
@use 'meetings/_inviteParticipantsPanel.scss';
@use 'meetings/_chatOverlay.scss';
+@use 'meetings/_errorBoundary.scss';
// The main `Meetings` in-call container
@use 'meetings/_call.scss';
diff --git a/css/meetings/_errorBoundary.scss b/css/meetings/_errorBoundary.scss
new file mode 100644
index 0000000000..d42aaa694f
--- /dev/null
+++ b/css/meetings/_errorBoundary.scss
@@ -0,0 +1,30 @@
+.meetings-error {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 100%;
+ height: 100%;
+ border: 1px solid tomato;
+
+ &--content {
+ text-align: center;
+ color: var(--text-color-medium);
+
+ i {
+ display: block;
+ margin: 32px auto;
+ width: 195px;
+ height: 65px;
+ }
+
+ a {
+ text-decoration: underline;
+ color: var(--text-color-high);
+ }
+ }
+
+ &--details {
+ margin: 58px 0;
+ font: var(--text-code1);
+ }
+}
diff --git a/js/chat/README.md b/js/chat/README.md
index 8bd1f44dd5..7b2f4e1a63 100644
--- a/js/chat/README.md
+++ b/js/chat/README.md
@@ -1,10 +1,16 @@
### Generated files used by the MEGA WebClient chat application.
-
---
-bundle.js: The libraries and custom JavaScript/JSX files (specified in webpack.config.js) necessary for MEGA chat.
+**bundle.js** / **bundle.*.js**: The libraries and custom JavaScript/JSX files necessary for MEGAchat.
+
+The architecture uses **Lazy Loading** (via React Suspense) to split the application into:
+1. `bundle.js`: The lightweight entry point.
+2. `bundle.*.js`: Lazy-loaded chunks (e.g., `bundle.call.js`, `bundle.contacts-panel.js`) loaded on-demand.
+
+Lazy chunk loading is intercepted by `megaChunkLoader` to route requests through `secureboot`'s `M.require()`; this
+ensures all chunks undergo strict XHR + SHA-256 hash verification before execution.
-> NB: This unobfuscated, unminified file is created with Webpack using:
+> NB: These unobfuscated, unminified files are created with Webpack using:
>
> ```bash
> npm update && npm install --production && ./scripts/build.sh
diff --git a/js/chat/bundle.call.js b/js/chat/bundle.call.js
new file mode 100644
index 0000000000..24ab8adc53
--- /dev/null
+++ b/js/chat/bundle.call.js
@@ -0,0 +1,7020 @@
+/** @file automatically generated, do not edit it. */
+"use strict";
+(self.webpackChunk_meganz_webclient = self.webpackChunk_meganz_webclient || []).push([[987],{
+
+ 8402
+(_, EXP_, REQ_) {
+
+// ESM COMPAT FLAG
+REQ_.r(EXP_);
+
+// EXPORTS
+REQ_.d(EXP_, {
+ "default": () => Call
+});
+
+// EXTERNAL MODULE: ./node_modules/@babel/runtime/helpers/esm/extends.js
+const esm_extends = REQ_(8168);
+// EXTERNAL MODULE: external "React"
+const external_React_ = REQ_(1594);
+const REaCt = REQ_.n(external_React_);
+// EXTERNAL MODULE: ./js/chat/mixins.js
+const mixins = REQ_(8264);
+// EXTERNAL MODULE: ./js/chat/chatGlobalEventManager.jsx
+const chatGlobalEventManager = REQ_(8676);
+// EXTERNAL MODULE: ./js/chat/ui/meetings/utils.jsx
+const utils = REQ_(3901);
+// EXTERNAL MODULE: ./js/chat/ui/contacts.jsx
+const ui_contacts = REQ_(8022);
+// EXTERNAL MODULE: ./js/ui/utils.jsx
+const ui_utils = REQ_(6411);
+;// ./js/chat/ui/meetings/videoNode.jsx
+
+
+
+
+
+class VideoNode extends mixins.w9 {
+ constructor(props, source) {
+ super(props);
+ this.domRef = REaCt().createRef();
+ this.contRef = REaCt().createRef();
+ this.audioLevelRef = REaCt().createRef();
+ this.statsHudRef = REaCt().createRef();
+ this.raisedHandListener = undefined;
+ this.state = {
+ raisedHandPeers: []
+ };
+ this.source = source;
+ this.state.raisedHandPeers = this.props.raisedHandPeers || [];
+ }
+ componentDidMount() {
+ let _this$props$didMount, _this$props, _this$domRef;
+ super.componentDidMount();
+ this.source.registerConsumer(this);
+ (_this$props$didMount = (_this$props = this.props).didMount) == null || _this$props$didMount.call(_this$props, (_this$domRef = this.domRef) == null ? void 0 : _this$domRef.current);
+ this.requestVideo(true);
+ this.raisedHandListener = mBroadcaster.addListener('meetings:raisedHand', raisedHandPeers => this.setState({
+ raisedHandPeers
+ }, () => this.safeForceUpdate()));
+ }
+ onVisibilityChange(isVisible) {
+ this.requestVideo(isVisible);
+ }
+ componentDidUpdate() {
+ super.componentDidUpdate();
+ if (this.props.didUpdate) {
+ let _this$domRef2;
+ this.props.didUpdate((_this$domRef2 = this.domRef) == null ? void 0 : _this$domRef2.current);
+ }
+ this.requestVideo();
+ }
+ onAvChange() {
+ this.safeForceUpdate();
+ }
+ displayVideoElement(video, container) {
+ this.attachVideoElemHandlers(video);
+ this.video = video;
+ container.replaceChildren(video);
+ }
+ attachVideoElemHandlers(video) {
+ if (video._snSetup) {
+ return;
+ }
+ video.autoplay = true;
+ video.controls = false;
+ video.muted = true;
+ video.ondblclick = e => {
+ const {
+ onDoubleClick,
+ toggleFullScreen
+ } = this.props;
+ onDoubleClick == null || onDoubleClick(this.source, e);
+ if (toggleFullScreen && !document.fullscreenElement && this.domRef.current) {
+ if (typeof toggleFullScreen === 'function') {
+ toggleFullScreen(this);
+ }
+ this.domRef.current.requestFullscreen({
+ navigationUI: 'hide'
+ });
+ }
+ };
+ video.onloadeddata = ev => {
+ if (this.props.onLoadedData) {
+ this.props.onLoadedData(ev);
+ }
+ };
+ video._snSetup = true;
+ }
+ componentWillUnmount() {
+ super.componentWillUnmount();
+ delete this.video;
+ this.detachVideoElemHandlers();
+ this.source.deregisterConsumer(this);
+ mBroadcaster.removeListener(this.raisedHandListener);
+ if (this.props.willUnmount) {
+ this.props.willUnmount();
+ }
+ }
+ detachVideoElemHandlers() {
+ let _this$contRef$current;
+ const video = (_this$contRef$current = this.contRef.current) == null ? void 0 : _this$contRef$current.firstChild;
+ if (!video || !video._snSetup) {
+ return;
+ }
+ video.onloadeddata = null;
+ video.ondblclick = null;
+ delete video._snSetup;
+ }
+ isVideoCropped() {
+ let _this$video;
+ return (_this$video = this.video) == null ? void 0 : _this$video.classList.contains("video-crop");
+ }
+ cropVideo() {
+ let _this$video2;
+ (_this$video2 = this.video) == null || _this$video2.classList.add("video-crop");
+ }
+ uncropVideo() {
+ let _this$video3;
+ (_this$video3 = this.video) == null || _this$video3.classList.remove("video-crop");
+ }
+ displayStats(stats) {
+ const elem = this.statsHudRef.current;
+ if (!elem) {
+ return;
+ }
+ elem.textContent = stats ? `${stats} (${this.ownVideo ? "cloned" : "ref"})` : "";
+ }
+ renderVideoDebugMode() {
+ if (this.source.isFake) {
+ return null;
+ }
+ let className = "video-rtc-stats";
+ let title;
+ if (this.isLocal) {
+ if (window.sfuClient) {
+ title = new URL(window.sfuClient.url).host;
+ }
+ if (this.props.isSelfOverlay) {
+ className += " video-rtc-stats-ralign";
+ }
+ }
+ if (!title) {
+ title = "";
+ }
+ return JSX_("div", {
+ ref: this.statsHudRef,
+ className,
+ title
+ });
+ }
+ renderContent() {
+ const {
+ source,
+ contRef
+ } = this;
+ if (this.props.isPresenterNode || source.av & Av.Camera) {
+ return JSX_("div", {
+ ref: contRef,
+ className: "video-node-holder video-node-loading"
+ });
+ }
+ delete this._lastResizeHeight;
+ return JSX_(ui_contacts.eu, {
+ contact: M.u[source.userHandle]
+ });
+ }
+ getStatusIcon(icon, label) {
+ return JSX_("span", {
+ className: "simpletip",
+ "data-simpletip-class": "theme-dark-forced",
+ "data-simpletipposition": "top",
+ "data-simpletipoffset": "5",
+ "data-simpletip": label
+ }, JSX_("i", {
+ className: icon
+ }));
+ }
+ renderStatus() {
+ const {
+ chatRoom,
+ isPresenterNode,
+ minimized
+ } = this.props;
+ const {
+ raisedHandPeers
+ } = this.state;
+ const {
+ source
+ } = this;
+ const {
+ sfuClient
+ } = chatRoom.call;
+ const {
+ userHandle,
+ isOnHold
+ } = source;
+ const $$CONTAINER = ({
+ children
+ }) => JSX_("div", {
+ className: "video-node-status theme-dark-forced"
+ }, children);
+ const name = JSX_("div", {
+ className: "video-status-name"
+ }, isPresenterNode ? JSX_(ui_utils.zT, null, l.presenter_nail.replace('%s', M.getNameByHandle(userHandle))) : JSX_(ui_contacts.uA, {
+ contact: M.u[userHandle],
+ emoji: true
+ }));
+ if (isOnHold) {
+ return JSX_($$CONTAINER, null, name, this.getStatusIcon('sprite-fm-mono icon-pause', l[23542].replace('%s', M.getNameByHandle(userHandle) || megaChat.plugins.userHelper.SIMPLETIP_USER_LOADER)));
+ }
+ return JSX_(REaCt().Fragment, null, !minimized && JSX_("div", {
+ className: "stream-signifiers"
+ }, raisedHandPeers && raisedHandPeers.length && raisedHandPeers.includes(userHandle) ? this.getStatusIcon('sprite-fm-uni stream-signifier-icon icon-raise-hand') : null), JSX_($$CONTAINER, null, name, JSX_(AudioLevelIndicator, {
+ source
+ }), sfuClient.haveBadNetwork ? this.getStatusIcon('sprite-fm-mono icon-call-offline', l.poor_connection) : null));
+ }
+ render() {
+ const {
+ mode,
+ chatRoom,
+ simpletip,
+ className,
+ children,
+ onClick
+ } = this.props;
+ const {
+ domRef,
+ source,
+ isLocal,
+ isLocalScreen
+ } = this;
+ if (!chatRoom.call) {
+ return null;
+ }
+ const {
+ call
+ } = chatRoom;
+ const isActiveSpeaker = !source.audioMuted && call.speakerCid === source.clientId;
+ return JSX_("div", {
+ ref: domRef,
+ className: `
+ video-node
+ ${onClick ? 'clickable' : ''}
+ ${className || ''}
+ ${isLocal && !isLocalScreen ? ' local-stream-mirrored' : ''}
+ ${simpletip ? 'simpletip' : ''}
+ ${isActiveSpeaker && mode === utils.g.THUMBNAIL ? 'active-speaker' : ''}
+ `,
+ "data-simpletip": simpletip == null ? void 0 : simpletip.label,
+ "data-simpletipposition": simpletip == null ? void 0 : simpletip.position,
+ "data-simpletipoffset": simpletip == null ? void 0 : simpletip.offset,
+ "data-simpletip-class": simpletip == null ? void 0 : simpletip.className,
+ onClick: evt => onClick == null ? void 0 : onClick(source, evt)
+ }, source && JSX_(REaCt().Fragment, null, children || null, JSX_("div", {
+ className: "video-node-content"
+ }, CallManager2.Call.VIDEO_DEBUG_MODE ? this.renderVideoDebugMode() : null, this.renderContent(), this.renderStatus())));
+ }
+}
+class DynVideo extends VideoNode {
+ onAvChange() {
+ this._lastResizeHeight = null;
+ super.onAvChange();
+ }
+ dynRequestVideo() {
+ const {
+ source,
+ domRef
+ } = this;
+ if (source.isFake || source.isDestroyed) {
+ return;
+ }
+ if (source.isStreaming() && this.isMounted()) {
+ const node = domRef == null ? void 0 : domRef.current;
+ this.dynRequestVideoBySize(node.offsetHeight);
+ } else {
+ this.dynRequestVideoBySize(0);
+ this.displayStats(null);
+ }
+ }
+ dynRequestVideoQuality(quality) {
+ this.requestedQ = quality && CallManager2.FORCE_LOWQ ? 1 : quality;
+ if (!this.source.dynUpdateVideoQuality()) {
+ this.dynUpdateVideoElem();
+ }
+ }
+ dynRequestVideoBySize(h) {
+ if (h === 0) {
+ this._lastResizeHeight = 0;
+ this.dynRequestVideoQuality(CallManager2.VIDEO_QUALITY.NO_VIDEO);
+ return;
+ }
+ if (this.contRef.current) {
+ if (this._lastResizeHeight === h) {
+ return;
+ }
+ this._lastResizeHeight = h;
+ } else {
+ this._lastResizeHeight = null;
+ }
+ let newQ;
+ if (h > 360) {
+ newQ = CallManager2.VIDEO_QUALITY.HIGH;
+ } else if (h > 180) {
+ newQ = CallManager2.VIDEO_QUALITY.MEDIUM;
+ } else if (h > 90 || this.noThumb) {
+ newQ = CallManager2.VIDEO_QUALITY.LOW;
+ } else {
+ newQ = CallManager2.VIDEO_QUALITY.THUMB;
+ }
+ this.dynRequestVideoQuality(newQ);
+ }
+ dynUpdateVideoElem() {
+ let _this$source$hiResPla;
+ const vidCont = this.contRef.current;
+ if (!this.isMounted() || !vidCont) {
+ return;
+ }
+ const player = this.noThumb ? (_this$source$hiResPla = this.source.hiResPlayer) == null || (_this$source$hiResPla = _this$source$hiResPla.gui) == null ? void 0 : _this$source$hiResPla.video : this.source.player;
+ if (!player) {
+ vidCont.replaceChildren();
+ return;
+ }
+ this.dynSetVideoSource(player, vidCont);
+ }
+}
+class DynVideoDirect extends DynVideo {
+ constructor(props, source) {
+ super(props, source);
+ this.isDirect = true;
+ this.requestVideo = this.dynRequestVideo;
+ }
+ dynSetVideoSource(srcPlayer, vidCont) {
+ if (vidCont.firstChild !== srcPlayer) {
+ this.displayVideoElement(srcPlayer, vidCont);
+ }
+ if (srcPlayer.paused) {
+ srcPlayer.play().catch(nop);
+ }
+ }
+}
+class PeerVideoHiRes extends DynVideoDirect {
+ constructor(props) {
+ super(props, props.source);
+ }
+}
+class DynVideoCloned extends DynVideo {
+ constructor(props, source) {
+ super(props, source);
+ this.ownVideo = CallManager2.createVideoElement();
+ }
+ dynSetVideoSource(srcPlayer, vidCont) {
+ const cloned = this.ownVideo;
+ const currVideo = vidCont.firstChild;
+ if (!currVideo) {
+ this.displayVideoElement(cloned, vidCont);
+ } else {
+ assert(currVideo === cloned);
+ }
+ if (cloned.paused || cloned.srcObject !== srcPlayer.srcObject) {
+ cloned.srcObject = srcPlayer.srcObject;
+ Promise.resolve(cloned.play()).catch(nop);
+ }
+ }
+}
+class PeerVideoThumb extends DynVideoCloned {
+ constructor(props) {
+ super(props, props.source);
+ this.requestVideo = this.dynRequestVideo;
+ }
+}
+class PeerVideoThumbFixed extends VideoNode {
+ constructor(props) {
+ super(props, props.source);
+ assert(props.source.hasScreenAndCam);
+ this.ownVideo = CallManager2.createVideoElement();
+ if (CallManager2.Call.VIDEO_DEBUG_MODE) {
+ this.onRxStats = this._onRxStats;
+ }
+ }
+ addVideo() {
+ assert(this.source.hasScreenAndCam);
+ const vidCont = this.contRef.current;
+ assert(vidCont);
+ if (vidCont.firstChild !== this.ownVideo) {
+ this.displayVideoElement(this.ownVideo, vidCont);
+ }
+ }
+ delVideo() {
+ SfuClient.playerStop(this.ownVideo);
+ const vidCont = this.contRef.current;
+ if (!vidCont) {
+ return;
+ }
+ vidCont.replaceChildren();
+ }
+ requestVideo(forceVisible) {
+ if (!this.isComponentVisible() && !forceVisible) {
+ return;
+ }
+ if (this.player) {
+ this.playVideo();
+ } else {
+ this.addVideo();
+ this.player = this.source.sfuPeer.getThumbVideo(() => {
+ return this;
+ });
+ }
+ }
+ playVideo() {
+ let _this$player$slot;
+ const track = (_this$player$slot = this.player.slot) == null ? void 0 : _this$player$slot.inTrack;
+ if (!track) {
+ return;
+ }
+ SfuClient.playerPlay(this.ownVideo, track, true);
+ }
+ attachToTrack(track) {
+ if (!this.source.hasScreenAndCam) {
+ return;
+ }
+ SfuClient.playerPlay(this.ownVideo, track);
+ }
+ detachFromTrack() {
+ this.delVideo();
+ }
+ onPlayerDestroy() {
+ delete this.player;
+ }
+ componentWillUnmount() {
+ if (this.player) {
+ this.player.destroy();
+ }
+ super.componentWillUnmount();
+ }
+ _onRxStats(track, info, raw) {
+ if (this.player) {
+ this.displayStats(CallManager2.Call.rxStatsToText(track, info, raw));
+ }
+ }
+}
+class PeerVideoHiResCloned extends DynVideoCloned {
+ constructor(props) {
+ super(props, props.source);
+ this.noThumb = true;
+ this.requestVideo = this.dynRequestVideo;
+ }
+}
+class LocalVideoHiResCloned extends VideoNode {
+ constructor(props) {
+ super(props, props.chatRoom.call.getLocalStream());
+ this.isLocal = true;
+ this.ownVideo = CallManager2.createVideoElement();
+ }
+ get isLocalScreen() {
+ return this.source.av & Av.Screen;
+ }
+ requestVideo(forceVisible) {
+ if (d > 1 && forceVisible) {
+ console.debug('ignoring forceVisible');
+ }
+ const vidCont = this.contRef.current;
+ if (!vidCont) {
+ return;
+ }
+ const track = this.source.sfuClient.localScreenTrack();
+ if (!track) {
+ vidCont.replaceChildren();
+ } else {
+ if (vidCont.firstChild !== this.ownVideo) {
+ this.displayVideoElement(this.ownVideo, vidCont);
+ }
+ SfuClient.playerPlay(this.ownVideo, track, true);
+ }
+ }
+}
+class LocalVideoHiRes extends DynVideoDirect {
+ constructor(props) {
+ super(props, props.chatRoom.call.getLocalStream());
+ this.isLocal = true;
+ }
+ get isLocalScreen() {
+ return this.source.av & Av.Screen;
+ }
+}
+class LocalVideoThumb extends VideoNode {
+ constructor(props) {
+ const source = props.chatRoom.call.getLocalStream();
+ super(props, source);
+ this.isLocal = true;
+ this.isLocalScreen = source.av & Av.Screen && !(source.av & Av.Camera);
+ this.sfuClient = props.chatRoom.call.sfuClient;
+ this.ownVideo = CallManager2.createVideoElement();
+ }
+ requestVideo() {
+ const vidCont = this.contRef.current;
+ if (!vidCont) {
+ return;
+ }
+ const currVideo = vidCont.firstChild;
+ const track = this.isLocalScreen ? this.sfuClient.localScreenTrack() : this.sfuClient.localCameraTrack();
+ if (!track) {
+ if (currVideo) {
+ vidCont.replaceChildren();
+ }
+ } else {
+ if (!currVideo) {
+ this.displayVideoElement(this.ownVideo, vidCont);
+ } else {
+ assert(currVideo === this.ownVideo);
+ }
+ SfuClient.playerPlay(this.ownVideo, track, true);
+ }
+ }
+ onAvChange() {
+ const av = this.sfuClient.availAv;
+ this.isLocalScreen = av & Av.Screen && !(av & Av.Camera);
+ super.onAvChange();
+ }
+}
+class AudioLevelIndicator extends REaCt().Component {
+ constructor(props) {
+ super(props);
+ this.source = props.source;
+ this.indicatorRef = REaCt().createRef();
+ this.updateAudioLevel = this.updateAudioLevel.bind(this);
+ }
+ componentDidMount() {
+ this.source.registerVuLevelConsumer(this);
+ }
+ componentWillUnmount() {
+ this.source.unregisterVuLevelConsumer(this);
+ }
+ updateAudioLevel(level) {
+ const levelInd = this.indicatorRef.current;
+ if (!levelInd) {
+ return;
+ }
+ level = Math.round(level * 400);
+ if (level > 90) {
+ level = 90;
+ }
+ levelInd.style.height = `${level + 10}%`;
+ }
+ render() {
+ const {
+ audioMuted
+ } = this.source;
+ return JSX_("span", {
+ className: "simpletip",
+ "data-simpletip-class": "theme-dark-forced",
+ "data-simpletipposition": "top",
+ "data-simpletipoffset": "5",
+ "data-simpletip": audioMuted ? l.muted : ''
+ }, JSX_("i", {
+ className: `
+ sprite-fm-mono
+ ${audioMuted ? 'icon-mic-off-thin-outline inactive' : 'icon-mic-thin-outline speaker-indicator'}
+ `
+ }, audioMuted ? null : JSX_("div", {
+ ref: this.indicatorRef,
+ className: "mic-fill"
+ })));
+ }
+}
+// EXTERNAL MODULE: ./js/chat/ui/meetings/button.jsx
+const meetings_button = REQ_(6740);
+// EXTERNAL MODULE: ./js/chat/ui/inviteParticipantsPanel.jsx
+const inviteParticipantsPanel = REQ_(8956);
+;// ./js/chat/ui/meetings/participantsNotice.jsx
+
+
+
+
+
+
+class ParticipantsNotice extends mixins.w9 {
+ constructor(props) {
+ super(props);
+ this.domRef = REaCt().createRef();
+ this.renderUserAlone = () => JSX_("div", {
+ className: `
+ ${ParticipantsNotice.NAMESPACE}
+ theme-dark-forced
+ user-alone
+ `
+ }, this.props.stayOnEnd ? JSX_("div", {
+ className: `${ParticipantsNotice.NAMESPACE}-heading`
+ }, JSX_("h1", null, this.props.everHadPeers ? l.only_one_here : l.waiting_for_others)) : JSX_("div", {
+ className: `${ParticipantsNotice.NAMESPACE}-content user-alone`
+ }, JSX_("h3", null, l.only_one_here), JSX_("p", {
+ className: "theme-dark-forced"
+ }, JSX_(ui_utils.P9, null, l.empty_call_dlg_text.replace('%s', '2'))), JSX_("div", {
+ className: "notice-footer"
+ }, JSX_(meetings_button.A, {
+ className: "mega-button large stay-on-call",
+ onClick: this.props.onStayConfirm
+ }, JSX_("span", null, l.empty_call_stay_button)), JSX_(meetings_button.A, {
+ className: "mega-button positive large stay-on-call",
+ onClick: this.props.onCallEnd
+ }, JSX_("span", null, l.empty_call_dlg_end)))));
+ this.renderUserWaiting = () => {
+ const {
+ chatRoom,
+ onInviteToggle
+ } = this.props;
+ return JSX_("div", {
+ className: `
+ ${ParticipantsNotice.NAMESPACE}
+ ${chatRoom.isMeeting ? '' : 'user-alone'}
+ theme-dark-forced
+ `
+ }, JSX_("div", {
+ className: `${ParticipantsNotice.NAMESPACE}-heading`
+ }, chatRoom.type === 'private' ? JSX_("h1", null, JSX_(ui_utils.zT, null, l.waiting_for_peer.replace('%NAME', chatRoom.getRoomTitle()))) : JSX_("h1", null, l.waiting_for_others)), chatRoom.isMeeting && chatRoom.publicLink && JSX_("div", {
+ className: `${ParticipantsNotice.NAMESPACE}-content-invite`
+ }, JSX_(inviteParticipantsPanel.Q, {
+ chatRoom,
+ disableLinkToggle: true,
+ onAddParticipants: () => {
+ this.setState({
+ inviteDialog: false
+ }, () => onInviteToggle());
+ }
+ })));
+ };
+ this.av = this.props.call.sfuClient.availAv;
+ }
+ specShouldComponentUpdate(newProps) {
+ const {
+ stayOnEnd,
+ hasLeft,
+ isOnHold,
+ call
+ } = this.props;
+ const currAv = this.av;
+ this.av = call.sfuClient.availAv;
+ return newProps.stayOnEnd !== stayOnEnd || newProps.hasLeft !== hasLeft || newProps.isOnHold !== isOnHold || this.av !== currAv;
+ }
+ render() {
+ const {
+ call,
+ hasLeft,
+ streamContainer,
+ chatRoom
+ } = this.props;
+ if (call.isDestroyed) {
+ return null;
+ }
+ return JSX_("div", {
+ ref: this.domRef,
+ className: `${ParticipantsNotice.NAMESPACE}-container`
+ }, call.isSharingScreen() ? null : JSX_(LocalVideoHiRes, {
+ className: "local-stream-mirrored",
+ chatRoom,
+ source: call.getLocalStream()
+ }), streamContainer(hasLeft ? this.renderUserAlone() : this.renderUserWaiting()));
+ }
+}
+ParticipantsNotice.NAMESPACE = 'participants-notice';
+// EXTERNAL MODULE: ./js/chat/ui/chatToaster.jsx
+const chatToaster = REQ_(8491);
+;// ./js/chat/ui/meetings/participantsBlock.jsx
+
+
+
+
+
+
+const MAX_STREAMS_PER_PAGE = 10;
+const SIMPLE_TIP = {
+ position: 'top',
+ offset: 5,
+ className: 'theme-dark-forced'
+};
+class ParticipantsBlock extends mixins.w9 {
+ constructor(...args) {
+ super(...args);
+ this.domRef = REaCt().createRef();
+ this.nodeMenuRef = REaCt().createRef();
+ this.dupNodeMenuRef = REaCt().createRef();
+ this.state = {
+ page: 0
+ };
+ this.movePage = direction => this.setState(state => ({
+ page: direction === utils.Bq.NEXT ? state.page + 1 : state.page - 1
+ }));
+ this.renderLocalNode = isPresenterNode => {
+ const {
+ call,
+ peers,
+ mode,
+ raisedHandPeers,
+ chatRoom,
+ forcedLocal,
+ presenterThumbSelected,
+ onSeparate,
+ onSpeakerChange,
+ onModeChange
+ } = this.props;
+ const localStream = call.getLocalStream();
+ if (localStream) {
+ const IS_SPEAKER_VIEW = mode === utils.g.MAIN && forcedLocal;
+ const VideoClass = isPresenterNode ? LocalVideoHiResCloned : LocalVideoThumb;
+ let isActive = false;
+ if (isPresenterNode) {
+ isActive = forcedLocal && !presenterThumbSelected;
+ } else if (call.pinnedCid === 0 || forcedLocal) {
+ if (presenterThumbSelected) {
+ isActive = !isPresenterNode;
+ } else if (localStream.hasScreen) {
+ isActive = isPresenterNode;
+ } else {
+ isActive = true;
+ }
+ }
+ return JSX_(VideoClass, {
+ key: `${u_handle}${isPresenterNode ? '_block' : ''}`,
+ className: `
+ local-stream-node
+ ${call.isSharingScreen() ? '' : 'local-stream-mirrored'}
+ ${isActive ? 'active' : ''}
+ ${call.speakerCid === 0 ? 'active-speaker' : ''}
+ `,
+ simpletip: {
+ ...SIMPLE_TIP,
+ label: l[8885]
+ },
+ mode,
+ raisedHandPeers,
+ chatRoom,
+ source: localStream,
+ localAudioMuted: !(call.av & SfuClient.Av.Audio),
+ isPresenterNode,
+ onClick: (source, ev) => {
+ const nodeMenuRef = isPresenterNode ? this.nodeMenuRef && this.nodeMenuRef.current : this.dupNodeMenuRef && this.dupNodeMenuRef.current;
+ if (nodeMenuRef && nodeMenuRef.contains(ev.target)) {
+ ev.preventDefault();
+ ev.stopPropagation();
+ return;
+ }
+ return onSpeakerChange(localStream, !isPresenterNode);
+ }
+ }, (peers == null ? void 0 : peers.length) && JSX_("div", {
+ ref: isPresenterNode ? this.nodeMenuRef : this.dupNodeMenuRef,
+ className: "node-menu theme-dark-forced"
+ }, JSX_("div", {
+ className: "node-menu-toggle"
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-more-horizontal-thin-outline"
+ })), JSX_("div", {
+ className: "node-menu-content"
+ }, JSX_("ul", null, JSX_("li", null, JSX_(meetings_button.A, {
+ icon: `
+ sprite-fm-mono
+ ${IS_SPEAKER_VIEW ? 'grid-9' : 'grid-main'}
+ `,
+ onClick: () => {
+ if (IS_SPEAKER_VIEW) {
+ return onModeChange(utils.g.THUMBNAIL);
+ }
+ return onSpeakerChange(localStream);
+ }
+ }, JSX_("span", null, IS_SPEAKER_VIEW ? l.switch_to_thumb_view : l.display_in_main_view))), JSX_("li", null, JSX_(meetings_button.A, {
+ icon: "sprite-fm-mono grid-separate",
+ onClick: onSeparate
+ }, JSX_("span", null, l.separate_from_grid_button)))))));
+ }
+ return null;
+ };
+ this.onScroll = (chunks, evt) => {
+ const {
+ page
+ } = this.state;
+ if (evt.deltaY < 0) {
+ if (page > 0) {
+ this.movePage(utils.Bq.PREV);
+ }
+ } else if (evt.deltaY > 0) {
+ if (page < Object.values(chunks).length - 1) {
+ this.movePage(utils.Bq.NEXT);
+ }
+ }
+ };
+ }
+ shouldComponentUpdate() {
+ const {
+ peers
+ } = this.props;
+ return peers && peers.length;
+ }
+ render() {
+ const {
+ call,
+ mode,
+ peers,
+ floatDetached,
+ chatRoom,
+ raisedHandPeers,
+ presenterThumbSelected,
+ onSpeakerChange
+ } = this.props;
+ if (peers && peers.length) {
+ const {
+ screen,
+ video,
+ rest
+ } = filterAndSplitSources(peers, call);
+ const sources = [...screen, ...video, ...rest];
+ const $$PEER = (peer, i) => {
+ const {
+ clientId,
+ userHandle,
+ hasScreenAndCam,
+ hasScreen,
+ isLocal
+ } = peer;
+ if (screen.length && (screen[0].clientId === clientId || screen[0].isLocal && isLocal)) {
+ screen.shift();
+ }
+ if (!(peer instanceof CallManager2.Peer)) {
+ const isPresenterNode = screen.length && screen[0].isLocal;
+ if (floatDetached && !isPresenterNode) {
+ return;
+ }
+ return this.renderLocalNode(!floatDetached && isPresenterNode);
+ }
+ const presenterCid = screen.length && screen[0].clientId === clientId;
+ let PeerClass;
+ if (hasScreenAndCam) {
+ PeerClass = presenterCid ? PeerVideoHiResCloned : PeerVideoThumbFixed;
+ } else {
+ PeerClass = PeerVideoThumb;
+ }
+ assert(!presenterCid || hasScreen);
+ const isActiveSpeaker = !peer.audioMuted && call.speakerCid === peer.clientId;
+ let isActive = false;
+ if (call.pinnedCid === clientId) {
+ if (presenterThumbSelected) {
+ isActive = !presenterCid;
+ } else if (hasScreen) {
+ isActive = presenterCid;
+ } else {
+ isActive = true;
+ }
+ }
+ const name = M.getNameByHandle(userHandle);
+ let label = name;
+ if (presenterCid) {
+ label = name ? l.presenter_nail.replace('%s', name) : megaChat.plugins.userHelper.SIMPLETIP_USER_LOADER;
+ } else {
+ label = name || megaChat.plugins.userHelper.SIMPLETIP_USER_LOADER;
+ }
+ return JSX_(PeerClass, {
+ key: `${userHandle}-${i}-${clientId}`,
+ className: `
+ video-crop
+ ${isActive ? 'active' : ''}
+ ${isActiveSpeaker ? 'active-speaker' : ''}
+ `,
+ simpletip: {
+ ...SIMPLE_TIP,
+ label
+ },
+ raisedHandPeers,
+ mode,
+ chatRoom,
+ source: peer,
+ isPresenterNode: !!presenterCid,
+ onSpeakerChange: node => onSpeakerChange(node, !presenterCid),
+ onClick: node => onSpeakerChange(node, !presenterCid)
+ });
+ };
+ if (sources.length <= (floatDetached ? MAX_STREAMS_PER_PAGE : 9)) {
+ return JSX_("div", {
+ ref: this.domRef,
+ className: "stream-participants-block theme-dark-forced"
+ }, JSX_("div", {
+ className: "participants-container"
+ }, JSX_("div", {
+ className: `
+ participants-grid
+ ${floatDetached && sources.length === 1 || sources.length === 0 ? 'single-column' : ''}
+ `
+ }, sources.map((p, i) => $$PEER(p, i)))));
+ }
+ const {
+ page
+ } = this.state;
+ const chunks = chunkNodes(sources, MAX_STREAMS_PER_PAGE);
+ return JSX_("div", {
+ ref: this.domRef,
+ className: "carousel"
+ }, JSX_("div", {
+ className: "carousel-container",
+ onWheel: evt => this.onScroll(chunks, evt)
+ }, JSX_("div", {
+ className: "stream-participants-block theme-dark-forced"
+ }, JSX_("div", {
+ className: "participants-container"
+ }, Object.values(chunks).map((chunk, i) => {
+ const {
+ id,
+ nodes
+ } = chunk;
+ return JSX_("div", {
+ key: id,
+ className: `
+ carousel-page
+ ${i === page ? 'active' : ''}
+ `
+ }, page === 0 ? null : JSX_("button", {
+ className: "carousel-control carousel-button-prev theme-dark-forced",
+ onClick: () => this.movePage(utils.Bq.PREV)
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-arrow-up"
+ })), JSX_("div", {
+ className: `
+ participants-grid
+ ${nodes.length === 1 ? 'single-column' : ''}
+ `
+ }, nodes.map((peer, j) => $$PEER(peer, j + i * MAX_STREAMS_PER_PAGE))), page >= Object.values(chunks).length - 1 ? null : JSX_("button", {
+ className: "carousel-control carousel-button-next theme-dark-forced",
+ onClick: () => this.movePage(utils.Bq.NEXT)
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-arrow-down"
+ })));
+ })))));
+ }
+ return null;
+ }
+}
+;// ./js/chat/ui/meetings/videoNodeMenu.jsx
+
+
+
+
+
+const Privilege = ({
+ chatRoom,
+ stream
+}) => {
+ const {
+ call,
+ userHandle
+ } = stream || {};
+ if (call && call.isPublic) {
+ const {
+ OPERATOR,
+ FULL
+ } = ChatRoom.MembersSet.PRIVILEGE_STATE;
+ const currentUserModerator = chatRoom.members[u_handle] === OPERATOR;
+ const targetUserModerator = chatRoom.members[userHandle] === OPERATOR;
+ return currentUserModerator && JSX_(meetings_button.A, {
+ targetUserModerator,
+ icon: "sprite-fm-mono icon-admin-outline",
+ onClick: () => {
+ ['alterUserPrivilege', 'onCallPrivilegeChange'].map(event => chatRoom.trigger(event, [userHandle, targetUserModerator ? FULL : OPERATOR]));
+ }
+ }, JSX_("span", null, targetUserModerator ? l.remove_moderator : l.make_moderator));
+ }
+ return null;
+};
+const Contact = ({
+ stream,
+ ephemeralAccounts,
+ onCallMinimize
+}) => {
+ const {
+ userHandle
+ } = stream;
+ const IS_GUEST = (0,utils.P)() || ephemeralAccounts && ephemeralAccounts.includes(userHandle);
+ const HAS_RELATIONSHIP = M.u[userHandle].c === 1;
+ if (HAS_RELATIONSHIP) {
+ return JSX_(meetings_button.A, {
+ icon: "sprite-fm-mono icon-chat",
+ onClick: () => {
+ onCallMinimize();
+ loadSubPage(`fm/chat/p/${userHandle}`);
+ }
+ }, JSX_("span", null, l[7997]));
+ }
+ return JSX_(meetings_button.A, {
+ className: IS_GUEST ? 'disabled' : '',
+ icon: "sprite-fm-mono icon-add",
+ onClick: () => {
+ return IS_GUEST ? false : M.syncContactEmail(userHandle, true).then(email => {
+ const OPC = Object.values(M.opc);
+ if (OPC && OPC.length && OPC.some(opc => opc.m === email)) {
+ return msgDialog('warningb', '', l[17545]);
+ }
+ msgDialog('info', l[150], l[5898]);
+ M.inviteContact(M.u[u_handle].m, email);
+ }).catch(() => mBroadcaster.sendMessage('meetings:ephemeralAdd', userHandle));
+ }
+ }, JSX_("span", null, l[24581]));
+};
+const Pin = ({
+ stream,
+ mode,
+ onSpeakerChange,
+ onModeChange
+}) => {
+ return JSX_(meetings_button.A, {
+ icon: "sprite-fm-mono grid-main",
+ onClick: () => mode === utils.g.THUMBNAIL ? onSpeakerChange == null ? void 0 : onSpeakerChange(stream) : onModeChange == null ? void 0 : onModeChange(utils.g.THUMBNAIL)
+ }, JSX_("span", null, mode === utils.g.THUMBNAIL ? l.display_in_main_view : l.switch_to_thumb_view));
+};
+class VideoNodeMenu extends mixins.w9 {
+ constructor(...args) {
+ super(...args);
+ this.domRef = REaCt().createRef();
+ this.ToggleCrop = ({
+ videoNodeRef
+ }) => {
+ const videoNode = videoNodeRef == null ? void 0 : videoNodeRef.current;
+ if (!videoNode) {
+ return null;
+ }
+ return videoNode.isVideoCropped() ? JSX_(meetings_button.A, {
+ icon: "sprite-fm-mono grid-main",
+ onClick: () => {
+ videoNode.uncropVideo();
+ this.forceUpdate();
+ }
+ }, JSX_("span", null, "Uncrop video")) : JSX_(meetings_button.A, {
+ icon: "sprite-fm-mono grid-main",
+ onClick: () => {
+ videoNode.cropVideo();
+ this.forceUpdate();
+ }
+ }, JSX_("span", null, "Crop video"));
+ };
+ }
+ render() {
+ const {
+ NAMESPACE
+ } = VideoNodeMenu;
+ const {
+ stream,
+ isPresenterNode,
+ mode,
+ onSpeakerChange,
+ onModeChange
+ } = this.props;
+ const {
+ userHandle,
+ clientId
+ } = stream;
+ if (isPresenterNode) {
+ return JSX_("div", {
+ ref: this.domRef,
+ className: `
+ ${NAMESPACE}
+ theme-dark-forced
+ ${mode === utils.g.THUMBNAIL ? '' : 'presenter'}
+ `
+ }, JSX_("div", {
+ className: `${NAMESPACE}-toggle`
+ }, JSX_("i", {
+ className: `sprite-fm-mono call-node-pin icon-pin${mode === utils.g.MAIN ? '-off' : ''}`,
+ onClick: () => mode === utils.g.THUMBNAIL ? onSpeakerChange == null ? void 0 : onSpeakerChange(stream) : onModeChange == null ? void 0 : onModeChange(utils.g.THUMBNAIL)
+ })));
+ }
+ if (userHandle !== u_handle) {
+ const $$CONTROLS = {
+ Contact,
+ Pin,
+ Privilege
+ };
+ return JSX_("div", {
+ ref: this.domRef,
+ className: `
+ ${NAMESPACE}
+ theme-dark-forced
+ `
+ }, JSX_("div", {
+ className: `${NAMESPACE}-toggle`
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-more-horizontal-thin-outline"
+ })), JSX_("div", {
+ className: `${NAMESPACE}-content`
+ }, JSX_("ul", null, Object.values($$CONTROLS).map(($$CONTROL, i) => JSX_("li", {
+ key: `${Object.keys($$CONTROLS)[i]}-${clientId}-${userHandle}`
+ }, JSX_($$CONTROL, this.props))))));
+ }
+ return null;
+ }
+}
+VideoNodeMenu.NAMESPACE = 'node-menu';
+// EXTERNAL MODULE: ./js/ui/modalDialogs.jsx + 1 modules
+const modalDialogs = REQ_(8120);
+;// ./js/chat/ui/meetings/modeSwitch.jsx
+
+
+
+
+class ModeSwitch extends mixins.w9 {
+ constructor(...args) {
+ super(...args);
+ this.domRef = REaCt().createRef();
+ this.state = {
+ expanded: false,
+ settings: false
+ };
+ this.handleMousedown = ({
+ target
+ }) => {
+ if (this.state.expanded || this.state.settings) {
+ let _this$domRef;
+ return (_this$domRef = this.domRef) != null && (_this$domRef = _this$domRef.current) != null && _this$domRef.contains(target) ? null : this.doClose();
+ }
+ };
+ this.handleKeydown = ({
+ keyCode
+ }) => keyCode && keyCode === 27 && this.doClose();
+ this.doClose = () => this.isMounted() && this.setState({
+ expanded: false,
+ settings: false
+ }, () => this.props.setActiveElement(this.state.expanded));
+ this.doToggle = () => this.isMounted() && this.setState(state => ({
+ expanded: !state.expanded
+ }), () => this.props.setActiveElement(this.state.expanded || this.state.settings));
+ this.setStreamsPerPage = streamsPerPage => {
+ if (streamsPerPage) {
+ let _this$props$onStreams, _this$props;
+ (_this$props$onStreams = (_this$props = this.props).onStreamsPerPageChange) == null || _this$props$onStreams.call(_this$props, streamsPerPage);
+ this.doClose();
+ }
+ };
+ this.getModeIcon = mode => {
+ switch (mode) {
+ case utils.g.THUMBNAIL:
+ return 'grid-9';
+ case utils.g.MAIN:
+ return 'grid-main';
+ default:
+ return null;
+ }
+ };
+ this.Toggle = () => {
+ const {
+ mode
+ } = this.props;
+ return JSX_("div", {
+ className: `${ModeSwitch.BASE_CLASS}-toggle`,
+ onClick: this.doToggle
+ }, JSX_(meetings_button.A, null, JSX_("i", {
+ className: `sprite-fm-mono ${this.getModeIcon(mode)}`
+ }), mode === utils.g.THUMBNAIL && JSX_("div", null, l.thumbnail_view), mode === utils.g.MAIN && JSX_("div", null, l.main_view)), JSX_("i", {
+ className: "sprite-fm-mono icon-arrow-down"
+ }));
+ };
+ this.Option = ({
+ label,
+ mode
+ }) => {
+ return JSX_("div", {
+ className: `
+ ${ModeSwitch.BASE_CLASS}-option
+ ${mode === this.props.mode ? 'active' : ''}
+ `,
+ onClick: () => {
+ this.doToggle();
+ this.props.onModeChange(mode);
+ }
+ }, JSX_(meetings_button.A, null, JSX_("i", {
+ className: `sprite-fm-mono ${this.getModeIcon(mode)}`
+ }), JSX_("div", null, label)));
+ };
+ this.Settings = () => {
+ const {
+ streamsPerPage
+ } = this.props;
+ return JSX_("div", {
+ className: `${ModeSwitch.BASE_CLASS}-settings`
+ }, JSX_("div", {
+ className: "settings-wrapper"
+ }, JSX_("strong", null, l.layout_settings_heading), JSX_("span", null, l.layout_settings_info), JSX_("div", {
+ className: "recurring-radio-buttons"
+ }, JSX_("div", {
+ className: "recurring-label-wrap"
+ }, JSX_("div", {
+ className: `
+ uiTheme
+ ${streamsPerPage === utils.gh.MIN ? 'radioOn' : 'radioOff'}
+ `
+ }, JSX_("input", {
+ type: "radio",
+ name: "9",
+ onClick: () => this.setStreamsPerPage(utils.gh.MIN)
+ })), JSX_("div", {
+ className: "radio-txt"
+ }, JSX_("span", {
+ className: "recurring-radio-label",
+ onClick: () => this.setStreamsPerPage(utils.gh.MIN)
+ }, "9"))), JSX_("div", {
+ className: "recurring-label-wrap"
+ }, JSX_("div", {
+ className: `
+ uiTheme
+ ${streamsPerPage === utils.gh.MED ? 'radioOn' : 'radioOff'}
+ `
+ }, JSX_("input", {
+ type: "radio",
+ name: "21",
+ onClick: () => {
+ this.setStreamsPerPage(utils.gh.MED);
+ }
+ })), JSX_("div", {
+ className: "radio-txt"
+ }, JSX_("span", {
+ className: "recurring-radio-label",
+ onClick: () => this.setStreamsPerPage(utils.gh.MED)
+ }, "21"))), JSX_("div", {
+ className: "recurring-label-wrap"
+ }, JSX_("div", {
+ className: `
+ uiTheme
+ ${streamsPerPage === utils.gh.MAX ? 'radioOn' : 'radioOff'}
+ `
+ }, JSX_("input", {
+ type: "radio",
+ name: "49",
+ onClick: () => {
+ this.setStreamsPerPage(utils.gh.MAX);
+ }
+ })), JSX_("div", {
+ className: "radio-txt"
+ }, JSX_("span", {
+ className: "recurring-radio-label",
+ onClick: () => this.setStreamsPerPage(utils.gh.MAX)
+ }, "49")))), JSX_("small", null, l.layout_settings_warning)), JSX_("div", {
+ className: "settings-close"
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-dialog-close",
+ onClick: this.doClose
+ })));
+ };
+ }
+ componentWillUnmount() {
+ super.componentWillUnmount();
+ document.removeEventListener('mousedown', this.handleMousedown);
+ document.removeEventListener('keydown', this.handleKeydown);
+ }
+ componentDidMount() {
+ super.componentDidMount();
+ document.addEventListener('mousedown', this.handleMousedown);
+ document.addEventListener('keydown', this.handleKeydown);
+ }
+ render() {
+ const {
+ Toggle,
+ Option,
+ Settings,
+ domRef,
+ state,
+ doToggle
+ } = this;
+ return JSX_("div", {
+ ref: domRef,
+ className: ModeSwitch.BASE_CLASS
+ }, JSX_(Toggle, null), JSX_("div", {
+ className: `
+ ${ModeSwitch.BASE_CLASS}-menu
+ ${state.expanded ? 'expanded' : ''}
+ `
+ }, JSX_(Option, {
+ label: l.main_view,
+ mode: utils.g.MAIN
+ }), JSX_(Option, {
+ label: l.thumbnail_view,
+ mode: utils.g.THUMBNAIL
+ }), JSX_("div", {
+ className: `${ModeSwitch.BASE_CLASS}-option`,
+ onClick: () => this.setState({
+ settings: true
+ }, doToggle)
+ }, JSX_(meetings_button.A, null, JSX_("i", {
+ className: "sprite-fm-mono icon-settings"
+ }), JSX_("div", null, l.layout_settings_button)))), state.settings && JSX_(Settings, null));
+ }
+}
+ModeSwitch.NAMESPACE = 'modeSwitch';
+ModeSwitch.BASE_CLASS = 'mode';
+;// ./js/chat/ui/meetings/streamHead.jsx
+
+
+
+
+
+
+
+
+
+class StreamHead extends mixins.w9 {
+ constructor(...args) {
+ super(...args);
+ this.delayProcID = null;
+ this.domRef = REaCt().createRef();
+ this.durationRef = REaCt().createRef();
+ this.dialogRef = REaCt().createRef();
+ this.topicRef = REaCt().createRef();
+ this.interval = undefined;
+ this.state = {
+ dialog: false,
+ duration: undefined,
+ banner: false,
+ modeSwitch: false
+ };
+ this.updateDurationDOM = () => {
+ if (this.durationRef) {
+ this.durationRef.current.innerText = this.durationString;
+ }
+ };
+ this.closeTooltips = () => {
+ for (const node of this.domRef.current.querySelectorAll('.simpletip')) {
+ node.dispatchEvent(StreamHead.EVENTS.SIMPLETIP);
+ }
+ };
+ this.toggleFullscreen = () => this.fullscreen ? document.exitFullscreen() : document.documentElement.requestFullscreen();
+ this.toggleBanner = callback => this.setState(state => ({
+ banner: !state.banner
+ }), () => callback && callback());
+ this.handleDialogClose = ({
+ target
+ }) => {
+ if (this.state.dialog) {
+ let _targetDialog$domRef;
+ const {
+ topicRef,
+ dialogRef,
+ delayProcID
+ } = this;
+ const topicElement = topicRef && topicRef.current;
+ const targetDialog = dialogRef && dialogRef.current && dialogRef.current;
+ const dialogElement = (_targetDialog$domRef = targetDialog.domRef) == null ? void 0 : _targetDialog$domRef.current;
+ if (topicElement.contains(target)) {
+ return;
+ }
+ return (target.classList.contains('icon-dialog-close') || !dialogElement.contains(target)) && this.setState({
+ dialog: false
+ }, () => delayProcID && delay.cancel(delayProcID));
+ }
+ };
+ this.getModerators = () => {
+ let _this$props$chatRoom;
+ const members = (_this$props$chatRoom = this.props.chatRoom) == null ? void 0 : _this$props$chatRoom.members;
+ if (members) {
+ const moderators = [];
+ for (const [handle, role] of Object.entries(members)) {
+ if (role === ChatRoom.MembersSet.PRIVILEGE_STATE.OPERATOR) {
+ moderators.push(M.getNameByHandle(handle));
+ }
+ }
+ return mega.utils.trans.listToString(moderators, mega.icu.format(l.meeting_moderators, moderators.length));
+ }
+ };
+ this.Dialog = () => {
+ const link = `${getBaseUrl()}/${this.props.chatRoom.publicLink}`;
+ const mods = this.getModerators();
+ return JSX_(modalDialogs.A.ModalDialog, (0,esm_extends.A)({
+ ref: this.dialogRef
+ }, this.state, {
+ mods,
+ name: "meeting-info-dialog",
+ title: l[18132],
+ className: "group-chat-link dialog-template-main theme-dark-forced in-call-info",
+ hideOverlay: true
+ }), JSX_("section", {
+ className: "content"
+ }, JSX_("div", {
+ className: "content-block"
+ }, JSX_(ui_utils.zT, {
+ className: "info"
+ }, mods), JSX_("div", {
+ className: "info"
+ }, l.copy_and_share), JSX_("div", {
+ className: "link-input-container"
+ }, JSX_("div", {
+ className: "mega-input with-icon box-style"
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-link"
+ }), JSX_("input", {
+ type: "text",
+ className: "megaInputs",
+ readOnly: true,
+ value: link
+ })), JSX_(meetings_button.A, {
+ className: "mega-button positive copy-to-clipboard",
+ onClick: () => {
+ if (copyToClipboard(link)) {
+ this.toggleBanner(() => {
+ this.delayProcID = delay(`${StreamHead.NAMESPACE}-banner`, this.toggleBanner, 10000);
+ });
+ }
+ }
+ }, JSX_("span", null, l[63]))), this.state.banner && JSX_("div", {
+ className: "banner-copy-success"
+ }, l[7654]))), JSX_("footer", null, JSX_("div", {
+ className: "footer-container"
+ })));
+ };
+ this.Pagination = () => {
+ const {
+ mode,
+ peers,
+ page,
+ streamsPerPage,
+ floatDetached,
+ chunksLength,
+ call,
+ onMovePage
+ } = this.props;
+ if (mode !== utils.g.THUMBNAIL || !peers) {
+ return null;
+ }
+ const {
+ screen,
+ video,
+ rest
+ } = filterAndSplitSources(peers, call);
+ if (screen.length + video.length + rest.length > (floatDetached ? streamsPerPage + 1 : streamsPerPage)) {
+ return JSX_("div", {
+ className: `${StreamHead.NAMESPACE}-pagination`
+ }, JSX_(meetings_button.A, {
+ className: `
+ carousel-button-prev
+ theme-dark-forced
+ ${page !== 0 ? '' : 'disabled'}
+ `,
+ icon: "sprite-fm-mono icon-arrow-left",
+ onClick: () => page !== 0 && onMovePage(utils.Bq.PREV)
+ }), JSX_("div", null, page + 1, "/", chunksLength), JSX_(meetings_button.A, {
+ className: `
+ carousel-button-next
+ theme-dark-forced
+ ${page < chunksLength - 1 ? '' : 'disabled'}
+ `,
+ icon: "sprite-fm-mono icon-arrow-right",
+ onClick: () => page < chunksLength - 1 && onMovePage(utils.Bq.NEXT)
+ }));
+ }
+ return null;
+ };
+ }
+ get fullscreen() {
+ return document.fullscreenElement;
+ }
+ get duration() {
+ return (Date.now() - this.props.call.ts) / 1000;
+ }
+ get durationString() {
+ return this.duration ? secondsToTimeShort(this.duration) : '--:--:--';
+ }
+ componentWillUnmount() {
+ super.componentWillUnmount();
+ clearInterval(this.durationInterval);
+ document.removeEventListener(StreamHead.EVENTS.FULLSCREEN, this.closeTooltips);
+ document.removeEventListener(StreamHead.EVENTS.CLICK_DIALOG, this.handleDialogClose);
+ }
+ componentDidMount() {
+ super.componentDidMount();
+ this.durationInterval = setInterval(this.updateDurationDOM, 1000);
+ document.addEventListener(StreamHead.EVENTS.FULLSCREEN, this.closeTooltips);
+ document.addEventListener(StreamHead.EVENTS.CLICK_DIALOG, this.handleDialogClose);
+ }
+ render() {
+ const {
+ NAMESPACE
+ } = StreamHead;
+ const {
+ mode,
+ streamsPerPage,
+ chatRoom,
+ onStreamsPerPageChange,
+ onCallMinimize,
+ onModeChange,
+ setActiveElement
+ } = this.props;
+ const {
+ dialog
+ } = this.state;
+ const SIMPLETIP = {
+ position: 'bottom',
+ offset: 5,
+ className: 'theme-dark-forced'
+ };
+ return JSX_("div", {
+ ref: this.domRef,
+ className: `${NAMESPACE}`
+ }, dialog && JSX_(this.Dialog, null), JSX_("div", {
+ className: `${NAMESPACE}-content theme-dark-forced`
+ }, JSX_("div", {
+ className: `${NAMESPACE}-info`
+ }, JSX_("div", {
+ ref: this.durationRef,
+ className: "stream-duration"
+ }, this.durationString), JSX_("div", {
+ ref: this.topicRef,
+ className: `
+ stream-topic
+ ${chatRoom.isMeeting && chatRoom.publicLink ? 'has-meeting-link' : ''}
+ `,
+ onClick: () => chatRoom.isMeeting && chatRoom.publicLink && this.setState({
+ dialog: !dialog,
+ banner: false
+ }, () => setActiveElement(this.state.dialog))
+ }, JSX_(ui_utils.zT, null, chatRoom.getRoomTitle()), chatRoom.isMeeting && chatRoom.publicLink && JSX_("i", {
+ className: `
+ sprite-fm-mono
+ ${dialog ? 'icon-arrow-up' : 'icon-arrow-down'}
+ `
+ }))), JSX_(this.Pagination, null), JSX_("div", {
+ className: `${NAMESPACE}-controls`
+ }, JSX_(ModeSwitch, {
+ mode,
+ streamsPerPage,
+ onStreamsPerPageChange,
+ onModeChange,
+ setActiveElement
+ }), JSX_(meetings_button.A, {
+ className: "head-control",
+ simpletip: {
+ ...SIMPLETIP,
+ label: this.fullscreen ? l.exit_fullscreen : l[17803]
+ },
+ icon: this.fullscreen ? 'icon-fullscreen-leave' : 'icon-fullscreen-enter',
+ onClick: this.toggleFullscreen
+ }, JSX_("span", null, this.fullscreen ? l.exit_fullscreen : l[17803])), JSX_(meetings_button.A, {
+ className: "head-control",
+ simpletip: {
+ ...SIMPLETIP,
+ label: l.minimize
+ },
+ icon: "icon-call-min-mode",
+ onClick: () => {
+ onCallMinimize();
+ eventlog(500305);
+ }
+ }, JSX_("div", null, l.minimize)))));
+ }
+}
+StreamHead.NAMESPACE = 'stream-head';
+StreamHead.EVENTS = {
+ FULLSCREEN: 'fullscreenchange',
+ SIMPLETIP: new Event('simpletipClose'),
+ CLICK_DIALOG: 'click'
+};
+// EXTERNAL MODULE: ./js/chat/ui/fallback.jsx
+const fallback = REQ_(3439);
+// EXTERNAL MODULE: ./js/ui/dropdowns.jsx
+const dropdowns = REQ_(1510);
+// EXTERNAL MODULE: ./js/ui/buttons.jsx
+const buttons = REQ_(5155);
+;// ./js/chat/ui/meetings/floatExtendedControls.jsx
+
+
+
+class FloatExtendedControls extends REaCt().Component {
+ constructor(...args) {
+ super(...args);
+ this.isActive = type => {
+ return !!(this.props.call.av & type);
+ };
+ }
+ render() {
+ const {
+ hasToRenderPermissionsWarning,
+ renderPermissionsWarning,
+ resetError,
+ showScreenDialog,
+ onScreenSharingClick,
+ onHoldClick
+ } = this.props;
+ const {
+ onHold,
+ Screen
+ } = SfuClient.Av;
+ const isOnHold = this.isActive(onHold);
+ const callHoldLabel = isOnHold ? l[23459] : l[23460];
+ const screenSharingLabel = this.isActive(Screen) ? l[22890] : l[22889];
+ return JSX_(buttons.$, {
+ className: "mega-button theme-light-forced round large button-group",
+ icon: "sprite-fm-mono icon-options",
+ showScreenDialog
+ }, this.isActive(Screen) && JSX_("div", {
+ className: "info-indicator active"
+ }), JSX_(dropdowns.ms, {
+ className: "button-group-menu theme-dark-forced",
+ noArrow: true,
+ positionAt: "center top",
+ collision: "none",
+ vertOffset: -90,
+ ref: r => {
+ this.dropdownRef = r;
+ },
+ onBeforeActiveChange: e => {
+ if (e) {
+ $(document.body).trigger('closeAllDropdownsExcept', this.dropdownRef);
+ }
+ },
+ showScreenDialog
+ }, JSX_(dropdowns.tJ, {
+ key: "call-hold",
+ className: `
+ theme-dark-forced
+ ${isOnHold ? 'active' : ''}
+ `,
+ label: callHoldLabel,
+ icon: `
+ sprite-fm-mono
+ ${isOnHold ? 'icon-play-small-regular-outline' : 'icon-pause-small-regular-outline'}
+ `,
+ onClick: onHoldClick
+ }), JSX_(dropdowns.tJ, {
+ key: "screen-sharing",
+ className: `
+ theme-dark-forced
+ ${isOnHold ? 'disabled' : ''}
+ ${this.isActive(Screen) ? 'active' : ''}
+ `,
+ label: screenSharingLabel,
+ icon: `
+ sprite-fm-mono
+ ${this.isActive(Screen) ? 'icon-monitor-off' : 'icon-monitor'}
+ `,
+ onClick: () => {
+ resetError(Av.Screen);
+ onScreenSharingClick();
+ }
+ }), hasToRenderPermissionsWarning(Screen) ? renderPermissionsWarning(Screen, this) : null));
+ }
+}
+FloatExtendedControls.NAMESPACE = 'stream-extended-controls';
+;// ./js/chat/ui/meetings/micObserver.jsx
+
+
+
+
+const withMicObserver = Component => class extends mixins.w9 {
+ constructor(props) {
+ super(props);
+ this.namespace = `SO-${Component.NAMESPACE}`;
+ this.inputObserver = `onNoMicInput.${this.namespace}`;
+ this.sendObserver = `onAudioSendDenied.${this.namespace}`;
+ this.state = {
+ signal: true,
+ blocked: false
+ };
+ this.renderSignalWarning = this.renderSignalWarning.bind(this);
+ this.renderBlockedWarning = this.renderBlockedWarning.bind(this);
+ }
+ bindObservers() {
+ this.props.chatRoom.rebind(this.inputObserver, () => this.setState({
+ signal: false
+ })).rebind(this.sendObserver, () => {
+ this.setState({
+ blocked: true
+ }, () => {
+ if (this.props.minimized) {
+ const toast = new ChatToast(l.max_speakers_toast, {
+ icon: 'sprite-fm-uni icon-hazard',
+ close: true
+ });
+ toast.dispatch();
+ }
+ });
+ });
+ }
+ renderSignalDialog() {
+ return msgDialog('warningb', null, l.no_mic_title, l.chat_mic_off_tooltip, null, 1);
+ }
+ renderSignalWarning() {
+ return JSX_("div", {
+ className: `
+ ${this.namespace}
+ meetings-signal-issue
+ simpletip
+ `,
+ "data-simpletip": l.show_info,
+ "data-simpletipposition": "top",
+ "data-simpletipoffset": "5",
+ "data-simpletip-class": "theme-dark-forced",
+ onClick: () => this.renderSignalDialog()
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-exclamation-filled"
+ }));
+ }
+ renderBlockedWarning() {
+ return JSX_("div", {
+ className: "stream-toast theme-dark-forced"
+ }, JSX_("div", {
+ className: "stream-toast-content"
+ }, JSX_("i", {
+ className: "stream-toast-icon sprite-fm-uni icon-warning"
+ }), JSX_("div", {
+ className: "stream-toast-message"
+ }, l.max_speakers_toast), JSX_(meetings_button.A, {
+ className: "mega-button action stream-toast-close",
+ icon: "sprite-fm-mono icon-close-component",
+ onClick: () => this.setState({
+ blocked: false
+ })
+ })));
+ }
+ componentWillUnmount() {
+ super.componentWillUnmount();
+ this.props.chatRoom.unbind(this.inputObserver);
+ }
+ componentDidMount() {
+ super.componentDidMount();
+ this.bindObservers();
+ }
+ render() {
+ return JSX_(Component, (0,esm_extends.A)({}, this.props, {
+ signal: this.state.signal,
+ renderSignalWarning: this.renderSignalWarning,
+ blocked: this.state.blocked,
+ renderBlockedWarning: this.renderBlockedWarning
+ }));
+ }
+};
+// EXTERNAL MODULE: ./js/chat/ui/meetings/permissionsObserver.jsx
+const permissionsObserver = REQ_(192);
+// EXTERNAL MODULE: ./js/chat/ui/meetings/hostsObserver.jsx
+const hostsObserver = REQ_(7677);
+;// ./js/chat/ui/meetings/float.jsx
+
+
+
+
+
+
+
+
+
+
+
+class FloatingVideo extends REaCt().Component {
+ constructor(...args) {
+ super(...args);
+ this.collapseListener = null;
+ this.state = {
+ collapsed: false
+ };
+ this.toggleCollapsedMode = () => {
+ return this.setState(state => ({
+ collapsed: !state.collapsed
+ }));
+ };
+ }
+ componentWillUnmount() {
+ mBroadcaster.removeListener(this.collapseListener);
+ }
+ componentDidMount() {
+ this.collapseListener = mBroadcaster.addListener('meetings:collapse', () => this.setState({
+ collapsed: true
+ }));
+ }
+ componentDidUpdate() {
+ if (typeof psa !== 'undefined') {
+ psa.repositionMeetingsCall();
+ }
+ }
+ render() {
+ const {
+ peers,
+ minimized,
+ call,
+ floatDetached
+ } = this.props;
+ if (peers.length === 0 && !minimized && !call.isSharingScreen()) {
+ return null;
+ }
+ const STREAM_PROPS = {
+ ...this.props,
+ collapsed: this.state.collapsed,
+ toggleCollapsedMode: this.toggleCollapsedMode,
+ onLoadedData: this.onLoadedData
+ };
+ if (minimized) {
+ return JSX_(ui_utils.Ay.RenderTo, {
+ element: document.body
+ }, JSX_(Stream, STREAM_PROPS));
+ }
+ return floatDetached ? JSX_(Stream, STREAM_PROPS) : null;
+ }
+}
+FloatingVideo.NAMESPACE = 'float-video';
+FloatingVideo.POSITION_MODIFIER = 'with-sidebar';
+class Stream extends mixins.w9 {
+ constructor(...args) {
+ super(...args);
+ this.domRef = REaCt().createRef();
+ this.DRAGGABLE = {
+ POSITION: {
+ top: undefined,
+ left: undefined
+ },
+ OPTIONS: {
+ scroll: 'false',
+ cursor: 'move',
+ opacity: 1,
+ start: () => {
+ if (this.state.options) {
+ this.handleOptionsToggle();
+ }
+ $(document.body).trigger('closeAllDropdownsExcept');
+ },
+ stop: (event, ui) => {
+ this.DRAGGABLE.POSITION = ui.position;
+ const {
+ clientWidth,
+ clientHeight
+ } = document.body;
+ const {
+ helper
+ } = ui;
+ const {
+ left,
+ top
+ } = this.DRAGGABLE.POSITION;
+ if (left < clientWidth / 2) {
+ helper.css('left', `${left / clientWidth * 100}%`).css('right', 'unset');
+ } else {
+ helper.css('left', 'unset').css('right', `${clientWidth - left - helper.width()}px`);
+ }
+ if (top < clientHeight / 2) {
+ helper.css('top', `${top / clientHeight * 100}%`).css('bottom', 'unset');
+ } else {
+ helper.css('top', 'unset').css('bottom', `${clientHeight - top - helper.height()}px`);
+ }
+ }
+ }
+ };
+ this.EVENTS = {
+ MINIMIZE: ['slideshow:open', 'contact:open', 'textEditor:open', 'chat:open'],
+ EXPAND: ['slideshow:close', 'textEditor:close']
+ };
+ this.LISTENERS = [];
+ this.PREV_STATE = {};
+ this.state = {
+ options: false
+ };
+ this.getStreamSource = () => {
+ const {
+ call,
+ mode,
+ forcedLocal
+ } = this.props;
+ return mode === utils.g.MINI && !forcedLocal ? call.getActiveStream() : call.getLocalStream();
+ };
+ this.unbindEvents = () => {
+ const events = [...this.EVENTS.MINIMIZE, ...this.EVENTS.EXPAND];
+ for (let i = events.length; i--;) {
+ const event = events[i];
+ mBroadcaster.removeListener(this.LISTENERS[event]);
+ }
+ document.removeEventListener('click', this.handleOptionsClose);
+ };
+ this.bindEvents = () => {
+ for (let i = this.EVENTS.MINIMIZE.length; i--;) {
+ const event = this.EVENTS.MINIMIZE[i];
+ this.LISTENERS[event] = mBroadcaster.addListener(event, () => {
+ this.PREV_STATE.minimised = this.props.minimized;
+ return this.props.onCallMinimize();
+ });
+ }
+ for (let i = this.EVENTS.EXPAND.length; i--;) {
+ const event = this.EVENTS.EXPAND[i];
+ this.LISTENERS[event] = mBroadcaster.addListener(event, () => {
+ if (this.PREV_STATE.minimised) {
+ delete this.PREV_STATE.minimised;
+ return;
+ }
+ delete this.PREV_STATE.minimised;
+ return this.props.view === utils.gR.CHAT && this.props.onCallExpand();
+ });
+ }
+ document.addEventListener('click', this.handleOptionsClose);
+ };
+ this.initDraggable = () => {
+ let _this$domRef;
+ const {
+ minimized,
+ wrapperRef
+ } = this.props;
+ const containerEl = (_this$domRef = this.domRef) == null ? void 0 : _this$domRef.current;
+ if (containerEl) {
+ $(containerEl).draggable({
+ ...this.DRAGGABLE.OPTIONS,
+ containment: minimized ? 'body' : wrapperRef == null ? void 0 : wrapperRef.current
+ });
+ }
+ };
+ this.repositionDraggable = () => {
+ let _this$props$wrapperRe, _this$domRef2;
+ const wrapperEl = (_this$props$wrapperRe = this.props.wrapperRef) == null ? void 0 : _this$props$wrapperRe.current;
+ const localEl = (_this$domRef2 = this.domRef) == null ? void 0 : _this$domRef2.current;
+ if (localEl.offsetLeft + localEl.offsetWidth > wrapperEl.offsetWidth) {
+ localEl.style.left = 'unset';
+ localEl.style.removeProperty("right");
+ }
+ };
+ this.handleOptionsClose = ({
+ target
+ }) => {
+ if (this.state.options && !target.classList.contains('icon-options')) {
+ this.setState({
+ options: false
+ });
+ }
+ };
+ this.handleOptionsToggle = () => this.setState({
+ options: !this.state.options
+ });
+ this.renderOnHoldVideoNode = () => JSX_(LocalVideoHiRes, {
+ chatRoom: this.props.chatRoom
+ });
+ this.renderOptionsDialog = () => {
+ const {
+ call,
+ mode,
+ forcedLocal,
+ onScreenSharingClick,
+ onSpeakerChange,
+ onModeChange,
+ toggleCollapsedMode,
+ onMoveIntoGrid
+ } = this.props;
+ const IS_SPEAKER_VIEW = mode === utils.g.MAIN && forcedLocal;
+ const {
+ POSITION
+ } = this.DRAGGABLE;
+ return JSX_("div", {
+ className: `
+ ${FloatingVideo.NAMESPACE}-options
+ ${POSITION.left < 200 ? 'options-top' : ''}
+ ${POSITION.left < 200 && POSITION.top < 100 ? 'options-bottom' : ''}
+ theme-dark-forced
+ `
+ }, JSX_("ul", null, JSX_("li", null, JSX_(meetings_button.A, {
+ icon: `
+ sprite-fm-mono
+ ${IS_SPEAKER_VIEW ? 'grid-9' : 'grid-main'}
+ `,
+ onClick: () => this.setState({
+ options: false
+ }, () => {
+ if (IS_SPEAKER_VIEW) {
+ return onModeChange(utils.g.THUMBNAIL);
+ }
+ onSpeakerChange(call.getLocalStream());
+ })
+ }, JSX_("div", null, IS_SPEAKER_VIEW ? l.switch_to_thumb_view : l.display_in_main_view))), JSX_("li", null, JSX_(meetings_button.A, {
+ icon: "sprite-fm-mono icon-collapse-up",
+ onClick: onMoveIntoGrid
+ }, JSX_("div", null, l.move_into_grid_button))), JSX_("li", null, JSX_(meetings_button.A, {
+ icon: "sprite-fm-mono icon-download-standard",
+ onClick: () => this.setState({
+ options: false
+ }, () => toggleCollapsedMode())
+ }, JSX_("div", null, l.collapse_self_video)))), !!(call.av & SfuClient.Av.Screen) && JSX_("ul", {
+ className: "has-separator"
+ }, JSX_("li", null, JSX_(meetings_button.A, {
+ className: "end-screen-share",
+ icon: "icon-end-screenshare",
+ onClick: () => {
+ this.setState({
+ options: false
+ });
+ onScreenSharingClick();
+ }
+ }, JSX_("div", null, l[22890])))));
+ };
+ this.renderMiniMode = source => {
+ const {
+ call,
+ chatRoom,
+ mode,
+ minimized,
+ isPresenterNode,
+ onLoadedData
+ } = this.props;
+ if (call.isOnHold) {
+ return this.renderOnHoldVideoNode();
+ }
+ const VideoClass = source.isLocal ? isPresenterNode ? LocalVideoHiRes : LocalVideoThumb : PeerVideoHiRes;
+ return JSX_(VideoClass, {
+ key: source,
+ source,
+ chatRoom,
+ mode,
+ minimized,
+ isPresenterNode,
+ onLoadedData
+ });
+ };
+ this.renderSelfView = () => {
+ const {
+ isOnHold,
+ raisedHandPeers,
+ minimized,
+ chatRoom,
+ isPresenterNode,
+ call,
+ onLoadedData
+ } = this.props;
+ const {
+ options
+ } = this.state;
+ if (isOnHold) {
+ return this.renderOnHoldVideoNode();
+ }
+ const VideoNode = call.isSharingScreen() ? LocalVideoHiResCloned : LocalVideoThumb;
+ return JSX_(REaCt().Fragment, null, JSX_(VideoNode, {
+ isSelfOverlay: true,
+ raisedHandPeers,
+ minimized,
+ chatRoom,
+ isPresenterNode,
+ onLoadedData
+ }), JSX_("div", {
+ className: `${FloatingVideo.NAMESPACE}-self-overlay`
+ }, minimized ? null : JSX_(meetings_button.A, {
+ className: `
+ mega-button
+ theme-light-forced
+ action
+ small
+ float-video-options-control
+ ${options ? 'active' : ''}
+ `,
+ icon: "sprite-fm-mono icon-options",
+ onClick: () => this.handleOptionsToggle()
+ }), options && this.renderOptionsDialog()));
+ };
+ }
+ componentWillUnmount() {
+ super.componentWillUnmount();
+ this.unbindEvents();
+ }
+ componentDidUpdate(prevProps) {
+ super.componentDidUpdate();
+ if (this.props.mode !== prevProps.mode) {
+ this.initDraggable();
+ }
+ if (this.props.sidebar !== prevProps.sidebar && this.props.sidebar) {
+ this.repositionDraggable();
+ }
+ }
+ componentDidMount() {
+ super.componentDidMount();
+ this.bindEvents();
+ this.initDraggable();
+ }
+ render() {
+ const {
+ NAMESPACE,
+ POSITION_MODIFIER
+ } = FloatingVideo;
+ const {
+ call,
+ mode,
+ minimized,
+ sidebar,
+ collapsed,
+ toggleCollapsedMode,
+ onCallExpand
+ } = this.props;
+ const IS_MINI_MODE = mode === utils.g.MINI;
+ if (collapsed) {
+ return JSX_("div", {
+ ref: this.domRef,
+ className: `
+ ${NAMESPACE}
+ collapsed
+ theme-dark-forced
+ ${sidebar && !minimized ? POSITION_MODIFIER : ''}
+ `,
+ onClick: toggleCollapsedMode
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-arrow-up icon-collapse"
+ }), JSX_("div", {
+ className: "collapsed-audio-indicator"
+ }, JSX_(AudioLevelIndicator, {
+ source: call.getLocalStream()
+ })));
+ }
+ const source = this.getStreamSource() || call.getLocalStream();
+ return JSX_("div", {
+ ref: this.domRef,
+ className: `
+ ${NAMESPACE}
+ ${IS_MINI_MODE ? 'mini' : ''}
+ ${minimized ? 'minimized' : ''}
+ ${this.state.options ? 'active' : ''}
+ ${sidebar && !minimized ? POSITION_MODIFIER : ''}
+ `,
+ onClick: ({
+ target
+ }) => minimized && target.classList.contains(`${NAMESPACE}-overlay`) && onCallExpand()
+ }, IS_MINI_MODE && this.renderMiniMode(source), !IS_MINI_MODE && this.renderSelfView(), minimized && JSX_(__Minimized, (0,esm_extends.A)({}, this.props, {
+ onOptionsToggle: this.handleOptionsToggle
+ })));
+ }
+}
+class Minimized extends mixins.w9 {
+ constructor(props) {
+ super(props);
+ this.domRef = REaCt().createRef();
+ this.SIMPLETIP_PROPS = {
+ position: 'top',
+ offset: 5,
+ className: 'theme-dark-forced'
+ };
+ this.waitingPeersListener = undefined;
+ this.raisedHandListener = undefined;
+ this.state = {
+ unread: 0,
+ waitingRoomPeers: [],
+ raisedHandPeers: [],
+ hideWrList: false,
+ hideHandsList: false
+ };
+ this.isActive = type => {
+ return this.props.call.av & type;
+ };
+ this.getUnread = () => {
+ const {
+ chatRoom
+ } = this.props;
+ chatRoom.rebind(Minimized.UNREAD_EVENT, () => this.setState({
+ unread: chatRoom.getUnreadCount()
+ }, () => this.safeForceUpdate()));
+ };
+ this.renderSignalWarning = () => this.props.signal ? null : this.props.renderSignalWarning();
+ this.renderPermissionsWarning = type => {
+ const {
+ hasToRenderPermissionsWarning,
+ renderPermissionsWarning
+ } = this.props;
+ if (hasToRenderPermissionsWarning(type)) {
+ return renderPermissionsWarning(type, this);
+ }
+ return null;
+ };
+ this.renderStreamControls = () => {
+ const {
+ call,
+ chatRoom,
+ recorderCid,
+ hasToRenderPermissionsWarning,
+ renderPermissionsWarning,
+ resetError,
+ onRecordingToggle,
+ onAudioClick,
+ onVideoClick,
+ onScreenSharingClick,
+ onHoldClick,
+ onCallEnd
+ } = this.props;
+ const audioLabel = this.isActive(SfuClient.Av.Audio) ? l[16214] : l[16708];
+ const videoLabel = this.isActive(SfuClient.Av.Camera) ? l[22894] : l[22893];
+ const LeaveButton = (0,hostsObserver.C)(({
+ hasHost,
+ chatRoom,
+ confirmLeave,
+ onLeave
+ }) => {
+ return JSX_(meetings_button.A, {
+ simpletip: {
+ ...this.SIMPLETIP_PROPS,
+ label: l[5884]
+ },
+ className: "mega-button theme-dark-forced round large end-call",
+ icon: "icon-phone-02",
+ onClick: ev => {
+ ev.stopPropagation();
+ const callParticipants = chatRoom.getCallParticipants();
+ const doLeave = () => !chatRoom.iAmOperator() || hasHost(chatRoom.call ? chatRoom.call.peers.map(a => a.userHandle) : []) || callParticipants.length === 1 ? onLeave() : confirmLeave({
+ title: l.assign_host_leave_call,
+ body: l.assign_host_leave_call_details,
+ cta: l.assign_host_button,
+ altCta: l.leave_anyway
+ });
+ return recorderCid && recorderCid === call.sfuClient.cid ? (0,utils.sX)(doLeave, onRecordingToggle) : doLeave();
+ }
+ }, JSX_("span", null, l[5884]));
+ });
+ return JSX_(REaCt().Fragment, null, JSX_("div", {
+ className: `${FloatingVideo.NAMESPACE}-controls`
+ }, JSX_("div", {
+ className: "meetings-signal-container"
+ }, JSX_(meetings_button.A, {
+ simpletip: {
+ ...this.SIMPLETIP_PROPS,
+ label: audioLabel
+ },
+ className: `
+ mega-button
+ theme-light-forced
+ round
+ ${this.isActive(SfuClient.Av.onHold) ? 'disabled' : ''}
+ ${this.isActive(SfuClient.Av.Audio) ? '' : 'with-fill'}
+ `,
+ icon: this.isActive(SfuClient.Av.Audio) ? 'icon-mic-thin-outline' : 'icon-mic-off-thin-outline',
+ onClick: ev => {
+ ev.stopPropagation();
+ resetError(Av.Audio);
+ onAudioClick();
+ }
+ }, JSX_("span", null, audioLabel)), this.renderSignalWarning(), this.renderPermissionsWarning(Av.Audio)), JSX_("div", {
+ className: "meetings-signal-container"
+ }, JSX_(meetings_button.A, {
+ simpletip: {
+ ...this.SIMPLETIP_PROPS,
+ label: videoLabel
+ },
+ className: `
+ mega-button
+ theme-light-forced
+ round
+ ${this.isActive(SfuClient.Av.onHold) ? 'disabled' : ''}
+ ${this.isActive(SfuClient.Av.Camera) ? '' : 'with-fill'}
+ `,
+ icon: this.isActive(SfuClient.Av.Camera) ? 'icon-video-thin-outline' : 'icon-video-off-thin-outline',
+ onClick: ev => {
+ ev.stopPropagation();
+ resetError(Av.Camera);
+ onVideoClick();
+ }
+ }, JSX_("span", null, videoLabel)), this.renderPermissionsWarning(Av.Camera)), JSX_("div", {
+ className: "meetings-signal-container"
+ }, JSX_(FloatExtendedControls, {
+ call,
+ chatRoom,
+ onScreenSharingClick,
+ onHoldClick,
+ hasToRenderPermissionsWarning,
+ renderPermissionsWarning,
+ resetError,
+ showScreenDialog: !!this.props[`dialog-${Av.Screen}`]
+ }), this.renderPermissionsWarning(Av.Screen)), JSX_(LeaveButton, {
+ chatRoom,
+ participants: chatRoom.getCallParticipants(),
+ onLeave: onCallEnd,
+ onConfirmDenied: onCallEnd
+ })), JSX_("span", {
+ className: `${FloatingVideo.NAMESPACE}-fade`
+ }));
+ };
+ this.renderPeersList = () => {
+ const {
+ onCallExpand,
+ onParticipantsToggle,
+ onWrListToggle
+ } = this.props;
+ const {
+ waitingRoomPeers,
+ raisedHandPeers,
+ hideHandsList,
+ hideWrList
+ } = this.state;
+ if (hideHandsList && hideWrList) {
+ return null;
+ }
+ const showRaised = hideHandsList || !hideWrList && waitingRoomPeers.length ? false : !!raisedHandPeers.length;
+ if (!showRaised && hideWrList) {
+ return null;
+ }
+ const showButton = !showRaised || showRaised && raisedHandPeers.length > 1;
+ return JSX_("div", {
+ className: `
+ ${FloatingVideo.NAMESPACE}-alert
+ alert--waiting-peers
+ theme-dark-forced
+ `,
+ onClick: onCallExpand
+ }, JSX_(meetings_button.A, {
+ className: "close js-close",
+ icon: "sprite-fm-mono icon-dialog-close",
+ hideWrList,
+ hideHandsList,
+ onClick: ev => {
+ ev.stopPropagation();
+ this.setState({
+ hideHandsList: hideWrList || showRaised,
+ hideWrList: true
+ });
+ }
+ }), JSX_("div", {
+ className: `alert-label ${showButton ? '' : 'label-only'}`
+ }, showRaised && JSX_("i", {
+ className: "sprite-fm-uni icon-raise-hand"
+ }), !hideWrList && !!waitingRoomPeers.length && mega.icu.format(l.wr_peers_waiting, waitingRoomPeers.length), showRaised && (raisedHandPeers.length > 1 ? raisedHandPeers.includes(u_handle) ? mega.icu.format(l.raise_self_peers_raised, raisedHandPeers.length - 1) : mega.icu.format(l.raise_peers_raised, raisedHandPeers.length) : JSX_(ui_utils.P9, {
+ tag: "span",
+ content: raisedHandPeers[0] === u_handle ? l.raise_self_raised : l.raise_peer_raised.replace('%s', megaChat.html(M.getNameByHandle(raisedHandPeers[0])))
+ }))), showButton && JSX_(meetings_button.A, {
+ className: "show-people",
+ label: showRaised ? l[16797] : l.wr_see_waiting,
+ onClick: ev => {
+ ev.stopPropagation();
+ const promise = onCallExpand().catch(dump);
+ if (showRaised) {
+ promise.then(() => onParticipantsToggle(true));
+ } else if (waitingRoomPeers.length > 1) {
+ promise.then(() => onWrListToggle(true));
+ }
+ }
+ }, showRaised ? l[16797] : l.wr_see_waiting));
+ };
+ this.state.waitingRoomPeers = this.props.waitingRoomPeers || [];
+ this.state.raisedHandPeers = this.props.raisedHandPeers || [];
+ }
+ componentDidMount() {
+ super.componentDidMount();
+ this.getUnread();
+ this.waitingPeersListener = mBroadcaster.addListener('meetings:peersWaiting', waitingRoomPeers => this.setState({
+ waitingRoomPeers,
+ hideWrList: false,
+ hideHandsList: false
+ }, () => this.safeForceUpdate()));
+ this.raisedHandListener = mBroadcaster.addListener('meetings:raisedHand', raisedHandPeers => this.setState({
+ raisedHandPeers,
+ hideWrList: false,
+ hideHandsList: false
+ }, () => this.safeForceUpdate()));
+ ['onCallPeerJoined', 'onCallPeerLeft'].map(event => this.props.chatRoom.rebind(`${event}.${Minimized.NAMESPACE}`, (ev, {
+ userHandle
+ }) => this.isMounted() && this.setState(state => ({
+ raisedHandPeers: state.raisedHandPeers.includes(userHandle) ? state.raisedHandPeers.filter(h => h !== userHandle) : [...this.props.call.sfuClient.raisedHands]
+ }), this.safeForceUpdate)));
+ }
+ componentWillUnmount() {
+ super.componentWillUnmount();
+ this.props.chatRoom.unbind(Minimized.UNREAD_EVENT);
+ [this.waitingPeersListener, this.raisedHandListener].map(listener => mBroadcaster.removeListener(listener));
+ ['onCallPeerJoined', 'onCallPeerLeft'].map(event => this.props.chatRoom.off(`${event}.${Minimized.NAMESPACE}`));
+ }
+ render() {
+ const {
+ onCallExpand
+ } = this.props;
+ const {
+ unread,
+ raisedHandPeers,
+ waitingRoomPeers
+ } = this.state;
+ return JSX_("div", {
+ ref: this.domRef,
+ className: `${FloatingVideo.NAMESPACE}-wrapper`
+ }, JSX_("div", {
+ className: `${FloatingVideo.NAMESPACE}-overlay`
+ }, JSX_(meetings_button.A, {
+ simpletip: {
+ ...this.SIMPLETIP_PROPS,
+ label: l.expand_mini_call
+ },
+ className: "mega-button theme-light-forced action small expand",
+ icon: "sprite-fm-mono icon-fullscreen-enter",
+ onClick: ev => {
+ ev.stopPropagation();
+ onCallExpand();
+ }
+ }), this.renderStreamControls()), waitingRoomPeers && waitingRoomPeers.length || raisedHandPeers && raisedHandPeers.length ? this.renderPeersList() : null, unread ? JSX_("div", {
+ className: `${FloatingVideo.NAMESPACE}-notifications`
+ }, JSX_(meetings_button.A, {
+ className: "mega-button round large chat-control",
+ icon: "icon-chat-filled"
+ }, JSX_("span", null, l.chats)), JSX_("span", null, unread > 9 ? '9+' : unread)) : null);
+ }
+}
+Minimized.NAMESPACE = 'float-video-minimized';
+Minimized.UNREAD_EVENT = 'onUnreadCountUpdate.localStreamNotifications';
+const __Minimized = (0,mixins.Zz)(withMicObserver, permissionsObserver.$)(Minimized);
+;// ./js/chat/ui/meetings/stream.jsx
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+const Admit = (0,external_React_.lazy)(() => REQ_.e( 752).then(REQ_.bind(REQ_, 3056)));
+const NAMESPACE = 'stream';
+const chunkNodes = (nodes, size) => {
+ if (nodes && nodes.length && size) {
+ const chunked = [];
+ let index = 0;
+ while (index < nodes.length) {
+ chunked.push({
+ id: index,
+ nodes: nodes.slice(index, index + size)
+ });
+ index += size;
+ }
+ return chunked;
+ }
+ return null;
+};
+const filterAndSplitSources = (sources, call) => {
+ const screen = [];
+ const video = [];
+ const rest = [];
+ for (const peer of Object.values(sources.toJS())) {
+ if (peer instanceof CallManager2.Peer) {
+ if (peer.hasScreen) {
+ screen.push(peer, peer);
+ } else if (peer.videoMuted) {
+ rest.push(peer);
+ } else {
+ video.push(peer);
+ }
+ }
+ }
+ const local = call.getLocalStream();
+ if (local.hasScreen) {
+ const presenters = [...call.presenterStreams];
+ if (presenters.pop() === u_handle) {
+ screen.unshift(local, local);
+ } else {
+ screen.push(local, local);
+ }
+ } else if (local.av & Av.Camera) {
+ video.unshift(local);
+ } else {
+ rest.push(local);
+ }
+ return {
+ screen,
+ video,
+ rest
+ };
+};
+class stream_Stream extends mixins.w9 {
+ constructor(...args) {
+ super(...args);
+ this.domRef = REaCt().createRef();
+ this.containerRef = REaCt().createRef();
+ this.nodeRefs = [];
+ this.chunks = [];
+ this.chunksLength = 0;
+ this.lastRescaledCache = undefined;
+ this.state = {
+ page: 0,
+ overlayed: false,
+ streamsPerPage: utils.gh.MED,
+ floatDetached: false,
+ wrToggled: false
+ };
+ this.toggleFloatDetachment = () => {
+ this.setState(state => ({
+ floatDetached: !state.floatDetached
+ }));
+ };
+ this.toggleWaitingRoomList = state => {
+ this.setState({
+ wrToggled: state
+ });
+ };
+ }
+ movePage(direction) {
+ return this.setState(state => ({
+ page: direction === utils.Bq.NEXT ? state.page + 1 : state.page - 1
+ }));
+ }
+ getColumns(streamsCount) {
+ switch (true) {
+ case streamsCount >= 43:
+ return 7;
+ case streamsCount >= 26:
+ return 6;
+ case streamsCount >= 17:
+ return 5;
+ case streamsCount >= 13:
+ return 4;
+ case streamsCount === 1:
+ return 1;
+ case streamsCount >= 7:
+ return 3;
+ default:
+ return 2;
+ }
+ }
+ scaleNodes(columns, forced = false) {
+ let _Object$values$page;
+ const {
+ peers,
+ minimized,
+ mode,
+ call
+ } = this.props;
+ const {
+ screen,
+ video,
+ rest
+ } = filterAndSplitSources(peers, call);
+ let presenter = false;
+ const sources = [...screen, ...video, ...rest].filter(source => {
+ if (!source.isLocal) {
+ return true;
+ }
+ if (source.hasScreen && !presenter) {
+ presenter = true;
+ return true;
+ }
+ return false;
+ });
+ presenter = false;
+ const container = this.containerRef.current;
+ this.lastRescaledCache = forced ? null : this.lastRescaledCache;
+ if (minimized || !container) {
+ return;
+ }
+ const {
+ floatDetached,
+ streamsPerPage,
+ page
+ } = this.state;
+ const parentRef = container.parentNode;
+ const parentStyle = getComputedStyle(parentRef);
+ const extraVerticalMargin = parseInt(parentStyle.paddingTop) + parseInt(parentStyle.paddingBottom);
+ let containerWidth = parentRef.offsetWidth;
+ let containerHeight = parentRef.offsetHeight - extraVerticalMargin;
+ const nodesPerPage = floatDetached ? streamsPerPage : streamsPerPage - 1;
+ const streamsInUI = sources.length > nodesPerPage ? (_Object$values$page = Object.values(this.chunks)[page]) == null ? void 0 : _Object$values$page.nodes : sources;
+ if (streamsInUI) {
+ const streamCountInUI = sources.length > nodesPerPage || floatDetached ? streamsInUI.length : streamsInUI.length + 1;
+ let rows;
+ if (mode === utils.g.THUMBNAIL) {
+ columns = typeof columns === 'number' ? columns : this.getColumns(streamCountInUI);
+ rows = Math.ceil(streamCountInUI / columns);
+ } else {
+ rows = 1;
+ columns = 1;
+ }
+ containerWidth -= columns * 6 * 2;
+ containerHeight -= rows * 6 * 2;
+ let targetWidth = Math.floor(containerWidth / columns);
+ let targetHeight = targetWidth / 16 * 9;
+ if (targetHeight * rows > containerHeight) {
+ targetHeight = Math.floor(containerHeight / rows);
+ targetWidth = targetHeight / 9 * 16;
+ }
+ const nodeRefs = this.nodeRefs.flat();
+ const nodeRefsLength = nodeRefs.length;
+ const viewMode = mode || utils.g.MAIN;
+ let cache = `${viewMode}:${targetWidth}:${targetHeight}:${nodeRefsLength}:${rows}:${streamCountInUI}:${columns}`;
+ for (let i = 0; i < nodeRefsLength; i++) {
+ cache += `${nodeRefs[i].cacheKey}:`;
+ }
+ if (this.lastRescaledCache === cache) {
+ return;
+ }
+ this.lastRescaledCache = cache;
+ for (let i = 0; i < nodeRefsLength; i++) {
+ const node = nodeRefs[i];
+ if (node && node.ref) {
+ node.ref.style.width = `${targetWidth}px`;
+ node.ref.style.height = `${targetHeight}px`;
+ }
+ }
+ container.style.width = `${(targetWidth + 12) * columns}px`;
+ }
+ }
+ renderNodes() {
+ const {
+ mode,
+ peers,
+ call,
+ raisedHandPeers,
+ chatRoom,
+ onVideoDoubleClick,
+ onModeChange
+ } = this.props;
+ const {
+ page,
+ streamsPerPage,
+ floatDetached
+ } = this.state;
+ const {
+ screen,
+ video,
+ rest
+ } = filterAndSplitSources(peers, call);
+ const sources = [...screen, ...video, ...rest];
+ if (mode === utils.g.THUMBNAIL) {
+ const nodesPerPage = floatDetached ? streamsPerPage : streamsPerPage - 1;
+ if (sources.length <= nodesPerPage) {
+ const $$PEER = (peer, i) => {
+ const {
+ clientId,
+ hasScreenAndCam,
+ hasScreen,
+ isLocal
+ } = peer;
+ if (screen.length && (screen[0].clientId === clientId || screen[0].isLocal && isLocal)) {
+ screen.shift();
+ }
+ if (!(peer instanceof CallManager2.Peer)) {
+ const isPresenterNode = screen.length && screen[0].isLocal;
+ if (floatDetached && !isPresenterNode) {
+ return;
+ }
+ if (floatDetached || !isPresenterNode) {
+ return JSX_(LocalVideoThumb, {
+ key: `${mode}_thumb_${u_handle}`,
+ chatRoom,
+ isPresenterNode: false,
+ raisedHandPeers,
+ source: peer,
+ didMount: ref => {
+ this.nodeRefs.push({
+ clientId: u_handle,
+ cacheKey: `${mode}_${u_handle}_thumb`,
+ ref
+ });
+ this.scaleNodes(undefined, true);
+ },
+ willUnmount: () => {
+ this.nodeRefs = this.nodeRefs.filter(nodeRef => nodeRef.cacheKey !== `${mode}_${u_handle}_thumb`);
+ }
+ }, this.renderSelfViewMenu());
+ }
+ return JSX_(LocalVideoHiRes, {
+ key: `${mode}_${u_handle}`,
+ chatRoom,
+ isPresenterNode,
+ source: isPresenterNode && peer,
+ raisedHandPeers,
+ didMount: ref => {
+ this.nodeRefs.push({
+ clientId: u_handle,
+ cacheKey: `${mode}_${u_handle}`,
+ ref
+ });
+ this.scaleNodes(undefined, true);
+ },
+ willUnmount: () => {
+ this.nodeRefs = this.nodeRefs.filter(nodeRef => nodeRef.cacheKey !== `${mode}_${u_handle}`);
+ }
+ }, hasScreen ? this.renderNodeMenu(peer, {
+ isPresenterNode
+ }) : this.renderSelfViewMenu());
+ }
+ const presenterCid = screen.length && screen[0].clientId === clientId;
+ let PeerClass = PeerVideoThumb;
+ if (hasScreenAndCam) {
+ PeerClass = presenterCid ? PeerVideoHiRes : PeerVideoThumbFixed;
+ }
+ const cacheKey = `${mode}_${clientId}_${i}_${hasScreenAndCam ? 1 : 0}`;
+ return JSX_(PeerClass, {
+ key: cacheKey,
+ mode,
+ chatRoom,
+ menu: true,
+ source: peer,
+ raisedHandPeers,
+ isPresenterNode: !!presenterCid,
+ onDoubleClick: (peer, e) => {
+ e.preventDefault();
+ e.stopPropagation();
+ onVideoDoubleClick(peer, !presenterCid);
+ },
+ didMount: ref => {
+ this.nodeRefs.push({
+ clientId: presenterCid || clientId,
+ cacheKey,
+ ref
+ });
+ },
+ willUnmount: () => {
+ this.nodeRefs = this.nodeRefs.filter(nodeRef => nodeRef.cacheKey !== cacheKey);
+ }
+ }, this.renderNodeMenu(peer, {
+ isPresenterNode: !!presenterCid
+ }));
+ };
+ return sources.map((p, i) => $$PEER(p, i));
+ }
+ if (floatDetached) {
+ for (let i = 0; i < sources.length; i++) {
+ if (sources[i].isLocal) {
+ sources.splice(i, 1);
+ break;
+ }
+ }
+ }
+ this.chunks = chunkNodes(sources, streamsPerPage);
+ this.chunksLength = Object.values(this.chunks).length;
+ return JSX_("div", {
+ className: "carousel"
+ }, JSX_("div", {
+ className: "carousel-container"
+ }, Object.values(this.chunks).map((chunk, i) => {
+ const {
+ id,
+ nodes
+ } = chunk;
+ return JSX_("div", {
+ key: id,
+ className: `
+ carousel-page
+ ${i === page ? 'active' : ''}
+ `
+ }, nodes.map((peer, j) => {
+ const {
+ clientId,
+ hasScreenAndCam,
+ hasScreen,
+ isLocal
+ } = peer;
+ if (screen.length && (screen[0].clientId === clientId || screen[0].isLocal && isLocal)) {
+ screen.shift();
+ }
+ if (peer instanceof CallManager2.Peer) {
+ const presenterCid = screen.length && screen[0].clientId === clientId;
+ const cacheKey = `${mode}_${clientId}_${j + i * streamsPerPage}_${hasScreenAndCam ? 1 : 0}`;
+ let PeerClass = PeerVideoThumb;
+ if (hasScreenAndCam) {
+ PeerClass = presenterCid ? PeerVideoHiRes : PeerVideoThumbFixed;
+ }
+ return JSX_(PeerClass, {
+ key: cacheKey,
+ mode,
+ source: peer,
+ chatRoom,
+ isPresenterNode: !!presenterCid,
+ raisedHandPeers,
+ onDoubleClick: (peer, e) => {
+ e.preventDefault();
+ e.stopPropagation();
+ onVideoDoubleClick(peer);
+ },
+ didMount: ref => {
+ if (!this.nodeRefs[id]) {
+ this.nodeRefs[id] = [];
+ }
+ this.nodeRefs[id].push({
+ clientId: presenterCid || clientId,
+ ref,
+ cacheKey
+ });
+ this.scaleNodes(undefined, true);
+ },
+ willUnmount: () => {
+ this.nodeRefs = this.nodeRefs.map(chunk => chunk.filter(nodeRef => nodeRef.cacheKey !== cacheKey));
+ }
+ }, this.renderNodeMenu(peer, {
+ isPresenterNode: !!presenterCid
+ }));
+ }
+ const isPresenterNode = screen.length && screen[0].isLocal;
+ if (floatDetached && !isPresenterNode) {
+ return null;
+ }
+ if (floatDetached || !isPresenterNode) {
+ return JSX_(LocalVideoThumb, {
+ key: `${mode}_thumb_${u_handle}`,
+ chatRoom,
+ source: peer,
+ isPresenterNode: false,
+ didMount: ref => {
+ if (!this.nodeRefs[id]) {
+ this.nodeRefs[id] = [];
+ }
+ this.nodeRefs[id].push({
+ clientId: u_handle,
+ cacheKey: `${mode}_${u_handle}_thumb`,
+ ref
+ });
+ this.scaleNodes(undefined, true);
+ },
+ willUnmount: () => {
+ this.nodeRefs = this.nodeRefs.map(chunk => chunk.filter(nodeRef => nodeRef.cacheKey !== `${mode}_${u_handle}_thumb`));
+ }
+ }, this.renderSelfViewMenu());
+ }
+ return JSX_(LocalVideoHiRes, {
+ key: `${mode}_${u_handle}`,
+ chatRoom,
+ raisedHandPeers,
+ isPresenterNode,
+ source: isPresenterNode && peer,
+ didMount: ref => {
+ if (!this.nodeRefs[id]) {
+ this.nodeRefs[id] = [];
+ }
+ this.nodeRefs[id].push({
+ clientId: u_handle,
+ ref,
+ cacheKey: `${mode}_${u_handle}`
+ });
+ this.scaleNodes(undefined, true);
+ },
+ willUnmount: () => {
+ this.nodeRefs = this.nodeRefs.map(chunk => chunk.filter(nodeRef => nodeRef.cacheKey !== `${mode}_${u_handle}`));
+ }
+ }, hasScreen ? this.renderNodeMenu(peer, {
+ isPresenterNode
+ }) : this.renderSelfViewMenu());
+ }));
+ })));
+ }
+ const source = call.getActiveStream();
+ if (!source) {
+ return null;
+ }
+ const VideoType = source.isLocal ? LocalVideoHiRes : PeerVideoHiRes;
+ const videoNodeRef = REaCt().createRef();
+ return JSX_(VideoType, {
+ key: source.clientId,
+ chatRoom,
+ raisedHandPeers,
+ source,
+ isPresenterNode: source.hasScreen,
+ toggleFullScreen: () => {
+ call.setPinnedCid(source.clientId);
+ },
+ onSpeakerChange: () => {
+ onModeChange(utils.g.THUMBNAIL);
+ },
+ ref: node => {
+ videoNodeRef.current = node;
+ }
+ }, this.renderNodeMenu(source, {
+ key: `${source.clientId}-main`,
+ isMain: true,
+ videoNodeRef,
+ isPresenterNode: source.hasScreen
+ }));
+ }
+ renderNodeMenu(peer, props) {
+ const {
+ mode,
+ chatRoom,
+ ephemeralAccounts,
+ onCallMinimize,
+ onSpeakerChange,
+ onModeChange
+ } = this.props;
+ return JSX_(VideoNodeMenu, (0,esm_extends.A)({
+ mode,
+ privilege: chatRoom.members[peer.userHandle],
+ chatRoom,
+ stream: peer,
+ ephemeralAccounts,
+ onCallMinimize,
+ onSpeakerChange,
+ onModeChange
+ }, props));
+ }
+ renderSelfViewMenu() {
+ const {
+ call,
+ onSpeakerChange
+ } = this.props;
+ return JSX_("div", {
+ className: "node-menu theme-dark-forced"
+ }, JSX_("div", {
+ className: "node-menu-toggle"
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-more-horizontal-thin-outline"
+ })), JSX_("div", {
+ className: "node-menu-content"
+ }, JSX_("ul", null, JSX_("li", null, JSX_(meetings_button.A, {
+ icon: "sprite-fm-mono grid-main",
+ onClick: () => onSpeakerChange(call.getLocalStream())
+ }, JSX_("span", null, l.display_in_main_view))), JSX_("li", null, JSX_(meetings_button.A, {
+ icon: "sprite-fm-mono grid-separate",
+ onClick: this.toggleFloatDetachment
+ }, JSX_("span", null, l.separate_from_grid_button))))));
+ }
+ renderOnHold() {
+ return JSX_("div", {
+ className: "on-hold-overlay"
+ }, JSX_("div", {
+ className: "stream-on-hold theme-light-forced",
+ onClick: this.props.onHoldClick
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-play"
+ }), JSX_("span", null, l[23459])));
+ }
+ renderStreamContainer() {
+ const {
+ call,
+ chatRoom,
+ peers,
+ stayOnEnd,
+ everHadPeers,
+ isOnHold,
+ mode,
+ hasOtherParticipants,
+ onInviteToggle,
+ onStayConfirm,
+ onCallEnd
+ } = this.props;
+ const {
+ screen,
+ video,
+ rest
+ } = filterAndSplitSources(peers, call);
+ const sources = [...screen, ...video, ...rest];
+ const showNotice = sources.length === 0 || !hasOtherParticipants && !call.presenterStreams.has(u_handle);
+ const streamContainer = content => JSX_("div", {
+ ref: this.containerRef,
+ className: `
+ ${NAMESPACE}-container
+ ${showNotice ? 'with-notice' : ''}
+ ${sources.length === 1 && mode === utils.g.THUMBNAIL ? `${this.state.floatDetached ? 'single' : 'dual'}-stream` : ''}
+ `
+ }, content);
+ if (showNotice) {
+ return JSX_(ParticipantsNotice, {
+ call,
+ hasLeft: call.left,
+ chatRoom,
+ everHadPeers,
+ streamContainer,
+ stayOnEnd,
+ isOnHold,
+ onInviteToggle,
+ onStayConfirm,
+ onCallEnd: () => onCallEnd(1)
+ });
+ }
+ return streamContainer(this.renderNodes());
+ }
+ renderToaster() {
+ return JSX_(chatToaster.default, {
+ showDualNotifications: true,
+ hidden: this.props.minimized,
+ onShownToast: toast => {
+ if (toast.options && toast.options.persistent) {
+ this.setState({
+ overlayed: true
+ });
+ }
+ },
+ onHideToast: toast => {
+ if (this.state.overlayed && toast.options && toast.options.persistent) {
+ this.setState({
+ overlayed: false
+ });
+ }
+ }
+ });
+ }
+ specShouldComponentUpdate(nextProps) {
+ if (nextProps.minimized !== this.props.minimized || nextProps.mode !== this.props.mode || nextProps.isFloatingPresenter !== this.props.isFloatingPresenter) {
+ return true;
+ }
+ return null;
+ }
+ componentWillUnmount() {
+ super.componentWillUnmount();
+ chatGlobalEventManager.r.removeEventListener('resize', this.getUniqueId());
+ mBroadcaster.removeListener(this.callHoldListener);
+ }
+ componentDidMount() {
+ super.componentDidMount();
+ this.scaleNodes();
+ chatGlobalEventManager.r.addEventListener('resize', this.getUniqueId(), () => this.scaleNodes());
+ this.callHoldListener = mBroadcaster.addListener('meetings:toggleHold', () => this.scaleNodes(undefined, true));
+ }
+ componentDidUpdate() {
+ super.componentDidMount();
+ const {
+ call,
+ mode,
+ forcedLocal,
+ onSpeakerChange,
+ onModeChange
+ } = this.props;
+ this.scaleNodes();
+ if (this.chunksLength > 0 && this.state.page + 1 > this.chunksLength) {
+ this.movePage(utils.Bq.PREV);
+ }
+ if (mode === utils.g.THUMBNAIL && call.pinnedCid !== null) {
+ this.hasPresenter = true;
+ onSpeakerChange(call.getActiveStream());
+ } else if (mode === utils.g.MAIN && call.pinnedCid === null && !call.presenterStreams.size && this.hasPresenter) {
+ this.hasPresenter = false;
+ onModeChange(utils.g.THUMBNAIL);
+ } else if (mode === utils.g.MAIN && forcedLocal && call.pinnedCid !== 0) {
+ onSpeakerChange(call.getActiveStream());
+ } else if (!call.presenterStreams.size) {
+ this.hasPresenter = false;
+ }
+ }
+ render() {
+ const {
+ overlayed,
+ page,
+ streamsPerPage,
+ floatDetached,
+ wrToggled
+ } = this.state;
+ const {
+ mode,
+ call,
+ chatRoom,
+ minimized,
+ peers,
+ sidebar,
+ hovered,
+ forcedLocal,
+ view,
+ isOnHold,
+ waitingRoomPeers,
+ recorderCid,
+ raisedHandPeers,
+ isFloatingPresenter,
+ onRecordingToggle,
+ onCallMinimize,
+ onCallExpand,
+ onModeChange,
+ onAudioClick,
+ onVideoClick,
+ onCallEnd,
+ onScreenSharingClick,
+ onHoldClick,
+ onSpeakerChange,
+ onParticipantsToggle,
+ setActiveElement
+ } = this.props;
+ return JSX_("div", {
+ ref: this.domRef,
+ className: `
+ ${NAMESPACE}
+ ${sidebar ? '' : 'full'}
+ ${hovered ? 'hovered' : ''}
+ `
+ }, JSX_(external_React_.Suspense, {
+ fallback: JSX_(fallback.A, null)
+ }, waitingRoomPeers && waitingRoomPeers.length ? JSX_(Admit, {
+ chatRoom,
+ call,
+ peers: waitingRoomPeers,
+ expanded: wrToggled,
+ onWrListToggle: this.toggleWaitingRoomList
+ }) : null), this.renderToaster(), minimized ? null : JSX_(REaCt().Fragment, null, JSX_("div", {
+ className: `
+ ${NAMESPACE}-wrapper
+ ${mode === utils.g.MAIN ? 'with-participants-block' : ''}
+ `
+ }, isOnHold ? this.renderOnHold() : overlayed && JSX_("div", {
+ className: "call-overlay"
+ }), this.renderStreamContainer()), mode === utils.g.MAIN && JSX_(ParticipantsBlock, (0,esm_extends.A)({}, this.props, {
+ floatDetached,
+ onSeparate: this.toggleFloatDetachment
+ })), JSX_(StreamHead, {
+ disableCheckingVisibility: true,
+ mode,
+ peers,
+ page,
+ streamsPerPage,
+ floatDetached,
+ chunksLength: this.chunksLength,
+ call,
+ chatRoom,
+ onCallMinimize,
+ onModeChange,
+ onStreamsPerPageChange: streamsPerPage => this.setState({
+ streamsPerPage
+ }),
+ onMovePage: direction => this.movePage(direction),
+ setActiveElement
+ })), minimized || floatDetached ? JSX_(FloatingVideo, {
+ call,
+ peers,
+ mode,
+ view,
+ floatDetached,
+ isOnHold,
+ chatRoom,
+ minimized,
+ sidebar,
+ forcedLocal,
+ isPresenterNode: isFloatingPresenter,
+ wrapperRef: this.domRef,
+ waitingRoomPeers,
+ recorderCid,
+ raisedHandPeers,
+ onRecordingToggle,
+ onAudioClick,
+ onVideoClick,
+ onCallEnd,
+ onScreenSharingClick,
+ onCallMinimize,
+ onMoveIntoGrid: this.toggleFloatDetachment,
+ onCallExpand: async () => {
+ await onCallExpand();
+ this.scaleNodes(undefined, true);
+ },
+ onSpeakerChange,
+ onModeChange,
+ onHoldClick,
+ onParticipantsToggle,
+ onWrListToggle: this.toggleWaitingRoomList
+ }) : null);
+ }
+}
+// EXTERNAL MODULE: ./js/chat/ui/composedTextArea.jsx + 1 modules
+const composedTextArea = REQ_(2558);
+// EXTERNAL MODULE: ./js/chat/ui/historyPanel.jsx + 7 modules
+const historyPanel = REQ_(5522);
+// EXTERNAL MODULE: ./js/ui/perfectScrollbar.jsx
+const perfectScrollbar = REQ_(1301);
+;// ./js/chat/ui/meetings/collapse.jsx
+
+class Collapse extends REaCt().Component {
+ constructor(...args) {
+ super(...args);
+ this.state = {
+ expanded: true
+ };
+ }
+ render() {
+ const {
+ expanded
+ } = this.state;
+ const {
+ heading,
+ badge,
+ children
+ } = this.props;
+ return JSX_("div", {
+ className: "collapse"
+ }, heading && JSX_("div", {
+ className: "collapse-head",
+ onClick: () => this.setState(state => ({
+ expanded: !state.expanded
+ }))
+ }, JSX_("i", {
+ className: `
+ sprite-fm-mono
+ ${expanded ? 'icon-arrow-down' : 'icon-arrow-up'}
+ `
+ }), JSX_("h5", null, heading), badge !== undefined && badge > 0 && JSX_("span", {
+ className: "participants-count"
+ }, badge)), expanded && children);
+ }
+}
+// EXTERNAL MODULE: ./js/chat/ui/contactsPanel/utils.jsx
+const contactsPanel_utils = REQ_(836);
+;// ./js/chat/ui/meetings/participants.jsx
+
+
+
+
+
+
+
+
+
+
+
+
+class Participant extends mixins.w9 {
+ constructor(props) {
+ super(props);
+ this.domRef = REaCt().createRef();
+ this.raisedHandListener = undefined;
+ this.baseIconClass = 'sprite-fm-mono';
+ this.state = {
+ raisedHandPeers: []
+ };
+ this.state.raisedHandPeers = this.props.raisedHandPeers || [];
+ }
+ componentDidMount() {
+ super.componentDidMount();
+ this.props.source.registerConsumer(this);
+ this.raisedHandListener = mBroadcaster.addListener('meetings:raisedHand', raisedHandPeers => this.setState({
+ raisedHandPeers
+ }, () => this.safeForceUpdate()));
+ }
+ componentWillUnmount() {
+ super.componentWillUnmount();
+ this.props.source.deregisterConsumer(this);
+ mBroadcaster.removeListener(this.raisedHandListener);
+ }
+ onAvChange() {
+ this.safeForceUpdate();
+ }
+ render() {
+ const {
+ call,
+ mode,
+ chatRoom,
+ source,
+ contact,
+ handle,
+ name,
+ recorderCid,
+ onCallMinimize,
+ onSpeakerChange,
+ onModeChange
+ } = this.props;
+ const {
+ isOnHold,
+ videoMuted,
+ audioMuted,
+ clientId
+ } = source;
+ const isRelated = (0,contactsPanel_utils.X7)(contact);
+ return JSX_("div", {
+ ref: this.domRef,
+ className: "participant-wrapper"
+ }, this.state.raisedHandPeers.includes(handle) && !isOnHold ? JSX_("div", {
+ className: "participant-signifier"
+ }, JSX_("i", {
+ className: "sprite-fm-uni icon-raise-hand"
+ })) : JSX_(ui_contacts.eu, {
+ contact: M.u[handle]
+ }), JSX_("div", {
+ className: "name"
+ }, handle === u_handle ? JSX_(ui_utils.zT, null, `${name} ${l.me}`) : JSX_(ui_contacts.uA, {
+ contact: M.u[handle],
+ emoji: true
+ }), (0,utils.Cy)(chatRoom, handle) && JSX_("span", null, JSX_("i", {
+ className: `${this.baseIconClass} icon-admin-outline`
+ }))), JSX_("div", {
+ className: "status"
+ }, recorderCid === clientId || recorderCid === call.sfuClient.cid && handle === u_handle ? JSX_("div", {
+ className: "recording-status"
+ }, JSX_("span", null)) : null, JSX_("i", {
+ className: `
+ ${this.baseIconClass}
+ ${videoMuted ? 'icon-video-off-thin-outline inactive' : 'icon-video-thin-outline'}
+ `
+ }), JSX_(AudioLevelIndicator, {
+ source
+ }), JSX_("div", {
+ className: "participants-menu theme-dark-forced"
+ }, JSX_("div", {
+ className: "participants-menu-toggle"
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-side-menu"
+ })), JSX_("div", {
+ className: "participants-menu-content"
+ }, JSX_("ul", null, isRelated ? JSX_("li", null, JSX_(meetings_button.A, {
+ icon: "sprite-fm-mono icon-info",
+ onClick: () => {
+ onCallMinimize();
+ loadSubPage(`fm/chat/contacts/${handle}`);
+ }
+ }, JSX_("span", null, l[6859]))) : null, chatRoom.iAmOperator() && u_handle !== handle && !audioMuted && JSX_("li", null, JSX_(meetings_button.A, {
+ icon: "sprite-fm-mono icon-mic-off-thin-outline",
+ onClick: () => {
+ call.sfuClient.mutePeer(clientId);
+ megaChat.plugins.userHelper.getUserNickname(handle).catch(dump).always(name => {
+ ChatToast.quick(l.you_muted_peer.replace('%NAME', name || ''));
+ });
+ }
+ }, JSX_("span", null, l[16214]))), isRelated ? JSX_("li", null, JSX_(meetings_button.A, {
+ icon: "sprite-fm-mono icon-chat",
+ onClick: () => {
+ onCallMinimize();
+ loadSubPage(`fm/chat/p/${handle}`);
+ }
+ }, JSX_("span", null, l.send_message))) : null, chatRoom.iAmOperator() && u_handle !== handle && JSX_("li", null, JSX_(Privilege, {
+ stream: source,
+ chatRoom
+ })), JSX_("li", null, JSX_(Pin, {
+ mode,
+ stream: source,
+ onSpeakerChange,
+ onModeChange
+ })), call.isPublic && chatRoom.iAmOperator() && u_handle !== handle && JSX_("li", null, JSX_(meetings_button.A, {
+ icon: "sprite-fm-mono icon-disabled-filled",
+ onClick: () => chatRoom.trigger('onRemoveUserRequest', handle)
+ }, JSX_("span", null, l[8867]))))))));
+ }
+}
+class Participants extends mixins.w9 {
+ get allPeersMuted() {
+ return Object.values(this.props.peers).filter(p => p instanceof CallManager2.Peer).every(p => p.audioMuted);
+ }
+ constructor(props) {
+ super(props);
+ this.domRef = REaCt().createRef();
+ this.muteRef = REaCt().createRef();
+ this.NAMESPACE = 'participants';
+ this.FILTER = {
+ IN_CALL: 0,
+ CHAT_PARTICIPANTS: 1
+ };
+ this.state = {
+ filter: this.FILTER.IN_CALL,
+ noResponsePeers: [],
+ ringingPeers: [],
+ allPeersMuted: undefined
+ };
+ this.doHangUp = handle => {
+ if (handle) {
+ const {
+ call,
+ chatRoom
+ } = this.props;
+ return this.isMounted() && this.setState(state => ({
+ ringingPeers: state.ringingPeers.filter(p => p !== handle)
+ }), () => chatRoom.ringUser(handle, call.callId, 0));
+ }
+ };
+ this.doCall = handle => {
+ if (handle) {
+ const {
+ call,
+ chatRoom
+ } = this.props;
+ this.setState(state => ({
+ ringingPeers: [...state.ringingPeers, handle]
+ }), () => {
+ chatRoom.ringUser(handle, call.callId, 1);
+ if (chatRoom.options.w) {
+ let _call$sfuClient;
+ call == null || (_call$sfuClient = call.sfuClient) == null || _call$sfuClient.wrAllowJoin([handle]);
+ }
+ tSleep(40).then(() => {
+ this.doHangUp(handle);
+ return Object.keys(chatRoom.uniqueCallParts).includes(handle) ? null : this.setState(state => ({
+ noResponsePeers: [...state.noResponsePeers, handle]
+ }));
+ });
+ });
+ }
+ };
+ this.getCallState = handle => {
+ const {
+ noResponsePeers,
+ ringingPeers
+ } = this.state;
+ if (this.props.initialCallRinging || ringingPeers.includes(handle)) {
+ return l.call_state_calling;
+ }
+ if (noResponsePeers.includes(handle)) {
+ return l.call_state_no_response;
+ }
+ return l.call_state_not_in_call;
+ };
+ this.getCallParticipants = () => {
+ const {
+ call,
+ mode,
+ chatRoom,
+ recorderCid,
+ raisedHandPeers,
+ onCallMinimize,
+ onSpeakerChange,
+ onModeChange
+ } = this.props;
+ const peers = Object.values(this.props.peers);
+ const $$PEER = peer => peer && JSX_("li", {
+ key: `${peer.clientId || ''}-${peer.userHandle}`
+ }, JSX_(Participant, {
+ call,
+ mode,
+ chatRoom,
+ source: peer.userHandle ? peer : call.getLocalStream(),
+ contact: M.u[peer.userHandle] || undefined,
+ handle: peer.userHandle || u_handle,
+ name: peer.name || M.getNameByHandle(u_handle),
+ recorderCid,
+ raisedHandPeers,
+ onCallMinimize,
+ onSpeakerChange,
+ onModeChange
+ }));
+ let $$RAISED = [];
+ for (const userHandle of call.sfuClient.raisedHands) {
+ const peer = peers.find(p => (p.userHandle || p.localPeerStream.userHandle) === userHandle);
+ $$RAISED = [...$$RAISED, $$PEER(peer)];
+ }
+ const $$REST = peers.filter(p => ![...call.sfuClient.raisedHands].includes(p.userHandle || p.localPeerStream.userHandle)).sort((a, b) => !!a.userHandle - !!b.userHandle).map(peer => $$PEER(peer));
+ return JSX_("ul", null, $$RAISED, $$REST);
+ };
+ this.getChatParticipants = () => {
+ const {
+ chatRoom,
+ initialCallRinging
+ } = this.props;
+ const {
+ ringingPeers
+ } = this.state;
+ const callParticipants = Object.keys(chatRoom.uniqueCallParts);
+ const chatParticipants = chatRoom.getParticipantsExceptMe().filter(h => !callParticipants.includes(h));
+ if (chatParticipants != null && chatParticipants.length) {
+ return JSX_(REaCt().Fragment, null, chatParticipants.length > 1 ? (() => {
+ const isRingingAll = initialCallRinging || JSON.stringify(ringingPeers) === JSON.stringify(chatParticipants);
+ return JSX_(meetings_button.A, {
+ className: `
+ mega-button
+ action
+ neutral
+ call-control-all
+ ${isRingingAll ? 'disabled' : ''}
+ `,
+ icon: "sprite-fm-mono phone-call-01",
+ onClick: () => isRingingAll ? null : chatParticipants.map(handle => this.doCall(handle))
+ }, l.call_all_button);
+ })() : null, JSX_("ul", null, chatParticipants.map(handle => {
+ const contact = M.u[handle];
+ const isRinging = initialCallRinging || ringingPeers.includes(handle);
+ return JSX_("li", {
+ key: handle
+ }, JSX_(ui_contacts.eu, {
+ contact
+ }), JSX_("div", {
+ className: "name"
+ }, JSX_(ui_contacts.uA, {
+ contact: M.u[handle],
+ emoji: true
+ }), JSX_("span", {
+ className: `
+ user-card-presence
+ ${megaChat.userPresenceToCssClass(contact.presence)}
+ `
+ }), (0,utils.Cy)(chatRoom, handle) && JSX_("span", null, JSX_("i", {
+ className: "sprite-fm-mono icon-admin-outline"
+ })), JSX_("div", {
+ className: "call-state"
+ }, this.getCallState(handle))), isRinging ? null : JSX_("div", {
+ className: "call-control"
+ }, JSX_(meetings_button.A, {
+ className: "mega-button action neutral",
+ onClick: () => this.doCall(handle)
+ }, l.call_button)));
+ })));
+ }
+ return JSX_("div", {
+ className: "participants-empty"
+ }, JSX_("span", {
+ className: "empty-check-icon"
+ }), JSX_("h3", null, l.all_participants_in_call));
+ };
+ this.renderParticipantsList = () => {
+ const {
+ filter,
+ raisedHandPeers
+ } = this.state;
+ return JSX_("div", {
+ className: `
+ participants-list
+ ${filter === this.FILTER.IN_CALL ? '' : 'with-chat-participants'}
+ ${this.props.guest ? 'guest' : ''}
+ `
+ }, JSX_(perfectScrollbar.O, {
+ filter,
+ raisedHandPeers,
+ options: {
+ 'suppressScrollX': true
+ }
+ }, filter === this.FILTER.IN_CALL ? this.getCallParticipants() : this.getChatParticipants()));
+ };
+ this.renderMuteAllControl = () => {
+ const {
+ allPeersMuted
+ } = this.state;
+ const simpletip = {
+ label: l.mute_all_tooltip,
+ position: 'top',
+ className: 'theme-dark-forced'
+ };
+ return JSX_(meetings_button.A, {
+ ref: this.muteRef,
+ simpletip: allPeersMuted ? null : simpletip,
+ className: `
+ mega-button
+ action
+ ${this.NAMESPACE}-mute
+ ${allPeersMuted ? 'disabled' : ''}
+ `,
+ icon: "sprite-fm-mono icon-mic-off-thin-outline",
+ onClick: () => {
+ let _this$muteRef, _muteRef$buttonRef;
+ const muteRef = (_this$muteRef = this.muteRef) == null ? void 0 : _this$muteRef.current;
+ const buttonRef = (_muteRef$buttonRef = muteRef.buttonRef) == null ? void 0 : _muteRef$buttonRef.current;
+ return allPeersMuted ? null : this.setState({
+ allPeersMuted: true
+ }, () => {
+ this.props.call.sfuClient.mutePeer();
+ ChatToast.quick(l.you_muted_all_peers);
+ if (buttonRef) {
+ $(buttonRef).trigger('simpletipClose');
+ }
+ });
+ }
+ }, allPeersMuted ? l.all_muted : l.mute_all);
+ };
+ this.state.allPeersMuted = this.allPeersMuted;
+ }
+ componentWillUnmount() {
+ super.componentWillUnmount();
+ ['onCallPeerJoined', 'onPeerAvChange'].map(event => this.props.chatRoom.off(`${event}.${this.NAMESPACE}`));
+ }
+ componentDidMount() {
+ super.componentDidMount();
+ this.props.chatRoom.rebind(`onCallPeerJoined.${this.NAMESPACE}`, (ev, userHandle) => {
+ const {
+ noResponsePeers,
+ ringingPeers
+ } = this.state;
+ this.setState({
+ noResponsePeers: noResponsePeers.includes(userHandle) ? noResponsePeers.filter(h => h !== userHandle) : noResponsePeers,
+ ringingPeers: ringingPeers.includes(userHandle) ? ringingPeers.filter(h => h !== userHandle) : ringingPeers
+ });
+ }).rebind(`onPeerAvChange.${this.NAMESPACE}`, () => this.isMounted() && this.setState({
+ allPeersMuted: this.allPeersMuted
+ }));
+ }
+ render() {
+ const {
+ IN_CALL,
+ CHAT_PARTICIPANTS
+ } = this.FILTER;
+ const {
+ withInvite,
+ chatRoom,
+ peers,
+ onInviteToggle
+ } = this.props;
+ const {
+ filter
+ } = this.state;
+ return JSX_("div", {
+ ref: this.domRef,
+ className: this.NAMESPACE
+ }, chatRoom.type === 'private' ? null : JSX_("div", {
+ className: `${this.NAMESPACE}-nav`
+ }, JSX_(meetings_button.A, {
+ className: filter === IN_CALL ? 'active' : '',
+ onClick: () => this.setState({
+ filter: IN_CALL
+ })
+ }, l.call_heading_in_call), JSX_(meetings_button.A, {
+ className: filter === CHAT_PARTICIPANTS ? 'active' : '',
+ onClick: () => this.setState({
+ filter: CHAT_PARTICIPANTS
+ })
+ }, l.call_heading_not_in_call)), filter === IN_CALL ? JSX_(REaCt().Fragment, null, JSX_("div", {
+ className: `${this.NAMESPACE}-actions`
+ }, withInvite && JSX_(meetings_button.A, {
+ className: `
+ mega-button
+ action
+ ${this.NAMESPACE}-invite
+ `,
+ icon: "sprite-fm-mono icon-user-plus-thin-outline",
+ onClick: onInviteToggle
+ }, l[8726]), chatRoom.iAmOperator() && this.renderMuteAllControl()), JSX_(Collapse, (0,esm_extends.A)({}, this.props, {
+ filter,
+ heading: l[16217],
+ badge: (peers == null ? void 0 : peers.length) + 1
+ }), this.renderParticipantsList())) : this.renderParticipantsList());
+ }
+}
+;// ./js/chat/ui/meetings/guest.jsx
+
+
+class Guest extends REaCt().Component {
+ constructor(...args) {
+ super(...args);
+ this.state = {
+ copy: ''
+ };
+ }
+ componentDidMount() {
+ this.setState({
+ copy: `${l.free_storage_info__call.replace('%s', bytesToSize(mega.bstrg, 0))}`
+ });
+ }
+ render() {
+ const {
+ copy
+ } = this.state;
+ return JSX_("div", {
+ className: "guest-register"
+ }, JSX_("div", {
+ className: "guest-register-content"
+ }, JSX_(meetings_button.A, {
+ className: "close-guest-register",
+ icon: "icon-close-component",
+ onClick: this.props.onGuestClose
+ }, JSX_("span", null, l[148])), JSX_("div", null, JSX_("i", {
+ className: "sprite-fm-illustration-wide registration"
+ }), JSX_("span", null, copy)), JSX_(meetings_button.A, {
+ className: "mega-button positive register-button",
+ onClick: () => loadSubPage('register')
+ }, l.sign_up_btn)));
+ }
+}
+;// ./js/chat/ui/meetings/sidebar.jsx
+
+
+
+
+
+
+
+
+const inviteAllowed = chatRoom => {
+ if (chatRoom) {
+ return chatRoom.type !== 'private' && !!(chatRoom.options[MCO_FLAGS.OPEN_INVITE] || (0,utils.Cy)(chatRoom, u_handle) || chatRoom.publicLink);
+ }
+ return false;
+};
+class Sidebar extends mixins.w9 {
+ constructor(...args) {
+ super(...args);
+ this.domRef = REaCt().createRef();
+ this.historyPanel = null;
+ this.renderHead = ({
+ title,
+ children
+ }) => {
+ return JSX_("div", {
+ className: "sidebar-head"
+ }, JSX_(meetings_button.A, {
+ simpletip: {
+ label: l.close_sidebar,
+ className: 'theme-dark-forced'
+ },
+ className: "mega-button action small left",
+ icon: "icon-collapse-right",
+ onClick: this.props.onSidebarClose
+ }, JSX_("span", null, l.close_sidebar)), JSX_("h2", null, title), children || null);
+ };
+ this.renderParticipantsView = () => {
+ const {
+ call,
+ mode,
+ peers,
+ initialCallRinging,
+ chatRoom,
+ guest,
+ recorderCid,
+ raisedHandPeers,
+ onInviteToggle,
+ onCallMinimize,
+ onSpeakerChange,
+ onModeChange
+ } = this.props;
+ const withInvite = inviteAllowed(chatRoom);
+ return JSX_(REaCt().Fragment, null, this.renderHead({
+ title: l[16217]
+ }), JSX_(Participants, {
+ withInvite,
+ call,
+ mode,
+ peers,
+ initialCallRinging,
+ chatRoom,
+ guest,
+ recorderCid,
+ raisedHandPeers,
+ onInviteToggle,
+ onCallMinimize,
+ onSpeakerChange,
+ onModeChange
+ }));
+ };
+ this.renderChatView = () => {
+ const {
+ chatRoom,
+ typingAreaText,
+ onDeleteMessage,
+ onTypingAreaChanged
+ } = this.props;
+ return JSX_(REaCt().Fragment, null, this.renderHead({
+ title: l.chats
+ }), JSX_(historyPanel.A, {
+ ref: ref => {
+ this.historyPanel = ref;
+ },
+ chatRoom,
+ className: "in-call",
+ onDeleteClicked: onDeleteMessage
+ }), JSX_(composedTextArea.A, {
+ chatRoom,
+ parent: this,
+ containerRef: this.domRef,
+ typingAreaText,
+ onTypingAreaChanged
+ }));
+ };
+ }
+ render() {
+ const {
+ view,
+ guest,
+ onGuestClose
+ } = this.props;
+ return JSX_("div", {
+ className: "sidebar-wrapper theme-dark-forced"
+ }, JSX_("div", {
+ ref: this.domRef,
+ className: `
+ sidebar
+ ${view === utils.gR.CHAT ? 'chat-opened' : 'theme-dark-forced'}
+ `
+ }, view === utils.gR.PARTICIPANTS && this.renderParticipantsView(), view === utils.gR.CHAT && this.renderChatView(), guest && view !== utils.gR.CHAT && JSX_(Guest, {
+ onGuestClose
+ })));
+ }
+}
+;// ./js/chat/ui/meetings/workflow/invite/search.jsx
+let _Search;
+
+
+class Search extends REaCt().Component {
+ render() {
+ const {
+ value,
+ placeholder,
+ onChange
+ } = this.props;
+ return JSX_("div", {
+ className: `${Invite.NAMESPACE}-field`
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-preview-reveal"
+ }), JSX_("input", {
+ type: "text",
+ autoFocus: true,
+ placeholder: l[23750].replace('[X]', placeholder),
+ ref: Search.inputRef,
+ value,
+ onChange
+ }));
+ }
+}
+_Search = Search;
+Search.inputRef = REaCt().createRef();
+Search.focus = () => {
+ return _Search.inputRef && _Search.inputRef.current && _Search.inputRef.current.focus();
+};
+;// ./js/chat/ui/meetings/workflow/invite/footer.jsx
+
+
+const Footer = ({
+ selected,
+ onClose,
+ onAdd
+}) => {
+ return JSX_("footer", null, JSX_("div", {
+ className: "footer-container"
+ }, JSX_(meetings_button.A, {
+ className: "mega-button",
+ onClick: onClose
+ }, l.msg_dlg_cancel), JSX_(meetings_button.A, {
+ className: `
+ mega-button
+ positive
+ ${selected.length > 0 ? '' : 'disabled'}
+ `,
+ onClick: onAdd
+ }, l.add)));
+};
+ const footer = Footer;
+;// ./js/chat/ui/meetings/workflow/invite/nil.jsx
+
+
+const Nil = () => {
+ return JSX_("div", {
+ className: `${Invite.NAMESPACE}-nil`
+ }, JSX_("div", {
+ className: "fm-empty-contacts-bg"
+ }), JSX_("h2", null, HAS_CONTACTS() ? l[8674] : l[784]));
+};
+ const nil = Nil;
+// EXTERNAL MODULE: ./js/chat/ui/link.jsx
+const ui_link = REQ_(4649);
+;// ./js/chat/ui/meetings/workflow/invite/invite.jsx
+
+
+
+
+
+
+
+
+
+
+
+const HAS_CONTACTS = () => {
+ const keys = M.u.keys();
+ for (let i = 0; i < keys.length; i++) {
+ if (M.u[keys[i]].c === 1) {
+ return true;
+ }
+ }
+};
+class Invite extends REaCt().Component {
+ constructor(props) {
+ super(props);
+ this.domRef = REaCt().createRef();
+ this.wrapperRef = REaCt().createRef();
+ this.state = {
+ loading: true,
+ value: '',
+ searching: false,
+ contacts: [],
+ contactsInitial: [],
+ frequents: [],
+ frequentsInitial: [],
+ selected: [],
+ excluded: [],
+ input: false
+ };
+ this.getSortedContactsList = (frequents, excluded) => {
+ frequents = frequents || this.state.frequents;
+ excluded = excluded || this.state.excluded;
+ const filteredContacts = [];
+ (this.props.contacts || M.u).forEach(contact => {
+ if (contact.c === 1 && !frequents.includes(contact.u) && !excluded.includes(contact.u)) {
+ filteredContacts.push(contact);
+ }
+ });
+ const sortFn = M.getSortByNameFn2(1);
+ filteredContacts.sort((a, b) => sortFn(a, b));
+ return filteredContacts;
+ };
+ this.doMatch = (value, collection) => {
+ value = value.toLowerCase();
+ return collection.filter(contact => {
+ contact = typeof contact === 'string' ? M.getUserByHandle(contact) : contact;
+ const name = M.getNameByHandle(contact.u || contact).toLowerCase();
+ const email = contact.m && contact.m.toLowerCase();
+ return name.includes(value) || email.includes(value);
+ });
+ };
+ this.handleSearch = ev => {
+ const {
+ value
+ } = ev.target;
+ const searching = value.length >= 2;
+ const frequents = searching ? this.doMatch(value, this.state.frequentsInitial) : this.state.frequentsInitial;
+ const contacts = searching ? this.doMatch(value, this.state.contactsInitial) : this.state.contactsInitial;
+ this.setState({
+ value,
+ searching,
+ frequents,
+ contacts
+ }, () => {
+ const wrapperRef = this.wrapperRef && this.wrapperRef.current;
+ if (wrapperRef && searching) {
+ wrapperRef.reinitialise();
+ wrapperRef.scrollToY(0);
+ }
+ });
+ };
+ this.handleSelect = userHandle => {
+ this.setState(state => ({
+ selected: state.selected.includes(userHandle) ? state.selected.filter(c => c !== userHandle) : [...state.selected, userHandle]
+ }), () => Search.focus());
+ };
+ this.handleAdd = () => {
+ const {
+ selected
+ } = this.state;
+ const {
+ call,
+ chatRoom,
+ onClose
+ } = this.props;
+ if (selected.length > 0) {
+ if (chatRoom.options.w) {
+ let _call$sfuClient;
+ call == null || (_call$sfuClient = call.sfuClient) == null || _call$sfuClient.wrAllowJoin(selected);
+ }
+ chatRoom == null || chatRoom.trigger('onAddUserRequest', [selected]);
+ onClose == null || onClose();
+ }
+ };
+ this.getFrequentContacts = () => megaChat.getFrequentContacts().then(response => {
+ if (!this.domRef.current) {
+ return;
+ }
+ const frequents = [];
+ const maxFreq = Math.max(response.length - ui_contacts.lO, 0);
+ for (let i = response.length - 1; i >= maxFreq; i--) {
+ const contact = response[i];
+ if (!this.state.excluded.includes(contact.userId)) {
+ frequents.push(contact.userId);
+ }
+ }
+ this.setState({
+ frequents,
+ frequentsInitial: frequents,
+ contacts: this.getSortedContactsList(frequents),
+ loading: false
+ });
+ });
+ this.getFilteredFrequents = () => {
+ const {
+ frequents,
+ selected
+ } = this.state;
+ if (frequents.length === 0) {
+ return false;
+ }
+ return frequents.map(userHandle => {
+ return JSX_(ui_contacts.nB, {
+ key: userHandle,
+ contact: M.u[userHandle],
+ chatRoom: false,
+ className: `
+ contacts-search
+ short
+ ${selected.includes(userHandle) ? 'selected' : ''}
+ `,
+ noContextButton: true,
+ noContextMenu: true,
+ selectable: true,
+ onClick: () => this.handleSelect(userHandle)
+ });
+ });
+ };
+ this.getFilteredContacts = () => {
+ const {
+ contacts,
+ frequents,
+ excluded,
+ selected
+ } = this.state;
+ const $$CONTACTS = [];
+ for (let i = 0; i < contacts.length; i++) {
+ const contact = contacts[i];
+ const {
+ u: userHandle
+ } = contact;
+ if (!frequents.includes(userHandle) && !excluded.includes(userHandle)) {
+ $$CONTACTS.push(JSX_(ui_contacts.nB, {
+ key: userHandle,
+ contact,
+ chatRoom: false,
+ className: `
+ contacts-search
+ short
+ ${selected.includes(userHandle) ? 'selected' : ''}
+ `,
+ noContextButton: true,
+ noContextMenu: true,
+ selectable: true,
+ onClick: () => this.handleSelect(userHandle)
+ }));
+ }
+ }
+ return $$CONTACTS.length === 0 ? false : $$CONTACTS;
+ };
+ this.renderContent = () => {
+ const frequentContacts = this.getFilteredFrequents();
+ const contactsFiltered = this.getFilteredContacts();
+ if (HAS_CONTACTS()) {
+ const {
+ contacts,
+ frequents
+ } = this.state;
+ const $$RESULT_TABLE = (header, children) => JSX_("div", {
+ className: "contacts-search-subsection"
+ }, JSX_("div", {
+ className: "contacts-list-header"
+ }, header), JSX_("div", {
+ className: "contacts-search-list"
+ }, children));
+ if (frequents.length === 0 && contacts.length === 0) {
+ return JSX_(nil, null);
+ }
+ return JSX_(perfectScrollbar.O, {
+ ref: this.wrapperRef,
+ options: {
+ 'suppressScrollX': true
+ }
+ }, frequentContacts ? $$RESULT_TABLE(l[20141], frequentContacts) : '', contactsFiltered ? $$RESULT_TABLE(l[165], contactsFiltered) : '');
+ }
+ return JSX_(nil, null);
+ };
+ this.renderLoading = () => {
+ return JSX_("div", {
+ className: `${Invite.NAMESPACE}-loading`
+ }, JSX_("h2", null, l[1456]));
+ };
+ this.state.excluded = this.props.chatRoom ? this.props.chatRoom.getParticipantsExceptMe() : [];
+ this.state.contacts = this.state.contactsInitial = this.getSortedContactsList();
+ }
+ componentDidMount() {
+ this.getFrequentContacts();
+ }
+ render() {
+ const {
+ NAMESPACE
+ } = Invite;
+ const {
+ value,
+ loading,
+ selected,
+ contactsInitial
+ } = this.state;
+ const {
+ chatRoom,
+ call,
+ onClose
+ } = this.props;
+ const {
+ isMeeting,
+ publicLink
+ } = chatRoom || {};
+ const callPartsLength = chatRoom.getCallParticipants().length;
+ return JSX_(modalDialogs.A.ModalDialog, (0,esm_extends.A)({}, this.state, {
+ ref: this.domRef,
+ name: NAMESPACE,
+ className: `
+ ${NAMESPACE}
+ dialog-template-tool
+ `,
+ callPartsLength,
+ hideOverlay: true,
+ onClose
+ }), JSX_("div", {
+ className: `${NAMESPACE}-head`
+ }, JSX_("h2", null, isMeeting ? l.invite_participants : l[8726]), isMeeting && publicLink && JSX_(REaCt().Fragment, null, JSX_("p", null, l.copy_and_share), JSX_("div", {
+ className: "link-input-container"
+ }, JSX_(meetings_button.A, {
+ className: `mega-button large positive ${publicLink ? '' : 'disabled'}`,
+ onClick: () => publicLink && copyToClipboard(`${getBaseUrl()}/${publicLink}`, l[371])
+ }, !publicLink ? l[7006] : l[1394]))), HAS_CONTACTS() && JSX_(Search, {
+ value,
+ placeholder: contactsInitial.length,
+ onChange: this.handleSearch
+ }), call.sfuClient.callLimits && call.sfuClient.callLimits.usr && callPartsLength >= call.sfuClient.callLimits.usr && JSX_("div", {
+ className: `${NAMESPACE}-user-limit-banner`
+ }, call.organiser === u_handle ? (0,ui_utils.lI)(l.invite_limit_banner_organiser, '[A]', ui_link.A, {
+ className: 'invite-limit-link',
+ onClick() {
+ window.open(`${getBaseUrl()}/pro`, '_blank', 'noopener,noreferrer');
+ eventlog(500260);
+ }
+ }) : l.invite_limit_banner_host)), JSX_("div", {
+ className: "fm-dialog-body"
+ }, JSX_("div", {
+ className: `${NAMESPACE}-contacts`
+ }, loading ? this.renderLoading() : this.renderContent())), JSX_(footer, {
+ selected,
+ onAdd: this.handleAdd,
+ onClose
+ }));
+ }
+}
+Invite.NAMESPACE = 'invite-meeting';
+;// ./js/chat/ui/meetings/workflow/ephemeral.jsx
+
+
+
+const Ephemeral = ({
+ ephemeralAccounts,
+ onClose
+}) => {
+ const ephemeralAccount = ephemeralAccounts && ephemeralAccounts[ephemeralAccounts.length - 1];
+ return JSX_(modalDialogs.A.ModalDialog, {
+ name: "ephemeral-dialog",
+ dialogType: "message",
+ icon: "sprite-fm-uni icon-info",
+ title: JSX_(ui_contacts.uA, {
+ emoji: true,
+ contact: M.u[ephemeralAccount]
+ }),
+ noCloseOnClickOutside: true,
+ buttons: [{
+ key: 'ok',
+ label: l[81],
+ onClick: onClose
+ }],
+ onClose
+ }, JSX_("p", null, l.ephemeral_info));
+};
+ const workflow_ephemeral = Ephemeral;
+;// ./js/chat/ui/meetings/offline.jsx
+
+
+const Offline = ({
+ onCallEnd,
+ onClose
+}) => {
+ return JSX_(modalDialogs.A.ModalDialog, {
+ name: "reconnect-dialog",
+ dialogType: "message",
+ icon: "sprite-fm-uni icon-warning",
+ title: l.no_internet,
+ noCloseOnClickOutside: true,
+ buttons: [{
+ key: 'ok',
+ label: l.msg_dlg_cancel,
+ onClick: onClose
+ }, {
+ key: 'leave',
+ label: l[5883],
+ className: 'negative',
+ onClick: onCallEnd
+ }],
+ onClose
+ }, JSX_("p", null, l.no_connection));
+};
+ const meetings_offline = Offline;
+// EXTERNAL MODULE: ./js/chat/ui/conversationpanel.jsx + 10 modules
+const conversationpanel = REQ_(5677);
+;// ./js/chat/ui/meetings/streamControls.jsx
+
+
+
+
+
+
+
+
+
+
+class StreamControls extends mixins.w9 {
+ constructor(...args) {
+ super(...args);
+ this.domRef = REaCt().createRef();
+ this.endContainerRef = REaCt().createRef();
+ this.endButtonRef = REaCt().createRef();
+ this.SIMPLETIP = {
+ position: 'top',
+ offset: 8,
+ className: 'theme-dark-forced'
+ };
+ this.state = {
+ endCallOptions: false,
+ endCallPending: false,
+ devices: {},
+ audioSelectDropdown: false,
+ videoSelectDropdown: false,
+ loading: false,
+ muteSpeak: false
+ };
+ this.LeaveButton = (0,hostsObserver.C)(({
+ hasHost,
+ chatRoom,
+ confirmLeave,
+ onLeave
+ }) => {
+ const doLeave = () => hasHost(chatRoom.call ? chatRoom.call.peers.map(a => a.userHandle) : []) ? onLeave() : confirmLeave({
+ title: l.assign_host_leave_call,
+ body: l.assign_host_leave_call_details,
+ cta: l.assign_host_button,
+ altCta: l.leave_anyway
+ });
+ return JSX_(meetings_button.A, {
+ className: "mega-button",
+ onClick: () => {
+ const {
+ recorderCid,
+ call,
+ onRecordingToggle
+ } = this.props;
+ return recorderCid && recorderCid === call.sfuClient.cid ? (0,utils.sX)(doLeave, onRecordingToggle) : doLeave();
+ }
+ }, JSX_("span", null, l.leave));
+ });
+ this.setActiveElement = forced => this.props.setActiveElement(forced || this.state.audioSelectDropdown || this.state.videoSelectDropdown || this.state.endCallOptions);
+ this.handleMousedown = ({
+ target
+ }) => {
+ if (this.isMounted()) {
+ const {
+ audioSelectDropdown,
+ videoSelectDropdown,
+ endCallOptions
+ } = this.state;
+ return (audioSelectDropdown || videoSelectDropdown || endCallOptions) && ['audio-sources', 'video-sources', 'meetings-end-options'].some(selector => {
+ let _document$querySelect;
+ return (_document$querySelect = document.querySelector(`.${selector}`)) == null ? void 0 : _document$querySelect.contains(target);
+ }) ? 0x4B1D : this.setState({
+ audioSelectDropdown: false,
+ videoSelectDropdown: false,
+ endCallOptions: false
+ }, this.setActiveElement);
+ }
+ };
+ this.renderDebug = () => {
+ return JSX_("div", {
+ className: "stream-debug",
+ style: {
+ position: 'absolute',
+ left: 25,
+ bottom: 36,
+ display: 'flex',
+ alignItems: 'center',
+ color: 'tomato'
+ }
+ }, JSX_(meetings_button.A, {
+ className: "mega-button round small theme-dark-forced positive",
+ simpletip: {
+ ...this.SIMPLETIP,
+ label: 'Add Stream'
+ },
+ onClick: () => this.props.onStreamToggle(utils.hK.ADD)
+ }, JSX_("span", null, l.add)), JSX_(meetings_button.A, {
+ className: "mega-button round small theme-dark-forced negative",
+ simpletip: {
+ ...this.SIMPLETIP,
+ label: 'Remove Stream'
+ },
+ onClick: () => this.props.peers.length > 1 && this.props.onStreamToggle(utils.hK.REMOVE)
+ }, JSX_("span", null, l[83])), JSX_("span", null, this.props.peers.length + 1));
+ };
+ this.renderEndCallOptions = () => {
+ let _this$endContainerRef;
+ const {
+ call,
+ chatRoom,
+ recorderCid,
+ onRecordingToggle,
+ onCallEnd
+ } = this.props;
+ const {
+ endCallOptions,
+ endCallPending
+ } = this.state;
+ const doEnd = () => this.setState({
+ endCallPending: true
+ }, () => chatRoom.endCallForAll());
+ const endContainerRef = (_this$endContainerRef = this.endContainerRef) == null ? void 0 : _this$endContainerRef.current;
+ return JSX_("div", (0,esm_extends.A)({}, endCallOptions && {
+ style: (({
+ left,
+ top
+ }) => ({
+ left,
+ top
+ }))(endContainerRef.getBoundingClientRect())
+ }, {
+ className: `
+ meetings-end-options
+ theme-dark-forced
+ ${endCallOptions ? '' : 'hidden'}
+ `
+ }), JSX_("div", {
+ className: "meetings-end-options-content"
+ }, JSX_(this.LeaveButton, {
+ chatRoom,
+ recorderCid,
+ participants: chatRoom.getCallParticipants(),
+ onLeave: onCallEnd,
+ onConfirmDenied: onCallEnd
+ }), JSX_(meetings_button.A, {
+ className: `
+ mega-button
+ positive
+ ${endCallPending ? 'disabled' : ''}
+ `,
+ onClick: () => {
+ if (recorderCid && recorderCid === call.sfuClient.cid) {
+ return renderEndConfirm(doEnd, onRecordingToggle);
+ }
+ return doEnd();
+ }
+ }, JSX_("span", null, l.end_for_all))));
+ };
+ this.renderEndCall = () => {
+ const {
+ call,
+ chatRoom,
+ peers,
+ recorderCid,
+ onRecordingToggle,
+ onCallEnd
+ } = this.props;
+ return JSX_("div", {
+ ref: this.endContainerRef,
+ className: "end-call-container",
+ onClick: () => {
+ if (chatRoom.type !== 'private' && peers.length && (0,utils.Cy)(chatRoom, u_handle)) {
+ return this.setState(state => ({
+ endCallOptions: !state.endCallOptions
+ }), () => {
+ if (this.endButtonRef) {
+ $(this.endButtonRef.current).trigger('simpletipClose');
+ }
+ this.setActiveElement();
+ });
+ }
+ if (recorderCid && recorderCid === call.sfuClient.cid) {
+ return chatRoom.type === 'private' ? renderEndConfirm(onCallEnd, onRecordingToggle) : (0,utils.sX)(onCallEnd, onRecordingToggle);
+ }
+ return onCallEnd();
+ }
+ }, JSX_(ui_utils.Ay.RenderTo, {
+ element: document.body
+ }, this.renderEndCallOptions()), JSX_(meetings_button.A, {
+ simpletip: {
+ ...this.SIMPLETIP,
+ label: l[5884]
+ },
+ className: "mega-button theme-dark-forced round negative end-call call-action",
+ icon: "icon-phone-02",
+ didMount: button => {
+ this.endButtonRef = button.buttonRef;
+ }
+ }), JSX_("span", null, l.end_button));
+ };
+ this.renderSourceOpener = ({
+ type,
+ eventId
+ }) => {
+ return JSX_("div", {
+ className: `
+ input-source-opener
+ button
+ ${this.state[type] ? 'active-dropdown' : ''}
+ `,
+ onClick: async ev => {
+ ev.stopPropagation();
+ this.setState(() => ({
+ loading: true
+ }), async () => {
+ const devices = await this.updateMediaDevices();
+ const updated = JSON.stringify(devices) !== JSON.stringify(this.state.devices);
+ this.setState(state => ({
+ loading: false,
+ audioSelectDropdown: false,
+ videoSelectDropdown: false,
+ devices: updated ? devices : this.state.devices,
+ [type]: !state[type]
+ }), () => {
+ const {
+ audioSelectDropdown,
+ videoSelectDropdown
+ } = this.state;
+ this.props.setActiveElement(audioSelectDropdown || videoSelectDropdown);
+ eventlog(eventId);
+ });
+ });
+ }
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-arrow-up"
+ }));
+ };
+ this.handleDeviceChange = () => {
+ this.micDefaultRenamed = false;
+ this.updateMediaDevices().always(devices => {
+ let _sfuClient$localAudio, _oldDevices$audioIn;
+ if (!this.isMounted()) {
+ return;
+ }
+ const {
+ devices: oldDevices
+ } = this.state;
+ const {
+ sfuClient,
+ av
+ } = this.props.call;
+ if (av & Av.Audio && !SfuClient.micDeviceId && ((_sfuClient$localAudio = sfuClient.localAudioTrack()) == null ? void 0 : _sfuClient$localAudio.getCapabilities().deviceId) === 'default' && oldDevices != null && (_oldDevices$audioIn = oldDevices.audioIn) != null && _oldDevices$audioIn.default && devices.audioIn.default && oldDevices.audioIn.default !== devices.audioIn.default) {
+ for (const [key, value] of Object.entries(devices.audioIn)) {
+ if (key !== 'default' && devices.audioIn.default.indexOf(value) > -1) {
+ sfuClient.setMicDevice(key).then(() => SfuClient.persistMicDevice(null));
+ break;
+ }
+ }
+ }
+ this.setState({
+ devices,
+ audioSelectDropdown: false,
+ videoSelectDropdown: false
+ }, this.setActiveElement);
+ });
+ };
+ this.renderOnboardingRaise = () => {
+ const {
+ chatRoom,
+ onOnboardingRaiseDismiss
+ } = this.props;
+ return JSX_("div", {
+ className: "meetings-call-onboarding"
+ }, JSX_("div", {
+ className: "mega-dialog mega-onboarding-dialog dialog-template-message onboarding-raise",
+ id: "ob-dialog",
+ role: "dialog",
+ "aria-labelledby": "ob-dialog-title",
+ "aria-modal": "true"
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-tooltip-arrow tooltip-arrow bottom",
+ id: "ob-dialog-arrow"
+ }), JSX_("header", null, JSX_("div", null, JSX_("h2", {
+ id: "ob-dialog-title"
+ }, l.raise_onboarding_title), JSX_("p", {
+ id: "ob-dialog-text"
+ }, chatRoom.isMeeting ? l.raise_onboarding_body : l.raise_onboarding_group_body))), JSX_("footer", null, JSX_("div", {
+ className: "footer-container"
+ }, JSX_("button", {
+ className: "mega-button js-next small theme-light-forced",
+ onClick: onOnboardingRaiseDismiss
+ }, JSX_("span", null, l.ok_button))))));
+ };
+ this.renderRaiseButton = () => {
+ const {
+ call,
+ raisedHandPeers,
+ onboardingRaise
+ } = this.props;
+ const isOnHold = call.av & Av.onHold;
+ const hasRaisedHand = raisedHandPeers.includes(u_handle);
+ return JSX_("li", {
+ className: isOnHold ? 'disabled' : ''
+ }, onboardingRaise && this.renderOnboardingRaise(), JSX_(meetings_button.A, {
+ className: `
+ mega-button
+ theme-light-forced
+ call-action
+ round
+ ${isOnHold ? 'disabled' : ''}
+ ${hasRaisedHand ? 'with-fill' : ''}
+ `,
+ icon: "icon-raise-hand",
+ onClick: isOnHold ? null : () => {
+ if (hasRaisedHand) {
+ call.sfuClient.lowerHand();
+ eventlog(500311);
+ return;
+ }
+ call.sfuClient.raiseHand();
+ eventlog(500249);
+ }
+ }), JSX_("span", null, l.raise_button));
+ };
+ }
+ renderSoundDropdown() {
+ const {
+ call
+ } = this.props;
+ const {
+ micDeviceId,
+ audioOutDeviceId
+ } = SfuClient;
+ const {
+ audioIn = {},
+ audioOut = {}
+ } = this.state.devices;
+ let selectedIn;
+ const inTrack = call.sfuClient.localAudioTrack();
+ if (inTrack) {
+ const {
+ deviceId
+ } = inTrack.getCapabilities();
+ selectedIn = deviceId in audioIn ? deviceId : 'default';
+ if (deviceId === 'default' && inTrack.label !== audioIn.default) {
+ this.micDefaultRenamed = inTrack.label;
+ }
+ } else if (micDeviceId) {
+ selectedIn = micDeviceId in audioIn ? micDeviceId : 'default';
+ } else {
+ selectedIn = 'default';
+ }
+ if (this.micDefaultRenamed) {
+ audioIn.default = this.micDefaultRenamed;
+ }
+ let selectedOut;
+ let peerPlayer;
+ if (call.sfuClient.peers.size) {
+ peerPlayer = call.sfuClient.peers.values().next().audioPlayer;
+ }
+ if (peerPlayer && peerPlayer.playerElem && peerPlayer.playerElem.sinkId) {
+ const {
+ sinkId
+ } = peerPlayer.playerElem;
+ selectedOut = sinkId in audioOut ? sinkId : 'default';
+ } else if (audioOutDeviceId) {
+ selectedOut = audioOutDeviceId in audioOut ? audioOutDeviceId : 'default';
+ } else {
+ selectedOut = 'default';
+ }
+ const mics = Object.entries(audioIn).map(([id, name]) => {
+ return JSX_(dropdowns.tJ, {
+ key: id,
+ onClick: () => {
+ call.sfuClient.setMicDevice(id === 'default' ? null : id);
+ this.setState({
+ audioSelectDropdown: false
+ }, this.setActiveElement);
+ }
+ }, JSX_(REaCt().Fragment, null, JSX_("div", {
+ className: "av-device-name"
+ }, name), selectedIn === id && JSX_("i", {
+ className: "sprite-fm-mono icon-check-small-regular-outline"
+ })));
+ });
+ const speakers = Object.entries(audioOut).map(([id, name]) => {
+ return JSX_(dropdowns.tJ, {
+ key: id,
+ onClick: () => {
+ Promise.resolve(call.sfuClient.setAudioOutDevice(id === 'default' ? null : id)).catch(dump);
+ this.setState({
+ audioSelectDropdown: false
+ }, this.setActiveElement);
+ }
+ }, JSX_(REaCt().Fragment, null, JSX_("div", {
+ className: "av-device-name"
+ }, name), selectedOut === id && JSX_("i", {
+ className: "sprite-fm-mono icon-check-small-regular-outline"
+ })));
+ });
+ return JSX_(dropdowns.ms, {
+ className: "input-sources audio-sources theme-dark-forced",
+ active: true,
+ noArrow: true,
+ positionMy: "center top",
+ positionAt: "center bottom",
+ horizOffset: -50,
+ vertOffset: 16,
+ closeDropdown: () => this.setState({
+ audioSelectDropdown: false
+ }, this.setActiveElement)
+ }, JSX_("div", {
+ className: "source-label"
+ }, l.microphone), mics.length ? mics : JSX_(dropdowns.tJ, {
+ label: l.no_mics
+ }), JSX_("hr", null), JSX_("div", {
+ className: "source-label"
+ }, l.speaker), speakers.length ? speakers : JSX_(dropdowns.tJ, {
+ label: l.no_speakers
+ }), JSX_("hr", null), JSX_(dropdowns.tJ, {
+ icon: "sprite-fm-mono icon-volume-max-small-regular-outline",
+ label: l.test_speaker,
+ disabled: speakers.length === 0,
+ onClick: () => {
+ delay('call-test-speaker', () => {
+ this.testAudioOut().catch(ex => {
+ console.error('Failed to test audio on the selected device', ex, audioOutDeviceId);
+ });
+ });
+ }
+ }));
+ }
+ renderVideoDropdown() {
+ const {
+ call
+ } = this.props;
+ const {
+ videoIn = {}
+ } = this.state.devices;
+ const {
+ camDeviceId
+ } = SfuClient;
+ let selectedCam;
+ if (call.sfuClient.localCameraTrack()) {
+ const {
+ deviceId
+ } = call.sfuClient.localCameraTrack().getCapabilities();
+ selectedCam = deviceId in videoIn ? deviceId : 'default';
+ } else if (camDeviceId) {
+ selectedCam = camDeviceId in videoIn ? camDeviceId : 'default';
+ } else {
+ selectedCam = 'default';
+ }
+ const cameras = Object.entries(videoIn).map(([id, name]) => {
+ return JSX_(dropdowns.tJ, {
+ key: id,
+ onClick: () => {
+ call.sfuClient.setCameraDevice(id === 'default' ? null : id);
+ this.setState({
+ videoSelectDropdown: false
+ }, this.setActiveElement);
+ }
+ }, JSX_(REaCt().Fragment, null, JSX_("div", {
+ className: "av-device-name"
+ }, name), selectedCam === id && JSX_("i", {
+ className: "sprite-fm-mono icon-check-small-regular-outline"
+ })));
+ });
+ return JSX_(dropdowns.ms, {
+ className: "input-sources video-sources theme-dark-forced",
+ active: true,
+ noArrow: true,
+ positionMy: "center top",
+ positionAt: "center bottom",
+ horizOffset: -50,
+ vertOffset: 16,
+ closeDropdown: () => this.setState({
+ videoSelectDropdown: false
+ }, this.setActiveElement)
+ }, JSX_("div", {
+ className: "source-label"
+ }, l.camera_button), cameras.length ? cameras : JSX_(dropdowns.tJ, {
+ label: l.no_cameras
+ }));
+ }
+ async updateMediaDevices() {
+ let devices = await SfuClient.enumMediaDevices().catch(dump);
+ devices = devices || {
+ audioIn: {},
+ audioOut: {},
+ videoIn: {}
+ };
+ const removeEmptyDevices = devices => {
+ for (const key of Object.keys(devices)) {
+ if (!key || !devices[key]) {
+ delete devices[key];
+ }
+ }
+ };
+ removeEmptyDevices(devices.audioIn);
+ removeEmptyDevices(devices.audioOut);
+ removeEmptyDevices(devices.videoIn);
+ if (devices.audioIn.communications) {
+ delete devices.audioIn.communications;
+ }
+ return devices;
+ }
+ async testAudioOut() {
+ if (!SfuClient.audioOutDeviceId) {
+ return megaChat.playSound(megaChat.SOUNDS.SPEAKER_TEST);
+ }
+ const currentDevices = await this.updateMediaDevices();
+ if (currentDevices.audioOut && !(SfuClient.audioOutDeviceId in currentDevices.audioOut)) {
+ return megaChat.playSound(megaChat.SOUNDS.SPEAKER_TEST);
+ }
+ const ctx = new AudioContext({
+ sinkId: SfuClient.audioOutDeviceId
+ });
+ if (ctx.state !== 'running') {
+ throw new Error('The audio context failed to start');
+ }
+ const soundBuffer = await megaChat.fetchSoundBuffer(megaChat.SOUNDS.SPEAKER_TEST);
+ const buffer = await ctx.decodeAudioData(soundBuffer);
+ const gain = ctx.createGain();
+ const source = ctx.createBufferSource();
+ source.buffer = buffer;
+ source.connect(gain);
+ gain.connect(ctx.destination);
+ gain.gain.value = 0.07;
+ source.start();
+ }
+ componentWillUnmount() {
+ super.componentWillUnmount();
+ document.removeEventListener('mousedown', this.handleMousedown);
+ navigator.mediaDevices.removeEventListener('devicechange', this.handleDeviceChange);
+ this.props.chatRoom.off(`onLocalSpeechDetected.${StreamControls.NAMESPACE}`);
+ }
+ componentDidMount() {
+ super.componentDidMount();
+ document.addEventListener('mousedown', this.handleMousedown);
+ navigator.mediaDevices.addEventListener('devicechange', this.handleDeviceChange);
+ this.props.chatRoom.rebind(`onLocalSpeechDetected.${StreamControls.NAMESPACE}`, () => this.setState({
+ muteSpeak: true
+ }, () => this.setActiveElement(true)));
+ }
+ render() {
+ const {
+ call,
+ signal,
+ chatRoom,
+ renderSignalWarning,
+ hasToRenderPermissionsWarning,
+ renderPermissionsWarning,
+ resetError,
+ blocked,
+ renderBlockedWarning,
+ onAudioClick,
+ onVideoClick,
+ onScreenSharingClick,
+ onHoldClick
+ } = this.props;
+ const {
+ audioSelectDropdown,
+ videoSelectDropdown,
+ muteSpeak
+ } = this.state;
+ const avFlags = call.av;
+ const isOnHold = avFlags & Av.onHold;
+ return JSX_(REaCt().Fragment, null, blocked && renderBlockedWarning(), JSX_("div", {
+ ref: this.domRef,
+ className: StreamControls.NAMESPACE
+ }, d && localStorage.callDebug ? this.renderDebug() : '', JSX_("ul", null, JSX_("li", {
+ className: `
+ ${isOnHold ? 'disabled' : ''}
+ with-input-selector
+ `,
+ onClick: () => isOnHold ? null : this.setState({
+ muteSpeak: false
+ }, () => {
+ resetError(Av.Audio);
+ onAudioClick();
+ })
+ }, muteSpeak && JSX_("div", {
+ className: "mic-muted-tip theme-light-forced",
+ onClick: ev => ev.stopPropagation()
+ }, JSX_("span", null, l.mic_still_muted), JSX_(meetings_button.A, {
+ className: "mic-muted-tip-btn",
+ onClick: () => {
+ this.setState({
+ muteSpeak: false
+ }, () => {
+ this.setActiveElement();
+ eventlog(500509);
+ });
+ }
+ }, l[148]), JSX_("i", {
+ className: "sprite-fm-mono icon-tooltip-arrow tooltip-arrow bottom"
+ })), JSX_(meetings_button.A, {
+ className: `
+ mega-button
+ theme-light-forced
+ call-action
+ round
+ ${isOnHold ? 'disabled' : ''}
+ ${avFlags & Av.Audio || isOnHold ? '' : 'with-fill'}
+ `,
+ icon: avFlags & Av.Audio ? 'icon-mic-thin-outline' : 'icon-mic-off-thin-outline'
+ }), JSX_("span", null, l.mic_button), signal ? null : renderSignalWarning(), hasToRenderPermissionsWarning(Av.Audio) ? renderPermissionsWarning(Av.Audio) : null, this.renderSourceOpener({
+ type: 'audioSelectDropdown',
+ eventId: chatRoom.isMeeting ? 500299 : 500300
+ })), audioSelectDropdown && JSX_("div", {
+ ref: this.audioDropdownRef
+ }, this.renderSoundDropdown()), JSX_("li", {
+ className: `
+ ${isOnHold ? 'disabled' : ''}
+ with-input-selector
+ `,
+ onClick: () => {
+ if (isOnHold) {
+ return;
+ }
+ resetError(Av.Camera);
+ onVideoClick();
+ }
+ }, JSX_(meetings_button.A, {
+ className: `
+ mega-button
+ theme-light-forced
+ call-action
+ round
+ ${isOnHold ? 'disabled' : ''}
+ ${avFlags & Av.Camera || isOnHold ? '' : 'with-fill'}
+ `,
+ icon: avFlags & Av.Camera ? 'icon-video-thin-outline' : 'icon-video-off-thin-outline'
+ }), JSX_("span", null, l.camera_button), hasToRenderPermissionsWarning(Av.Camera) ? renderPermissionsWarning(Av.Camera) : null, this.renderSourceOpener({
+ type: 'videoSelectDropdown',
+ eventId: chatRoom.isMeeting ? 500301 : 500302
+ })), videoSelectDropdown && JSX_("div", {
+ ref: this.videoDropdownRef
+ }, this.renderVideoDropdown()), JSX_("li", {
+ className: isOnHold ? 'disabled' : '',
+ onClick: () => {
+ if (isOnHold) {
+ return;
+ }
+ resetError(Av.Screen);
+ onScreenSharingClick();
+ if (chatRoom.isMeeting) {
+ eventlog(500303);
+ } else {
+ eventlog(500304);
+ }
+ }
+ }, JSX_(meetings_button.A, {
+ className: `
+ mega-button
+ theme-light-forced
+ call-action
+ round
+ ${isOnHold ? 'disabled' : ''}
+ ${avFlags & Av.Screen ? 'with-fill' : ''}
+ `,
+ icon: avFlags & Av.Screen ? 'icon-monitor-off' : 'icon-monitor'
+ }), JSX_("span", null, avFlags & Av.Screen ? l.screenshare_stop_button : l.screenshare_button), hasToRenderPermissionsWarning(Av.Screen) ? renderPermissionsWarning(Av.Screen, this) : null), chatRoom.type === 'private' ? null : this.renderRaiseButton(), JSX_("li", {
+ onClick: onHoldClick
+ }, JSX_(meetings_button.A, {
+ className: `
+ mega-button
+ theme-light-forced
+ call-action
+ round
+ ${isOnHold ? 'with-fill' : ''}
+ `,
+ icon: isOnHold ? 'icon-play-small-regular-outline' : 'icon-pause-small-regular-outline'
+ }), JSX_("span", null, isOnHold ? l.resume_call_button : l.hold_button)), JSX_("li", null, this.renderEndCall()))));
+ }
+}
+StreamControls.NAMESPACE = 'stream-controls';
+ const streamControls = (0,mixins.Zz)(withMicObserver, permissionsObserver.$)(StreamControls);
+;// ./js/chat/ui/meetings/sidebarControls.jsx
+
+
+
+const SidebarControls = ({
+ npeers,
+ view,
+ sidebar,
+ call,
+ chatRoom,
+ onChatToggle,
+ onParticipantsToggle,
+ onInviteToggle
+}) => {
+ const notifications = chatRoom.getUnreadCount();
+ const isOnHold = !!((call == null ? void 0 : call.av) & Av.onHold);
+ const canInvite = chatRoom.type !== 'private' && !!(chatRoom.iAmOperator() || chatRoom.options[MCO_FLAGS.OPEN_INVITE] || chatRoom.publicLink);
+ return JSX_("div", {
+ className: "sidebar-controls"
+ }, JSX_("ul", {
+ className: isOnHold ? 'disabled' : ''
+ }, canInvite && JSX_("li", {
+ onClick: isOnHold ? null : onInviteToggle
+ }, JSX_(meetings_button.A, {
+ className: `
+ mega-button
+ theme-dark-forced
+ call-action
+ round
+ `,
+ icon: "icon-user-plus-thin-outline"
+ }), JSX_("span", {
+ className: "control-label"
+ }, l[8726])), JSX_("li", {
+ onClick: isOnHold ? null : onChatToggle
+ }, JSX_(meetings_button.A, {
+ className: `
+ mega-button
+ theme-dark-forced
+ call-action
+ round
+ ${sidebar && view === utils.gR.CHAT ? 'selected' : ''}
+ ${isOnHold ? 'disabled' : ''}
+ `,
+ icon: sidebar && view === utils.gR.CHAT ? 'icon-chat-filled' : 'icon-message-chat-circle-thin'
+ }), JSX_("span", {
+ className: "control-label"
+ }, l.chat_call_button), notifications > 0 && JSX_("span", {
+ className: "notification-badge notifications-count"
+ }, notifications > 9 ? '9+' : notifications)), JSX_("li", {
+ onClick: isOnHold ? null : onParticipantsToggle
+ }, JSX_(meetings_button.A, {
+ className: `
+ mega-button
+ theme-dark-forced
+ call-action
+ round
+ ${sidebar && view === utils.gR.PARTICIPANTS ? 'selected' : ''}
+ ${isOnHold ? 'disabled' : ''}
+ `,
+ icon: sidebar && view === utils.gR.PARTICIPANTS ? 'icon-users-thin-solid' : 'icon-users-thin-outline'
+ }), JSX_("span", {
+ className: "control-label"
+ }, l.participants_call_button), JSX_("span", {
+ className: `
+ notification-badge
+ participants-count
+ theme-dark-forced
+ ${npeers + 1 > 99 ? 'large' : ''}
+ `
+ }, npeers + 1))));
+};
+ const sidebarControls = SidebarControls;
+;// ./js/chat/ui/meetings/call.jsx
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+const call_NAMESPACE = 'meetings-call';
+const MOUSE_OUT_DELAY = 2500;
+class RecordingConsentDialog extends REaCt().Component {
+ componentWillUnmount() {
+ if ($.dialog && $.dialog === RecordingConsentDialog.dialogName) {
+ closeDialog();
+ }
+ }
+ render() {
+ const {
+ peers,
+ recorderCid,
+ onCallEnd,
+ onClose
+ } = this.props;
+ const recordingPeer = peers[recorderCid];
+ const recorderName = nicknames.getNickname(recordingPeer).substr(0, ChatToastIntegration.MAX_NAME_CHARS);
+ return JSX_(modalDialogs.A.ModalDialog, {
+ dialogName: RecordingConsentDialog.dialogName,
+ className: `
+ mega-dialog
+ dialog-template-message
+ info
+ `,
+ stopKeyPropagation: true,
+ noCloseOnClickOutside: true
+ }, JSX_("header", null, JSX_("div", {
+ className: "graphic"
+ }, JSX_("i", {
+ className: "info sprite-fm-uni icon-info"
+ })), JSX_("div", {
+ className: "info-container"
+ }, JSX_("h3", {
+ id: "msgDialog-title"
+ }, l.call_recorded_heading), JSX_("p", {
+ className: "text"
+ }, JSX_(ui_utils.P9, null, l.call_recorded_body.replace('[A]', ``).replace('[/A]', ''))))), JSX_("footer", null, JSX_("div", {
+ className: "footer-container"
+ }, JSX_("div", {
+ className: "space-between"
+ }, JSX_(meetings_button.A, {
+ className: "mega-button",
+ onClick: onCallEnd
+ }, JSX_("span", null, l[5883])), JSX_(meetings_button.A, {
+ className: "mega-button positive",
+ onClick: () => {
+ onClose();
+ ChatToast.quick(l.user_recording_toast.replace('%NAME', recorderName));
+ }
+ }, JSX_("span", null, l.ok_button))))));
+ }
+}
+RecordingConsentDialog.dialogName = `${"meetings-call"}-consent`;
+class Call extends mixins.w9 {
+ constructor(props) {
+ super(props);
+ this.domRef = REaCt().createRef();
+ this.recordingConsentDialog = `${call_NAMESPACE}-consent`;
+ this.ephemeralAddListener = undefined;
+ this.delayProcID = null;
+ this.pCallTimer = null;
+ this.offlineDelayed = undefined;
+ this.callStartTimeout = undefined;
+ this.flagMap = attribCache.bitMapsManager.exists('obv4') ? attribCache.bitMapsManager.get('obv4') : undefined;
+ this.timeoutBannerRef = REaCt().createRef();
+ this.state = {
+ mode: undefined,
+ view: utils.gR.PARTICIPANTS,
+ sidebar: false,
+ forcedLocal: false,
+ hovered: false,
+ invite: false,
+ ephemeral: false,
+ offline: false,
+ ephemeralAccounts: [],
+ everHadPeers: false,
+ guest: (0,utils.P)(),
+ waitingRoomPeers: [],
+ raisedHandPeers: [],
+ raisedHandToast: false,
+ initialCallRinging: false,
+ onboardingUI: false,
+ onboardingRecording: false,
+ onboardingRaise: false,
+ recorderCid: undefined,
+ recordingConsentDialog: false,
+ recordingConsented: false,
+ recordingActivePeer: undefined,
+ recordingTooltip: false,
+ invitePanel: false,
+ presenterThumbSelected: false,
+ timeoutBanner: false,
+ showTimeoutUpgrade: false,
+ activeElement: false
+ };
+ this.handleRetryTimeout = () => {
+ const {
+ call,
+ chatRoom
+ } = this.props;
+ if ((call == null ? void 0 : call.sfuClient.connState) === SfuClient.ConnState.kDisconnectedRetrying) {
+ this.handleCallEnd();
+ chatRoom.trigger('onRetryTimeout');
+ megaChat.playSound(megaChat.SOUNDS.CALL_END);
+ }
+ };
+ this.handleCallOnline = () => {
+ if (this.pCallTimer) {
+ this.pCallTimer.abort();
+ this.pCallTimer = null;
+ }
+ this.setState({
+ offline: false,
+ raisedHandPeers: [...this.props.call.sfuClient.raisedHands]
+ });
+ };
+ this.customIsEventuallyVisible = () => true;
+ this.renderRaisedHandToast = () => {
+ const {
+ raisedHandPeers
+ } = this.state;
+ window.toaster.main.hideAll();
+ toaster.main.show({
+ buttons: [{
+ text: l[16797],
+ onClick: () => this.setState({
+ sidebar: true,
+ view: utils.gR.PARTICIPANTS,
+ raisedHandToast: false
+ }, () => window.toaster.main.hideAll())
+ }],
+ onClose: () => this.setState({
+ raisedHandToast: false
+ }, () => window.toaster.main.hideAll()),
+ classes: ['theme-dark-forced', 'call-toast'],
+ icons: ['sprite-fm-uni icon-raise-hand'],
+ timeout: 0,
+ content: (() => {
+ const peerName = M.getNameByHandle(raisedHandPeers[0]);
+ const peersCount = raisedHandPeers.length;
+ const withCurrentPeer = raisedHandPeers.includes(u_handle);
+ const CONTENT = {
+ 1: () => l.raise_peer_raised.replace('%s', peerName),
+ 2: () => {
+ const message = withCurrentPeer ? l.raise_self_peers_raised : l.raise_two_raised;
+ return mega.icu.format(message, peersCount - 1).replace('%s', peerName);
+ },
+ rest: () => {
+ const message = withCurrentPeer ? l.raise_self_peers_raised : l.raise_peers_raised;
+ return mega.icu.format(message, withCurrentPeer ? peersCount - 1 : peersCount);
+ }
+ };
+ return (CONTENT[peersCount] || CONTENT.rest)();
+ })()
+ });
+ };
+ this.bindCallEvents = () => {
+ const {
+ chatRoom
+ } = this.props;
+ chatRoom.rebind(`onCallPeerLeft.${call_NAMESPACE}`, (ev, {
+ userHandle,
+ clientId
+ }) => {
+ const {
+ minimized,
+ peers,
+ call,
+ chatRoom
+ } = this.props;
+ if (clientId === this.state.recorderCid) {
+ chatRoom.trigger('onRecordingStopped', {
+ userHandle,
+ clientId
+ });
+ }
+ if (minimized) {
+ this.setState({
+ mode: peers.length === 0 ? utils.g.THUMBNAIL : utils.g.MINI
+ }, () => {
+ call.setViewMode(this.state.mode);
+ });
+ }
+ });
+ chatRoom.rebind(`onCallPeerJoined.${call_NAMESPACE}`, () => {
+ const {
+ minimized,
+ peers,
+ call
+ } = this.props;
+ if (minimized) {
+ this.setState({
+ mode: peers.length === 0 ? utils.g.THUMBNAIL : utils.g.MINI
+ }, () => {
+ call.setViewMode(this.state.mode);
+ });
+ }
+ if (call.hasOtherParticipant()) {
+ if (!this.state.everHadPeers) {
+ this.setState({
+ everHadPeers: true
+ });
+ }
+ clearTimeout(this.callStartTimeout);
+ }
+ });
+ chatRoom.rebind(`onCallLeft.${call_NAMESPACE}`, () => this.props.minimized && this.props.onCallEnd());
+ chatRoom.rebind(`wrOnUsersEntered.${call_NAMESPACE}`, (ev, users) => Object.entries(users).forEach(([handle, host]) => {
+ return host || this.state.waitingRoomPeers.includes(handle) ? null : this.isMounted() && this.setState({
+ waitingRoomPeers: [...this.state.waitingRoomPeers, handle]
+ }, () => {
+ const {
+ waitingRoomPeers
+ } = this.state;
+ if (waitingRoomPeers && waitingRoomPeers.length === 1) {
+ megaChat.playSound(megaChat.SOUNDS.CALL_JOIN_WAITING);
+ }
+ mBroadcaster.sendMessage('meetings:peersWaiting', waitingRoomPeers);
+ });
+ }));
+ const usrwr = (e, users) => {
+ users = typeof users === 'string' ? [users] : users;
+ return this.isMounted() && this.setState({
+ waitingRoomPeers: this.state.waitingRoomPeers.filter(h => !users.includes(h))
+ }, () => mBroadcaster.sendMessage('meetings:peersWaiting', this.state.waitingRoomPeers));
+ };
+ chatRoom.rebind(`wrOnUserLeft.${call_NAMESPACE}`, usrwr);
+ chatRoom.rebind(`wrOnUsersAllow.${call_NAMESPACE}`, usrwr);
+ chatRoom.rebind(`wrOnUserDump.${call_NAMESPACE}`, (ev, users) => Object.entries(users).forEach(([handle, host]) => {
+ return host || this.state.waitingRoomPeers.includes(handle) ? null : this.isMounted() && this.setState({
+ waitingRoomPeers: [...this.state.waitingRoomPeers, handle]
+ });
+ }));
+ chatRoom.rebind(`onRecordingStarted.${call_NAMESPACE}`, (ev, {
+ userHandle,
+ clientId
+ }) => {
+ if (!this.state.recorderCid) {
+ return this.state.recordingConsented ? this.setState({
+ recorderCid: clientId
+ }, () => {
+ ChatToast.quick(l.user_recording_toast.replace('%NAME', nicknames.getNickname(userHandle).substr(0, ChatToastIntegration.MAX_NAME_CHARS)));
+ }) : (() => {
+ closeDialog();
+ M.safeShowDialog(RecordingConsentDialog.dialogName, () => this.setState({
+ recorderCid: clientId,
+ recordingConsentDialog: true
+ }));
+ })();
+ }
+ });
+ chatRoom.rebind(`onRecordingStopped.${call_NAMESPACE}`, (ev, {
+ userHandle,
+ clientId
+ }) => {
+ const {
+ recorderCid
+ } = this.state;
+ this.setState({
+ recordingConsentDialog: false,
+ recorderCid: clientId === recorderCid ? false : recorderCid
+ }, () => window.sfuClient && clientId === recorderCid && ChatToast.quick(l.user_recording_nop_toast.replace('%NAME', nicknames.getNickname(userHandle).substr(0, ChatToastIntegration.MAX_NAME_CHARS))));
+ });
+ chatRoom.rebind(`onMutedBy.${call_NAMESPACE}`, (ev, {
+ cid
+ }) => {
+ megaChat.plugins.userHelper.getUserNickname(this.props.peers[cid]).catch(dump).always(name => {
+ ChatToast.quick(l.muted_by.replace('%NAME', name || ''));
+ });
+ });
+ chatRoom.rebind(`onCallEndTimeUpdated.${call_NAMESPACE}`, ({
+ data
+ }) => {
+ this.setState({
+ timeoutBanner: !!data,
+ showTimeoutUpgrade: this.props.call.organiser === u_handle && data - Date.now() >= 120e3
+ }, () => {
+ if (this.state.timeoutBanner) {
+ this.timeoutBannerInterval = this.timeoutBannerInterval || setInterval(() => this.updateTimeoutDuration(), 1000);
+ } else {
+ clearInterval(this.timeoutBannerInterval);
+ delete this.timeoutBannerInterval;
+ }
+ });
+ });
+ chatRoom.rebind(`onRaisedHandAdd.${call_NAMESPACE}`, (ev, {
+ userHandle
+ }) => this.isMounted() && this.setState(state => ({
+ raisedHandPeers: [...state.raisedHandPeers, userHandle]
+ }), () => {
+ const {
+ raisedHandPeers
+ } = this.state;
+ if (userHandle !== u_handle && !this.props.minimized) {
+ this.setState({
+ raisedHandToast: true
+ }, () => this.renderRaisedHandToast());
+ }
+ mBroadcaster.sendMessage('meetings:raisedHand', raisedHandPeers);
+ }));
+ chatRoom.rebind(`onRaisedHandDel.${call_NAMESPACE}`, (ev, {
+ userHandle
+ }) => this.isMounted() && this.setState(state => ({
+ raisedHandPeers: state.raisedHandPeers.filter(h => h !== userHandle)
+ }), () => {
+ const {
+ raisedHandPeers,
+ raisedHandToast
+ } = this.state;
+ mBroadcaster.sendMessage('meetings:raisedHand', raisedHandPeers);
+ if (raisedHandPeers && raisedHandPeers.length) {
+ return raisedHandToast ? this.renderRaisedHandToast() : null;
+ }
+ return this.setState({
+ raisedHandToast: false
+ }, () => window.toaster.main.hideAll());
+ }));
+ chatRoom.rebind(`onRecordingActivePeer.${call_NAMESPACE}`, (ev, {
+ userHandle
+ }) => this.setState({
+ recordingActivePeer: userHandle
+ }));
+ };
+ this.unbindCallEvents = () => ['onCallPeerLeft', 'onCallPeerJoined', 'onCallLeft', 'wrOnUsersAllow', 'wrOnUsersEntered', 'wrOnUserLeft', 'alterUserPrivilege', 'onCallState', 'onRecordingStarted', 'onRecordingStopped', 'onRecordingActivePeer', 'onCallEndTimeUpdated', 'onRaisedHandAdd', 'onRaisedHandDel'].map(event => this.props.chatRoom.off(`${event}.${call_NAMESPACE}`));
+ this.handleCallMinimize = () => {
+ const {
+ call,
+ peers,
+ onCallMinimize
+ } = this.props;
+ const {
+ mode,
+ sidebar,
+ view
+ } = this.state;
+ const {
+ callToutId,
+ stayOnEnd,
+ presenterStreams
+ } = call;
+ Call.STATE.PREVIOUS = mode !== utils.g.MINI ? {
+ mode,
+ sidebar,
+ view
+ } : Call.STATE.PREVIOUS;
+ const doMinimize = () => {
+ onCallMinimize();
+ window.toaster.main.hideAll();
+ };
+ mega.ui.mInfoPanel.hide();
+ return peers.length > 0 || presenterStreams.has(u_handle) ? this.setState({
+ mode: utils.g.MINI,
+ sidebar: false
+ }, () => {
+ doMinimize();
+ call.setViewMode(utils.g.MINI);
+ }) : (() => {
+ doMinimize();
+ if (typeof callToutId !== 'undefined' && !stayOnEnd) {
+ onIdle(() => call.showTimeoutDialog());
+ }
+ })();
+ };
+ this.handleCallExpand = async () => {
+ mega.ui.mInfoPanel.hide();
+ return new Promise(resolve => {
+ this.setState({
+ ...Call.STATE.PREVIOUS
+ }, () => {
+ this.props.onCallExpand();
+ resolve();
+ });
+ });
+ };
+ this.handleStreamToggle = action => {
+ const {
+ peers
+ } = this.props;
+ if (action === utils.hK.ADD && peers.length === utils.$A) {
+ return;
+ }
+ return action === utils.hK.ADD ? peers.addFakeDupStream() : peers.removeFakeDupStream();
+ };
+ this.handleSpeakerChange = (source, presenterThumbSelected) => {
+ if (source) {
+ this.handleModeChange(utils.g.MAIN);
+ const sourceId = source.isLocal ? 0 : source.clientId;
+ if (sourceId !== this.props.call.pinnedCid) {
+ this.props.call.setPinnedCid(sourceId);
+ } else {
+ this.props.call.setPinnedCid(sourceId, !source.hasScreen || presenterThumbSelected === this.state.presenterThumbSelected);
+ }
+ const {
+ pinnedCid
+ } = this.props.call;
+ this.setState({
+ forcedLocal: !!(source.isLocal && pinnedCid !== null),
+ presenterThumbSelected: pinnedCid === null ? false : !!presenterThumbSelected && source.hasScreen
+ });
+ } else if (source === null) {
+ this.setState({
+ presenterThumbSelected: !!presenterThumbSelected
+ });
+ }
+ };
+ this.handleModeChange = mode => {
+ this.props.call.setViewMode(mode);
+ this.setState({
+ mode,
+ forcedLocal: false
+ });
+ };
+ this.handleChatToggle = () => {
+ if (this.state.sidebar && this.state.view === utils.gR.CHAT) {
+ return this.setState({
+ ...Call.STATE.DEFAULT
+ });
+ }
+ return this.setState({
+ sidebar: true,
+ view: utils.gR.CHAT
+ });
+ };
+ this.handleParticipantsToggle = forceOpen => {
+ if (forceOpen !== true) {
+ forceOpen = false;
+ }
+ if (this.state.sidebar && this.state.view === utils.gR.CHAT) {
+ return this.setState({
+ sidebar: true,
+ view: utils.gR.PARTICIPANTS
+ });
+ }
+ return this.setState({
+ sidebar: forceOpen ? true : !this.state.sidebar,
+ view: utils.gR.PARTICIPANTS
+ });
+ };
+ this.handleInviteToggle = () => {
+ if (Object.values(M.u.toJS()).some(u => u.c === 1)) {
+ const participants = (0,conversationpanel.z)(this.props.chatRoom);
+ if ((0,conversationpanel.e)(participants)) {
+ msgDialog(`confirmationa:!^${l[8726]}!${l.msg_dlg_cancel}`, null, `${l.all_contacts_added}`, `${l.all_contacts_added_to_chat}`, res => {
+ if (res) {
+ contactAddDialog(null, false);
+ }
+ });
+ } else {
+ this.setState({
+ invite: !this.state.invite
+ });
+ }
+ } else {
+ msgDialog(`confirmationa:!^${l[8726]}!${l.msg_dlg_cancel}`, null, `${l.no_contacts}`, `${l.no_contacts_text}`, resp => {
+ if (resp) {
+ contactAddDialog(null, false);
+ }
+ });
+ }
+ };
+ this.handleHoldToggle = async () => {
+ await this.props.call.toggleHold();
+ mBroadcaster.sendMessage('meetings:toggleHold');
+ };
+ this.handleScreenSharingToggle = () => {
+ const {
+ call
+ } = this.props;
+ const userAgent = navigator.userAgent.match(/Chrom(e|ium)\/(\d+)\./);
+ const version = parseInt(userAgent[2], 10);
+ if (version === 92) {
+ return msgDialog('info', undefined, l[47], l.chrome_screensharing);
+ }
+ return call.toggleScreenSharing();
+ };
+ this.handleCallEnd = () => {
+ let _this$props$call;
+ mega.ui.mInfoPanel.hide();
+ (_this$props$call = this.props.call) == null || _this$props$call.destroy(SfuClient.TermCode.kUserHangup);
+ };
+ this.handleEphemeralAdd = handle => handle && this.setState(state => ({
+ ephemeral: true,
+ ephemeralAccounts: [...state.ephemeralAccounts, handle]
+ }));
+ this.handleStayConfirm = () => {
+ const {
+ call
+ } = this.props;
+ call.handleStayConfirm();
+ onIdle(() => this.safeForceUpdate());
+ };
+ this.handleRecordingToggle = () => {
+ const {
+ call,
+ chatRoom
+ } = this.props;
+ if (chatRoom.isMeeting) {
+ eventlog(500286);
+ } else {
+ eventlog(500287);
+ }
+ if (this.state.recorderCid) {
+ return msgDialog(`confirmation:!^${l.stop_recording_dialog_cta}!${l.stop_recording_nop_dialog_cta}`, undefined, l.stop_recording_dialog_heading, l.stop_recording_dialog_body, cb => cb && sfuClient.recordingStop(), 1);
+ }
+ msgDialog(`warningb:!^${l.start_recording_dialog_cta}!${l.msg_dlg_cancel}`, null, l.notify_participants_dialog_heading, l.notify_participants_dialog_body, cb => {
+ if (cb || cb === null) {
+ return;
+ }
+ call.sfuClient.recordingStart(this.onWeStoppedRecording).then(() => {
+ call.recorderCid = this.state.recorderCid;
+ this.setState({
+ recorderCid: call.sfuClient.cid
+ });
+ this.handleModeChange(utils.g.MAIN);
+ call.recordActiveStream();
+ ChatToast.quick(l.started_recording_toast);
+ }).catch(dump);
+ }, 1);
+ };
+ this.onWeStoppedRecording = err => this.isMounted() && this.setState({
+ recorderCid: undefined,
+ recordingActivePeer: undefined
+ }, () => err ? ChatToast.quick(`${l.stopped_recording_toast} Error: ${err.message || err}`) : ChatToast.quick(l.stopped_recording_toast));
+ this.renderRecordingControl = () => {
+ const {
+ chatRoom,
+ call,
+ peers
+ } = this.props;
+ const {
+ recorderCid,
+ recordingTooltip,
+ recordingActivePeer
+ } = this.state;
+ const userIsModerator = (0,utils.Cy)(chatRoom, u_handle);
+ const $$CONTAINER = ({
+ className,
+ onClick,
+ children
+ }) => JSX_("div", {
+ className: `
+ recording-control
+ ${localStorage.callDebug ? 'with-offset' : ''}
+ ${className || ''}
+ `,
+ onClick
+ }, children);
+ if (recorderCid) {
+ const isRecorder = userIsModerator && recorderCid === call.sfuClient.cid;
+ const recordingPeer = peers[recorderCid];
+ return JSX_($$CONTAINER, {
+ recordingTooltip,
+ className: "recording-fixed"
+ }, JSX_("div", (0,esm_extends.A)({
+ className: `
+ recording-ongoing
+ simpletip
+ ${isRecorder ? '' : 'plain-background'}
+ `
+ }, recorderCid !== call.sfuClient.cid && {
+ 'data-simpletip': l.host_recording.replace('%NAME', nicknames.getNickname(recordingPeer) || megaChat.plugins.userHelper.SIMPLETIP_USER_LOADER),
+ 'data-simpletipposition': 'top',
+ 'data-simpletipoffset': 5,
+ 'data-simpletip-class': 'theme-dark-forced'
+ }), JSX_("span", {
+ className: `
+ recording-icon
+ button
+ ${recordingTooltip ? 'active-dropdown' : ''}
+ ${isRecorder ? 'clickable' : ''}
+ `,
+ onMouseEnter: () => isRecorder && this.setState({
+ recordingTooltip: true
+ }),
+ onMouseOut: () => isRecorder && delay('meetings-rec-hover', () => this.setState({
+ recordingTooltip: false
+ }), 1250)
+ }, "REC ", JSX_("i", null), JSX_(dropdowns.ms, {
+ className: "recording-info theme-dark-forced",
+ active: recordingTooltip,
+ noArrow: false,
+ positionMy: "center top",
+ positionAt: "center bottom",
+ vertOffset: 40,
+ horizOffset: 30
+ }, JSX_("div", null, "Currently recording: ", nicknames.getNickname(recordingActivePeer)))), isRecorder && JSX_("span", {
+ className: "recording-toggle",
+ onClick: this.handleRecordingToggle
+ }, l.record_stop_button)));
+ }
+ const isOnHold = !!((call == null ? void 0 : call.av) & Av.onHold);
+ return userIsModerator && JSX_($$CONTAINER, {
+ className: isOnHold ? 'disabled' : '',
+ onClick: () => {
+ this.setState({
+ onboardingRecording: false,
+ hovered: false
+ }, () => {
+ this.flagMap.setSync(OBV4_FLAGS.CHAT_CALL_RECORDING, 1);
+ this.flagMap.safeCommit();
+ });
+ return isOnHold || recorderCid && recorderCid !== call.sfuClient.cid ? null : this.handleRecordingToggle();
+ }
+ }, JSX_(meetings_button.A, {
+ className: `
+ mega-button
+ theme-dark-forced
+ call-action
+ round
+ recording-start
+ ${isOnHold ? 'disabled' : ''}
+ `
+ }, JSX_("div", null, JSX_("i", null))), JSX_("span", {
+ className: "record-label"
+ }, l.record_start_button));
+ };
+ this.setActiveElement = activeElement => this.setState({
+ activeElement
+ });
+ const {
+ SOUNDS
+ } = megaChat;
+ [SOUNDS.RECONNECT, SOUNDS.CALL_END, SOUNDS.CALL_JOIN_WAITING].map(sound => ion.sound.preload(sound));
+ this.state.mode = props.call.viewMode;
+ this.setOnboarding();
+ this.handleMouseMove = this.handleMouseMove.bind(this);
+ this.handleMouseOut = this.handleMouseOut.bind(this);
+ }
+ handleMouseMove() {
+ this.setState({
+ hovered: true
+ });
+ if (this.delayProcID) {
+ delay.cancel(this.delayProcID);
+ this.delayProcID = null;
+ }
+ }
+ handleMouseOut() {
+ if (this.state.hovered) {
+ this.delayProcID = delay('meetings-call-hover', () => {
+ if (this.isMounted()) {
+ this.setState({
+ hovered: false
+ });
+ }
+ }, MOUSE_OUT_DELAY);
+ }
+ }
+ handleCallOffline() {
+ if (!this.pCallTimer) {
+ (this.pCallTimer = tSleep(30)).then(() => {
+ this.setState({
+ offline: true
+ });
+ });
+ }
+ }
+ setOnboarding() {
+ this.state.onboardingUI = this.state.hovered = this.flagMap && !this.flagMap.getSync(OBV4_FLAGS.CHAT_CALL_UI);
+ if (!this.state.onboardingUI) {
+ this.state.onboardingRecording = this.state.hovered = this.flagMap && !this.flagMap.getSync(OBV4_FLAGS.CHAT_CALL_RECORDING);
+ }
+ if (!this.state.onboardingUI && !this.state.onboardingRecording) {
+ this.state.onboardingRaise = this.state.hovered = this.flagMap && !this.flagMap.getSync(OBV4_FLAGS.CHAT_CALL_RAISE);
+ }
+ }
+ handleInvitePanelToggle() {
+ delay('chat-event-inv-call', () => eventlog(99962));
+ this.setState({
+ invitePanel: !this.state.invitePanel
+ });
+ }
+ handleInviteOrAdd() {
+ const {
+ chatRoom
+ } = this.props;
+ if (chatRoom.type === 'group') {
+ return this.handleInviteToggle();
+ }
+ loadingDialog.show('fetchchatlink');
+ chatRoom.updatePublicHandle(false, false, true).catch(dump).always(() => {
+ loadingDialog.hide('fetchchatlink');
+ if (!this.isMounted()) {
+ return;
+ }
+ if (!chatRoom.iAmOperator() && chatRoom.options[MCO_FLAGS.OPEN_INVITE] && !chatRoom.publicLink) {
+ this.handleInviteToggle();
+ } else if (chatRoom.type === 'public' && !chatRoom.topic) {
+ this.handleInviteToggle();
+ } else {
+ this.handleInvitePanelToggle();
+ }
+ });
+ }
+ renderTimeLimitBanner() {
+ return JSX_("div", {
+ className: "call-time-limit-banner theme-dark-forced"
+ }, JSX_("span", {
+ ref: this.timeoutBannerRef
+ }, this.timeoutString), JSX_("span", {
+ className: "call-limit-banner-action",
+ onClick: () => {
+ clearInterval(this.timeoutBannerInterval);
+ delete this.timeoutBannerInterval;
+ this.setState({
+ timeoutBanner: false
+ });
+ }
+ }, l[2005]), this.state.showTimeoutUpgrade && JSX_(ui_link.A, {
+ className: "call-limit-banner-action",
+ onClick: () => {
+ window.open(`${getBaseUrl()}/pro`, '_blank', 'noopener,noreferrer');
+ eventlog(500262);
+ }
+ }, l.upgrade_now));
+ }
+ get timeoutString() {
+ const {
+ call
+ } = this.props;
+ if (call.callEndTime === 0) {
+ return '';
+ }
+ const remainSeconds = Math.max(0, Math.ceil((call.callEndTime - Date.now()) / 1000));
+ if (call.organiser === u_handle) {
+ if (remainSeconds < 60) {
+ return mega.icu.format(l.free_call_banner_organiser_ending_sec, remainSeconds);
+ }
+ if (remainSeconds <= 120) {
+ return mega.icu.format(l.free_call_banner_organiser_ending, Math.ceil(remainSeconds / 60));
+ }
+ return mega.icu.format(l.free_call_banner_organiser_warning, Math.ceil(remainSeconds / 60));
+ }
+ if (remainSeconds < 60) {
+ return mega.icu.format(l.free_call_banner_ending_sec, remainSeconds);
+ }
+ if (remainSeconds <= 120) {
+ return mega.icu.format(l.free_call_banner_ending, Math.ceil(remainSeconds / 60));
+ }
+ return mega.icu.format(l.free_call_banner_warning, Math.ceil(remainSeconds / 60));
+ }
+ updateTimeoutDuration() {
+ if (this.timeoutBannerRef) {
+ const {
+ current
+ } = this.timeoutBannerRef;
+ const newStr = this.timeoutString;
+ if (newStr && current && current.innerText !== newStr) {
+ current.innerText = newStr;
+ }
+ if (this.state.showTimeoutUpgrade && this.props.call.callEndTime - Date.now() <= 12e4) {
+ this.setState({
+ showTimeoutUpgrade: false
+ });
+ }
+ }
+ }
+ componentWillUnmount() {
+ super.componentWillUnmount();
+ const {
+ minimized,
+ willUnmount,
+ chatRoom
+ } = this.props;
+ chatRoom.megaChat.off(`sfuConnClose.${call_NAMESPACE}`);
+ chatRoom.megaChat.off(`sfuConnOpen.${call_NAMESPACE}`);
+ chatRoom.megaChat.off(`onSpeakerChange.${call_NAMESPACE}`);
+ chatRoom.megaChat.off(`onPeerAvChange.${call_NAMESPACE}`);
+ mBroadcaster.removeListener(this.ephemeralAddListener);
+ mBroadcaster.removeListener(this.pageChangeListener);
+ clearTimeout(this.callStartTimeout);
+ delay.cancel('callOffline');
+ if ($.dialog) {
+ closeDialog();
+ }
+ if (this.timeoutBannerInterval) {
+ clearInterval(this.timeoutBannerInterval);
+ }
+ window.toaster.main.hideAll();
+ this.unbindCallEvents();
+ willUnmount == null || willUnmount(minimized);
+ }
+ componentDidMount() {
+ super.componentDidMount();
+ const {
+ call,
+ didMount,
+ chatRoom
+ } = this.props;
+ this.ephemeralAddListener = mBroadcaster.addListener('meetings:ephemeralAdd', handle => this.handleEphemeralAdd(handle));
+ this.pageChangeListener = mBroadcaster.addListener('pagechange', () => {
+ const currentRoom = megaChat.getCurrentRoom();
+ if ((0,utils.Av)() && (!M.chat || currentRoom && currentRoom.chatId !== chatRoom.chatId)) {
+ this.handleCallMinimize();
+ }
+ });
+ chatRoom.megaChat.rebind(`sfuConnOpen.${call_NAMESPACE}`, () => this.handleCallOnline());
+ chatRoom.megaChat.rebind(`sfuConnClose.${call_NAMESPACE}`, () => this.handleCallOffline());
+ chatRoom.rebind(`onCallState.${call_NAMESPACE}`, (ev, {
+ arg
+ }) => this.setState({
+ initialCallRinging: arg
+ }));
+ const {
+ tresizer
+ } = $;
+ chatRoom.rebind(`onPeerAvChange.${call_NAMESPACE}`, tresizer);
+ chatRoom.rebind(`onSpeakerChange.${call_NAMESPACE}`, tresizer);
+ this.callStartTimeout = setTimeout(() => {
+ if (!mega.config.get('callemptytout') && !call.hasOtherParticipant()) {
+ call.left = true;
+ call.initCallTimeout();
+ }
+ }, 300000);
+ setTimeout(() => {
+ let _call$peers;
+ return ((_call$peers = call.peers) == null ? void 0 : _call$peers.length) && !call.hasOtherParticipant() && this.setState({
+ everHadPeers: true
+ });
+ }, 2e3);
+ if (sessionStorage.previewMedia) {
+ const {
+ audio,
+ video
+ } = JSON.parse(sessionStorage.previewMedia);
+ sessionStorage.removeItem('previewMedia');
+ tSleep(2).then(() => audio && call.sfuClient.muteAudio()).then(() => video && call.sfuClient.muteCamera()).catch(dump);
+ }
+ this.bindCallEvents();
+ didMount == null || didMount();
+ }
+ componentDidUpdate() {
+ if (typeof psa !== 'undefined') {
+ psa.repositionMeetingsCall();
+ }
+ }
+ render() {
+ let _ref;
+ const {
+ minimized,
+ peers,
+ call,
+ chatRoom,
+ parent,
+ typingAreaText,
+ onDeleteMessage,
+ onTypingAreaChanged
+ } = this.props;
+ const {
+ mode,
+ view,
+ sidebar,
+ hovered,
+ forcedLocal,
+ invite,
+ ephemeral,
+ ephemeralAccounts,
+ guest,
+ offline,
+ onboardingUI,
+ onboardingRecording,
+ onboardingRaise,
+ everHadPeers,
+ initialCallRinging,
+ waitingRoomPeers,
+ recorderCid,
+ raisedHandPeers,
+ recordingConsentDialog,
+ invitePanel,
+ presenterThumbSelected,
+ timeoutBanner,
+ activeElement
+ } = this.state;
+ const {
+ stayOnEnd
+ } = call;
+ const hasOnboarding = onboardingUI || onboardingRecording || onboardingRaise;
+ const STREAM_PROPS = {
+ mode,
+ peers,
+ sidebar,
+ hovered: hasOnboarding || hovered,
+ forcedLocal,
+ call,
+ view,
+ chatRoom,
+ parent,
+ stayOnEnd,
+ everHadPeers,
+ waitingRoomPeers,
+ recorderCid,
+ presenterThumbSelected,
+ raisedHandPeers,
+ activeElement,
+ hasOtherParticipants: call.hasOtherParticipant(),
+ isOnHold: call.sfuClient.isOnHold,
+ isFloatingPresenter: (_ref = mode === utils.g.MINI && !forcedLocal ? call.getActiveStream() : call.getLocalStream()) == null ? void 0 : _ref.hasScreen,
+ onSpeakerChange: this.handleSpeakerChange,
+ onModeChange: this.handleModeChange,
+ onInviteToggle: this.handleInviteToggle,
+ onStayConfirm: this.handleStayConfirm
+ };
+ return JSX_("div", {
+ ref: this.domRef,
+ className: `
+ meetings-call
+ ${minimized ? 'minimized' : ''}
+ ${timeoutBanner ? 'with-timeout-banner' : ''}
+ ${activeElement ? 'with-active-element' : ''}
+ `,
+ onMouseMove: hasOnboarding ? null : this.handleMouseMove,
+ onMouseOut: hasOnboarding ? null : this.handleMouseOut
+ }, timeoutBanner && this.renderTimeLimitBanner(), JSX_(stream_Stream, (0,esm_extends.A)({}, STREAM_PROPS, {
+ minimized,
+ ephemeralAccounts,
+ onCallMinimize: this.handleCallMinimize,
+ onCallExpand: this.handleCallExpand,
+ onCallEnd: this.handleCallEnd,
+ onStreamToggle: this.handleStreamToggle,
+ onRecordingToggle: () => call.sfuClient.recordingStop(),
+ onChatToggle: this.handleChatToggle,
+ onParticipantsToggle: this.handleParticipantsToggle,
+ onAudioClick: () => call.toggleAudio(),
+ onVideoClick: () => call.toggleVideo(),
+ onScreenSharingClick: this.handleScreenSharingToggle,
+ onHoldClick: this.handleHoldToggle,
+ onVideoDoubleClick: this.handleSpeakerChange,
+ setActiveElement: this.setActiveElement
+ })), sidebar && JSX_(Sidebar, (0,esm_extends.A)({}, STREAM_PROPS, {
+ guest,
+ initialCallRinging,
+ typingAreaText,
+ onGuestClose: () => this.setState({
+ guest: false
+ }),
+ onSidebarClose: () => this.setState({
+ ...Call.STATE.DEFAULT
+ }),
+ onDeleteMessage,
+ onCallMinimize: this.handleCallMinimize,
+ onInviteToggle: () => this.handleInviteOrAdd(),
+ onTypingAreaChanged
+ })), minimized ? null : JSX_(REaCt().Fragment, null, this.renderRecordingControl(), JSX_(streamControls, {
+ call,
+ minimized,
+ peers,
+ chatRoom,
+ recorderCid,
+ hovered,
+ raisedHandPeers,
+ onboardingRaise,
+ onOnboardingRaiseDismiss: () => {
+ this.setState({
+ onboardingRaise: false,
+ hovered: false
+ }, () => {
+ this.flagMap.setSync(OBV4_FLAGS.CHAT_CALL_RAISE, 1);
+ this.flagMap.safeCommit();
+ });
+ },
+ onRecordingToggle: () => this.setState({
+ recorderCid: undefined
+ }, () => call.sfuClient.recordingStop()),
+ onAudioClick: () => call.toggleAudio(),
+ onVideoClick: () => call.toggleVideo(),
+ onScreenSharingClick: this.handleScreenSharingToggle,
+ onCallEnd: this.handleCallEnd,
+ onStreamToggle: this.handleStreamToggle,
+ onHoldClick: this.handleHoldToggle,
+ setActiveElement: this.setActiveElement
+ }), JSX_(sidebarControls, {
+ call,
+ chatRoom,
+ npeers: peers.length,
+ mode,
+ view,
+ sidebar,
+ onChatToggle: this.handleChatToggle,
+ onParticipantsToggle: this.handleParticipantsToggle,
+ onInviteToggle: () => this.handleInviteOrAdd()
+ })), invite && JSX_(Invite, {
+ contacts: M.u,
+ call,
+ chatRoom,
+ onClose: () => this.setState({
+ invite: false
+ })
+ }), ephemeral && JSX_(workflow_ephemeral, {
+ ephemeralAccounts,
+ onClose: () => this.setState({
+ ephemeral: false
+ })
+ }), offline && JSX_(meetings_offline, {
+ onClose: () => {
+ if (offline) {
+ this.setState({
+ offline: false
+ }, () => delay('call:timeout', this.handleRetryTimeout, 3e4));
+ }
+ },
+ onCallEnd: () => {
+ this.setState({
+ offline: false
+ }, () => this.handleRetryTimeout());
+ }
+ }), onboardingUI && JSX_("div", {
+ className: `${call_NAMESPACE}-onboarding`
+ }, JSX_("div", {
+ className: "mega-dialog mega-onboarding-dialog dialog-template-message onboarding-UI",
+ id: "ob-dialog",
+ role: "dialog",
+ "aria-labelledby": "ob-dialog-title",
+ "aria-modal": "true"
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-tooltip-arrow tooltip-arrow top",
+ id: "ob-dialog-arrow"
+ }), JSX_("header", null, JSX_("div", null, JSX_("h2", {
+ id: "ob-dialog-title"
+ }, l.onboarding_call_title), JSX_("p", {
+ id: "ob-dialog-text"
+ }, l.onboarding_call_body))), JSX_("footer", null, JSX_("div", {
+ className: "footer-container"
+ }, JSX_("button", {
+ className: "mega-button js-next small theme-light-forced",
+ onClick: () => {
+ this.setState({
+ onboardingUI: false,
+ onboardingRecording: chatRoom.iAmOperator() && !this.flagMap.getSync(OBV4_FLAGS.CHAT_CALL_RECORDING)
+ }, () => {
+ this.flagMap.setSync(OBV4_FLAGS.CHAT_CALL_UI, 1);
+ this.flagMap.safeCommit();
+ this.setState({
+ onboardingRaise: !this.state.onboardingRecording && !this.flagMap.getSync(OBV4_FLAGS.CHAT_CALL_RAISE)
+ });
+ });
+ }
+ }, JSX_("span", null, l.ok_button)))))), onboardingRecording && (0,utils.Cy)(chatRoom, u_handle) && JSX_("div", {
+ className: `${call_NAMESPACE}-onboarding`
+ }, JSX_("div", {
+ className: "mega-dialog mega-onboarding-dialog dialog-template-message onboarding-recording",
+ id: "ob-dialog",
+ role: "dialog",
+ "aria-labelledby": "ob-dialog-title",
+ "aria-modal": "true"
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-tooltip-arrow tooltip-arrow bottom",
+ id: "ob-dialog-arrow"
+ }), JSX_("header", null, JSX_("div", null, JSX_("h2", {
+ id: "ob-dialog-title"
+ }, l.recording_onboarding_title), JSX_("p", {
+ id: "ob-dialog-text"
+ }, l.recording_onboarding_body_intro), JSX_("p", {
+ id: "ob-dialog-text"
+ }, l.recording_onboarding_body_details))), JSX_("footer", null, JSX_("div", {
+ className: "footer-container"
+ }, JSX_(ui_link.A, {
+ className: "link-button",
+ to: "https://help.mega.io/chats-meetings/chats/call-recording",
+ target: "_blank"
+ }, l[8742]), JSX_("button", {
+ className: "mega-button js-next small theme-light-forced",
+ onClick: () => {
+ this.setState({
+ onboardingRecording: false,
+ onboardingRaise: true
+ }, () => {
+ this.flagMap.setSync(OBV4_FLAGS.CHAT_CALL_RECORDING, 1);
+ this.flagMap.safeCommit();
+ });
+ }
+ }, JSX_("span", null, l.ok_button)))))), recordingConsentDialog && JSX_(RecordingConsentDialog, {
+ peers,
+ recorderCid,
+ onClose: () => this.setState({
+ recordingConsentDialog: false,
+ recordingConsented: true
+ }),
+ onCallEnd: this.handleCallEnd
+ }), invitePanel && JSX_(modalDialogs.A.ModalDialog, {
+ className: "theme-dark-forced",
+ onClose: () => {
+ this.setState({
+ invitePanel: false
+ });
+ },
+ dialogName: "chat-link-dialog",
+ chatRoom
+ }, JSX_(inviteParticipantsPanel.Q, {
+ chatRoom,
+ onAddParticipants: () => {
+ this.setState({
+ invitePanel: false
+ }, () => this.handleInviteToggle());
+ }
+ })));
+ }
+}
+Call.STATE = {
+ DEFAULT: {
+ sidebar: false
+ },
+ PREVIOUS: {
+ mode: null,
+ sidebar: null,
+ view: null
+ }
+};
+
+ },
+
+ 192
+(_, EXP_, REQ_) {
+
+ REQ_.d(EXP_, {
+ $: () => withPermissionsObserver
+ });
+ const _babel_runtime_helpers_extends0__ = REQ_(8168);
+ const react1__ = REQ_(1594);
+ const react1___default = REQ_.n(react1__);
+ const _mixins_js2__ = REQ_(8264);
+ const _ui_modalDialogs_jsx3__ = REQ_(8120);
+ const _ui_utils_jsx4__ = REQ_(6411);
+
+
+
+
+
+const errors = {
+ browser: 'NotAllowedError: Permission denied',
+ system: 'NotAllowedError: Permission denied by system',
+ dismissed: 'NotAllowedError: Permission dismissed',
+ nil: 'NotFoundError: Requested device not found',
+ sharedCam: 'NotReadableError: Could not start video source',
+ sharedMic: 'NotReadableError: Could not start audio source',
+ sharedGeneric: 'NotReadableError: Device in use'
+};
+const isUserActionError = error => {
+ return error && error === errors.browser;
+};
+const withPermissionsObserver = Component => {
+ return class extends _mixins_js2__ .w9 {
+ constructor(props) {
+ super(props);
+ this.namespace = `PO-${Component.NAMESPACE}`;
+ this.observer = `onLocalMediaError.${this.namespace}`;
+ this.childRef = undefined;
+ this.platform = ua.details.os;
+ this.helpURL = `${l.mega_help_host}/chats-meetings/meetings/enable-audio-video-call-permissions`;
+ this.macURI = 'x-apple.systempreferences:com.apple.preference.security';
+ this.winURI = 'ms-settings';
+ this.CONTENT = {
+ [Av.Audio]: {
+ system: {
+ title: l.no_mic_title,
+ info: this.platform === 'Windows' ? l.no_mic_system_windows.replace('[A]', ``).replace('[/A]', '') : l.no_mic_system_mac.replace('[A]', ``).replace('[/A]', ''),
+ buttons: [this.platform === 'Apple' || this.platform === 'Windows' ? {
+ key: 'open-settings',
+ label: l.open_system_settings,
+ className: 'positive',
+ onClick: () => {
+ window.open(this.platform === 'Apple' ? `${this.macURI}?Privacy_Microphone` : `${this.winURI}:privacy-microphone`, '_blank', 'noopener,noreferrer');
+ this.closePermissionsDialog(Av.Audio);
+ }
+ } : {
+ key: 'ok',
+ label: l.ok_button,
+ className: 'positive',
+ onClick: () => this.closePermissionsDialog(Av.Audio)
+ }]
+ },
+ browser: {
+ title: l.no_mic_title,
+ cover: 'permissions-mic',
+ info: l.allow_mic_access.replace('[X]', ''),
+ buttons: [{
+ key: 'ok',
+ label: l.ok_button,
+ className: 'positive',
+ onClick: () => this.closePermissionsDialog(Av.Audio)
+ }]
+ },
+ nil: {
+ title: l.no_mic_detected_title,
+ info: l.no_mic_detected_info,
+ buttons: [{
+ key: 'ok',
+ label: l.ok_button,
+ className: 'positive',
+ onClick: () => this.closePermissionsDialog(Av.Audio)
+ }]
+ },
+ shared: {
+ title: l.no_mic_title,
+ info: l.shared_mic_err_info.replace('[A]', ``).replace('[/A]', ''),
+ buttons: [{
+ key: 'ok',
+ label: l.ok_button,
+ className: 'positive',
+ onClick: () => this.closePermissionsDialog(Av.Audio)
+ }]
+ }
+ },
+ [Av.Camera]: {
+ system: {
+ title: l.no_camera_title,
+ info: this.platform === 'Windows' ? l.no_camera_system_windows.replace('[A]', ``).replace('[/A]', '') : l.no_camera_system_mac.replace('[A]', ``).replace('[/A]', ''),
+ buttons: [this.platform === 'Apple' || this.platform === 'Windows' ? {
+ key: 'open-settings',
+ label: l.open_system_settings,
+ className: 'positive',
+ onClick: () => {
+ window.open(this.platform === 'Apple' ? `${this.macURI}?Privacy_Camera` : `${this.winURI}:privacy-webcam`, '_blank', 'noopener,noreferrer');
+ this.closePermissionsDialog(Av.Camera);
+ }
+ } : {
+ key: 'ok',
+ label: l.ok_button,
+ className: 'positive',
+ onClick: () => this.closePermissionsDialog(Av.Camera)
+ }]
+ },
+ browser: {
+ title: l.no_camera_title,
+ cover: 'permissions-camera',
+ info: l.allow_camera_access.replace('[X]', ''),
+ buttons: [{
+ key: 'ok',
+ label: l.ok_button,
+ className: 'positive',
+ onClick: () => this.closePermissionsDialog(Av.Camera)
+ }]
+ },
+ nil: {
+ title: l.no_camera_detected_title,
+ info: l.no_camera_detected_info,
+ buttons: [{
+ key: 'ok',
+ label: l.ok_button,
+ className: 'positive',
+ onClick: () => this.closePermissionsDialog(Av.Camera)
+ }]
+ },
+ shared: {
+ title: l.no_camera_title,
+ info: l.shared_cam_err_info.replace('[A]', ``).replace('[/A]', ''),
+ buttons: [{
+ key: 'ok',
+ label: l.ok_button,
+ className: 'positive',
+ onClick: () => this.closePermissionsDialog(Av.Camera)
+ }]
+ }
+ },
+ [Av.Screen]: {
+ title: l.no_screen_title,
+ info: l.no_screen_system.replace('[A]', ``).replace('[/A]', ''),
+ buttons: [{
+ key: 'open-settings',
+ label: l.open_system_settings,
+ className: 'positive',
+ onClick: () => {
+ window.open(`${this.macURI}?Privacy_ScreenCapture`, '_blank', 'noopener,noreferrer');
+ this.closePermissionsDialog(Av.Screen);
+ }
+ }]
+ }
+ };
+ this.state = {
+ errMic: '',
+ errCamera: '',
+ errScreen: '',
+ [`dialog-${Av.Audio}`]: null,
+ [`dialog-${Av.Camera}`]: null,
+ [`dialog-${Av.Screen}`]: null
+ };
+ this.getPermissionsDialogContent = () => {
+ const {
+ CONTENT,
+ state
+ } = this;
+ const {
+ errMic,
+ errCamera
+ } = state;
+ const {
+ browser,
+ system,
+ nil,
+ sharedCam,
+ sharedMic,
+ sharedGeneric
+ } = errors;
+ return {
+ [Av.Audio]: {
+ ...errMic === browser && CONTENT[Av.Audio].browser,
+ ...errMic === system && CONTENT[Av.Audio].system,
+ ...errMic === nil && CONTENT[Av.Audio].nil,
+ ...errMic === sharedMic && CONTENT[Av.Audio].shared,
+ ...errMic === sharedGeneric && CONTENT[Av.Audio].shared
+ },
+ [Av.Camera]: {
+ ...errCamera === browser && CONTENT[Av.Camera].browser,
+ ...errCamera === system && CONTENT[Av.Camera].system,
+ ...errCamera === nil && CONTENT[Av.Camera].nil,
+ ...errCamera === sharedCam && CONTENT[Av.Camera].shared,
+ ...errCamera === sharedGeneric && CONTENT[Av.Camera].shared
+ },
+ [Av.Screen]: CONTENT[Av.Screen]
+ };
+ };
+ this.resetError = av => {
+ this.setState({
+ errMic: av === Av.Audio ? '' : this.state.errMic,
+ errCamera: av === Av.Camera ? '' : this.state.errCamera,
+ errScreen: av === Av.Screen ? '' : this.state.errScreen
+ });
+ };
+ this.hasToRenderPermissionsWarning = this.hasToRenderPermissionsWarning.bind(this);
+ this.renderPermissionsWarning = this.renderPermissionsWarning.bind(this);
+ }
+ hasToRenderPermissionsWarning(av) {
+ const CONFIG = {
+ [Av.Audio]: {
+ showOnUserActionError: true,
+ err: this.state.errMic
+ },
+ [Av.Camera]: {
+ showOnUserActionError: true,
+ err: this.state.errCamera
+ },
+ [Av.Screen]: {
+ showOnUserActionError: false,
+ err: this.state.errScreen
+ }
+ };
+ const current = CONFIG[av];
+ if (current) {
+ return isUserActionError(current.err) ? current.showOnUserActionError : current.err;
+ }
+ return false;
+ }
+ closePermissionsDialog(av) {
+ this.setState({
+ [`dialog-${av}`]: false
+ }, () => {
+ let _this$childRef;
+ return (_this$childRef = this.childRef) == null ? void 0 : _this$childRef.safeForceUpdate();
+ });
+ }
+ renderPermissionsDialog(av, child) {
+ const content = this.getPermissionsDialogContent();
+ const {
+ title,
+ info,
+ buttons,
+ cover
+ } = content[av] || {};
+ return JSX_(_ui_modalDialogs_jsx3__ .A.ModalDialog, {
+ dialogName: `${this.namespace}-permissions-${av}`,
+ className: `
+ meetings-permissions-dialog
+ dialog-template-message
+ with-close-btn
+ warning
+ `,
+ buttons,
+ hideOverlay: Component.NAMESPACE === 'preview-meeting' && !document.body.classList.contains('not-logged'),
+ onClose: () => {
+ this.setState({
+ [`dialog-${av}`]: false
+ }, () => child && child.safeForceUpdate());
+ }
+ }, JSX_("header", null, cover ? null : JSX_("div", {
+ className: "graphic"
+ }, JSX_("i", {
+ className: "warning sprite-fm-uni icon-warning"
+ })), JSX_("div", {
+ className: "info-container"
+ }, JSX_("h3", {
+ id: "msgDialog-title"
+ }, title || l[47]), cover && JSX_("div", {
+ className: "permissions-warning-cover"
+ }, JSX_("span", {
+ className: cover
+ })), JSX_(_ui_utils_jsx4__ .P9, {
+ tag: "p",
+ className: "permissions-warning-info",
+ content: info
+ }))));
+ }
+ renderPermissionsWarning(av, child) {
+ const {
+ errMic,
+ errCamera
+ } = this.state;
+ const dismissed = errMic === errors.dismissed || errCamera === errors.dismissed;
+ return JSX_("div", {
+ className: `
+ ${this.namespace}
+ meetings-signal-issue
+ simpletip
+ ${dismissed ? 'with-small-area' : ''}
+ `,
+ "data-simpletip": l.show_info,
+ "data-simpletipposition": "top",
+ "data-simpletipoffset": "5",
+ "data-simpletip-class": "theme-dark-forced",
+ onClick: () => dismissed ? null : this.setState({
+ [`dialog-${av}`]: true
+ }, () => {
+ if (child) {
+ this.childRef = child;
+ }
+ })
+ }, JSX_("span", {
+ className: "signal-issue-background"
+ }), JSX_("i", {
+ className: "sprite-fm-mono icon-exclamation-filled"
+ }), this.state[`dialog-${av}`] && this.renderPermissionsDialog(av, child));
+ }
+ componentWillUnmount() {
+ super.componentWillUnmount();
+ megaChat.unbind(this.observer);
+ }
+ componentDidMount() {
+ super.componentDidMount();
+ megaChat.rebind(this.observer, (ev, errAv) => {
+ this.setState({
+ errMic: errAv && errAv.mic ? String(errAv.mic) : this.state.errMic,
+ errCamera: errAv && errAv.camera ? String(errAv.camera) : this.state.errCamera,
+ errScreen: errAv && errAv.screen ? String(errAv.screen) : this.state.errScreen
+ });
+ });
+ megaChat.rebind(`onLocalMediaQueryError.${this.namespace}`, (ev, {
+ type,
+ err
+ }) => {
+ if (type === 'screen' && String(err) === errors.system) {
+ this.setState({
+ [`dialog-${Av.Screen}`]: true
+ }, () => this.safeForceUpdate());
+ }
+ });
+ }
+ render() {
+ return JSX_(Component, (0,_babel_runtime_helpers_extends0__ .A)({}, this.props, this.state, {
+ errMic: this.state.errMic,
+ errCamera: this.state.errCamera,
+ errScreen: this.state.errScreen,
+ hasToRenderPermissionsWarning: this.hasToRenderPermissionsWarning,
+ resetError: this.resetError,
+ renderPermissionsWarning: this.renderPermissionsWarning
+ }));
+ }
+ };
+};
+
+ },
+
+ 7128
+(_, EXP_, REQ_) {
+
+REQ_.r(EXP_);
+ REQ_.d(EXP_, {
+ "default": () => Join
+ });
+ const react0__ = REQ_(1594);
+ const react0___default = REQ_.n(react0__);
+ const _ui_modalDialogs_jsx1__ = REQ_(8120);
+ const _ui_utils_jsx2__ = REQ_(6411);
+ const _button_jsx3__ = REQ_(6740);
+ const _preview_jsx4__ = REQ_(3546);
+ const _historyPanel_jsx5__ = REQ_(5522);
+ const _link_jsx6__ = REQ_(4649);
+ const _utils_jsx7__ = REQ_(2153);
+
+
+
+
+
+
+
+
+class Join extends react0___default().Component {
+ constructor(props) {
+ super(props);
+ this.NAMESPACE = 'join-meeting';
+ this.state = {
+ preview: false,
+ view: _utils_jsx7__ .j.INITIAL,
+ firstName: '',
+ lastName: '',
+ previewAudio: true,
+ previewVideo: false,
+ ephemeralDialog: false
+ };
+ this.handleKeyDown = ({
+ key
+ }) => {
+ let _this$props$onClose, _this$props;
+ return key && key === 'Escape' ? (_this$props$onClose = (_this$props = this.props).onClose) == null ? void 0 : _this$props$onClose.call(_this$props) : true;
+ };
+ this.showPanels = () => {
+ return [document.querySelector('.nw-fm-left-icons-panel'), document.querySelector('.chat-app-container')].map(el => el && el.classList.remove('hidden'));
+ };
+ this.hidePanels = () => {
+ return [document.querySelector('.nw-fm-left-icons-panel'), document.querySelector('.chat-app-container')].map(el => el && el.classList.add('hidden'));
+ };
+ this.showConfirmationDialog = () => {
+ megaChat.destroy();
+ return mega.ui.sendSignupLinkDialog(JSON.parse(localStorage.awaitingConfirmationAccount), () => {
+ delete localStorage.awaitingConfirmationAccount;
+ u_logout(true).then(() => location.reload());
+ });
+ };
+ this.Ephemeral = () => {
+ const onCancel = () => this.setState({
+ ephemeralDialog: false
+ });
+ const msgFragments = l.ephemeral_data_lost.split(/\[A]|\[\/A]/);
+ return JSX_(_ui_modalDialogs_jsx1__ .A.ModalDialog, {
+ name: "end-ephemeral",
+ dialogType: "message",
+ icon: "sprite-fm-uni icon-warning",
+ title: l.ephemeral_data_lost_title,
+ noCloseOnClickOutside: true,
+ buttons: [{
+ key: 'cancel',
+ label: l.msg_dlg_cancel,
+ onClick: onCancel
+ }, {
+ key: 'continue',
+ label: l[507],
+ className: 'positive',
+ onClick: () => {
+ u_logout(true).then(() => location.reload());
+ sessionStorage.guestForced = true;
+ }
+ }],
+ onClose: onCancel
+ }, JSX_("p", null, msgFragments[0], JSX_(_link_jsx6__ .A, {
+ to: "/register",
+ onClick: () => loadSubPage('register')
+ }, msgFragments[1]), msgFragments[2]));
+ };
+ this.Head = () => {
+ let _this$props$chatRoom;
+ return JSX_("div", {
+ className: `${this.NAMESPACE}-head`
+ }, JSX_("div", {
+ className: `${this.NAMESPACE}-logo`
+ }, JSX_("i", {
+ className: `
+ sprite-fm-illustration-wide
+ ${mega.ui.isDarkTheme() ? 'mega-logo-dark' : 'img-mega-logo-light'}
+ `
+ })), JSX_("h1", null, JSX_(_ui_utils_jsx2__ .zT, null, l.you_have_invitation.replace('%1', (_this$props$chatRoom = this.props.chatRoom) == null ? void 0 : _this$props$chatRoom.topic))), isEphemeral() && JSX_("div", {
+ className: "ephemeral-info"
+ }, JSX_("i", {
+ className: "sprite-fm-uni icon-warning"
+ }), JSX_("p", null, l.ephemeral_data_store_lost)));
+ };
+ this.Intro = () => {
+ const $$CONTAINER = ({
+ children
+ }) => JSX_(react0___default().Fragment, null, JSX_("div", {
+ className: `${this.NAMESPACE}-content`
+ }, children), this.Chat());
+ if (isEphemeral()) {
+ return JSX_($$CONTAINER, null, JSX_(_button_jsx3__ .A, {
+ className: "mega-button positive",
+ onClick: () => this.setState({
+ ephemeralDialog: true
+ })
+ }, l.join_as_guest), JSX_(_button_jsx3__ .A, {
+ className: "mega-button",
+ onClick: () => loadSubPage('register')
+ }, l[5582]), JSX_("span", null, l[5585], JSX_("a", {
+ href: "#",
+ onClick: () => mega.ui.showLoginRequiredDialog({
+ minUserType: 3,
+ skipInitialDialog: 1
+ }).done(() => this.setState({
+ view: _utils_jsx7__ .j.ACCOUNT
+ }))
+ }, l[171])));
+ }
+ return JSX_($$CONTAINER, null, JSX_(_button_jsx3__ .A, {
+ className: "mega-button positive",
+ onClick: () => this.setState({
+ view: _utils_jsx7__ .j.GUEST
+ })
+ }, l.join_as_guest), JSX_(_button_jsx3__ .A, {
+ className: "mega-button",
+ onClick: () => {
+ let _this$props$chatRoom2;
+ megaChat.loginOrRegisterBeforeJoining((_this$props$chatRoom2 = this.props.chatRoom) == null ? void 0 : _this$props$chatRoom2.publicChatHandle, false, true, undefined, () => this.setState({
+ view: _utils_jsx7__ .j.ACCOUNT
+ }));
+ }
+ }, l[171]), JSX_("p", null, JSX_(_ui_utils_jsx2__ .P9, {
+ onClick: e => {
+ e.preventDefault();
+ megaChat.loginOrRegisterBeforeJoining(this.props.chatRoom.publicChatHandle, true, undefined, undefined, () => this.setState({
+ view: _utils_jsx7__ .j.ACCOUNT
+ }));
+ }
+ }, l[20635])));
+ };
+ this.Chat = () => {
+ const {
+ chatRoom
+ } = this.props;
+ const {
+ preview
+ } = this.state;
+ return JSX_("div", {
+ className: `
+ ${this.NAMESPACE}-chat
+ ${preview ? 'expanded' : ''}
+ `
+ }, JSX_("div", {
+ className: "chat-content"
+ }, JSX_("div", {
+ className: "chat-content-head",
+ onClick: () => this.setState({
+ preview: !preview
+ })
+ }, JSX_(_ui_utils_jsx2__ .zT, null, chatRoom.topic), JSX_(_button_jsx3__ .A, {
+ icon: "icon-minimise"
+ })), preview && JSX_("div", {
+ className: "chat-body"
+ }, JSX_(_historyPanel_jsx5__ .A, {
+ chatRoom,
+ onMount: cmp => {
+ let _cmp$messagesListScro;
+ return (_cmp$messagesListScro = cmp.messagesListScrollable) == null ? void 0 : _cmp$messagesListScro.scrollToBottom();
+ }
+ }))));
+ };
+ this.Card = ({
+ children
+ }) => {
+ const {
+ previewAudio,
+ previewVideo
+ } = this.state;
+ return JSX_("div", {
+ className: "card"
+ }, JSX_("div", {
+ className: "card-body"
+ }, children, JSX_("div", null, JSX_(_link_jsx6__ .A, {
+ to: "https://mega.io/chatandmeetings",
+ target: "_blank"
+ }, l.how_meetings_work))), JSX_("div", {
+ className: "card-preview"
+ }, JSX_(_preview_jsx4__ .A, {
+ audio: previewAudio,
+ video: previewVideo,
+ context: this.NAMESPACE,
+ onToggle: (audio, video) => this.setState({
+ previewAudio: audio,
+ previewVideo: video
+ })
+ })));
+ };
+ this.Field = ({
+ name,
+ children
+ }) => {
+ let _this$state$name;
+ return JSX_("div", {
+ className: `
+ mega-input
+ title-ontop
+ ${(_this$state$name = this.state[name]) != null && _this$state$name.length ? 'valued' : ''}
+ `
+ }, JSX_("div", {
+ className: "mega-input-title"
+ }, children, JSX_("span", {
+ className: "required-red"
+ }, "*")), JSX_("input", {
+ type: "text",
+ name,
+ className: "titleTop required megaInputs",
+ placeholder: children,
+ value: this.state[name] || '',
+ maxLength: 40,
+ onChange: ev => this.setState({
+ [name]: ev.target.value
+ })
+ }));
+ };
+ this.Guest = () => JSX_(this.Card, null, JSX_("h2", null, l.enter_name_join_meeting), JSX_("div", {
+ className: "card-fields"
+ }, JSX_(this.Field, {
+ name: "firstName"
+ }, l[1096]), JSX_(this.Field, {
+ name: "lastName"
+ }, l[1097])), JSX_(_button_jsx3__ .A, {
+ className: `
+ mega-button
+ positive
+ large
+ ${this.state.firstName.length && this.state.lastName.length ? '' : 'disabled'}
+ ${this.state.joining && " loading disabled"}
+ `,
+ onClick: () => {
+ if (this.state.joining) {
+ return;
+ }
+ let {
+ firstName,
+ lastName,
+ previewAudio,
+ previewVideo
+ } = this.state;
+ firstName = firstName && firstName.trim();
+ lastName = lastName && lastName.trim();
+ if (firstName && lastName && firstName.length > 0 && lastName.length > 0) {
+ this.setState({
+ 'joining': true
+ });
+ if (this.props.chatRoom.scheduledMeeting) {
+ delay('chat-event-sm-guest-join', () => eventlog(99929));
+ }
+ this.props.onJoinGuestClick(firstName, lastName, previewAudio, previewVideo);
+ }
+ }
+ }, l.join_chat_button));
+ this.Account = () => JSX_(this.Card, null, JSX_("h4", null, l.join_meeting), JSX_(_button_jsx3__ .A, {
+ className: `mega-button positive large ${this.state.joining && " loading disabled"}`,
+ onClick: () => {
+ if (!this.state.joining) {
+ this.setState({
+ 'joining': true
+ });
+ this.props.onJoinClick(this.state.previewAudio, this.state.previewVideo);
+ }
+ }
+ }, l.join_chat_button));
+ this.Unsupported = () => JSX_("div", {
+ className: "meetings-unsupported-container"
+ }, JSX_("i", {
+ className: "sprite-fm-uni icon-error"
+ }), JSX_("div", {
+ className: "unsupported-info"
+ }, JSX_("h3", null, l.heading_unsupported_browser), JSX_("h3", null, l.join_meeting_methods), JSX_("ul", null, JSX_("li", null, l.join_via_link), JSX_("li", null, JSX_(_ui_utils_jsx2__ .P9, null, l.join_via_mobile.replace('[A]', '').replace('[/A]', ''))))));
+ this.View = view => {
+ switch (view) {
+ default:
+ return this.Intro();
+ case _utils_jsx7__ .j.GUEST:
+ return this.Guest();
+ case _utils_jsx7__ .j.ACCOUNT:
+ return this.Account();
+ case _utils_jsx7__ .j.UNSUPPORTED:
+ return this.Unsupported();
+ }
+ };
+ this.state.view = sessionStorage.guestForced ? _utils_jsx7__ .j.GUEST : props.initialView || this.state.view;
+ if (localStorage.awaitingConfirmationAccount) {
+ this.showConfirmationDialog();
+ }
+ }
+ componentDidMount() {
+ document.addEventListener('keydown', this.handleKeyDown);
+ this.hidePanels();
+ megaChat._joinDialogIsShown = true;
+ alarm.hideAllWarningPopups();
+ sessionStorage.removeItem('guestForced');
+ if (!megaChat.hasSupportForCalls) {
+ this.setState({
+ view: _utils_jsx7__ .j.UNSUPPORTED
+ });
+ }
+ }
+ componentWillUnmount() {
+ document.removeEventListener('keydown', this.handleKeyDown);
+ this.showPanels();
+ megaChat._joinDialogIsShown = false;
+ if (this.props.onClose) {
+ this.props.onClose();
+ }
+ }
+ render() {
+ const {
+ view,
+ ephemeralDialog
+ } = this.state;
+ return JSX_(_ui_utils_jsx2__ .Ay.RenderTo, {
+ element: document.body
+ }, JSX_("div", {
+ className: this.NAMESPACE
+ }, this.Head(), this.View(view), ephemeralDialog && JSX_(this.Ephemeral, null)));
+ }
+}
+
+ },
+
+ 2914
+(_, EXP_, REQ_) {
+
+REQ_.r(EXP_);
+ REQ_.d(EXP_, {
+ "default": () => Loading
+ });
+ const react0__ = REQ_(1594);
+ const react0___default = REQ_.n(react0__);
+
+class Loading extends react0___default().Component {
+ constructor(...args) {
+ super(...args);
+ this.domRef = react0___default().createRef();
+ this.PERMISSIONS = {
+ VIDEO: 'camera',
+ AUDIO: 'microphone'
+ };
+ this.state = {
+ pendingPermissions: false
+ };
+ this.queryPermissions = name => {
+ navigator.permissions.query({
+ name
+ }).then(status => {
+ const {
+ name,
+ state
+ } = status;
+ status.onchange = () => name === 'audio_capture' && this.queryPermissions(this.PERMISSIONS.VIDEO);
+ if (state === 'prompt') {
+ return this.domRef.current && this.setState({
+ pendingPermissions: name
+ });
+ }
+ }).catch(ex => console.warn(`Failed to get permissions state: ${ex}`));
+ };
+ this.renderLoading = () => {
+ return JSX_(react0___default().Fragment, null, JSX_("span", null, JSX_("i", {
+ className: "sprite-fm-mono icon-video-call-filled"
+ })), JSX_("h3", null, this.props.title || l[5533]), JSX_("div", {
+ className: "loading-container"
+ }, JSX_("div", {
+ className: "loading-indication"
+ })));
+ };
+ this.renderDebug = () => {
+ const {
+ chatRoom
+ } = this.props;
+ if (chatRoom && chatRoom.call) {
+ return JSX_("div", {
+ className: `${Loading.NAMESPACE}-debug`
+ }, JSX_("div", null, "callId: ", chatRoom.call.callId), JSX_("div", null, "roomId: ", chatRoom.roomId), JSX_("div", null, "isMeeting: ", chatRoom.isMeeting ? 'true' : 'false'));
+ }
+ };
+ }
+ componentWillUnmount() {
+ megaChat.unbind(`onLocalMediaQueryError.${Loading.NAMESPACE}`);
+ }
+ componentDidMount() {
+ let _notify, _alarm;
+ document.dispatchEvent(new Event('closeDropdowns'));
+ if ($.dialog) {
+ closeDialog == null || closeDialog();
+ }
+ mega.ui.mInfoPanel.hide();
+ (_notify = notify) == null || _notify.closePopup();
+ (_alarm = alarm) == null || _alarm.hideAllWarningPopups();
+ document.querySelectorAll('.js-dropdown-account').forEach(({
+ classList
+ }) => classList.contains('show') && classList.remove('show'));
+ const {
+ chatRoom
+ } = this.props;
+ const {
+ audio,
+ video
+ } = chatRoom.meetingsLoading;
+ const isVideoCall = audio && video;
+ if (audio && !video) {
+ this.queryPermissions(this.PERMISSIONS.AUDIO);
+ }
+ if (isVideoCall) {
+ Object.values(this.PERMISSIONS).forEach(name => this.queryPermissions(name));
+ }
+ megaChat.rebind(`onLocalMediaQueryError.${Loading.NAMESPACE}`, (ev, {
+ type,
+ err
+ }) => {
+ if (isVideoCall && type === 'mic' && String(err).includes('dismissed')) {
+ this.queryPermissions(this.PERMISSIONS.VIDEO);
+ }
+ });
+ }
+ render() {
+ const {
+ pendingPermissions
+ } = this.state;
+ return JSX_("div", {
+ ref: this.domRef,
+ className: Loading.NAMESPACE
+ }, JSX_("div", {
+ className: `${Loading.NAMESPACE}-content`
+ }, pendingPermissions ? JSX_("h2", null, pendingPermissions === 'audio_capture' ? l.permissions_allow_mic : l.permissions_allow_camera) : this.renderLoading()), d ? this.renderDebug() : '');
+ }
+}
+Loading.NAMESPACE = 'meetings-loading';
+
+ },
+
+ 3546
+(_, EXP_, REQ_) {
+
+ REQ_.d(EXP_, {
+ A: () => __WEBPACK_DEFAULT_EXPORT__
+ });
+ const react0__ = REQ_(1594);
+ const react0___default = REQ_.n(react0__);
+ const _mixins_js1__ = REQ_(8264);
+ const _contacts_jsx2__ = REQ_(8022);
+ const _utils_jsx3__ = REQ_(3901);
+ const _button_jsx4__ = REQ_(6740);
+ const _permissionsObserver_jsx5__ = REQ_(192);
+
+
+
+
+
+
+class Preview extends react0___default().Component {
+ constructor(props) {
+ super(props);
+ this.domRef = react0___default().createRef();
+ this.videoRef = react0___default().createRef();
+ this.stream = null;
+ this.state = {
+ audio: false,
+ video: false,
+ avatarMeta: undefined
+ };
+ this.getTrackType = type => !type ? 'getTracks' : type === Preview.STREAMS.AUDIO ? 'getAudioTracks' : 'getVideoTracks';
+ this.startStream = type => {
+ this.stopStream();
+ const {
+ audio,
+ video
+ } = this.state;
+ navigator.mediaDevices.getUserMedia({
+ audio,
+ video
+ }).then(stream => {
+ const videoRef = this.videoRef.current;
+ if (videoRef) {
+ videoRef.srcObject = stream;
+ this.stream = stream;
+ if (this.props.onToggle) {
+ this.props.onToggle(this.state.audio, this.state.video);
+ }
+ }
+ }).catch(ex => {
+ const stream = type === Preview.STREAMS.AUDIO ? 'audio' : 'video';
+ return this.domRef.current && this.setState(state => ({
+ [stream]: !state[stream]
+ }), () => {
+ megaChat.trigger('onLocalMediaError', {
+ [type === Preview.STREAMS.AUDIO ? 'mic' : 'camera']: `${ex.name}: ${ex.message}`
+ });
+ console.error(`${ex.name}: ${ex.message}`);
+ });
+ });
+ };
+ this.stopStream = type => {
+ if (this.stream) {
+ const trackType = this.getTrackType(type);
+ const tracks = this.stream[trackType]();
+ for (const track of tracks) {
+ track.stop();
+ }
+ }
+ };
+ this.toggleStream = type => {
+ let _this$props$resetErro, _this$props;
+ const stream = type === Preview.STREAMS.AUDIO ? 'audio' : 'video';
+ this.setState(state => ({
+ [stream]: !state[stream]
+ }), () => {
+ if (this.props.onToggle) {
+ this.props.onToggle(this.state.audio, this.state.video);
+ }
+ return this.state[stream] ? this.startStream(type) : this.stopStream(type);
+ });
+ (_this$props$resetErro = (_this$props = this.props).resetError) == null || _this$props$resetErro.call(_this$props, type === Preview.STREAMS.AUDIO ? Av.Audio : Av.Camera);
+ };
+ this.renderAvatar = () => {
+ if ((0,_utils_jsx3__ .P)()) {
+ return JSX_("div", {
+ className: "avatar-guest"
+ }, JSX_("i", {
+ className: "sprite-fm-uni icon-owner"
+ }));
+ }
+ if (is_chatlink) {
+ const {
+ avatarUrl,
+ color,
+ shortName
+ } = this.state.avatarMeta || {};
+ return JSX_("div", {
+ className: `
+ avatar-wrapper
+ ${color ? `color${color}` : ''}
+ `
+ }, avatarUrl && JSX_("img", {
+ src: avatarUrl,
+ alt: ""
+ }), color && JSX_("span", null, shortName));
+ }
+ return JSX_(_contacts_jsx2__ .eu, {
+ contact: M.u[u_handle]
+ });
+ };
+ this.state.audio = this.props.audio || this.state.audio;
+ if (this.props.video) {
+ this.state.video = this.props.video;
+ this.startStream(Preview.STREAMS.VIDEO);
+ this.props.onToggle(this.state.audio, this.state.video);
+ }
+ }
+ componentWillUnmount() {
+ this.stopStream();
+ }
+ componentDidMount() {
+ if (this.props.onToggle) {
+ this.props.onToggle(this.state.audio, this.state.video);
+ }
+ this.setState({
+ avatarMeta: is_chatlink ? generateAvatarMeta(u_handle) : undefined
+ });
+ }
+ render() {
+ const {
+ NAMESPACE
+ } = Preview;
+ const {
+ hasToRenderPermissionsWarning,
+ renderPermissionsWarning
+ } = this.props;
+ const {
+ audio,
+ video
+ } = this.state;
+ const SIMPLETIP_PROPS = {
+ label: undefined,
+ position: 'top',
+ className: 'theme-dark-forced'
+ };
+ return JSX_("div", {
+ ref: this.domRef,
+ className: `
+ ${NAMESPACE}
+ local-stream-mirrored
+ `
+ }, video && JSX_("div", {
+ className: `${NAMESPACE}-video-overlay`
+ }), JSX_("video", {
+ className: video ? 'streaming' : '',
+ muted: true,
+ autoPlay: true,
+ ref: this.videoRef
+ }), !video && this.renderAvatar(), JSX_("div", {
+ className: `${NAMESPACE}-controls`
+ }, JSX_("div", {
+ className: "preview-control-wrapper"
+ }, JSX_(_button_jsx4__ .A, {
+ simpletip: {
+ ...SIMPLETIP_PROPS,
+ label: audio ? l[16214] : l[16708]
+ },
+ className: `
+ mega-button
+ round
+ theme-light-forced
+ ${NAMESPACE}-control
+ ${audio ? '' : 'with-fill'}
+ `,
+ icon: audio ? 'icon-mic-thin-outline' : 'icon-mic-off-thin-outline',
+ onClick: () => {
+ this.toggleStream(Preview.STREAMS.AUDIO);
+ }
+ }), JSX_("span", null, l.mic_button), hasToRenderPermissionsWarning(Av.Audio) ? renderPermissionsWarning(Av.Audio) : null), JSX_("div", {
+ className: "preview-control-wrapper"
+ }, JSX_(_button_jsx4__ .A, {
+ simpletip: {
+ ...SIMPLETIP_PROPS,
+ label: video ? l[22894] : l[22893]
+ },
+ className: `
+ mega-button
+ round
+ theme-light-forced
+ ${NAMESPACE}-control
+ ${video ? '' : 'with-fill'}
+ `,
+ icon: video ? 'icon-video-thin-outline' : 'icon-video-off-thin-outline',
+ onClick: () => this.toggleStream(Preview.STREAMS.VIDEO)
+ }), JSX_("span", null, l.camera_button), hasToRenderPermissionsWarning(Av.Camera) ? renderPermissionsWarning(Av.Camera) : null)));
+ }
+}
+Preview.NAMESPACE = 'preview-meeting';
+Preview.STREAMS = {
+ AUDIO: 1,
+ VIDEO: 2
+};
+ const __WEBPACK_DEFAULT_EXPORT__ = (0,_mixins_js1__ .Zz)(_permissionsObserver_jsx5__ .$)(Preview);
+
+ }
+
+}]);
\ No newline at end of file
diff --git a/js/chat/bundle.cloud-browser.js b/js/chat/bundle.cloud-browser.js
new file mode 100644
index 0000000000..ac014b887b
--- /dev/null
+++ b/js/chat/bundle.cloud-browser.js
@@ -0,0 +1,2643 @@
+/** @file automatically generated, do not edit it. */
+"use strict";
+(self.webpackChunk_meganz_webclient = self.webpackChunk_meganz_webclient || []).push([[313],{
+
+ 6961
+(_, EXP_, REQ_) {
+
+// ESM COMPAT FLAG
+REQ_.r(EXP_);
+
+// EXPORTS
+REQ_.d(EXP_, {
+ "default": () => cloudBrowserModalDialog
+});
+
+// EXTERNAL MODULE: external "React"
+const external_React_ = REQ_(1594);
+const REaCt = REQ_.n(external_React_);
+// EXTERNAL MODULE: ./js/ui/modalDialogs.jsx + 1 modules
+const modalDialogs = REQ_(8120);
+;// ./js/ui/jsx/fm/viewModeSelector.jsx
+
+const VIEW_MODE = {
+ 'GRID': 1,
+ 'LIST': undefined
+};
+const ViewModeSelector = ({
+ viewMode,
+ onChange
+}) => {
+ return JSX_("div", {
+ className: "chat-fm-view-mode-selector"
+ }, JSX_("i", {
+ className: `
+ sprite-fm-mono
+ icon-view-medium-list
+ ${viewMode ? '' : 'active'}
+ `,
+ title: l[5553],
+ onClick: () => onChange == null ? void 0 : onChange(VIEW_MODE.LIST)
+ }), JSX_("i", {
+ className: `
+ sprite-fm-mono
+ icon-view-grid
+ ${viewMode ? " active" : ""}
+ `,
+ title: l[5552],
+ onClick: () => onChange == null ? void 0 : onChange(VIEW_MODE.GRID)
+ }));
+};
+ const viewModeSelector = ViewModeSelector;
+// EXTERNAL MODULE: ./js/chat/mixins.js
+const mixins = REQ_(8264);
+;// ./js/ui/jsx/fm/breadcrumbs.jsx
+
+
+class Breadcrumbs extends mixins.w9 {
+ constructor(props) {
+ super(props);
+ this.domRef = REaCt().createRef();
+ this.state = {
+ 'breadcrumbDropdownVisible': false
+ };
+ this.onGlobalClickHandler = this.onGlobalClickHandler.bind(this);
+ this.onBreadcrumbNodeClick = this.onBreadcrumbNodeClick.bind(this);
+ }
+ getBreadcrumbNodeText(nodeId, prevNodeId) {
+ const backupsId = M.BackupsId || 'backups';
+ switch (nodeId) {
+ case M.RootID:
+ return l[164];
+ case M.RubbishID:
+ return l[167];
+ case backupsId:
+ return l.restricted_folder_button;
+ case 'shares':
+ return prevNodeId && M.d[prevNodeId] ? M.d[prevNodeId].m : l[5589];
+ default:
+ return M.d[nodeId] && M.d[nodeId].name;
+ }
+ }
+ getBreadcrumbDropdownContents(items) {
+ const contents = [];
+ for (const item of items) {
+ if (!item.name) {
+ continue;
+ }
+ contents.push(JSX_("a", {
+ className: "crumb-drop-link",
+ key: `drop_link_${ item.nodeId}`,
+ onClick: e => this.onBreadcrumbNodeClick(e, item.nodeId)
+ }, JSX_("i", {
+ className: `sprite-fm-mono icon24 ${{
+ 'cloud-drive': 'icon-cloud',
+ 'backups': 'icon-database-filled',
+ 's4-object-storage': 'icon-bucket-triangle-thin-solid',
+ 's4-buckets': 'icon-bucket-outline'
+ }[item.type] || 'folder'}`
+ }), JSX_("span", null, item.name)));
+ }
+ return contents;
+ }
+ onBreadcrumbNodeClick(e, nodeId) {
+ e.preventDefault();
+ e.stopPropagation();
+ if (this._clickToHideListener) {
+ this.removeGlobalClickHandler();
+ this.setState({
+ 'breadcrumbDropdownVisible': false
+ });
+ }
+ this.props.onNodeClick(nodeId);
+ }
+ customIsEventuallyVisible() {
+ return true;
+ }
+ onGlobalClickHandler(e) {
+ let _this$domRef;
+ const node = (_this$domRef = this.domRef) == null ? void 0 : _this$domRef.current;
+ if (node.contains(e.target) || node === e.target) {
+ return;
+ }
+ if (this._clickToHideListener) {
+ this.removeGlobalClickHandler();
+ }
+ this.setState({
+ 'breadcrumbDropdownVisible': false
+ });
+ }
+ removeGlobalClickHandler() {
+ this._clickToHideListener = false;
+ document.body.removeEventListener("click", this.onGlobalClickHandler);
+ }
+ componentDidUpdate() {
+ super.componentDidUpdate();
+ if (this.state.breadcrumbDropdownVisible) {
+ if (!this._clickToHideListener) {
+ this._clickToHideListener = true;
+ document.body.addEventListener("click", this.onGlobalClickHandler);
+ }
+ } else if (this._clickToHideListener) {
+ this.removeGlobalClickHandler();
+ }
+ }
+ componentWillUnmount() {
+ super.componentWillUnmount();
+ this.removeGlobalClickHandler();
+ }
+ render() {
+ const {
+ className,
+ highlighted,
+ currentlyViewedEntry,
+ isSearch,
+ path
+ } = this.props;
+ const breadcrumb = [];
+ const extraPathItems = [];
+ let breadcrumbDropdownContents = [];
+ const entryId = isSearch ? highlighted[0] : currentlyViewedEntry;
+ if (entryId !== undefined) {
+ (path || M.getPath(entryId)).forEach((nodeId, k, path) => {
+ let breadcrumbClasses = '';
+ let folderType = 'folder';
+ if (nodeId === M.RootID) {
+ breadcrumbClasses += " cloud-drive";
+ } else {
+ breadcrumbClasses += " folder";
+ }
+ if (nodeId.length === 11 && M.u[nodeId]) {
+ return;
+ }
+ if (nodeId === "shares") {
+ breadcrumbClasses += " shared-with-me";
+ }
+ const prevNodeId = path[k - 1];
+ let nodeName = this.getBreadcrumbNodeText(nodeId, prevNodeId);
+ if ('utils' in s4) {
+ const data = s4.utils.getBreadcrumbsData(nodeId);
+ if (data) {
+ ({
+ type: folderType,
+ localeName: nodeName
+ } = data);
+ }
+ }
+ if (!nodeName) {
+ return;
+ }
+ ((nodeId, k) => {
+ if (k < 4) {
+ breadcrumb.unshift(JSX_("a", {
+ className: `fm-breadcrumbs contains-directories ${ breadcrumbClasses}`,
+ key: nodeId,
+ onClick: e => this.onBreadcrumbNodeClick(e, nodeId)
+ }, JSX_("span", {
+ className: `right-arrow-bg simpletip`,
+ "data-simpletip": nodeName
+ }, JSX_("span", {
+ className: "selectable-txt"
+ }, nodeName)), k !== 0 && JSX_("i", {
+ className: "next-arrow sprite-fm-mono icon-arrow-right icon16"
+ })));
+ } else {
+ folderType = nodeId === M.RootID ? 'cloud-drive' : folderType;
+ if (M.BackupsId && nodeId === M.BackupsId) {
+ folderType = 'backups';
+ }
+ extraPathItems.push({
+ name: nodeName,
+ type: folderType,
+ nodeId
+ });
+ }
+ })(nodeId, k);
+ });
+ if (extraPathItems.length > 0) {
+ breadcrumbDropdownContents = this.getBreadcrumbDropdownContents(extraPathItems);
+ }
+ }
+ return JSX_("div", {
+ ref: this.domRef,
+ className: `
+ fm-breadcrumbs-wrapper
+ ${className || ''}
+ `
+ }, JSX_("div", {
+ className: "fm-breadcrumbs-block"
+ }, breadcrumbDropdownContents.length ? JSX_(REaCt().Fragment, null, JSX_("div", {
+ className: "crumb-overflow-link"
+ }, JSX_("a", {
+ className: "breadcrumb-dropdown-link dropdown",
+ onClick: () => {
+ this.setState({
+ breadcrumbDropdownVisible: !this.state.breadcrumbDropdownVisible
+ });
+ }
+ }, JSX_("i", {
+ className: "menu-icon sprite-fm-mono icon-options icon16"
+ })), JSX_("i", {
+ className: "sprite-fm-mono icon-arrow-right icon16"
+ })), breadcrumb) : breadcrumb), breadcrumbDropdownContents.length ? JSX_("div", {
+ className: this.state.breadcrumbDropdownVisible ? 'breadcrumb-dropdown active' : 'breadcrumb-dropdown'
+ }, breadcrumbDropdownContents) : '');
+ }
+}
+// EXTERNAL MODULE: ./js/ui/jsx/fm/fmView.jsx + 10 modules
+const fmView = REQ_(872);
+;// ./js/ui/cloudBrowserModalDialog.jsx
+
+
+
+
+
+const MIN_SEARCH_LENGTH = 2;
+class CloudBrowserDialog extends modalDialogs.A.SafeShowDialogController {
+ static getFilterFunction(customFilterFn) {
+ return tryCatch(n => {
+ if (n.s4 && n.p === M.RootID && M.getS4NodeType(n) === 'container') {
+ return false;
+ }
+ if (!n.name || missingkeys[n.h] || M.getNodeShare(n).down) {
+ return false;
+ }
+ return !customFilterFn || customFilterFn(n);
+ });
+ }
+ constructor(props) {
+ super(props);
+ this.domRef = REaCt().createRef();
+ this.dialogName = 'attach-cloud-dialog';
+ this.state = {
+ 'isActiveSearch': false,
+ 'selected': [],
+ 'highlighted': [],
+ 'currentlyViewedEntry': M.RootID,
+ 'selectedTab': M.RootID,
+ 'searchValue': '',
+ 'searchText': ''
+ };
+ this.onAttachClicked = this.onAttachClicked.bind(this);
+ this.onClearSearchIconClick = this.onClearSearchIconClick.bind(this);
+ this.onPopupDidMount = this.onPopupDidMount.bind(this);
+ this.onSearchChange = this.onSearchChange.bind(this);
+ this.onSearchIconClick = this.onSearchIconClick.bind(this);
+ this.onSelected = this.onSelected.bind(this);
+ this.onHighlighted = this.onHighlighted.bind(this);
+ this.handleTabChange = this.handleTabChange.bind(this);
+ this.onViewModeSwitch = this.onViewModeSwitch.bind(this);
+ this.onBreadcrumbNodeClick = this.onBreadcrumbNodeClick.bind(this);
+ this.onExpand = this.onExpand.bind(this);
+ }
+ onViewModeSwitch(newMode) {
+ const currentViewMode = mega.config.get('cbvm') | 0;
+ if (newMode === currentViewMode) {
+ return;
+ }
+ mega.config.set('cbvm', newMode);
+ this.forceUpdate();
+ }
+ getHeaderButtonsClass() {
+ const classes = ['fm-header-buttons'];
+ if (this.state.isActiveSearch) {
+ classes.push('active-search');
+ }
+ return classes.join(' ');
+ }
+ getSearchIconClass() {
+ const classes = ['sprite-fm-mono', 'icon-preview-reveal'];
+ if (this.state.isActiveSearch && this.state.searchText.length > 0) {
+ classes.push('disabled');
+ }
+ return classes.join(' ');
+ }
+ onSearchIconClick() {
+ const isActiveSearch = !this.state.isActiveSearch;
+ if (isActiveSearch) {
+ this.searchInput.focus();
+ this.setState({
+ isActiveSearch
+ });
+ }
+ }
+ onClearSearchIconClick() {
+ this.setState({
+ 'isActiveSearch': false,
+ 'searchValue': '',
+ 'searchText': '',
+ 'currentlyViewedEntry': this.state.selectedTab
+ });
+ }
+ handleTabChange(selectedTab) {
+ const s4Cn = selectedTab === 's4' && M.tree.s4 && Object.keys(M.tree.s4);
+ this.clearSelectionAndHighlight();
+ this.setState({
+ selectedTab,
+ currentlyViewedEntry: s4Cn && s4Cn.length === 1 ? s4Cn[0] : selectedTab,
+ searchValue: '',
+ searchText: '',
+ isLoading: false
+ });
+ }
+ onSearchBlur() {
+ if (this.state.searchText === '') {
+ this.setState({
+ 'isActiveSearch': false
+ });
+ }
+ }
+ onSearchChange(e) {
+ const searchValue = e.target.value;
+ const newState = {
+ searchText: searchValue,
+ nodeLoading: searchValue.length >= MIN_SEARCH_LENGTH
+ };
+ if (searchValue && searchValue.length >= MIN_SEARCH_LENGTH) {
+ this.setState(newState);
+ delay('cbd:search-proc', this.searchProc.bind(this), 500);
+ return;
+ }
+ if (this.state.currentlyViewedEntry === 'search' && (!searchValue || searchValue.length < MIN_SEARCH_LENGTH)) {
+ newState.currentlyViewedEntry = this.state.selectedTab;
+ newState.searchValue = undefined;
+ }
+ this.setState(newState);
+ this.clearSelectionAndHighlight();
+ }
+ searchProc() {
+ const {
+ searchText
+ } = this.state;
+ const newState = {
+ nodeLoading: true
+ };
+ if (searchText && searchText.length >= MIN_SEARCH_LENGTH) {
+ this.setState(newState);
+ M.fmSearchNodes(searchText).then(() => {
+ newState.nodeLoading = false;
+ newState.searchValue = searchText;
+ newState.currentlyViewedEntry = 'search';
+ this.setState(newState);
+ this.clearSelectionAndHighlight();
+ });
+ }
+ }
+ onSelected(nodes) {
+ this.setState({
+ 'selected': nodes
+ });
+ this.props.onSelected(nodes);
+ }
+ onHighlighted(nodes) {
+ this.setState({
+ 'highlighted': nodes
+ });
+ if (this.props.onHighlighted) {
+ this.props.onHighlighted(nodes);
+ }
+ }
+ clearSelectionAndHighlight() {
+ this.onSelected([]);
+ this.onHighlighted([]);
+ if (selectionManager) {
+ selectionManager.clear_selection();
+ }
+ }
+ onPopupDidMount(elem) {
+ this.domNode = elem;
+ }
+ onAttachClicked() {
+ this.props.onAttachClicked();
+ }
+ onBreadcrumbNodeClick(nodeId) {
+ if (nodeId === 'shares' || nodeId === 's4') {
+ return this.handleTabChange(nodeId);
+ }
+ if (M.getNodeByHandle(nodeId).t) {
+ const nodeRoot = M.getNodeRoot(nodeId);
+ this.setState({
+ selectedTab: nodeRoot === "contacts" ? 'shares' : nodeRoot,
+ currentlyViewedEntry: nodeId,
+ selected: [],
+ searchValue: '',
+ searchText: ''
+ });
+ }
+ }
+ onExpand(nodeId) {
+ this.setState({
+ 'currentlyViewedEntry': nodeId,
+ 'searchValue': '',
+ 'searchText': '',
+ 'selected': [],
+ 'highlighted': []
+ });
+ }
+ render() {
+ assert(this.dialogBecameVisible);
+ const self = this;
+ const viewMode = mega.config.get('cbvm') | 0;
+ const classes = `add-from-cloud ${self.props.className} dialog-template-tool `;
+ let folderIsHighlighted = false;
+ let share = false;
+ let isS4Cn = false;
+ const isSearch = this.state.currentlyViewedEntry === 'search';
+ const entryId = isSearch ? self.state.highlighted[0] : self.state.currentlyViewedEntry;
+ const filterFn = CloudBrowserDialog.getFilterFunction(this.props.customFilterFn);
+ const isIncomingShare = M.getNodeRoot(entryId) === "shares";
+ this.state.highlighted.forEach(nodeId => {
+ if (M.getNodeByHandle(nodeId).t) {
+ folderIsHighlighted = true;
+ if (M.tree.s4 && M.tree.s4[nodeId]) {
+ isS4Cn = true;
+ }
+ }
+ share = M.getNodeShare(nodeId);
+ });
+ const buttons = [{
+ "label": this.props.cancelLabel,
+ "key": "cancel",
+ "onClick": e => {
+ e.preventDefault();
+ e.stopPropagation();
+ if (this.props.onCancel) {
+ this.props.onCancel(this);
+ }
+ this.props.onClose(this);
+ }
+ }];
+ if (folderIsHighlighted) {
+ const {
+ highlighted
+ } = this.state;
+ const className = `${share && share.down ? 'disabled' : ''}`;
+ const highlightedNode = highlighted && highlighted.length && highlighted[0];
+ const allowAttachFolders = this.props.allowAttachFolders && !isIncomingShare && !isS4Cn;
+ buttons.push({
+ "label": this.props.openLabel,
+ "key": "select",
+ className: `positive ${className} ${highlighted.length > 1 ? 'disabled' : ''}`,
+ onClick: e => {
+ e.preventDefault();
+ e.stopPropagation();
+ if (highlighted.length > 1) {
+ return;
+ }
+ this.setState({
+ currentlyViewedEntry: highlightedNode
+ });
+ this.clearSelectionAndHighlight();
+ this.setState({
+ selected: [],
+ searchValue: '',
+ searchText: '',
+ highlighted: []
+ });
+ }
+ }, allowAttachFolders ? {
+ "label": l[8023],
+ "key": "attach",
+ className: `positive ${ className}`,
+ onClick: () => {
+ this.props.onClose();
+ onIdle(() => {
+ const createPublicLink = h => {
+ M.createPublicLink(h).then(({
+ link
+ }) => this.props.room.sendMessage(link));
+ };
+ const frs = [];
+ const files = [];
+ for (let i = 0; i < highlighted.length; i++) {
+ const node = M.getNodeByHandle(highlighted[i]);
+ if (node && M.isFileNode(node)) {
+ if (!M.getNodeShare(node).down) {
+ files.push(node);
+ }
+ } else if (mega.fileRequestCommon.storage.isDropExist(highlighted[i]).length) {
+ frs.push(highlighted[i]);
+ } else {
+ createPublicLink(highlighted[i]);
+ }
+ }
+ if (files.length) {
+ this.props.onSelected(files);
+ this.props.onAttachClicked();
+ }
+ if (frs.length) {
+ const fldName = frs.length > 1 ? l[17626] : l[17403].replace('%1', escapeHTML(M.getNameByHandle(frs[0])) || l[1049]);
+ msgDialog('confirmation', l[1003], fldName, l[18229], e => {
+ if (e) {
+ mega.fileRequest.removeList(frs).then(() => {
+ for (let i = 0; i < frs.length; i++) {
+ createPublicLink(frs[i]);
+ }
+ }).catch(dump);
+ }
+ });
+ }
+ });
+ }
+ } : null);
+ }
+ if (!folderIsHighlighted || this.props.folderSelectable && (!this.props.noShareFolderAttach || !(isIncomingShare && folderIsHighlighted))) {
+ buttons.push({
+ "label": this.props.selectLabel,
+ "key": "select",
+ "className": `positive ${ this.state.selected.length === 0 || share && share.down || isS4Cn ? "disabled" : ""}`,
+ "onClick": e => {
+ if (this.state.selected.length > 0) {
+ this.props.onSelected(this.state.selected);
+ this.props.onAttachClicked();
+ }
+ e.preventDefault();
+ e.stopPropagation();
+ }
+ });
+ }
+ let clearSearchBtn = null;
+ if (self.state.searchText.length >= MIN_SEARCH_LENGTH) {
+ clearSearchBtn = JSX_("i", {
+ className: "sprite-fm-mono icon-close-component",
+ onClick: () => {
+ self.onClearSearchIconClick();
+ }
+ });
+ }
+ const breadcrumbPath = M.getPath(entryId);
+ return JSX_(modalDialogs.A.ModalDialog, {
+ title: self.props.title || l[8011],
+ className: classes + (isSearch && this.state.selected.length > 0 ? 'has-breadcrumbs-bottom' : '') + this.dialogName,
+ onClose: () => {
+ self.props.onClose(self);
+ },
+ dialogName: "add-from-cloud-dialog dialog-template-tool",
+ popupDidMount: self.onPopupDidMount,
+ buttons
+ }, JSX_("section", {
+ ref: this.domRef,
+ className: "content"
+ }, JSX_("div", {
+ className: "content-block"
+ }, JSX_("div", {
+ className: "fm-dialog-tabs"
+ }, JSX_("div", {
+ className: `
+ fm-dialog-tab cloud
+ ${self.state.selectedTab === M.RootID ? 'active' : ''}
+ `,
+ onClick: () => self.handleTabChange(M.RootID)
+ }, l[164]), JSX_("div", {
+ className: `
+ fm-dialog-tab incoming
+ ${self.state.selectedTab === 'shares' ? 'active' : ''}
+ `,
+ onClick: () => self.handleTabChange('shares')
+ }, l[5542]), JSX_("div", {
+ className: `
+ fm-dialog-tab s4
+ ${self.state.selectedTab === 's4' ? 'active' : ''}
+ ${u_attr.s4 ? '' : 'hidden'}
+ `,
+ onClick: () => self.handleTabChange('s4')
+ }, l.obj_storage), JSX_("div", {
+ className: "clear"
+ })), JSX_("div", {
+ className: "fm-picker-header"
+ }, JSX_("div", {
+ className: self.getHeaderButtonsClass()
+ }, JSX_(viewModeSelector, {
+ viewMode,
+ onChange: this.onViewModeSwitch
+ }), JSX_("div", {
+ className: "fm-files-search"
+ }, JSX_("i", {
+ className: self.getSearchIconClass(),
+ onClick: () => {
+ self.onSearchIconClick();
+ }
+ }), JSX_("input", {
+ ref: input => {
+ this.searchInput = input;
+ },
+ type: "search",
+ placeholder: l[102],
+ value: self.state.searchText,
+ onChange: self.onSearchChange,
+ onBlur: () => {
+ self.onSearchBlur();
+ }
+ }), clearSearchBtn), JSX_("div", {
+ className: "clear"
+ })), !isSearch && JSX_(Breadcrumbs, {
+ className: "add-from-cloud",
+ nodeId: entryId,
+ path: breadcrumbPath,
+ onNodeClick: this.onBreadcrumbNodeClick,
+ isSearch,
+ highlighted: this.state.highlighted,
+ currentlyViewedEntry: this.state.currentlyViewedEntry
+ })), JSX_(fmView.A, {
+ nodeLoading: this.state.nodeLoading,
+ sortFoldersFirst: true,
+ currentlyViewedEntry: this.state.currentlyViewedEntry,
+ customFilterFn: filterFn,
+ folderSelectNotAllowed: this.props.folderSelectNotAllowed,
+ folderSelectable: this.props.folderSelectable,
+ onSelected: this.onSelected,
+ onHighlighted: this.onHighlighted,
+ onAttachClicked: this.onAttachClicked,
+ initialSelected: this.state.selected,
+ initialHighlighted: this.state.highlighted,
+ searchValue: this.state.searchValue,
+ minSearchLength: MIN_SEARCH_LENGTH,
+ onExpand: this.onExpand,
+ viewMode,
+ initialSortBy: ['name', 'asc'],
+ fmConfigSortEnabled: true,
+ fmConfigSortId: "cbd"
+ }), isSearch && breadcrumbPath.length > 0 && JSX_("div", {
+ className: `
+ fm-breadcrumbs-wrapper add-from-cloud breadcrumbs-bottom
+ `
+ }, JSX_("div", {
+ className: "fm-breadcrumbs-block"
+ }, JSX_(Breadcrumbs, {
+ nodeId: entryId,
+ path: breadcrumbPath,
+ onNodeClick: this.onBreadcrumbNodeClick,
+ isSearch,
+ highlighted: this.state.highlighted,
+ currentlyViewedEntry: this.state.currentlyViewedEntry
+ }), JSX_("div", {
+ className: "clear"
+ }))))));
+ }
+}
+CloudBrowserDialog.defaultProps = {
+ 'selectLabel': l[8023],
+ 'openLabel': l[1710],
+ 'cancelLabel': l.msg_dlg_cancel,
+ 'hideable': true,
+ 'className': ''
+};
+ const cloudBrowserModalDialog = CloudBrowserDialog;
+
+ },
+
+ 872
+(_, EXP_, REQ_) {
+
+
+// EXPORTS
+REQ_.d(EXP_, {
+ A: () => FMView
+});
+
+// EXTERNAL MODULE: external "React"
+const external_React_ = REQ_(1594);
+const REaCt = REQ_.n(external_React_);
+// EXTERNAL MODULE: ./js/chat/mixins.js
+const mixins = REQ_(8264);
+// EXTERNAL MODULE: ./node_modules/@babel/runtime/helpers/esm/extends.js
+const esm_extends = REQ_(8168);
+// EXTERNAL MODULE: ./node_modules/@babel/runtime/helpers/esm/applyDecoratedDescriptor.js
+const applyDecoratedDescriptor = REQ_(793);
+// EXTERNAL MODULE: ./js/ui/perfectScrollbar.jsx
+const perfectScrollbar = REQ_(1301);
+;// ./js/ui/jsx/megaList/megaList2.jsx
+
+
+let _dec, _class;
+
+
+
+const MegaList2 = (_dec = (0,mixins.hG)(30, true), _class = class MegaList2 extends mixins.w9 {
+ constructor(props) {
+ super(props);
+ this._calculated = false;
+ this._firstRender = true;
+ this.customIsEventuallyVisible = true;
+ this.requiresUpdateOnResize = true;
+ this.adapterChangedDoRepaint = false;
+ assert(props.listAdapter, 'missing `listAdapter` for MegaList2');
+ assert(props.nodeAdapter, 'missing `nodeAdapter` for MegaList2');
+ assert(props.entries, 'missing `entries` for MegaList2');
+ this.options = {
+ extraRows: 8,
+ batchPages: 0,
+ perfectScrollOptions: {
+ 'handlers': ['click-rail', 'drag-thumb', 'wheel', 'touch'],
+ 'minScrollbarLength': 20
+ }
+ };
+ this.onPsUserScroll = this.onPsUserScroll.bind(this);
+ this.thumbsLoadingHandlers = new MapSet();
+ this.thumbsThatRequireLoading = new MapSet();
+ this.requestThumbnailCb = this.requestThumbnailCb.bind(this);
+ }
+ specShouldComponentUpdate(nextProps) {
+ let invalidate = false;
+ if (nextProps.listAdapter.prototype.constructor.name !== this.props.listAdapter.prototype.constructor.name || nextProps.entries !== this.props.entries || nextProps.viewMode !== this.props.viewMode) {
+ invalidate = true;
+ }
+ if (nextProps.sortBy !== this.props.sortBy || nextProps.currentlyViewedEntry !== this.props.currentlyViewedEntry) {
+ invalidate = true;
+ this.domRef.scrollToY(0);
+ }
+ if (invalidate) {
+ this._calculated = false;
+ this.adapterChangedDoRepaint = true;
+ return true;
+ }
+ return null;
+ }
+ _recalculate() {
+ if (this._calculated) {
+ return this._calculated;
+ }
+ const calculated = this._calculated = Object.create(null);
+ lazy(calculated, 'scrollWidth', () => {
+ return this.domRef.getClientWidth();
+ });
+ lazy(calculated, 'scrollHeight', () => this.domRef.getClientHeight() - calculated.headerHeight);
+ lazy(calculated, 'itemWidth', () => {
+ if (this.props.listAdapter.itemWidth === false) {
+ return calculated.scrollWidth;
+ }
+ return this.props.listAdapter.itemWidth;
+ });
+ lazy(calculated, 'itemHeight', () => {
+ return this.props.itemHeight || this.props.listAdapter.itemHeight;
+ });
+ lazy(calculated, 'headerHeight', () => this.props.headerHeight || 0);
+ lazy(calculated, 'contentWidth', () => {
+ const contentWidth = this.domRef.getContentWidth();
+ if (contentWidth) {
+ return contentWidth;
+ }
+ return calculated.itemWidth;
+ });
+ lazy(calculated, 'itemsPerRow', () => {
+ if (this.props.listAdapter.itemsPerRow) {
+ return this.props.listAdapter.itemsPerRow;
+ }
+ return Math.max(1, Math.floor(calculated.contentWidth / calculated.itemWidth));
+ });
+ lazy(calculated, 'contentHeight', () => {
+ return Math.ceil(this.props.entries.length / calculated.itemsPerRow) * calculated.itemHeight;
+ });
+ lazy(calculated, 'scrollLeft', () => {
+ return this.domRef.getScrollPositionX();
+ });
+ lazy(calculated, 'scrollTop', () => {
+ if (this.adapterChangedDoRepaint) {
+ return 0;
+ }
+ return this.domRef.getScrollPositionY();
+ });
+ lazy(calculated, 'scrolledPercentX', () => {
+ return 100 / calculated.scrollWidth * calculated.scrollLeft;
+ });
+ lazy(calculated, 'scrolledPercentY', () => {
+ return 100 / calculated.scrollHeight * calculated.scrollTop;
+ });
+ lazy(calculated, 'isAtTop', () => {
+ return calculated.scrollTop === 0;
+ });
+ lazy(calculated, 'isAtBottom', () => {
+ return calculated.scrollTop === calculated.scrollHeight;
+ });
+ lazy(calculated, 'itemsPerPage', () => {
+ return Math.ceil(calculated.scrollHeight / calculated.itemHeight) * calculated.itemsPerRow;
+ });
+ lazy(calculated, 'visibleFirstItemNum', () => {
+ let value = 0;
+ value = Math.floor(Math.floor(calculated.scrollTop / calculated.itemHeight) * calculated.itemsPerRow);
+ if (value > 0) {
+ value = Math.max(0, value - this.options.extraRows * calculated.itemsPerRow);
+ }
+ return value;
+ });
+ lazy(calculated, 'visibleLastItemNum', () => {
+ let value = Math.min(this.props.entries.length, Math.ceil(Math.ceil(calculated.scrollTop / calculated.itemHeight) * calculated.itemsPerRow + calculated.itemsPerPage));
+ if (value < this.props.entries.length) {
+ value = Math.min(this.props.entries.length, value + this.options.extraRows * calculated.itemsPerRow);
+ }
+ return value;
+ });
+ if (this.options.batchPages > 0) {
+ const perPage = calculated.itemsPerPage;
+ const visibleF = calculated.visibleFirstItemNum;
+ calculated.visibleFirstItemNum = Math.max(0, ((visibleF - visibleF % perPage) / perPage - 1 - this.options.batchPages) * perPage);
+ const visibleL = calculated.visibleLastItemNum;
+ calculated.visibleLastItemNum = Math.min(this.props.entries.length, ((visibleL - visibleL % perPage) / perPage + 1 + this.options.batchPages) * perPage);
+ }
+ Object.defineProperty(M, 'rmItemsInView', {
+ get: () => {
+ const c = this.domRef && this._calculated || !1;
+ return c.itemsPerPage + c.itemsPerRow | 0;
+ },
+ configurable: true
+ });
+ }
+ _contentUpdated() {
+ this._calculated = false;
+ this._recalculate();
+ if (this.listContent && this._lastContentHeight !== this._calculated.contentHeight) {
+ this._lastContentHeight = this._calculated.contentHeight;
+ this.listContent.style.height = `${this._calculated.contentHeight }px`;
+ }
+ if (this.domRef && this._calculated.scrollHeight + this._calculated.scrollTop > this._calculated.contentHeight) {
+ this.domRef.scrollToY(this._calculated.contentHeight - this._calculated.scrollHeight);
+ }
+ if (this.listAdapterInstance && this.listAdapterInstance.onContentUpdated) {
+ this.listAdapterInstance.onContentUpdated();
+ }
+ }
+ _getCalcsThatTriggerChange() {
+ return [this.props.entries.length, this._calculated.scrollHeight, this._calculated.itemWidth, this._calculated.itemHeight, this._calculated.contentWidth, this._calculated.itemsPerRow, this._calculated.contentHeight, this._calculated.visibleFirstItemNum, this._calculated.visibleLastItemNum];
+ }
+ indexOfEntry(nodeHandle, prop) {
+ prop = prop || 'h';
+ for (let i = 0; i < this.props.entries.length; i++) {
+ const entry = this.props.entries[i];
+ if (entry[prop] === nodeHandle) {
+ return i;
+ }
+ }
+ return -1;
+ }
+ scrollToItem(nodeHandle) {
+ const elementIndex = this.indexOfEntry(nodeHandle);
+ if (elementIndex === -1) {
+ return false;
+ }
+ let shouldScroll = false;
+ const itemOffsetTop = Math.floor(elementIndex / this._calculated.itemsPerRow) * this._calculated.itemHeight;
+ const itemOffsetTopPlusHeight = itemOffsetTop + this._calculated.itemHeight;
+ if (itemOffsetTop < this._calculated.scrollTop || itemOffsetTopPlusHeight > this._calculated.scrollTop + this._calculated.scrollHeight) {
+ shouldScroll = true;
+ }
+ if (shouldScroll) {
+ this.domRef.scrollToY(itemOffsetTop);
+ onIdle(() => {
+ this.safeForceUpdate();
+ });
+ return true;
+ }
+ return false;
+ }
+ onPsUserScroll() {
+ if (!this.isMounted()) {
+ return;
+ }
+ const oldCalc = JSON.stringify(this._getCalcsThatTriggerChange());
+ this._contentUpdated();
+ const newCalc = JSON.stringify(this._getCalcsThatTriggerChange());
+ if (oldCalc !== newCalc) {
+ this.forceUpdate();
+ }
+ }
+ onResizeDoUpdate() {
+ super.onResizeDoUpdate();
+ this._contentUpdated();
+ }
+ componentDidMount() {
+ super.componentDidMount();
+ this._contentUpdated();
+ this.forceUpdate();
+ }
+ componentDidUpdate() {
+ super.componentDidUpdate();
+ this._contentUpdated();
+ if (this.adapterChangedDoRepaint) {
+ this.adapterChangedDoRepaint = false;
+ this._calculated = false;
+ this._recalculate();
+ }
+ if (this.thumbsThatRequireLoading.size) {
+ delay('chat:mega-list2:thumb-loader', () => this.enqueueThumbnailRetrieval(), 20);
+ }
+ this._firstRender = this._firstRender || this.props.viewmode !== M.viewmode;
+ if (this._firstRender && this.domRef) {
+ let _this$domRef;
+ this._firstRender = false;
+ Ps.update((_this$domRef = this.domRef) == null ? void 0 : _this$domRef.$Node);
+ }
+ }
+ enqueueThumbnailRetrieval() {
+ const loaders = new Map(this.thumbsLoadingHandlers);
+ const nodes = new Map(this.thumbsThatRequireLoading);
+ const pending = [];
+ const defaultCallback = (n, src, id) => {
+ let img = document.getElementById(id || `chat_${n.h}`);
+ if (img && (img = img.querySelector('img'))) {
+ let _img$parentNode$paren;
+ img.src = src;
+ (_img$parentNode$paren = img.parentNode.parentNode) == null || _img$parentNode$paren.classList.add('thumb');
+ }
+ };
+ const setSource = n => {
+ if (thumbnails.has(n.fa)) {
+ const src = thumbnails.get(n.fa);
+ const batch = [...nodes.get(n.fa)];
+ for (let i = batch.length; i--;) {
+ const n = batch[i];
+ const handlers = [...loaders.get(n.h)];
+ for (let i = handlers.length; i--;) {
+ let callback = handlers[i];
+ if (typeof callback !== 'function') {
+ callback = defaultCallback;
+ }
+ tryCatch(() => {
+ const id = callback(n, src);
+ if (id) {
+ defaultCallback(n, src, id);
+ }
+ })();
+ }
+ }
+ return true;
+ }
+ };
+ for (const [, [n]] of nodes) {
+ if (!setSource(n)) {
+ pending.push(n);
+ }
+ }
+ if (pending.length) {
+ fm_thumbnails('standalone', pending, setSource);
+ }
+ this.thumbsLoadingHandlers.clear();
+ this.thumbsThatRequireLoading.clear();
+ }
+ requestThumbnailCb(node, immediate, callback) {
+ if (node && node.fa) {
+ if (typeof immediate === 'function') {
+ callback = immediate;
+ immediate = 0;
+ }
+ node.seen = node.seen || -7;
+ this.thumbsLoadingHandlers.set(node.h, callback);
+ this.thumbsThatRequireLoading.set(node.fa, node);
+ delay('chat:mega-list2:thumb-loader', () => this.enqueueThumbnailRetrieval(), immediate || 480);
+ }
+ }
+ render() {
+ if (this.isMounted() && !this._calculated) {
+ this._recalculate();
+ }
+ const {
+ listAdapter,
+ listAdapterOpts,
+ entries,
+ nodeAdapterProps,
+ viewMode,
+ header,
+ onContextMenu
+ } = this.props;
+ const className = `${listAdapter.containerClassName } megaList megaList2`;
+ const first = this._calculated.visibleFirstItemNum;
+ const last = this._calculated.visibleLastItemNum;
+ const nodes = [];
+ for (let i = first; i < last; i++) {
+ const node = entries[i];
+ nodes.push(JSX_(this.props.nodeAdapter, (0,esm_extends.A)({
+ key: `${i }_${ node[this.props.keyProp]}`,
+ h: node[this.props.keyProp],
+ index: i,
+ megaList: this,
+ listAdapter,
+ node,
+ calculated: this._calculated,
+ listAdapterOpts,
+ onContextMenu,
+ selected: this.props.selected ? this.props.selected.indexOf(node[this.props.keyProp]) > -1 : false,
+ highlighted: this.props.highlighted ? this.props.highlighted.indexOf(node[this.props.keyProp]) > -1 : false,
+ requestThumbnailCb: this.requestThumbnailCb,
+ keyProp: this.props.keyProp || 'h'
+ }, nodeAdapterProps)));
+ }
+ const listAdapterName = listAdapter.prototype.constructor.name;
+ return JSX_(REaCt().Fragment, null, JSX_(perfectScrollbar.O, {
+ key: `ps_${ listAdapterName }_${ viewMode}`,
+ options: this.options.perfectScrollOptions,
+ onUserScroll: this.onPsUserScroll,
+ className,
+ style: {
+ 'position': 'relative'
+ },
+ ref: instance => {
+ this.domRef = instance;
+ }
+ }, JSX_(this.props.listAdapter, (0,esm_extends.A)({
+ containerClassName: this.props.containerClassName,
+ key: `ps_${ listAdapterName }_${ this.props.viewMode }_la`,
+ ref: listAdapterInstance => {
+ this.listAdapterInstance = listAdapterInstance;
+ },
+ listContentRef: listContent => {
+ this.listContent = listContent;
+ },
+ header,
+ megaList: this,
+ calculated: this._calculated
+ }, listAdapterOpts), nodes)));
+ }
+}, (0,applyDecoratedDescriptor.A)(_class.prototype, "onPsUserScroll", [_dec], Object.getOwnPropertyDescriptor(_class.prototype, "onPsUserScroll"), _class.prototype), _class);
+// EXTERNAL MODULE: ./js/ui/jsx/fm/nodes/genericNodePropsComponent.jsx + 1 modules
+const genericNodePropsComponent = REQ_(4285);
+;// ./js/ui/jsx/fm/nodes/genericGrid.jsx
+
+
+class GenericGrid extends genericNodePropsComponent.B {
+ render() {
+ const {
+ node,
+ calculated,
+ index,
+ listAdapter,
+ className,
+ keyProp
+ } = this.props;
+ const style = {};
+ listAdapter.repositionItem(node, calculated, index, style);
+ const toApplySensitive = !!mega.sensitives.isSensitive(node) && (mega.sensitives.showGlobally ? 1 : 2);
+ let image = null;
+ let src = null;
+ let isThumbClass = "";
+ if (node.fa && (is_image2(node) || is_video(node))) {
+ src = thumbnails.get(node.fa);
+ if (!src) {
+ this.props.requestThumbnailCb(node);
+ src = window.noThumbURI || '';
+ }
+ image = src ? JSX_("img", {
+ alt: "",
+ src
+ }) : JSX_("img", {
+ alt: ""
+ });
+ isThumbClass = " thumb";
+ } else {
+ image = JSX_("img", null);
+ }
+ let fileStatusClass = "";
+ if (node.fav) {
+ fileStatusClass += " icon-favourite-filled";
+ }
+ return JSX_("a", {
+ className: `data-block-view megaListItem ui-droppable ui-draggable ui-draggable-handle ${ this.nodeProps.classNames.join(" ") }${className && className(node) || "" }${toApplySensitive ? toApplySensitive === 1 ? ' is-sensitive' : ' hidden-as-sensitive' : ''}`,
+ id: `chat_${ node[keyProp]}`,
+ onClick: e => {
+ this.props.onClick(e, this.props.node);
+ },
+ onDoubleClick: e => {
+ this.props.onDoubleClick(e, this.props.node);
+ },
+ title: this.nodeProps.title,
+ style
+ }, JSX_("span", {
+ className: `data-block-bg ${ isThumbClass}`
+ }, JSX_("span", {
+ className: "data-block-indicators"
+ }, JSX_("span", {
+ className: `file-status-icon indicator sprite-fm-mono${ fileStatusClass}`
+ }), JSX_("span", {
+ className: "versioning-indicator"
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-versions-previous"
+ })), JSX_("i", {
+ className: "sprite-fm-mono icon-link"
+ })), JSX_("span", {
+ className: `item-type-icon-90 icon-${ this.nodeProps.icon }-90`
+ }, image), JSX_("div", {
+ className: "video-thumb-details"
+ }, JSX_("i", {
+ className: "small-icon small-play-icon"
+ }), JSX_("span", null, "00:00"))), JSX_("span", {
+ className: "file-block-title"
+ }, this.nodeProps.title));
+ }
+}
+;// ./js/ui/jsx/fm/nodes/genericTable.jsx
+
+
+
+class GenericTableHeader extends mixins.w9 {
+ constructor(...args) {
+ super(...args);
+ this.domRef = REaCt().createRef();
+ }
+ render() {
+ const {
+ sortBy,
+ columns
+ } = this.props;
+ const columnsRendered = [];
+ for (let i = 0; i < columns.length; i++) {
+ var _colProps;
+ let col = columns[i];
+ let colProps;
+ if (Array.isArray(col)) {
+ colProps = col[1];
+ col = col[0];
+ }
+ let sortable;
+ if (col.sortable) {
+ let classes = "";
+ if (sortBy[0] === col.id) {
+ const ordClass = sortBy[1] === "desc" ? "icon-arrow-down" : "icon-arrow-up";
+ classes = `${classes} ${ordClass}`;
+ }
+ if (col.id === 'fav') {
+ classes += ' hidden';
+ }
+ sortable = JSX_("i", {
+ className: `sprite-fm-mono ${col.id} ${classes}`
+ });
+ }
+ columnsRendered.push(JSX_("th", {
+ megatype: col.megatype,
+ className: col.headerClassName || col.megatype || "",
+ key: `${col.id }_${ i}`,
+ onClick: e => {
+ e.preventDefault();
+ if (col.sortable) {
+ this.props.onClick(col.id);
+ }
+ }
+ }, JSX_("span", null, ((_colProps = colProps) == null ? void 0 : _colProps.label) || col.label), col.icon && JSX_("i", {
+ className: `sprite-fm-mono ${ col.icon}`
+ }), sortable));
+ }
+ return JSX_("thead", {
+ ref: this.domRef
+ }, JSX_("tr", null, columnsRendered));
+ }
+}
+class GenericTable extends genericNodePropsComponent.B {
+ render() {
+ let _this$nodeProps;
+ const {
+ node,
+ index,
+ listAdapterOpts,
+ className,
+ keyProp
+ } = this.props;
+ const toApplySensitive = !!mega.sensitives.isSensitive(node) && (mega.sensitives.showGlobally ? 1 : 2);
+ const columns = [];
+ for (let i = 0; i < listAdapterOpts.columns.length; i++) {
+ const customColumn = listAdapterOpts.columns[i];
+ if (Array.isArray(customColumn)) {
+ columns.push(JSX_(customColumn[0], {
+ ...customColumn[1],
+ 'nodeAdapter': this,
+ 'h': node[keyProp],
+ node,
+ 'key': `${i }_${ customColumn[0].prototype.constructor.name}`,
+ keyProp
+ }));
+ } else {
+ columns.push(JSX_(customColumn, {
+ 'nodeAdapter': this,
+ 'h': node[keyProp],
+ node,
+ 'key': `${i }_${ customColumn.prototype.constructor.name}`,
+ keyProp
+ }));
+ }
+ }
+ const listClassName = listAdapterOpts.className;
+ return JSX_("tr", {
+ className: `node_${ node[keyProp] } ${ className && className(node) || "" } ${ listClassName && listClassName(node) || "" } ${ (_this$nodeProps = this.nodeProps) == null ? void 0 : _this$nodeProps.classNames.join(" ") }${toApplySensitive ? toApplySensitive === 1 ? ' is-sensitive' : ' hidden-as-sensitive' : ''}`,
+ id: node[keyProp],
+ onContextMenu: ev => {
+ if (this.props.onContextMenu) {
+ this.props.onContextMenu(ev, node[keyProp]);
+ }
+ },
+ onClick: e => {
+ this.props.onClick(e, this.props.node);
+ },
+ onDoubleClick: e => {
+ this.props.onDoubleClick(e, this.props.node);
+ },
+ key: `${index }_${ node[keyProp]}`
+ }, columns);
+ }
+}
+;// ./js/ui/jsx/megaList/adapters.jsx
+
+
+class GenericListAdapter extends mixins.w9 {
+ constructor(...args) {
+ super(...args);
+ this.customIsEventuallyVisible = true;
+ }
+}
+class Grid extends GenericListAdapter {
+ static repositionItem(node, calculated, index, style) {
+ style.position = "absolute";
+ style.top = calculated.itemHeight * Math.floor(index / calculated.itemsPerRow);
+ if (calculated.itemsPerRow > 1) {
+ style.left = index % calculated.itemsPerRow * calculated.itemWidth;
+ }
+ }
+ render() {
+ return JSX_("div", {
+ className: "megaList-content",
+ ref: this.props.listContentRef,
+ style: {
+ 'position': 'relative'
+ }
+ }, this.props.children);
+ }
+}
+Grid.itemWidth = 212;
+Grid.itemHeight = 212;
+Grid.containerClassName = "file-block-scrolling megaListContainer";
+class Table extends GenericListAdapter {
+ onContentUpdated() {
+ const {
+ calculated
+ } = this.props;
+ const pusherHeight = calculated.visibleFirstItemNum * calculated.itemHeight | 0;
+ if (this.topPusher) {
+ this.topPusher.style.height = `${pusherHeight }px`;
+ }
+ if (this.bottomPusher) {
+ this.bottomPusher.style.height = `${calculated.contentHeight - pusherHeight - (calculated.visibleLastItemNum - calculated.visibleFirstItemNum) * calculated.itemHeight | 0 }px`;
+ }
+ }
+ componentDidUpdate() {
+ super.componentDidUpdate();
+ this.onContentUpdated();
+ }
+ render() {
+ return JSX_("table", {
+ width: "100%",
+ className: this.props.containerClassName || "grid-table table-hover fm-dialog-table"
+ }, this.props.header, JSX_("tbody", {
+ ref: this.props.listContentRef
+ }, JSX_("tr", {
+ className: "megalist-pusher top",
+ ref: r => {
+ this.topPusher = r;
+ }
+ }), this.props.children, JSX_("tr", {
+ className: "megalist-pusher bottom",
+ ref: r => {
+ this.bottomPusher = r;
+ }
+ })));
+ }
+}
+Table.itemHeight = 32;
+Table.itemsPerRow = 1;
+Table.containerClassName = "grid-scrolling-table megaListContainer";
+// EXTERNAL MODULE: ./js/ui/jsx/fm/nodes/columns/columnFavIcon.jsx
+const columnFavIcon = REQ_(6794);
+;// ./js/ui/tooltips.jsx
+
+
+class Handler extends REaCt().Component {
+ render() {
+ const {
+ className,
+ onMouseOver,
+ onMouseOut,
+ children
+ } = this.props;
+ return JSX_("span", {
+ className: `
+ tooltip-handler
+ ${className || ''}
+ `,
+ onMouseOver,
+ onMouseOut
+ }, children);
+ }
+}
+class Contents extends REaCt().Component {
+ render() {
+ let className = `tooltip-contents dropdown body tooltip ${ this.props.className ? this.props.className : ""}`;
+ if (this.props.active) {
+ className += " visible";
+ return JSX_("div", {
+ className
+ }, this.props.withArrow ? JSX_("i", {
+ className: "dropdown-white-arrow"
+ }) : null, this.props.children);
+ } else {
+ return null;
+ }
+ }
+}
+class Tooltip extends mixins.w9 {
+ constructor(props) {
+ super(props);
+ this.domRef = REaCt().createRef();
+ this.state = {
+ 'active': false
+ };
+ }
+ componentDidUpdate(oldProps, oldState) {
+ const self = this;
+ if (oldState.active === true && this.state.active === false) {
+ chatGlobalEventManager.removeEventListener('resize', `tooltip${ this.getUniqueId()}`);
+ }
+ if (self.state.active === true) {
+ self.repositionTooltip();
+ chatGlobalEventManager.addEventListener('resize', `tooltip${ this.getUniqueId()}`, () => {
+ self.repositionTooltip();
+ });
+ if (this.props.onShown) {
+ this.props.onShown();
+ }
+ }
+ }
+ repositionTooltip() {
+ let _this$domRef;
+ let elLeftPos, elTopPos, elWidth, elHeight;
+ let tooltipLeftPos, tooltipTopPos, tooltipWidth, tooltipHeight;
+ let docHeight;
+ let arrowClass;
+ if (!this.isMounted()) {
+ return;
+ }
+ const $container = $((_this$domRef = this.domRef) == null ? void 0 : _this$domRef.current);
+ const $el = $('.tooltip-handler', $container);
+ const $tooltip = $('.tooltip-contents', $container);
+ let {tooltipOffset} = this.props;
+ const arrow = this.props.withArrow;
+ if ($el && $tooltip) {
+ elWidth = $el.outerWidth();
+ elHeight = $el.outerHeight();
+ elLeftPos = $el.offset().left;
+ elTopPos = $el.offset().top;
+ tooltipWidth = $tooltip.outerWidth();
+ tooltipHeight = $tooltip.outerHeight();
+ docHeight = $(window).height();
+ $tooltip.removeClass('dropdown-arrow left-arrow right-arrow up-arrow down-arrow').removeAttr('style');
+ if (!tooltipOffset) {
+ tooltipOffset = 7;
+ }
+ if (elTopPos - tooltipHeight - tooltipOffset > 10) {
+ tooltipLeftPos = elLeftPos + elWidth / 2 - tooltipWidth / 2;
+ tooltipTopPos = elTopPos - tooltipHeight - tooltipOffset;
+ arrowClass = arrow ? 'dropdown-arrow down-arrow' : '';
+ } else if (docHeight - (elTopPos + elHeight + tooltipHeight + tooltipOffset) > 10) {
+ tooltipLeftPos = elLeftPos + elWidth / 2 - tooltipWidth / 2;
+ tooltipTopPos = elTopPos + elHeight + tooltipOffset;
+ arrowClass = arrow ? 'dropdown-arrow up-arrow' : '';
+ } else if (elLeftPos - tooltipWidth - tooltipOffset > 10) {
+ tooltipLeftPos = elLeftPos - tooltipWidth - tooltipOffset;
+ tooltipTopPos = elTopPos + elHeight / 2 - tooltipHeight / 2;
+ arrowClass = arrow ? 'dropdown-arrow right-arrow' : '';
+ } else {
+ tooltipLeftPos = elLeftPos + elWidth + tooltipOffset;
+ tooltipTopPos = elTopPos + elHeight / 2 - tooltipHeight / 2;
+ arrowClass = arrow ? 'dropdown-arrow left-arrow' : '';
+ }
+ $tooltip.css({
+ 'left': tooltipLeftPos,
+ 'top': tooltipTopPos - 5
+ });
+ $tooltip.addClass(arrowClass);
+ }
+ }
+ onHandlerMouseOver() {
+ this.setState({
+ 'active': true
+ });
+ }
+ onHandlerMouseOut() {
+ this.setState({
+ 'active': false
+ });
+ }
+ render() {
+ const self = this;
+ const others = [];
+ let handler = null;
+ let contents = null;
+ let x = 0;
+ REaCt().Children.forEach(this.props.children, (child) => {
+ if (child.type.name === 'Handler') {
+ handler = REaCt().cloneElement(child, {
+ onMouseOver () {
+ self.onHandlerMouseOver();
+ },
+ onMouseOut () {
+ self.onHandlerMouseOut();
+ }
+ });
+ } else if (child.type.name === 'Contents') {
+ contents = REaCt().cloneElement(child, {
+ active: self.state.active,
+ withArrow: self.props.withArrow
+ });
+ } else {
+ const tmp = REaCt().cloneElement(child, {
+ key: x++
+ });
+ others.push(tmp);
+ }
+ });
+ return JSX_("span", {
+ ref: this.domRef,
+ className: this.props.className || ''
+ }, handler, contents, others);
+ }
+}
+Tooltip.defaultProps = {
+ 'hideable': true
+};
+ const tooltips = {
+ Tooltip,
+ Handler,
+ Contents
+};
+;// ./js/ui/jsx/fm/nodes/columns/columnNodeName.jsx
+
+
+
+class ColumnNodeName extends genericNodePropsComponent.B {
+ constructor(...args) {
+ super(...args);
+ this.state = {
+ src: null
+ };
+ }
+ static get label() {
+ return l[86];
+ }
+ componentDidMount() {
+ super.componentDidMount();
+ }
+ render() {
+ const {
+ nodeAdapter
+ } = this.props;
+ const {
+ node,
+ requestThumbnailCb
+ } = nodeAdapter.props;
+ const src = this.state.src || thumbnails.get(node.fa);
+ return JSX_("td", {
+ megatype: ColumnNodeName.megatype
+ }, src || is_image2(node) || is_video(node) ? JSX_(tooltips.Tooltip, {
+ withArrow: true,
+ className: "tooltip-handler-container",
+ onShown: () => {
+ if (!src) {
+ requestThumbnailCb(node, true, (n, src) => {
+ this.setState({
+ src
+ });
+ return `preview_${n.h}`;
+ });
+ }
+ }
+ }, JSX_(tooltips.Handler, {
+ className: `item-type-icon icon-${fileIcon(node)}-24`
+ }), JSX_(tooltips.Contents, {
+ className: "img-preview"
+ }, JSX_("div", {
+ className: "dropdown img-wrapper img-block",
+ id: `preview_${node.h}`
+ }, JSX_("img", {
+ alt: "",
+ className: `thumbnail-placeholder ${node.h}`,
+ src: node.fa || src ? src || `${staticpath}/images/mega/ajax-loader-tiny.gif` : window.noThumbURI
+ })))) : JSX_("span", {
+ className: `
+ item-type-icon icon-${fileIcon(node)}-24
+ `
+ }), JSX_("span", {
+ className: "tranfer-filetype-txt"
+ }, nodeAdapter.nodeProps.title));
+ }
+}
+ColumnNodeName.sortable = true;
+ColumnNodeName.id = 'name';
+ColumnNodeName.megatype = 'fname';
+;// ./js/ui/jsx/fm/nodes/columns/columnSize.jsx
+
+
+class ColumnSize extends genericNodePropsComponent.B {
+ static get label() {
+ return l[87];
+ }
+ render() {
+ const {
+ nodeAdapter
+ } = this.props;
+ return JSX_("td", {
+ megatype: ColumnSize.megatype,
+ className: "size"
+ }, nodeAdapter.nodeProps.size);
+ }
+}
+ColumnSize.sortable = true;
+ColumnSize.id = "size";
+ColumnSize.megatype = "size";
+;// ./js/ui/jsx/fm/nodes/columns/columnTimeAdded.jsx
+
+
+class ColumnTimeAdded extends genericNodePropsComponent.B {
+ static get label() {
+ return l[16169];
+ }
+ render() {
+ const {
+ nodeAdapter
+ } = this.props;
+ return JSX_("td", {
+ megatype: ColumnTimeAdded.megatype,
+ className: "time ad"
+ }, nodeAdapter.nodeProps.timestamp);
+ }
+}
+ColumnTimeAdded.sortable = true;
+ColumnTimeAdded.id = "ts";
+ColumnTimeAdded.megatype = "timeAd";
+;// ./js/ui/jsx/fm/nodes/columns/columnExtras.jsx
+
+
+class ColumnExtras extends genericNodePropsComponent.B {
+ render() {
+ return JSX_("td", {
+ megatype: ColumnExtras.megatype,
+ className: "grid-url-field own-data extras-column"
+ }, JSX_("span", {
+ className: "versioning-indicator"
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-versions-previous"
+ })), JSX_("i", {
+ className: "sprite-fm-mono icon-link"
+ }));
+ }
+}
+ColumnExtras.sortable = false;
+ColumnExtras.id = "extras";
+ColumnExtras.label = "";
+ColumnExtras.megatype = "extras";
+ColumnExtras.headerClassName = "grid-url-header";
+;// ./js/ui/jsx/fm/browserEntries.jsx
+
+
+
+
+
+
+
+
+
+
+
+class BrowserEntries extends mixins.w9 {
+ constructor(props) {
+ super(props);
+ this.state = {
+ 'sortBy': props.sortBy || ['name', 'asc']
+ };
+ this.toggleSortBy = this.toggleSortBy.bind(this);
+ }
+ UNSAFE_componentWillMount() {
+ this.lastCharKeyPressed = false;
+ this.lastCharKeyIndex = -1;
+ }
+ componentDidMount() {
+ super.componentDidMount();
+ this.bindEvents();
+ }
+ componentWillUnmount() {
+ super.componentWillUnmount();
+ this.unbindEvents();
+ }
+ componentDidUpdate(oldProps) {
+ if (oldProps.sortBy && (oldProps.sortBy[0] !== this.props.sortBy[0] || oldProps.sortBy[1] !== this.props.sortBy[1])) {
+ this.setState({
+ 'sortBy': this.props.sortBy
+ });
+ }
+ }
+ handleKeyNavigation(selectionManager, shiftKey, keyCode, viewMode) {
+ let curr;
+ const {
+ folderSelectNotAllowed
+ } = this.props;
+ if (shiftKey && folderSelectNotAllowed) {
+ curr = selectionManager.last_selected;
+ }
+ const {KEYS} = BrowserEntries;
+ if (viewMode) {
+ if (keyCode === KEYS.LEFT) {
+ selectionManager.select_prev(shiftKey, true);
+ } else if (keyCode === KEYS.RIGHT) {
+ selectionManager.select_next(shiftKey, true);
+ } else if (keyCode === KEYS.UP) {
+ selectionManager.select_grid_up(shiftKey, true);
+ } else {
+ selectionManager.select_grid_down(shiftKey, true);
+ }
+ } else if (keyCode === KEYS.UP) {
+ selectionManager.select_prev(shiftKey, true);
+ } else {
+ selectionManager.select_next(shiftKey, true);
+ }
+ if (shiftKey && folderSelectNotAllowed && $.selected.length > 1) {
+ const folderNodes = $.selected.filter(n => !M.isFileNode(M.getNodeByHandle(n)));
+ if (folderNodes.length > 1) {
+ if (!M.isFileNode(M.getNodeByHandle(curr))) {
+ array.remove(folderNodes, curr);
+ }
+ if (folderNodes.length) {
+ const newCurr = selectionManager.last_selected;
+ for (let i = 0; i < folderNodes.length; i++) {
+ selectionManager.remove_from_selection(folderNodes[i]);
+ }
+ if (M.isFileNode(M.getNodeByHandle(newCurr))) {
+ selectionManager.set_currently_selected(curr);
+ } else if (curr && $.selected.includes(curr)) {
+ selectionManager.set_currently_selected(curr);
+ } else if ($.selected.length) {
+ selectionManager.set_currently_selected($.selected[0]);
+ }
+ }
+ }
+ }
+ }
+ _invalidKeydownTarget(e) {
+ return e.target && (e.target.tagName === 'INPUT' || e.target.tagName === 'BUTTON' || e.target.tagName === 'TEXTAREA' && !e.target.classList.contains('messages-textarea') || e.target.tagName === 'SELECT');
+ }
+ _isNavigationKeyDown(e, keyCode) {
+ const {
+ KEYS
+ } = BrowserEntries;
+ const {
+ viewMode
+ } = this.props;
+ return !e.metaKey && (!viewMode && (keyCode === KEYS.UP || keyCode === KEYS.DOWN) || viewMode && (keyCode === KEYS.UP || keyCode === KEYS.DOWN || keyCode === KEYS.LEFT || keyCode === KEYS.RIGHT));
+ }
+ bindEvents() {
+ const {
+ KEYS
+ } = BrowserEntries;
+ $(document.body).rebind(`keydown.be${this.getUniqueId()}`, e => {
+ let charTyped = false;
+ const keyCode = e.which || e.keyCode;
+ const $searchField = $('div.fm-files-search input');
+ const $typingArea = $('textarea.messages-textarea');
+ const {
+ selectionManager,
+ viewMode
+ } = this.props;
+ if (this._invalidKeydownTarget(e)) {
+ return;
+ }
+ if ($searchField.is(':focus')) {
+ return;
+ }
+ if ($typingArea.is(':focus')) {
+ $typingArea.trigger('blur');
+ }
+ if (keyCode === KEYS.A && (e.ctrlKey || e.metaKey)) {
+ this.handleSelectAll();
+ e.preventDefault();
+ e.stopPropagation();
+ } else if (e.metaKey && keyCode === KEYS.UP || keyCode === KEYS.BACKSPACE) {
+ this.handleKeyBack();
+ } else if (this._isNavigationKeyDown(e, keyCode)) {
+ this.handleKeyNavigation(selectionManager, e.shiftKey, keyCode, viewMode);
+ } else if (keyCode >= 48 && keyCode <= 57 || keyCode >= 65 && keyCode <= 123 || keyCode > 255) {
+ charTyped = String.fromCharCode(keyCode).toLowerCase();
+ this.handleCharTyped(charTyped);
+ } else if (keyCode === KEYS.ENTER || e.metaKey && keyCode === KEYS.DOWN) {
+ this.handleAttach();
+ }
+ mega.ui.mInfoPanel.reRenderIfVisible($.selected);
+ if (!charTyped) {
+ this.lastCharKeyPressed = false;
+ this.lastCharKeyIndex = -1;
+ }
+ });
+ }
+ handleSelectAll() {
+ const {
+ selectionManager,
+ folderSelectNotAllowed,
+ entries
+ } = this.props;
+ selectionManager.select_all();
+ if (folderSelectNotAllowed) {
+ const folders = entries.filter(h => !M.isFileNode(M.getNodeByHandle(h)));
+ for (let i = 0; i < folders.length; i++) {
+ selectionManager.remove_from_selection(folders[i].h);
+ }
+ }
+ }
+ handleKeyBack() {
+ const {
+ viewMode,
+ currentlyViewedEntry
+ } = this.props;
+ if (!viewMode) {
+ const currentFolder = M.getNode(currentlyViewedEntry);
+ if (currentFolder.p) {
+ this.expandFolder(currentFolder.p);
+ }
+ }
+ }
+ handleCharTyped(charTyped) {
+ const {
+ entries,
+ keyProp,
+ selectionManager
+ } = this.props;
+ const foundMatchingNodes = entries.filter(node => {
+ return node.name && node.name.substring(0, 1).toLowerCase() === charTyped;
+ });
+ if (this.lastCharKeyPressed === charTyped) {
+ this.lastCharKeyIndex++;
+ }
+ this.lastCharKeyPressed = charTyped;
+ if (foundMatchingNodes.length > 0) {
+ if (!foundMatchingNodes[this.lastCharKeyIndex]) {
+ this.lastCharKeyIndex = 0;
+ }
+ const foundNode = foundMatchingNodes[this.lastCharKeyIndex];
+ selectionManager.clear_selection();
+ selectionManager.set_currently_selected(foundNode[keyProp], true);
+ }
+ }
+ handleAttach() {
+ const {
+ highlighted,
+ folderSelectNotAllowed,
+ entries,
+ keyProp,
+ onAttachClicked
+ } = this.props;
+ let selectedNodes = highlighted;
+ if (folderSelectNotAllowed) {
+ selectedNodes = highlighted.filter(h => {
+ const node = entries.find(e => e[keyProp] === h);
+ return node && node.t === 0;
+ });
+ if (selectedNodes.length === 0) {
+ const cursorNode = highlighted[0] && M.getNodeByHandle(highlighted[0]);
+ if (cursorNode.t === 1) {
+ this.expandFolder(cursorNode[keyProp]);
+ return;
+ } else if (highlighted.length > 0) {
+ this.expandFolder(highlighted[0]);
+ return;
+ }
+ return;
+ }
+ }
+ onAttachClicked(selectedNodes);
+ }
+ unbindEvents() {
+ $(document.body).off(`keydown.be${ this.getUniqueId()}`);
+ }
+ onEntryClick(e, node) {
+ const {
+ selectionManager,
+ keyProp,
+ folderSelectNotAllowed,
+ highlighted = []
+ } = this.props;
+ this.lastCharKeyPressed = false;
+ this.lastCharKeyIndex = -1;
+ e.stopPropagation();
+ e.preventDefault();
+ if (!e.shiftKey && !e.ctrlKey && !e.metaKey) {
+ selectionManager.clear_selection();
+ selectionManager.set_currently_selected(node[keyProp]);
+ } else if (e.shiftKey) {
+ if ($.selected && $.selected.length) {
+ let selFolders;
+ if (folderSelectNotAllowed) {
+ selFolders = $.selected.filter(n => !M.isFileNode(M.getNodeByHandle(n)));
+ }
+ selectionManager.shift_select_to(node[keyProp], false, true, false);
+ if (folderSelectNotAllowed && $.selected.length > 1) {
+ const folderNodes = $.selected.filter(n => !M.isFileNode(M.getNodeByHandle(n)));
+ if (folderNodes.length > 1) {
+ array.remove(folderNodes, selFolders[0] || folderNodes[0]);
+ for (let i = 0; i < folderNodes.length; i++) {
+ selectionManager.remove_from_selection(folderNodes[i]);
+ }
+ }
+ }
+ } else {
+ selectionManager.set_currently_selected(node[keyProp]);
+ }
+ } else if (e.ctrlKey || e.metaKey) {
+ if (!highlighted || !highlighted.includes(node[keyProp])) {
+ if (folderSelectNotAllowed) {
+ if (node.t === 1 && highlighted.length > 0) {
+ return;
+ } else if (highlighted.some(nodeId => {
+ const node = M.getNodeByHandle(nodeId);
+ return node && node.t === 1;
+ })) {
+ selectionManager.clear_selection();
+ }
+ }
+ selectionManager.add_to_selection(node[keyProp]);
+ } else if (highlighted && highlighted.includes(node[keyProp])) {
+ if (folderSelectNotAllowed) {
+ if (node.t === 1) {
+ return;
+ } else if (highlighted.some(nodeId => {
+ const node = M.getNodeByHandle(nodeId);
+ return node && node.t === 1;
+ })) {
+ selectionManager.clear();
+ }
+ }
+ selectionManager.remove_from_selection(node[keyProp]);
+ }
+ }
+ }
+ expandFolder(nodeId) {
+ const self = this;
+ const node = M.getNodeByHandle(nodeId);
+ if (node) {
+ self.lastCharKeyPressed = false;
+ self.lastCharKeyIndex = -1;
+ self.setState({
+ 'selected': [],
+ 'highlighted': [],
+ 'cursor': false
+ });
+ self.props.onExpand(node);
+ self.forceUpdate();
+ }
+ }
+ onEntryDoubleClick(e, node) {
+ const self = this;
+ self.lastCharKeyPressed = false;
+ self.lastCharKeyIndex = -1;
+ e.stopPropagation();
+ e.preventDefault();
+ const share = M.getNodeShare(node);
+ if (share && share.down) {
+ return;
+ }
+ if (node.t) {
+ self.props.onExpand(node);
+ self.forceUpdate();
+ } else {
+ self.onEntryClick(e, node);
+ self.props.onAttachClicked();
+ }
+ }
+ customIsEventuallyVisible() {
+ return true;
+ }
+ toggleSortBy(colId) {
+ const newState = {};
+ if (this.state.sortBy[0] === colId) {
+ newState.sortBy = [colId, this.state.sortBy[1] === "asc" ? "desc" : "asc"];
+ } else {
+ newState.sortBy = [colId, "asc"];
+ }
+ this.setState(newState);
+ this.props.onSortByChanged(newState.sortBy);
+ }
+ render() {
+ const {viewMode} = this.props;
+ const listAdapterOpts = this.props.listAdapterOpts || {};
+ if (!viewMode) {
+ listAdapterOpts.columns = [columnFavIcon.$, ColumnNodeName, ColumnSize, ColumnTimeAdded, ColumnExtras];
+ }
+ if (this.props.listAdapterColumns) {
+ listAdapterOpts.columns = this.props.listAdapterColumns;
+ }
+ if (this.props.isLoading) {
+ return JSX_("div", {
+ className: "dialog-empty-block active dialog-fm folder"
+ }, JSX_("div", {
+ className: "dialog-empty-pad"
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-cloud-drive"
+ }), JSX_("div", {
+ className: "dialog-empty-header"
+ }, l[5533])));
+ } else if (!this.props.entries.length && this.props.currentlyViewedEntry === 'search') {
+ return JSX_("div", {
+ className: "dialog-empty-block active dialog-fm folder"
+ }, JSX_("div", {
+ className: "dialog-empty-pad"
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-preview-reveal"
+ }), JSX_("div", {
+ className: "dialog-empty-header"
+ }, l[978])));
+ } else if (!this.props.entries.length) {
+ const nilComp = this.props.NilComponent;
+ return nilComp && (typeof nilComp === "function" ? nilComp() : nilComp) || JSX_("div", {
+ className: "dialog-empty-block active dialog-fm folder"
+ }, this.props.currentlyViewedEntry === 'shares' ? JSX_("div", {
+ className: "dialog-empty-pad"
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-folder-incoming-share-filled"
+ }), JSX_("div", {
+ className: "dialog-empty-header"
+ }, l[6871])) : JSX_("div", {
+ className: "dialog-empty-pad"
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-folder-filled"
+ }), JSX_("div", {
+ className: "dialog-empty-header"
+ }, this.props.currentlyViewedEntry === M.RootID ? l[1343] : M.u[this.props.currentlyViewedEntry] ? l[6787] : l[782])));
+ }
+ return JSX_(MegaList2, {
+ viewMode,
+ sortBy: this.state.sortBy,
+ currentlyViewedEntry: this.props.currentlyViewedEntry,
+ selected: this.props.selected,
+ highlighted: this.props.highlighted,
+ containerClassName: this.props.containerClassName,
+ nodeAdapterProps: {
+ 'onClick': (e, node) => {
+ this.onEntryClick(e, node);
+ mega.ui.mInfoPanel.reRenderIfVisible($.selected);
+ },
+ 'onDoubleClick': (e, node) => {
+ this.onEntryDoubleClick(e, node);
+ },
+ 'className': node => {
+ return this.props.highlighted.indexOf(node[this.props.keyProp]) > -1 ? " ui-selected" : "";
+ }
+ },
+ ref: r => {
+ this.megaList = r;
+ },
+ listAdapter: viewMode ? Grid : Table,
+ nodeAdapter: viewMode ? GenericGrid : GenericTable,
+ listAdapterOpts,
+ entries: this.props.entries,
+ itemHeight: this.props.megaListItemHeight,
+ headerHeight: viewMode ? 0 : 56,
+ header: !viewMode && JSX_(GenericTableHeader, {
+ columns: listAdapterOpts.columns,
+ sortBy: this.state.sortBy,
+ onClick: this.toggleSortBy,
+ headerContainerClassName: this.props.headerContainerClassName
+ }),
+ currentdirid: this.props.currentdirid,
+ onContextMenu: this.props.onContextMenu,
+ keyProp: this.props.keyProp
+ });
+ }
+}
+BrowserEntries.KEYS = {
+ A: 65,
+ UP: 38,
+ DOWN: 40,
+ LEFT: 37,
+ RIGHT: 39,
+ ENTER: 13,
+ BACKSPACE: 8
+};
+BrowserEntries.defaultProps = {
+ 'hideable': true,
+ 'requiresUpdateOnResize': true
+};
+;// ./js/ui/jsx/fm/fmView.jsx
+
+
+
+class FMView extends mixins.w9 {
+ constructor(props) {
+ let _this$dataSource;
+ super(props);
+ this.domRef = REaCt().createRef();
+ let initialSortBy = props.initialSortBy || ['name', 'asc'];
+ if (props.fmConfigSortEnabled) {
+ let _fmconfig$sortmodes;
+ const sortId = props.fmConfigSortId;
+ assert(sortId, 'missing fmConfigSortId');
+ if ((_fmconfig$sortmodes = fmconfig.sortmodes) != null && (_fmconfig$sortmodes = _fmconfig$sortmodes[sortId]) != null && _fmconfig$sortmodes.n) {
+ let _fmconfig$sortmodes2;
+ initialSortBy = this._translateFmConfigSortMode((_fmconfig$sortmodes2 = fmconfig.sortmodes) == null ? void 0 : _fmconfig$sortmodes2[sortId]);
+ }
+ }
+ this.state = {
+ 'sortBy': initialSortBy,
+ 'selected': [],
+ 'highlighted': [],
+ 'entries': null
+ };
+ this.dataSource = this.props.dataSource;
+ this.state.entries = this.getEntries();
+ this.onAttachClicked = this.onAttachClicked.bind(this);
+ this.onContextMenu = this.onContextMenu.bind(this);
+ if ((_this$dataSource = this.dataSource) != null && _this$dataSource.addChangeListener) {
+ this._listener = this.dataSource.addChangeListener(() => {
+ if (!this.isMounted()) {
+ return;
+ }
+ this.setState({
+ 'entries': this.getEntries()
+ });
+ });
+ }
+ this.initSelectionManager();
+ }
+ getDataSourceNode(h) {
+ return this.dataSource && this.dataSource[h] || M.getNodeByHandle(h);
+ }
+ _translateFmConfigSortMode(currentSortModes) {
+ const sortId = this.props.fmConfigSortId;
+ assert(sortId, 'missing fmConfigSortId');
+ const sortByArr = [];
+ if (currentSortModes != null && currentSortModes.n) {
+ sortByArr[0] = currentSortModes.n;
+ const sortMap = this.props.fmConfigSortMap;
+ const aliasKeys = sortMap && Object.keys(sortMap) || [];
+ for (const alias of aliasKeys) {
+ if (sortByArr[0] === sortMap[alias]) {
+ sortByArr[0] = alias;
+ break;
+ }
+ }
+ sortByArr[1] = currentSortModes.d === 1 ? "asc" : "desc";
+ }
+ return sortByArr;
+ }
+ initSelectionManager(entries) {
+ this.selectionManager = new SelectionManager2_React(entries || this.state.entries, this.props.currentdirid || "cloud-drive", () => {
+ let _this$browserEntries;
+ return (_this$browserEntries = this.browserEntries) == null || (_this$browserEntries = _this$browserEntries.megaList) == null || (_this$browserEntries = _this$browserEntries._calculated) == null ? void 0 : _this$browserEntries.itemsPerRow;
+ }, nodeHandle => {
+ if (this.browserEntries && this.browserEntries.megaList) {
+ this.browserEntries.megaList.scrollToItem(nodeHandle);
+ }
+ }, {
+ 'onSelectedUpdated': selectedList => {
+ this.onSelectionUpdated(selectedList);
+ }
+ });
+ }
+ onSelectionUpdated(selectedList) {
+ selectedList = [...selectedList];
+ const highlighted = selectedList;
+ if (this.props.folderSelectNotAllowed && !this.props.folderSelectable) {
+ selectedList = selectedList.filter(nodeId => !this.getDataSourceNode(nodeId).t);
+ }
+ this.setState({
+ 'selected': selectedList,
+ highlighted
+ });
+ this.props.onSelected(selectedList);
+ this.props.onHighlighted(highlighted);
+ $.selected = highlighted;
+ }
+ getEntries(newState) {
+ const self = this;
+ const sortBy = newState && newState.sortBy || self.state.sortBy;
+ const order = sortBy[1] === "asc" ? 1 : -1;
+ const entries = [];
+ let sortFunc, filterFunc, dataSource;
+ const minSearchLength = self.props.minSearchLength || 3;
+ const showSen = mega.sensitives.showGlobally;
+ if (self.props.currentlyViewedEntry === "search" && self.props.searchValue && self.props.searchValue.length >= minSearchLength) {
+ dataSource = this.dataSource || {
+ ...M.tnd,
+ ...M.d
+ };
+ filterFunc = M.getFilterBySearchFn(self.props.searchValue);
+ } else {
+ const tmp = M.getChildren(self.props.currentlyViewedEntry) || M.tree[self.props.currentlyViewedEntry] || this.props.dataSource;
+ dataSource = Object.create(null);
+ for (const h in tmp) {
+ const n = this.getDataSourceNode(h);
+ if (n) {
+ dataSource[h] = n;
+ }
+ }
+ }
+ const {
+ customFilterFn
+ } = this.props;
+ for (const h in dataSource) {
+ const n = dataSource[h];
+ const e = n && (!n.h || n.h.length === 8 && crypto_keyok(n) || n.h.length === 11);
+ const s = e && !n.fv && (showSen || !mega.sensitives.isSensitive(n));
+ if (s && (!customFilterFn || customFilterFn(n)) && (!filterFunc || filterFunc(n))) {
+ entries.push(n);
+ }
+ }
+ if (sortBy[0] === "name") {
+ sortFunc = M.getSortByNameFn();
+ } else if (sortBy[0] === "size") {
+ sortFunc = M.getSortBySizeFn();
+ } else if (sortBy[0] === "ts") {
+ sortFunc = M.getSortByDateTimeFn();
+ } else if (sortBy[0] === "rts") {
+ sortFunc = M.getSortByRtsFn();
+ } else if (sortBy[0] === "status") {
+ sortFunc = M.getSortByStatusFn();
+ } else if (sortBy[0] === "interaction") {
+ sortFunc = M.getSortByInteractionFn();
+ } else if (sortBy[0] === "verification") {
+ sortFunc = M.getSortByVerificationFn();
+ } else if (sortBy[0] === "email") {
+ sortFunc = M.getSortByEmail();
+ } else if (sortBy[0] === 'access') {
+ sortFunc = (a, b, o) => typeof a.r !== 'undefined' && typeof b.r !== 'undefined' && (a.r < b.r ? -1 : 1) * o;
+ } else {
+ sortFunc = M.sortByFavFn(order);
+ }
+ const folders = [];
+ if (this.props.sortFoldersFirst) {
+ for (let i = entries.length; i--;) {
+ if (entries[i] && entries[i].t) {
+ folders.unshift(entries[i]);
+ entries.splice(i, 1);
+ }
+ }
+ }
+ folders.sort((a, b) => {
+ return sortFunc(a, b, order);
+ });
+ entries.sort((a, b) => {
+ return sortFunc(a, b, order);
+ });
+ return folders.concat(entries);
+ }
+ onHighlighted(nodes) {
+ this.setState({
+ 'highlighted': nodes
+ });
+ if (this.props.onHighlighted) {
+ this.props.onHighlighted(nodes);
+ }
+ }
+ finishedLoading(newState) {
+ newState.isLoading = false;
+ newState.entries = this.getEntries();
+ this.initSelectionManager(newState.entries);
+ this.setState(newState);
+ }
+ addOrUpdRawListener() {
+ if (this._rawListener) {
+ mBroadcaster.removeListener(this._rawListener);
+ }
+ this._rawListener = mBroadcaster.addListener(`fmViewUpdate:${ this.props.currentlyViewedEntry}`, () => {
+ this.setState({
+ 'entries': this.getEntries()
+ }, () => {
+ if (this.browserEntries.isMounted()) {
+ this.browserEntries.forceUpdate();
+ }
+ });
+ });
+ }
+ componentDidMount() {
+ let _this$dataSource2;
+ super.componentDidMount();
+ if (!((_this$dataSource2 = this.dataSource) != null && _this$dataSource2.addChangeListener)) {
+ this.addOrUpdRawListener();
+ }
+ if (this.props.fmConfigSortEnabled) {
+ this._sortModeListener = mBroadcaster.addListener("fmconfig:sortmodes", sortModes => {
+ this.onFmConfigSortModeChanged(sortModes);
+ });
+ }
+ }
+ componentDidUpdate(prevProps) {
+ const {
+ currentlyViewedEntry: currEntry,
+ searchValue: currSearch
+ } = this.props;
+ const {
+ currentlyViewedEntry: prevEntry,
+ searchValue: prevSearch
+ } = prevProps;
+ const dataSourceChanged = this.props.dataSource !== prevProps.dataSource;
+ if (dataSourceChanged || prevEntry !== currEntry || currSearch !== prevSearch) {
+ let _this$dataSource3;
+ this.dataSource = this.props.dataSource;
+ const newState = {
+ 'selected': [],
+ 'highlighted': []
+ };
+ if (!((_this$dataSource3 = this.dataSource) != null && _this$dataSource3.addChangeListener)) {
+ this.addOrUpdRawListener();
+ }
+ const handle = currEntry;
+ if (handle === 'shares') {
+ newState.isLoading = true;
+ this.setState(newState);
+ dbfetch.geta(Object.keys(M.c.shares || {})).always(() => {
+ this.finishedLoading(newState);
+ });
+ return;
+ }
+ if (this.getDataSourceNode(handle).t && !M.getChildren(handle)) {
+ this.setState({
+ 'isLoading': true
+ });
+ dbfetch.get(handle).always(() => {
+ this.finishedLoading(newState);
+ });
+ return;
+ }
+ const entries = this.getEntries();
+ this.initSelectionManager(entries);
+ this.setState({
+ entries
+ });
+ }
+ }
+ onAttachClicked() {
+ this.props.onAttachClicked();
+ }
+ onContextMenu() {}
+ componentWillUnmount() {
+ super.componentWillUnmount();
+ if (this._listener) {
+ let _this$dataSource4;
+ (_this$dataSource4 = this.dataSource) == null || _this$dataSource4.removeChangeListener(this._listener);
+ }
+ if (this._rawListener) {
+ mBroadcaster.removeListener(this._rawListener);
+ }
+ if (this._sortModeListener) {
+ mBroadcaster.removeListener(this._sortModeListener);
+ }
+ $.selected = [];
+ this.selectionManager.destroy();
+ this.selectionManager = undefined;
+ $('.dropdown.body.files-menu.context').css('z-index', '');
+ }
+ onSortByChanged(newState) {
+ if (newState[0] === this.state.sortBy[0] && newState[1] === this.state.sortBy[1]) {
+ return;
+ }
+ const entries = this.getEntries({
+ 'sortBy': newState
+ });
+ this.setState({
+ 'sortBy': newState,
+ entries,
+ 'selected': [],
+ 'highlighted': []
+ }, () => {
+ if (this.props.onSortByChanged) {
+ this.props.onSortByChanged(newState);
+ }
+ if (this.props.fmConfigSortEnabled) {
+ const sortId = this.props.fmConfigSortId;
+ assert(sortId, 'fmConfigSortId missing');
+ if (newState[0] === this.props.initialSortBy[0] && newState[1] === this.props.initialSortBy[1]) {
+ const sortModes = typeof fmconfig.sortmodes !== 'undefined' ? fmconfig.sortmodes : Object.create(null);
+ delete sortModes[sortId];
+ mega.config.set('sortmodes', sortModes);
+ return;
+ }
+ const map = this.props.fmConfigSortMap || Object.create(null);
+ const name = map[newState[0]] || newState[0];
+ const direction = newState[1] === "asc" ? 1 : -1;
+ fmsortmode(sortId, name, direction);
+ }
+ });
+ this.initSelectionManager(entries);
+ }
+ onFmConfigSortModeChanged(sortModes) {
+ const currentSortMode = sortModes[this.props.fmConfigSortId];
+ if (!currentSortMode) {
+ this.onSortByChanged(this.props.initialSortBy || ['name', 'asc']);
+ } else {
+ const newSortMode = this._translateFmConfigSortMode(currentSortMode);
+ if (this.state.sortBy[0] !== newSortMode[0] || this.state.sortBy[1] !== newSortMode[1]) {
+ this.onSortByChanged(newSortMode);
+ }
+ }
+ }
+ render() {
+ return JSX_("div", {
+ ref: this.domRef,
+ className: "content-container",
+ onClick: ev => {
+ $.hideContextMenu(ev);
+ }
+ }, JSX_(BrowserEntries, {
+ isLoading: this.state.isLoading || this.props.nodeLoading,
+ currentlyViewedEntry: this.props.currentlyViewedEntry,
+ entries: this.state.entries || [],
+ onExpand: node => {
+ this.setState({
+ 'selected': [],
+ 'highlighted': []
+ });
+ this.props.onExpand(node[this.props.keyProp || 'h']);
+ },
+ sortBy: this.state.sortBy,
+ folderSelectNotAllowed: this.props.folderSelectNotAllowed,
+ onAttachClicked: this.onAttachClicked,
+ viewMode: this.props.viewMode,
+ selected: this.state.selected,
+ highlighted: this.state.highlighted,
+ onContextMenu: this.props.onContextMenu || this.onContextMenu,
+ selectionManager: this.selectionManager,
+ ref: browserEntries => {
+ this.browserEntries = browserEntries;
+ },
+ onSortByChanged: newState => {
+ this.onSortByChanged(newState);
+ },
+ listAdapterColumns: this.props.listAdapterColumns,
+ currentdirid: this.props.currentdirid,
+ containerClassName: this.props.containerClassName,
+ headerContainerClassName: this.props.headerContainerClassName,
+ megaListItemHeight: this.props.megaListItemHeight,
+ keyProp: this.props.keyProp || 'h',
+ NilComponent: this.props.NilComponent,
+ listAdapterOpts: this.props.listAdapterOpts
+ }));
+ }
+}
+
+ },
+
+ 6794
+(_, EXP_, REQ_) {
+
+ REQ_.d(EXP_, {
+ $: () => ColumnFavIcon
+ });
+ const react0__ = REQ_(1594);
+ const react0___default = REQ_.n(react0__);
+ const _genericNodePropsComponent1__ = REQ_(4285);
+
+
+class ColumnFavIcon extends _genericNodePropsComponent1__ .B {
+ render() {
+ const {
+ nodeAdapter
+ } = this.props;
+ const {
+ node
+ } = nodeAdapter.props;
+ const isFavouritable = node.r === 2;
+ return JSX_("td", {
+ megatype: ColumnFavIcon.megatype,
+ className: ColumnFavIcon.megatype
+ }, JSX_("span", {
+ className: `grid-status-icon sprite-fm-mono ${ missingkeys[node.h] ? " icon-info" : nodeAdapter.nodeProps.fav ? " icon-favourite-filled" : " icon-dot" }${!isFavouritable && " disabled" || ""}`,
+ onClick: () => {
+ if (isFavouritable) {
+ M.favourite([node.h], !node.fav);
+ }
+ }
+ }));
+ }
+}
+ColumnFavIcon.sortable = true;
+ColumnFavIcon.id = "fav";
+ColumnFavIcon.label = "";
+ColumnFavIcon.icon = "icon-favourite-filled";
+ColumnFavIcon.megatype = "fav";
+ColumnFavIcon.headerClassName = "grid-first-th fav";
+
+ },
+
+ 4285
+(_, EXP_, REQ_) {
+
+
+// EXPORTS
+REQ_.d(EXP_, {
+ B: () => GenericNodePropsComponent
+});
+
+// EXTERNAL MODULE: ./js/chat/mixins.js
+const mixins = REQ_(8264);
+;// ./js/ui/jsx/fm/nodes/nodeProperties.jsx
+class NodeProperties {
+ static get(node, changeListener) {
+ assert(node.h, 'missing handle for node');
+ if (NodeProperties._globalCleanupTimer) {
+ NodeProperties._globalCleanupTimer.abort();
+ }
+ (NodeProperties._globalCleanupTimer = tSleep(120)).then(() => {
+ NodeProperties.cleanup(0);
+ });
+ let nodeProps;
+ if (!NodeProperties._cache.has(node.h)) {
+ nodeProps = new NodeProperties(node, changeListener);
+ NodeProperties._cache.set(node.h, nodeProps);
+ }
+ return nodeProps || NodeProperties._cache.get(node.h);
+ }
+ unuse(changeListener) {
+ const {node} = this;
+ if (!node) {
+ if (d) {
+ console.warn("This should not happen.");
+ }
+ return;
+ }
+ this.changeListeners.delete(changeListener);
+ let usages = NodeProperties._usages.get(this);
+ if (usages) {
+ NodeProperties._usages.set(this, --usages);
+ if (usages === 0 && NodeProperties._cache.size > NodeProperties.MAX_CACHE_SIZE) {
+ delay('nodePropCleanup', NodeProperties.cleanup, 1000);
+ }
+ }
+ }
+ static cleanup(maxCacheSize) {
+ maxCacheSize = typeof maxCacheSize === "undefined" ? NodeProperties.MAX_CACHE_SIZE : maxCacheSize;
+ const len = NodeProperties._cache.size;
+ let removed = 0;
+ for (const entry of NodeProperties._cache) {
+ const id = entry[0];
+ const node = entry[1];
+ const usage = NodeProperties._usages.get(node);
+ if (usage === 0) {
+ NodeProperties._usages.delete(node);
+ node._cleanup();
+ NodeProperties._cache.delete(id);
+ removed++;
+ if (len - removed < maxCacheSize) {
+ return;
+ }
+ }
+ }
+ }
+ constructor(node, changeListener) {
+ this.node = node;
+ this.changeListeners = new Set();
+ if (changeListener) {
+ this.changeListeners.add(changeListener);
+ }
+ const _onChange = () => {
+ this.initProps();
+ for (const listener of this.changeListeners) {
+ listener();
+ }
+ };
+ if (this.node.addChangeListener) {
+ this._listener = this.node.addChangeListener(_onChange);
+ } else {
+ this._mbListener = mBroadcaster.addListener(`nodeUpdated:${ node.h}`, _onChange);
+ }
+ this.initProps();
+ }
+ use(changeListener) {
+ if (changeListener) {
+ this.changeListeners.add(changeListener);
+ }
+ NodeProperties._usages.set(this, (NodeProperties._usages.get(this) | 0) + 1);
+ }
+ _cleanup() {
+ if (this._listener) {
+ this.node.removeChangeListener(this._listener);
+ }
+ if (this._mbListener) {
+ mBroadcaster.removeListener(this._mbListener);
+ }
+ oDestroy(this);
+ }
+ initProps() {
+ const {node} = this;
+ lazy(this, 'title', () => {
+ if (missingkeys[node.h]) {
+ return node.t ? l[8686] : l[8687];
+ }
+ return M.getNameByHandle(node.h);
+ });
+ lazy(this, 'classNames', () => {
+ const classNames = [];
+ if (node.su) {
+ classNames.push('inbound-share');
+ }
+ if (node.t) {
+ classNames.push('folder');
+ } else {
+ classNames.push('file');
+ }
+ const share = this.shareData;
+ if (missingkeys[node.h] || share.down) {
+ if (share.down) {
+ classNames.push('taken-down');
+ }
+ if (missingkeys[node.h]) {
+ classNames.push('undecryptable');
+ }
+ }
+ if (share) {
+ classNames.push('linked');
+ }
+ if (node.lbl && !folderlink) {
+ const colourLabel = M.getLabelClassFromId(node.lbl);
+ classNames.push('colour-label');
+ classNames.push(colourLabel);
+ }
+ return classNames;
+ });
+ lazy(this, 'icon', () => {
+ return fileIcon(node);
+ });
+ lazy(this, 'isFolder', () => {
+ return !!node.t;
+ });
+ lazy(this, 'shareData', () => {
+ return M.getNodeShare(node);
+ });
+ lazy(this, 'isTakendown', () => {
+ return this.shareData && !!this.shareData.down;
+ });
+ lazy(this, 'fav', () => {
+ return !!node.fav;
+ });
+ lazy(this, 'size', () => {
+ return bytesToSize(node.tb || node.s);
+ });
+ lazy(this, 'timestamp', () => {
+ return time2date(node.ts);
+ });
+ lazy(this, 'root', () => {
+ return M.getNodeRoot(node.h);
+ });
+ lazy(this, 'incomingShareData', () => {
+ const result = {};
+ if (node.r === 1) {
+ result.accessLabel = l[56];
+ result.accessIcon = 'icon-permissions-write';
+ } else if (node.r === 2) {
+ result.accessLabel = l[57];
+ result.accessIcon = 'icon-star';
+ } else {
+ result.accessLabel = l[55];
+ result.accessIcon = 'icon-read-only';
+ }
+ return result;
+ });
+ lazy(this, 'timestamp', () => {
+ return time2date(node.ts);
+ });
+ lazy(this, 'onlineStatus', () => {
+ return M.onlineStatusClass(node.presence ? node.presence : "unavailable");
+ });
+ }
+}
+NodeProperties._cache = new Map();
+NodeProperties._usages = new WeakMap();
+NodeProperties._globalCleanupTimer = void 0;
+NodeProperties.MAX_CACHE_SIZE = 100;
+if (d) {
+ window.NodeProperties = NodeProperties;
+}
+;// ./js/ui/jsx/fm/nodes/genericNodePropsComponent.jsx
+
+
+class GenericNodePropsComponent extends mixins.w9 {
+ constructor(props) {
+ super(props);
+ if (this.props.node.h) {
+ this.nodeProps = NodeProperties.get(this.props.node);
+ this.changeListener = this.changeListener.bind(this);
+ }
+ }
+ changeListener() {
+ if (this.isMounted()) {
+ this.safeForceUpdate();
+ }
+ }
+ UNSAFE_componentWillReceiveProps(nextProps) {
+ if (nextProps.highlighted !== this.props.highlighted) {
+ this.safeForceUpdate();
+ }
+ }
+ UNSAFE_componentWillMount() {
+ let _this$nodeProps;
+ if (super.UNSAFE_componentWillMount) {
+ super.UNSAFE_componentWillMount();
+ }
+ (_this$nodeProps = this.nodeProps) == null || _this$nodeProps.use(this.changeListener);
+ }
+ componentWillUnmount() {
+ let _this$nodeProps2;
+ super.componentWillUnmount();
+ (_this$nodeProps2 = this.nodeProps) == null || _this$nodeProps2.unuse(this.changeListener);
+ }
+}
+
+ }
+
+}]);
\ No newline at end of file
diff --git a/js/chat/bundle.contacts-panel.js b/js/chat/bundle.contacts-panel.js
new file mode 100644
index 0000000000..fa0b919102
--- /dev/null
+++ b/js/chat/bundle.contacts-panel.js
@@ -0,0 +1,3381 @@
+/** @file automatically generated, do not edit it. */
+"use strict";
+(self.webpackChunk_meganz_webclient = self.webpackChunk_meganz_webclient || []).push([[253],{
+
+ 5392
+(_, EXP_, REQ_) {
+
+// ESM COMPAT FLAG
+REQ_.r(EXP_);
+
+// EXPORTS
+REQ_.d(EXP_, {
+ "default": () => ContactsPanel
+});
+
+// EXTERNAL MODULE: external "React"
+const external_React_ = REQ_(1594);
+const REaCt = REQ_.n(external_React_);
+// EXTERNAL MODULE: ./js/chat/mixins.js
+const mixins = REQ_(8264);
+// EXTERNAL MODULE: ./js/ui/buttons.jsx
+const buttons = REQ_(5155);
+// EXTERNAL MODULE: ./js/chat/ui/contactsPanel/utils.jsx
+const utils = REQ_(836);
+;// ./js/chat/ui/contactsPanel/navigation.jsx
+
+
+
+const Navigation = ({
+ view,
+ receivedRequestsCount
+}) => {
+ return JSX_("div", {
+ className: "contacts-navigation"
+ }, JSX_("ul", null, Object.keys(utils.gR).map(key => {
+ let activeClass = view === utils.gR[key] ? 'active' : '';
+ if (view === utils.gR.PROFILE && utils.gR[key] === utils.gR.CONTACTS) {
+ activeClass = 'active';
+ }
+ if (utils.gR[key] !== utils.gR.PROFILE) {
+ return JSX_("li", {
+ key,
+ onClick: () => {
+ let page = key.toLowerCase().split("_")[0];
+ page = page === 'contacts' ? '' : page;
+ loadSubPage(`fm/chat/contacts/${page}`);
+ }
+ }, JSX_(buttons.$, {
+ className: `
+ mega-button
+ action
+ ${activeClass}
+ `,
+ receivedRequestsCount
+ }, JSX_("span", null, utils.d_[key]), receivedRequestsCount > 0 && utils.gR[key] === utils.gR.RECEIVED_REQUESTS && JSX_("div", {
+ className: "notifications-count"
+ }, receivedRequestsCount > 9 ? '9+' : receivedRequestsCount)));
+ }
+ return null;
+ })));
+};
+ const navigation = Navigation;
+// EXTERNAL MODULE: ./js/ui/utils.jsx
+const ui_utils = REQ_(6411);
+;// ./js/chat/ui/contactsPanel/nil.jsx
+
+
+
+class Nil extends REaCt().Component {
+ componentDidMount() {
+ setContactLink();
+ }
+ render() {
+ const {
+ title
+ } = this.props;
+ return JSX_("div", {
+ className: "fm-empty-section fm-empty-contacts"
+ }, JSX_("div", {
+ className: "fm-empty-pad"
+ }, JSX_("i", {
+ className: "section-icon sprite-fm-mono icon-contacts"
+ }), JSX_("div", {
+ className: "fm-empty-cloud-txt"
+ }, title), JSX_("div", {
+ className: "fm-empty-description"
+ }, l[19115]), JSX_(buttons.$, {
+ className: "mega-button positive large fm-empty-button",
+ onClick: () => contactAddDialog()
+ }, JSX_("span", null, l[71])), JSX_("div", {
+ className: "empty-share-public"
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-link-circle"
+ }), JSX_(ui_utils.P9, null, l[19111]))));
+ }
+}
+// EXTERNAL MODULE: ./js/ui/jsx/fm/fmView.jsx + 10 modules
+const fmView = REQ_(872);
+// EXTERNAL MODULE: ./js/chat/ui/contacts.jsx
+const contacts = REQ_(8022);
+// EXTERNAL MODULE: ./js/ui/jsx/fm/nodes/genericNodePropsComponent.jsx + 1 modules
+const genericNodePropsComponent = REQ_(4285);
+;// ./js/ui/jsx/fm/nodes/columns/columnContactName.jsx
+
+
+
+
+class ColumnContactName extends genericNodePropsComponent.B {
+ constructor(...args) {
+ super(...args);
+ this.Mail = (0,ui_utils.T9)(() => JSX_("span", {
+ className: "contact-item-email"
+ }, this.props.nodeAdapter.props.node.m));
+ }
+ static get label() {
+ return l[86];
+ }
+ get name() {
+ const {
+ nodeAdapter,
+ node
+ } = this.props;
+ if (nodeAdapter.nodeProps) {
+ return nodeAdapter.nodeProps.title;
+ }
+ return M.getNameByEmail(node.m);
+ }
+ _renderAvatar() {
+ const {
+ nodeAdapter
+ } = this.props;
+ const {
+ node
+ } = nodeAdapter.props;
+ if (nodeAdapter.nodeProps || node.name !== '') {
+ return JSX_(contacts.eu, {
+ contact: node,
+ className: "avatar-wrapper box-avatar"
+ });
+ } else if (node.name === '') {
+ return JSX_(ui_utils.P9, null, useravatar.contact(node.m, 'box-avatar'));
+ }
+ return null;
+ }
+ render() {
+ return JSX_("td", null, this._renderAvatar(), JSX_("div", {
+ className: "contact-item"
+ }, JSX_("div", {
+ className: "contact-item-user"
+ }, JSX_(ui_utils.sp, null, this.name)), JSX_(this.Mail, null)), JSX_("div", {
+ className: "clear"
+ }));
+ }
+}
+ColumnContactName.sortable = true;
+ColumnContactName.id = "name";
+ColumnContactName.megatype = "name";
+;// ./js/ui/jsx/fm/nodes/columns/columnContactStatus.jsx
+
+
+class ColumnContactStatus extends genericNodePropsComponent.B {
+ static get label() {
+ return l[89];
+ }
+ render() {
+ const {
+ nodeAdapter
+ } = this.props;
+ const {onlineStatus} = nodeAdapter.nodeProps;
+ return JSX_("td", {
+ megatype: ColumnContactStatus.megatype,
+ className: ColumnContactStatus.megatype
+ }, JSX_("div", {
+ className: "contact-item"
+ }, JSX_("div", {
+ className: "contact-item-status"
+ }, JSX_("div", {
+ className: `user-card-presence ${ onlineStatus[1]}`
+ }), onlineStatus[0])));
+ }
+}
+ColumnContactStatus.sortable = true;
+ColumnContactStatus.id = "status";
+ColumnContactStatus.megatype = "status";
+;// ./js/ui/jsx/fm/nodes/columns/columnContactLastInteraction.jsx
+
+
+class ColumnContactLastInteraction extends genericNodePropsComponent.B {
+ constructor(...args) {
+ super(...args);
+ this.getLastInteractionIcon = handle => {
+ const {
+ interactions
+ } = this.props;
+ const interaction = interactions[handle];
+ const {
+ type,
+ time
+ } = interaction || {
+ type: undefined,
+ time: undefined
+ };
+ return JSX_("i", {
+ className: `
+ sprite-fm-mono
+ ${parseInt(type, 10) === 0 ? 'icon-cloud' : ''}
+ ${parseInt(type, 10) === 1 ? 'icon-chat' : ''}
+ ${!time ? 'icon-minimise' : ''}
+ `
+ });
+ };
+ this.getLastInteractionTime = handle => {
+ const {
+ interactions
+ } = this.props;
+ const interaction = interactions[handle];
+ return interaction ? time2last(interaction.time) : l[1051];
+ };
+ }
+ static get label() {
+ return l[5904];
+ }
+ render() {
+ const {
+ nodeAdapter
+ } = this.props;
+ const {
+ node
+ } = nodeAdapter.props;
+ return JSX_("td", {
+ megatype: ColumnContactLastInteraction.megatype,
+ className: ColumnContactLastInteraction.megatype
+ }, JSX_("div", {
+ className: "contact-item"
+ }, JSX_("div", {
+ className: "contact-item-time"
+ }, this.getLastInteractionIcon(node.h), this.getLastInteractionTime(node.h))));
+ }
+}
+ColumnContactLastInteraction.sortable = true;
+ColumnContactLastInteraction.id = "interaction";
+ColumnContactLastInteraction.megatype = "interaction";
+;// ./js/ui/jsx/fm/nodes/columns/columnContactVerifiedStatus.jsx
+
+
+
+class ColumnContactVerifiedStatus extends genericNodePropsComponent.B {
+ constructor(...args) {
+ super(...args);
+ this.getFingerPrintDialogLink = handle => {
+ const onVerifyContactClicked = handle => {
+ (0,utils.qH)(this.props.contacts[handle]);
+ };
+ return JSX_("div", {
+ className: "verify-contact-link-container"
+ }, JSX_("div", {
+ className: "verify-contact-link",
+ onClick: () => onVerifyContactClicked(handle)
+ }, l.verify_credentials));
+ };
+ }
+ render() {
+ const {
+ nodeAdapter
+ } = this.props;
+ const {
+ node
+ } = nodeAdapter.props;
+ return JSX_("td", {
+ megatype: ColumnContactVerifiedStatus.megatype,
+ className: ColumnContactVerifiedStatus.megatype
+ }, JSX_("div", {
+ className: "contact-item"
+ }, JSX_("div", {
+ className: "contact-item-verification"
+ }, (0,utils.p4)(this.props.contacts[node.h]) ? ColumnContactVerifiedStatus.verifiedLabel : this.getFingerPrintDialogLink(node.h))));
+ }
+}
+ColumnContactVerifiedStatus.sortable = true;
+ColumnContactVerifiedStatus.id = "verification";
+ColumnContactVerifiedStatus.megatype = "verification";
+ColumnContactVerifiedStatus.label = JSX_(REaCt().Fragment, null, l.contact_ver_verification, "\xA0", JSX_("i", {
+ className: "simpletip sprite-fm-mono contacts-verification-icon icon-info",
+ "data-simpletip": l.contact_ver_tooltip_content,
+ "data-simpletip-class": "contacts-verification-icon-simpletip"
+}));
+ColumnContactVerifiedStatus.verifiedLabel = JSX_("div", {
+ className: "verified-contact-label-container"
+}, JSX_("i", {
+ className: "small-icon icons-sprite tiny-green-tick"
+}), l[6776]);
+// EXTERNAL MODULE: ./js/ui/dropdowns.jsx
+const dropdowns = REQ_(1510);
+// EXTERNAL MODULE: ./js/chat/ui/meetings/utils.jsx
+const meetings_utils = REQ_(3901);
+// EXTERNAL MODULE: ./js/chat/ui/conversations.jsx + 2 modules
+const conversations = REQ_(4904);
+;// ./js/chat/ui/contactsPanel/contextMenu.jsx
+
+
+
+
+
+
+
+class ContextMenu extends REaCt().Component {
+ constructor(...args) {
+ super(...args);
+ this.EVENT_CLOSE = new Event('closeDropdowns');
+ this.close = callback => {
+ if (callback && typeof callback === 'function' && !M.isInvalidUserStatus()) {
+ callback();
+ }
+ document.dispatchEvent(this.EVENT_CLOSE);
+ };
+ this.handleSetNickname = handle => this.close(() => nicknames.setNicknameDialog.init(handle));
+ this.handleAddContact = handle => {
+ M.syncContactEmail(handle, true).then(email => {
+ const OPC = Object.values(M.opc);
+ const ALREADY_SENT = OPC && OPC.length && OPC.some(opc => opc.m === email);
+ this.close(() => {
+ if (ALREADY_SENT) {
+ return msgDialog('warningb', '', l[17545]);
+ }
+ msgDialog('info', l[150], l[5898]);
+ M.inviteContact(M.u[u_handle].m, email);
+ });
+ }).catch(nop);
+ };
+ }
+ render() {
+ const {
+ contact,
+ selected,
+ withProfile
+ } = this.props;
+ if ((0,utils.X7)(contact)) {
+ return JSX_(REaCt().Fragment, null, withProfile && JSX_("div", {
+ className: "dropdown-avatar rounded",
+ onClick: e => {
+ e.stopPropagation();
+ loadSubPage(`fm/chat/contacts/${contact.h}`);
+ }
+ }, JSX_(contacts.eu, {
+ contact,
+ className: "avatar-wrapper context-avatar"
+ }), JSX_("div", {
+ className: "dropdown-profile"
+ }, JSX_("span", null, JSX_(ui_utils.zT, null, M.getNameByHandle(contact.u))), JSX_(contacts.i1, {
+ contact
+ }))), JSX_(dropdowns.tJ, {
+ icon: "sprite-fm-mono icon-chat",
+ label: l[8632],
+ onClick: () => this.close(() => {
+ if (selected && selected.length) {
+ return megaChat.createAndShowGroupRoomFor(selected, '', {
+ keyRotation: true,
+ createChatLink: false
+ });
+ }
+ loadSubPage(`fm/chat/p/${contact.u}`);
+ megaChat.trigger(conversations.qY.NAV_RENDER_VIEW, conversations.Vw.CHATS);
+ })
+ }), JSX_(dropdowns.tJ, {
+ icon: "sprite-fm-mono icon-send-files",
+ label: l[6834],
+ onClick: () => this.close(() => megaChat.openChatAndSendFilesDialog(contact.u))
+ }), JSX_(dropdowns.tJ, {
+ icon: "sprite-fm-mono icon-folder-outgoing-share",
+ label: l[5631],
+ onClick: () => this.close(() => openCopyShareDialog(contact.u))
+ }), JSX_("div", {
+ "data-simpletipposition": "top",
+ className: "simpletip",
+ "data-simpletip": !megaChat.hasSupportForCalls ? l.call_not_suported : ''
+ }, JSX_(dropdowns.tJ, {
+ submenu: megaChat.hasSupportForCalls,
+ disabled: !navigator.onLine || !megaChat.hasSupportForCalls,
+ icon: "sprite-fm-mono icon-phone",
+ className: "sprite-fm-mono-before icon-arrow-right-before",
+ label: l[19125]
+ }), JSX_("div", {
+ className: "dropdown body submenu"
+ }, JSX_(dropdowns.tJ, {
+ icon: "sprite-fm-mono icon-phone",
+ disabled: !navigator.onLine || !megaChat.hasSupportForCalls,
+ label: l[5896],
+ onClick: () => (0,meetings_utils.dQ)().then(() => this.close(() => megaChat.createAndShowPrivateRoom(contact.u).then(room => {
+ room.setActive();
+ room.startAudioCall();
+ }))).catch(() => d && console.warn('Already in a call.'))
+ }), JSX_(dropdowns.tJ, {
+ icon: "sprite-fm-mono icon-video-call-filled",
+ disabled: !navigator.onLine || !megaChat.hasSupportForCalls,
+ label: l[5897],
+ onClick: () => (0,meetings_utils.dQ)().then(() => this.close(() => megaChat.createAndShowPrivateRoom(contact.u).then(room => {
+ room.setActive();
+ room.startVideoCall();
+ }))).catch(() => d && console.warn('Already in a call.'))
+ }))), JSX_("hr", null), withProfile && JSX_(dropdowns.tJ, {
+ icon: "sprite-fm-mono icon-my-account",
+ label: l[5868],
+ onClick: () => loadSubPage(`fm/chat/contacts/${contact.u}`)
+ }), JSX_(dropdowns.tJ, {
+ icon: "sprite-fm-mono icon-rename",
+ label: contact.nickname === '' ? l.set_nickname_label : l.edit_nickname_label,
+ onClick: () => this.handleSetNickname(contact.u)
+ }), JSX_("hr", null), JSX_(dropdowns.tJ, {
+ submenu: true,
+ icon: "sprite-fm-mono icon-key",
+ className: "sprite-fm-mono-before icon-arrow-right-before",
+ label: l[6872]
+ }), JSX_("div", {
+ className: "dropdown body white-context-menu submenu"
+ }, (0,utils.p4)(contact) ? JSX_(dropdowns.tJ, {
+ label: l[742],
+ onClick: () => this.close(() => (0,utils.U_)(contact))
+ }) : JSX_(dropdowns.tJ, {
+ label: l[1960],
+ onClick: () => this.close(() => (0,utils.qH)(contact))
+ })), JSX_("div", {
+ className: "dropdown-credentials"
+ }, (0,utils.ym)(contact.u)), JSX_("hr", null), JSX_(dropdowns.tJ, {
+ icon: "sprite-fm-mono icon-disable",
+ label: l[1001],
+ disabled: !!contact.b,
+ className: "",
+ onClick: () => this.close(() => fmremove(contact.u))
+ }));
+ }
+ return JSX_(REaCt().Fragment, null, JSX_(dropdowns.tJ, {
+ icon: "sprite-fm-mono icon-disabled-filled",
+ label: l[71],
+ onClick: () => this.handleAddContact(contact.u)
+ }), JSX_(dropdowns.tJ, {
+ icon: "sprite-fm-mono icon-rename",
+ label: contact.nickname === '' ? l.set_nickname_label : l.edit_nickname_label,
+ onClick: () => this.handleSetNickname(contact.u)
+ }));
+ }
+}
+;// ./js/ui/jsx/fm/nodes/columns/columnContactButtons.jsx
+
+
+
+
+
+
+
+class ColumnContactButtons extends genericNodePropsComponent.B {
+ render() {
+ const {
+ nodeAdapter
+ } = this.props;
+ const {
+ node,
+ selected
+ } = nodeAdapter.props;
+ const handle = node.h;
+ return JSX_("td", {
+ megatype: ColumnContactButtons.megatype,
+ className: ColumnContactButtons.megatype
+ }, JSX_("div", {
+ className: "contact-item"
+ }, JSX_("div", {
+ className: "contact-item-controls"
+ }, JSX_(buttons.$, {
+ className: "mega-button action simpletip",
+ icon: "sprite-fm-mono icon-phone",
+ attrs: {
+ 'data-simpletip': !megaChat.hasSupportForCalls ? l.unsupported_browser_audio : l[5896]
+ },
+ disabled: !navigator.onLine || !megaChat.hasSupportForCalls,
+ onClick: () => M.isInvalidUserStatus() || (0,meetings_utils.dQ)().then(() => megaChat.createAndShowPrivateRoom(handle).then(room => {
+ room.setActive();
+ room.startAudioCall();
+ })).catch(() => d && console.warn('Already in a call.'))
+ }), JSX_(buttons.$, {
+ className: "mega-button action simpletip",
+ icon: "sprite-fm-mono icon-chat",
+ attrs: {
+ 'data-simpletip': l[8632]
+ },
+ onClick: () => {
+ loadSubPage(`fm/chat/p/${handle}`);
+ megaChat.trigger(conversations.qY.NAV_RENDER_VIEW, conversations.Vw.CHATS);
+ }
+ }), JSX_(buttons.$, {
+ className: "mega-button action simpletip",
+ icon: "sprite-fm-mono icon-send-files",
+ attrs: {
+ 'data-simpletip': l[6834]
+ },
+ onClick: () => M.isInvalidUserStatus() || megaChat.openChatAndSendFilesDialog(handle)
+ }), JSX_(buttons.$, {
+ ref: node => {
+ this.props.onContextMenuRef(handle, node);
+ },
+ className: "mega-button action contact-more",
+ icon: "sprite-fm-mono icon-options"
+ }, JSX_(dropdowns.ms, {
+ className: "context",
+ noArrow: true,
+ positionMy: "left bottom",
+ positionAt: "right bottom",
+ positionLeft: this.props.contextMenuPosition || null,
+ horizOffset: 4,
+ onActiveChange: opened => {
+ this.props.onActiveChange(opened);
+ }
+ }, JSX_(ContextMenu, {
+ contact: node,
+ selected,
+ withProfile: true
+ }))))));
+ }
+}
+ColumnContactButtons.sortable = false;
+ColumnContactButtons.id = "grid-url-header-nw";
+ColumnContactButtons.label = "";
+ColumnContactButtons.megatype = "grid-url-header-nw";
+// EXTERNAL MODULE: ./js/chat/ui/updateObserver.jsx
+const updateObserver = REQ_(4372);
+;// ./js/chat/ui/contactsPanel/contactList.jsx
+
+
+
+
+
+
+
+
+
+
+class ContactList extends mixins.w9 {
+ constructor(props) {
+ super(props);
+ this.domRef = REaCt().createRef();
+ this.contextMenuRefs = [];
+ this.state = {
+ selected: [],
+ searchValue: null,
+ interactions: {},
+ contextMenuPosition: null
+ };
+ this.onSelected = this.onSelected.bind(this);
+ this.onHighlighted = this.onHighlighted.bind(this);
+ this.onExpand = this.onExpand.bind(this);
+ this.onAttachClicked = this.onAttachClicked.bind(this);
+ this.getLastInteractions = this.getLastInteractions.bind(this);
+ }
+ getLastInteractions() {
+ const {
+ contacts
+ } = this.props;
+ const promises = [];
+ const push = handle => {
+ promises.push(Promise.resolve(getLastInteractionWith(handle, true, true)).then(ts => [ts, handle]));
+ };
+ for (const handle in contacts) {
+ if (contacts[handle].c === 1) {
+ push(handle);
+ }
+ }
+ Promise.allSettled(promises).then(res => {
+ if (this.isMounted()) {
+ const interactions = {};
+ for (let i = res.length; i--;) {
+ if (res[i].status !== 'fulfilled') {
+ if (d && res[i].reason !== false) {
+ console.warn('getLastInteractions', res[i].reason);
+ }
+ } else {
+ const [ts, u] = res[i].value;
+ const [type, time] = ts.split(':');
+ interactions[u] = {
+ u,
+ type,
+ time
+ };
+ }
+ }
+ this.setState({
+ interactions
+ });
+ }
+ }).catch(ex => {
+ console.error("Failed to handle last interactions!", ex);
+ });
+ }
+ handleContextMenu(ev, handle) {
+ ev.preventDefault();
+ ev.persist();
+ if (this.state.selected.length > 1) {
+ return null;
+ }
+ const $$REF = this.contextMenuRefs[handle];
+ if ($$REF && $$REF.isMounted()) {
+ let _$$REF$domRef;
+ const refNodePosition = ((_$$REF$domRef = $$REF.domRef) == null ? void 0 : _$$REF$domRef.current) && $$REF.domRef.current.getBoundingClientRect().x;
+ this.setState({
+ contextMenuPosition: ev.clientX > refNodePosition ? null : ev.clientX
+ }, () => $$REF.onClick(ev));
+ }
+ }
+ onSelected(handle) {
+ this.setState({
+ 'selected': handle
+ });
+ }
+ onHighlighted(handle) {
+ this.setState({
+ 'highlighted': handle
+ });
+ }
+ onExpand(handle) {
+ loadSubPage(`/fm/chat/contacts/${ handle}`);
+ }
+ onAttachClicked() {
+ if (this.state.selected[0]) {
+ this.onExpand(this.state.selected[0]);
+ }
+ }
+ componentDidMount() {
+ super.componentDidMount();
+ this.getLastInteractions();
+ }
+ render() {
+ const {
+ contacts
+ } = this.props;
+ if (contacts && contacts.length > 1) {
+ return JSX_("div", {
+ ref: this.domRef,
+ className: "contacts-list"
+ }, JSX_(fmView.A, {
+ dataSource: contacts,
+ customFilterFn: r => {
+ return r.c === 1;
+ },
+ currentlyViewedEntry: "contacts",
+ onSelected: this.onSelected,
+ onHighlighted: this.onHighlighted,
+ searchValue: this.state.searchValue,
+ onExpand: this.onExpand,
+ onAttachClicked: this.onAttachClicked,
+ viewMode: 0,
+ currentdirid: "contacts",
+ megaListItemHeight: 59,
+ headerContainerClassName: "contacts-table contacts-table-head",
+ containerClassName: "contacts-table contacts-table-results",
+ onContextMenu: (ev, handle) => this.handleContextMenu(ev, handle),
+ listAdapterColumns: [ColumnContactName, ColumnContactStatus, [ColumnContactLastInteraction, {
+ interactions: this.state.interactions
+ }], [ColumnContactVerifiedStatus, {
+ contacts
+ }], [ColumnContactButtons, {
+ onContextMenuRef: (handle, node) => {
+ this.contextMenuRefs[handle] = node;
+ },
+ onActiveChange: opened => {
+ if (!opened) {
+ this.setState({
+ contextMenuPosition: null
+ });
+ }
+ },
+ contextMenuPosition: this.state.contextMenuPosition
+ }]],
+ initialSortBy: ['status', 'asc'],
+ fmConfigSortEnabled: true,
+ fmConfigSortId: "contacts",
+ NilComponent: JSX_(Nil, {
+ title: l[5737]
+ })
+ }));
+ }
+ return JSX_(Nil, {
+ title: l[5737]
+ });
+ }
+}
+ContactList.updateListener = 'getLastInteractions';
+ContactList.updateInterval = 6e4;
+ const contactList = (0,mixins.Zz)(updateObserver.Y)(ContactList);
+;// ./js/ui/jsx/fm/nodes/columns/columnContactRequestsEmail.jsx
+
+
+
+class ColumnContactRequestsEmail extends mixins.w9 {
+ constructor(...args) {
+ super(...args);
+ this.domRef = REaCt().createRef();
+ }
+ static get label() {
+ return l[95];
+ }
+ render() {
+ const {
+ nodeAdapter,
+ currView
+ } = this.props;
+ const {
+ node
+ } = nodeAdapter.props;
+ return JSX_("td", {
+ ref: this.domRef
+ }, currView && currView === 'opc' ? JSX_("span", null, JSX_("i", {
+ className: "sprite-fm-uni icon-send-requests"
+ })) : JSX_(ui_utils.P9, null, useravatar.contact(node.m, 'box-avatar')), JSX_("div", {
+ className: "contact-item"
+ }, JSX_("div", {
+ className: "contact-item-user"
+ }, node.m)), JSX_("div", {
+ className: "clear"
+ }));
+ }
+}
+ColumnContactRequestsEmail.sortable = true;
+ColumnContactRequestsEmail.id = "email";
+ColumnContactRequestsEmail.megatype = "email";
+;// ./js/ui/jsx/fm/nodes/columns/columnContactRequestsTs.jsx
+
+
+class ColumnContactRequestsTs extends mixins.w9 {
+ constructor(...args) {
+ super(...args);
+ this.domRef = REaCt().createRef();
+ }
+ static get label() {
+ return l[19506];
+ }
+ render() {
+ const {
+ nodeAdapter
+ } = this.props;
+ const {
+ node
+ } = nodeAdapter.props;
+ let timestamp = node.rts || node.ts;
+ if (timestamp) {
+ timestamp = time2last(timestamp);
+ } else {
+ timestamp = node.dts ? l[6112] : "";
+ }
+ return JSX_("td", {
+ ref: this.domRef
+ }, JSX_("div", {
+ className: "contact-item"
+ }, JSX_("div", {
+ className: "contact-item-time"
+ }, timestamp)), JSX_("div", {
+ className: "clear"
+ }));
+ }
+}
+ColumnContactRequestsTs.sortable = true;
+ColumnContactRequestsTs.id = "ts";
+ColumnContactRequestsTs.megatype = "ts";
+;// ./js/ui/jsx/fm/nodes/columns/columnContactRequestsRcvdBtns.jsx
+
+
+
+class ColumnContactRequestsRcvdBtns extends mixins.w9 {
+ constructor(...args) {
+ super(...args);
+ this.domRef = REaCt().createRef();
+ }
+ render() {
+ const {
+ nodeAdapter
+ } = this.props;
+ const {
+ node
+ } = nodeAdapter.props;
+ return JSX_("td", {
+ ref: this.domRef,
+ megatype: ColumnContactRequestsRcvdBtns.megatype,
+ className: ColumnContactRequestsRcvdBtns.megatype
+ }, JSX_("div", {
+ className: "contact-item-controls"
+ }, JSX_(buttons.$, {
+ className: "mega-button action contact-reject",
+ icon: "sprite-fm-mono icon-close-component",
+ label: l[20981],
+ onClick: () => this.props.onReject(node.p)
+ }), JSX_(buttons.$, {
+ className: "mega-button action contact-block",
+ icon: "sprite-fm-mono icon-disable",
+ label: l[20980],
+ onClick: () => this.props.onBlock(node.p)
+ }), JSX_(buttons.$, {
+ className: "mega-button action contact-accept",
+ icon: "sprite-fm-mono icon-check",
+ label: l[5856],
+ onClick: () => this.props.onAccept(node.p)
+ })));
+ }
+}
+ColumnContactRequestsRcvdBtns.sortable = true;
+ColumnContactRequestsRcvdBtns.id = "grid-url-header-nw";
+ColumnContactRequestsRcvdBtns.label = "";
+ColumnContactRequestsRcvdBtns.megatype = "grid-url-header-nw contact-controls-container";
+;// ./js/chat/ui/contactsPanel/receivedRequests.jsx
+
+
+
+
+
+
+
+const ReceivedRequests = ({
+ received
+}) => {
+ const nameOrEmailColumn = received.mixed ? ColumnContactName : [ColumnContactRequestsEmail, {
+ currView: "ipc"
+ }];
+ return JSX_("div", {
+ className: "contacts-list"
+ }, JSX_(fmView.A, {
+ sortFoldersFirst: false,
+ dataSource: received.data,
+ customFilterFn: r => {
+ return !r.dts;
+ },
+ currentlyViewedEntry: "ipc",
+ onSelected: nop,
+ onHighlighted: nop,
+ onExpand: nop,
+ onAttachClicked: nop,
+ viewMode: 0,
+ currentdirid: "ipc",
+ megaListItemHeight: 59,
+ headerContainerClassName: "contacts-table requests-table contacts-table-head",
+ containerClassName: "contacts-table requests-table contacts-table-results",
+ listAdapterColumns: [nameOrEmailColumn, [ColumnContactRequestsTs, {
+ label: l[19505]
+ }], [ColumnContactRequestsRcvdBtns, {
+ onReject: handle => {
+ M.denyPendingContactRequest(handle).catch(dump);
+ },
+ onBlock: handle => {
+ M.ignorePendingContactRequest(handle).catch(dump);
+ },
+ onAccept: handle => {
+ M.acceptPendingContactRequest(handle).catch(dump);
+ }
+ }]],
+ keyProp: "p",
+ nodeAdapterProps: {
+ 'className': node => {
+ return `
+ ${node.dts || node.s && node.s === 3 ? 'deleted' : ''}
+ ${node.s && node.s === 1 ? 'ignored' : ''}
+ `;
+ }
+ },
+ NilComponent: () => {
+ return JSX_(Nil, {
+ title: l[6196]
+ });
+ },
+ initialSortBy: ['email', 'asc'],
+ fmConfigSortEnabled: true,
+ fmConfigSortId: "ipc"
+ }));
+};
+ const receivedRequests = ReceivedRequests;
+;// ./js/ui/jsx/fm/nodes/columns/columnContactRequestsSentBtns.jsx
+
+
+
+class ColumnContactRequestsSentBtns extends mixins.w9 {
+ constructor(...args) {
+ super(...args);
+ this.domRef = REaCt().createRef();
+ this.reinviteAllowed = rts => {
+ const UTC_DATE_NOW = Math.floor(Date.now() / 1000);
+ return UTC_DATE_NOW > rts + 1209600;
+ };
+ }
+ render() {
+ const {
+ nodeAdapter
+ } = this.props;
+ const {
+ node
+ } = nodeAdapter.props;
+ return JSX_("td", {
+ ref: this.domRef,
+ megatype: ColumnContactRequestsSentBtns.megatype,
+ className: ColumnContactRequestsSentBtns.megatype
+ }, JSX_("div", {
+ className: "contact-item-controls contact-request-sent"
+ }, !node.dts && this.reinviteAllowed(node.rts) && JSX_(buttons.$, {
+ className: "mega-button action",
+ icon: "sprite-fm-mono icon-rewind",
+ label: l[5861],
+ onClick: () => this.props.onReinvite(node.m)
+ }), !node.dts && JSX_(buttons.$, {
+ className: "mega-button action contact-reject",
+ icon: "sprite-fm-mono icon-close-component",
+ label: l.msg_dlg_cancel,
+ onClick: () => this.props.onReject(node.m)
+ })));
+ }
+}
+ColumnContactRequestsSentBtns.sortable = true;
+ColumnContactRequestsSentBtns.id = "grid-url-header-nw";
+ColumnContactRequestsSentBtns.label = "";
+ColumnContactRequestsSentBtns.megatype = "grid-url-header-nw contact-controls-container";
+;// ./js/ui/jsx/fm/nodes/columns/columnContactRequestsRts.jsx
+
+
+class ColumnContactRequestsRts extends ColumnContactRequestsTs {
+ static get label() {
+ return l[19506];
+ }
+}
+ColumnContactRequestsRts.sortable = true;
+ColumnContactRequestsRts.id = "rts";
+ColumnContactRequestsRts.megatype = "rts";
+;// ./js/chat/ui/contactsPanel/sentRequests.jsx
+
+
+
+
+
+
+const SentRequests = ({
+ sent
+}) => {
+ return JSX_("div", {
+ className: "contacts-list"
+ }, JSX_(fmView.A, {
+ sortFoldersFirst: false,
+ dataSource: sent,
+ currentlyViewedEntry: "opc",
+ onSelected: nop,
+ onHighlighted: nop,
+ onExpand: nop,
+ onAttachClicked: nop,
+ viewMode: 0,
+ currentdirid: "opc",
+ megaListItemHeight: 59,
+ headerContainerClassName: "contacts-table requests-table contacts-table-head",
+ containerClassName: "contacts-table requests-table contacts-table-results",
+ listAdapterColumns: [[ColumnContactRequestsEmail, {
+ currView: "opc"
+ }], ColumnContactRequestsRts, [ColumnContactRequestsSentBtns, {
+ onReject: email => {
+ M.cancelPendingContactRequest(email).catch(ex => {
+ if (ex === EARGS) {
+ msgDialog('info', '', 'This pending contact is already deleted.');
+ } else {
+ tell(ex);
+ }
+ });
+ },
+ onReinvite: email => {
+ M.reinvitePendingContactRequest(email).then(() => contactsInfoDialog(l[19126], email, l[19127])).catch(tell);
+ }
+ }]],
+ NilComponent: () => {
+ return JSX_(Nil, {
+ title: l[6196]
+ });
+ },
+ listAdapterOpts: {
+ 'className': node => node.dts && ' disabled'
+ },
+ keyProp: "p",
+ initialSortBy: ['email', 'asc'],
+ fmConfigSortEnabled: true,
+ fmConfigSortMap: {
+ 'rts': 'rTimeStamp'
+ },
+ fmConfigSortId: "opc"
+ }));
+};
+ const sentRequests = SentRequests;
+// EXTERNAL MODULE: ./js/ui/jsx/fm/nodes/columns/columnFavIcon.jsx
+const columnFavIcon = REQ_(6794);
+;// ./js/ui/jsx/fm/nodes/columns/columnSharedFolderName.jsx
+
+
+class ColumnSharedFolderName extends genericNodePropsComponent.B {
+ static get label() {
+ return l[86];
+ }
+ render() {
+ const {
+ nodeAdapter
+ } = this.props;
+ const {
+ node
+ } = nodeAdapter.props;
+ return JSX_("td", {
+ megatype: ColumnSharedFolderName.megatype,
+ className: ColumnSharedFolderName.megatype
+ }, JSX_("div", {
+ className: "item-type-icon-90 icon-folder-incoming-90 sprite-fm-uni-after icon-warning-after"
+ }), JSX_("div", {
+ className: "shared-folder-info-block"
+ }, JSX_("div", {
+ className: "shared-folder-name"
+ }, missingkeys[node.h] ? l[8686] : nodeAdapter.nodeProps.title), JSX_("div", {
+ className: "shared-folder-info"
+ }, fm_contains(node.tf, node.td))));
+ }
+}
+ColumnSharedFolderName.sortable = true;
+ColumnSharedFolderName.id = "name";
+ColumnSharedFolderName.megatype = "name";
+;// ./js/ui/jsx/fm/nodes/columns/columnSharedFolderAccess.jsx
+
+
+class ColumnSharedFolderAccess extends genericNodePropsComponent.B {
+ static get label() {
+ return l[5906];
+ }
+ render() {
+ const {
+ nodeAdapter
+ } = this.props;
+ return JSX_("td", {
+ megatype: ColumnSharedFolderAccess.megatype,
+ className: ColumnSharedFolderAccess.megatype
+ }, JSX_("div", {
+ className: "shared-folder-access"
+ }, JSX_("i", {
+ className: `
+ sprite-fm-mono
+ ${nodeAdapter.nodeProps.incomingShareData.accessIcon}
+ `
+ }), JSX_("span", null, nodeAdapter.nodeProps.incomingShareData.accessLabel)));
+ }
+}
+ColumnSharedFolderAccess.sortable = true;
+ColumnSharedFolderAccess.id = 'access';
+ColumnSharedFolderAccess.megatype = 'access';
+;// ./js/ui/jsx/fm/nodes/columns/columnSharedFolderButtons.jsx
+
+
+
+class ColumnSharedFolderButtons extends genericNodePropsComponent.B {
+ render() {
+ const {
+ nodeAdapter
+ } = this.props;
+ const {
+ node
+ } = nodeAdapter.props;
+ const handle = node.h;
+ return JSX_("td", {
+ megatype: ColumnSharedFolderButtons.megatype,
+ className: ColumnSharedFolderButtons.megatype
+ }, JSX_("div", {
+ className: "contact-item"
+ }, JSX_("div", {
+ className: "contact-item-controls"
+ }, JSX_(buttons.$, {
+ className: "mega-button action contact-more",
+ icon: "sprite-fm-mono icon-options",
+ onClick: (button, e) => {
+ e.persist();
+ $.selected = [handle];
+ e.preventDefault();
+ e.stopPropagation();
+ e.delegateTarget = $(e.target).parents('td')[0];
+ e.currentTarget = $(e.target).parents('tr');
+ if (!$(e.target).hasClass('active')) {
+ M.contextMenuUI(e, 1);
+ $(this).addClass('active');
+ } else {
+ $.hideContextMenu();
+ $(e.target).removeClass('active');
+ }
+ }
+ }))));
+ }
+}
+ColumnSharedFolderButtons.sortable = true;
+ColumnSharedFolderButtons.id = "grid-url-header-nw";
+ColumnSharedFolderButtons.label = "";
+ColumnSharedFolderButtons.megatype = "grid-url-header-nw";
+// EXTERNAL MODULE: ./js/chat/ui/link.jsx
+const ui_link = REQ_(4649);
+;// ./js/chat/ui/contactsPanel/contactProfile.jsx
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+class ContactProfile extends mixins.w9 {
+ constructor(...args) {
+ super(...args);
+ this.domRef = REaCt().createRef();
+ this.state = {
+ selected: [],
+ loading: true
+ };
+ this.onAttachClicked = () => {
+ const {
+ selected
+ } = this.state;
+ if (selected[0]) {
+ this.onExpand(selected[0]);
+ }
+ };
+ this.onExpand = handle => loadSubPage(`fm/${handle}`);
+ this.Breadcrumb = () => {
+ const {
+ handle
+ } = this.props;
+ return JSX_("div", {
+ className: "profile-breadcrumb"
+ }, JSX_("ul", null, JSX_("li", null, JSX_(ui_link.A, {
+ to: "/fm/chat/contacts"
+ }, utils.d_.CONTACTS), JSX_("i", {
+ className: "sprite-fm-mono icon-arrow-right"
+ })), JSX_("li", null, JSX_(ui_utils.zT, null, M.getNameByHandle(handle)))));
+ };
+ this.Credentials = () => {
+ const {
+ handle
+ } = this.props;
+ const contact = M.u[handle];
+ if (handle && contact && contact.c === 1) {
+ const IS_VERIFIED = (0,utils.p4)(contact);
+ return JSX_("div", {
+ className: "profile-credentials"
+ }, JSX_("span", {
+ className: "credentials-head"
+ }, l[6872]), JSX_("div", {
+ className: "credentials-fingerprints"
+ }, (0,utils.ym)(handle)), JSX_("button", {
+ className: `
+ mega-button
+ small
+ ${IS_VERIFIED ? '' : 'positive'}
+ `,
+ onClick: () => (IS_VERIFIED ? utils.U_ : utils.qH)(contact)
+ }, IS_VERIFIED ? l[742] : l.verify_credentials));
+ }
+ return null;
+ };
+ this.handleContextMenu = (e, handle) => {
+ e.persist();
+ e.preventDefault();
+ e.stopPropagation();
+ e.delegateTarget = e.target.tagName === "TR" ? e.target : $(e.target).parents('tr')[0];
+ e.currentTarget = $(e.delegateTarget);
+ $.selected = [handle];
+ M.contextMenuUI(e, 1);
+ };
+ }
+ UNSAFE_componentWillMount() {
+ if (super.UNSAFE_componentWillMount) {
+ super.UNSAFE_componentWillMount();
+ }
+ const {
+ handle
+ } = this.props;
+ if (handle) {
+ const contact = M.u[handle];
+ if (contact) {
+ this._listener = contact.addChangeListener(() => {
+ if (contact && contact.c === 1) {
+ this.safeForceUpdate();
+ } else {
+ loadSubPage("/fm/chat/contacts");
+ return 0xDEAD;
+ }
+ });
+ }
+ }
+ }
+ componentWillUnmount() {
+ super.componentWillUnmount();
+ if (this._listener) {
+ const {
+ handle
+ } = this.props;
+ const contact = M.u[handle];
+ contact.removeChangeListener(this._listener);
+ }
+ }
+ componentDidMount() {
+ super.componentDidMount();
+ dbfetch.geta(Object.keys(M.c.shares || {}), new MegaPromise()).finally(() => {
+ if (this.isMounted()) {
+ this.setState({
+ 'loading': false
+ });
+ }
+ });
+ }
+ getSharedFoldersView() {
+ return this.state.loading ? null : JSX_(fmView.A, {
+ currentlyViewedEntry: this.props.handle,
+ onSelected: handle => this.setState({
+ selected: handle
+ }),
+ onHighlighted: nop,
+ searchValue: this.state.searchValue,
+ onExpand: this.onExpand,
+ onAttachClicked: this.onAttachClicked,
+ viewMode: 0,
+ currentdirid: "shares",
+ megaListItemHeight: 65,
+ headerContainerClassName: "grid-table-header",
+ containerClassName: "grid-table shared-with-me",
+ onContextMenu: (ev, handle) => this.handleContextMenu(ev, handle),
+ listAdapterColumns: [columnFavIcon.$, [ColumnSharedFolderName, {
+ 'label': `${l.shared_folders_from.replace('%NAME', M.getNameByHandle(this.props.handle))}`
+ }], ColumnSharedFolderAccess, ColumnSharedFolderButtons]
+ });
+ }
+ render() {
+ const {
+ handle
+ } = this.props;
+ if (handle) {
+ const contact = M.u[handle];
+ if (!contact || contact.c !== 1) {
+ return JSX_(Nil, {
+ title: l.contact_not_found
+ });
+ }
+ const HAS_RELATIONSHIP = (0,utils.X7)(contact);
+ return JSX_("div", {
+ ref: this.domRef,
+ className: "contacts-profile"
+ }, JSX_(this.Breadcrumb, null), JSX_("div", {
+ className: "profile-content"
+ }, JSX_("div", {
+ className: "profile-head"
+ }, HAS_RELATIONSHIP && JSX_(this.Credentials, null), JSX_(contacts.eu, {
+ contact,
+ className: "profile-photo avatar-wrapper contacts-medium-avatar"
+ }), JSX_("div", {
+ className: "profile-info"
+ }, JSX_("h2", null, JSX_(ui_utils.zT, null, M.getNameByHandle(handle)), JSX_(contacts.i1, {
+ contact
+ })), JSX_("span", null, contact.m)), HAS_RELATIONSHIP && JSX_("div", {
+ className: "profile-controls"
+ }, JSX_(buttons.$, {
+ className: "mega-button round simpletip",
+ icon: "sprite-fm-mono icon-chat-filled",
+ attrs: {
+ 'data-simpletip': l[8632]
+ },
+ onClick: () => {
+ loadSubPage(`fm/chat/p/${handle}`);
+ megaChat.trigger(conversations.qY.NAV_RENDER_VIEW, conversations.Vw.CHATS);
+ }
+ }), JSX_(buttons.$, {
+ className: "mega-button round simpletip",
+ icon: "sprite-fm-mono icon-send-files",
+ attrs: {
+ 'data-simpletip': l[6834]
+ },
+ onClick: () => {
+ if (M.isInvalidUserStatus()) {
+ return;
+ }
+ megaChat.openChatAndSendFilesDialog(handle);
+ }
+ }), JSX_(buttons.$, {
+ className: "mega-button round",
+ icon: "sprite-fm-mono icon-options"
+ }, JSX_(dropdowns.ms, {
+ className: "context",
+ noArrow: true,
+ positionMy: "left bottom",
+ positionAt: "right bottom",
+ horizOffset: 4
+ }, JSX_(ContextMenu, {
+ contact
+ }))))), JSX_("div", {
+ className: "profile-shared-folders"
+ }, this.getSharedFoldersView())));
+ }
+ return null;
+ }
+}
+;// ./js/chat/ui/contactsPanel/contactsPanel.jsx
+
+
+
+
+
+
+
+
+class ContactsPanel extends mixins.w9 {
+ get view() {
+ switch (megaChat.routingSubSection) {
+ case null:
+ return utils.gR.CONTACTS;
+ case "contact":
+ return utils.gR.PROFILE;
+ case "received":
+ return utils.gR.RECEIVED_REQUESTS;
+ case "sent":
+ return utils.gR.SENT_REQUESTS;
+ default:
+ console.error("Shouldn't happen.");
+ return false;
+ }
+ }
+ constructor(props) {
+ super(props);
+ this.domRef = REaCt().createRef();
+ this.requestReceivedListener = null;
+ this.state = {
+ receivedRequestsCount: 0
+ };
+ this.handleToggle = ({
+ keyCode
+ }) => {
+ if (keyCode === 27) {
+ const HAS_DIALOG_OPENED = $.dialog || ['.contact-nickname-dialog', '.fingerprint-dialog', '.context'].some(selector => {
+ const dialog = document.querySelector(selector);
+ return dialog && dialog.offsetHeight > 0;
+ });
+ return HAS_DIALOG_OPENED ? keyCode : loadSubPage('fm/chat');
+ }
+ };
+ this.handleAcceptAllRequests = () => {
+ const {
+ data: received
+ } = this.props.received;
+ const receivedKeys = Object.keys(received || {});
+ if (receivedKeys.length) {
+ for (let i = receivedKeys.length; i--;) {
+ M.acceptPendingContactRequest(receivedKeys[i]).catch(dump);
+ }
+ }
+ };
+ this.renderView = () => {
+ const {
+ contacts,
+ received,
+ sent
+ } = this.props;
+ const {
+ view
+ } = this;
+ switch (view) {
+ case utils.gR.CONTACTS:
+ return JSX_(contactList, {
+ contacts
+ });
+ case utils.gR.PROFILE:
+ return JSX_(ContactProfile, {
+ handle: view === utils.gR.PROFILE && megaChat.routingParams
+ });
+ case utils.gR.RECEIVED_REQUESTS:
+ return JSX_(receivedRequests, {
+ received
+ });
+ case utils.gR.SENT_REQUESTS:
+ return JSX_(sentRequests, {
+ sent
+ });
+ }
+ };
+ this.state.receivedRequestsCount = Object.keys(M.ipc).length;
+ }
+ componentWillUnmount() {
+ super.componentWillUnmount();
+ document.documentElement.removeEventListener(utils.qY.KEYDOWN, this.handleToggle);
+ if (this.requestReceivedListener) {
+ mBroadcaster.removeListener(this.requestReceivedListener);
+ }
+ }
+ componentDidMount() {
+ super.componentDidMount();
+ document.documentElement.addEventListener(utils.qY.KEYDOWN, this.handleToggle);
+ this.requestReceivedListener = mBroadcaster.addListener('fmViewUpdate:ipc', () => this.setState({
+ receivedRequestsCount: Object.keys(M.ipc).length
+ }));
+ }
+ render() {
+ const {
+ view,
+ state
+ } = this;
+ const {
+ receivedRequestsCount
+ } = state;
+ return JSX_("div", {
+ ref: this.domRef,
+ className: "contacts-panel"
+ }, JSX_(navigation, {
+ view,
+ contacts: this.props.contacts,
+ receivedRequestsCount
+ }), view !== utils.gR.PROFILE && JSX_("div", {
+ className: "contacts-actions"
+ }, view === utils.gR.RECEIVED_REQUESTS && receivedRequestsCount > 1 && JSX_("button", {
+ className: "mega-button action",
+ onClick: this.handleAcceptAllRequests
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-check"
+ }), JSX_("span", null, l[19062]))), JSX_("div", {
+ className: "contacts-content"
+ }, this.renderView()));
+ }
+}
+
+ },
+
+ 872
+(_, EXP_, REQ_) {
+
+
+// EXPORTS
+REQ_.d(EXP_, {
+ A: () => FMView
+});
+
+// EXTERNAL MODULE: external "React"
+const external_React_ = REQ_(1594);
+const REaCt = REQ_.n(external_React_);
+// EXTERNAL MODULE: ./js/chat/mixins.js
+const mixins = REQ_(8264);
+// EXTERNAL MODULE: ./node_modules/@babel/runtime/helpers/esm/extends.js
+const esm_extends = REQ_(8168);
+// EXTERNAL MODULE: ./node_modules/@babel/runtime/helpers/esm/applyDecoratedDescriptor.js
+const applyDecoratedDescriptor = REQ_(793);
+// EXTERNAL MODULE: ./js/ui/perfectScrollbar.jsx
+const perfectScrollbar = REQ_(1301);
+;// ./js/ui/jsx/megaList/megaList2.jsx
+
+
+let _dec, _class;
+
+
+
+const MegaList2 = (_dec = (0,mixins.hG)(30, true), _class = class MegaList2 extends mixins.w9 {
+ constructor(props) {
+ super(props);
+ this._calculated = false;
+ this._firstRender = true;
+ this.customIsEventuallyVisible = true;
+ this.requiresUpdateOnResize = true;
+ this.adapterChangedDoRepaint = false;
+ assert(props.listAdapter, 'missing `listAdapter` for MegaList2');
+ assert(props.nodeAdapter, 'missing `nodeAdapter` for MegaList2');
+ assert(props.entries, 'missing `entries` for MegaList2');
+ this.options = {
+ extraRows: 8,
+ batchPages: 0,
+ perfectScrollOptions: {
+ 'handlers': ['click-rail', 'drag-thumb', 'wheel', 'touch'],
+ 'minScrollbarLength': 20
+ }
+ };
+ this.onPsUserScroll = this.onPsUserScroll.bind(this);
+ this.thumbsLoadingHandlers = new MapSet();
+ this.thumbsThatRequireLoading = new MapSet();
+ this.requestThumbnailCb = this.requestThumbnailCb.bind(this);
+ }
+ specShouldComponentUpdate(nextProps) {
+ let invalidate = false;
+ if (nextProps.listAdapter.prototype.constructor.name !== this.props.listAdapter.prototype.constructor.name || nextProps.entries !== this.props.entries || nextProps.viewMode !== this.props.viewMode) {
+ invalidate = true;
+ }
+ if (nextProps.sortBy !== this.props.sortBy || nextProps.currentlyViewedEntry !== this.props.currentlyViewedEntry) {
+ invalidate = true;
+ this.domRef.scrollToY(0);
+ }
+ if (invalidate) {
+ this._calculated = false;
+ this.adapterChangedDoRepaint = true;
+ return true;
+ }
+ return null;
+ }
+ _recalculate() {
+ if (this._calculated) {
+ return this._calculated;
+ }
+ const calculated = this._calculated = Object.create(null);
+ lazy(calculated, 'scrollWidth', () => {
+ return this.domRef.getClientWidth();
+ });
+ lazy(calculated, 'scrollHeight', () => this.domRef.getClientHeight() - calculated.headerHeight);
+ lazy(calculated, 'itemWidth', () => {
+ if (this.props.listAdapter.itemWidth === false) {
+ return calculated.scrollWidth;
+ }
+ return this.props.listAdapter.itemWidth;
+ });
+ lazy(calculated, 'itemHeight', () => {
+ return this.props.itemHeight || this.props.listAdapter.itemHeight;
+ });
+ lazy(calculated, 'headerHeight', () => this.props.headerHeight || 0);
+ lazy(calculated, 'contentWidth', () => {
+ const contentWidth = this.domRef.getContentWidth();
+ if (contentWidth) {
+ return contentWidth;
+ }
+ return calculated.itemWidth;
+ });
+ lazy(calculated, 'itemsPerRow', () => {
+ if (this.props.listAdapter.itemsPerRow) {
+ return this.props.listAdapter.itemsPerRow;
+ }
+ return Math.max(1, Math.floor(calculated.contentWidth / calculated.itemWidth));
+ });
+ lazy(calculated, 'contentHeight', () => {
+ return Math.ceil(this.props.entries.length / calculated.itemsPerRow) * calculated.itemHeight;
+ });
+ lazy(calculated, 'scrollLeft', () => {
+ return this.domRef.getScrollPositionX();
+ });
+ lazy(calculated, 'scrollTop', () => {
+ if (this.adapterChangedDoRepaint) {
+ return 0;
+ }
+ return this.domRef.getScrollPositionY();
+ });
+ lazy(calculated, 'scrolledPercentX', () => {
+ return 100 / calculated.scrollWidth * calculated.scrollLeft;
+ });
+ lazy(calculated, 'scrolledPercentY', () => {
+ return 100 / calculated.scrollHeight * calculated.scrollTop;
+ });
+ lazy(calculated, 'isAtTop', () => {
+ return calculated.scrollTop === 0;
+ });
+ lazy(calculated, 'isAtBottom', () => {
+ return calculated.scrollTop === calculated.scrollHeight;
+ });
+ lazy(calculated, 'itemsPerPage', () => {
+ return Math.ceil(calculated.scrollHeight / calculated.itemHeight) * calculated.itemsPerRow;
+ });
+ lazy(calculated, 'visibleFirstItemNum', () => {
+ let value = 0;
+ value = Math.floor(Math.floor(calculated.scrollTop / calculated.itemHeight) * calculated.itemsPerRow);
+ if (value > 0) {
+ value = Math.max(0, value - this.options.extraRows * calculated.itemsPerRow);
+ }
+ return value;
+ });
+ lazy(calculated, 'visibleLastItemNum', () => {
+ let value = Math.min(this.props.entries.length, Math.ceil(Math.ceil(calculated.scrollTop / calculated.itemHeight) * calculated.itemsPerRow + calculated.itemsPerPage));
+ if (value < this.props.entries.length) {
+ value = Math.min(this.props.entries.length, value + this.options.extraRows * calculated.itemsPerRow);
+ }
+ return value;
+ });
+ if (this.options.batchPages > 0) {
+ const perPage = calculated.itemsPerPage;
+ const visibleF = calculated.visibleFirstItemNum;
+ calculated.visibleFirstItemNum = Math.max(0, ((visibleF - visibleF % perPage) / perPage - 1 - this.options.batchPages) * perPage);
+ const visibleL = calculated.visibleLastItemNum;
+ calculated.visibleLastItemNum = Math.min(this.props.entries.length, ((visibleL - visibleL % perPage) / perPage + 1 + this.options.batchPages) * perPage);
+ }
+ Object.defineProperty(M, 'rmItemsInView', {
+ get: () => {
+ const c = this.domRef && this._calculated || !1;
+ return c.itemsPerPage + c.itemsPerRow | 0;
+ },
+ configurable: true
+ });
+ }
+ _contentUpdated() {
+ this._calculated = false;
+ this._recalculate();
+ if (this.listContent && this._lastContentHeight !== this._calculated.contentHeight) {
+ this._lastContentHeight = this._calculated.contentHeight;
+ this.listContent.style.height = `${this._calculated.contentHeight }px`;
+ }
+ if (this.domRef && this._calculated.scrollHeight + this._calculated.scrollTop > this._calculated.contentHeight) {
+ this.domRef.scrollToY(this._calculated.contentHeight - this._calculated.scrollHeight);
+ }
+ if (this.listAdapterInstance && this.listAdapterInstance.onContentUpdated) {
+ this.listAdapterInstance.onContentUpdated();
+ }
+ }
+ _getCalcsThatTriggerChange() {
+ return [this.props.entries.length, this._calculated.scrollHeight, this._calculated.itemWidth, this._calculated.itemHeight, this._calculated.contentWidth, this._calculated.itemsPerRow, this._calculated.contentHeight, this._calculated.visibleFirstItemNum, this._calculated.visibleLastItemNum];
+ }
+ indexOfEntry(nodeHandle, prop) {
+ prop = prop || 'h';
+ for (let i = 0; i < this.props.entries.length; i++) {
+ const entry = this.props.entries[i];
+ if (entry[prop] === nodeHandle) {
+ return i;
+ }
+ }
+ return -1;
+ }
+ scrollToItem(nodeHandle) {
+ const elementIndex = this.indexOfEntry(nodeHandle);
+ if (elementIndex === -1) {
+ return false;
+ }
+ let shouldScroll = false;
+ const itemOffsetTop = Math.floor(elementIndex / this._calculated.itemsPerRow) * this._calculated.itemHeight;
+ const itemOffsetTopPlusHeight = itemOffsetTop + this._calculated.itemHeight;
+ if (itemOffsetTop < this._calculated.scrollTop || itemOffsetTopPlusHeight > this._calculated.scrollTop + this._calculated.scrollHeight) {
+ shouldScroll = true;
+ }
+ if (shouldScroll) {
+ this.domRef.scrollToY(itemOffsetTop);
+ onIdle(() => {
+ this.safeForceUpdate();
+ });
+ return true;
+ }
+ return false;
+ }
+ onPsUserScroll() {
+ if (!this.isMounted()) {
+ return;
+ }
+ const oldCalc = JSON.stringify(this._getCalcsThatTriggerChange());
+ this._contentUpdated();
+ const newCalc = JSON.stringify(this._getCalcsThatTriggerChange());
+ if (oldCalc !== newCalc) {
+ this.forceUpdate();
+ }
+ }
+ onResizeDoUpdate() {
+ super.onResizeDoUpdate();
+ this._contentUpdated();
+ }
+ componentDidMount() {
+ super.componentDidMount();
+ this._contentUpdated();
+ this.forceUpdate();
+ }
+ componentDidUpdate() {
+ super.componentDidUpdate();
+ this._contentUpdated();
+ if (this.adapterChangedDoRepaint) {
+ this.adapterChangedDoRepaint = false;
+ this._calculated = false;
+ this._recalculate();
+ }
+ if (this.thumbsThatRequireLoading.size) {
+ delay('chat:mega-list2:thumb-loader', () => this.enqueueThumbnailRetrieval(), 20);
+ }
+ this._firstRender = this._firstRender || this.props.viewmode !== M.viewmode;
+ if (this._firstRender && this.domRef) {
+ let _this$domRef;
+ this._firstRender = false;
+ Ps.update((_this$domRef = this.domRef) == null ? void 0 : _this$domRef.$Node);
+ }
+ }
+ enqueueThumbnailRetrieval() {
+ const loaders = new Map(this.thumbsLoadingHandlers);
+ const nodes = new Map(this.thumbsThatRequireLoading);
+ const pending = [];
+ const defaultCallback = (n, src, id) => {
+ let img = document.getElementById(id || `chat_${n.h}`);
+ if (img && (img = img.querySelector('img'))) {
+ let _img$parentNode$paren;
+ img.src = src;
+ (_img$parentNode$paren = img.parentNode.parentNode) == null || _img$parentNode$paren.classList.add('thumb');
+ }
+ };
+ const setSource = n => {
+ if (thumbnails.has(n.fa)) {
+ const src = thumbnails.get(n.fa);
+ const batch = [...nodes.get(n.fa)];
+ for (let i = batch.length; i--;) {
+ const n = batch[i];
+ const handlers = [...loaders.get(n.h)];
+ for (let i = handlers.length; i--;) {
+ let callback = handlers[i];
+ if (typeof callback !== 'function') {
+ callback = defaultCallback;
+ }
+ tryCatch(() => {
+ const id = callback(n, src);
+ if (id) {
+ defaultCallback(n, src, id);
+ }
+ })();
+ }
+ }
+ return true;
+ }
+ };
+ for (const [, [n]] of nodes) {
+ if (!setSource(n)) {
+ pending.push(n);
+ }
+ }
+ if (pending.length) {
+ fm_thumbnails('standalone', pending, setSource);
+ }
+ this.thumbsLoadingHandlers.clear();
+ this.thumbsThatRequireLoading.clear();
+ }
+ requestThumbnailCb(node, immediate, callback) {
+ if (node && node.fa) {
+ if (typeof immediate === 'function') {
+ callback = immediate;
+ immediate = 0;
+ }
+ node.seen = node.seen || -7;
+ this.thumbsLoadingHandlers.set(node.h, callback);
+ this.thumbsThatRequireLoading.set(node.fa, node);
+ delay('chat:mega-list2:thumb-loader', () => this.enqueueThumbnailRetrieval(), immediate || 480);
+ }
+ }
+ render() {
+ if (this.isMounted() && !this._calculated) {
+ this._recalculate();
+ }
+ const {
+ listAdapter,
+ listAdapterOpts,
+ entries,
+ nodeAdapterProps,
+ viewMode,
+ header,
+ onContextMenu
+ } = this.props;
+ const className = `${listAdapter.containerClassName } megaList megaList2`;
+ const first = this._calculated.visibleFirstItemNum;
+ const last = this._calculated.visibleLastItemNum;
+ const nodes = [];
+ for (let i = first; i < last; i++) {
+ const node = entries[i];
+ nodes.push(JSX_(this.props.nodeAdapter, (0,esm_extends.A)({
+ key: `${i }_${ node[this.props.keyProp]}`,
+ h: node[this.props.keyProp],
+ index: i,
+ megaList: this,
+ listAdapter,
+ node,
+ calculated: this._calculated,
+ listAdapterOpts,
+ onContextMenu,
+ selected: this.props.selected ? this.props.selected.indexOf(node[this.props.keyProp]) > -1 : false,
+ highlighted: this.props.highlighted ? this.props.highlighted.indexOf(node[this.props.keyProp]) > -1 : false,
+ requestThumbnailCb: this.requestThumbnailCb,
+ keyProp: this.props.keyProp || 'h'
+ }, nodeAdapterProps)));
+ }
+ const listAdapterName = listAdapter.prototype.constructor.name;
+ return JSX_(REaCt().Fragment, null, JSX_(perfectScrollbar.O, {
+ key: `ps_${ listAdapterName }_${ viewMode}`,
+ options: this.options.perfectScrollOptions,
+ onUserScroll: this.onPsUserScroll,
+ className,
+ style: {
+ 'position': 'relative'
+ },
+ ref: instance => {
+ this.domRef = instance;
+ }
+ }, JSX_(this.props.listAdapter, (0,esm_extends.A)({
+ containerClassName: this.props.containerClassName,
+ key: `ps_${ listAdapterName }_${ this.props.viewMode }_la`,
+ ref: listAdapterInstance => {
+ this.listAdapterInstance = listAdapterInstance;
+ },
+ listContentRef: listContent => {
+ this.listContent = listContent;
+ },
+ header,
+ megaList: this,
+ calculated: this._calculated
+ }, listAdapterOpts), nodes)));
+ }
+}, (0,applyDecoratedDescriptor.A)(_class.prototype, "onPsUserScroll", [_dec], Object.getOwnPropertyDescriptor(_class.prototype, "onPsUserScroll"), _class.prototype), _class);
+// EXTERNAL MODULE: ./js/ui/jsx/fm/nodes/genericNodePropsComponent.jsx + 1 modules
+const genericNodePropsComponent = REQ_(4285);
+;// ./js/ui/jsx/fm/nodes/genericGrid.jsx
+
+
+class GenericGrid extends genericNodePropsComponent.B {
+ render() {
+ const {
+ node,
+ calculated,
+ index,
+ listAdapter,
+ className,
+ keyProp
+ } = this.props;
+ const style = {};
+ listAdapter.repositionItem(node, calculated, index, style);
+ const toApplySensitive = !!mega.sensitives.isSensitive(node) && (mega.sensitives.showGlobally ? 1 : 2);
+ let image = null;
+ let src = null;
+ let isThumbClass = "";
+ if (node.fa && (is_image2(node) || is_video(node))) {
+ src = thumbnails.get(node.fa);
+ if (!src) {
+ this.props.requestThumbnailCb(node);
+ src = window.noThumbURI || '';
+ }
+ image = src ? JSX_("img", {
+ alt: "",
+ src
+ }) : JSX_("img", {
+ alt: ""
+ });
+ isThumbClass = " thumb";
+ } else {
+ image = JSX_("img", null);
+ }
+ let fileStatusClass = "";
+ if (node.fav) {
+ fileStatusClass += " icon-favourite-filled";
+ }
+ return JSX_("a", {
+ className: `data-block-view megaListItem ui-droppable ui-draggable ui-draggable-handle ${ this.nodeProps.classNames.join(" ") }${className && className(node) || "" }${toApplySensitive ? toApplySensitive === 1 ? ' is-sensitive' : ' hidden-as-sensitive' : ''}`,
+ id: `chat_${ node[keyProp]}`,
+ onClick: e => {
+ this.props.onClick(e, this.props.node);
+ },
+ onDoubleClick: e => {
+ this.props.onDoubleClick(e, this.props.node);
+ },
+ title: this.nodeProps.title,
+ style
+ }, JSX_("span", {
+ className: `data-block-bg ${ isThumbClass}`
+ }, JSX_("span", {
+ className: "data-block-indicators"
+ }, JSX_("span", {
+ className: `file-status-icon indicator sprite-fm-mono${ fileStatusClass}`
+ }), JSX_("span", {
+ className: "versioning-indicator"
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-versions-previous"
+ })), JSX_("i", {
+ className: "sprite-fm-mono icon-link"
+ })), JSX_("span", {
+ className: `item-type-icon-90 icon-${ this.nodeProps.icon }-90`
+ }, image), JSX_("div", {
+ className: "video-thumb-details"
+ }, JSX_("i", {
+ className: "small-icon small-play-icon"
+ }), JSX_("span", null, "00:00"))), JSX_("span", {
+ className: "file-block-title"
+ }, this.nodeProps.title));
+ }
+}
+;// ./js/ui/jsx/fm/nodes/genericTable.jsx
+
+
+
+class GenericTableHeader extends mixins.w9 {
+ constructor(...args) {
+ super(...args);
+ this.domRef = REaCt().createRef();
+ }
+ render() {
+ const {
+ sortBy,
+ columns
+ } = this.props;
+ const columnsRendered = [];
+ for (let i = 0; i < columns.length; i++) {
+ var _colProps;
+ let col = columns[i];
+ let colProps;
+ if (Array.isArray(col)) {
+ colProps = col[1];
+ col = col[0];
+ }
+ let sortable;
+ if (col.sortable) {
+ let classes = "";
+ if (sortBy[0] === col.id) {
+ const ordClass = sortBy[1] === "desc" ? "icon-arrow-down" : "icon-arrow-up";
+ classes = `${classes} ${ordClass}`;
+ }
+ if (col.id === 'fav') {
+ classes += ' hidden';
+ }
+ sortable = JSX_("i", {
+ className: `sprite-fm-mono ${col.id} ${classes}`
+ });
+ }
+ columnsRendered.push(JSX_("th", {
+ megatype: col.megatype,
+ className: col.headerClassName || col.megatype || "",
+ key: `${col.id }_${ i}`,
+ onClick: e => {
+ e.preventDefault();
+ if (col.sortable) {
+ this.props.onClick(col.id);
+ }
+ }
+ }, JSX_("span", null, ((_colProps = colProps) == null ? void 0 : _colProps.label) || col.label), col.icon && JSX_("i", {
+ className: `sprite-fm-mono ${ col.icon}`
+ }), sortable));
+ }
+ return JSX_("thead", {
+ ref: this.domRef
+ }, JSX_("tr", null, columnsRendered));
+ }
+}
+class GenericTable extends genericNodePropsComponent.B {
+ render() {
+ let _this$nodeProps;
+ const {
+ node,
+ index,
+ listAdapterOpts,
+ className,
+ keyProp
+ } = this.props;
+ const toApplySensitive = !!mega.sensitives.isSensitive(node) && (mega.sensitives.showGlobally ? 1 : 2);
+ const columns = [];
+ for (let i = 0; i < listAdapterOpts.columns.length; i++) {
+ const customColumn = listAdapterOpts.columns[i];
+ if (Array.isArray(customColumn)) {
+ columns.push(JSX_(customColumn[0], {
+ ...customColumn[1],
+ 'nodeAdapter': this,
+ 'h': node[keyProp],
+ node,
+ 'key': `${i }_${ customColumn[0].prototype.constructor.name}`,
+ keyProp
+ }));
+ } else {
+ columns.push(JSX_(customColumn, {
+ 'nodeAdapter': this,
+ 'h': node[keyProp],
+ node,
+ 'key': `${i }_${ customColumn.prototype.constructor.name}`,
+ keyProp
+ }));
+ }
+ }
+ const listClassName = listAdapterOpts.className;
+ return JSX_("tr", {
+ className: `node_${ node[keyProp] } ${ className && className(node) || "" } ${ listClassName && listClassName(node) || "" } ${ (_this$nodeProps = this.nodeProps) == null ? void 0 : _this$nodeProps.classNames.join(" ") }${toApplySensitive ? toApplySensitive === 1 ? ' is-sensitive' : ' hidden-as-sensitive' : ''}`,
+ id: node[keyProp],
+ onContextMenu: ev => {
+ if (this.props.onContextMenu) {
+ this.props.onContextMenu(ev, node[keyProp]);
+ }
+ },
+ onClick: e => {
+ this.props.onClick(e, this.props.node);
+ },
+ onDoubleClick: e => {
+ this.props.onDoubleClick(e, this.props.node);
+ },
+ key: `${index }_${ node[keyProp]}`
+ }, columns);
+ }
+}
+;// ./js/ui/jsx/megaList/adapters.jsx
+
+
+class GenericListAdapter extends mixins.w9 {
+ constructor(...args) {
+ super(...args);
+ this.customIsEventuallyVisible = true;
+ }
+}
+class Grid extends GenericListAdapter {
+ static repositionItem(node, calculated, index, style) {
+ style.position = "absolute";
+ style.top = calculated.itemHeight * Math.floor(index / calculated.itemsPerRow);
+ if (calculated.itemsPerRow > 1) {
+ style.left = index % calculated.itemsPerRow * calculated.itemWidth;
+ }
+ }
+ render() {
+ return JSX_("div", {
+ className: "megaList-content",
+ ref: this.props.listContentRef,
+ style: {
+ 'position': 'relative'
+ }
+ }, this.props.children);
+ }
+}
+Grid.itemWidth = 212;
+Grid.itemHeight = 212;
+Grid.containerClassName = "file-block-scrolling megaListContainer";
+class Table extends GenericListAdapter {
+ onContentUpdated() {
+ const {
+ calculated
+ } = this.props;
+ const pusherHeight = calculated.visibleFirstItemNum * calculated.itemHeight | 0;
+ if (this.topPusher) {
+ this.topPusher.style.height = `${pusherHeight }px`;
+ }
+ if (this.bottomPusher) {
+ this.bottomPusher.style.height = `${calculated.contentHeight - pusherHeight - (calculated.visibleLastItemNum - calculated.visibleFirstItemNum) * calculated.itemHeight | 0 }px`;
+ }
+ }
+ componentDidUpdate() {
+ super.componentDidUpdate();
+ this.onContentUpdated();
+ }
+ render() {
+ return JSX_("table", {
+ width: "100%",
+ className: this.props.containerClassName || "grid-table table-hover fm-dialog-table"
+ }, this.props.header, JSX_("tbody", {
+ ref: this.props.listContentRef
+ }, JSX_("tr", {
+ className: "megalist-pusher top",
+ ref: r => {
+ this.topPusher = r;
+ }
+ }), this.props.children, JSX_("tr", {
+ className: "megalist-pusher bottom",
+ ref: r => {
+ this.bottomPusher = r;
+ }
+ })));
+ }
+}
+Table.itemHeight = 32;
+Table.itemsPerRow = 1;
+Table.containerClassName = "grid-scrolling-table megaListContainer";
+// EXTERNAL MODULE: ./js/ui/jsx/fm/nodes/columns/columnFavIcon.jsx
+const columnFavIcon = REQ_(6794);
+;// ./js/ui/tooltips.jsx
+
+
+class Handler extends REaCt().Component {
+ render() {
+ const {
+ className,
+ onMouseOver,
+ onMouseOut,
+ children
+ } = this.props;
+ return JSX_("span", {
+ className: `
+ tooltip-handler
+ ${className || ''}
+ `,
+ onMouseOver,
+ onMouseOut
+ }, children);
+ }
+}
+class Contents extends REaCt().Component {
+ render() {
+ let className = `tooltip-contents dropdown body tooltip ${ this.props.className ? this.props.className : ""}`;
+ if (this.props.active) {
+ className += " visible";
+ return JSX_("div", {
+ className
+ }, this.props.withArrow ? JSX_("i", {
+ className: "dropdown-white-arrow"
+ }) : null, this.props.children);
+ } else {
+ return null;
+ }
+ }
+}
+class Tooltip extends mixins.w9 {
+ constructor(props) {
+ super(props);
+ this.domRef = REaCt().createRef();
+ this.state = {
+ 'active': false
+ };
+ }
+ componentDidUpdate(oldProps, oldState) {
+ const self = this;
+ if (oldState.active === true && this.state.active === false) {
+ chatGlobalEventManager.removeEventListener('resize', `tooltip${ this.getUniqueId()}`);
+ }
+ if (self.state.active === true) {
+ self.repositionTooltip();
+ chatGlobalEventManager.addEventListener('resize', `tooltip${ this.getUniqueId()}`, () => {
+ self.repositionTooltip();
+ });
+ if (this.props.onShown) {
+ this.props.onShown();
+ }
+ }
+ }
+ repositionTooltip() {
+ let _this$domRef;
+ let elLeftPos, elTopPos, elWidth, elHeight;
+ let tooltipLeftPos, tooltipTopPos, tooltipWidth, tooltipHeight;
+ let docHeight;
+ let arrowClass;
+ if (!this.isMounted()) {
+ return;
+ }
+ const $container = $((_this$domRef = this.domRef) == null ? void 0 : _this$domRef.current);
+ const $el = $('.tooltip-handler', $container);
+ const $tooltip = $('.tooltip-contents', $container);
+ let {tooltipOffset} = this.props;
+ const arrow = this.props.withArrow;
+ if ($el && $tooltip) {
+ elWidth = $el.outerWidth();
+ elHeight = $el.outerHeight();
+ elLeftPos = $el.offset().left;
+ elTopPos = $el.offset().top;
+ tooltipWidth = $tooltip.outerWidth();
+ tooltipHeight = $tooltip.outerHeight();
+ docHeight = $(window).height();
+ $tooltip.removeClass('dropdown-arrow left-arrow right-arrow up-arrow down-arrow').removeAttr('style');
+ if (!tooltipOffset) {
+ tooltipOffset = 7;
+ }
+ if (elTopPos - tooltipHeight - tooltipOffset > 10) {
+ tooltipLeftPos = elLeftPos + elWidth / 2 - tooltipWidth / 2;
+ tooltipTopPos = elTopPos - tooltipHeight - tooltipOffset;
+ arrowClass = arrow ? 'dropdown-arrow down-arrow' : '';
+ } else if (docHeight - (elTopPos + elHeight + tooltipHeight + tooltipOffset) > 10) {
+ tooltipLeftPos = elLeftPos + elWidth / 2 - tooltipWidth / 2;
+ tooltipTopPos = elTopPos + elHeight + tooltipOffset;
+ arrowClass = arrow ? 'dropdown-arrow up-arrow' : '';
+ } else if (elLeftPos - tooltipWidth - tooltipOffset > 10) {
+ tooltipLeftPos = elLeftPos - tooltipWidth - tooltipOffset;
+ tooltipTopPos = elTopPos + elHeight / 2 - tooltipHeight / 2;
+ arrowClass = arrow ? 'dropdown-arrow right-arrow' : '';
+ } else {
+ tooltipLeftPos = elLeftPos + elWidth + tooltipOffset;
+ tooltipTopPos = elTopPos + elHeight / 2 - tooltipHeight / 2;
+ arrowClass = arrow ? 'dropdown-arrow left-arrow' : '';
+ }
+ $tooltip.css({
+ 'left': tooltipLeftPos,
+ 'top': tooltipTopPos - 5
+ });
+ $tooltip.addClass(arrowClass);
+ }
+ }
+ onHandlerMouseOver() {
+ this.setState({
+ 'active': true
+ });
+ }
+ onHandlerMouseOut() {
+ this.setState({
+ 'active': false
+ });
+ }
+ render() {
+ const self = this;
+ const others = [];
+ let handler = null;
+ let contents = null;
+ let x = 0;
+ REaCt().Children.forEach(this.props.children, (child) => {
+ if (child.type.name === 'Handler') {
+ handler = REaCt().cloneElement(child, {
+ onMouseOver () {
+ self.onHandlerMouseOver();
+ },
+ onMouseOut () {
+ self.onHandlerMouseOut();
+ }
+ });
+ } else if (child.type.name === 'Contents') {
+ contents = REaCt().cloneElement(child, {
+ active: self.state.active,
+ withArrow: self.props.withArrow
+ });
+ } else {
+ const tmp = REaCt().cloneElement(child, {
+ key: x++
+ });
+ others.push(tmp);
+ }
+ });
+ return JSX_("span", {
+ ref: this.domRef,
+ className: this.props.className || ''
+ }, handler, contents, others);
+ }
+}
+Tooltip.defaultProps = {
+ 'hideable': true
+};
+ const tooltips = {
+ Tooltip,
+ Handler,
+ Contents
+};
+;// ./js/ui/jsx/fm/nodes/columns/columnNodeName.jsx
+
+
+
+class ColumnNodeName extends genericNodePropsComponent.B {
+ constructor(...args) {
+ super(...args);
+ this.state = {
+ src: null
+ };
+ }
+ static get label() {
+ return l[86];
+ }
+ componentDidMount() {
+ super.componentDidMount();
+ }
+ render() {
+ const {
+ nodeAdapter
+ } = this.props;
+ const {
+ node,
+ requestThumbnailCb
+ } = nodeAdapter.props;
+ const src = this.state.src || thumbnails.get(node.fa);
+ return JSX_("td", {
+ megatype: ColumnNodeName.megatype
+ }, src || is_image2(node) || is_video(node) ? JSX_(tooltips.Tooltip, {
+ withArrow: true,
+ className: "tooltip-handler-container",
+ onShown: () => {
+ if (!src) {
+ requestThumbnailCb(node, true, (n, src) => {
+ this.setState({
+ src
+ });
+ return `preview_${n.h}`;
+ });
+ }
+ }
+ }, JSX_(tooltips.Handler, {
+ className: `item-type-icon icon-${fileIcon(node)}-24`
+ }), JSX_(tooltips.Contents, {
+ className: "img-preview"
+ }, JSX_("div", {
+ className: "dropdown img-wrapper img-block",
+ id: `preview_${node.h}`
+ }, JSX_("img", {
+ alt: "",
+ className: `thumbnail-placeholder ${node.h}`,
+ src: node.fa || src ? src || `${staticpath}/images/mega/ajax-loader-tiny.gif` : window.noThumbURI
+ })))) : JSX_("span", {
+ className: `
+ item-type-icon icon-${fileIcon(node)}-24
+ `
+ }), JSX_("span", {
+ className: "tranfer-filetype-txt"
+ }, nodeAdapter.nodeProps.title));
+ }
+}
+ColumnNodeName.sortable = true;
+ColumnNodeName.id = 'name';
+ColumnNodeName.megatype = 'fname';
+;// ./js/ui/jsx/fm/nodes/columns/columnSize.jsx
+
+
+class ColumnSize extends genericNodePropsComponent.B {
+ static get label() {
+ return l[87];
+ }
+ render() {
+ const {
+ nodeAdapter
+ } = this.props;
+ return JSX_("td", {
+ megatype: ColumnSize.megatype,
+ className: "size"
+ }, nodeAdapter.nodeProps.size);
+ }
+}
+ColumnSize.sortable = true;
+ColumnSize.id = "size";
+ColumnSize.megatype = "size";
+;// ./js/ui/jsx/fm/nodes/columns/columnTimeAdded.jsx
+
+
+class ColumnTimeAdded extends genericNodePropsComponent.B {
+ static get label() {
+ return l[16169];
+ }
+ render() {
+ const {
+ nodeAdapter
+ } = this.props;
+ return JSX_("td", {
+ megatype: ColumnTimeAdded.megatype,
+ className: "time ad"
+ }, nodeAdapter.nodeProps.timestamp);
+ }
+}
+ColumnTimeAdded.sortable = true;
+ColumnTimeAdded.id = "ts";
+ColumnTimeAdded.megatype = "timeAd";
+;// ./js/ui/jsx/fm/nodes/columns/columnExtras.jsx
+
+
+class ColumnExtras extends genericNodePropsComponent.B {
+ render() {
+ return JSX_("td", {
+ megatype: ColumnExtras.megatype,
+ className: "grid-url-field own-data extras-column"
+ }, JSX_("span", {
+ className: "versioning-indicator"
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-versions-previous"
+ })), JSX_("i", {
+ className: "sprite-fm-mono icon-link"
+ }));
+ }
+}
+ColumnExtras.sortable = false;
+ColumnExtras.id = "extras";
+ColumnExtras.label = "";
+ColumnExtras.megatype = "extras";
+ColumnExtras.headerClassName = "grid-url-header";
+;// ./js/ui/jsx/fm/browserEntries.jsx
+
+
+
+
+
+
+
+
+
+
+
+class BrowserEntries extends mixins.w9 {
+ constructor(props) {
+ super(props);
+ this.state = {
+ 'sortBy': props.sortBy || ['name', 'asc']
+ };
+ this.toggleSortBy = this.toggleSortBy.bind(this);
+ }
+ UNSAFE_componentWillMount() {
+ this.lastCharKeyPressed = false;
+ this.lastCharKeyIndex = -1;
+ }
+ componentDidMount() {
+ super.componentDidMount();
+ this.bindEvents();
+ }
+ componentWillUnmount() {
+ super.componentWillUnmount();
+ this.unbindEvents();
+ }
+ componentDidUpdate(oldProps) {
+ if (oldProps.sortBy && (oldProps.sortBy[0] !== this.props.sortBy[0] || oldProps.sortBy[1] !== this.props.sortBy[1])) {
+ this.setState({
+ 'sortBy': this.props.sortBy
+ });
+ }
+ }
+ handleKeyNavigation(selectionManager, shiftKey, keyCode, viewMode) {
+ let curr;
+ const {
+ folderSelectNotAllowed
+ } = this.props;
+ if (shiftKey && folderSelectNotAllowed) {
+ curr = selectionManager.last_selected;
+ }
+ const {KEYS} = BrowserEntries;
+ if (viewMode) {
+ if (keyCode === KEYS.LEFT) {
+ selectionManager.select_prev(shiftKey, true);
+ } else if (keyCode === KEYS.RIGHT) {
+ selectionManager.select_next(shiftKey, true);
+ } else if (keyCode === KEYS.UP) {
+ selectionManager.select_grid_up(shiftKey, true);
+ } else {
+ selectionManager.select_grid_down(shiftKey, true);
+ }
+ } else if (keyCode === KEYS.UP) {
+ selectionManager.select_prev(shiftKey, true);
+ } else {
+ selectionManager.select_next(shiftKey, true);
+ }
+ if (shiftKey && folderSelectNotAllowed && $.selected.length > 1) {
+ const folderNodes = $.selected.filter(n => !M.isFileNode(M.getNodeByHandle(n)));
+ if (folderNodes.length > 1) {
+ if (!M.isFileNode(M.getNodeByHandle(curr))) {
+ array.remove(folderNodes, curr);
+ }
+ if (folderNodes.length) {
+ const newCurr = selectionManager.last_selected;
+ for (let i = 0; i < folderNodes.length; i++) {
+ selectionManager.remove_from_selection(folderNodes[i]);
+ }
+ if (M.isFileNode(M.getNodeByHandle(newCurr))) {
+ selectionManager.set_currently_selected(curr);
+ } else if (curr && $.selected.includes(curr)) {
+ selectionManager.set_currently_selected(curr);
+ } else if ($.selected.length) {
+ selectionManager.set_currently_selected($.selected[0]);
+ }
+ }
+ }
+ }
+ }
+ _invalidKeydownTarget(e) {
+ return e.target && (e.target.tagName === 'INPUT' || e.target.tagName === 'BUTTON' || e.target.tagName === 'TEXTAREA' && !e.target.classList.contains('messages-textarea') || e.target.tagName === 'SELECT');
+ }
+ _isNavigationKeyDown(e, keyCode) {
+ const {
+ KEYS
+ } = BrowserEntries;
+ const {
+ viewMode
+ } = this.props;
+ return !e.metaKey && (!viewMode && (keyCode === KEYS.UP || keyCode === KEYS.DOWN) || viewMode && (keyCode === KEYS.UP || keyCode === KEYS.DOWN || keyCode === KEYS.LEFT || keyCode === KEYS.RIGHT));
+ }
+ bindEvents() {
+ const {
+ KEYS
+ } = BrowserEntries;
+ $(document.body).rebind(`keydown.be${this.getUniqueId()}`, e => {
+ let charTyped = false;
+ const keyCode = e.which || e.keyCode;
+ const $searchField = $('div.fm-files-search input');
+ const $typingArea = $('textarea.messages-textarea');
+ const {
+ selectionManager,
+ viewMode
+ } = this.props;
+ if (this._invalidKeydownTarget(e)) {
+ return;
+ }
+ if ($searchField.is(':focus')) {
+ return;
+ }
+ if ($typingArea.is(':focus')) {
+ $typingArea.trigger('blur');
+ }
+ if (keyCode === KEYS.A && (e.ctrlKey || e.metaKey)) {
+ this.handleSelectAll();
+ e.preventDefault();
+ e.stopPropagation();
+ } else if (e.metaKey && keyCode === KEYS.UP || keyCode === KEYS.BACKSPACE) {
+ this.handleKeyBack();
+ } else if (this._isNavigationKeyDown(e, keyCode)) {
+ this.handleKeyNavigation(selectionManager, e.shiftKey, keyCode, viewMode);
+ } else if (keyCode >= 48 && keyCode <= 57 || keyCode >= 65 && keyCode <= 123 || keyCode > 255) {
+ charTyped = String.fromCharCode(keyCode).toLowerCase();
+ this.handleCharTyped(charTyped);
+ } else if (keyCode === KEYS.ENTER || e.metaKey && keyCode === KEYS.DOWN) {
+ this.handleAttach();
+ }
+ mega.ui.mInfoPanel.reRenderIfVisible($.selected);
+ if (!charTyped) {
+ this.lastCharKeyPressed = false;
+ this.lastCharKeyIndex = -1;
+ }
+ });
+ }
+ handleSelectAll() {
+ const {
+ selectionManager,
+ folderSelectNotAllowed,
+ entries
+ } = this.props;
+ selectionManager.select_all();
+ if (folderSelectNotAllowed) {
+ const folders = entries.filter(h => !M.isFileNode(M.getNodeByHandle(h)));
+ for (let i = 0; i < folders.length; i++) {
+ selectionManager.remove_from_selection(folders[i].h);
+ }
+ }
+ }
+ handleKeyBack() {
+ const {
+ viewMode,
+ currentlyViewedEntry
+ } = this.props;
+ if (!viewMode) {
+ const currentFolder = M.getNode(currentlyViewedEntry);
+ if (currentFolder.p) {
+ this.expandFolder(currentFolder.p);
+ }
+ }
+ }
+ handleCharTyped(charTyped) {
+ const {
+ entries,
+ keyProp,
+ selectionManager
+ } = this.props;
+ const foundMatchingNodes = entries.filter(node => {
+ return node.name && node.name.substring(0, 1).toLowerCase() === charTyped;
+ });
+ if (this.lastCharKeyPressed === charTyped) {
+ this.lastCharKeyIndex++;
+ }
+ this.lastCharKeyPressed = charTyped;
+ if (foundMatchingNodes.length > 0) {
+ if (!foundMatchingNodes[this.lastCharKeyIndex]) {
+ this.lastCharKeyIndex = 0;
+ }
+ const foundNode = foundMatchingNodes[this.lastCharKeyIndex];
+ selectionManager.clear_selection();
+ selectionManager.set_currently_selected(foundNode[keyProp], true);
+ }
+ }
+ handleAttach() {
+ const {
+ highlighted,
+ folderSelectNotAllowed,
+ entries,
+ keyProp,
+ onAttachClicked
+ } = this.props;
+ let selectedNodes = highlighted;
+ if (folderSelectNotAllowed) {
+ selectedNodes = highlighted.filter(h => {
+ const node = entries.find(e => e[keyProp] === h);
+ return node && node.t === 0;
+ });
+ if (selectedNodes.length === 0) {
+ const cursorNode = highlighted[0] && M.getNodeByHandle(highlighted[0]);
+ if (cursorNode.t === 1) {
+ this.expandFolder(cursorNode[keyProp]);
+ return;
+ } else if (highlighted.length > 0) {
+ this.expandFolder(highlighted[0]);
+ return;
+ }
+ return;
+ }
+ }
+ onAttachClicked(selectedNodes);
+ }
+ unbindEvents() {
+ $(document.body).off(`keydown.be${ this.getUniqueId()}`);
+ }
+ onEntryClick(e, node) {
+ const {
+ selectionManager,
+ keyProp,
+ folderSelectNotAllowed,
+ highlighted = []
+ } = this.props;
+ this.lastCharKeyPressed = false;
+ this.lastCharKeyIndex = -1;
+ e.stopPropagation();
+ e.preventDefault();
+ if (!e.shiftKey && !e.ctrlKey && !e.metaKey) {
+ selectionManager.clear_selection();
+ selectionManager.set_currently_selected(node[keyProp]);
+ } else if (e.shiftKey) {
+ if ($.selected && $.selected.length) {
+ let selFolders;
+ if (folderSelectNotAllowed) {
+ selFolders = $.selected.filter(n => !M.isFileNode(M.getNodeByHandle(n)));
+ }
+ selectionManager.shift_select_to(node[keyProp], false, true, false);
+ if (folderSelectNotAllowed && $.selected.length > 1) {
+ const folderNodes = $.selected.filter(n => !M.isFileNode(M.getNodeByHandle(n)));
+ if (folderNodes.length > 1) {
+ array.remove(folderNodes, selFolders[0] || folderNodes[0]);
+ for (let i = 0; i < folderNodes.length; i++) {
+ selectionManager.remove_from_selection(folderNodes[i]);
+ }
+ }
+ }
+ } else {
+ selectionManager.set_currently_selected(node[keyProp]);
+ }
+ } else if (e.ctrlKey || e.metaKey) {
+ if (!highlighted || !highlighted.includes(node[keyProp])) {
+ if (folderSelectNotAllowed) {
+ if (node.t === 1 && highlighted.length > 0) {
+ return;
+ } else if (highlighted.some(nodeId => {
+ const node = M.getNodeByHandle(nodeId);
+ return node && node.t === 1;
+ })) {
+ selectionManager.clear_selection();
+ }
+ }
+ selectionManager.add_to_selection(node[keyProp]);
+ } else if (highlighted && highlighted.includes(node[keyProp])) {
+ if (folderSelectNotAllowed) {
+ if (node.t === 1) {
+ return;
+ } else if (highlighted.some(nodeId => {
+ const node = M.getNodeByHandle(nodeId);
+ return node && node.t === 1;
+ })) {
+ selectionManager.clear();
+ }
+ }
+ selectionManager.remove_from_selection(node[keyProp]);
+ }
+ }
+ }
+ expandFolder(nodeId) {
+ const self = this;
+ const node = M.getNodeByHandle(nodeId);
+ if (node) {
+ self.lastCharKeyPressed = false;
+ self.lastCharKeyIndex = -1;
+ self.setState({
+ 'selected': [],
+ 'highlighted': [],
+ 'cursor': false
+ });
+ self.props.onExpand(node);
+ self.forceUpdate();
+ }
+ }
+ onEntryDoubleClick(e, node) {
+ const self = this;
+ self.lastCharKeyPressed = false;
+ self.lastCharKeyIndex = -1;
+ e.stopPropagation();
+ e.preventDefault();
+ const share = M.getNodeShare(node);
+ if (share && share.down) {
+ return;
+ }
+ if (node.t) {
+ self.props.onExpand(node);
+ self.forceUpdate();
+ } else {
+ self.onEntryClick(e, node);
+ self.props.onAttachClicked();
+ }
+ }
+ customIsEventuallyVisible() {
+ return true;
+ }
+ toggleSortBy(colId) {
+ const newState = {};
+ if (this.state.sortBy[0] === colId) {
+ newState.sortBy = [colId, this.state.sortBy[1] === "asc" ? "desc" : "asc"];
+ } else {
+ newState.sortBy = [colId, "asc"];
+ }
+ this.setState(newState);
+ this.props.onSortByChanged(newState.sortBy);
+ }
+ render() {
+ const {viewMode} = this.props;
+ const listAdapterOpts = this.props.listAdapterOpts || {};
+ if (!viewMode) {
+ listAdapterOpts.columns = [columnFavIcon.$, ColumnNodeName, ColumnSize, ColumnTimeAdded, ColumnExtras];
+ }
+ if (this.props.listAdapterColumns) {
+ listAdapterOpts.columns = this.props.listAdapterColumns;
+ }
+ if (this.props.isLoading) {
+ return JSX_("div", {
+ className: "dialog-empty-block active dialog-fm folder"
+ }, JSX_("div", {
+ className: "dialog-empty-pad"
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-cloud-drive"
+ }), JSX_("div", {
+ className: "dialog-empty-header"
+ }, l[5533])));
+ } else if (!this.props.entries.length && this.props.currentlyViewedEntry === 'search') {
+ return JSX_("div", {
+ className: "dialog-empty-block active dialog-fm folder"
+ }, JSX_("div", {
+ className: "dialog-empty-pad"
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-preview-reveal"
+ }), JSX_("div", {
+ className: "dialog-empty-header"
+ }, l[978])));
+ } else if (!this.props.entries.length) {
+ const nilComp = this.props.NilComponent;
+ return nilComp && (typeof nilComp === "function" ? nilComp() : nilComp) || JSX_("div", {
+ className: "dialog-empty-block active dialog-fm folder"
+ }, this.props.currentlyViewedEntry === 'shares' ? JSX_("div", {
+ className: "dialog-empty-pad"
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-folder-incoming-share-filled"
+ }), JSX_("div", {
+ className: "dialog-empty-header"
+ }, l[6871])) : JSX_("div", {
+ className: "dialog-empty-pad"
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-folder-filled"
+ }), JSX_("div", {
+ className: "dialog-empty-header"
+ }, this.props.currentlyViewedEntry === M.RootID ? l[1343] : M.u[this.props.currentlyViewedEntry] ? l[6787] : l[782])));
+ }
+ return JSX_(MegaList2, {
+ viewMode,
+ sortBy: this.state.sortBy,
+ currentlyViewedEntry: this.props.currentlyViewedEntry,
+ selected: this.props.selected,
+ highlighted: this.props.highlighted,
+ containerClassName: this.props.containerClassName,
+ nodeAdapterProps: {
+ 'onClick': (e, node) => {
+ this.onEntryClick(e, node);
+ mega.ui.mInfoPanel.reRenderIfVisible($.selected);
+ },
+ 'onDoubleClick': (e, node) => {
+ this.onEntryDoubleClick(e, node);
+ },
+ 'className': node => {
+ return this.props.highlighted.indexOf(node[this.props.keyProp]) > -1 ? " ui-selected" : "";
+ }
+ },
+ ref: r => {
+ this.megaList = r;
+ },
+ listAdapter: viewMode ? Grid : Table,
+ nodeAdapter: viewMode ? GenericGrid : GenericTable,
+ listAdapterOpts,
+ entries: this.props.entries,
+ itemHeight: this.props.megaListItemHeight,
+ headerHeight: viewMode ? 0 : 56,
+ header: !viewMode && JSX_(GenericTableHeader, {
+ columns: listAdapterOpts.columns,
+ sortBy: this.state.sortBy,
+ onClick: this.toggleSortBy,
+ headerContainerClassName: this.props.headerContainerClassName
+ }),
+ currentdirid: this.props.currentdirid,
+ onContextMenu: this.props.onContextMenu,
+ keyProp: this.props.keyProp
+ });
+ }
+}
+BrowserEntries.KEYS = {
+ A: 65,
+ UP: 38,
+ DOWN: 40,
+ LEFT: 37,
+ RIGHT: 39,
+ ENTER: 13,
+ BACKSPACE: 8
+};
+BrowserEntries.defaultProps = {
+ 'hideable': true,
+ 'requiresUpdateOnResize': true
+};
+;// ./js/ui/jsx/fm/fmView.jsx
+
+
+
+class FMView extends mixins.w9 {
+ constructor(props) {
+ let _this$dataSource;
+ super(props);
+ this.domRef = REaCt().createRef();
+ let initialSortBy = props.initialSortBy || ['name', 'asc'];
+ if (props.fmConfigSortEnabled) {
+ let _fmconfig$sortmodes;
+ const sortId = props.fmConfigSortId;
+ assert(sortId, 'missing fmConfigSortId');
+ if ((_fmconfig$sortmodes = fmconfig.sortmodes) != null && (_fmconfig$sortmodes = _fmconfig$sortmodes[sortId]) != null && _fmconfig$sortmodes.n) {
+ let _fmconfig$sortmodes2;
+ initialSortBy = this._translateFmConfigSortMode((_fmconfig$sortmodes2 = fmconfig.sortmodes) == null ? void 0 : _fmconfig$sortmodes2[sortId]);
+ }
+ }
+ this.state = {
+ 'sortBy': initialSortBy,
+ 'selected': [],
+ 'highlighted': [],
+ 'entries': null
+ };
+ this.dataSource = this.props.dataSource;
+ this.state.entries = this.getEntries();
+ this.onAttachClicked = this.onAttachClicked.bind(this);
+ this.onContextMenu = this.onContextMenu.bind(this);
+ if ((_this$dataSource = this.dataSource) != null && _this$dataSource.addChangeListener) {
+ this._listener = this.dataSource.addChangeListener(() => {
+ if (!this.isMounted()) {
+ return;
+ }
+ this.setState({
+ 'entries': this.getEntries()
+ });
+ });
+ }
+ this.initSelectionManager();
+ }
+ getDataSourceNode(h) {
+ return this.dataSource && this.dataSource[h] || M.getNodeByHandle(h);
+ }
+ _translateFmConfigSortMode(currentSortModes) {
+ const sortId = this.props.fmConfigSortId;
+ assert(sortId, 'missing fmConfigSortId');
+ const sortByArr = [];
+ if (currentSortModes != null && currentSortModes.n) {
+ sortByArr[0] = currentSortModes.n;
+ const sortMap = this.props.fmConfigSortMap;
+ const aliasKeys = sortMap && Object.keys(sortMap) || [];
+ for (const alias of aliasKeys) {
+ if (sortByArr[0] === sortMap[alias]) {
+ sortByArr[0] = alias;
+ break;
+ }
+ }
+ sortByArr[1] = currentSortModes.d === 1 ? "asc" : "desc";
+ }
+ return sortByArr;
+ }
+ initSelectionManager(entries) {
+ this.selectionManager = new SelectionManager2_React(entries || this.state.entries, this.props.currentdirid || "cloud-drive", () => {
+ let _this$browserEntries;
+ return (_this$browserEntries = this.browserEntries) == null || (_this$browserEntries = _this$browserEntries.megaList) == null || (_this$browserEntries = _this$browserEntries._calculated) == null ? void 0 : _this$browserEntries.itemsPerRow;
+ }, nodeHandle => {
+ if (this.browserEntries && this.browserEntries.megaList) {
+ this.browserEntries.megaList.scrollToItem(nodeHandle);
+ }
+ }, {
+ 'onSelectedUpdated': selectedList => {
+ this.onSelectionUpdated(selectedList);
+ }
+ });
+ }
+ onSelectionUpdated(selectedList) {
+ selectedList = [...selectedList];
+ const highlighted = selectedList;
+ if (this.props.folderSelectNotAllowed && !this.props.folderSelectable) {
+ selectedList = selectedList.filter(nodeId => !this.getDataSourceNode(nodeId).t);
+ }
+ this.setState({
+ 'selected': selectedList,
+ highlighted
+ });
+ this.props.onSelected(selectedList);
+ this.props.onHighlighted(highlighted);
+ $.selected = highlighted;
+ }
+ getEntries(newState) {
+ const self = this;
+ const sortBy = newState && newState.sortBy || self.state.sortBy;
+ const order = sortBy[1] === "asc" ? 1 : -1;
+ const entries = [];
+ let sortFunc, filterFunc, dataSource;
+ const minSearchLength = self.props.minSearchLength || 3;
+ const showSen = mega.sensitives.showGlobally;
+ if (self.props.currentlyViewedEntry === "search" && self.props.searchValue && self.props.searchValue.length >= minSearchLength) {
+ dataSource = this.dataSource || {
+ ...M.tnd,
+ ...M.d
+ };
+ filterFunc = M.getFilterBySearchFn(self.props.searchValue);
+ } else {
+ const tmp = M.getChildren(self.props.currentlyViewedEntry) || M.tree[self.props.currentlyViewedEntry] || this.props.dataSource;
+ dataSource = Object.create(null);
+ for (const h in tmp) {
+ const n = this.getDataSourceNode(h);
+ if (n) {
+ dataSource[h] = n;
+ }
+ }
+ }
+ const {
+ customFilterFn
+ } = this.props;
+ for (const h in dataSource) {
+ const n = dataSource[h];
+ const e = n && (!n.h || n.h.length === 8 && crypto_keyok(n) || n.h.length === 11);
+ const s = e && !n.fv && (showSen || !mega.sensitives.isSensitive(n));
+ if (s && (!customFilterFn || customFilterFn(n)) && (!filterFunc || filterFunc(n))) {
+ entries.push(n);
+ }
+ }
+ if (sortBy[0] === "name") {
+ sortFunc = M.getSortByNameFn();
+ } else if (sortBy[0] === "size") {
+ sortFunc = M.getSortBySizeFn();
+ } else if (sortBy[0] === "ts") {
+ sortFunc = M.getSortByDateTimeFn();
+ } else if (sortBy[0] === "rts") {
+ sortFunc = M.getSortByRtsFn();
+ } else if (sortBy[0] === "status") {
+ sortFunc = M.getSortByStatusFn();
+ } else if (sortBy[0] === "interaction") {
+ sortFunc = M.getSortByInteractionFn();
+ } else if (sortBy[0] === "verification") {
+ sortFunc = M.getSortByVerificationFn();
+ } else if (sortBy[0] === "email") {
+ sortFunc = M.getSortByEmail();
+ } else if (sortBy[0] === 'access') {
+ sortFunc = (a, b, o) => typeof a.r !== 'undefined' && typeof b.r !== 'undefined' && (a.r < b.r ? -1 : 1) * o;
+ } else {
+ sortFunc = M.sortByFavFn(order);
+ }
+ const folders = [];
+ if (this.props.sortFoldersFirst) {
+ for (let i = entries.length; i--;) {
+ if (entries[i] && entries[i].t) {
+ folders.unshift(entries[i]);
+ entries.splice(i, 1);
+ }
+ }
+ }
+ folders.sort((a, b) => {
+ return sortFunc(a, b, order);
+ });
+ entries.sort((a, b) => {
+ return sortFunc(a, b, order);
+ });
+ return folders.concat(entries);
+ }
+ onHighlighted(nodes) {
+ this.setState({
+ 'highlighted': nodes
+ });
+ if (this.props.onHighlighted) {
+ this.props.onHighlighted(nodes);
+ }
+ }
+ finishedLoading(newState) {
+ newState.isLoading = false;
+ newState.entries = this.getEntries();
+ this.initSelectionManager(newState.entries);
+ this.setState(newState);
+ }
+ addOrUpdRawListener() {
+ if (this._rawListener) {
+ mBroadcaster.removeListener(this._rawListener);
+ }
+ this._rawListener = mBroadcaster.addListener(`fmViewUpdate:${ this.props.currentlyViewedEntry}`, () => {
+ this.setState({
+ 'entries': this.getEntries()
+ }, () => {
+ if (this.browserEntries.isMounted()) {
+ this.browserEntries.forceUpdate();
+ }
+ });
+ });
+ }
+ componentDidMount() {
+ let _this$dataSource2;
+ super.componentDidMount();
+ if (!((_this$dataSource2 = this.dataSource) != null && _this$dataSource2.addChangeListener)) {
+ this.addOrUpdRawListener();
+ }
+ if (this.props.fmConfigSortEnabled) {
+ this._sortModeListener = mBroadcaster.addListener("fmconfig:sortmodes", sortModes => {
+ this.onFmConfigSortModeChanged(sortModes);
+ });
+ }
+ }
+ componentDidUpdate(prevProps) {
+ const {
+ currentlyViewedEntry: currEntry,
+ searchValue: currSearch
+ } = this.props;
+ const {
+ currentlyViewedEntry: prevEntry,
+ searchValue: prevSearch
+ } = prevProps;
+ const dataSourceChanged = this.props.dataSource !== prevProps.dataSource;
+ if (dataSourceChanged || prevEntry !== currEntry || currSearch !== prevSearch) {
+ let _this$dataSource3;
+ this.dataSource = this.props.dataSource;
+ const newState = {
+ 'selected': [],
+ 'highlighted': []
+ };
+ if (!((_this$dataSource3 = this.dataSource) != null && _this$dataSource3.addChangeListener)) {
+ this.addOrUpdRawListener();
+ }
+ const handle = currEntry;
+ if (handle === 'shares') {
+ newState.isLoading = true;
+ this.setState(newState);
+ dbfetch.geta(Object.keys(M.c.shares || {})).always(() => {
+ this.finishedLoading(newState);
+ });
+ return;
+ }
+ if (this.getDataSourceNode(handle).t && !M.getChildren(handle)) {
+ this.setState({
+ 'isLoading': true
+ });
+ dbfetch.get(handle).always(() => {
+ this.finishedLoading(newState);
+ });
+ return;
+ }
+ const entries = this.getEntries();
+ this.initSelectionManager(entries);
+ this.setState({
+ entries
+ });
+ }
+ }
+ onAttachClicked() {
+ this.props.onAttachClicked();
+ }
+ onContextMenu() {}
+ componentWillUnmount() {
+ super.componentWillUnmount();
+ if (this._listener) {
+ let _this$dataSource4;
+ (_this$dataSource4 = this.dataSource) == null || _this$dataSource4.removeChangeListener(this._listener);
+ }
+ if (this._rawListener) {
+ mBroadcaster.removeListener(this._rawListener);
+ }
+ if (this._sortModeListener) {
+ mBroadcaster.removeListener(this._sortModeListener);
+ }
+ $.selected = [];
+ this.selectionManager.destroy();
+ this.selectionManager = undefined;
+ $('.dropdown.body.files-menu.context').css('z-index', '');
+ }
+ onSortByChanged(newState) {
+ if (newState[0] === this.state.sortBy[0] && newState[1] === this.state.sortBy[1]) {
+ return;
+ }
+ const entries = this.getEntries({
+ 'sortBy': newState
+ });
+ this.setState({
+ 'sortBy': newState,
+ entries,
+ 'selected': [],
+ 'highlighted': []
+ }, () => {
+ if (this.props.onSortByChanged) {
+ this.props.onSortByChanged(newState);
+ }
+ if (this.props.fmConfigSortEnabled) {
+ const sortId = this.props.fmConfigSortId;
+ assert(sortId, 'fmConfigSortId missing');
+ if (newState[0] === this.props.initialSortBy[0] && newState[1] === this.props.initialSortBy[1]) {
+ const sortModes = typeof fmconfig.sortmodes !== 'undefined' ? fmconfig.sortmodes : Object.create(null);
+ delete sortModes[sortId];
+ mega.config.set('sortmodes', sortModes);
+ return;
+ }
+ const map = this.props.fmConfigSortMap || Object.create(null);
+ const name = map[newState[0]] || newState[0];
+ const direction = newState[1] === "asc" ? 1 : -1;
+ fmsortmode(sortId, name, direction);
+ }
+ });
+ this.initSelectionManager(entries);
+ }
+ onFmConfigSortModeChanged(sortModes) {
+ const currentSortMode = sortModes[this.props.fmConfigSortId];
+ if (!currentSortMode) {
+ this.onSortByChanged(this.props.initialSortBy || ['name', 'asc']);
+ } else {
+ const newSortMode = this._translateFmConfigSortMode(currentSortMode);
+ if (this.state.sortBy[0] !== newSortMode[0] || this.state.sortBy[1] !== newSortMode[1]) {
+ this.onSortByChanged(newSortMode);
+ }
+ }
+ }
+ render() {
+ return JSX_("div", {
+ ref: this.domRef,
+ className: "content-container",
+ onClick: ev => {
+ $.hideContextMenu(ev);
+ }
+ }, JSX_(BrowserEntries, {
+ isLoading: this.state.isLoading || this.props.nodeLoading,
+ currentlyViewedEntry: this.props.currentlyViewedEntry,
+ entries: this.state.entries || [],
+ onExpand: node => {
+ this.setState({
+ 'selected': [],
+ 'highlighted': []
+ });
+ this.props.onExpand(node[this.props.keyProp || 'h']);
+ },
+ sortBy: this.state.sortBy,
+ folderSelectNotAllowed: this.props.folderSelectNotAllowed,
+ onAttachClicked: this.onAttachClicked,
+ viewMode: this.props.viewMode,
+ selected: this.state.selected,
+ highlighted: this.state.highlighted,
+ onContextMenu: this.props.onContextMenu || this.onContextMenu,
+ selectionManager: this.selectionManager,
+ ref: browserEntries => {
+ this.browserEntries = browserEntries;
+ },
+ onSortByChanged: newState => {
+ this.onSortByChanged(newState);
+ },
+ listAdapterColumns: this.props.listAdapterColumns,
+ currentdirid: this.props.currentdirid,
+ containerClassName: this.props.containerClassName,
+ headerContainerClassName: this.props.headerContainerClassName,
+ megaListItemHeight: this.props.megaListItemHeight,
+ keyProp: this.props.keyProp || 'h',
+ NilComponent: this.props.NilComponent,
+ listAdapterOpts: this.props.listAdapterOpts
+ }));
+ }
+}
+
+ },
+
+ 6794
+(_, EXP_, REQ_) {
+
+ REQ_.d(EXP_, {
+ $: () => ColumnFavIcon
+ });
+ const react0__ = REQ_(1594);
+ const react0___default = REQ_.n(react0__);
+ const _genericNodePropsComponent1__ = REQ_(4285);
+
+
+class ColumnFavIcon extends _genericNodePropsComponent1__ .B {
+ render() {
+ const {
+ nodeAdapter
+ } = this.props;
+ const {
+ node
+ } = nodeAdapter.props;
+ const isFavouritable = node.r === 2;
+ return JSX_("td", {
+ megatype: ColumnFavIcon.megatype,
+ className: ColumnFavIcon.megatype
+ }, JSX_("span", {
+ className: `grid-status-icon sprite-fm-mono ${ missingkeys[node.h] ? " icon-info" : nodeAdapter.nodeProps.fav ? " icon-favourite-filled" : " icon-dot" }${!isFavouritable && " disabled" || ""}`,
+ onClick: () => {
+ if (isFavouritable) {
+ M.favourite([node.h], !node.fav);
+ }
+ }
+ }));
+ }
+}
+ColumnFavIcon.sortable = true;
+ColumnFavIcon.id = "fav";
+ColumnFavIcon.label = "";
+ColumnFavIcon.icon = "icon-favourite-filled";
+ColumnFavIcon.megatype = "fav";
+ColumnFavIcon.headerClassName = "grid-first-th fav";
+
+ },
+
+ 4285
+(_, EXP_, REQ_) {
+
+
+// EXPORTS
+REQ_.d(EXP_, {
+ B: () => GenericNodePropsComponent
+});
+
+// EXTERNAL MODULE: ./js/chat/mixins.js
+const mixins = REQ_(8264);
+;// ./js/ui/jsx/fm/nodes/nodeProperties.jsx
+class NodeProperties {
+ static get(node, changeListener) {
+ assert(node.h, 'missing handle for node');
+ if (NodeProperties._globalCleanupTimer) {
+ NodeProperties._globalCleanupTimer.abort();
+ }
+ (NodeProperties._globalCleanupTimer = tSleep(120)).then(() => {
+ NodeProperties.cleanup(0);
+ });
+ let nodeProps;
+ if (!NodeProperties._cache.has(node.h)) {
+ nodeProps = new NodeProperties(node, changeListener);
+ NodeProperties._cache.set(node.h, nodeProps);
+ }
+ return nodeProps || NodeProperties._cache.get(node.h);
+ }
+ unuse(changeListener) {
+ const {node} = this;
+ if (!node) {
+ if (d) {
+ console.warn("This should not happen.");
+ }
+ return;
+ }
+ this.changeListeners.delete(changeListener);
+ let usages = NodeProperties._usages.get(this);
+ if (usages) {
+ NodeProperties._usages.set(this, --usages);
+ if (usages === 0 && NodeProperties._cache.size > NodeProperties.MAX_CACHE_SIZE) {
+ delay('nodePropCleanup', NodeProperties.cleanup, 1000);
+ }
+ }
+ }
+ static cleanup(maxCacheSize) {
+ maxCacheSize = typeof maxCacheSize === "undefined" ? NodeProperties.MAX_CACHE_SIZE : maxCacheSize;
+ const len = NodeProperties._cache.size;
+ let removed = 0;
+ for (const entry of NodeProperties._cache) {
+ const id = entry[0];
+ const node = entry[1];
+ const usage = NodeProperties._usages.get(node);
+ if (usage === 0) {
+ NodeProperties._usages.delete(node);
+ node._cleanup();
+ NodeProperties._cache.delete(id);
+ removed++;
+ if (len - removed < maxCacheSize) {
+ return;
+ }
+ }
+ }
+ }
+ constructor(node, changeListener) {
+ this.node = node;
+ this.changeListeners = new Set();
+ if (changeListener) {
+ this.changeListeners.add(changeListener);
+ }
+ const _onChange = () => {
+ this.initProps();
+ for (const listener of this.changeListeners) {
+ listener();
+ }
+ };
+ if (this.node.addChangeListener) {
+ this._listener = this.node.addChangeListener(_onChange);
+ } else {
+ this._mbListener = mBroadcaster.addListener(`nodeUpdated:${ node.h}`, _onChange);
+ }
+ this.initProps();
+ }
+ use(changeListener) {
+ if (changeListener) {
+ this.changeListeners.add(changeListener);
+ }
+ NodeProperties._usages.set(this, (NodeProperties._usages.get(this) | 0) + 1);
+ }
+ _cleanup() {
+ if (this._listener) {
+ this.node.removeChangeListener(this._listener);
+ }
+ if (this._mbListener) {
+ mBroadcaster.removeListener(this._mbListener);
+ }
+ oDestroy(this);
+ }
+ initProps() {
+ const {node} = this;
+ lazy(this, 'title', () => {
+ if (missingkeys[node.h]) {
+ return node.t ? l[8686] : l[8687];
+ }
+ return M.getNameByHandle(node.h);
+ });
+ lazy(this, 'classNames', () => {
+ const classNames = [];
+ if (node.su) {
+ classNames.push('inbound-share');
+ }
+ if (node.t) {
+ classNames.push('folder');
+ } else {
+ classNames.push('file');
+ }
+ const share = this.shareData;
+ if (missingkeys[node.h] || share.down) {
+ if (share.down) {
+ classNames.push('taken-down');
+ }
+ if (missingkeys[node.h]) {
+ classNames.push('undecryptable');
+ }
+ }
+ if (share) {
+ classNames.push('linked');
+ }
+ if (node.lbl && !folderlink) {
+ const colourLabel = M.getLabelClassFromId(node.lbl);
+ classNames.push('colour-label');
+ classNames.push(colourLabel);
+ }
+ return classNames;
+ });
+ lazy(this, 'icon', () => {
+ return fileIcon(node);
+ });
+ lazy(this, 'isFolder', () => {
+ return !!node.t;
+ });
+ lazy(this, 'shareData', () => {
+ return M.getNodeShare(node);
+ });
+ lazy(this, 'isTakendown', () => {
+ return this.shareData && !!this.shareData.down;
+ });
+ lazy(this, 'fav', () => {
+ return !!node.fav;
+ });
+ lazy(this, 'size', () => {
+ return bytesToSize(node.tb || node.s);
+ });
+ lazy(this, 'timestamp', () => {
+ return time2date(node.ts);
+ });
+ lazy(this, 'root', () => {
+ return M.getNodeRoot(node.h);
+ });
+ lazy(this, 'incomingShareData', () => {
+ const result = {};
+ if (node.r === 1) {
+ result.accessLabel = l[56];
+ result.accessIcon = 'icon-permissions-write';
+ } else if (node.r === 2) {
+ result.accessLabel = l[57];
+ result.accessIcon = 'icon-star';
+ } else {
+ result.accessLabel = l[55];
+ result.accessIcon = 'icon-read-only';
+ }
+ return result;
+ });
+ lazy(this, 'timestamp', () => {
+ return time2date(node.ts);
+ });
+ lazy(this, 'onlineStatus', () => {
+ return M.onlineStatusClass(node.presence ? node.presence : "unavailable");
+ });
+ }
+}
+NodeProperties._cache = new Map();
+NodeProperties._usages = new WeakMap();
+NodeProperties._globalCleanupTimer = void 0;
+NodeProperties.MAX_CACHE_SIZE = 100;
+if (d) {
+ window.NodeProperties = NodeProperties;
+}
+;// ./js/ui/jsx/fm/nodes/genericNodePropsComponent.jsx
+
+
+class GenericNodePropsComponent extends mixins.w9 {
+ constructor(props) {
+ super(props);
+ if (this.props.node.h) {
+ this.nodeProps = NodeProperties.get(this.props.node);
+ this.changeListener = this.changeListener.bind(this);
+ }
+ }
+ changeListener() {
+ if (this.isMounted()) {
+ this.safeForceUpdate();
+ }
+ }
+ UNSAFE_componentWillReceiveProps(nextProps) {
+ if (nextProps.highlighted !== this.props.highlighted) {
+ this.safeForceUpdate();
+ }
+ }
+ UNSAFE_componentWillMount() {
+ let _this$nodeProps;
+ if (super.UNSAFE_componentWillMount) {
+ super.UNSAFE_componentWillMount();
+ }
+ (_this$nodeProps = this.nodeProps) == null || _this$nodeProps.use(this.changeListener);
+ }
+ componentWillUnmount() {
+ let _this$nodeProps2;
+ super.componentWillUnmount();
+ (_this$nodeProps2 = this.nodeProps) == null || _this$nodeProps2.unuse(this.changeListener);
+ }
+}
+
+ }
+
+}]);
\ No newline at end of file
diff --git a/js/chat/bundle.core-ui.js b/js/chat/bundle.core-ui.js
new file mode 100644
index 0000000000..67b4ce589b
--- /dev/null
+++ b/js/chat/bundle.core-ui.js
@@ -0,0 +1,11098 @@
+/** @file automatically generated, do not edit it. */
+"use strict";
+(self.webpackChunk_meganz_webclient = self.webpackChunk_meganz_webclient || []).push([[493],{
+
+ 8491
+(_, EXP_, REQ_) {
+
+REQ_.r(EXP_);
+ REQ_.d(EXP_, {
+ "default": () => ChatToaster
+ });
+ const react0__ = REQ_(1594);
+ const react0___default = REQ_.n(react0__);
+ const _mixins1__ = REQ_(8264);
+ const _meetings_utils_jsx2__ = REQ_(3901);
+ const _ui_buttons3__ = REQ_(5155);
+
+
+
+
+const NAMESPACE = 'chat-toast';
+class ChatToaster extends react0___default().Component {
+ constructor(props) {
+ super(props);
+ this.uid = `${this.constructor.name}--${(0,_mixins1__ .LP)()}`;
+ this.domRef = react0___default().createRef();
+ this.state = {
+ toast: null,
+ endTime: 0,
+ fmToastId: null,
+ persistentToast: null
+ };
+ this.toasts = [];
+ this.persistentToasts = [];
+ }
+ enqueueToast(e) {
+ if (this.props.showDualNotifications && e.data.options && e.data.options.persistent) {
+ this.persistentToasts.push(e.data);
+ } else {
+ this.toasts.push(e.data);
+ }
+ this.pollToasts();
+ }
+ pollToasts() {
+ const {
+ toast: shownToast,
+ persistentToast: shownPersistentToast
+ } = this.state;
+ const {
+ isRootToaster,
+ showDualNotifications,
+ onShownToast
+ } = this.props;
+ const now = Date.now();
+ if (this.toasts.length + this.persistentToasts.length) {
+ if (this.domRef.current && (!isRootToaster && (0,_meetings_utils_jsx2__ .Av)() || M.chat)) {
+ if (this.toasts.length && !shownToast) {
+ this.dispatchToast(this.toasts.shift(), now);
+ }
+ if (showDualNotifications && this.persistentToasts.length && !shownPersistentToast) {
+ const persistentToast = this.persistentToasts.shift();
+ this.setState({
+ persistentToast
+ }, () => this.pollToasts());
+ if (typeof onShownToast === 'function') {
+ onShownToast(persistentToast);
+ }
+ }
+ } else if (isRootToaster && this.toasts.length && !shownToast) {
+ const toast = this.toasts.shift();
+ this.dispatchToast(toast, now, {
+ fmToastId: 'tmp'
+ });
+ this.dispatchFMToast(toast);
+ }
+ }
+ }
+ dispatchFMToast(toast, redraw) {
+ window.toaster.alerts.medium(...toast.renderFM()).then(fmToastId => {
+ if (!redraw) {
+ toast.onShown(fmToastId);
+ }
+ this.setState({
+ fmToastId
+ });
+ if (toast.updater && typeof toast.updater === 'function') {
+ toast.updater();
+ toast.updateInterval = setInterval(() => {
+ toast.updater();
+ const value = toast.render();
+ if (!value) {
+ window.toaster.alerts.hide(fmToastId);
+ return this.onClose(toast.options && toast.options.persistent);
+ }
+ if (value !== $('span', `#${fmToastId}`).text()) {
+ $('span', `#${fmToastId}`).text(value);
+ }
+ }, 250);
+ }
+ });
+ }
+ dispatchToast(toast, now, options = {}) {
+ const {
+ fmToastId,
+ endTime,
+ silent
+ } = options;
+ const {
+ onShownToast,
+ onHideToast
+ } = this.props;
+ this.setState({
+ toast,
+ endTime: endTime || now + toast.getTTL(),
+ fmToastId
+ }, () => {
+ if (!silent) {
+ toast.onShown();
+ }
+ this.timeout = setTimeout(() => {
+ delete this.timeout;
+ this.setState({
+ toast: null,
+ endTime: 0
+ }, () => this.pollToasts());
+ if (typeof toast.onEnd === 'function') {
+ toast.onEnd();
+ }
+ if (typeof onHideToast === 'function') {
+ onHideToast(toast);
+ }
+ if (toast.updateInterval) {
+ clearInterval(toast.updateInterval);
+ delete toast.updateInterval;
+ }
+ }, endTime ? endTime - now : toast.getTTL());
+ });
+ if (typeof onShownToast === 'function') {
+ onShownToast(toast);
+ }
+ }
+ onClose(persistent) {
+ const {
+ showDualNotifications,
+ onHideToast
+ } = this.props;
+ const {
+ toast,
+ persistentToast
+ } = this.state;
+ if (showDualNotifications && persistent) {
+ if (typeof persistentToast.onEnd === 'function') {
+ persistentToast.onEnd();
+ }
+ this.setState({
+ persistentToast: null
+ }, () => this.pollToasts());
+ if (typeof onHideToast === 'function') {
+ onHideToast(persistentToast);
+ }
+ return;
+ }
+ if (toast.updateInterval) {
+ clearInterval(toast.updateInterval);
+ delete toast.updateInterval;
+ }
+ clearTimeout(this.timeout);
+ delete this.timeout;
+ if (typeof toast.onEnd === 'function') {
+ toast.onEnd();
+ }
+ if (typeof onHideToast === 'function') {
+ onHideToast(toast);
+ }
+ this.setState({
+ toast: null,
+ endTime: 0
+ }, () => this.pollToasts());
+ }
+ flush() {
+ const {
+ toast,
+ persistentToast,
+ fmToastId
+ } = this.state;
+ this.endToastIntervals();
+ if (fmToastId && fmToastId !== 'tmp') {
+ window.toaster.alerts.hide(fmToastId);
+ }
+ this.toasts = [];
+ this.persistentToasts = [];
+ if (this.timeout) {
+ clearTimeout(this.timeout);
+ delete this.timeout;
+ }
+ if (toast) {
+ this.onClose(toast.persistent);
+ }
+ if (persistentToast) {
+ this.onClose(true);
+ }
+ this.setState({
+ toast: null,
+ endTime: 0,
+ fmToastId: null,
+ persistentToast: null
+ });
+ }
+ endToastIntervals() {
+ if (!this.props.isRootToaster) {
+ return;
+ }
+ for (const toast of this.toasts) {
+ if (toast.updateInterval) {
+ clearInterval(toast.updateInterval);
+ }
+ }
+ for (const toast of this.persistentToasts) {
+ if (toast.updateInterval) {
+ clearInterval(toast.updateInterval);
+ }
+ }
+ }
+ componentDidMount() {
+ megaChat.rebind(`onChatToast.toaster${this.uid}`, e => this.enqueueToast(e));
+ megaChat.rebind(`onChatToastFlush.toaster${this.uid}`, () => this.flush());
+ onIdle(() => this.pollToasts());
+ if (this.props.isRootToaster) {
+ this.bpcListener = mBroadcaster.addListener('beforepagechange', tpage => {
+ const {
+ toast,
+ endTime,
+ fmToastId
+ } = this.state;
+ const now = Date.now();
+ if (toast && endTime - 500 > now) {
+ const toChat = tpage.includes('chat') && tpage !== 'securechat';
+ if (toChat && !M.chat) {
+ clearTimeout(this.timeout);
+ window.toaster.alerts.hide(fmToastId);
+ if (toast.updateInterval) {
+ clearInterval(toast.updateInterval);
+ delete toast.updateInterval;
+ }
+ this.dispatchToast(toast, now, {
+ endTime,
+ silent: true
+ });
+ } else if (!toChat && M.chat) {
+ clearTimeout(this.timeout);
+ this.dispatchToast(toast, now, {
+ fmToastId: 'tmp',
+ endTime,
+ silent: true
+ });
+ this.dispatchFMToast(toast, true);
+ }
+ } else if (toast && typeof toast.onEnd === 'function') {
+ toast.onEnd();
+ }
+ });
+ }
+ }
+ componentWillUnmount() {
+ megaChat.off(`onChatToast.toaster${this.uid}`);
+ megaChat.off(`onChatToastFlush.toaster${this.uid}`);
+ if (this.bpcListener) {
+ mBroadcaster.removeListener(this.bpcListener);
+ }
+ if (this.timeout) {
+ clearTimeout(this.timeout);
+ }
+ this.endToastIntervals();
+ }
+ render() {
+ const {
+ hidden,
+ isRootToaster,
+ showDualNotifications
+ } = this.props;
+ const {
+ toast,
+ fmToastId,
+ persistentToast
+ } = this.state;
+ return !hidden && !fmToastId && JSX_("div", {
+ ref: this.domRef,
+ className: `chat-toast-bar ${isRootToaster ? 'toaster-root' : ''}`
+ }, showDualNotifications && persistentToast && JSX_(ChatToastMsg, {
+ toast: persistentToast,
+ isRootToaster,
+ usePersistentStyle: true,
+ onClose: p => this.onClose(p)
+ }), toast && JSX_(ChatToastMsg, {
+ toast,
+ isRootToaster,
+ isDualToast: !!persistentToast,
+ onClose: p => this.onClose(p)
+ }));
+ }
+}
+class ChatToastMsg extends react0___default().Component {
+ constructor(...args) {
+ super(...args);
+ this.state = {
+ value: ''
+ };
+ }
+ componentDidMount() {
+ const {
+ toast,
+ onClose
+ } = this.props;
+ if (toast.updater && typeof toast.updater === 'function') {
+ toast.updater();
+ this.updateInterval = setInterval(() => {
+ toast.updater();
+ const value = toast.render();
+ if (!value) {
+ return onClose(toast.options && toast.options.persistent);
+ }
+ if (value !== this.state.value) {
+ this.setState({
+ value
+ });
+ }
+ }, 250);
+ }
+ const value = toast.render();
+ if (value) {
+ this.setState({
+ value
+ });
+ } else {
+ onClose(toast.options && toast.options.persistent);
+ }
+ }
+ componentWillUnmount() {
+ if (this.updateInterval) {
+ clearInterval(this.updateInterval);
+ }
+ }
+ render() {
+ const {
+ toast,
+ isRootToaster,
+ isDualToast,
+ usePersistentStyle,
+ onClose
+ } = this.props;
+ const {
+ value
+ } = this.state;
+ if (usePersistentStyle && toast.options.persistent) {
+ return JSX_("div", {
+ className: `${NAMESPACE} chat-persistent-toast`
+ }, value || toast.render());
+ }
+ const closeButton = toast.close && JSX_(_ui_buttons3__ .$, {
+ className: "chat-toast-close",
+ icon: "sprite-fm-mono icon-close-component",
+ onClick: onClose
+ });
+ const icon = toast.icon && JSX_("i", {
+ className: toast.icon
+ });
+ if (isRootToaster) {
+ return JSX_("div", {
+ className: `${NAMESPACE} chat-toast-wrapper root-toast`
+ }, JSX_("div", {
+ className: "toast-value-wrapper"
+ }, icon, JSX_("div", {
+ className: "toast-value"
+ }, value || toast.render())), closeButton);
+ }
+ return JSX_("div", {
+ className: `${NAMESPACE} chat-toast-wrapper theme-light-forced ${isDualToast ? 'dual-toast' : ''}`
+ }, JSX_("div", {
+ className: "toast-value"
+ }, value || toast.render()));
+ }
+}
+
+ },
+
+ 2558
+(_, EXP_, REQ_) {
+
+
+// EXPORTS
+REQ_.d(EXP_, {
+ A: () => composedTextArea
+});
+
+// EXTERNAL MODULE: external "React"
+const external_React_ = REQ_(1594);
+const REaCt = REQ_.n(external_React_);
+;// ./js/chat/ui/whosTyping.jsx
+
+class WhosTyping extends REaCt().Component {
+ constructor(...args) {
+ super(...args);
+ this.domRef = REaCt().createRef();
+ this.state = {
+ currentlyTyping: {}
+ };
+ }
+ componentDidMount() {
+ const {
+ chatRoom
+ } = this.props;
+ chatRoom.rebind('onParticipantTyping.whosTyping', (e, user_handle, bCastCode) => {
+ if (user_handle === u_handle) {
+ return;
+ }
+ const u_h = user_handle;
+ if (u_h === u_handle) {
+ return;
+ } else if (!M.u[u_h]) {
+ return;
+ }
+ const currentlyTyping = {
+ ...this.state.currentlyTyping
+ };
+ if (currentlyTyping[u_h]) {
+ currentlyTyping[u_h].abort();
+ }
+ if (bCastCode === 1) {
+ const timer = tSleep(5);
+ timer.then(() => {
+ this.stoppedTyping(u_h);
+ });
+ currentlyTyping[u_h] = timer;
+ this.setState({
+ currentlyTyping
+ });
+ } else {
+ this.stoppedTyping(u_h);
+ }
+ this.forceUpdate();
+ });
+ }
+ componentWillUnmount() {
+ this.props.chatRoom.off('onParticipantTyping.whosTyping');
+ }
+ stoppedTyping(u_h) {
+ if (this.domRef.current) {
+ const {
+ currentlyTyping
+ } = this.state;
+ if (currentlyTyping[u_h]) {
+ const newState = {
+ ...currentlyTyping
+ };
+ if (!newState[u_h].aborted) {
+ newState[u_h].abort();
+ }
+ delete newState[u_h];
+ this.setState({
+ currentlyTyping: newState
+ });
+ }
+ }
+ }
+ render() {
+ const users = Object.keys(this.state.currentlyTyping);
+ if (users.length > 0) {
+ const names = users.map(u_h => M.getNameByHandle(u_h)).filter(String);
+ let namesDisplay = "";
+ let areMultipleUsersTyping = false;
+ if (names.length > 1) {
+ areMultipleUsersTyping = true;
+ namesDisplay = [names.splice(0, names.length - 1).join(", "), names[0]];
+ } else {
+ areMultipleUsersTyping = false;
+ namesDisplay = [names[0]];
+ }
+ return JSX_("div", {
+ ref: this.domRef,
+ className: "typing-block"
+ }, JSX_("div", {
+ className: "typing-text"
+ }, areMultipleUsersTyping ? l[8872].replace("%1", namesDisplay[0]).replace("%2", namesDisplay[1]) : l[8629].replace("%1", namesDisplay[0])), JSX_("div", {
+ className: "typing-bounce"
+ }, JSX_("div", {
+ className: "typing-bounce1"
+ }), JSX_("div", {
+ className: "typing-bounce2"
+ }), JSX_("div", {
+ className: "typing-bounce3"
+ })));
+ }
+ return null;
+ }
+}
+// EXTERNAL MODULE: ./js/chat/ui/typingArea.jsx + 5 modules
+const typingArea = REQ_(4762);
+// EXTERNAL MODULE: ./js/ui/buttons.jsx
+const buttons = REQ_(5155);
+// EXTERNAL MODULE: ./js/ui/dropdowns.jsx
+const dropdowns = REQ_(1510);
+;// ./js/chat/ui/composedTextArea.jsx
+
+
+
+
+
+const ComposedTextArea = ({
+ chatRoom,
+ parent,
+ containerRef,
+ typingAreaText,
+ onTypingAreaChanged
+}) => JSX_("div", {
+ className: "chat-textarea-block"
+}, JSX_(WhosTyping, {
+ chatRoom
+}), JSX_(typingArea.T, {
+ chatRoom,
+ className: "main-typing-area",
+ containerRef,
+ disabled: chatRoom.isReadOnly(),
+ persist: true,
+ text: typingAreaText,
+ onValueChanged: onTypingAreaChanged,
+ onUpEditPressed: () => {
+ const keys = chatRoom.messagesBuff.messages.keys();
+ for (let i = keys.length; i--;) {
+ const message = chatRoom.messagesBuff.messages[keys[i]];
+ const contact = M.u[message.userId];
+ if (!contact) {
+ continue;
+ }
+ if (message.isEditable() && !message.requiresManualRetry && !message.deleted && (!message.type || message instanceof Message) && (!message.isManagement || !message.isManagement())) {
+ parent.historyPanel.editMessage(message.messageId);
+ return true;
+ }
+ }
+ return false;
+ },
+ onResized: () => {
+ parent.historyPanel.handleWindowResize();
+ },
+ onConfirm: messageContents => {
+ const {
+ messagesListScrollable
+ } = parent.historyPanel;
+ if (messageContents && messageContents.length > 0) {
+ if (!chatRoom.scrolledToBottom) {
+ chatRoom.scrolledToBottom = true;
+ parent.lastScrollPosition = 0;
+ chatRoom.rebind('onMessagesBuffAppend.pull', () => {
+ if (messagesListScrollable) {
+ messagesListScrollable.scrollToBottom(false);
+ delay('messagesListScrollable', () => {
+ messagesListScrollable.enable();
+ }, 1500);
+ }
+ });
+ chatRoom.sendMessage(messageContents);
+ messagesListScrollable == null || messagesListScrollable.disable();
+ messagesListScrollable == null || messagesListScrollable.scrollToBottom(true);
+ } else {
+ chatRoom.sendMessage(messageContents);
+ }
+ }
+ }
+}, JSX_(buttons.$, {
+ className: "popup-button left",
+ icon: "sprite-fm-mono icon-add",
+ disabled: chatRoom.isReadOnly()
+}, JSX_(dropdowns.ms, {
+ className: "wide-dropdown attach-to-chat-popup light",
+ noArrow: "true",
+ positionMy: "left top",
+ positionAt: "left bottom",
+ vertOffset: 4,
+ wrapper: "#fmholder"
+}, JSX_("div", {
+ className: "dropdown info-txt"
+}, l[23753] || 'Send...'), JSX_(dropdowns.tJ, {
+ className: "link-button",
+ icon: "sprite-fm-mono icon-cloud",
+ label: l[19794] || 'My Cloud Drive',
+ disabled: mega.paywall,
+ onClick: () => chatRoom.trigger('openAttachCloudDialog')
+}), JSX_(dropdowns.tJ, {
+ className: "link-button",
+ icon: "sprite-fm-mono icon-session-history",
+ label: l[19795] || 'My computer',
+ disabled: mega.paywall,
+ onClick: () => chatRoom.uploadFromComputer()
+}), !is_eplusplus && !is_chatlink && !chatRoom.isNote && JSX_(REaCt().Fragment, null, JSX_("hr", null), JSX_(dropdowns.tJ, {
+ className: "link-button",
+ icon: "sprite-fm-mono icon-send-contact",
+ label: l.share_contact_button,
+ onClick: () => chatRoom.trigger('openSendContactDialog')
+}))))));
+ const composedTextArea = ComposedTextArea;
+
+ },
+
+ 5677
+(_, EXP_, REQ_) {
+
+
+// EXPORTS
+REQ_.d(EXP_, {
+ ConversationPanels: () => ConversationPanels,
+ e: () => allContactsInChat,
+ z: () => excludedParticipants
+});
+
+// EXTERNAL MODULE: ./node_modules/@babel/runtime/helpers/esm/applyDecoratedDescriptor.js
+const applyDecoratedDescriptor = REQ_(793);
+// EXTERNAL MODULE: ./node_modules/@babel/runtime/helpers/esm/extends.js
+const esm_extends = REQ_(8168);
+// EXTERNAL MODULE: external "React"
+const external_React_ = REQ_(1594);
+const REaCt = REQ_.n(external_React_);
+// EXTERNAL MODULE: ./js/ui/utils.jsx
+const utils = REQ_(6411);
+// EXTERNAL MODULE: ./js/chat/mixins.js
+const mixins = REQ_(8264);
+// EXTERNAL MODULE: ./js/ui/buttons.jsx
+const buttons = REQ_(5155);
+// EXTERNAL MODULE: ./js/ui/modalDialogs.jsx + 1 modules
+const modalDialogs = REQ_(8120);
+// EXTERNAL MODULE: ./js/ui/dropdowns.jsx
+const ui_dropdowns = REQ_(1510);
+// EXTERNAL MODULE: ./js/chat/ui/contacts.jsx
+const ui_contacts = REQ_(8022);
+// EXTERNAL MODULE: ./js/chat/chatRoom.jsx
+const chat_chatRoom = REQ_(7057);
+;// ./js/ui/historyRetentionDialog.jsx
+
+
+
+
+const LIMIT = {
+ CHARS: 2,
+ HOURS: 24,
+ DAYS: 31,
+ WEEKS: 4,
+ MONTHS: 12
+};
+class HistoryRetentionDialog extends external_React_.Component {
+ constructor(props) {
+ super(props);
+ this.dialogName = 'msg-retention-dialog';
+ this.inputRef = REaCt().createRef();
+ this.state = {
+ selectedTimeFormat: chat_chatRoom.zd.HOURS,
+ timeRange: undefined
+ };
+ this.handleRadioChange = e => {
+ const selectedTimeFormat = e.target.value;
+ this.setState(prevState => ({
+ selectedTimeFormat,
+ timeRange: this.filterTimeRange(prevState.timeRange, selectedTimeFormat)
+ }));
+ };
+ this.handleOnTimeCheck = e => {
+ const checkingValue = e.type === 'paste' ? e.clipboardData.getData('text') : e.key;
+ if (e.keyCode !== 8 && isNaN(checkingValue)) {
+ e.preventDefault();
+ }
+ };
+ this.handleOnTimeChange = e => {
+ const timeValue = e.target.value;
+ this.setState(prevState => ({
+ timeRange: this.filterTimeRange(timeValue, prevState.selectedTimeFormat)
+ }));
+ };
+ const {
+ chatRoom
+ } = props;
+ this.state.timeRange = chatRoom.getRetentionTimeFormatted();
+ if (this.state.timeRange === 0) {
+ this.state.timeRange = '';
+ }
+ this.state.selectedTimeFormat = chatRoom.getRetentionFormat();
+ this.state.selectedTimeFormat = this.state.selectedTimeFormat === chat_chatRoom.zd.DISABLED ? chat_chatRoom.zd.HOURS : this.state.selectedTimeFormat;
+ }
+ hasInput() {
+ return this.state.timeRange && parseInt(this.state.timeRange, 10) >= 1;
+ }
+ getMaxTimeRange(selectedTimeFormat) {
+ switch (selectedTimeFormat) {
+ case chat_chatRoom.zd.HOURS:
+ return LIMIT.HOURS;
+ case chat_chatRoom.zd.DAYS:
+ return LIMIT.DAYS;
+ case chat_chatRoom.zd.WEEKS:
+ return LIMIT.WEEKS;
+ case chat_chatRoom.zd.MONTHS:
+ return LIMIT.MONTHS;
+ }
+ }
+ getParsedLabel(label, timeRange) {
+ timeRange = timeRange ? parseInt(timeRange, 10) : this.getMaxTimeRange(label);
+ switch (label) {
+ case chat_chatRoom.zd.HOURS:
+ return mega.icu.format(l.plural_hour, timeRange);
+ case chat_chatRoom.zd.DAYS:
+ return mega.icu.format(l.plural_day, timeRange);
+ case chat_chatRoom.zd.WEEKS:
+ return mega.icu.format(l.plural_week, timeRange);
+ case chat_chatRoom.zd.MONTHS:
+ return mega.icu.format(l.plural_month, timeRange);
+ }
+ }
+ filterTimeRange(timeRange, selectedTimeFormat) {
+ if (timeRange.length > LIMIT.CHARS) {
+ return timeRange.substring(0, LIMIT.CHARS);
+ }
+ timeRange = parseInt(timeRange, 10);
+ if (timeRange === 0 || isNaN(timeRange)) {
+ return '';
+ }
+ return Math.min(this.getMaxTimeRange(selectedTimeFormat), timeRange);
+ }
+ handleOnSubmit(e) {
+ if (!this.hasInput()) {
+ return;
+ }
+ e.preventDefault();
+ e.stopPropagation();
+ const {
+ chatRoom,
+ onClose
+ } = this.props;
+ const {
+ selectedTimeFormat,
+ timeRange
+ } = this.state;
+ let time = 0;
+ switch (selectedTimeFormat) {
+ case chat_chatRoom.zd.HOURS:
+ time = hoursToSeconds(Number(timeRange));
+ break;
+ case chat_chatRoom.zd.DAYS:
+ time = daysToSeconds(Number(timeRange));
+ break;
+ case chat_chatRoom.zd.WEEKS:
+ time = daysToSeconds(Number(timeRange) * 7);
+ break;
+ case chat_chatRoom.zd.MONTHS:
+ time = daysToSeconds(Number(timeRange) * 30);
+ break;
+ }
+ chatRoom.setRetention(time);
+ onClose();
+ }
+ renderCustomRadioButton() {
+ return [chat_chatRoom.zd.HOURS, chat_chatRoom.zd.DAYS, chat_chatRoom.zd.WEEKS, chat_chatRoom.zd.MONTHS].map(label => {
+ return JSX_(CustomRadioButton, {
+ checked: this.state.selectedTimeFormat === label,
+ label: this.getParsedLabel(label, this.state.timeRange),
+ name: "time-selector",
+ value: label,
+ onChange: this.handleRadioChange,
+ key: label
+ });
+ });
+ }
+ componentDidMount() {
+ M.safeShowDialog(this.dialogName, () => {
+ $(document.body).rebind('keydown.historyRetentionDialog', e => {
+ const key = e.keyCode || e.which;
+ if (key === 13) {
+ this.handleOnSubmit(e);
+ }
+ });
+ });
+ }
+ componentWillUnmount() {
+ $(document.body).off('keydown.historyRetentionDialog');
+ if ($.dialog === this.dialogName) {
+ closeDialog();
+ }
+ }
+ render() {
+ const {
+ chatRoom,
+ onClose
+ } = this.props;
+ const {
+ selectedTimeFormat,
+ timeRange
+ } = this.state;
+ return JSX_(modalDialogs.A.ModalDialog, (0,esm_extends.A)({}, this.state, {
+ chatRoom,
+ onClose,
+ dialogName: this.dialogName,
+ dialogType: "tool",
+ onClick: () => this.inputRef.current.focus()
+ }), JSX_("header", null, JSX_("h2", {
+ id: "msg-retention-dialog-title"
+ }, l[23434])), JSX_("section", {
+ className: "content"
+ }, JSX_("div", {
+ className: "content-block"
+ }, JSX_("p", null, l[23435])), JSX_("div", {
+ className: "content-block form"
+ }, JSX_("div", {
+ className: "form-section"
+ }, JSX_("span", {
+ className: "form-section-placeholder"
+ }, this.getParsedLabel(selectedTimeFormat, timeRange)), JSX_("input", {
+ type: "number",
+ min: "0",
+ step: "1",
+ max: this.getMaxTimeRange(selectedTimeFormat),
+ className: "form-section-time",
+ placeholder: this.getMaxTimeRange(selectedTimeFormat),
+ ref: this.inputRef,
+ autoFocus: true,
+ value: timeRange,
+ onChange: this.handleOnTimeChange,
+ onKeyPress: this.handleOnTimeCheck,
+ onPaste: this.handleOnTimeCheck
+ })), JSX_("div", {
+ className: "form-section"
+ }, JSX_("div", {
+ className: "form-section-radio"
+ }, this.renderCustomRadioButton())))), JSX_("footer", null, JSX_("div", {
+ className: "footer-container"
+ }, JSX_("button", {
+ className: "mega-button",
+ onClick: onClose
+ }, JSX_("span", null, l.msg_dlg_cancel)), JSX_("button", {
+ className: `
+ mega-button positive
+ ${this.hasInput() ? '' : 'disabled'}
+ `,
+ onClick: e => this.handleOnSubmit(e)
+ }, JSX_("span", null, l[726])))));
+ }
+}
+function CustomRadioButton({
+ checked = false,
+ label,
+ name,
+ value,
+ onChange
+}) {
+ return JSX_("label", {
+ key: value,
+ className: "radio-txt"
+ }, label, JSX_("div", {
+ className: `custom-radio small green-active ${ checked ? "radioOn" : "radioOff"}`
+ }, JSX_("input", {
+ type: "radio",
+ name,
+ value,
+ checked,
+ onChange
+ })));
+}
+// EXTERNAL MODULE: ./js/ui/perfectScrollbar.jsx
+const perfectScrollbar = REQ_(1301);
+;// ./js/ui/accordion.jsx
+
+
+class AccordionPanel extends mixins.w9 {
+ constructor(...args) {
+ super(...args);
+ this.domRef = REaCt().createRef();
+ }
+ render() {
+ const {
+ accordionClass,
+ expanded,
+ title,
+ className,
+ children,
+ onToggle
+ } = this.props;
+ return JSX_("div", {
+ ref: this.domRef,
+ className: `
+ chat-dropdown
+ container
+ ${accordionClass || ''}
+ `
+ }, JSX_("div", {
+ className: `
+ chat-dropdown
+ header
+ ${expanded ? 'expanded' : ''}
+ `,
+ onClick: onToggle
+ }, JSX_("span", null, title), JSX_("i", {
+ className: "sprite-fm-mono icon-arrow-down"
+ })), expanded ? JSX_("div", {
+ className: `
+ chat-dropdown
+ content
+ have-animation
+ ${className | ''}
+ `
+ }, children) : null);
+ }
+}
+class Accordion extends mixins.w9 {
+ constructor(...args) {
+ super(...args);
+ this.domRef = REaCt().createRef();
+ this.state = {
+ expandedPanel: this.props.expandedPanel
+ };
+ }
+ onToggle(e, key) {
+ const obj = {};
+ obj[key] = !(this.state.expandedPanel || {})[key];
+ this.setState({
+ 'expandedPanel': obj
+ });
+ this.props.onToggle && this.props.onToggle(key);
+ }
+ render() {
+ const self = this;
+ const classes = `accordion-panels ${ self.props.className ? self.props.className : ''}`;
+ const accordionPanels = [];
+ let x = 0;
+ REaCt().Children.forEach(self.props.children, child => {
+ if (!child) {
+ return;
+ }
+ if (child.type.name === 'AccordionPanel' || child.type.name && child.type.name.indexOf('AccordionPanel') > -1) {
+ accordionPanels.push(REaCt().cloneElement(child, {
+ key: child.key,
+ expanded: !!self.state.expandedPanel[child.key],
+ accordion: self,
+ onToggle (e) {
+ self.onToggle(e, child.key);
+ }
+ }));
+ } else {
+ accordionPanels.push(REaCt().cloneElement(child, {
+ key: x++,
+ accordion: self
+ }));
+ }
+ });
+ return JSX_("div", {
+ ref: this.domRef,
+ className: classes
+ }, accordionPanels);
+ }
+}
+
+;// ./js/chat/ui/participantsList.jsx
+
+
+
+
+
+class ParticipantsList extends mixins.w9 {
+ constructor(props) {
+ super(props);
+ this.domRef = REaCt().createRef();
+ this.state = {
+ 'scrollPositionY': 0,
+ 'scrollHeight': 144
+ };
+ this.doResizesOnComponentUpdate = SoonFc(10, function () {
+ let _self$domRef;
+ const self = this;
+ if (!self.isMounted()) {
+ return;
+ }
+ let fitHeight = self.contactsListScroll.getContentHeight();
+ if (!fitHeight) {
+ return null;
+ }
+ const $node = $((_self$domRef = self.domRef) == null ? void 0 : _self$domRef.current);
+ const $parentContainer = $node.closest('.chat-right-pad');
+ const maxHeight = $parentContainer.outerHeight(true) - $('.chat-right-head', $parentContainer).outerHeight(true) - 72;
+ if (fitHeight < $('.buttons-block', $parentContainer).outerHeight(true)) {
+ fitHeight = Math.max(fitHeight, 53);
+ } else if (maxHeight < fitHeight) {
+ fitHeight = Math.max(maxHeight, 53);
+ }
+ fitHeight = Math.min(self.calculateListHeight($parentContainer), fitHeight);
+ const $contactsList = $('.chat-contacts-list', $parentContainer);
+ if ($contactsList.height() !== fitHeight) {
+ $('.chat-contacts-list', $parentContainer).height(fitHeight);
+ if (self.contactsListScroll) {
+ self.contactsListScroll.reinitialise();
+ }
+ }
+ if (self.state.scrollHeight !== fitHeight) {
+ self.setState({
+ 'scrollHeight': fitHeight
+ });
+ }
+ self.onUserScroll();
+ });
+ }
+ onUserScroll() {
+ if (!this.contactsListScroll) {
+ return;
+ }
+ const scrollPosY = this.contactsListScroll.getScrollPositionY();
+ if (this.state.scrollPositionY !== scrollPosY) {
+ this.setState({
+ 'scrollPositionY': scrollPosY
+ });
+ }
+ }
+ calculateListHeight($parentContainer) {
+ const room = this.props.chatRoom;
+ return ($parentContainer ? $parentContainer : $('.conversationsApp')).outerHeight() - 144 - 10 - (room.type === "public" && room.observers > 0 ? 48 : 0) - (room.isReadOnly() ? 12 : 0);
+ }
+ componentDidUpdate() {
+ const self = this;
+ if (!self.isMounted()) {
+ return;
+ }
+ if (!self.contactsListScroll) {
+ return null;
+ }
+ self.doResizesOnComponentUpdate();
+ }
+ render() {
+ const {
+ chatRoom
+ } = this.props;
+ if (!chatRoom) {
+ return null;
+ }
+ return JSX_("div", {
+ ref: this.domRef,
+ className: "chat-contacts-list"
+ }, JSX_(perfectScrollbar.O, {
+ chatRoom,
+ members: chatRoom.members,
+ ref: ref => {
+ this.contactsListScroll = ref;
+ },
+ disableCheckingVisibility: true,
+ onUserScroll: SoonFc(this.onUserScroll.bind(this), 76),
+ requiresUpdateOnResize: true,
+ isVisible: chatRoom.isCurrentlyActive,
+ options: {
+ suppressScrollX: true
+ }
+ }, JSX_(ParticipantsListInner, {
+ chatRoom,
+ members: chatRoom.members,
+ scrollPositionY: this.state.scrollPositionY,
+ scrollHeight: this.state.scrollHeight,
+ disableCheckingVisibility: true
+ })));
+ }
+}
+ParticipantsList.defaultProps = {
+ 'requiresUpdateOnResize': true,
+ 'contactCardHeight': 36
+};
+class ParticipantsListInner extends mixins.w9 {
+ constructor(...args) {
+ super(...args);
+ this.domRef = REaCt().createRef();
+ }
+ render() {
+ const room = this.props.chatRoom;
+ const {contactCardHeight} = this.props;
+ const {scrollPositionY} = this.props;
+ const {scrollHeight} = this.props;
+ const {
+ OPERATOR,
+ FULL,
+ READONLY
+ } = ChatRoom.MembersSet.PRIVILEGE_STATE;
+ if (!room) {
+ return null;
+ }
+ if (!room.isCurrentlyActive) {
+ return false;
+ }
+ const contacts = room.getParticipantsExceptMe();
+ const contactsList = [];
+ const firstVisibleUserNum = Math.floor(scrollPositionY / contactCardHeight);
+ const visibleUsers = Math.ceil(scrollHeight / contactCardHeight);
+ const contactListInnerStyles = {
+ 'height': contacts.length * contactCardHeight
+ };
+ if ((room.type === "group" || room.type === "public") && !room.stateIsLeftOrLeaving() && room.members.hasOwnProperty(u_handle)) {
+ contacts.unshift(u_handle);
+ contactListInnerStyles.height += contactCardHeight;
+ }
+ const onRemoveClicked = contactHash => {
+ room.trigger('onRemoveUserRequest', [contactHash]);
+ };
+ const onSetPrivClicked = (contactHash, priv) => {
+ if (room.members[contactHash] !== priv) {
+ room.trigger('alterUserPrivilege', [contactHash, priv]);
+ }
+ };
+ for (let i = 0; i < contacts.length; i++) {
+ const contactHash = contacts[i];
+ if (!(contactHash in M.u)) {
+ continue;
+ }
+ const contact = M.u[contactHash];
+ if (i < firstVisibleUserNum || i > firstVisibleUserNum + visibleUsers) {
+ continue;
+ }
+ const dropdowns = [];
+ let dropdownIconClasses = "small-icon tiny-icon icons-sprite grey-dots";
+ const dropdownRemoveButton = [];
+ if (room.type === "public" || room.type === "group" && room.members) {
+ if (room.iAmOperator() && contactHash !== u_handle) {
+ dropdownRemoveButton.push(JSX_(ui_dropdowns.tJ, {
+ className: "red",
+ key: "remove",
+ icon: "sprite-fm-mono icon-disabled-filled",
+ label: l[8867],
+ onClick: onRemoveClicked.bind(this, contactHash)
+ }));
+ }
+ if (room.iAmOperator()) {
+ dropdowns.push(JSX_("div", {
+ key: "setPermLabel",
+ className: "dropdown-items-info"
+ }, l[8868]));
+ dropdowns.push(JSX_(ui_dropdowns.tJ, {
+ key: "privOperator",
+ icon: "sprite-fm-mono icon-admin-outline",
+ label: l[8875],
+ className: `
+ tick-item
+ ${room.members[contactHash] === OPERATOR ? 'active' : ''}
+ `,
+ disabled: contactHash === u_handle,
+ onClick: () => onSetPrivClicked(contactHash, OPERATOR)
+ }));
+ dropdowns.push(JSX_(ui_dropdowns.tJ, {
+ key: "privFullAcc",
+ icon: "sprite-fm-mono icon-chat",
+ className: `
+ tick-item
+ ${room.members[contactHash] === FULL ? 'active' : ''}
+ `,
+ disabled: contactHash === u_handle,
+ label: l[8874],
+ onClick: () => onSetPrivClicked(contactHash, FULL)
+ }));
+ dropdowns.push(JSX_(ui_dropdowns.tJ, {
+ key: "privReadOnly",
+ icon: "sprite-fm-mono icon-read-only",
+ className: `
+ tick-item
+ ${room.members[contactHash] === READONLY ? 'active' : ''}
+ `,
+ disabled: contactHash === u_handle,
+ label: l[8873],
+ onClick: () => onSetPrivClicked(contactHash, READONLY)
+ }));
+ }
+ const baseClassName = 'sprite-fm-mono';
+ switch (room.members[contactHash]) {
+ case OPERATOR:
+ dropdownIconClasses = `${baseClassName} icon-admin`;
+ break;
+ case FULL:
+ dropdownIconClasses = `${baseClassName} icon-chat-filled`;
+ break;
+ case READONLY:
+ dropdownIconClasses = `${baseClassName} icon-read-only`;
+ break;
+ default:
+ break;
+ }
+ contactsList.push(JSX_(ui_contacts.nB, {
+ key: contact.u,
+ contact,
+ chatRoom: room,
+ className: "right-chat-contact-card",
+ dropdownPositionMy: "left top",
+ dropdownPositionAt: "left top",
+ dropdowns,
+ dropdownDisabled: contactHash === u_handle || is_chatlink || is_eplusplus,
+ dropdownButtonClasses: "contacts-icon",
+ dropdownRemoveButton,
+ dropdownIconClasses,
+ noLoading: true,
+ isInCall: room.uniqueCallParts && room.uniqueCallParts[contactHash],
+ style: {
+ width: 234,
+ position: 'absolute',
+ top: i * contactCardHeight
+ }
+ }));
+ }
+ }
+ return JSX_("div", {
+ ref: this.domRef,
+ className: "chat-contacts-list-inner default-bg",
+ style: contactListInnerStyles
+ }, contactsList);
+ }
+}
+ParticipantsListInner.defaultProps = {
+ requiresUpdateOnResize: true,
+ contactCardHeight: 32,
+ scrollPositionY: 0,
+ scrollHeight: 128,
+ chatRoom: undefined
+};
+
+// EXTERNAL MODULE: ./js/chat/ui/messages/generic.jsx + 14 modules
+const generic = REQ_(8025);
+;// ./js/chat/ui/sharedFilesAccordionPanel.jsx
+
+let _dec, _class;
+
+
+
+class SharedFileItem extends mixins.u9 {
+ render() {
+ const self = this;
+ const {message} = this.props;
+ const contact = Message.getContactForMessage(message);
+ const name = M.getNameByHandle(contact.u);
+ const timestamp = time2date(message.delay);
+ const {node} = this.props;
+ const {icon} = this.props;
+ return JSX_("div", {
+ className: `chat-shared-block ${ self.props.isLoading ? "is-loading" : ""}`,
+ key: `${message.messageId }_${ node.h}`,
+ onClick: () => this.props.isPreviewable ? M.viewMediaFile(node) : M.addDownload([node]),
+ onDoubleClick: () => M.addDownload([node])
+ }, JSX_("div", {
+ className: `icon-or-thumb ${thumbnails.has(node.fa) ? "thumb" : ""}`
+ }, JSX_("div", {
+ className: `item-type-icon-90 icon-${icon}-90`
+ }), JSX_("div", {
+ className: "img-wrapper",
+ id: this.props.imgId
+ }, JSX_("img", {
+ alt: "",
+ src: thumbnails.get(node.fa) || ""
+ }))), JSX_("div", {
+ className: "chat-shared-info"
+ }, JSX_("span", {
+ className: "txt"
+ }, node.name), JSX_("span", {
+ className: "txt small"
+ }, JSX_(utils.zT, null, name)), JSX_("span", {
+ className: "txt small grey"
+ }, timestamp)));
+ }
+}
+const SharedFilesAccordionPanel = (_dec = utils.Ay.SoonFcWrap(350), _class = class SharedFilesAccordionPanel extends mixins.w9 {
+ constructor(...args) {
+ super(...args);
+ this.domRef = REaCt().createRef();
+ }
+ eventuallyRenderThumbnails() {
+ if (this.allShownNodes) {
+ const pending = [];
+ const nodes = new Map(this.allShownNodes);
+ const render = n => {
+ if (thumbnails.has(n.fa)) {
+ const src = thumbnails.get(n.fa);
+ const batch = [...nodes.get(n.fa)];
+ for (let i = batch.length; i--;) {
+ const n = batch[i];
+ let img = document.getElementById(`sharedFiles!${n.ch}`);
+ if (img && (img = img.querySelector('img'))) {
+ img.src = src;
+ if (img = Object(img.parentNode).parentNode) {
+ img.classList.add('thumb');
+ }
+ }
+ }
+ return true;
+ }
+ };
+ for (const [, [n]] of nodes) {
+ if (!render(n)) {
+ pending.push(n);
+ }
+ }
+ this.allShownNodes.clear();
+ if (pending.length) {
+ fm_thumbnails('standalone', pending, render);
+ }
+ }
+ }
+ UNSAFE_componentWillMount() {
+ this.allShownNodes = new MapSet();
+ }
+ componentWillUnmount() {
+ super.componentWillUnmount();
+ delete this.allShownNodes;
+ }
+ componentDidUpdate() {
+ this.eventuallyRenderThumbnails();
+ }
+ render() {
+ const self = this;
+ const room = self.props.chatRoom;
+ const mb = room.messagesBuff;
+ let contents = null;
+ let currentPage = mb.sharedFilesPage;
+ const startPos = currentPage * 12;
+ const endPos = startPos + 12;
+ let totalPages = mb.haveMoreSharedFiles ? "..." : Math.ceil(mb.sharedFiles.length / 12);
+ totalPages = mb.sharedFiles.length && !totalPages ? 1 : totalPages;
+ const haveMore = mb.haveMoreSharedFiles || currentPage + 1 < totalPages;
+ const files = [];
+ if (!mb.haveMoreSharedFiles && currentPage === totalPages) {
+ currentPage = mb.sharedFilesPage = Math.max(totalPages - 1, 0);
+ }
+ if (this.props.expanded) {
+ let prev = null;
+ let next = null;
+ if (currentPage > 0) {
+ prev = JSX_("div", {
+ className: "chat-share-nav button prev",
+ onClick () {
+ mb.sharedFilesPage--;
+ self.safeForceUpdate();
+ }
+ });
+ }
+ if (haveMore) {
+ next = JSX_("div", {
+ className: "chat-share-nav button next",
+ onClick () {
+ if (self.isLoadingMore) {
+ return;
+ }
+ if (mb.sharedFiles.length < endPos + 12) {
+ self.isLoadingMore = true;
+ mb.retrieveSharedFilesHistory(12).catch(dump).finally(() => {
+ self.isLoadingMore = false;
+ mb.sharedFilesPage++;
+ if (!mb.haveMoreSharedFiles && mb.sharedFilesPage > totalPages) {
+ mb.sharedFilesPage = totalPages - 1;
+ }
+ Soon(() => {
+ self.safeForceUpdate();
+ });
+ });
+ } else {
+ mb.sharedFilesPage++;
+ }
+ Soon(() => {
+ self.safeForceUpdate();
+ });
+ }
+ });
+ }
+ if (!mb.sharedFilesLoadedOnce) {
+ mb.retrieveSharedFilesHistory(12).then(() => this.safeForceUpdate()).catch(dump);
+ }
+ let sharedNodesContainer = null;
+ if (mb.isRetrievingSharedFiles && !self.isLoadingMore) {
+ sharedNodesContainer = JSX_("div", {
+ className: "chat-dropdown empty-txt loading-initial"
+ }, JSX_("div", {
+ className: "loading-spinner light small"
+ }, JSX_("div", {
+ className: "main-loader"
+ })));
+ } else if (!mb.haveMoreSharedFiles && !mb.sharedFiles.length) {
+ sharedNodesContainer = JSX_("div", {
+ className: "chat-dropdown empty-txt"
+ }, l[19985]);
+ } else {
+ const keys = clone(mb.sharedFiles.keys()).reverse();
+ for (let i = startPos; i < endPos; i++) {
+ var message = mb.sharedFiles[keys[i]];
+ if (!message) {
+ continue;
+ }
+ const nodes = message.getAttachmentMeta();
+ nodes.forEach((node) => {
+ const imgId = `sharedFiles!${ node.ch}`;
+ const {
+ icon,
+ showThumbnail,
+ isPreviewable
+ } = M.getMediaProperties(node);
+ files.push(JSX_(SharedFileItem, {
+ message,
+ key: `${node.h}_${message.messageId}`,
+ isLoading: self.isLoadingMore,
+ node,
+ icon,
+ imgId,
+ showThumbnail,
+ isPreviewable,
+ chatRoom: room,
+ contact: Message.getContactForMessage(message)
+ }));
+ if (showThumbnail) {
+ self.allShownNodes.set(node.fa, node);
+ }
+ });
+ }
+ sharedNodesContainer = JSX_("div", null, files);
+ }
+ contents = JSX_("div", {
+ className: "chat-dropdown content have-animation"
+ }, room.hasMessages() ? sharedNodesContainer : JSX_("div", {
+ className: "chat-dropdown empty-txt"
+ }, l[19985]), self.isLoadingMore ? JSX_("div", {
+ className: "loading-spinner light small"
+ }, JSX_("div", {
+ className: "main-loader"
+ })) : null, files.length > 0 ? JSX_("div", {
+ className: "chat-share-nav body"
+ }, prev, next, JSX_("div", {
+ className: "chat-share-nav pages"
+ }, (l[19988] ? l[19988] : "Page %1").replace("%1", currentPage + 1))) : null);
+ }
+ return JSX_("div", {
+ ref: this.domRef,
+ className: "chat-dropdown container"
+ }, JSX_("div", {
+ className: `
+ chat-dropdown
+ header
+ ${this.props.expanded ? 'expanded' : ''}
+ `,
+ onClick: this.props.onToggle
+ }, JSX_("span", null, this.props.title), JSX_("i", {
+ className: "sprite-fm-mono icon-arrow-down"
+ })), JSX_("div", {
+ className: `
+ chat-shared-files-container
+ ${this.isLoadingMore ? 'is-loading' : ''}
+ `
+ }, contents));
+ }
+}, (0,applyDecoratedDescriptor.A)(_class.prototype, "eventuallyRenderThumbnails", [_dec], Object.getOwnPropertyDescriptor(_class.prototype, "eventuallyRenderThumbnails"), _class.prototype), _class);
+
+;// ./js/chat/ui/incomingSharesAccordionPanel.jsx
+
+
+const SharedFolderItem = ({
+ node,
+ isLoading
+}) => {
+ return JSX_("div", {
+ key: node.h,
+ className: `
+ chat-shared-block
+ incoming
+ ${isLoading ? 'is-loading' : ''}
+ `,
+ onClick: () => M.openFolder(node.h),
+ onDoubleClick: () => M.openFolder(node.h)
+ }, JSX_("div", {
+ className: "item-type-icon-90 icon-folder-incoming-90"
+ }), JSX_("div", {
+ className: "chat-shared-info"
+ }, JSX_("span", {
+ className: "txt"
+ }, node.name), JSX_("span", {
+ className: "txt small"
+ }, fm_contains(node.tf, node.td))));
+};
+class IncSharesAccordionPanel extends mixins.w9 {
+ constructor(...args) {
+ super(...args);
+ this.domRef = REaCt().createRef();
+ }
+ UNSAFE_componentWillMount() {
+ this.hadLoaded = false;
+ }
+ getContactHandle() {
+ const self = this;
+ const room = self.props.chatRoom;
+ const contactHandle = room.getParticipantsExceptMe()[0];
+ if (!contactHandle || room.type !== "private") {
+ return {};
+ }
+ return contactHandle;
+ }
+ render() {
+ const self = this;
+ const room = self.props.chatRoom;
+ const contactHandle = self.getContactHandle();
+ let contents = null;
+ if (this.props.expanded) {
+ if (!this.hadLoaded) {
+ this.hadLoaded = true;
+ self.isLoadingMore = true;
+ dbfetch.geta(Object.keys(M.c.shares || {}), new MegaPromise()).always(() => {
+ self.isLoadingMore = false;
+ Soon(() => {
+ if (self.isComponentEventuallyVisible()) {
+ self.safeForceUpdate();
+ }
+ }, 5000);
+ });
+ }
+ let incomingSharesContainer = null;
+ const sharedFolders = M.c[contactHandle] && Object.keys(M.c[contactHandle]) || [];
+ if (!self.isLoadingMore && (!sharedFolders || sharedFolders.length === 0)) {
+ incomingSharesContainer = JSX_("div", {
+ className: "chat-dropdown empty-txt"
+ }, l[19986]);
+ } else {
+ const haveMore = sharedFolders.length > 10;
+ const defSortFn = M.getSortByNameFn();
+ sharedFolders.sort((a, b) => {
+ const nodeA = M.d[a];
+ const nodeB = M.d[b];
+ return defSortFn(nodeA, nodeB, -1);
+ });
+ const renderNodes = [];
+ for (let i = 0; i < Math.min(sharedFolders.length, 10); i++) {
+ const nodeHandle = sharedFolders[i];
+ const node = M.d[nodeHandle];
+ if (!node) {
+ continue;
+ }
+ renderNodes.push(JSX_(SharedFolderItem, {
+ key: node.h,
+ isLoading: self.isLoadingMore,
+ node,
+ chatRoom: room
+ }));
+ }
+ incomingSharesContainer = JSX_("div", null, renderNodes, haveMore ? JSX_("div", {
+ className: "chat-share-nav body"
+ }, JSX_("div", {
+ className: "chat-share-nav show-all",
+ onClick () {
+ M.openFolder(contactHandle);
+ }
+ }, JSX_("span", {
+ className: "item-type-icon icon-folder-incoming-24"
+ }, JSX_("span", {
+ className: "item-type-icon icon-folder-incoming-24"
+ })), JSX_("span", {
+ className: "txt"
+ }, l[19797] ? l[19797] : "Show All"))) : null);
+ }
+ contents = JSX_("div", {
+ className: "chat-dropdown content have-animation"
+ }, incomingSharesContainer, self.isLoadingMore ? JSX_("div", {
+ className: "chat-dropdown empty-txt"
+ }, JSX_("div", {
+ className: "loading-spinner light small"
+ }, JSX_("div", {
+ className: "main-loader"
+ }))) : null);
+ }
+ return JSX_("div", {
+ ref: this.domRef,
+ className: "chat-dropdown container"
+ }, JSX_("div", {
+ className: `
+ chat-dropdown
+ header
+ ${this.props.expanded ? 'expanded' : ''}
+ `,
+ onClick: this.props.onToggle
+ }, JSX_("span", null, this.props.title), JSX_("i", {
+ className: "sprite-fm-mono icon-arrow-down"
+ })), JSX_("div", {
+ className: `
+ chat-shared-files-container
+ ${this.isLoadingMore ? 'is-loading' : ''}
+ `
+ }, contents));
+ }
+}
+
+;// ./js/chat/ui/chatlinkDialog.jsx
+
+
+
+
+class ChatlinkDialog extends REaCt().Component {
+ constructor(...args) {
+ super(...args);
+ this.domRef = REaCt().createRef();
+ this.state = {
+ link: l[5533],
+ newTopic: ''
+ };
+ this.onClose = () => {
+ if (this.props.onClose) {
+ this.props.onClose();
+ }
+ };
+ }
+ retrieveChatLink(forced) {
+ const {
+ chatRoom
+ } = this.props;
+ if (is_chatlink) {
+ return this.setState({
+ link: `${getBaseUrl()}/chat/${is_chatlink.ph}#${is_chatlink.key}`
+ });
+ }
+ if (!chatRoom.topic && !forced) {
+ delete this.loading;
+ return;
+ }
+ this.loading = chatRoom.updatePublicHandle(false, true).always(() => {
+ this.loading = false;
+ if (this.domRef.current) {
+ this.setState({
+ link: chatRoom.publicLink ? `${getBaseUrl()}/${chatRoom.publicLink}` : l[20660]
+ });
+ }
+ });
+ }
+ componentDidMount() {
+ this.retrieveChatLink();
+ M.safeShowDialog(ChatlinkDialog.NAMESPACE, () => {
+ if (!this.domRef.current) {
+ throw new Error(`${ChatlinkDialog.NAMESPACE} dialog: component not mounted.`);
+ }
+ return $(`#${ChatlinkDialog.NAMESPACE}`);
+ });
+ }
+ componentWillUnmount() {
+ if ($.dialog === ChatlinkDialog.NAMESPACE) {
+ closeDialog();
+ }
+ }
+ render() {
+ const {
+ chatRoom
+ } = this.props;
+ const {
+ newTopic,
+ link
+ } = this.state;
+ const closeButton = this.loading ? null : JSX_("button", {
+ key: "close",
+ className: "mega-button negative links-button",
+ onClick: this.onClose
+ }, JSX_("span", null, l[148]));
+ const publicLinkDetails = chatRoom.isMeeting ? l.meeting_link_details : l[20644];
+ return JSX_("div", {
+ ref: this.domRef
+ }, JSX_(modalDialogs.A.ModalDialog, (0,esm_extends.A)({}, this.state, {
+ id: ChatlinkDialog.NAMESPACE,
+ title: chatRoom.iAmOperator() && !chatRoom.topic ? chatRoom.isMeeting ? l.rename_meeting : l[9080] : '',
+ className: `
+ chat-rename-dialog
+ export-chat-links-dialog
+ group-chat-link
+ ${chatRoom.topic ? '' : 'requires-topic'}
+ `,
+ onClose: this.onClose,
+ dialogName: "chat-link-dialog",
+ dialogType: chatRoom.iAmOperator() && !chatRoom.topic ? 'main' : 'graphic',
+ chatRoom,
+ popupDidMount: this.onPopupDidMount
+ }), chatRoom.iAmOperator() && !chatRoom.topic ? JSX_("section", {
+ className: "content"
+ }, JSX_("div", {
+ className: "content-block"
+ }, JSX_("div", {
+ className: "export-chat-ink-warning"
+ }, l[20617]), JSX_("div", {
+ className: "rename-input-bl",
+ style: {
+ margin: '10px auto 20px auto'
+ }
+ }, JSX_("input", {
+ type: "text",
+ name: "newTopic",
+ value: newTopic,
+ style: {
+ paddingLeft: 8
+ },
+ onChange: ev => this.setState({
+ newTopic: ev.target.value
+ }),
+ onKeyPress: ev => ev.which === 13 && chatRoom.setRoomTopic(newTopic).then(() => this.retrieveChatLink(true)).catch(dump),
+ placeholder: l[20616],
+ maxLength: ChatRoom.TOPIC_MAX_LENGTH
+ })))) : JSX_(REaCt().Fragment, null, JSX_("header", null, chatRoom.isMeeting ? JSX_("div", {
+ className: "chat-topic-icon meeting-icon"
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-video-call-filled"
+ })) : JSX_("i", {
+ className: "sprite-fm-uni icon-chat-group"
+ }), JSX_("h2", {
+ id: "chat-link-dialog-title"
+ }, JSX_(utils.zT, null, chatRoom.getRoomTitle()))), JSX_("section", {
+ className: "content"
+ }, JSX_("div", {
+ className: "content-block"
+ }, JSX_("div", {
+ className: "chat-link-input"
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-link-small"
+ }), JSX_("input", {
+ type: "text",
+ readOnly: true,
+ value: this.loading ? l[5533] : !chatRoom.topic ? l[20660] : link
+ })), JSX_("div", {
+ className: "info"
+ }, chatRoom.publicLink || is_chatlink ? publicLinkDetails : null)))), JSX_("footer", null, JSX_("div", {
+ className: "footer-container"
+ }, chatRoom.iAmOperator() && chatRoom.publicLink && JSX_("button", {
+ key: "deleteLink",
+ className: `
+ mega-button
+ links-button
+ ${this.loading ? 'disabled' : ''}
+ `,
+ onClick: () => {
+ chatRoom.updatePublicHandle(1);
+ this.onClose();
+ }
+ }, JSX_("span", null, chatRoom.isMeeting ? l.meeting_link_delete : l[20487])), chatRoom.topic ? chatRoom.publicLink || is_chatlink ? JSX_("button", {
+ className: `
+ mega-button
+ positive
+ copy-to-clipboard
+ ${this.loading ? 'disabled' : ''}
+ `,
+ onClick: () => {
+ copyToClipboard(link, l[7654]);
+ if (chatRoom.isMeeting) {
+ eventlog(500231);
+ }
+ }
+ }, JSX_("span", null, l[63])) : closeButton : chatRoom.iAmOperator() ? JSX_("button", {
+ key: "setTopic",
+ className: `
+ mega-button
+ positive
+ links-button
+ ${newTopic && newTopic.trim() ? '' : 'disabled'}
+ `,
+ onClick: () => chatRoom.setRoomTopic(newTopic).then(() => this.retrieveChatLink(true)).catch(dump)
+ }, JSX_("span", null, l[20615])) : closeButton))));
+ }
+}
+ChatlinkDialog.defaultProps = {
+ requiresUpdateOnResize: true,
+ disableCheckingVisibility: true
+};
+ChatlinkDialog.NAMESPACE = 'chat-link-dialog';
+// EXTERNAL MODULE: ./js/chat/ui/historyPanel.jsx + 7 modules
+const historyPanel = REQ_(5522);
+// EXTERNAL MODULE: ./js/chat/ui/composedTextArea.jsx + 1 modules
+const composedTextArea = REQ_(2558);
+;// ./js/chat/ui/pushSettingsDialog.jsx
+
+let _PushSettingsDialog;
+
+
+class PushSettingsDialog extends REaCt().Component {
+ constructor(props) {
+ super(props);
+ this.renderOptions = () => {
+ return Object.keys(PushSettingsDialog.options).map(key => {
+ key = parseInt(key, 10) || Infinity;
+ return JSX_("label", {
+ key,
+ className: "radio-txt"
+ }, PushSettingsDialog.options[key], JSX_("div", {
+ className: `custom-radio small green-active ${ this.state.pushSettingsValue === key ? "radioOn" : "radioOff"}`
+ }, JSX_("input", {
+ type: "radio",
+ name: "time-selector",
+ value: key,
+ checked: this.state.pushSettingsValue === key,
+ onChange: () => this.setState({
+ pushSettingsValue: key
+ })
+ })));
+ });
+ };
+ this.state = {
+ pushSettingsValue: this.props.pushSettingsValue || Infinity
+ };
+ }
+ render() {
+ return JSX_(modalDialogs.A.ModalDialog, (0,esm_extends.A)({}, this.state, {
+ name: "push-settings",
+ title: l.dnd_mute_title,
+ subtitle: this.props.room.isMeeting ? l.meeting_dnd_subtitle : l[22015],
+ className: "push-settings-dialog",
+ dialogName: "push-settings-chat-dialog",
+ dialogType: "tool",
+ onClose: this.props.onClose
+ }), JSX_("section", {
+ className: "content"
+ }, JSX_("div", {
+ className: "content-block"
+ }, JSX_("div", null, this.renderOptions()))), JSX_("footer", null, JSX_("div", {
+ className: "footer-container"
+ }, JSX_("button", {
+ className: "mega-button",
+ onClick: this.props.onClose
+ }, JSX_("span", null, l.msg_dlg_cancel)), JSX_("button", {
+ className: "mega-button positive",
+ onClick: () => this.props.onConfirm(this.state.pushSettingsValue)
+ }, JSX_("span", null, l[726])))));
+ }
+}
+_PushSettingsDialog = PushSettingsDialog;
+PushSettingsDialog.options = {
+ 30: l[22012],
+ 60: l[19048],
+ 360: l[22013],
+ 1440: l[22014],
+ Infinity: l[22011]
+};
+PushSettingsDialog.default = _PushSettingsDialog.options[_PushSettingsDialog.options.length - 1];
+;// ./js/chat/ui/meetings/workflow/alert.jsx
+
+
+const NAMESPACE = 'meetings-alert';
+class Alert extends mixins.w9 {
+ constructor(...args) {
+ super(...args);
+ this.domRef = REaCt().createRef();
+ }
+ componentWillUnmount() {
+ let _this$props$onTransit, _this$props;
+ super.componentWillUnmount();
+ (_this$props$onTransit = (_this$props = this.props).onTransition) == null || _this$props$onTransit.call(_this$props);
+ }
+ componentDidUpdate() {
+ let _this$props$onTransit2, _this$props2;
+ super.componentDidUpdate();
+ (_this$props$onTransit2 = (_this$props2 = this.props).onTransition) == null || _this$props$onTransit2.call(_this$props2, this.domRef);
+ }
+ componentDidMount() {
+ let _this$props$onTransit3, _this$props3;
+ super.componentDidMount();
+ (_this$props$onTransit3 = (_this$props3 = this.props).onTransition) == null || _this$props$onTransit3.call(_this$props3, this.domRef);
+ }
+ render() {
+ const {
+ type,
+ className,
+ content,
+ children,
+ offset,
+ onClose
+ } = this.props;
+ if (content || children) {
+ return JSX_("div", {
+ ref: this.domRef,
+ className: `
+ ${NAMESPACE}
+ ${type ? `${NAMESPACE}-${type}` : ''}
+ ${className || ''}
+ `,
+ style: offset ? {
+ marginTop: `${offset}px`
+ } : undefined
+ }, JSX_("div", {
+ className: `${NAMESPACE}-content`
+ }, content || children), onClose && JSX_("span", {
+ className: `${NAMESPACE}-close`,
+ onClick: onClose
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-close-component"
+ })));
+ }
+ return null;
+ }
+}
+Alert.TYPE = {
+ LIGHT: 'light',
+ NEUTRAL: 'neutral',
+ MEDIUM: 'medium',
+ HIGH: 'high',
+ ERROR: 'error'
+};
+// EXTERNAL MODULE: ./js/chat/ui/meetings/schedule/helpers.jsx
+const helpers = REQ_(6521);
+// EXTERNAL MODULE: ./js/chat/ui/meetings/hostsObserver.jsx
+const hostsObserver = REQ_(7677);
+// EXTERNAL MODULE: ./js/chat/ui/inviteParticipantsPanel.jsx
+const inviteParticipantsPanel = REQ_(8956);
+;// ./js/chat/ui/chatOverlay.jsx
+
+
+
+const chatOverlay_NAMESPACE = 'chat-overlay';
+const ChatOverlays = {
+ PARTICIPANT_LIMIT: 'participants-limit'
+};
+class ChatOverlay extends REaCt().Component {
+ constructor(...args) {
+ super(...args);
+ this.MegaLogo = () => JSX_("div", {
+ className: `${chatOverlay_NAMESPACE}-logo`
+ }, JSX_("i", {
+ className: `sprite-fm-illustration-wide ${mega.ui.isDarkTheme() ? 'mega-logo-dark' : 'img-mega-logo-light'}`
+ }));
+ }
+ renderParticipantsLimit() {
+ return JSX_(REaCt().Fragment, null, JSX_("div", {
+ className: `${chatOverlay_NAMESPACE}-head`
+ }, JSX_(this.MegaLogo, null), JSX_("h1", null, l.join_call_user_limit_title)), JSX_("div", {
+ className: `${chatOverlay_NAMESPACE}-body`
+ }, JSX_("p", null, l.call_join_user_limit_banner), JSX_(buttons.$, {
+ className: "mega-button positive",
+ onClick: () => {
+ let _this$props$onClose, _this$props;
+ (_this$props$onClose = (_this$props = this.props).onClose) == null || _this$props$onClose.call(_this$props);
+ }
+ }, l.call_link_user_limit_button)));
+ }
+ render() {
+ const {
+ overlayType
+ } = this.props;
+ let body = null;
+ if (overlayType === ChatOverlays.PARTICIPANT_LIMIT) {
+ body = this.renderParticipantsLimit();
+ }
+ if (!body) {
+ if (d) {
+ console.error('Invalid ChatOverlay', overlayType);
+ }
+ return null;
+ }
+ return JSX_(utils.Ay.RenderTo, {
+ element: document.body
+ }, JSX_("div", {
+ className: `${chatOverlay_NAMESPACE} ${overlayType}`
+ }, body));
+ }
+}
+
+// EXTERNAL MODULE: ./js/chat/ui/meetings/workflow/utils.jsx
+const workflow_utils = REQ_(2153);
+;// ./js/chat/ui/meetings/schedule/occurrences.jsx
+
+
+
+
+
+class Occurrences extends mixins.w9 {
+ constructor(...args) {
+ super(...args);
+ this.domRef = REaCt().createRef();
+ this.loadingMore = false;
+ this.state = {
+ editDialog: false,
+ occurrenceId: undefined
+ };
+ }
+ loadOccurrences() {
+ if (!this.loadingMore) {
+ const {
+ scheduledMeeting,
+ occurrences
+ } = this.props;
+ const occurrenceItems = Object.values(occurrences || {});
+ const lastOccurrence = occurrenceItems[occurrenceItems.length - 1];
+ if (lastOccurrence) {
+ this.loadingMore = true;
+ scheduledMeeting.getOccurrences({
+ from: lastOccurrence.start
+ }).catch(dump).finally(() => {
+ this.loadingMore = false;
+ });
+ }
+ }
+ }
+ renderCancelConfirmation(occurrence) {
+ const {
+ scheduledMeeting,
+ chatRoom
+ } = this.props;
+ const nextOccurrences = Object.values(scheduledMeeting.occurrences).filter(o => o.isUpcoming);
+ if (nextOccurrences.length > 1) {
+ return msgDialog(`confirmation:!^${l.cancel_meeting_occurrence_button}!${l.schedule_cancel_abort}`, 'cancel-occurrence', l.schedule_cancel_occur_dlg_title, l.schedule_cancel_occur_dlg_text, cb => cb && occurrence.cancel(), 1);
+ }
+ return chatRoom.hasMessages(true) ? msgDialog(`confirmation:!^${l.cancel_meeting_button}!${l.schedule_cancel_abort}`, 'cancel-occurrence', l.schedule_cancel_all_dialog_title, l.schedule_cancel_all_dialog_move, cb => cb && megaChat.plugins.meetingsManager.cancelMeeting(scheduledMeeting, scheduledMeeting.chatId), 1) : msgDialog(`confirmation:!^${l.cancel_meeting_button}!${l.schedule_cancel_abort}`, 'cancel-occurrence', l.schedule_cancel_all_dialog_title, l.schedule_cancel_all_dialog_archive, cb => cb && megaChat.plugins.meetingsManager.cancelMeeting(scheduledMeeting, scheduledMeeting.chatId), 1);
+ }
+ renderLoading() {
+ return JSX_("div", {
+ className: "loading-sketch"
+ }, Array.from({
+ length: 10
+ }, (el, i) => {
+ return JSX_("div", {
+ key: i,
+ className: "chat-occurrence"
+ }, JSX_("div", {
+ className: "chat-occurrence-date"
+ }), JSX_("div", {
+ className: "chat-occurrence-content"
+ }, JSX_("div", {
+ className: "chat-occurrence-title"
+ }), JSX_("div", {
+ className: "chat-occurrence-time"
+ })));
+ }));
+ }
+ renderOccurrences() {
+ const {
+ chatRoom,
+ occurrences,
+ occurrencesLoading,
+ scheduledMeeting
+ } = this.props;
+ if (occurrencesLoading) {
+ return this.renderLoading();
+ }
+ if (occurrences && occurrences.length > 0) {
+ const sortedOccurrences = Object.values(occurrences).sort((a, b) => a.start - b.start);
+ return JSX_(REaCt().Fragment, null, sortedOccurrences.map(occurrence => occurrence.isUpcoming ? JSX_("div", {
+ key: occurrence.uid,
+ className: `
+ chat-occurrence
+ ${occurrence.uid}
+ `
+ }, JSX_("div", {
+ className: "chat-occurrence-date"
+ }, (0,helpers.cK)(occurrence.start) && JSX_("span", null, l.today_occurrence_label, " -"), (0,helpers.ef)(occurrence.start) && JSX_("span", null, l.tomorrow_occurrence_label, " -"), JSX_("span", null, time2date(occurrence.start / 1000, 19))), JSX_("div", {
+ className: "chat-occurrence-content"
+ }, JSX_("div", {
+ className: "chat-occurrence-title"
+ }, scheduledMeeting.title), JSX_("div", {
+ className: "chat-occurrence-time"
+ }, toLocaleTime(occurrence.start), " - \xA0", toLocaleTime(occurrence.end)), chatRoom.iAmOperator() && JSX_("div", {
+ className: "chat-occurrence-controls"
+ }, JSX_("div", {
+ className: "chat-occurrence-control simpletip",
+ "data-simpletip": l[1342],
+ "data-simpletipposition": "top",
+ "data-simpletipoffset": "5"
+ }, JSX_(buttons.$, {
+ icon: "sprite-fm-mono icon-rename",
+ onClick: () => {
+ megaChat.trigger(megaChat.plugins.meetingsManager.EVENTS.EDIT, occurrence);
+ }
+ })), JSX_("div", {
+ className: "chat-occurrence-control simpletip",
+ "data-simpletip": l[82],
+ "data-simpletipposition": "top",
+ "data-simpletipoffset": "5"
+ }, JSX_(buttons.$, {
+ icon: "sprite-fm-mono icon-bin",
+ onClick: () => this.renderCancelConfirmation(occurrence)
+ }))))) : null));
+ }
+ return JSX_("span", null, l.no_occurrences_remain);
+ }
+ render() {
+ return JSX_("div", {
+ ref: this.domRef,
+ className: "chat-occurrences-list"
+ }, JSX_(perfectScrollbar.O, {
+ chatRoom: this.props.chatRoom,
+ ref: ref => {
+ this.contactsListScroll = ref;
+ },
+ disableCheckingVisibility: true,
+ onUserScroll: ps => ps.isCloseToBottom(30) && this.loadOccurrences(),
+ isVisible: this.isCurrentlyActive,
+ options: {
+ suppressScrollX: true
+ }
+ }, JSX_("div", {
+ className: "chat-occurrences-list-inner"
+ }, this.renderOccurrences())));
+ }
+}
+// EXTERNAL MODULE: ./js/chat/ui/fallback.jsx
+const fallback = REQ_(3439);
+// EXTERNAL MODULE: ./js/chat/ui/meetings/utils.jsx
+const meetings_utils = REQ_(3901);
+;// ./js/chat/ui/conversationpanel.jsx
+
+
+let conversationpanel_dec, _dec2, conversationpanel_class;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+const Call = (0,external_React_.lazy)(() => REQ_.e( 987).then(REQ_.bind(REQ_, 8402)));
+const Loading = (0,external_React_.lazy)(() => REQ_.e( 987).then(REQ_.bind(REQ_, 2914)));
+const Join = (0,external_React_.lazy)(() => REQ_.e( 987).then(REQ_.bind(REQ_, 7128)));
+const CloudBrowserDialog = (0,external_React_.lazy)(() => REQ_.e( 313).then(REQ_.bind(REQ_, 6961)));
+const WaitingRoom = (0,external_React_.lazy)(() => REQ_.e( 752).then(REQ_.bind(REQ_, 2659)));
+const ENABLE_GROUP_CALLING_FLAG = true;
+const MAX_USERS_CHAT_PRIVATE = 100;
+const ALERTS_BASE_OFFSET = 4;
+const DISMISS_TRANSITIONS = {
+ NOT_SHOWN: 0,
+ SHOWN: 1,
+ DISMISSED: 2
+};
+class EndCallButton extends REaCt().Component {
+ constructor(...args) {
+ super(...args);
+ this.IS_MODERATOR = (0,meetings_utils.Cy)(this.props.chatRoom, u_handle);
+ this.LeaveButton = (0,hostsObserver.C)(({
+ hasHost,
+ chatRoom,
+ confirmLeave,
+ onLeave
+ }) => {
+ return JSX_(ui_dropdowns.tJ, {
+ className: "link-button",
+ icon: "sprite-fm-mono icon-leave-call",
+ label: l.leave,
+ persistent: true,
+ onClick: () => {
+ const doLeave = () => hasHost(chatRoom.call ? chatRoom.call.peers.map(a => a.userHandle) : []) ? onLeave() : confirmLeave({
+ title: l.assign_host_leave_call,
+ body: l.assign_host_leave_call_details,
+ cta: l.assign_host_button,
+ altCta: l.leave_anyway
+ });
+ const {
+ recorderCid,
+ sfuClient
+ } = chatRoom.call;
+ return recorderCid && recorderCid === sfuClient.cid ? (0,meetings_utils.sX)(doLeave, () => sfuClient.recordingStop()) : doLeave();
+ }
+ });
+ });
+ }
+ renderButton({
+ label,
+ onClick,
+ children = null,
+ disabled
+ }) {
+ return JSX_(buttons.$, {
+ className: `
+ link-button
+ light
+ red
+ dropdown-element
+ ${disabled ? 'disabled' : ''}
+ `,
+ icon: "small-icon colorized horizontal-red-handset",
+ label,
+ onClick: disabled ? null : onClick
+ }, children);
+ }
+ render() {
+ const {
+ chatRoom
+ } = this.props;
+ const {
+ type,
+ call
+ } = chatRoom;
+ if (call) {
+ const peers = call.peers && call.peers.length;
+ if (type === 'private') {
+ return this.renderButton({
+ label: l[5884],
+ onClick: () => call.hangUp()
+ });
+ }
+ if (this.IS_MODERATOR) {
+ const doEnd = () => chatRoom.endCallForAll();
+ return this.renderButton({
+ label: l[5884],
+ onClick: peers ? null : () => call.hangUp(),
+ children: peers && JSX_(ui_dropdowns.ms, {
+ className: "wide-dropdown light end-call-selector",
+ noArrow: "true",
+ vertOffset: 4,
+ horizOffset: 0
+ }, JSX_(this.LeaveButton, {
+ chatRoom,
+ participants: chatRoom.getCallParticipants(),
+ onLeave: () => call.hangUp(),
+ onConfirmDenied: () => call.hangUp()
+ }), JSX_(ui_dropdowns.tJ, {
+ className: "link-button",
+ icon: "sprite-fm-mono icon-contacts",
+ label: l.end_for_all,
+ onClick: () => {
+ const {
+ recorderCid,
+ sfuClient
+ } = call;
+ return recorderCid && recorderCid === u_handle ? (0,meetings_utils._F)(doEnd, () => sfuClient.recordingStop()) : doEnd();
+ }
+ }))
+ });
+ }
+ return this.renderButton({
+ label: peers ? l[5883] : l[5884],
+ onClick: () => call.hangUp()
+ })
+ ;
+ }
+ if (chatRoom.havePendingGroupCall()) {
+ return this.IS_MODERATOR ? this.renderButton({
+ label: l.end_call_for_all,
+ onClick: () => msgDialog('confirmation', null, l.end_call_for_all_title, l.end_call_for_all_text, cb => cb ? chatRoom.endCallForAll() : 0xDEAD),
+ disabled: !chatRoom.iAmInRoom()
+ }) : null;
+ }
+ return null;
+ }
+}
+const StartMeetingNotification = ({
+ chatRoom,
+ offset,
+ onWaitingRoomJoin,
+ onStartCall
+}) => {
+ if (chatRoom.call || !megaChat.hasSupportForCalls) {
+ return null;
+ }
+ return JSX_("div", {
+ className: "in-call-notif neutral start",
+ style: {
+ marginTop: offset
+ },
+ onClick: () => {
+ eventlog(500288);
+ if (chatRoom.options.w && !chatRoom.iAmOperator()) {
+ return onWaitingRoomJoin();
+ }
+ return onStartCall(meetings_utils.ZE.AUDIO);
+ }
+ }, JSX_("button", {
+ className: "mega-button positive small"
+ }, l.schedule_start_aot));
+};
+const JoinCallNotification = ({
+ chatRoom,
+ offset,
+ rhpCollapsed
+}) => {
+ if (chatRoom.call) {
+ return null;
+ }
+ if (!megaChat.hasSupportForCalls) {
+ return JSX_(Alert, {
+ className: `
+ ${rhpCollapsed ? 'full-span' : ''}
+ ${offset === ALERTS_BASE_OFFSET ? 'single-alert' : ''}
+ unsupported-call-alert-progress
+ `,
+ offset: offset === ALERTS_BASE_OFFSET ? 0 : offset,
+ type: Alert.TYPE.MEDIUM,
+ content: l.active_call_not_supported
+ });
+ }
+ if (chatRoom.callUserLimited && !chatRoom.canJoinLimitedCall()) {
+ return JSX_("div", {
+ className: "call-user-limit-banner",
+ style: {
+ marginTop: offset
+ }
+ }, l.call_join_user_limit_banner);
+ }
+ return JSX_("div", {
+ className: "in-call-notif neutral join",
+ style: {
+ marginTop: offset
+ }
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-phone"
+ }), JSX_(utils.P9, {
+ onClick: () => {
+ return (0,meetings_utils.dQ)(true, chatRoom).then(() => chatRoom.joinCall()).catch(ex => d && console.warn('Already in a call.', ex));
+ }
+ }, (l[20460] || 'There is an active group call. [A]Join[/A]').replace('[A]', '')));
+};
+const allContactsInChat = participants => {
+ const currentContacts = M.u.keys();
+ for (let i = 0; i < currentContacts.length; i++) {
+ const k = currentContacts[i];
+ if (M.u[k].c === 1 && !participants.includes(k)) {
+ return false;
+ }
+ }
+ return true;
+};
+const excludedParticipants = room => {
+ const excParticipants = room.type === "group" || room.type === "public" ? room.members && Object.keys(room.members).length > 0 ? Object.keys(room.members) : room.getParticipants() : room.getParticipants();
+ if (excParticipants.includes(u_handle)) {
+ array.remove(excParticipants, u_handle, false);
+ }
+ return excParticipants;
+};
+class ConversationRightArea extends mixins.w9 {
+ constructor(...args) {
+ super(...args);
+ this.domRef = REaCt().createRef();
+ this.state = {
+ contactPickerDialog: false,
+ inviteDialog: false
+ };
+ this.LeaveButton = (0,hostsObserver.C)(({
+ chatRoom,
+ hasHost,
+ confirmLeave,
+ onLeave
+ }) => {
+ const isDisabled = chatRoom.call || is_chatlink || !chatRoom.iAmInRoom();
+ const participants = chatRoom.getParticipantsExceptMe();
+ return JSX_("div", {
+ className: `
+ link-button
+ light
+ ${isDisabled ? 'disabled' : ''}
+ `,
+ onClick: isDisabled ? null : () => hasHost(participants) || !participants.length ? onLeave() : confirmLeave({
+ title: chatRoom.isMeeting ? l.assign_host_to_leave : l.assign_host_to_leave_group,
+ body: chatRoom.isMeeting ? l.assign_host_to_details : l.assign_host_to_details_group,
+ cta: l.assign_host_button
+ })
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-disabled-filled"
+ }), JSX_("span", null, chatRoom.isMeeting ? l.meeting_leave : l[8633]));
+ });
+ this.OptionsButton = ({
+ icon,
+ label,
+ secondLabel,
+ toggled,
+ disabled,
+ onClick
+ }) => {
+ const {
+ chatRoom
+ } = this.props;
+ const isDisabled = !chatRoom.iAmOperator() || disabled;
+ return JSX_(buttons.$, {
+ className: `
+ link-button
+ light
+ room-settings-button
+ `,
+ disabled: isDisabled,
+ icon: `
+ sprite-fm-mono
+ ${icon}
+ `,
+ label,
+ secondLabel,
+ secondLabelClass: "label--green",
+ toggle: {
+ enabled: toggled,
+ onClick: isDisabled ? null : onClick
+ },
+ onClick: isDisabled ? null : onClick
+ });
+ };
+ this.handleCancelMeeting = () => {
+ const {
+ chatRoom
+ } = this.props;
+ const {
+ scheduledMeeting,
+ chatId
+ } = chatRoom || {};
+ if (scheduledMeeting) {
+ const {
+ isRecurring,
+ title
+ } = scheduledMeeting;
+ const doConfirm = res => {
+ if (res) {
+ megaChat.plugins.meetingsManager.cancelMeeting(scheduledMeeting, chatId);
+ delay('chat-event-sm-cancel', () => eventlog(99925));
+ }
+ };
+ if (isRecurring) {
+ return chatRoom.hasMessages(true) ? msgDialog(`confirmation:!^${l.cancel_meeting_button}!${l.schedule_cancel_abort}`, null, l.schedule_cancel_dialog_title.replace('%s', megaChat.html(title)), l.schedule_cancel_dialog_move_recurring, doConfirm, 1) : msgDialog(`confirmation:!^${l.schedule_cancel_dialog_confirm}!${l.schedule_cancel_abort}`, null, l.schedule_cancel_dialog_title.replace('%s', megaChat.html(title)), l.schedule_cancel_dialog_archive_recurring, doConfirm, 1);
+ }
+ return chatRoom.hasMessages(true) ? msgDialog(`confirmation:!^${l.cancel_meeting_button}!${l.schedule_cancel_abort}`, null, l.schedule_cancel_dialog_title.replace('%s', megaChat.html(title)), l.schedule_cancel_dialog_move_single, doConfirm, 1) : msgDialog(`confirmation:!^${l.schedule_cancel_dialog_confirm}!${l.schedule_cancel_abort}`, null, l.schedule_cancel_dialog_title.replace('%s', megaChat.html(title)), l.schedule_cancel_dialog_archive_single, doConfirm, 1);
+ }
+ };
+ }
+ customIsEventuallyVisible() {
+ return this.props.chatRoom.isCurrentlyActive;
+ }
+ setRetention(chatRoom, retentionTime) {
+ chatRoom.setRetention(retentionTime);
+ $(document).trigger('closeDropdowns');
+ }
+ renderOptionsBanner() {
+ const {
+ chatRoom
+ } = this.props;
+ return !!chatRoom.options[MCO_FLAGS.WAITING_ROOM] && !!chatRoom.options[MCO_FLAGS.OPEN_INVITE] ? JSX_("div", {
+ className: "room-settings-banner"
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-info"
+ }), JSX_(utils.P9, null, l.waiting_room_invite.replace('[A]', ``).replace('[/A]', ''))) : null;
+ }
+ handleAddParticipants() {
+ if (Object.values(M.u.toJS()).some(u => u.c === 1)) {
+ if (allContactsInChat(excludedParticipants(this.props.chatRoom))) {
+ return msgDialog(`confirmationa:!^${l[8726]}!${l.msg_dlg_cancel}`, null, `${l.all_contacts_added}`, `${l.all_contacts_added_to_chat}`, res => {
+ if (res) {
+ contactAddDialog(null, false);
+ }
+ }, 1);
+ }
+ return this.setState({
+ contactPickerDialog: true
+ });
+ }
+ msgDialog(`confirmationa:!^${l[8726]}!${l.msg_dlg_cancel}`, null, `${l.no_contacts}`, `${l.no_contacts_text}`, resp => {
+ if (resp) {
+ contactAddDialog(null, false);
+ }
+ }, 1);
+ }
+ renderPushSettingsButton() {
+ const {
+ pushSettingsValue,
+ chatRoom,
+ onPushSettingsToggled,
+ onPushSettingsClicked
+ } = this.props;
+ const icon = pushSettingsValue || pushSettingsValue === 0 ? 'icon-notification-off-filled' : 'icon-notification-filled';
+ return JSX_("div", {
+ className: "push-settings"
+ }, JSX_("div", {
+ className: "chat-button-separator"
+ }), JSX_(buttons.$, {
+ className: `
+ link-button
+ light
+ push-settings-button
+ ${chatRoom.isReadOnly() ? 'disabled' : ''}
+ `,
+ icon: `
+ sprite-fm-mono
+ ${icon}
+ `,
+ label: chatRoom.isMeeting ? l.meeting_notifications : l[16709],
+ secondLabel: (() => {
+ if (pushSettingsValue !== null && pushSettingsValue !== undefined) {
+ return pushSettingsValue === 0 ? PushSettingsDialog.options[Infinity] : l[23539].replace('%s', toLocaleTime(pushSettingsValue));
+ }
+ })(),
+ secondLabelClass: "label--green",
+ toggle: chatRoom.isReadOnly() ? null : {
+ enabled: !pushSettingsValue && pushSettingsValue !== 0,
+ onClick: () => !pushSettingsValue && pushSettingsValue !== 0 ? onPushSettingsClicked() : onPushSettingsToggled()
+ },
+ onClick: () => chatRoom.isReadOnly() ? null : onPushSettingsClicked()
+ }), JSX_("div", {
+ className: "chat-button-separator"
+ }));
+ }
+ componentDidMount() {
+ super.componentDidMount();
+ megaChat.rebind(`${megaChat.plugins.meetingsManager.EVENTS.OCCURRENCES_UPDATE}.${this.getUniqueId()}`, () => {
+ if (this.isMounted()) {
+ this.safeForceUpdate();
+ }
+ });
+ megaChat.rebind(`onPrepareIncomingCallDialog.${this.getUniqueId()}`, () => {
+ if (this.isMounted() && this.state.inviteDialog) {
+ this.setState({
+ inviteDialog: false
+ });
+ }
+ });
+ }
+ render() {
+ let _room$messagesBuff, _room$messagesBuff2, _room$messagesBuff3, _room$messagesBuff4, _room$messagesBuff5;
+ const self = this;
+ const {
+ chatRoom: room,
+ onStartCall,
+ occurrencesLoading,
+ onShowScheduledDescription
+ } = self.props;
+ if (!room || !room.roomId) {
+ return null;
+ }
+ if (!room.isCurrentlyActive && !self._wasAppendedEvenOnce) {
+ return null;
+ }
+ self._wasAppendedEvenOnce = true;
+ const startCallDisabled = isStartCallDisabled(room) || room.iAmWaitingRoomPeer();
+ let startAudioCallButton;
+ let startVideoCallButton;
+ const isInCall = !!room.call;
+ if (isInCall) {
+ startAudioCallButton = startVideoCallButton = null;
+ }
+ if (room.type === "group" || room.type === "public") {
+ if (room.getCallParticipants().length > 0 && !isInCall) {
+ startAudioCallButton = startVideoCallButton = null;
+ }
+ }
+ if (startAudioCallButton !== null) {
+ startAudioCallButton = JSX_("div", {
+ "data-simpletip": l.unsupported_browser_audio,
+ "data-simpletipposition": "top",
+ "data-simpletipoffset": "7",
+ className: `
+ link-button light
+ ${megaChat.hasSupportForCalls ? '' : 'simpletip'}
+ ${startCallDisabled ? 'disabled' : ''}
+ `,
+ onClick: () => onStartCall(meetings_utils.ZE.AUDIO)
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-phone"
+ }), JSX_("span", null, l[5896]));
+ }
+ if (startVideoCallButton !== null) {
+ startVideoCallButton = JSX_("div", {
+ "data-simpletip": l.unsupported_browser_video,
+ "data-simpletipposition": "top",
+ "data-simpletipoffset": "7",
+ className: `
+ link-button light
+ ${megaChat.hasSupportForCalls ? '' : 'simpletip'}
+ ${startCallDisabled ? 'disabled' : ''}
+ `,
+ onClick: () => onStartCall(meetings_utils.ZE.VIDEO)
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-video-call-filled"
+ }), JSX_("span", null, l[5897]));
+ }
+ const AVseperator = JSX_("div", {
+ className: "chat-button-separator"
+ });
+ let isReadOnlyElement = null;
+ if (room.isReadOnly()) {
+ isReadOnlyElement = JSX_("center", {
+ className: "center",
+ style: {
+ margin: "6px"
+ }
+ }, l.read_only_chat);
+ }
+ const exParticipants = excludedParticipants(room);
+ let dontShowTruncateButton = false;
+ if (!room.iAmOperator() || room.isReadOnly() || ((_room$messagesBuff = room.messagesBuff) == null ? void 0 : _room$messagesBuff.messages.length) === 0 || ((_room$messagesBuff2 = room.messagesBuff) == null ? void 0 : _room$messagesBuff2.messages.length) === 1 && ((_room$messagesBuff3 = room.messagesBuff) == null ? void 0 : _room$messagesBuff3.messages.getItem(0).dialogType) === "truncated") {
+ dontShowTruncateButton = true;
+ }
+ const renameButtonClass = `
+ link-button
+ light
+ ${(0,meetings_utils.P)() || room.isReadOnly() || !room.iAmOperator() ? 'disabled' : ''}
+ `;
+ const getChatLinkClass = `
+ link-button
+ light
+ ${(0,meetings_utils.P)() || room.isReadOnly() ? 'disabled' : ''}
+ `;
+ let participantsList = null;
+ if (room.type === "group" || room.type === "public") {
+ participantsList = JSX_("div", null, isReadOnlyElement, JSX_(buttons.$, {
+ className: "mega-button action invite-dialog-btn",
+ icon: "sprite-fm-mono icon-user-plus-thin-outline",
+ label: l[8726],
+ disabled: (0,meetings_utils.P)() || room.isReadOnly() || !room.iAmOperator() && !room.publicLink && !room.options[MCO_FLAGS.OPEN_INVITE],
+ onClick: () => {
+ delay('chat-event-inv-rhp', () => eventlog(99963));
+ if (room.type === 'group') {
+ return this.handleAddParticipants();
+ }
+ loadingDialog.show('fetchchatlink');
+ room.updatePublicHandle(false, false, true).catch(dump).always(() => {
+ loadingDialog.hide('fetchchatlink');
+ if (!this.isMounted()) {
+ return;
+ }
+ if (!room.iAmOperator() && room.options[MCO_FLAGS.OPEN_INVITE] && !room.publicLink) {
+ this.handleAddParticipants();
+ } else if (room.type === 'public' && !room.topic) {
+ this.handleAddParticipants();
+ } else {
+ this.setState({
+ inviteDialog: true
+ });
+ }
+ });
+ }
+ }), JSX_(ParticipantsList, {
+ ref (r) {
+ self.participantsListRef = r;
+ },
+ chatRoom: room,
+ members: room.members,
+ isCurrentlyActive: room.isCurrentlyActive
+ }));
+ }
+ const addParticipantBtn = room.type === 'private' && JSX_(buttons.$, {
+ className: "link-button light",
+ icon: "sprite-fm-mono icon-add-small",
+ label: l[8007],
+ disabled: (0,meetings_utils.P)() || room.isReadOnly() || !(room.iAmOperator() || room.type !== 'private' && room.options[MCO_FLAGS.OPEN_INVITE]),
+ onClick: () => Object.values(M.u.toJS()).some(u => u.c === 1) ? !allContactsInChat(exParticipants) ? this.setState({
+ contactPickerDialog: true
+ }) : msgDialog(`confirmationa:!^${l[8726]}!${l.msg_dlg_cancel}`, null, `${l.all_contacts_added}`, `${l.all_contacts_added_to_chat}`, res => {
+ if (res) {
+ contactAddDialog(null, false);
+ }
+ }, 1) : msgDialog(`confirmationa:!^${l[8726]}!${l.msg_dlg_cancel}`, null, `${l.no_contacts}`, `${l.no_contacts_text}`, resp => {
+ if (resp) {
+ contactAddDialog(null, false);
+ }
+ }, 1)
+ });
+ const waitingRoomButton = {
+ icon: 'icon-clock-user-thin-solid',
+ label: l.waiting_room,
+ secondLabel: l.waiting_room_info,
+ toggled: room.options[MCO_FLAGS.WAITING_ROOM],
+ disabled: room.havePendingCall(),
+ onClick: () => {
+ room.toggleWaitingRoom();
+ delay('chat-event-wr-create-button', () => eventlog(99937));
+ }
+ };
+ const openInviteButton = {
+ icon: 'icon-user-filled',
+ label: room.isMeeting ? l.meeting_open_invite_label : l.chat_open_invite_label,
+ secondLabel: l.open_invite_desc,
+ toggled: room.options[MCO_FLAGS.OPEN_INVITE],
+ onClick: () => {
+ room.toggleOpenInvite();
+ if (room.scheduledMeeting) {
+ delay('chat-event-sm-allow-non-hosts', () => eventlog(99928));
+ }
+ }
+ };
+ const retentionTime = room.retentionTime ? secondsToDays(room.retentionTime) : 0;
+ const ICON_ACTIVE = JSX_("i", {
+ className: "sprite-fm-mono icon-check"
+ });
+ const retentionHistoryBtn = JSX_(buttons.$, {
+ className: "link-button light history-retention-btn",
+ icon: "sprite-fm-mono icon-recents-filled",
+ label: l[23436],
+ disabled: !room.iAmOperator() || room.isReadOnly() || (0,meetings_utils.P)(),
+ secondLabel: room.getRetentionLabel(),
+ secondLabelClass: "label--red",
+ chatRoom: room
+ }, room.iAmOperator() ? JSX_(ui_dropdowns.ms, {
+ className: "retention-history-menu light",
+ noArrow: "false",
+ vertOffset: -53,
+ horizOffset: -205
+ }, JSX_("div", {
+ className: "retention-history-menu__list"
+ }, JSX_("div", {
+ className: "dropdown-item link-button retention-history-menu__list__elem",
+ onClick: () => this.setRetention(room, 0)
+ }, JSX_("span", null, l.disabled_chat_history_cleaning_status), retentionTime === 0 && ICON_ACTIVE), JSX_("div", {
+ className: "dropdown-item link-button retention-history-menu__list__elem",
+ onClick: () => this.setRetention(room, daysToSeconds(1))
+ }, JSX_("span", null, l[23437]), retentionTime === 1 && ICON_ACTIVE), JSX_("div", {
+ className: "dropdown-item link-button retention-history-menu__list__elem",
+ onClick: () => this.setRetention(room, daysToSeconds(7))
+ }, JSX_("span", null, l[23438]), retentionTime === 7 && ICON_ACTIVE), JSX_("div", {
+ className: "dropdown-item link-button retention-history-menu__list__elem",
+ onClick: () => this.setRetention(room, daysToSeconds(30))
+ }, JSX_("span", null, l[23439]), retentionTime === 30 && ICON_ACTIVE), JSX_("div", {
+ className: "dropdown-item link-button retention-history-menu__list__elem",
+ onClick: () => {
+ $(document).trigger('closeDropdowns');
+ self.props.onHistoryRetentionConfig();
+ }
+ }, JSX_("span", null, l[23440]), [0, 1, 7, 30].indexOf(retentionTime) === -1 && ICON_ACTIVE))) : null);
+ const MEMBERS_LIMITED = Object.keys(room.members).length > MAX_USERS_CHAT_PRIVATE;
+ const {
+ scheduledMeeting,
+ isMeeting
+ } = room;
+ const {
+ isRecurring,
+ isUpcoming,
+ occurrences
+ } = scheduledMeeting || {};
+ let archiveText = room.isMeeting ? l.archive_meeting_btn : l.archive_chat_btn;
+ if (room.isArchived()) {
+ archiveText = room.isMeeting ? l.unarchive_meeting_btn : l[19065];
+ }
+ return JSX_("div", {
+ ref: this.domRef,
+ className: "chat-right-area"
+ }, JSX_(perfectScrollbar.O, {
+ className: "chat-right-area conversation-details-scroll",
+ options: {
+ 'suppressScrollX': true
+ },
+ ref: ref => {
+ this.rightScroll = ref;
+ },
+ triggerGlobalResize: true,
+ isVisible: room.isCurrentlyActive,
+ chatRoom: room
+ }, JSX_("div", {
+ className: "chat-right-pad"
+ }, JSX_(Accordion, (0,esm_extends.A)({}, this.state, {
+ chatRoom: room,
+ onToggle: SoonFc(20, () => {
+ if (this.rightScroll) {
+ this.rightScroll.reinitialise();
+ }
+ if (this.participantsListRef) {
+ let _this$participantsLis, _this$participantsLis2;
+ (_this$participantsLis = (_this$participantsLis2 = this.participantsListRef).safeForceUpdate) == null || _this$participantsLis.call(_this$participantsLis2);
+ }
+ }),
+ expandedPanel: {
+ participants: false,
+ options: false,
+ occurrences: isMeeting && scheduledMeeting && isRecurring
+ }
+ }), participantsList ? JSX_(AccordionPanel, {
+ className: "small-pad",
+ title: room.isMeeting ? l.meeting_participants : l.chat_participants,
+ chatRoom: room,
+ key: "participants"
+ }, participantsList) : null, room.type === 'public' && room.observers > 0 && !room.options.w ? JSX_("div", {
+ className: "accordion-text observers"
+ }, l[20466], JSX_("span", {
+ className: "observers-count"
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-eye-reveal"
+ }), room.observers)) : JSX_("div", null), isRecurring && isUpcoming && scheduledMeeting.occurrences.some(o => o.isUpcoming) && JSX_(AccordionPanel, {
+ key: "occurrences",
+ className: "chat-occurrences-panel",
+ accordionClass: "chatroom-occurrences-panel",
+ title: l.occurrences_heading,
+ chatRoom: room,
+ scheduledMeeting,
+ occurrences
+ }, JSX_(Occurrences, {
+ chatRoom: room,
+ scheduledMeeting,
+ occurrences,
+ occurrencesLoading
+ })), JSX_(AccordionPanel, {
+ key: "options",
+ className: "have-animation buttons",
+ accordionClass: "chatroom-options-panel",
+ title: l[7537],
+ chatRoom: room,
+ sfuClient: window.sfuClient
+ }, JSX_(REaCt().Fragment, null, room.isNote ? null : JSX_(REaCt().Fragment, null, addParticipantBtn, startAudioCallButton, startVideoCallButton, JSX_(EndCallButton, {
+ call: room.havePendingGroupCall() || room.haveActiveCall(),
+ chatRoom: room
+ }), scheduledMeeting && JSX_("div", {
+ className: `
+ link-button light
+ schedule-view-desc
+ ${room.isReadOnly() || !scheduledMeeting.description ? 'disabled' : ''}
+ `,
+ onClick: () => {
+ if (!room.isReadOnly() && scheduledMeeting.description) {
+ onShowScheduledDescription();
+ }
+ }
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-description"
+ }), JSX_("span", null, l.schedule_view_desc)), (room.type === 'group' || room.type === 'public') && !scheduledMeeting ? JSX_("div", {
+ className: renameButtonClass,
+ onClick: e => {
+ if ($(e.target).closest('.disabled').length > 0) {
+ return false;
+ }
+ if (this.props.onRenameClicked) {
+ this.props.onRenameClicked();
+ }
+ }
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-rename"
+ }), JSX_("span", null, room.isMeeting ? l.rename_meeting : l[9080])) : null, scheduledMeeting ? JSX_("div", {
+ className: `
+ link-button
+ light
+ ${room.iAmOperator() ? '' : 'disabled'}
+ `,
+ onClick: () => room.iAmOperator() ? megaChat.trigger(megaChat.plugins.meetingsManager.EVENTS.EDIT, room) : null
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-rename"
+ }), scheduledMeeting.isRecurring ? JSX_("span", null, l.edit_meeting_series_button) : JSX_("span", null, l.edit_meeting_button)) : null, room.type === 'public' && !room.isMeeting ? JSX_("div", {
+ className: getChatLinkClass,
+ onClick: e => {
+ if ($(e.target).closest('.disabled').length > 0) {
+ return false;
+ }
+ this.props.onGetManageChatLinkClicked();
+ }
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-link-filled"
+ }), JSX_("span", null, l[20481])) : null, scheduledMeeting ? JSX_("div", {
+ className: `
+ link-button
+ light
+ ${room.iAmOperator() && !scheduledMeeting.canceled ? '' : 'disabled'}
+ `,
+ onClick: () => {
+ if (room.iAmOperator() && !scheduledMeeting.canceled) {
+ this.handleCancelMeeting();
+ }
+ }
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-bin-filled"
+ }), scheduledMeeting.isRecurring ? JSX_("span", null, l.cancel_meeting_series_button) : JSX_("span", null, l.cancel_meeting_button)) : null, !room.membersSetFromApi.members.hasOwnProperty(u_handle) && room.type === 'public' && !is_chatlink && room.publicChatHandle && room.publicChatKey ? JSX_("div", {
+ className: "link-button light",
+ onClick: e => {
+ if ($(e.target).closest('.disabled').length > 0) {
+ return false;
+ }
+ this.props.onJoinViaPublicLinkClicked();
+ }
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-rename"
+ }), JSX_("span", null, l[20597])) : null, scheduledMeeting ? null : JSX_(REaCt().Fragment, null, AVseperator, JSX_(buttons.$, {
+ className: "link-button light dropdown-element",
+ icon: "sprite-fm-mono icon-upload-filled",
+ label: l[23753],
+ disabled: room.isReadOnly()
+ }, JSX_(ui_dropdowns.ms, {
+ className: "wide-dropdown send-files-selector light",
+ noArrow: "true",
+ vertOffset: 4,
+ onClick: () => false
+ }, JSX_("div", {
+ className: "dropdown info-txt"
+ }, l[23753] || 'Send...'), JSX_(ui_dropdowns.tJ, {
+ className: "link-button",
+ icon: "sprite-fm-mono icon-cloud-drive",
+ label: l[19794] || 'My Cloud Drive',
+ disabled: mega.paywall,
+ onClick: () => {
+ this.props.onAttachFromCloudClicked();
+ }
+ }), JSX_(ui_dropdowns.tJ, {
+ className: "link-button",
+ icon: "sprite-fm-mono icon-session-history",
+ label: l[19795] || 'My computer',
+ disabled: mega.paywall,
+ onClick: () => {
+ this.props.onAttachFromComputerClicked();
+ }
+ })))), this.renderPushSettingsButton()), room.type === 'private' ? null : JSX_(REaCt().Fragment, null, room.scheduledMeeting && this.OptionsButton(waitingRoomButton), this.OptionsButton(openInviteButton), this.renderOptionsBanner(), AVseperator), JSX_(buttons.$, {
+ className: "link-button light export-chat-button",
+ disabled: ((_room$messagesBuff4 = room.messagesBuff) == null ? void 0 : _room$messagesBuff4.messages.length) === 0 || room.exportIo,
+ onClick: () => {
+ room.exportToFile();
+ }
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-export-chat-filled"
+ }), JSX_("span", null, room.isMeeting ? l.export_meeting_rhp : l.export_chat_rhp)), JSX_(buttons.$, {
+ className: "link-button light clear-history-button",
+ disabled: dontShowTruncateButton || !room.members.hasOwnProperty(u_handle),
+ onClick: () => {
+ if (this.props.onTruncateClicked) {
+ this.props.onTruncateClicked();
+ }
+ }
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-remove"
+ }), JSX_("span", {
+ className: "accordion-clear-history-text"
+ }, room.isMeeting ? l.meeting_clear_hist : l[8871])), retentionHistoryBtn, room.iAmOperator() && room.type === 'public' && !scheduledMeeting ? JSX_("div", {
+ className: "chat-enable-key-rotation-paragraph"
+ }, AVseperator, JSX_("div", {
+ className: `
+ link-button
+ light
+ ${MEMBERS_LIMITED ? 'disabled' : ''}
+ `,
+ onClick: e => {
+ if (MEMBERS_LIMITED || $(e.target).closest('.disabled').length > 0) {
+ return false;
+ }
+ this.props.onMakePrivateClicked();
+ }
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-key"
+ }), JSX_("span", null, l[20623])), JSX_("p", null, JSX_("span", null, l[20454]))) : null, AVseperator, JSX_("div", {
+ className: `
+ link-button
+ light
+ ${(room.members.hasOwnProperty(u_handle) || room.state === ChatRoom.STATE.LEFT) && !is_chatlink ? '' : 'disabled'}
+ `,
+ onClick: e => {
+ if ($(e.target).closest('.disabled').length > 0) {
+ return false;
+ }
+ if (room.isArchived()) {
+ if (this.props.onUnarchiveClicked) {
+ this.props.onUnarchiveClicked();
+ }
+ } else if (this.props.onArchiveClicked) {
+ this.props.onArchiveClicked();
+ }
+ }
+ }, JSX_("i", {
+ className: `
+ sprite-fm-mono
+ ${room.isArchived() ? 'icon-unarchive' : 'icon-archive'}
+ `
+ }), JSX_("span", null, archiveText)), room.type === 'private' ? null : JSX_(this.LeaveButton, {
+ chatRoom: room,
+ participants: room.getParticipantsExceptMe(),
+ onLeave: () => room.leave(true)
+ }))), JSX_(SharedFilesAccordionPanel, {
+ key: "sharedFiles",
+ title: l[19796] || 'Shared Files',
+ chatRoom: room,
+ sharedFiles: (_room$messagesBuff5 = room.messagesBuff) == null ? void 0 : _room$messagesBuff5.sharedFiles
+ }), room.type === 'private' && !room.isNote ? JSX_(IncSharesAccordionPanel, {
+ key: "incomingShares",
+ title: l[5542],
+ chatRoom: room
+ }) : null))), this.state.contactPickerDialog && JSX_(ui_contacts.hm, {
+ exclude: exParticipants,
+ megaChat: room.megaChat,
+ multiple: true,
+ className: "popup add-participant-selector",
+ singleSelectedButtonLabel: room.isMeeting ? l.meeting_add_participant : l[8869],
+ multipleSelectedButtonLabel: room.isMeeting ? l.meeting_add_participant : l[8869],
+ nothingSelectedButtonLabel: l[8870],
+ inviteWarningLabel: room.haveActiveCall(),
+ chatRoom: room,
+ onSelectDone: selected => {
+ this.props.onAddParticipantSelected(selected);
+ this.setState({
+ contactPickerDialog: false
+ });
+ },
+ onClose: () => this.setState({
+ contactPickerDialog: false
+ }),
+ selectFooter: true
+ }), this.state.inviteDialog && JSX_(modalDialogs.A.ModalDialog, {
+ onClose: () => {
+ this.setState({
+ inviteDialog: false
+ });
+ },
+ dialogName: "chat-link-dialog",
+ chatRoom: room
+ }, JSX_(inviteParticipantsPanel.Q, {
+ chatRoom: room,
+ onAddParticipants: () => {
+ this.setState({
+ inviteDialog: false
+ }, () => this.handleAddParticipants());
+ }
+ })));
+ }
+}
+ConversationRightArea.defaultProps = {
+ 'requiresUpdateOnResize': true
+};
+const ConversationPanel = (conversationpanel_dec = utils.Ay.SoonFcWrap(360), _dec2 = (0,mixins.N9)(0.7, 9), conversationpanel_class = class ConversationPanel extends mixins.w9 {
+ constructor(props) {
+ super(props);
+ this.domRef = REaCt().createRef();
+ this.messagesBlockRef = REaCt().createRef();
+ this.$container = undefined;
+ this.$messages = undefined;
+ this.selectedNodes = [];
+ this.state = {
+ startCallPopupIsActive: false,
+ localVideoIsMinimized: false,
+ isFullscreenModeEnabled: false,
+ mouseOverDuringCall: false,
+ attachCloudDialog: false,
+ sendContactDialog: false,
+ confirmDeleteDialog: false,
+ pasteImageConfirmDialog: false,
+ nonLoggedInJoinChatDialog: false,
+ pushSettingsDialog: false,
+ pushSettingsValue: null,
+ messageToBeDeleted: null,
+ callMinimized: false,
+ editing: false,
+ showHistoryRetentionDialog: false,
+ setNonLoggedInJoinChatDlgTrue: null,
+ hasInvalidKeys: null,
+ invalidKeysBanner: null,
+ descriptionDialog: false,
+ occurrencesLoading: false,
+ waitingRoom: false,
+ callUserLimit: false,
+ historyTimeOutBanner: DISMISS_TRANSITIONS.NOT_SHOWN,
+ renameDialog: false,
+ renameDialogValue: undefined,
+ typingAreaText: ''
+ };
+ this.RenameDialog = () => {
+ const {
+ chatRoom
+ } = this.props;
+ const {
+ renameDialogValue
+ } = this.state;
+ const isDisabled = renameDialogValue === chatRoom.getRoomTitle() || !$.trim(renameDialogValue).length;
+ const onSubmit = () => chatRoom.setRoomTopic(renameDialogValue).then(() => this.setState({
+ renameDialog: false,
+ renameDialogValue: undefined
+ })).catch(dump);
+ return JSX_(modalDialogs.A.ModalDialog, {
+ chatRoom,
+ title: chatRoom.isMeeting ? l.rename_meeting : l[9080],
+ name: "rename-group",
+ className: "chat-rename-dialog dialog-template-main",
+ onClose: () => this.setState({
+ renameDialog: false,
+ renameDialogValue: undefined
+ }),
+ buttons: [{
+ label: l.msg_dlg_cancel,
+ onClick: () => this.setState({
+ renameDialog: false,
+ renameDialogValue: undefined
+ })
+ }, {
+ label: l[61],
+ className: `
+ positive
+ ${isDisabled ? 'disabled' : ''}
+ `,
+ onClick: isDisabled ? null : onSubmit
+ }]
+ }, JSX_("section", {
+ className: "content"
+ }, JSX_("div", {
+ className: "content-block"
+ }, JSX_("div", {
+ className: "dialog secondary-header"
+ }, JSX_("div", {
+ className: "rename-input-bl"
+ }, JSX_("input", {
+ type: "text",
+ name: "newTopic",
+ className: "chat-rename-group-dialog",
+ value: renameDialogValue === undefined ? chatRoom.getRoomTitle() : renameDialogValue,
+ maxLength: ChatRoom.TOPIC_MAX_LENGTH,
+ onChange: ev => this.setState({
+ renameDialogValue: ev.target.value.substr(0, 30)
+ }),
+ onKeyUp: ev => isDisabled ? null : ev.which === 13 && onSubmit()
+ }))))));
+ };
+ this.SelectContactDialog = () => {
+ const {
+ chatRoom
+ } = this.props;
+ const excludedContacts = chatRoom.getParticipantsExceptMe().filter(userHandle => userHandle in M.u);
+ return JSX_(modalDialogs.A.SelectContactDialog, {
+ chatRoom,
+ exclude: excludedContacts,
+ onSelectClicked: selected => this.setState({
+ sendContactDialog: false
+ }, () => chatRoom.attachContacts(selected)),
+ onClose: () => this.setState({
+ sendContactDialog: false
+ })
+ });
+ };
+ this.DescriptionDialog = () => {
+ const {
+ chatRoom
+ } = this.props;
+ const dialogName = 'scheduled-description-dialog';
+ return JSX_(modalDialogs.A.ModalDialog, {
+ className: "scheduled-description-dialog",
+ meeting: chatRoom.scheduledMeeting,
+ popupDidMount: () => M.safeShowDialog(dialogName, () => $(`.${dialogName}`)),
+ popupWillUnmount: () => $.dialog === dialogName && closeDialog(),
+ onClose: () => this.setState({
+ descriptionDialog: false
+ })
+ }, JSX_("header", null, JSX_("h3", null, l.schedule_desc_dlg_title)), JSX_("section", {
+ className: "content"
+ }, JSX_(perfectScrollbar.O, {
+ className: "description-scroller"
+ }, JSX_(utils.P9, {
+ content: megaChat.html(chatRoom.scheduledMeeting.description).replace(/\n/g, '
') || l.schedule_no_desc
+ }))));
+ };
+ this.PushSettingsDialog = () => {
+ const {
+ chatRoom
+ } = this.props;
+ const {
+ pushSettingsValue
+ } = this.state;
+ const state = {
+ pushSettingsDialog: false,
+ pushSettingsValue: null
+ };
+ return JSX_(PushSettingsDialog, {
+ room: chatRoom,
+ pushSettingsValue,
+ onClose: () => this.setState({
+ ...state,
+ pushSettingsValue
+ }, () => $.dialog === 'push-settings-dialog' && closeDialog()),
+ onConfirm: pushSettingsValue => this.setState({
+ ...state,
+ pushSettingsValue
+ }, () => pushNotificationSettings.setDnd(chatRoom.chatId, pushSettingsValue === Infinity ? 0 : unixtime() + pushSettingsValue * 60))
+ });
+ };
+ this.updateTypingAreaText = value => {
+ this.setState({
+ typingAreaText: value
+ });
+ };
+ const {
+ chatRoom: _chatRoom
+ } = this.props;
+ const uniqueId = this.getUniqueId();
+ _chatRoom.rebind(`openAttachCloudDialog.${uniqueId}`, () => this.setState({
+ attachCloudDialog: true
+ }));
+ _chatRoom.rebind(`openSendContactDialog.${uniqueId}`, () => this.setState({
+ sendContactDialog: true
+ }));
+ _chatRoom.rebind(`openDescriptionDialog.${uniqueId}`, () => this.setState({
+ descriptionDialog: true
+ }));
+ this.handleKeyDown = SoonFc(120, ev => this._handleKeyDown(ev));
+ this.state.waitingRoom = _chatRoom.options.w && (_chatRoom.isAnonymous() || megaChat.initialChatId || is_eplusplus);
+ }
+ customIsEventuallyVisible() {
+ return this.props.chatRoom.isCurrentlyActive;
+ }
+ onMouseMove() {
+ if (this.isComponentEventuallyVisible()) {
+ this.props.chatRoom.trigger("onChatIsFocused");
+ }
+ }
+ _handleKeyDown() {
+ if (this.__isMounted) {
+ const {chatRoom} = this.props;
+ if (chatRoom.isActive() && !chatRoom.isReadOnly()) {
+ chatRoom.trigger("onChatIsFocused");
+ }
+ }
+ }
+ handleDeleteDialog(msg) {
+ if (msg) {
+ this.setState({
+ editing: false,
+ confirmDeleteDialog: true,
+ messageToBeDeleted: msg
+ });
+ }
+ }
+ toggleExpandedFlag() {
+ if (this.props.onToggleExpandedFlag) {
+ this.props.onToggleExpandedFlag();
+ }
+ return document.body.classList[(0,meetings_utils.Av)() ? 'remove' : 'add'](meetings_utils.Fj);
+ }
+ startCall(type, scheduled) {
+ const {
+ chatRoom
+ } = this.props;
+ if (isStartCallDisabled(chatRoom) || chatRoom.iAmWaitingRoomPeer()) {
+ return false;
+ }
+ return type === meetings_utils.ZE.AUDIO ? chatRoom.startAudioCall(scheduled) : chatRoom.startVideoCall(scheduled);
+ }
+ renderUpcomingInfo() {
+ const {
+ scheduledMeeting
+ } = this.props.chatRoom;
+ if (scheduledMeeting) {
+ const {
+ recurring,
+ nextOccurrenceStart,
+ nextOccurrenceEnd,
+ isUpcoming
+ } = scheduledMeeting;
+ const until = `${(0,helpers.ro)(nextOccurrenceStart, nextOccurrenceEnd) ? '' : time2date(nextOccurrenceEnd / 1000, 4)} ${toLocaleTime(nextOccurrenceEnd)}`;
+ return JSX_(REaCt().Fragment, null, isUpcoming && recurring && JSX_("span", null, l.next_meeting), JSX_("span", null, (l.schedule_formatted_date || '%1 from %2 to %3').replace('%1', time2date(nextOccurrenceStart / 1000, 4)).replace('%2', toLocaleTime(nextOccurrenceStart)).replace('%3', until)));
+ }
+ return null;
+ }
+ componentDidMount() {
+ super.componentDidMount();
+ const {
+ chatRoom
+ } = this.props;
+ this.$container = $('.conversation-panel', '#fmholder');
+ this.$messages = $('.messages.scroll-area > .perfectScrollbarContainer', this.$container);
+ window.addEventListener('keydown', this.handleKeyDown);
+ chatRoom.rebind('onSendMessage.scrollToBottom', () => {
+ chatRoom.scrolledToBottom = true;
+ if (this.messagesListScrollable) {
+ this.messagesListScrollable.scrollToBottom();
+ }
+ });
+ chatRoom.rebind('openSendFilesDialog.cpanel', () => this.setState({
+ attachCloudDialog: true
+ }));
+ chatRoom.rebind('showGetChatLinkDialog.ui', () => {
+ createTimeoutPromise(() => chatRoom.topic && chatRoom.state === ChatRoom.STATE.READY, 350, 15000).always(() => {
+ return chatRoom.isCurrentlyActive ? this.setState({
+ chatLinkDialog: true
+ }) : chatRoom.updatePublicHandle(false, true);
+ });
+ });
+ if (chatRoom.type === 'private') {
+ const otherContactHash = chatRoom.getParticipantsExceptMe()[0];
+ if (otherContactHash in M.u) {
+ this._privateChangeListener = M.u[otherContactHash].addChangeListener(() => {
+ if (!this.isMounted()) {
+ return 0xDEAD;
+ }
+ this.safeForceUpdate();
+ });
+ }
+ }
+ if (is_chatlink && !chatRoom.isMeeting) {
+ this.state.setNonLoggedInJoinChatDlgTrue = setTimeout(() => {
+ M.safeShowDialog('chat-links-preview-desktop', () => {
+ if (this.isMounted()) {
+ this.setState({
+ nonLoggedInJoinChatDialog: true
+ });
+ }
+ });
+ }, rand_range(5, 10) * 1000);
+ }
+ if (is_chatlink && chatRoom.isMeeting && u_type !== false && u_type < 3) {
+ eventlog(99747, JSON.stringify([1, u_type | 0]), true);
+ }
+ chatRoom._uiIsMounted = true;
+ chatRoom.$rConversationPanel = this;
+ onIdle(() => this.isMounted() && chatRoom.trigger('onComponentDidMount'));
+ ChatdIntegration._waitForProtocolHandler(chatRoom, () => {
+ if (this.isMounted()) {
+ const hasInvalidKeys = chatRoom.hasInvalidKeys();
+ this.setState({
+ hasInvalidKeys,
+ invalidKeysBanner: hasInvalidKeys
+ }, () => this.safeForceUpdate());
+ }
+ });
+ megaChat.rebind(`${megaChat.plugins.meetingsManager.EVENTS.OCCURRENCES_UPDATE}.${this.getUniqueId()}`, () => {
+ return this.isMounted() && this.setState({
+ occurrencesLoading: false
+ });
+ });
+ chatRoom.rebind(`wrOnJoinNotAllowed.${this.getUniqueId()}`, () => {
+ return this.isMounted() && this.setState({
+ waitingRoom: true
+ });
+ });
+ chatRoom.rebind(`wrOnJoinAllowed.${this.getUniqueId()}`, () => {
+ return this.isMounted() && this.setState({
+ waitingRoom: false
+ });
+ });
+ chatRoom.rebind(`onCallUserLimitExceeded.${this.getUniqueId()}`, () => {
+ if (!this.isMounted()) {
+ return;
+ }
+ if (megaChat.initialChatId || is_eplusplus) {
+ this.setState({
+ callUserLimit: true
+ });
+ }
+ });
+ chatRoom.rebind(`onHistTimeoutChange.${this.getUniqueId()}`, () => {
+ if (this.state.historyTimeOutBanner === DISMISS_TRANSITIONS.NOT_SHOWN && chatRoom.historyTimedOut) {
+ this.setState({
+ historyTimeOutBanner: DISMISS_TRANSITIONS.SHOWN
+ });
+ } else if (this.state.historyTimeOutBanner && !chatRoom.historyTimedOut) {
+ this.setState({
+ historyTimeOutBanner: DISMISS_TRANSITIONS.NOT_SHOWN
+ });
+ }
+ });
+ if (chatRoom.options.w) {
+ chatRoom.rebind(`onMembersUpdated.${this.getUniqueId()}`, (ev, {
+ userId,
+ priv
+ }) => {
+ if (userId === u_handle && priv !== ChatRoom.MembersSet.PRIVILEGE_STATE.LEFT) {
+ chatRoom.unbind(`onMembersUpdated.${this.getUniqueId()}`);
+ if (is_chatlink) {
+ return megaChat.routing.reinitAndOpenExistingChat(chatRoom.chatId, chatRoom.publicChatHandle).then(chatRoom => chatRoom.havePendingCall() && priv === ChatRoom.MembersSet.PRIVILEGE_STATE.OPERATOR && chatRoom.joinCall()).catch(dump);
+ }
+ return this.state.waitingRoom && this.setState({
+ waitingRoom: priv !== ChatRoom.MembersSet.PRIVILEGE_STATE.OPERATOR
+ });
+ }
+ });
+ }
+ this.pageChangeListener = mBroadcaster.addListener('beforepagechange', () => M.chat && this.state.waitingRoom && this.setState({
+ waitingRoom: false
+ }, () => this.safeForceUpdate()));
+ }
+ componentWillUnmount() {
+ super.componentWillUnmount();
+ const self = this;
+ const {chatRoom} = self.props;
+ chatRoom._uiIsMounted = true;
+ if (this._privateChangeListener) {
+ const otherContactHash = self.props.chatRoom.getParticipantsExceptMe()[0];
+ if (otherContactHash in M.u) {
+ M.u[otherContactHash].removeChangeListener(this._privateChangeListener);
+ delete this._privateChangeListener;
+ }
+ }
+ mBroadcaster.removeListener(this.pageChangeListener);
+ this.props.chatRoom.unbind(`openAttachCloudDialog.${this.getUniqueId()}`);
+ this.props.chatRoom.unbind(`openSendContactDialog.${this.getUniqueId()}`);
+ this.props.chatRoom.unbind(`openDescriptionDialog.${this.getUniqueId()}`);
+ window.removeEventListener('keydown', self.handleKeyDown);
+ $(document).off(`fullscreenchange.megaChat_${chatRoom.roomId}`);
+ $(document).off(`keydown.keyboardScroll_${chatRoom.roomId}`);
+ this.props.chatRoom.unbind(`wrOnJoinNotAllowed.${this.getUniqueId()}`);
+ this.props.chatRoom.unbind(`wrOnJoinAllowed.${this.getUniqueId()}`);
+ megaChat.unbind(`onIncomingCall.${this.getUniqueId()}`);
+ this.props.chatRoom.unbind(`onHistTimeoutChange.${this.getUniqueId()}`);
+ }
+ componentDidUpdate(prevProps, prevState) {
+ const self = this;
+ const room = this.props.chatRoom;
+ room.megaChat.updateSectionUnreadCount();
+ if (prevProps.isActive === false && self.props.isActive === true) {
+ const $typeArea = $('.messages-textarea:visible:first', this.$container);
+ if ($typeArea.length === 1) {
+ $typeArea.trigger("focus");
+ moveCursortoToEnd($typeArea[0]);
+ }
+ }
+ if (!prevState.renameDialog && self.state.renameDialog === true) {
+ Soon(() => {
+ const $input = $('.chat-rename-dialog input');
+ if ($input && $input[0] && !$($input[0]).is(":focus")) {
+ $input.trigger("focus");
+ $input[0].selectionStart = 0;
+ $input[0].selectionEnd = $input.val().length;
+ }
+ });
+ }
+ if (self.$messages && self.isComponentEventuallyVisible()) {
+ $(window).rebind('pastedimage.chatRoom', (e, blob, fileName) => {
+ if (self.$messages && self.isComponentEventuallyVisible()) {
+ self.setState({
+ 'pasteImageConfirmDialog': [blob, fileName, URL.createObjectURL(blob)]
+ });
+ e.preventDefault();
+ }
+ });
+ self.props.chatRoom.trigger("onComponentDidUpdate");
+ }
+ }
+ isActive() {
+ return document.hasFocus() && this.$messages && this.$messages.is(":visible");
+ }
+ render() {
+ const self = this;
+ const room = this.props.chatRoom;
+ if (!room || !room.roomId) {
+ return null;
+ }
+ const contacts = room.getParticipantsExceptMe();
+ let contactHandle;
+ let contact;
+ let nonLoggedInJoinChatDialog = null;
+ if (self.state.nonLoggedInJoinChatDialog === true) {
+ const usersCount = Object.keys(room.members).length;
+ const closeJoinDialog = () => {
+ onIdle(() => {
+ if ($.dialog === 'chat-links-preview-desktop') {
+ closeDialog();
+ }
+ });
+ self.setState({
+ 'nonLoggedInJoinChatDialog': false
+ });
+ };
+ nonLoggedInJoinChatDialog = JSX_(modalDialogs.A.ModalDialog, {
+ title: l[20596],
+ className: "mega-dialog chat-links-preview-desktop dialog-template-graphic",
+ chatRoom: room,
+ onClose: closeJoinDialog
+ }, JSX_("section", {
+ className: "content"
+ }, JSX_("div", {
+ className: "chatlink-contents"
+ }, JSX_("div", {
+ className: "huge-icon group-chat"
+ }), JSX_("h3", null, JSX_(utils.zT, null, room.getRoomTitle())), JSX_("h5", null, usersCount ? mega.icu.format(l[20233], usersCount) : ''), JSX_("p", null, l[20595]))), JSX_("footer", null, JSX_("div", {
+ className: "bottom-buttons"
+ }, JSX_("button", {
+ className: "mega-button positive",
+ onClick: () => {
+ closeJoinDialog();
+ megaChat.loginOrRegisterBeforeJoining(room.publicChatHandle, false, false, false, () => {
+ megaChat.routing.reinitAndJoinPublicChat(room.chatId, room.publicChatHandle, room.publicChatKey).then(() => {
+ delete megaChat.initialPubChatHandle;
+ }, ex => {
+ console.error("Failed to join room:", ex);
+ });
+ });
+ }
+ }, l[20597]), JSX_("button", {
+ className: "mega-button",
+ onClick: closeJoinDialog
+ }, l[18682]))));
+ }
+ let privateChatDialog;
+ if (self.state.privateChatDialog === true) {
+ const onClose = () => this.setState({
+ privateChatDialog: false
+ });
+ privateChatDialog = JSX_(modalDialogs.A.ModalDialog, {
+ title: l[20594],
+ className: "mega-dialog create-private-chat",
+ chatRoom: room,
+ onClose,
+ dialogType: "action",
+ dialogName: "create-private-chat-dialog"
+ }, JSX_("section", {
+ className: "content"
+ }, JSX_("div", {
+ className: "content-block"
+ }, JSX_("i", {
+ className: "huge-icon lock"
+ }), JSX_("div", {
+ className: "dialog-body-text"
+ }, JSX_("strong", null, l[20590]), JSX_("br", null), JSX_("span", null, l[20591])))), JSX_("footer", null, JSX_("div", {
+ className: "footer-container"
+ }, JSX_("button", {
+ className: "mega-button positive large",
+ onClick: () => {
+ this.props.chatRoom.switchOffPublicMode();
+ onClose();
+ }
+ }, JSX_("span", null, l[20593])))));
+ }
+ let confirmDeleteDialog = null;
+ if (self.state.confirmDeleteDialog === true) {
+ confirmDeleteDialog = JSX_(modalDialogs.A.ConfirmDialog, {
+ chatRoom: room,
+ dialogType: "main",
+ title: l[8004],
+ subtitle: l[8879],
+ name: "delete-message",
+ pref: "1",
+ onClose: () => {
+ self.setState({
+ 'confirmDeleteDialog': false
+ });
+ },
+ onConfirmClicked: () => {
+ const msg = self.state.messageToBeDeleted;
+ if (!msg) {
+ return;
+ }
+ const chatdint = room.megaChat.plugins.chatdIntegration;
+ if (msg.getState() === Message.STATE.SENT || msg.getState() === Message.STATE.DELIVERED || msg.getState() === Message.STATE.NOT_SENT) {
+ const textContents = msg.textContents || '';
+ if (textContents[1] === Message.MANAGEMENT_MESSAGE_TYPES.VOICE_CLIP) {
+ const attachmentMetadata = msg.getAttachmentMeta() || [];
+ Promise.all(attachmentMetadata.map(v => M.moveToRubbish(v.h))).catch(dump);
+ }
+ chatdint.deleteMessage(room, msg.internalId ? msg.internalId : msg.orderValue);
+ msg.deleted = true;
+ msg.textContents = "";
+ } else if (msg.getState() === Message.STATE.NOT_SENT_EXPIRED) {
+ chatdint.discardMessage(room, msg.internalId ? msg.internalId : msg.orderValue);
+ }
+ self.setState({
+ 'confirmDeleteDialog': false,
+ 'messageToBeDeleted': false
+ });
+ if (msg.getState && msg.getState() === Message.STATE.NOT_SENT && !msg.requiresManualRetry) {
+ msg.message = "";
+ msg.textContents = "";
+ msg.messageHtml = "";
+ msg.deleted = true;
+ msg.trigger('onChange', [msg, "deleted", false, true]);
+ }
+ }
+ }, JSX_("section", {
+ className: "content"
+ }, JSX_("div", {
+ className: "content-block"
+ }, JSX_(generic.A, {
+ className: " dialog-wrapper",
+ message: self.state.messageToBeDeleted,
+ hideActionButtons: true,
+ initTextScrolling: true,
+ dialog: true,
+ chatRoom: self.props.chatRoom
+ }))));
+ }
+ if (self.state.pasteImageConfirmDialog) {
+ confirmDeleteDialog = JSX_(modalDialogs.A.ConfirmDialog, {
+ chatRoom: room,
+ title: l[20905],
+ subtitle: l[20906],
+ icon: "sprite-fm-uni icon-question",
+ name: "paste-image-chat",
+ pref: "2",
+ onClose: () => {
+ self.setState({
+ 'pasteImageConfirmDialog': false
+ });
+ },
+ onConfirmClicked: () => {
+ const meta = self.state.pasteImageConfirmDialog;
+ if (!meta) {
+ return;
+ }
+ try {
+ Object.defineProperty(meta[0], 'name', {
+ configurable: true,
+ writeable: true,
+ value: `${Date.now() }.${ M.getSafeName(meta[1] || meta[0].name)}`
+ });
+ } catch (e) {}
+ self.props.chatRoom.scrolledToBottom = true;
+ M.addUpload([meta[0]]);
+ self.setState({
+ 'pasteImageConfirmDialog': false
+ });
+ URL.revokeObjectURL(meta[2]);
+ }
+ }, JSX_("img", {
+ src: self.state.pasteImageConfirmDialog[2],
+ style: {
+ maxWidth: "90%",
+ height: "auto",
+ maxHeight: $(document).outerHeight() * 0.3,
+ margin: '10px auto',
+ display: 'block',
+ border: '1px solid #ccc',
+ borderRadius: '4px'
+ },
+ onLoad (e) {
+ $(e.target).parents('.paste-image-chat').position({
+ of: $(document.body)
+ });
+ }
+ }));
+ }
+ if (self.state.truncateDialog === true) {
+ confirmDeleteDialog = JSX_(modalDialogs.A.ConfirmDialog, {
+ chatRoom: room,
+ title: room.isMeeting ? l.meeting_clear_hist : l[8871],
+ subtitle: room.isMeeting ? l.meeting_trunc_txt : l[8881],
+ icon: "sprite-fm-uni icon-question",
+ name: "truncate-conversation",
+ pref: "3",
+ dontShowAgainCheckbox: false,
+ onClose: () => {
+ self.setState({
+ 'truncateDialog': false
+ });
+ },
+ onConfirmClicked: () => {
+ self.props.chatRoom.scrolledToBottom = true;
+ room.truncate();
+ self.setState({
+ 'truncateDialog': false
+ });
+ }
+ });
+ }
+ if (self.state.archiveDialog === true) {
+ confirmDeleteDialog = JSX_(modalDialogs.A.ConfirmDialog, {
+ chatRoom: room,
+ title: room.isMeeting ? l.meeting_archive_dlg : l[19068],
+ subtitle: room.isMeeting ? l.meeting_archive_dlg_text : l[19069],
+ icon: "sprite-fm-uni icon-question",
+ name: "archive-conversation-dialog",
+ pref: "4",
+ onClose: () => {
+ self.setState({
+ 'archiveDialog': false
+ });
+ },
+ onConfirmClicked: () => {
+ self.props.chatRoom.scrolledToBottom = true;
+ room.archive();
+ self.setState({
+ 'archiveDialog': false
+ });
+ }
+ });
+ }
+ if (self.state.unarchiveDialog === true) {
+ confirmDeleteDialog = JSX_(modalDialogs.A.ConfirmDialog, {
+ chatRoom: room,
+ title: room.isMeeting ? l.meeting_unarchive_dlg : l[19063],
+ subtitle: room.isMeeting ? l.meeting_unarchive_dlg_text : l[19064],
+ icon: "sprite-fm-uni icon-question",
+ name: "unarchive-conversation-dialog",
+ pref: "5",
+ onClose: () => {
+ self.setState({
+ 'unarchiveDialog': false
+ });
+ },
+ onConfirmClicked: () => {
+ self.props.chatRoom.scrolledToBottom = true;
+ room.unarchive();
+ self.setState({
+ 'unarchiveDialog': false
+ });
+ }
+ });
+ }
+ let topicInfo = null;
+ const isUpcoming = room.scheduledMeeting && room.scheduledMeeting.isUpcoming;
+ const isRecurring = room.scheduledMeeting && room.scheduledMeeting.isRecurring;
+ if (room.type === 'group' || room.type === 'public') {
+ topicInfo = JSX_("div", {
+ className: "chat-topic-info"
+ }, JSX_("div", {
+ className: `
+ chat-topic-icon
+ ${room.isMeeting ? 'meeting-icon' : ''}
+ `
+ }, JSX_("i", {
+ className: room.isMeeting ? 'sprite-fm-mono icon-video-call-filled' : 'sprite-fm-uni icon-chat-group'
+ })), JSX_("div", {
+ className: "chat-topic-text"
+ }, JSX_("span", {
+ className: "txt"
+ }, JSX_(utils.zT, null, room.getRoomTitle()), isUpcoming && isRecurring && JSX_("i", {
+ className: "sprite-fm-mono recurring-meeting icon-repeat-thin-solid"
+ })), JSX_("span", {
+ className: "txt small"
+ }, is_chatlink && isUpcoming && !isRecurring ? this.renderUpcomingInfo() : JSX_(ui_contacts.U5, {
+ chatRoom: room
+ }))));
+ } else {
+ contactHandle = contacts[0];
+ contact = M.u[contactHandle || u_handle];
+ topicInfo = megaChat.WITH_SELF_NOTE && room.isNote ? JSX_("div", {
+ className: "note-chat-topic"
+ }, JSX_("div", {
+ className: "note-chat-signifier"
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-file-text-thin-outline note-chat-icon"
+ })), JSX_("span", {
+ className: "note-chat-label"
+ }, l.note_label)) : JSX_(ui_contacts.nB, {
+ key: contact.u,
+ className: "short",
+ chatRoom: room,
+ contact,
+ noContextButton: true,
+ showLastGreen: true
+ });
+ }
+ let historyRetentionDialog = null;
+ if (self.state.showHistoryRetentionDialog === true) {
+ historyRetentionDialog = JSX_(HistoryRetentionDialog, {
+ chatRoom: room,
+ title: '',
+ name: "rename-group",
+ className: "",
+ onClose: () => {
+ self.setState({
+ showHistoryRetentionDialog: false
+ });
+ }
+ });
+ }
+ if (this.state.waitingRoom) {
+ return JSX_(WaitingRoom, {
+ chatRoom: room,
+ havePendingCall: room.havePendingCall(),
+ onWaitingRoomLeave: () => {
+ let _room$call;
+ (_room$call = room.call) == null || _room$call.destroy();
+ if (is_eplusplus) {
+ room.leave(true);
+ return onIdle(M.logout);
+ }
+ return this.setState({
+ waitingRoom: false
+ }, () => {
+ onIdle(() => {
+ if (megaChat.initialChatId) {
+ megaChat.initialChatId = undefined;
+ loadSubPage(getLandingPage());
+ }
+ });
+ });
+ }
+ });
+ }
+ if (this.state.callUserLimit) {
+ return JSX_(ChatOverlay, {
+ overlayType: ChatOverlays.PARTICIPANT_LIMIT,
+ onClose: () => {
+ if (is_eplusplus) {
+ location.replace('https://mega.io');
+ } else {
+ this.setState({
+ callUserLimit: false
+ });
+ }
+ }
+ });
+ }
+ const startCallDisabled = isStartCallDisabled(room) || room.iAmWaitingRoomPeer();
+ return JSX_("div", {
+ ref: this.domRef,
+ className: `
+ conversation-panel
+ ${room.type === 'public' ? 'group-chat ' : ''}
+ ${room.type}-chat
+ ${!room.isCurrentlyActive || megaChat._joinDialogIsShown ? 'hidden' : ''}
+ `,
+ onMouseMove: () => self.onMouseMove(),
+ "data-room-id": self.props.chatRoom.chatId
+ }, JSX_(external_React_.Suspense, {
+ fallback: JSX_(fallback.A, null)
+ }, room.meetingsLoading && JSX_(Loading, {
+ chatRoom: room,
+ title: room.meetingsLoading.title
+ }), room.call && JSX_(Call, {
+ chatRoom: room,
+ peers: room.call.peers,
+ call: room.call,
+ minimized: this.state.callMinimized,
+ typingAreaText: this.state.typingAreaText,
+ onCallMinimize: () => {
+ return this.state.callMinimized ? null : this.setState({
+ callMinimized: true
+ }, () => {
+ this.toggleExpandedFlag();
+ this.safeForceUpdate();
+ });
+ },
+ onCallExpand: () => {
+ return this.state.callMinimized && this.setState({
+ callMinimized: false
+ }, () => {
+ $.hideTopMenu();
+ if ($.dialog) {
+ closeDialog();
+ }
+ loadSubPage('fm/chat');
+ room.show();
+ this.toggleExpandedFlag();
+ });
+ },
+ didMount: () => {
+ this.toggleExpandedFlag();
+ if (room.isMeeting) {
+ room.updatePublicHandle().catch(dump);
+ }
+ },
+ willUnmount: minimised => this.setState({
+ callMinimized: false
+ }, () => minimised ? null : this.toggleExpandedFlag()),
+ onCallEnd: () => this.safeForceUpdate(),
+ onDeleteMessage: msg => this.handleDeleteDialog(msg),
+ onTypingAreaChanged: this.updateTypingAreaText,
+ parent: this
+ }), megaChat.initialPubChatHandle && room.publicChatHandle === megaChat.initialPubChatHandle && !room.call && room.isMeeting && !room.call && room.activeCallIds.length > 0 && JSX_(Join, {
+ initialView: u_type || is_eplusplus ? workflow_utils.j.ACCOUNT : workflow_utils.j.INITIAL,
+ chatRoom: room,
+ onJoinGuestClick: (firstName, lastName, audioFlag, videoFlag) => {
+ room.meetingsLoading = l.joining;
+ u_eplusplus(firstName, lastName).then(() => {
+ return megaChat.routing.reinitAndJoinPublicChat(room.chatId, room.publicChatHandle, room.publicChatKey);
+ }).then(() => {
+ delete megaChat.initialPubChatHandle;
+ return megaChat.getChatById(room.chatId).joinCall(audioFlag, videoFlag);
+ }).catch(ex => {
+ if (d) {
+ console.error('E++ account failure!', ex);
+ }
+ setTimeout(() => {
+ msgDialog('warninga', l[135], l.eplusplus_create_failed, escapeHTML(api_strerror(ex) || ex));
+ }, 1234);
+ eventlog(99745, JSON.stringify([1, String(ex).split('\n')[0]]));
+ });
+ },
+ onJoinClick: (audioFlag, videoFlag) => {
+ const {chatId} = room;
+ if (room.members[u_handle]) {
+ delete megaChat.initialPubChatHandle;
+ megaChat.routing.reinitAndOpenExistingChat(chatId, room.publicChatHandle).then(() => {
+ return megaChat.getChatById(chatId).joinCall(audioFlag, videoFlag);
+ }).catch(ex => {
+ console.error("Failed to open existing room and join call:", ex);
+ });
+ } else {
+ megaChat.routing.reinitAndJoinPublicChat(chatId, room.publicChatHandle, room.publicChatKey).then(() => {
+ delete megaChat.initialPubChatHandle;
+ return megaChat.getChatById(chatId).joinCall(audioFlag, videoFlag);
+ }).catch(ex => {
+ console.error("Failed to join room:", ex);
+ });
+ }
+ }
+ })), JSX_("div", {
+ className: `
+ chat-content-block
+ ${room.megaChat.chatUIFlags.convPanelCollapse ? 'no-pane' : 'with-pane'}
+ `
+ }, room.megaChat.chatUIFlags.convPanelCollapse ? null : JSX_(ConversationRightArea, {
+ isVisible: this.props.chatRoom.isCurrentlyActive,
+ chatRoom: this.props.chatRoom,
+ roomFlags: this.props.chatRoom.flags,
+ members: this.props.chatRoom.membersSetFromApi,
+ messagesBuff: room.messagesBuff,
+ pushSettingsValue: pushNotificationSettings.getDnd(this.props.chatRoom.chatId),
+ occurrencesLoading: this.state.occurrencesLoading,
+ onStartCall: mode => (0,meetings_utils.dQ)(room.haveActiveCall(), room).then(() => this.startCall(mode)).catch(() => d && console.warn('Already in a call.')),
+ onAttachFromComputerClicked: () => this.props.chatRoom.uploadFromComputer(),
+ onTruncateClicked: () => this.setState({
+ truncateDialog: true
+ }),
+ onArchiveClicked: () => this.setState({
+ archiveDialog: true
+ }),
+ onUnarchiveClicked: () => this.setState({
+ unarchiveDialog: true
+ }),
+ onRenameClicked: () => {
+ this.setState({
+ renameDialog: true,
+ renameDialogValue: this.props.chatRoom.getRoomTitle()
+ });
+ },
+ onGetManageChatLinkClicked: () => this.setState({
+ chatLinkDialog: true
+ }),
+ onMakePrivateClicked: () => this.setState({
+ privateChatDialog: true
+ }),
+ onCloseClicked: () => room.destroy(),
+ onJoinViaPublicLinkClicked: () => room.joinViaPublicHandle(),
+ onSwitchOffPublicMode: topic => room.switchOffPublicMode(topic),
+ onAttachFromCloudClicked: () => this.setState({
+ attachCloudDialog: true
+ }),
+ onPushSettingsClicked: () => M.safeShowDialog('push-settings-dialog', () => this.setState({
+ pushSettingsDialog: true
+ })),
+ onPushSettingsToggled: () => {
+ return room.dnd || room.dnd === 0 ? this.setState({
+ pushSettingsValue: null
+ }, () => pushNotificationSettings.disableDnd(room.chatId)) : pushNotificationSettings.setDnd(room.chatId, 0);
+ },
+ onHistoryRetentionConfig: () => this.setState({
+ showHistoryRetentionDialog: true
+ }),
+ onAddParticipantSelected: contactHashes => {
+ room.scrolledToBottom = true;
+ if (room.type === 'group' || room.type === 'public') {
+ if (room.options.w && room.call) {
+ let _room$call$sfuClient;
+ (_room$call$sfuClient = room.call.sfuClient) == null || _room$call$sfuClient.wrAllowJoin(contactHashes);
+ }
+ return room.trigger('onAddUserRequest', [contactHashes]);
+ }
+ loadingDialog.show();
+ megaChat.trigger('onNewGroupChatRequest', [[...room.getParticipantsExceptMe(), ...contactHashes], {
+ keyRotation: false,
+ topic: ''
+ }]);
+ },
+ onShowScheduledDescription: room.scheduledMeeting ? () => this.setState({
+ descriptionDialog: true
+ }) : null
+ }), this.state.sendContactDialog && JSX_(this.SelectContactDialog, null), this.state.descriptionDialog && JSX_(this.DescriptionDialog, null), this.state.pushSettingsDialog && JSX_(this.PushSettingsDialog, null), JSX_(external_React_.Suspense, {
+ fallback: JSX_(fallback.A, null)
+ }, this.state.attachCloudDialog && JSX_(CloudBrowserDialog, {
+ room,
+ allowAttachFolders: true,
+ onSelected: nodes => {
+ this.selectedNodes = nodes;
+ },
+ onAttachClicked: () => {
+ this.setState({
+ attachCloudDialog: false
+ }, () => {
+ chatRoom.scrolledToBottom = true;
+ chatRoom.attachNodes(this.selectedNodes).catch(dump);
+ });
+ },
+ onClose: () => {
+ this.setState({
+ attachCloudDialog: false
+ }, () => {
+ this.selectedNodes = [];
+ });
+ }
+ })), privateChatDialog, nonLoggedInJoinChatDialog, confirmDeleteDialog, historyRetentionDialog, null, this.state.renameDialog && JSX_(this.RenameDialog, null), this.state.chatLinkDialog && JSX_(ChatlinkDialog, {
+ chatRoom: this.props.chatRoom,
+ onClose: () => this.setState({
+ chatLinkDialog: false
+ })
+ }), JSX_("div", {
+ className: `
+ chat-topic-block
+ ${room.isNote ? 'is-note' : ''}
+ `
+ }, JSX_("div", {
+ className: "chat-topic-buttons"
+ }, room.type === 'public' && room.isMeeting && JSX_(buttons.$, {
+ className: "mega-button small share-meeting-button",
+ label: l.share_meeting_button,
+ onClick: () => this.setState({
+ chatLinkDialog: true
+ }, () => eventlog(500230))
+ }), JSX_(buttons.$, {
+ className: "right",
+ disableCheckingVisibility: true,
+ icon: "sprite-fm-mono icon-info-filled",
+ onClick: () => room.megaChat.toggleUIFlag('convPanelCollapse')
+ }), room.isNote ? null : JSX_(REaCt().Fragment, null, JSX_("div", {
+ "data-simpletip": l.unsupported_browser_video,
+ "data-simpletipposition": "top",
+ "data-simpletipoffset": "5",
+ className: `
+ ${!megaChat.hasSupportForCalls ? 'simpletip' : ''}
+ right
+ ${startCallDisabled ? 'disabled' : ''}
+ `
+ }, JSX_(buttons.$, {
+ icon: "sprite-fm-mono icon-video-call-filled",
+ onClick: () => startCallDisabled ? false : (0,meetings_utils.dQ)(room.haveActiveCall(), room).then(() => this.startCall(meetings_utils.ZE.VIDEO)).catch(() => d && console.warn('Already in a call.')).then(() => room.isMeeting ? eventlog(500289) : eventlog(500290))
+ })), JSX_("div", {
+ "data-simpletip": l.unsupported_browser_audio,
+ "data-simpletipposition": "top",
+ "data-simpletipoffset": "5",
+ className: `
+ ${!megaChat.hasSupportForCalls ? 'simpletip' : ''}
+ right
+ ${startCallDisabled ? 'disabled' : ''}
+ `
+ }, JSX_(buttons.$, {
+ icon: "sprite-fm-mono icon-phone",
+ onClick: () => startCallDisabled ? false : (0,meetings_utils.dQ)(room.haveActiveCall(), room).then(() => this.startCall(meetings_utils.ZE.AUDIO)).catch(() => d && console.warn('Already in a call.')).then(() => room.isMeeting ? eventlog(500291) : eventlog(500292))
+ })))), topicInfo), JSX_("div", {
+ ref: this.messagesBlockRef,
+ className: `
+ messages-block
+ ${""}
+ `
+ }, this.state.hasInvalidKeys && this.state.invalidKeysBanner && JSX_(Alert, {
+ type: Alert.TYPE.HIGH,
+ className: `
+ ${megaChat.chatUIFlags.convPanelCollapse ? 'full-span' : ''}
+ ${this.props.offset === ALERTS_BASE_OFFSET ? 'single-alert' : ''}
+ `,
+ offset: this.props.offset === ALERTS_BASE_OFFSET ? 0 : this.props.offset,
+ content: JSX_(REaCt().Fragment, null, l.chat_key_failed_banner.split('[A]')[0], JSX_("a", {
+ onClick: () => M.reload()
+ }, l.chat_key_failed_banner.substring(l.chat_key_failed_banner.indexOf('[A]') + 3, l.chat_key_failed_banner.indexOf('[/A]'))), l.chat_key_failed_banner.split('[/A]')[1]),
+ onClose: () => this.setState({
+ invalidKeysBanner: false
+ })
+ }), this.state.historyTimeOutBanner === DISMISS_TRANSITIONS.SHOWN && JSX_(Alert, {
+ type: Alert.TYPE.ERROR,
+ className: `
+ ${megaChat.chatUIFlags.convPanelCollapse ? 'full-span' : ''}
+ ${this.props.offset === ALERTS_BASE_OFFSET ? 'single_alert' : ''}
+ history-timeout-banner
+ `,
+ offset: this.props.offset === ALERTS_BASE_OFFSET ? 0 : this.props.offset,
+ content: JSX_(REaCt().Fragment, null, l.chat_timeout_banner, JSX_("a", {
+ onClick: () => location.reload()
+ }, l[85])),
+ onClose: () => this.setState({
+ historyTimeOutBanner: DISMISS_TRANSITIONS.DISMISSED
+ })
+ }), JSX_(historyPanel.A, (0,esm_extends.A)({}, this.props, {
+ onMessagesListScrollableMount: mls => {
+ this.messagesListScrollable = mls;
+ },
+ ref: historyPanel => {
+ this.historyPanel = historyPanel;
+ },
+ onDeleteClicked: msg => this.handleDeleteDialog(msg)
+ })), !is_chatlink && room.state !== ChatRoom.STATE.LEFT && navigator.onLine && room.scheduledMeeting && !room.isArchived() && !this.state.hasInvalidKeys && !isStartCallDisabled(room) ? JSX_(StartMeetingNotification, {
+ chatRoom: room,
+ offset: this.props.offset,
+ onWaitingRoomJoin: () => this.setState({
+ waitingRoom: true
+ }),
+ onStartCall: mode => {
+ return isStartCallDisabled(room) ? null : (0,meetings_utils.dQ)(true, room).then(() => this.startCall(mode, true)).catch(ex => d && console.warn(`Already in a call. ${ex}`));
+ }
+ }) : null, !is_chatlink && room.state !== ChatRoom.STATE.LEFT && (room.havePendingGroupCall() || room.havePendingCall()) && !this.state.hasInvalidKeys && navigator.onLine ? JSX_(JoinCallNotification, {
+ rhpCollapsed: megaChat.chatUIFlags.convPanelCollapse,
+ chatRoom: room,
+ offset: this.props.offset
+ }) : null, room.isAnonymous() ? JSX_("div", {
+ className: "join-chat-block"
+ }, JSX_("div", {
+ className: "mega-button large positive",
+ onClick: () => {
+ const join = () => {
+ megaChat.routing.reinitAndJoinPublicChat(room.chatId, room.publicChatHandle, room.publicChatKey).then(() => delete megaChat.initialPubChatHandle, ex => console.error("Failed to join room:", ex));
+ };
+ if (u_type === 0) {
+ return loadSubPage('register');
+ }
+ if (u_type === false) {
+ clearTimeout(self.state.setNonLoggedInJoinChatDlgTrue);
+ megaChat.loginOrRegisterBeforeJoining(room.publicChatHandle, false, false, false, join);
+ return;
+ }
+ clearTimeout(self.state.setNonLoggedInJoinChatDlgTrue);
+ join();
+ }
+ }, l[20597])) : JSX_(composedTextArea.A, {
+ chatRoom: room,
+ parent: this,
+ containerRef: this.messagesBlockRef,
+ typingAreaText: this.state.typingAreaText,
+ onTypingAreaChanged: this.updateTypingAreaText
+ }))));
+ }
+}, (0,applyDecoratedDescriptor.A)(conversationpanel_class.prototype, "onMouseMove", [conversationpanel_dec], Object.getOwnPropertyDescriptor(conversationpanel_class.prototype, "onMouseMove"), conversationpanel_class.prototype), (0,applyDecoratedDescriptor.A)(conversationpanel_class.prototype, "render", [_dec2], Object.getOwnPropertyDescriptor(conversationpanel_class.prototype, "render"), conversationpanel_class.prototype), conversationpanel_class);
+class ConversationPanels extends mixins.w9 {
+ constructor(props) {
+ super(props);
+ this.domRef = REaCt().createRef();
+ this.notificationListener = 'meetings:notificationPermissions';
+ this.notificationGranted = undefined;
+ this.notificationHelpURL = `${l.mega_help_host}/chats-meetings/meetings/enable-notification-browser-system-permission`;
+ this.state = {
+ supportAlert: undefined,
+ notificationsPermissions: undefined,
+ alertsOffset: ALERTS_BASE_OFFSET
+ };
+ this.closeSupportAlert = () => this.setState({
+ supportAlert: false
+ }, () => mega.config.set('nocallsup', 1));
+ this.onNotificationsGranted = () => {
+ msgDialog('info', '', l.notifications_permissions_granted_title, l.notifications_permissions_granted_info.replace('[A]', ``).replace('[/A]', ''));
+ this.notificationGranted = new Notification(l.notification_granted_title, {
+ body: l.notification_granted_body
+ });
+ };
+ this.state.supportAlert = !megaChat.hasSupportForCalls;
+ this.state.notificationsPermissions = window.Notification ? Notification.permission : 'granted';
+ }
+ renderNotificationsPending() {
+ return JSX_(Alert, {
+ type: Alert.TYPE.LIGHT,
+ className: `
+ ${megaChat.chatUIFlags.convPanelCollapse ? 'full-span' : ''}
+ ${this.props.isEmpty ? 'empty-state' : ''}
+ `,
+ ref: ref => {
+ this.notifPendingRef = ref;
+ },
+ onTransition: ref => this.setState({
+ alertsOffset: ref ? ref.current.offsetHeight : ALERTS_BASE_OFFSET
+ }),
+ onClose: () => {
+ this.setState({
+ notificationsPermissions: undefined
+ }, () => {
+ showToast('success', l.notifications_permissions_toast_title, l.notifications_permissions_toast_control, '', () => loadSubPage('fm/account/notifications'));
+ });
+ }
+ }, l.notifications_permissions_pending, JSX_("div", {
+ className: "meetings-alert-control"
+ }, JSX_("a", {
+ href: "#",
+ onClick: ev => {
+ ev.preventDefault();
+ Notification.requestPermission().then(status => {
+ this.setState({
+ notificationsPermissions: status
+ }, () => onIdle(() => this.state.notificationsPermissions === 'granted' && this.onNotificationsGranted()));
+ }).catch(ex => d && console.warn(`Failed to retrieve permissions: ${ex}`));
+ }
+ }, l.notifications_permissions_enable)));
+ }
+ renderNotificationsBlocked() {
+ return JSX_(Alert, {
+ type: Alert.TYPE.MEDIUM,
+ className: `
+ ${megaChat.chatUIFlags.convPanelCollapse ? 'full-span' : ''}
+ ${this.props.isEmpty ? 'empty-state' : ''}
+ `,
+ ref: ref => {
+ this.notifBlockedRef = ref;
+ },
+ onTransition: ref => this.setState({
+ alertsOffset: ref ? ref.current.offsetHeight : ALERTS_BASE_OFFSET
+ }),
+ onClose: () => this.setState({
+ notificationsPermissions: undefined
+ })
+ }, JSX_(utils.P9, {
+ content: l.notifications_permissions_denied_info.replace('[A]', ``).replace('[/A]', '')
+ }));
+ }
+ componentWillUnmount() {
+ super.componentWillUnmount();
+ mBroadcaster.removeListener(this.notificationListener);
+ }
+ componentDidMount() {
+ let _this$props$onMount, _this$props;
+ super.componentDidMount();
+ (_this$props$onMount = (_this$props = this.props).onMount) == null || _this$props$onMount.call(_this$props);
+ megaChat.chats.forEach(chatRoom => {
+ const {
+ scheduledMeeting
+ } = chatRoom;
+ if (scheduledMeeting && !scheduledMeeting.isPast && scheduledMeeting.isRecurring) {
+ scheduledMeeting.getOccurrences().catch(nop);
+ }
+ });
+ mBroadcaster.addListener(this.notificationListener, notificationsPermissions => this.isMounted() && this.setState({
+ notificationsPermissions
+ }));
+ window.addEventListener('resize', () => {
+ delay('conv-panels-resize', () => {
+ if (!M.chat || !this.isMounted()) {
+ return;
+ }
+ const {
+ alertsOffset
+ } = this.state;
+ if (alertsOffset !== ALERTS_BASE_OFFSET) {
+ let _this$notifBlockedRef, _this$notifPendingRef, _this$noSupportRef;
+ const state = {};
+ if ((_this$notifBlockedRef = this.notifBlockedRef) != null && _this$notifBlockedRef.current) {
+ state.alertsOffset = this.notifBlockedRef.current.offsetHeight;
+ } else if ((_this$notifPendingRef = this.notifPendingRef) != null && _this$notifPendingRef.current) {
+ state.alertsOffset = this.notifPendingRef.current.offsetHeight;
+ } else if ((_this$noSupportRef = this.noSupportRef) != null && _this$noSupportRef.current) {
+ state.alertsOffset = this.noSupportRef.current.offsetHeight;
+ }
+ if (state.alertsOffset !== alertsOffset) {
+ this.setState(state);
+ }
+ }
+ });
+ });
+ }
+ render() {
+ const {
+ routingSection,
+ chatUIFlags,
+ isEmpty,
+ onToggleExpandedFlag
+ } = this.props;
+ const {
+ notificationsPermissions,
+ supportAlert,
+ alertsOffset
+ } = this.state;
+ const now = Date.now();
+ return JSX_("div", {
+ ref: this.domRef,
+ className: "conversation-panels"
+ }, routingSection === 'contacts' || is_chatlink ? null : window.Notification && notificationsPermissions !== 'granted' && JSX_(REaCt().Fragment, null, notificationsPermissions === 'default' && this.renderNotificationsPending(), notificationsPermissions === 'denied' && this.renderNotificationsBlocked()), routingSection === 'contacts' ? null : supportAlert && !mega.config.get('nocallsup') && JSX_(Alert, {
+ type: Alert.TYPE.MEDIUM,
+ className: `
+ ${megaChat.chatUIFlags.convPanelCollapse ? 'full-span' : ''}
+ ${isEmpty ? 'empty-state' : ''}
+ unsupported-call-alert
+ `,
+ content: (0,meetings_utils.HV)(),
+ ref: ref => {
+ this.noSupportRef = ref;
+ },
+ onTransition: ref => this.setState({
+ alertsOffset: ref ? ref.current.offsetHeight : ALERTS_BASE_OFFSET
+ }),
+ onClose: this.closeSupportAlert
+ }), megaChat.chats.map(chatRoom => {
+ if (chatRoom.isCurrentlyActive || now - chatRoom.lastShownInUI < 900000) {
+ return JSX_(ConversationPanel, {
+ key: `${chatRoom.roomId}_${chatRoom.instanceIndex}`,
+ chatRoom,
+ roomType: chatRoom.type,
+ isExpanded: chatRoom.megaChat.chatUIFlags.convPanelCollapse,
+ isActive: chatRoom.isCurrentlyActive,
+ messagesBuff: chatRoom.messagesBuff,
+ chatUIFlags,
+ offset: alertsOffset,
+ onToggleExpandedFlag
+ });
+ }
+ return null;
+ }));
+ }
+}
+function isStartCallDisabled(room) {
+ if ((0,meetings_utils.P)()) {
+ return true;
+ }
+ if (!megaChat.hasSupportForCalls) {
+ return true;
+ }
+ return !room.isOnlineForCalls() || room.isReadOnly() || !room.chatId || room.call || (room.type === "group" || room.type === "public") && false || room.getCallParticipants().length > 0;
+}
+
+ },
+
+ 8596
+(_, EXP_, REQ_) {
+
+REQ_.r(EXP_);
+ REQ_.d(EXP_, {
+ "default": () => EmptyConversationsPanel
+ });
+ const react0__ = REQ_(1594);
+ const react0___default = REQ_.n(react0__);
+ const _ui_buttons_jsx1__ = REQ_(5155);
+ const _link_jsx2__ = REQ_(4649);
+ const _ui_utils_jsx3__ = REQ_(6411);
+
+
+
+
+const Tile = ({
+ title,
+ desc,
+ imgClass,
+ buttonPrimary,
+ buttonSecondary,
+ onClickPrimary,
+ onClickSecondary
+}) => JSX_("div", {
+ className: "conversations-empty-tile"
+}, JSX_("span", {
+ className: `chat-tile-img ${imgClass}`
+}), JSX_("div", {
+ className: "tile-content"
+}, JSX_("h2", null, title), JSX_("div", null, desc), JSX_(_ui_buttons_jsx1__ .$, {
+ className: "mega-button positive",
+ label: buttonPrimary,
+ onClick: onClickPrimary
+}), buttonSecondary && JSX_(_ui_buttons_jsx1__ .$, {
+ className: "mega-button action positive",
+ icon: "sprite-fm-mono icon-link",
+ label: buttonSecondary,
+ onClick: onClickSecondary
+})));
+class EmptyConversationsPanel extends react0___default().Component {
+ constructor(...args) {
+ super(...args);
+ this.domRef = react0___default().createRef();
+ this.state = {
+ linkData: ''
+ };
+ }
+ componentDidMount() {
+ (M.account && M.account.contactLink ? Promise.resolve(M.account.contactLink) : api.send('clc')).then(res => {
+ let _this$domRef;
+ if ((_this$domRef = this.domRef) != null && _this$domRef.current && typeof res === 'string') {
+ const prefix = res.startsWith('C!') ? '' : 'C!';
+ this.setState({
+ linkData: `${getBaseUrl()}/${prefix}${res}`
+ });
+ }
+ }).catch(dump);
+ }
+ render() {
+ const {
+ isMeeting,
+ onNewChat,
+ onStartMeeting,
+ onScheduleMeeting
+ } = this.props;
+ const {
+ linkData
+ } = this.state;
+ return JSX_("div", {
+ ref: this.domRef,
+ className: "conversations-empty"
+ }, JSX_("div", {
+ className: "conversations-empty-header"
+ }, JSX_("h1", null, isMeeting ? l.meetings_empty_header : l.chat_empty_header), JSX_("h3", null, (0,_ui_utils_jsx3__ .lI)(isMeeting ? l.meetings_empty_subheader : l.chat_empty_subheader, '[A]', _link_jsx2__ .A, {
+ onClick: () => {
+ window.open('https://mega.io/chatandmeetings', '_blank', 'noopener,noreferrer');
+ eventlog(this.props.isMeeting ? 500281 : 500280);
+ }
+ }))), JSX_("div", {
+ className: "conversations-empty-content"
+ }, JSX_(Tile, {
+ title: isMeeting ? l.meetings_empty_calls_head : l.invite_friend_btn,
+ desc: isMeeting ? l.meetings_empty_calls_desc : l.chat_empty_contact_desc,
+ imgClass: isMeeting ? 'empty-meetings-call' : 'empty-chat-contacts',
+ buttonPrimary: isMeeting ? l.new_meeting_start : l[71],
+ buttonSecondary: !isMeeting && linkData && l.copy_contact_link_btn,
+ onClickPrimary: () => {
+ if (isMeeting) {
+ onStartMeeting();
+ eventlog(500275);
+ } else {
+ contactAddDialog();
+ eventlog(500276);
+ }
+ },
+ onClickSecondary: () => {
+ copyToClipboard(linkData, `${l[371]}${linkData}`);
+ delay('chat-event-copy-contact-link', () => eventlog(500277));
+ }
+ }), JSX_(Tile, {
+ title: isMeeting ? l.meetings_empty_schedule_head : l.chat_empty_add_chat_header,
+ desc: isMeeting ? l.meetings_empty_schedule_desc : l.chat_empty_add_chat_desc,
+ imgClass: isMeeting ? 'empty-meetings-schedule' : 'empty-chat-new',
+ buttonPrimary: isMeeting ? l.schedule_meeting_start : l.add_chat,
+ onClickPrimary: () => {
+ if (isMeeting) {
+ onScheduleMeeting();
+ eventlog(500278);
+ } else {
+ onNewChat();
+ eventlog(500279);
+ }
+ }
+ })));
+ }
+}
+
+ },
+
+ 1635
+(_, EXP_, REQ_) {
+
+ REQ_.d(EXP_, {
+ Hc: () => GIF_PANEL_CLASS,
+ L9: () => MAX_HEIGHT,
+ kg: () => LABELS,
+ nC: () => API
+ });
+const GIF_PANEL_CLASS = 'gif-panel-wrapper';
+const MAX_HEIGHT = 550;
+const API = {
+ HOSTNAME: 'https://giphy.mega.nz/',
+ ENDPOINT: 'v1/gifs',
+ SCHEME: 'giphy://',
+ convert: path => {
+ if (path && typeof path === 'string') {
+ const FORMAT = [API.SCHEME, API.HOSTNAME];
+ if (path.indexOf(API.SCHEME) === 0 || path.indexOf(API.HOSTNAME) === 0) {
+ return String.prototype.replace.apply(path, path.indexOf(API.SCHEME) === 0 ? FORMAT : FORMAT.reverse());
+ }
+ }
+ },
+ LIMIT: 50,
+ OFFSET: 50
+};
+const LABELS = freeze({
+ get SEARCH() {
+ return l[24025];
+ },
+ get NO_RESULTS() {
+ return l[24050];
+ },
+ get NOT_AVAILABLE() {
+ return l[24512];
+ },
+ get END_OF_RESULTS() {
+ return l[24156];
+ }
+});
+
+ },
+
+ 5522
+(_, EXP_, REQ_) {
+
+
+// EXPORTS
+REQ_.d(EXP_, {
+ A: () => HistoryPanel
+});
+
+// EXTERNAL MODULE: ./node_modules/@babel/runtime/helpers/esm/applyDecoratedDescriptor.js
+const applyDecoratedDescriptor = REQ_(793);
+// EXTERNAL MODULE: external "React"
+const external_React_ = REQ_(1594);
+const REaCt = REQ_.n(external_React_);
+// EXTERNAL MODULE: ./js/chat/mixins.js
+const mixins = REQ_(8264);
+// EXTERNAL MODULE: ./js/ui/utils.jsx
+const utils = REQ_(6411);
+// EXTERNAL MODULE: ./js/chat/ui/contacts.jsx
+const contacts = REQ_(8022);
+// EXTERNAL MODULE: ./js/chat/ui/messages/mixin.jsx
+const mixin = REQ_(855);
+;// ./js/chat/ui/messages/alterParticipants.jsx
+
+
+
+
+class AltPartsConvMessage extends mixin.M {
+ haveMoreContactListeners() {
+ if (!this.props.message || !this.props.message.meta) {
+ return false;
+ }
+ const {
+ included,
+ excluded
+ } = this.props.message.meta;
+ return array.unique([...included || [], ...excluded || []]);
+ }
+ render() {
+ const self = this;
+ const {message} = this.props;
+ const contact = self.getContact();
+ const timestampInt = self.getTimestamp();
+ const timestamp = self.getTimestampAsString();
+ const datetime = JSX_("div", {
+ className: "message date-time simpletip",
+ "data-simpletip": time2date(timestampInt, 17)
+ }, timestamp);
+ let displayName;
+ if (contact) {
+ displayName = M.getNameByHandle(contact.u);
+ } else {
+ displayName = contact;
+ }
+ const messages = [];
+ message.meta.included.forEach((h) => {
+ const otherContact = M.u[h] ? M.u[h] : {
+ 'u': h,
+ h,
+ 'c': 0
+ };
+ const avatar = JSX_(contacts.eu, {
+ contact: otherContact,
+ chatRoom: self.props.chatRoom,
+ className: "message avatar-wrapper small-rounded-avatar"
+ });
+ const otherDisplayName = M.getNameByHandle(otherContact.u);
+ const isSelfJoin = h === contact.u;
+ let text = isSelfJoin ? l[23756] : l[8907];
+ if (self.props.chatRoom.isMeeting) {
+ text = isSelfJoin ? l.meeting_mgmt_user_joined : l.meeting_mgmt_user_added;
+ }
+ text = text.replace('%1', megaChat.html(otherDisplayName));
+ if (!isSelfJoin) {
+ text = text.replace('%2', `${megaChat.html(displayName)}`);
+ }
+ messages.push(JSX_("div", {
+ className: "message body",
+ "data-id": `id${ message.messageId}`,
+ key: `${message.messageId }_${ h}`
+ }, avatar, JSX_("div", {
+ className: "message content-area small-info-txt selectable-txt"
+ }, JSX_(contacts.bq, {
+ className: "message",
+ contact: otherContact,
+ chatRoom: self.props.chatRoom,
+ label: JSX_(utils.zT, null, otherDisplayName)
+ }), datetime, JSX_("div", {
+ className: "message text-block"
+ }, JSX_(utils.P9, null, text)))));
+ });
+ message.meta.excluded.forEach((h) => {
+ const otherContact = M.u[h] ? M.u[h] : {
+ 'u': h,
+ h,
+ 'c': 0
+ };
+ const avatar = JSX_(contacts.eu, {
+ contact: otherContact,
+ chatRoom: self.props.chatRoom,
+ className: "message avatar-wrapper small-rounded-avatar"
+ });
+ const otherDisplayName = M.getNameByHandle(otherContact.u);
+ let text;
+ if (otherContact.u === contact.u) {
+ text = self.props.chatRoom.isMeeting ? l.meeting_mgmt_left : l[8908];
+ } else {
+ text = (self.props.chatRoom.isMeeting ? l.meeting_mgmt_kicked : l[8906]).replace("%s", `${megaChat.html(displayName)}`);
+ }
+ messages.push(JSX_("div", {
+ className: "message body",
+ "data-id": `id${ message.messageId}`,
+ key: `${message.messageId }_${ h}`
+ }, avatar, JSX_("div", {
+ className: "message content-area small-info-txt selectable-txt"
+ }, JSX_(contacts.bq, {
+ className: "message",
+ chatRoom: self.props.chatRoom,
+ contact: otherContact,
+ label: JSX_(utils.zT, null, otherDisplayName)
+ }), datetime, JSX_("div", {
+ className: "message text-block"
+ }, JSX_(utils.P9, null, text)))));
+ });
+ return JSX_("div", null, messages);
+ }
+}
+
+;// ./js/chat/ui/messages/truncated.jsx
+
+
+
+
+class TruncatedMessage extends mixin.M {
+ render() {
+ const self = this;
+ let cssClasses = "message body";
+ const {message} = this.props;
+ const {chatRoom} = this.props.message;
+ const contact = self.getContact();
+ const timestampInt = self.getTimestamp();
+ const timestamp = self.getTimestampAsString();
+ let datetime = JSX_("div", {
+ className: "message date-time simpletip",
+ "data-simpletip": time2date(timestampInt, 17)
+ }, timestamp);
+ let displayName;
+ if (contact) {
+ displayName = M.getNameByHandle(contact.u);
+ } else {
+ displayName = contact;
+ }
+ let avatar = null;
+ if (this.props.grouped) {
+ cssClasses += " grouped";
+ } else {
+ avatar = JSX_(contacts.eu, {
+ contact,
+ className: "message avatar-wrapper small-rounded-avatar",
+ chatRoom
+ });
+ datetime = JSX_("div", {
+ className: "message date-time simpletip",
+ "data-simpletip": time2date(timestampInt, 17)
+ }, timestamp);
+ }
+ return JSX_("div", {
+ className: cssClasses,
+ "data-id": `id${ message.messageId}`,
+ key: message.messageId
+ }, avatar, JSX_("div", {
+ className: "message content-area small-info-txt selectable-txt"
+ }, JSX_(contacts.bq, {
+ contact,
+ className: "message",
+ label: JSX_(utils.zT, null, displayName),
+ chatRoom
+ }), datetime, JSX_("div", {
+ className: "message text-block"
+ }, l[8905])));
+ }
+}
+
+;// ./js/chat/ui/messages/privilegeChange.jsx
+
+
+
+
+class PrivilegeChange extends mixin.M {
+ haveMoreContactListeners() {
+ if (!this.props.message.meta || !this.props.message.meta.targetUserId) {
+ return false;
+ }
+ const uid = this.props.message.meta.targetUserId;
+ if (uid && M.u[uid]) {
+ return uid;
+ }
+ return false;
+ }
+ render() {
+ const self = this;
+ const {message} = this.props;
+ const {chatRoom} = this.props.message;
+ const contact = self.getContact();
+ const timestampInt = self.getTimestamp();
+ const timestamp = self.getTimestampAsString();
+ const datetime = JSX_("div", {
+ className: "message date-time simpletip",
+ "data-simpletip": time2date(timestampInt, 17)
+ }, timestamp);
+ let displayName;
+ if (contact) {
+ displayName = M.getNameByHandle(contact.u);
+ } else {
+ displayName = contact;
+ }
+ const messages = [];
+ const otherContact = M.u[message.meta.targetUserId] ? M.u[message.meta.targetUserId] : {
+ 'u': message.meta.targetUserId,
+ 'h': message.meta.targetUserId,
+ 'c': 0
+ };
+ const avatar = JSX_(contacts.eu, {
+ contact: otherContact,
+ className: "message avatar-wrapper small-rounded-avatar",
+ chatRoom
+ });
+ const otherDisplayName = M.getNameByHandle(otherContact.u);
+ let newPrivilegeText = "";
+ if (message.meta.privilege === 3) {
+ newPrivilegeText = l.priv_change_to_op;
+ } else if (message.meta.privilege === 2) {
+ newPrivilegeText = l.priv_change_to_std;
+ } else if (message.meta.privilege === 0) {
+ newPrivilegeText = l.priv_change_to_ro;
+ }
+ const text = newPrivilegeText.replace('[S]', '').replace('[/S]', '').replace('%s', `${megaChat.html(displayName)}`);
+ messages.push(JSX_("div", {
+ className: "message body",
+ "data-id": `id${ message.messageId}`,
+ key: message.messageId
+ }, avatar, JSX_("div", {
+ className: "message content-area small-info-txt selectable-txt"
+ }, JSX_(contacts.bq, {
+ className: "message",
+ chatRoom: self.props.chatRoom,
+ contact: otherContact,
+ label: JSX_(utils.zT, null, otherDisplayName)
+ }), datetime, JSX_("div", {
+ className: "message text-block"
+ }, JSX_(utils.P9, null, text)))));
+ return JSX_("div", null, messages);
+ }
+}
+
+;// ./js/chat/ui/messages/topicChange.jsx
+
+
+
+
+class TopicChange extends mixin.M {
+ render() {
+ const self = this;
+ const {message} = this.props;
+ const {megaChat} = this.props.message.chatRoom;
+ const {chatRoom} = this.props.message;
+ if (message.meta.isScheduled) {
+ return null;
+ }
+ const contact = self.getContact();
+ const timestampInt = self.getTimestamp();
+ const timestamp = self.getTimestampAsString();
+ const datetime = JSX_("div", {
+ className: "message date-time simpletip",
+ "data-simpletip": time2date(timestampInt, 17)
+ }, timestamp);
+ let displayName;
+ if (contact) {
+ displayName = M.getNameByHandle(contact.u);
+ } else {
+ displayName = contact;
+ }
+ const messages = [];
+ const avatar = JSX_(contacts.eu, {
+ contact,
+ chatRoom,
+ className: "message avatar-wrapper small-rounded-avatar"
+ });
+ const topic = megaChat.html(message.meta.topic);
+ const oldTopic = megaChat.html(message.meta.oldTopic) || '';
+ messages.push(JSX_("div", {
+ className: "message body",
+ "data-id": `id${ message.messageId}`,
+ key: message.messageId
+ }, avatar, JSX_("div", {
+ className: "message content-area small-info-txt selectable-txt"
+ }, JSX_(contacts.bq, {
+ className: "message",
+ chatRoom,
+ contact,
+ label: JSX_(utils.zT, null, displayName)
+ }), datetime, JSX_("div", {
+ className: "message text-block"
+ }, JSX_(utils.P9, null, (chatRoom.scheduledMeeting ? l.schedule_mgmt_title.replace('%1', `${oldTopic}`) : l[9081]).replace('%s', `${topic}`))))));
+ return JSX_("div", null, messages);
+ }
+}
+
+;// ./js/chat/ui/messages/closeOpenMode.jsx
+
+
+
+
+class CloseOpenModeMessage extends mixin.M {
+ render() {
+ const self = this;
+ let cssClasses = "message body";
+ const {message} = this.props;
+ const contact = self.getContact();
+ const timestampInt = self.getTimestamp();
+ const timestamp = self.getTimestampAsString();
+ let datetime = JSX_("div", {
+ className: "message date-time",
+ title: time2date(timestampInt)
+ }, timestamp);
+ let displayName;
+ if (contact) {
+ displayName = M.getNameByHandle(contact.u);
+ } else {
+ displayName = contact;
+ }
+ let avatar = null;
+ if (this.props.grouped) {
+ cssClasses += " grouped";
+ } else {
+ avatar = JSX_(contacts.eu, {
+ contact,
+ className: "message avatar-wrapper small-rounded-avatar",
+ chatRoom: this.props.chatRoom
+ });
+ datetime = JSX_("div", {
+ className: "message date-time",
+ title: time2date(timestampInt)
+ }, timestamp);
+ }
+ return JSX_("div", {
+ className: cssClasses,
+ "data-id": `id${ message.messageId}`,
+ key: message.messageId
+ }, avatar, JSX_("div", {
+ className: "message content-area small-info-txt selectable-txt"
+ }, JSX_("div", {
+ className: "message user-card-name"
+ }, JSX_(utils.zT, null, displayName)), datetime, JSX_("div", {
+ className: "message text-block"
+ }, l[20569])));
+ }
+}
+
+;// ./js/chat/ui/messages/chatHandle.jsx
+
+
+
+
+class ChatHandleMessage extends mixin.M {
+ render() {
+ const self = this;
+ let cssClasses = "message body";
+ const {message} = this.props;
+ const contact = self.getContact();
+ const timestampInt = self.getTimestamp();
+ const timestamp = self.getTimestampAsString();
+ let datetime = JSX_("div", {
+ className: "message date-time",
+ title: time2date(timestampInt)
+ }, timestamp);
+ let displayName;
+ if (contact) {
+ displayName = M.getNameByHandle(contact.u);
+ } else {
+ displayName = contact;
+ }
+ let avatar = null;
+ if (this.props.grouped) {
+ cssClasses += " grouped";
+ } else {
+ avatar = JSX_(contacts.eu, {
+ contact,
+ className: "message avatar-wrapper small-rounded-avatar",
+ chatRoom: this.props.chatRoom
+ });
+ datetime = JSX_("div", {
+ className: "message date-time",
+ title: time2date(timestampInt)
+ }, timestamp);
+ }
+ return JSX_("div", {
+ className: cssClasses,
+ "data-id": `id${ message.messageId}`,
+ key: message.messageId
+ }, avatar, JSX_("div", {
+ className: "message content-area small-info-txt selectable-txt"
+ }, JSX_("div", {
+ className: "message user-card-name"
+ }, JSX_(utils.zT, null, displayName)), datetime, JSX_("div", {
+ className: "message text-block"
+ }, message.meta.handleUpdate === 1 ? l[20570] : l[20571])));
+ }
+}
+
+// EXTERNAL MODULE: ./js/chat/ui/messages/generic.jsx + 14 modules
+const generic = REQ_(8025);
+// EXTERNAL MODULE: ./js/ui/perfectScrollbar.jsx
+const perfectScrollbar = REQ_(1301);
+;// ./js/chat/ui/messages/retentionChange.jsx
+
+
+
+
+class RetentionChange extends mixin.M {
+ render() {
+ const {
+ message
+ } = this.props;
+ const contact = this.getContact();
+ return JSX_("div", {
+ className: "message body",
+ "data-id": `id${ message.messageId}`,
+ key: message.messageId
+ }, JSX_(contacts.eu, {
+ contact,
+ className: "message avatar-wrapper small-rounded-avatar"
+ }), JSX_("div", {
+ className: "message content-area small-info-txt selectable-txt"
+ }, JSX_(contacts.bq, {
+ contact,
+ className: "message",
+ label: JSX_(utils.zT, null, M.getNameByHandle(contact.u))
+ }), JSX_("div", {
+ className: "message date-time simpletip",
+ "data-simpletip": time2date(this.getTimestamp(), 17)
+ }, this.getTimestampAsString()), JSX_("div", {
+ className: "message text-block"
+ }, message.getMessageRetentionSummary())));
+ }
+}
+// EXTERNAL MODULE: ./js/chat/ui/meetings/utils.jsx
+const meetings_utils = REQ_(3901);
+// EXTERNAL MODULE: ./js/chat/ui/messages/scheduleMetaChange.jsx
+const scheduleMetaChange = REQ_(5470);
+;// ./js/chat/ui/historyPanel.jsx
+
+let _dec, _class;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+const HistoryPanel = (_dec = (0,mixins.hG)(450, true), _class = class HistoryPanel extends mixins.w9 {
+ constructor(props) {
+ super(props);
+ this.$container = null;
+ this.$messages = null;
+ this.domRef = REaCt().createRef();
+ this.state = {
+ editing: false,
+ toast: false
+ };
+ this.renderNotice = label => JSX_("div", {
+ className: "dropdown body dropdown-arrow down-arrow tooltip not-sent-notification-cancel hidden"
+ }, JSX_("i", {
+ className: "dropdown-white-arrow"
+ }), JSX_("div", {
+ className: "dropdown notification-text"
+ }, JSX_("i", {
+ className: "small-icon conversations"
+ }), label));
+ this.renderLoadingSpinner = () => JSX_("div", {
+ style: {
+ top: '50%'
+ },
+ className: `
+ loading-spinner
+ js-messages-loading
+ light
+ manual-management
+ ${this.loadingShown ? '' : 'hidden'}
+ `
+ }, JSX_("div", {
+ className: "main-loader",
+ style: {
+ position: 'fixed',
+ top: '50%',
+ left: '50%'
+ }
+ }));
+ this.renderNavigationToast = () => {
+ const {
+ chatRoom
+ } = this.props;
+ const unreadCount = chatRoom.messagesBuff.getUnreadCount();
+ return JSX_("div", {
+ className: `
+ theme-dark-forced
+ messages-toast
+ ${this.state.toast ? 'active' : ''}
+ `,
+ onClick: () => {
+ this.setState({
+ toast: false
+ }, () => {
+ this.messagesListScrollable.scrollToBottom();
+ chatRoom.scrolledToBottom = true;
+ });
+ }
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-down"
+ }), unreadCount > 0 && JSX_("span", null, unreadCount > 9 ? '9+' : unreadCount));
+ };
+ this.onKeyboardScroll = ({
+ keyCode
+ }) => {
+ let _scrollbar$domRef;
+ const scrollbar = this.messagesListScrollable;
+ const domNode = scrollbar == null || (_scrollbar$domRef = scrollbar.domRef) == null ? void 0 : _scrollbar$domRef.current;
+ if (domNode && this.isComponentEventuallyVisible() && !this.state.attachCloudDialog) {
+ const scrollPositionY = scrollbar.getScrollPositionY();
+ const offset = parseInt(domNode.style.height);
+ const PAGE = {
+ UP: 33,
+ DOWN: 34
+ };
+ switch (keyCode) {
+ case PAGE.UP:
+ scrollbar.scrollToY(scrollPositionY - offset, true);
+ this.onMessagesScrollUserScroll(scrollbar, 100);
+ break;
+ case PAGE.DOWN:
+ if (!scrollbar.isAtBottom()) {
+ scrollbar.scrollToY(scrollPositionY + offset, true);
+ }
+ break;
+ }
+ }
+ };
+ this.onMessagesScrollUserScroll = (ps, offset = 5) => {
+ const {
+ chatRoom
+ } = this.props;
+ const {
+ messagesBuff
+ } = chatRoom;
+ const scrollPositionY = ps.getScrollPositionY();
+ if (messagesBuff.messages.length === 0) {
+ chatRoom.scrolledToBottom = true;
+ return;
+ }
+ if (ps.isCloseToBottom(30) === true) {
+ if (!chatRoom.scrolledToBottom) {
+ messagesBuff.detachMessages();
+ }
+ chatRoom.scrolledToBottom = true;
+ } else {
+ chatRoom.scrolledToBottom = false;
+ }
+ if (!this.scrollPullHistoryRetrieval && !messagesBuff.isRetrievingHistory && (ps.isAtTop() || scrollPositionY < offset && ps.getScrollHeight() > 500) && messagesBuff.haveMoreHistory()) {
+ ps.disable();
+ this.scrollPullHistoryRetrieval = true;
+ this.lastScrollPosition = scrollPositionY;
+ let msgAppended = 0;
+ const scrYOffset = ps.getScrollHeight();
+ chatRoom.one('onMessagesBuffAppend.pull', () => {
+ msgAppended++;
+ });
+ chatRoom.off('onHistoryDecrypted.pull');
+ chatRoom.one('onHistoryDecrypted.pull', () => {
+ chatRoom.off('onMessagesBuffAppend.pull');
+ if (msgAppended > 0) {
+ this._reposOnUpdate = scrYOffset;
+ }
+ this.scrollPullHistoryRetrieval = -1;
+ });
+ messagesBuff.retrieveChatHistory();
+ }
+ if (this.lastScrollPosition !== scrollPositionY) {
+ this.lastScrollPosition = scrollPositionY;
+ }
+ delay('chat-toast', this.initToast, 200);
+ };
+ this.initToast = () => {
+ let _this$messagesListScr;
+ const {
+ chatRoom
+ } = this.props;
+ return this.isMounted() && this.setState({
+ toast: !chatRoom.scrolledToBottom && !((_this$messagesListScr = this.messagesListScrollable) != null && _this$messagesListScr.isCloseToBottom != null && _this$messagesListScr.isCloseToBottom(30))
+ }, () => this.state.toast ? null : chatRoom.trigger('onChatIsFocused'));
+ };
+ this.handleWindowResize = this._handleWindowResize.bind(this);
+ }
+ customIsEventuallyVisible() {
+ return this.props.chatRoom.isCurrentlyActive;
+ }
+ UNSAFE_componentWillMount() {
+ let _chatRoom$messagesBuf;
+ const {
+ chatRoom
+ } = this.props;
+ chatRoom.rebind('onHistoryDecrypted.cp', () => this.eventuallyUpdate());
+ this._messagesBuffChangeHandler = (_chatRoom$messagesBuf = chatRoom.messagesBuff) == null ? void 0 : _chatRoom$messagesBuf.addChangeListener(SoonFc(() => {
+ if (this.isComponentEventuallyVisible()) {
+ let _this$domRef;
+ $('.js-messages-scroll-area', (_this$domRef = this.domRef) == null ? void 0 : _this$domRef.current).trigger('forceResize', [true]);
+ }
+ this.refreshUI();
+ }));
+ }
+ componentDidMount() {
+ super.componentDidMount();
+ const {
+ chatRoom,
+ onMount
+ } = this.props;
+ window.addEventListener('resize', this.handleWindowResize);
+ window.addEventListener('keydown', this.handleKeyDown);
+ this.$container = $(`.conversation-panel[data-room-id="${chatRoom.chatId}"]`);
+ this.eventuallyInit();
+ chatRoom.trigger('onHistoryPanelComponentDidMount');
+ if (onMount) {
+ onMount(this);
+ }
+ }
+ componentWillUnmount() {
+ super.componentWillUnmount();
+ const {
+ chatRoom
+ } = this.props;
+ if (this._messagesBuffChangeHandler) {
+ let _chatRoom$messagesBuf2;
+ (_chatRoom$messagesBuf2 = chatRoom.messagesBuff) == null || _chatRoom$messagesBuf2.removeChangeListener(this._messagesBuffChangeHandler);
+ delete this._messagesBuffChangeHandler;
+ }
+ window.removeEventListener('resize', this.handleWindowResize);
+ window.removeEventListener('keydown', this.handleKeyDown);
+ $(document).off(`fullscreenchange.megaChat_${chatRoom.roomId}`);
+ $(document).off(`keydown.keyboardScroll_${chatRoom.roomId}`);
+ }
+ componentDidUpdate(prevProps, prevState) {
+ let _self$domRef;
+ const self = this;
+ self.eventuallyInit(false);
+ const domNode = (_self$domRef = self.domRef) == null ? void 0 : _self$domRef.current;
+ const jml = domNode && domNode.querySelector('.js-messages-loading');
+ if (jml) {
+ if (self.loadingShown) {
+ jml.classList.remove('hidden');
+ } else {
+ jml.classList.add('hidden');
+ }
+ }
+ self.handleWindowResize();
+ if (prevState.editing === false && self.state.editing !== false && self.messagesListScrollable) {
+ self.messagesListScrollable.reinitialise(false);
+ Soon(() => {
+ if (self.editDomElement && self.editDomElement.length === 1) {
+ self.messagesListScrollable.scrollToElement(self.editDomElement[0], false);
+ }
+ });
+ }
+ if (self._reposOnUpdate !== undefined) {
+ const ps = self.messagesListScrollable;
+ ps.__prevPosY = ps.getScrollHeight() - self._reposOnUpdate + self.lastScrollPosition;
+ ps.scrollToY(ps.__prevPosY, true);
+ }
+ }
+ eventuallyInit(doResize) {
+ let _this$domRef2;
+ if (this.initialised) {
+ return;
+ }
+ const domNode = (_this$domRef2 = this.domRef) == null ? void 0 : _this$domRef2.current;
+ if (domNode) {
+ this.initialised = true;
+ } else {
+ return;
+ }
+ this.$messages = $('.messages.scroll-area > .perfectScrollbarContainer', this.$container);
+ this.$messages.droppable({
+ tolerance: 'pointer',
+ drop(e, ui) {
+ $.doDD(e, ui, 'drop', 1);
+ },
+ over(e, ui) {
+ $.doDD(e, ui, 'over', 1);
+ },
+ out(e, ui) {
+ $.doDD(e, ui, 'out', 1);
+ }
+ });
+ this.lastScrollPosition = null;
+ this.props.chatRoom.scrolledToBottom = true;
+ if (doResize !== false) {
+ this.handleWindowResize();
+ }
+ }
+ _handleWindowResize(e, scrollToBottom) {
+ if (!M.chat) {
+ return;
+ }
+ if (!this.isMounted()) {
+ this.componentWillUnmount();
+ return;
+ }
+ if (!this.isComponentEventuallyVisible()) {
+ return;
+ }
+ const self = this;
+ self.eventuallyInit(false);
+ if (!self.$messages) {
+ return;
+ }
+ if ((0,meetings_utils.Av)()) {
+ const $container = $('.meetings-call');
+ const $messages = $('.js-messages-scroll-area', $container);
+ const $textarea = $('.chat-textarea-block', $container);
+ const $sidebar = $('.sidebar', $container);
+ const scrollBlockHeight = parseInt($sidebar.outerHeight(), 10) - parseInt($textarea.outerHeight(), 10) - 72;
+ if ($sidebar.hasClass('chat-opened') && scrollBlockHeight !== $messages.outerHeight()) {
+ $messages.css('height', scrollBlockHeight);
+ self.refreshUI(true);
+ }
+ return;
+ }
+ const scrollBlockHeight = $('.chat-content-block', self.$container).outerHeight() - ($('.chat-topic-block', self.$container).outerHeight() || 0) - (is_chatlink ? $('.join-chat-block', self.$container).outerHeight() : $('.messages-block .chat-textarea-block', self.$container).outerHeight());
+ if (scrollBlockHeight !== self.$messages.outerHeight()) {
+ self.$messages.css('height', scrollBlockHeight);
+ $('.messages.main-pad', self.$messages).css('min-height', scrollBlockHeight);
+ self.refreshUI(true);
+ } else {
+ self.refreshUI(scrollToBottom);
+ }
+ }
+ refreshUI() {
+ if (this.isComponentEventuallyVisible()) {
+ const room = this.props.chatRoom;
+ room.renderContactTree();
+ room.megaChat.refreshConversations();
+ room.trigger('RefreshUI');
+ if (room.scrolledToBottom) {
+ delay(`hp:reinit-scroll:${this.getUniqueId()}`, () => {
+ if (this.messagesListScrollable) {
+ this.messagesListScrollable.reinitialise(true, true);
+ }
+ }, 30);
+ }
+ }
+ }
+ isLoading() {
+ const {chatRoom} = this.props;
+ if (chatRoom.historyTimedOut) {
+ return false;
+ }
+ const mb = chatRoom.messagesBuff;
+ return this.scrollPullHistoryRetrieval === true || chatRoom.activeSearches || mb.messagesHistoryIsLoading() || mb.joined === false || mb.isDecrypting;
+ }
+ specShouldComponentUpdate() {
+ return !this.loadingShown && this.isComponentEventuallyVisible();
+ }
+ enableScrollbar() {
+ const ps = this.messagesListScrollable;
+ ps.enable();
+ this._reposOnUpdate = undefined;
+ this.lastScrollPosition = ps.__prevPosY | 0;
+ }
+ editMessage(messageId) {
+ const self = this;
+ self.setState({
+ 'editing': messageId
+ });
+ self.props.chatRoom.scrolledToBottom = false;
+ }
+ onMessageEditDone(v, messageContents) {
+ const self = this;
+ const room = this.props.chatRoom;
+ room.scrolledToBottom = true;
+ self.editDomElement = null;
+ const currentContents = v.textContents;
+ v.edited = false;
+ if (messageContents === false || messageContents === currentContents) {
+ let _self$messagesListScr;
+ (_self$messagesListScr = self.messagesListScrollable) == null || _self$messagesListScr.scrollToBottom(true);
+ } else if (messageContents) {
+ let _self$messagesListScr2;
+ room.trigger('onMessageUpdating', v);
+ room.megaChat.plugins.chatdIntegration.updateMessage(room, v.internalId ? v.internalId : v.orderValue, messageContents);
+ if (v.getState && (v.getState() === Message.STATE.NOT_SENT || v.getState() === Message.STATE.SENT) && !v.requiresManualRetry) {
+ if (v.textContents) {
+ v.textContents = messageContents;
+ }
+ if (v.emoticonShortcutsProcessed) {
+ v.emoticonShortcutsProcessed = false;
+ }
+ if (v.emoticonsProcessed) {
+ v.emoticonsProcessed = false;
+ }
+ if (v.messageHtml) {
+ delete v.messageHtml;
+ }
+ v.trigger('onChange', [v, "textContents", "", messageContents]);
+ megaChat.plugins.richpreviewsFilter.processMessage({}, v, false, true);
+ }
+ (_self$messagesListScr2 = self.messagesListScrollable) == null || _self$messagesListScr2.scrollToBottom(true);
+ } else if (messageContents.length === 0) {
+ this.props.onDeleteClicked(v);
+ }
+ self.setState({
+ 'editing': false
+ });
+ self.refreshUI();
+ Soon(() => {
+ $('.chat-textarea-block:visible textarea').focus();
+ }, 300);
+ }
+ render() {
+ const self = this;
+ const room = this.props.chatRoom;
+ if (!room || !room.roomId) {
+ return null;
+ }
+ const contacts = room.getParticipantsExceptMe();
+ let contactHandle;
+ let contact;
+ let avatarMeta;
+ let contactName = "";
+ if (contacts && contacts.length === 1) {
+ contactHandle = contacts[0];
+ contact = M.u[contactHandle];
+ avatarMeta = contact ? generateAvatarMeta(contact.u) : {};
+ contactName = avatarMeta.fullName;
+ } else if (contacts && contacts.length > 1) {
+ contactName = room.getRoomTitle();
+ }
+ let messagesList = [];
+ if (this.isLoading()) {
+ self.loadingShown = true;
+ } else {
+ const mb = room.messagesBuff;
+ if (this.scrollPullHistoryRetrieval < 0) {
+ this.scrollPullHistoryRetrieval = false;
+ self.enableScrollbar();
+ }
+ delete self.loadingShown;
+ if (room.historyTimedOut || mb.joined === true && !self.scrollPullHistoryRetrieval && mb.haveMoreHistory() === false) {
+ const $$WELCOME_MESSAGE = ({
+ heading,
+ title,
+ info,
+ className
+ }) => JSX_("div", {
+ className: `
+ messages
+ welcome-message
+ ${className || ''}
+ `
+ }, JSX_(utils.P9, {
+ tag: "h1",
+ content: heading
+ }), title && JSX_("span", null, title), info);
+ messagesList = [...messagesList, room.isNote ? $$WELCOME_MESSAGE({
+ heading: l.note_heading,
+ info: JSX_("p", null, JSX_("i", {
+ className: "sprite-fm-mono icon-file-text-thin-outline note-chat-icon"
+ }), l.note_description),
+ className: 'note-chat-info'
+ }) : $$WELCOME_MESSAGE({
+ heading: room.scheduledMeeting || !contactName ? megaChat.html(room.getRoomTitle()) : l[8002].replace('%s', `${megaChat.html(contactName)}`),
+ title: l[8080],
+ info: JSX_(REaCt().Fragment, null, JSX_("p", null, JSX_("i", {
+ className: "sprite-fm-mono icon-lock"
+ }), JSX_(utils.P9, {
+ content: l[8540].replace("[S]", "").replace("[/S]", "")
+ })), JSX_("p", null, JSX_("i", {
+ className: "sprite-fm-mono icon-accept"
+ }), JSX_(utils.P9, {
+ content: l[8539].replace("[S]", "").replace("[/S]", "")
+ })))
+ })];
+ }
+ }
+ let lastTimeMarker;
+ let lastMessageFrom = null;
+ let lastGroupedMessageTimeStamp = null;
+ let grouped = false;
+ for (let i = 0; i < room.messagesBuff.messages.length; i++) {
+ let v = room.messagesBuff.messages.getItem(i);
+ if (!v.protocol && v.revoked !== true) {
+ let shouldRender = true;
+ if (v.isManagement && v.isManagement() === true && v.isRenderableManagement() === false || v.deleted === true) {
+ shouldRender = false;
+ }
+ const timestamp = v.delay;
+ const curTimeMarker = getTimeMarker(timestamp);
+ if (shouldRender === true && curTimeMarker && lastTimeMarker !== curTimeMarker) {
+ lastTimeMarker = curTimeMarker;
+ messagesList.push(JSX_("div", {
+ className: "message date-divider selectable-txt",
+ key: `${v.messageId }_marker`,
+ title: time2date(timestamp)
+ }, curTimeMarker));
+ grouped = false;
+ lastMessageFrom = null;
+ lastGroupedMessageTimeStamp = null;
+ }
+ if (shouldRender === true) {
+ let {userId} = v;
+ if (!userId && contact && contact.u) {
+ userId = contact.u;
+ }
+ if (v instanceof Message && v.dialogType !== "truncated") {
+ if (!lastMessageFrom || userId && lastMessageFrom === userId) {
+ if (timestamp - lastGroupedMessageTimeStamp < 300) {
+ grouped = true;
+ } else {
+ grouped = false;
+ lastMessageFrom = userId;
+ lastGroupedMessageTimeStamp = timestamp;
+ }
+ } else {
+ grouped = false;
+ lastMessageFrom = userId;
+ if (lastMessageFrom === userId) {
+ lastGroupedMessageTimeStamp = timestamp;
+ } else {
+ lastGroupedMessageTimeStamp = null;
+ }
+ }
+ } else {
+ grouped = false;
+ lastMessageFrom = null;
+ lastGroupedMessageTimeStamp = null;
+ }
+ }
+ if ((v.dialogType === "remoteCallEnded" || v.dialogType === "remoteCallStarted") && v && v.wrappedChatDialogMessage) {
+ v = v.wrappedChatDialogMessage;
+ }
+ if (v.dialogType) {
+ let messageInstance = null;
+ if (v.dialogType === 'alterParticipants') {
+ messageInstance = JSX_(AltPartsConvMessage, {
+ message: v,
+ key: v.messageId,
+ contact: Message.getContactForMessage(v),
+ grouped,
+ chatRoom: room
+ });
+ } else if (v.dialogType === 'truncated') {
+ messageInstance = JSX_(TruncatedMessage, {
+ message: v,
+ key: v.messageId,
+ contact: Message.getContactForMessage(v),
+ grouped,
+ chatRoom: room
+ });
+ } else if (v.dialogType === 'privilegeChange') {
+ messageInstance = JSX_(PrivilegeChange, {
+ message: v,
+ key: v.messageId,
+ contact: Message.getContactForMessage(v),
+ grouped,
+ chatRoom: room
+ });
+ } else if (v.dialogType === 'topicChange') {
+ messageInstance = JSX_(TopicChange, {
+ message: v,
+ key: v.messageId,
+ contact: Message.getContactForMessage(v),
+ grouped,
+ chatRoom: room
+ });
+ } else if (v.dialogType === 'openModeClosed') {
+ messageInstance = JSX_(CloseOpenModeMessage, {
+ message: v,
+ key: v.messageId,
+ contact: Message.getContactForMessage(v),
+ grouped,
+ chatRoom: room
+ });
+ } else if (v.dialogType === 'chatHandleUpdate') {
+ messageInstance = JSX_(ChatHandleMessage, {
+ message: v,
+ key: v.messageId,
+ contact: Message.getContactForMessage(v),
+ grouped,
+ chatRoom: room
+ });
+ } else if (v.dialogType === 'messageRetention') {
+ messageInstance = JSX_(RetentionChange, {
+ message: v,
+ key: v.messageId,
+ contact: Message.getContactForMessage(v)
+ });
+ } else if (v.dialogType === 'scheduleMeta') {
+ if (v.meta.onlyTitle) {
+ messageInstance = JSX_(TopicChange, {
+ message: v,
+ key: v.messageId,
+ contact: Message.getContactForMessage(v),
+ grouped,
+ chatRoom: v.chatRoom
+ });
+ } else {
+ if (v.meta.topicChange) {
+ messagesList.push(JSX_(TopicChange, {
+ message: v,
+ key: `${v.messageId}-topic`,
+ contact: Message.getContactForMessage(v),
+ grouped,
+ chatRoom: v.chatRoom
+ }));
+ }
+ messageInstance = JSX_(scheduleMetaChange.A, {
+ message: v,
+ key: v.messageId,
+ mode: v.meta.mode,
+ chatRoom: room,
+ grouped,
+ link: v.chatRoom.publicLink,
+ contact: Message.getContactForMessage(v)
+ });
+ }
+ }
+ messagesList.push(messageInstance);
+ } else {
+ if (!v.chatRoom) {
+ v.chatRoom = room;
+ }
+ messagesList.push(JSX_(generic.A, {
+ message: v,
+ state: v.state,
+ key: v.messageId,
+ contact: Message.getContactForMessage(v),
+ grouped,
+ onUpdate: () => {
+ self.onResizeDoUpdate();
+ },
+ editing: self.state.editing === v.messageId || self.state.editing === v.pendingMessageId,
+ onEditStarted: ((v, $domElement) => {
+ self.editDomElement = $domElement;
+ self.setState({
+ 'editing': v.messageId
+ });
+ self.forceUpdate();
+ }).bind(this, v),
+ chatRoom: room,
+ onEditDone: this.onMessageEditDone.bind(this, v),
+ onDeleteClicked: msg => {
+ if (this.props.onDeleteClicked) {
+ this.props.onDeleteClicked(msg);
+ }
+ },
+ onResized: () => {
+ this.handleWindowResize();
+ },
+ onEmojiBarChange: () => {
+ this.handleWindowResize();
+ }
+ }));
+ }
+ }
+ }
+ return JSX_("div", {
+ ref: this.domRef,
+ className: `
+ messages
+ scroll-area
+ ${this.props.className || ''}
+ `
+ }, JSX_(perfectScrollbar.O, {
+ className: "js-messages-scroll-area perfectScrollbarContainer",
+ ref: ref => {
+ let _this$props$onMessage, _this$props;
+ this.messagesListScrollable = ref;
+ $(document).rebind(`keydown.keyboardScroll_${room.roomId}`, this.onKeyboardScroll);
+ (_this$props$onMessage = (_this$props = this.props).onMessagesListScrollableMount) == null || _this$props$onMessage.call(_this$props, ref);
+ },
+ chatRoom: room,
+ messagesBuff: room.messagesBuff,
+ editDomElement: this.state.editDomElement,
+ editingMessageId: this.state.editing,
+ confirmDeleteDialog: this.state.confirmDeleteDialog,
+ renderedMessagesCount: messagesList.length,
+ options: {
+ suppressScrollX: true
+ },
+ isLoading: room.messagesBuff.messagesHistoryIsLoading() || room.activeSearches > 0 || this.loadingShown,
+ onFirstInit: ps => {
+ ps.scrollToBottom(true);
+ room.scrolledToBottom = 1;
+ },
+ onUserScroll: this.onMessagesScrollUserScroll
+ }, JSX_("div", {
+ className: "messages main-pad"
+ }, JSX_("div", {
+ className: "messages content-area"
+ }, this.renderLoadingSpinner(), messagesList))), this.renderNavigationToast());
+ }
+}, (0,applyDecoratedDescriptor.A)(_class.prototype, "enableScrollbar", [_dec], Object.getOwnPropertyDescriptor(_class.prototype, "enableScrollbar"), _class.prototype), _class);
+
+
+ },
+
+ 8956
+(_, EXP_, REQ_) {
+
+ REQ_.d(EXP_, {
+ Q: () => InviteParticipantsPanel
+ });
+ const react0__ = REQ_(1594);
+ const react0___default = REQ_.n(react0__);
+ const _meetings_utils_jsx1__ = REQ_(3901);
+ const _ui_miniui_jsx2__ = REQ_(5009);
+ const _ui_buttons_jsx3__ = REQ_(5155);
+ const _ui_dropdowns_jsx4__ = REQ_(1510);
+
+
+
+
+
+const NAMESPACE = 'invite-panel';
+class InviteParticipantsPanel extends react0___default().Component {
+ constructor(props) {
+ super(props);
+ this.domRef = react0___default().createRef();
+ this.state = {
+ link: '',
+ copied: false
+ };
+ this.retrieveChatLink();
+ }
+ retrieveChatLink(cim) {
+ const {
+ chatRoom
+ } = this.props;
+ if (!chatRoom.topic) {
+ return;
+ }
+ this.loading = chatRoom.updatePublicHandle(false, cim).always(() => {
+ delete this.loading;
+ if (this.domRef.current) {
+ if (chatRoom.publicLink) {
+ this.setState({
+ link: `${getBaseUrl()}/${chatRoom.publicLink}`
+ });
+ } else {
+ this.setState({
+ link: false
+ });
+ }
+ }
+ });
+ }
+ getInviteBody(encode) {
+ const {
+ chatRoom
+ } = this.props;
+ const {
+ link
+ } = this.state;
+ const {
+ scheduledMeeting
+ } = chatRoom;
+ let body = l.invite_body_text;
+ if (scheduledMeeting) {
+ const {
+ nextOccurrenceStart
+ } = chatRoom.scheduledMeeting;
+ body = l.invite_body_text_scheduled.replace('%4', time2date(nextOccurrenceStart / 1000, 20)).replace('%5', toLocaleTime(nextOccurrenceStart));
+ }
+ body = body.replace(/\[BR]/g, '\n').replace('%1', u_attr.name).replace('%2', chatRoom.getRoomTitle()).replace('%3', link);
+ if (encode) {
+ return typeof body.toWellFormatted === 'function' ? body.toWellFormatted() : body.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g, '').replace(/[\uD800-\uDBFF]/g, '\uFFFD').replace(/[\uDC00-\uDFFF]/g, '\uFFFD');
+ }
+ return body;
+ }
+ render() {
+ const {
+ chatRoom,
+ disableLinkToggle,
+ onAddParticipants
+ } = this.props;
+ const {
+ link,
+ copied
+ } = this.state;
+ const inCall = (0,_meetings_utils_jsx1__ .Av)();
+ if (this.loading) {
+ return JSX_("div", {
+ ref: this.domRef,
+ className: `
+ ${NAMESPACE}
+ ${inCall ? 'theme-dark-forced' : ''}
+ `
+ }, JSX_("header", null), JSX_("section", {
+ className: "content"
+ }, JSX_("div", {
+ className: "content-block"
+ })));
+ }
+ const canInvite = !!(chatRoom.iAmOperator() || chatRoom.options[MCO_FLAGS.OPEN_INVITE]) && onAddParticipants;
+ const canToggleLink = !disableLinkToggle && chatRoom.iAmOperator() && (chatRoom.isMeeting || chatRoom.topic);
+ const mailto = `mailto:?to=&subject=${l.invite_subject_text}&body=${this.getInviteBody(true)}`;
+ const copyText = chatRoom.isMeeting ? l.copy_meeting_link : l[1394];
+ return JSX_("div", {
+ ref: this.domRef,
+ className: `
+ ${NAMESPACE}
+ ${inCall ? 'theme-dark-forced' : ''}
+ `
+ }, JSX_("header", null, JSX_("h3", null, l.invite_participants)), JSX_("section", {
+ className: "content"
+ }, canToggleLink && chatRoom.type !== 'group' && JSX_("div", {
+ className: "content-block link-block"
+ }, JSX_("div", {
+ className: "text-wrapper"
+ }, JSX_("span", {
+ className: "link-label"
+ }, l.invite_toggle_link_label), JSX_("div", {
+ className: `link-description ${inCall ? '' : 'hidden'}`
+ }, l.invite_toggle_link_desc)), JSX_(_ui_miniui_jsx2__ .A.ToggleCheckbox, {
+ className: "meeting-link-toggle",
+ checked: !!link,
+ value: !!link,
+ onToggle: () => {
+ if (this.loading) {
+ return;
+ }
+ if (link) {
+ this.loading = chatRoom.updatePublicHandle(true).always(() => {
+ delete this.loading;
+ if (this.domRef.current) {
+ this.setState({
+ link: false
+ });
+ }
+ });
+ } else {
+ this.retrieveChatLink(true);
+ }
+ }
+ })), link && JSX_("div", {
+ className: "content-block"
+ }, JSX_(_ui_buttons_jsx3__ .$, {
+ className: "flat-button",
+ icon: `sprite-fm-mono icon-${copied ? 'check' : 'link-thin-outline'}`,
+ label: copied ? l.copied : copyText,
+ onClick: () => {
+ if (copied) {
+ return;
+ }
+ delay('chat-event-inv-copylink', () => eventlog(99964));
+ copyToClipboard(link);
+ this.setState({
+ copied: true
+ }, () => {
+ tSleep(3).then(() => {
+ if (this.domRef.current) {
+ this.setState({
+ copied: false
+ });
+ }
+ });
+ });
+ }
+ })), link && JSX_("div", {
+ className: "content-block"
+ }, JSX_(_ui_buttons_jsx3__ .$, {
+ className: "flat-button",
+ label: l.share_chat_link,
+ icon: "sprite-fm-mono icon-share-02-thin-outline"
+ }, JSX_(_ui_dropdowns_jsx4__ .ms, {
+ className: `
+ button-group-menu
+ invite-dropdown
+ ${inCall ? 'theme-dark-forced' : ''}
+ `,
+ noArrow: true,
+ positionAt: "left bottom",
+ collision: "none",
+ horizOffset: 79,
+ vertOffset: 6,
+ ref: r => {
+ this.dropdownRef = r;
+ },
+ onBeforeActiveChange: e => {
+ if (e) {
+ delay('chat-event-inv-dropdown', () => eventlog(99965));
+ $(document.body).trigger('closeAllDropdownsExcept', this.dropdownRef);
+ }
+ }
+ }, JSX_(_ui_dropdowns_jsx4__ .tJ, {
+ key: "send-invite",
+ className: `
+ ${inCall ? 'theme-dark-forced' : ''}
+ `,
+ icon: "sprite-fm-mono icon-mail-thin-outline",
+ label: l.share_chat_link_invite,
+ onClick: () => {
+ delay('chat-event-inv-email', () => eventlog(99966));
+ window.open(mailto, '_self', 'noopener,noreferrer');
+ }
+ }), JSX_(_ui_dropdowns_jsx4__ .tJ, {
+ key: "copy-invite",
+ className: `
+ ${inCall ? 'theme-dark-forced' : ''}
+ `,
+ label: l.copy_chat_link_invite,
+ icon: "sprite-fm-mono icon-square-copy",
+ onClick: () => {
+ delay('chat-event-inv-copy', () => eventlog(99967));
+ copyToClipboard(this.getInviteBody(), l.invite_copied);
+ }
+ })))), canInvite && (link || canToggleLink) && chatRoom.type !== 'group' && JSX_("div", {
+ className: "content-block invite-panel-divider"
+ }, l.invite_dlg_divider), canInvite && JSX_("div", {
+ className: "content-block add-participant-block"
+ }, JSX_(_ui_buttons_jsx3__ .$, {
+ className: "flat-button",
+ icon: "sprite-fm-mono icon-user-square-thin-outline",
+ label: l.add_participants,
+ onClick: () => {
+ delay('chat-event-inv-add-participant', () => eventlog(99968));
+ onAddParticipants();
+ }
+ }))));
+ }
+}
+
+ },
+
+ 4907
+(_, EXP_, REQ_) {
+
+// ESM COMPAT FLAG
+REQ_.r(EXP_);
+
+// EXPORTS
+REQ_.d(EXP_, {
+ "default": () => leftPanel
+});
+
+// EXTERNAL MODULE: ./node_modules/@babel/runtime/helpers/esm/extends.js
+const esm_extends = REQ_(8168);
+// EXTERNAL MODULE: external "React"
+const external_React_ = REQ_(1594);
+const REaCt = REQ_.n(external_React_);
+// EXTERNAL MODULE: ./js/chat/mixins.js
+const mixins = REQ_(8264);
+;// ./js/chat/ui/searchPanel/utils.jsx
+const STATUS = {
+ IN_PROGRESS: 1,
+ PAUSED: 2,
+ COMPLETED: 3
+};
+const EVENTS = {
+ RESULT_OPEN: 'chatSearchResultOpen',
+ KEYDOWN: 'keydown'
+};
+const ACTIONS = {
+ PAUSE: 'pause',
+ RESUME: 'resume'
+};
+const TYPE = {
+ MESSAGE: 1,
+ CHAT: 2,
+ MEMBER: 3,
+ NIL: 4
+};
+const LABEL = {
+ MESSAGES: l[6868],
+ CONTACTS_AND_CHATS: l[20174],
+ NO_RESULTS: l[8674],
+ SEARCH_MESSAGES_CTA: l[23547],
+ SEARCH_MESSAGES_INLINE: l[23548],
+ DECRYPTING_RESULTS: l[23543],
+ PAUSE_SEARCH: l[23544],
+ SEARCH_PAUSED: l[23549],
+ SEARCH_COMPLETE: l[23546]
+};
+;// ./js/chat/ui/searchPanel/searchField.jsx
+let _SearchField;
+
+
+
+const SEARCH_STATUS_CLASS = 'search-field-status';
+const BASE_ICON_CLASS = 'sprite-fm-mono';
+class SearchField extends mixins.w9 {
+ constructor(...args) {
+ super(...args);
+ this.domRef = REaCt().createRef();
+ this.state = {
+ hovered: false
+ };
+ this.renderStatusBanner = () => {
+ switch (this.props.status) {
+ case STATUS.IN_PROGRESS:
+ return JSX_("div", {
+ className: `${SEARCH_STATUS_CLASS} searching info`
+ }, LABEL.DECRYPTING_RESULTS);
+ case STATUS.PAUSED:
+ return JSX_("div", {
+ className: `${SEARCH_STATUS_CLASS} paused info`
+ }, LABEL.SEARCH_PAUSED);
+ case STATUS.COMPLETED:
+ return JSX_("div", {
+ className: `${SEARCH_STATUS_CLASS} complete success`
+ }, LABEL.SEARCH_COMPLETE);
+ default:
+ return null;
+ }
+ };
+ this.renderStatusControls = () => {
+ const {
+ status,
+ onToggle
+ } = this.props;
+ const handleHover = () => this.setState(state => ({
+ hovered: !state.hovered
+ }));
+ switch (status) {
+ case STATUS.IN_PROGRESS:
+ return JSX_("div", {
+ className: "progress-controls",
+ onClick: onToggle
+ }, JSX_("i", {
+ className: `${BASE_ICON_CLASS} icon-pause`
+ }));
+ case STATUS.PAUSED:
+ return JSX_("i", {
+ className: `${BASE_ICON_CLASS} icon-resume`,
+ onClick: onToggle,
+ onMouseOver: handleHover,
+ onMouseOut: handleHover
+ });
+ case STATUS.COMPLETED:
+ return null;
+ default:
+ return null;
+ }
+ };
+ }
+ componentDidMount() {
+ super.componentDidMount();
+ SearchField.focus();
+ }
+ render() {
+ const {
+ value,
+ searching,
+ status,
+ onChange,
+ onReset
+ } = this.props;
+ return JSX_("div", {
+ ref: this.domRef,
+ className: "search-field"
+ }, JSX_("i", {
+ className: `${BASE_ICON_CLASS} icon-preview-reveal search-icon-find`
+ }), JSX_("input", {
+ type: "search",
+ autoComplete: "off",
+ placeholder: l[102],
+ ref: SearchField.inputRef,
+ value,
+ onChange: ev => {
+ if (this.state.hovered) {
+ this.setState({
+ hovered: false
+ });
+ }
+ onChange(ev);
+ }
+ }), searching && JSX_("i", {
+ className: `
+ ${BASE_ICON_CLASS}
+ icon-close-component
+ search-icon-reset
+ `,
+ onClick: onReset
+ }), searching && status && JSX_(REaCt().Fragment, null, this.renderStatusControls(), this.renderStatusBanner()));
+ }
+}
+_SearchField = SearchField;
+SearchField.inputRef = REaCt().createRef();
+SearchField.select = () => {
+ const inputElement = _SearchField.inputRef && _SearchField.inputRef.current;
+ const value = inputElement && inputElement.value;
+ if (inputElement && value) {
+ inputElement.selectionStart = 0;
+ inputElement.selectionEnd = value.length;
+ }
+};
+SearchField.focus = () => _SearchField.inputRef && _SearchField.inputRef.current && _SearchField.inputRef.current.focus();
+SearchField.hasValue = () => _SearchField.inputRef && _SearchField.inputRef.current && !!_SearchField.inputRef.current.value.length;
+SearchField.isVisible = () => _SearchField.inputRef && _SearchField.inputRef.current && elementIsVisible(_SearchField.inputRef.current);
+;// ./js/chat/ui/searchPanel/resultTable.jsx
+
+const ResultTable = ({
+ heading,
+ children
+}) => {
+ return JSX_("div", {
+ className: `result-table ${heading ? '' : 'nil'}`
+ }, heading ? JSX_("div", {
+ className: "result-table-heading"
+ }, heading) : null, children);
+};
+ const resultTable = ResultTable;
+// EXTERNAL MODULE: ./js/chat/ui/contacts.jsx
+const contacts = REQ_(8022);
+// EXTERNAL MODULE: ./js/ui/utils.jsx
+const utils = REQ_(6411);
+;// ./js/chat/ui/searchPanel/resultRow.jsx
+
+
+
+
+
+
+
+const RESULT_ROW_CLASS = 'result-table-row';
+const USER_CARD_CLASS = 'user-card';
+const roomIsGroup = room => room && room.type === 'group' || room.type === 'public';
+const openResult = ({
+ room,
+ messageId,
+ index
+}, callback) => {
+ document.dispatchEvent(new Event(EVENTS.RESULT_OPEN));
+ if (isString(room)) {
+ loadSubPage(`fm/chat/p/${room}`);
+ } else if (room && room.chatId && !messageId) {
+ const chatRoom = megaChat.getChatById(room.chatId);
+ if (chatRoom) {
+ loadSubPage(chatRoom.getRoomUrl());
+ } else {
+ loadSubPage(`/fm/chat/contacts/${room.chatId}`);
+ }
+ } else {
+ loadSubPage(room.getRoomUrl());
+ if (messageId) {
+ room.scrollToMessageId(messageId, index);
+ }
+ }
+ return callback && typeof callback === 'function' && callback();
+};
+const lastActivity = room => {
+ if (!room.lastActivity || !room.ctime) {
+ room = megaChat.getChatById(room.chatId);
+ }
+ if (room && room.lastActivity || room.ctime) {
+ return room.lastActivity ? todayOrYesterday(room.lastActivity * 1000) ? getTimeMarker(room.lastActivity) : time2date(room.lastActivity, 17) : todayOrYesterday(room.ctime * 1000) ? getTimeMarker(room.ctime) : time2date(room.ctime, 17);
+ }
+ return l[8000];
+};
+class MessageRow extends mixins.w9 {
+ render() {
+ const {
+ data,
+ matches,
+ room,
+ index,
+ onResultOpen
+ } = this.props;
+ const isGroup = roomIsGroup(room);
+ const contact = room.getParticipantsExceptMe();
+ const summary = room.messagesBuff.getRenderableSummary(data);
+ const date = todayOrYesterday(data.delay * 1000) ? getTimeMarker(data.delay) : time2date(data.delay, 17);
+ return JSX_("div", {
+ ref: node => {
+ this.domRef = node;
+ },
+ className: `
+ ${RESULT_ROW_CLASS}
+ message
+ `,
+ onClick: () => openResult({
+ room,
+ messageId: data.messageId,
+ index
+ }, () => onResultOpen(this.domRef))
+ }, JSX_("div", {
+ className: "message-result-avatar"
+ }, isGroup && JSX_("div", {
+ className: "chat-topic-icon"
+ }, JSX_("i", {
+ className: "sprite-fm-uni icon-chat-group"
+ })), room.isNote && JSX_("div", {
+ className: "note-chat-signifier"
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-file-text-thin-outline note-chat-icon"
+ })), room.type === 'private' && JSX_(contacts.eu, {
+ contact: M.u[contact]
+ })), JSX_("div", {
+ className: "user-card"
+ }, JSX_("span", {
+ className: "title"
+ }, isGroup && JSX_(utils.sp, null, room.getRoomTitle()), room.isNote && JSX_("span", null, l.note_label), room.type === 'private' && JSX_(contacts.uA, {
+ contact: M.u[contact],
+ overflow: true
+ })), isGroup ? null : JSX_(contacts.i1, {
+ contact: M.u[contact]
+ }), JSX_("div", {
+ className: "clear"
+ }), JSX_("div", {
+ className: "message-result-info"
+ }, JSX_("div", {
+ className: "summary"
+ }, JSX_(utils.oM, {
+ content: megaChat.highlight(summary, matches, true)
+ })), JSX_("div", {
+ className: "result-separator"
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-dot"
+ })), JSX_("span", {
+ className: "date"
+ }, date))));
+ }
+}
+class ChatRow extends mixins.w9 {
+ render() {
+ const {
+ room,
+ matches,
+ onResultOpen
+ } = this.props;
+ const result = megaChat.highlight(megaChat.html(room.getRoomTitle()), matches, true);
+ return JSX_("div", {
+ ref: node => {
+ this.domRef = node;
+ },
+ className: RESULT_ROW_CLASS,
+ onClick: () => openResult({
+ room
+ }, () => onResultOpen(this.domRef))
+ }, JSX_("div", {
+ className: "chat-topic-icon"
+ }, JSX_("i", {
+ className: "sprite-fm-uni icon-chat-group"
+ })), JSX_("div", {
+ className: USER_CARD_CLASS
+ }, JSX_("div", {
+ className: "graphic"
+ }, JSX_(utils.oM, null, result)), JSX_("div", {
+ className: "result-last-activity"
+ }, lastActivity(room))), JSX_("div", {
+ className: "clear"
+ }));
+ }
+}
+class MemberRow extends mixins.w9 {
+ render() {
+ const {
+ data,
+ matches,
+ room,
+ contact,
+ onResultOpen
+ } = this.props;
+ const isGroup = room && roomIsGroup(room);
+ return JSX_("div", {
+ ref: node => {
+ this.domRef = node;
+ },
+ className: RESULT_ROW_CLASS,
+ onClick: () => openResult({
+ room: room || contact.h
+ }, () => onResultOpen(this.domRef))
+ }, isGroup ? JSX_("div", {
+ className: "chat-topic-icon"
+ }, JSX_("i", {
+ className: "sprite-fm-uni icon-chat-group"
+ })) : JSX_(contacts.eu, {
+ contact
+ }), JSX_("div", {
+ className: USER_CARD_CLASS
+ }, JSX_("div", {
+ className: "graphic"
+ }, isGroup ? JSX_(utils.oM, null, megaChat.highlight(megaChat.html(room.getRoomTitle()), matches, true)) : JSX_(REaCt().Fragment, null, JSX_(utils.oM, null, megaChat.highlight(megaChat.html(nicknames.getNickname(data)), matches, true)), JSX_(contacts.i1, {
+ contact
+ }))), lastActivity(room)), JSX_("div", {
+ className: "clear"
+ }));
+ }
+}
+const NilRow = ({
+ onSearchMessages,
+ isFirstQuery
+}) => {
+ const label = LABEL.SEARCH_MESSAGES_INLINE.replace('[A]', '').replace('[/A]', '');
+ return JSX_("div", {
+ className: `
+ ${RESULT_ROW_CLASS}
+ nil
+ `
+ }, JSX_("div", {
+ className: "nil-container"
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-preview-reveal"
+ }), JSX_("span", null, LABEL.NO_RESULTS), isFirstQuery && JSX_("div", {
+ className: "search-messages",
+ onClick: onSearchMessages
+ }, JSX_(utils.oM, {
+ tag: "div",
+ content: label
+ }))));
+};
+class ResultRow extends mixins.w9 {
+ constructor(...args) {
+ super(...args);
+ this.setActive = nodeRef => {
+ if (nodeRef) {
+ const elements = document.querySelectorAll(`.${RESULT_ROW_CLASS}.${"active"}`);
+ for (let i = elements.length; i--;) {
+ elements[i].classList.remove('active');
+ }
+ nodeRef.classList.add("active");
+ }
+ };
+ }
+ render() {
+ const {
+ type,
+ result,
+ children,
+ onSearchMessages,
+ isFirstQuery
+ } = this.props;
+ if (result) {
+ const {
+ data,
+ index,
+ matches,
+ room
+ } = result;
+ const PROPS = {
+ data,
+ index,
+ matches,
+ room,
+ onResultOpen: this.setActive
+ };
+ switch (type) {
+ case TYPE.MESSAGE:
+ return JSX_(MessageRow, PROPS);
+ case TYPE.CHAT:
+ return JSX_(ChatRow, PROPS);
+ case TYPE.MEMBER:
+ return JSX_(MemberRow, (0,esm_extends.A)({}, PROPS, {
+ contact: M.u[data]
+ }));
+ default:
+ return JSX_("div", {
+ className: RESULT_ROW_CLASS
+ }, children);
+ }
+ }
+ return JSX_(NilRow, {
+ onSearchMessages,
+ isFirstQuery
+ });
+ }
+}
+;// ./js/chat/ui/searchPanel/resultContainer.jsx
+
+
+
+
+class ResultContainer extends REaCt().Component {
+ constructor(...args) {
+ super(...args);
+ this.renderResults = (results, status, isFirstQuery, onSearchMessages) => {
+ if (status === STATUS.COMPLETED && results.length < 1) {
+ return JSX_(resultTable, null, JSX_(ResultRow, {
+ type: TYPE.NIL,
+ isFirstQuery,
+ onSearchMessages
+ }));
+ }
+ const RESULT_TABLE = {
+ CONTACTS_AND_CHATS: [],
+ MESSAGES: []
+ };
+ for (const resultTypeGroup in results) {
+ if (results.hasOwnProperty(resultTypeGroup)) {
+ const len = results[resultTypeGroup].length;
+ for (let i = 0; i < len; i++) {
+ const result = results[resultTypeGroup].getItem(i);
+ const {
+ MESSAGE,
+ MEMBER,
+ CHAT
+ } = TYPE;
+ const {
+ resultId,
+ type
+ } = result;
+ const table = type === MESSAGE ? 'MESSAGES' : 'CONTACTS_AND_CHATS';
+ RESULT_TABLE[table] = [...RESULT_TABLE[table], JSX_(ResultRow, {
+ key: resultId,
+ type: type === MESSAGE ? MESSAGE : type === MEMBER ? MEMBER : CHAT,
+ result
+ })];
+ }
+ }
+ }
+ return Object.keys(RESULT_TABLE).map((key, index) => {
+ const table = {
+ ref: RESULT_TABLE[key],
+ hasRows: RESULT_TABLE[key] && RESULT_TABLE[key].length,
+ isEmpty: RESULT_TABLE[key] && RESULT_TABLE[key].length < 1,
+ props: {
+ key: index,
+ heading: key === 'MESSAGES' ? LABEL.MESSAGES : LABEL.CONTACTS_AND_CHATS
+ }
+ };
+ if (table.hasRows) {
+ return JSX_(resultTable, table.props, table.ref.map(row => row));
+ }
+ if (status === STATUS.COMPLETED && key === 'MESSAGES') {
+ const SEARCH_MESSAGES = JSX_("button", {
+ className: "search-messages mega-button",
+ onClick: onSearchMessages
+ }, JSX_("span", null, LABEL.SEARCH_MESSAGES_CTA));
+ const NO_RESULTS = JSX_(ResultRow, {
+ type: TYPE.NIL,
+ isFirstQuery,
+ onSearchMessages
+ });
+ return JSX_(resultTable, table.props, isFirstQuery ? SEARCH_MESSAGES : NO_RESULTS);
+ }
+ return null;
+ });
+ };
+ }
+ render() {
+ const {
+ results,
+ status,
+ isFirstQuery,
+ onSearchMessages
+ } = this.props;
+ return this.renderResults(results, status, isFirstQuery, onSearchMessages);
+ }
+}
+// EXTERNAL MODULE: ./js/ui/perfectScrollbar.jsx
+const perfectScrollbar = REQ_(1301);
+;// ./js/chat/ui/searchPanel/searchPanel.jsx
+
+
+
+
+
+
+const SEARCH_PANEL_CLASS = `search-panel`;
+class SearchPanel extends mixins.w9 {
+ constructor(...args) {
+ super(...args);
+ this.domRef = (0,external_React_.createRef)();
+ this.wrapperRef = null;
+ this.state = {
+ value: '',
+ searching: false,
+ status: undefined,
+ isFirstQuery: true,
+ results: []
+ };
+ this.unbindEvents = () => {
+ if (this.pageChangeListener) {
+ mBroadcaster.removeListener(this.pageChangeListener);
+ }
+ document.removeEventListener(EVENTS.RESULT_OPEN, this.doPause);
+ document.removeEventListener(EVENTS.KEYDOWN, this.handleKeyDown);
+ megaChat.plugins.chatdIntegration.chatd.off('onClose.search');
+ megaChat.plugins.chatdIntegration.chatd.off('onOpen.search');
+ };
+ this.bindEvents = () => {
+ this.pageChangeListener = mBroadcaster.addListener('pagechange', this.doPause);
+ document.addEventListener(EVENTS.RESULT_OPEN, this.doPause);
+ document.addEventListener(EVENTS.KEYDOWN, this.handleKeyDown);
+ megaChat.plugins.chatdIntegration.chatd.rebind('onClose.search', () => this.state.searching && this.doToggle(ACTIONS.PAUSE));
+ megaChat.plugins.chatdIntegration.chatd.rebind('onOpen.search', () => this.state.searching && this.doToggle(ACTIONS.RESUME));
+ };
+ this.doPause = () => {
+ if (this.state.status === STATUS.IN_PROGRESS) {
+ this.doToggle(ACTIONS.PAUSE);
+ }
+ };
+ this.doSearch = (s, searchMessages) => {
+ return ChatSearch.doSearch(s, (room, result, results) => this.setState({
+ results
+ }), searchMessages).catch(ex => d && console.error('Search failed (or was reset)', ex)).always(() => this.setState({
+ status: STATUS.COMPLETED
+ }));
+ };
+ this.doToggle = (action) => {
+ const {
+ IN_PROGRESS,
+ PAUSED,
+ COMPLETED
+ } = STATUS;
+ const searching = this.state.status === IN_PROGRESS || this.state.status === PAUSED;
+ if (action && searching) {
+ const chatSearch = ChatSearch.doSearch.cs;
+ if (!chatSearch) {
+ return delay('chat-toggle', () => this.doToggle(action), 600);
+ }
+ this.setState({
+ status: action === ACTIONS.PAUSE ? PAUSED : action === ACTIONS.RESUME ? IN_PROGRESS : COMPLETED
+ }, () => chatSearch[action]());
+ }
+ };
+ this.doDestroy = () => ChatSearch && ChatSearch.doSearch && ChatSearch.doSearch.cs && ChatSearch.doSearch.cs.destroy();
+ this.handleKeyDown = ev => {
+ const {
+ keyCode
+ } = ev;
+ if (keyCode && keyCode === 27) {
+ return SearchField.hasValue() ? this.handleReset() : this.doPause();
+ }
+ };
+ this.handleChange = ev => {
+ if (SearchField.isVisible()) {
+ const {
+ value
+ } = ev.target;
+ const searching = value.length > 0;
+ this.doDestroy();
+ this.setState({
+ value,
+ searching,
+ status: undefined,
+ isFirstQuery: true,
+ results: []
+ }, () => {
+ if (searching) {
+ delay('chat-search', () => this.doSearch(value, false), 1600);
+ if ($.dialog === 'onboardingDialog') {
+ closeDialog();
+ }
+ } else {
+ megaChat.plugins.chatOnboarding.checkAndShowStep();
+ }
+ });
+ this.wrapperRef.scrollToY(0);
+ }
+ };
+ this.handleToggle = () => {
+ const inProgress = this.state.status === STATUS.IN_PROGRESS;
+ this.setState({
+ status: inProgress ? STATUS.PAUSED : STATUS.IN_PROGRESS
+ }, () => {
+ delay('chat-toggled', () => SearchField.focus());
+ return this.doToggle(inProgress ? ACTIONS.PAUSE : ACTIONS.RESUME);
+ });
+ };
+ this.handleReset = () => this.setState({
+ value: '',
+ searching: false,
+ status: undefined,
+ results: []
+ }, () => {
+ this.wrapperRef.scrollToY(0);
+ onIdle(() => SearchField.focus());
+ this.doDestroy();
+ });
+ this.handleSearchMessages = () => SearchField.hasValue() && this.setState({
+ status: STATUS.IN_PROGRESS,
+ isFirstQuery: false
+ }, () => {
+ this.doSearch(this.state.value, true);
+ SearchField.focus();
+ SearchField.select();
+ });
+ }
+ componentDidMount() {
+ super.componentDidMount();
+ this.bindEvents();
+ }
+ componentWillUnmount() {
+ super.componentWillUnmount();
+ this.unbindEvents();
+ }
+ render() {
+ const {
+ value,
+ searching,
+ status,
+ isFirstQuery,
+ results
+ } = this.state;
+ return JSX_("div", {
+ ref: this.domRef,
+ className: `
+ ${SEARCH_PANEL_CLASS}
+ ${searching ? 'expanded' : ''}
+ `
+ }, JSX_(SearchField, {
+ value,
+ searching,
+ status,
+ onChange: this.handleChange,
+ onToggle: this.handleToggle,
+ onReset: this.handleReset
+ }), JSX_(perfectScrollbar.O, {
+ className: "search-results-wrapper",
+ ref: wrapper => {
+ this.wrapperRef = wrapper;
+ },
+ options: {
+ 'suppressScrollX': true
+ }
+ }, searching && JSX_(ResultContainer, {
+ status,
+ results,
+ isFirstQuery,
+ onSearchMessages: this.handleSearchMessages
+ })));
+ }
+}
+// EXTERNAL MODULE: ./js/chat/ui/meetings/button.jsx
+const meetings_button = REQ_(6740);
+// EXTERNAL MODULE: ./js/chat/ui/leftPanel/utils.jsx
+const leftPanel_utils = REQ_(4664);
+;// ./js/chat/ui/leftPanel/navigation.jsx
+
+
+
+const Navigation = ({
+ view,
+ views: {
+ CHATS,
+ MEETINGS
+ },
+ routingSection,
+ unreadChats,
+ unreadMeetings,
+ contactRequests,
+ renderView
+}) => JSX_("div", {
+ className: `${leftPanel_utils.C}-nav`
+}, JSX_("div", {
+ className: `
+ ${leftPanel_utils.C}-nav-container
+ ${leftPanel_utils.C}-chats-tab
+ ${view === CHATS && routingSection === 'chat' ? 'active' : ''}
+ `,
+ onClick: () => {
+ renderView(CHATS);
+ eventlog(500233);
+ }
+}, JSX_(meetings_button.A, {
+ unreadChats,
+ className: `${leftPanel_utils.C}-nav-button`,
+ icon: "icon-chat-filled"
+}, !!unreadChats && JSX_("div", {
+ className: "notifications-count"
+})), JSX_("span", null, l.chats)), JSX_("div", {
+ className: `
+ ${leftPanel_utils.C}-nav-container
+ ${leftPanel_utils.C}-meetings-tab
+ ${view === MEETINGS && routingSection === 'chat' ? 'active' : ''}
+ `,
+ onClick: () => {
+ renderView(MEETINGS);
+ eventlog(500234);
+ }
+}, JSX_(meetings_button.A, {
+ unreadMeetings,
+ className: `${leftPanel_utils.C}-nav-button`,
+ icon: "icon-video-call-filled"
+}, !!unreadMeetings && JSX_("div", {
+ className: "notifications-count"
+})), JSX_("span", null, l.meetings)), is_eplusplus || is_chatlink ? null : JSX_("div", {
+ className: `
+ ${leftPanel_utils.C}-nav-container
+ ${leftPanel_utils.C}-contacts-tab
+ ${routingSection === 'contacts' ? 'active' : ''}
+ `,
+ onClick: () => {
+ loadSubPage('fm/chat/contacts');
+ eventlog(500296);
+ }
+}, JSX_(meetings_button.A, {
+ className: `${leftPanel_utils.C}-nav-button`,
+ contactRequests,
+ icon: "icon-contacts"
+}, !!contactRequests && JSX_("div", {
+ className: "notifications-count"
+})), JSX_("span", null, l[165])));
+// EXTERNAL MODULE: ./js/ui/buttons.jsx
+const buttons = REQ_(5155);
+// EXTERNAL MODULE: ./js/ui/dropdowns.jsx
+const dropdowns = REQ_(1510);
+;// ./js/chat/ui/leftPanel/actions.jsx
+
+
+
+
+const Actions = ({
+ view,
+ views,
+ filter,
+ routingSection,
+ startMeeting,
+ scheduleMeeting,
+ createNewChat,
+ onFilter
+}) => {
+ const {
+ CHATS,
+ MEETINGS,
+ LOADING
+ } = views;
+ if (is_eplusplus || is_chatlink) {
+ return null;
+ }
+ return JSX_("div", {
+ className: `${leftPanel_utils.C}-action-buttons`
+ }, view === LOADING && JSX_(buttons.$, {
+ className: "mega-button action loading-sketch"
+ }, JSX_("i", null), JSX_("span", null)), view === CHATS && routingSection !== 'contacts' && JSX_(REaCt().Fragment, null, JSX_(buttons.$, {
+ className: "mega-button small positive new-chat-action",
+ label: l.add_chat,
+ onClick: () => {
+ createNewChat();
+ eventlog(500284);
+ }
+ }), JSX_("div", {
+ className: "lhp-filter"
+ }, JSX_("div", {
+ className: "lhp-filter-control"
+ }, JSX_(buttons.$, {
+ icon: "sprite-fm-mono icon-sort-thin-solid"
+ }, JSX_(dropdowns.ms, {
+ className: "light",
+ noArrow: "true"
+ }, JSX_(dropdowns.tJ, {
+ className: "link-button",
+ icon: "sprite-fm-mono icon-eye-reveal",
+ label: l.filter_unread,
+ onClick: () => onFilter(leftPanel_utils.x.UNREAD)
+ }), JSX_(dropdowns.tJ, {
+ className: "link-button",
+ icon: "sprite-fm-mono icon-notification-off",
+ label: view === MEETINGS ? l.filter_muted__meetings : l.filter_muted__chats,
+ onClick: () => onFilter(leftPanel_utils.x.MUTED)
+ })))), filter && JSX_(REaCt().Fragment, null, filter === leftPanel_utils.x.MUTED && JSX_("div", {
+ className: "lhp-filter-tag",
+ onClick: () => onFilter(leftPanel_utils.x.MUTED)
+ }, JSX_("span", null, view === MEETINGS ? l.filter_muted__meetings : l.filter_muted__chats), JSX_("i", {
+ className: "sprite-fm-mono icon-close-component"
+ })), filter === leftPanel_utils.x.UNREAD && JSX_("div", {
+ className: "lhp-filter-tag",
+ onClick: () => onFilter(leftPanel_utils.x.UNREAD)
+ }, JSX_("span", null, l.filter_unread), JSX_("i", {
+ className: "sprite-fm-mono icon-close-component"
+ }))))), view === MEETINGS && routingSection !== 'contacts' && JSX_(buttons.$, {
+ className: "mega-button small positive new-meeting-action",
+ label: l.new_meeting
+ }, JSX_("i", {
+ className: "dropdown-indicator sprite-fm-mono icon-arrow-down"
+ }), JSX_(dropdowns.ms, {
+ className: "light",
+ noArrow: "true",
+ vertOffset: 4,
+ positionMy: "left top",
+ positionAt: "left bottom"
+ }, JSX_(dropdowns.tJ, {
+ className: "link-button",
+ icon: "sprite-fm-mono icon-video-plus",
+ label: l.new_meeting_start,
+ onClick: startMeeting
+ }), JSX_("hr", null), JSX_(dropdowns.tJ, {
+ className: "link-button",
+ icon: "sprite-fm-mono icon-calendar2",
+ label: l.schedule_meeting_start,
+ onClick: scheduleMeeting
+ }))), routingSection === 'contacts' && JSX_(buttons.$, {
+ className: "mega-button small positive",
+ label: l[71],
+ onClick: () => {
+ contactAddDialog();
+ eventlog(500285);
+ }
+ }));
+};
+ const actions = Actions;
+// EXTERNAL MODULE: ./node_modules/@babel/runtime/helpers/esm/applyDecoratedDescriptor.js
+const applyDecoratedDescriptor = REQ_(793);
+;// ./js/chat/ui/leftPanel/conversationsListItem.jsx
+
+let _dec, _dec2, _class;
+
+
+
+
+const ConversationsListItem = (_dec = utils.Ay.SoonFcWrap(40, true), _dec2 = (0,mixins.N9)(0.7, 8), _class = class ConversationsListItem extends mixins.w9 {
+ constructor(...args) {
+ super(...args);
+ this.domRef = REaCt().createRef();
+ this.state = {
+ isLoading: true
+ };
+ }
+ isLoading() {
+ const mb = this.props.chatRoom.messagesBuff;
+ if (mb.haveMessages) {
+ return false;
+ }
+ return mb.messagesHistoryIsLoading() || mb.joined === false && mb.isDecrypting;
+ }
+ specShouldComponentUpdate() {
+ return !this.state.isLoading;
+ }
+ componentWillUnmount() {
+ super.componentWillUnmount();
+ this.props.chatRoom.unbind('onUnreadCountUpdate.conversationsListItem');
+ }
+ componentDidMount() {
+ super.componentDidMount();
+ this.eventuallyScrollTo();
+ const promise = this.isLoading();
+ if (promise && promise.always) {
+ promise.always(() => {
+ if (this.isMounted()) {
+ this.setState({
+ isLoading: false
+ });
+ }
+ });
+ } else if (promise === false) {
+ this.setState({
+ isLoading: false
+ });
+ }
+ this.props.chatRoom.rebind('onUnreadCountUpdate.conversationsListItem', () => {
+ this.safeForceUpdate();
+ });
+ }
+ componentDidUpdate() {
+ super.componentDidUpdate();
+ this.eventuallyScrollTo();
+ }
+ eventuallyScrollTo() {
+ const chatRoom = this.props.chatRoom || false;
+ if (chatRoom._scrollToOnUpdate) {
+ if (chatRoom.isCurrentlyActive) {
+ chatRoom.scrollToChat();
+ } else {
+ chatRoom._scrollToOnUpdate = false;
+ }
+ }
+ }
+ getConversationTimestamp() {
+ const {
+ chatRoom
+ } = this.props;
+ if (chatRoom) {
+ const lastMessage = chatRoom.messagesBuff.getLatestTextMessage();
+ const timestamp = lastMessage && lastMessage.delay || chatRoom.ctime;
+ return todayOrYesterday(timestamp * 1000) ? getTimeMarker(timestamp) : time2date(timestamp, 17);
+ }
+ return null;
+ }
+ getScheduledDateTime() {
+ const {
+ scheduledMeeting
+ } = this.props.chatRoom;
+ if (scheduledMeeting) {
+ const {
+ nextOccurrenceStart,
+ nextOccurrenceEnd
+ } = scheduledMeeting;
+ return {
+ date: time2date(nextOccurrenceStart / 1000, 19),
+ startTime: toLocaleTime(nextOccurrenceStart),
+ endTime: toLocaleTime(nextOccurrenceEnd)
+ };
+ }
+ }
+ render() {
+ let classString = "";
+ const {chatRoom} = this.props;
+ if (!chatRoom || !chatRoom.chatId) {
+ return null;
+ }
+ const roomId = chatRoom.chatId;
+ if (chatRoom.isCurrentlyActive) {
+ classString += " active";
+ }
+ let nameClassString = "user-card-name conversation-name selectable-txt";
+ let contactId;
+ let id;
+ let contact;
+ if (chatRoom.type === 'private') {
+ const handle = chatRoom.getParticipantsExceptMe()[0];
+ contact = handle ? M.u[handle] : M.u[u_handle];
+ if (!contact) {
+ return `Unknown conversation id for ${chatRoom.roomId}`;
+ }
+ id = `conversation_${htmlentities(contact.u)}`;
+ } else if (chatRoom.type === 'group') {
+ contactId = roomId;
+ id = `conversation_${contactId}`;
+ classString += ' groupchat';
+ } else if (chatRoom.type === 'public') {
+ contactId = roomId;
+ id = `conversation_${contactId}`;
+ classString += ' groupchat public';
+ } else {
+ return `Unknown room type for ${chatRoom.roomId}`;
+ }
+ const unreadCount = chatRoom.messagesBuff.getUnreadCount();
+ let isUnread = false;
+ const notificationItems = [];
+ if (chatRoom.havePendingCall() && chatRoom.state !== ChatRoom.STATE.LEFT) {
+ notificationItems.push(JSX_("i", {
+ className: "tiny-icon white-handset",
+ key: "callIcon"
+ }));
+ }
+ if (unreadCount > 0) {
+ notificationItems.push(JSX_("span", {
+ key: "unreadCounter"
+ }, unreadCount > 9 ? "9+" : unreadCount));
+ isUnread = true;
+ }
+ let lastMessageDiv = null;
+ const showHideMsg = mega.config.get('showHideChat');
+ const lastMessage = showHideMsg ? '' : chatRoom.messagesBuff.getLatestTextMessage();
+ let lastMsgDivClasses;
+ if (lastMessage) {
+ lastMsgDivClasses = `conversation-message${ isUnread ? " unread" : ""}`;
+ const renderableSummary = chatRoom.messagesBuff.getRenderableSummary(lastMessage);
+ if (chatRoom.havePendingCall() || chatRoom.haveActiveCall()) {
+ lastMsgDivClasses += " call";
+ classString += " call-exists";
+ }
+ lastMessageDiv = JSX_("div", {
+ className: lastMsgDivClasses
+ }, JSX_(utils.P9, null, renderableSummary));
+ if (lastMessage.textContents && lastMessage.textContents[1] === Message.MANAGEMENT_MESSAGE_TYPES.VOICE_CLIP && lastMessage.getAttachmentMeta()[0]) {
+ const playTime = secondsToTimeShort(lastMessage.getAttachmentMeta()[0].playtime);
+ lastMessageDiv = JSX_("div", {
+ className: lastMsgDivClasses
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-audio-filled voice-message-icon"
+ }), playTime);
+ }
+ if (lastMessage.metaType && lastMessage.metaType === Message.MESSAGE_META_TYPE.GEOLOCATION) {
+ lastMessageDiv = JSX_("div", {
+ className: lastMsgDivClasses
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-location geolocation-icon"
+ }), l[20789]);
+ }
+ } else {
+ lastMsgDivClasses = "conversation-message";
+ lastMessageDiv = showHideMsg ? '' : JSX_("div", {
+ className: lastMsgDivClasses
+ }, this.state.isLoading ? l[7006] : l[8000]);
+ }
+ if (chatRoom.type !== 'public') {
+ nameClassString += ' privateChat';
+ }
+ let roomTitle = JSX_(utils.oM, null, megaChat.html(chatRoom.getRoomTitle()));
+ if (chatRoom.type === 'private') {
+ roomTitle = megaChat.WITH_SELF_NOTE && chatRoom.isNote ? JSX_("span", {
+ className: "note-chat-label"
+ }, l.note_label) : JSX_("span", null, JSX_("div", {
+ className: "user-card-wrapper"
+ }, JSX_(utils.oM, null, megaChat.html(chatRoom.getRoomTitle()))));
+ }
+ nameClassString += chatRoom.type === "private" || chatRoom.type === "group" ? ' badge-pad' : '';
+ const {
+ scheduledMeeting,
+ isMeeting
+ } = chatRoom;
+ const isUpcoming = scheduledMeeting && scheduledMeeting.isUpcoming;
+ const {
+ startTime,
+ endTime
+ } = this.getScheduledDateTime() || {};
+ const isEmptyNote = chatRoom.isNote && !chatRoom.hasMessages();
+ return JSX_("li", {
+ ref: this.domRef,
+ id,
+ className: `
+ ${classString}
+ ${isUpcoming ? 'upcoming-conversation' : ''}
+ ${this.props.className || ''}
+ `,
+ "data-room-id": roomId,
+ "data-jid": contactId,
+ onClick: ev => {
+ let _this$props$onConvers, _this$props;
+ return ((_this$props$onConvers = (_this$props = this.props).onConversationClick) == null ? void 0 : _this$props$onConvers.call(_this$props, ev)) || loadSubPage(chatRoom.getRoomUrl(false));
+ }
+ }, JSX_("div", {
+ className: "conversation-avatar"
+ }, (chatRoom.type === 'group' || chatRoom.type === 'public') && JSX_("div", {
+ className: `
+ chat-topic-icon
+ ${isMeeting ? 'meeting-icon' : ''}
+ `
+ }, JSX_("i", {
+ className: isMeeting ? 'sprite-fm-mono icon-video-call-filled' : 'sprite-fm-uni icon-chat-group'
+ })), chatRoom.type === 'private' && contact && chatRoom.isNote ? JSX_("div", {
+ className: `
+ note-chat-signifier
+ ${isEmptyNote ? 'note-chat-empty' : ''}
+ `
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-file-text-thin-outline note-chat-icon"
+ })) : JSX_(contacts.eu, {
+ contact
+ })), JSX_("div", {
+ className: "conversation-data"
+ }, JSX_("div", {
+ className: "conversation-data-top"
+ }, JSX_("div", {
+ className: `conversation-data-name ${nameClassString}`
+ }, roomTitle, chatRoom.isMuted() ? JSX_("i", {
+ className: "sprite-fm-mono icon-notification-off-filled muted-conversation-icon"
+ }) : null), chatRoom.isNote ? null : JSX_("div", {
+ className: "conversation-data-badges"
+ }, chatRoom.type === 'private' ? JSX_(contacts.i1, {
+ contact
+ }) : null, chatRoom.type === 'group' || chatRoom.type === 'private' ? JSX_("i", {
+ className: "sprite-fm-uni icon-ekr-key simpletip",
+ "data-simpletip": l[20935]
+ }) : null, scheduledMeeting && scheduledMeeting.isUpcoming && scheduledMeeting.isRecurring && JSX_("i", {
+ className: "sprite-fm-mono icon-repeat-thin-solid"
+ }))), JSX_("div", {
+ className: "clear"
+ }), isUpcoming ? JSX_("div", {
+ className: "conversation-message-info"
+ }, JSX_("div", {
+ className: "conversation-scheduled-data"
+ }, JSX_("span", null, startTime), JSX_("span", null, "\xA0 - \xA0"), JSX_("span", null, endTime)), JSX_("div", {
+ className: "conversation-scheduled-data"
+ }, notificationItems.length > 0 ? JSX_("div", {
+ className: `
+ unread-messages
+ items-${notificationItems.length}
+ unread-upcoming
+ ${unreadCount > 9 && notificationItems.length > 1 ? 'unread-spaced' : ''}
+ `
+ }, notificationItems) : null)) : JSX_("div", {
+ className: "conversation-message-info"
+ }, isEmptyNote ? null : lastMessageDiv)), isUpcoming || isEmptyNote ? null : JSX_("div", {
+ className: "date-time-wrapper"
+ }, JSX_("div", {
+ className: "date-time"
+ }, this.getConversationTimestamp()), notificationItems.length > 0 ? JSX_("div", {
+ className: `
+ unread-messages-container
+ ${unreadCount > 9 && notificationItems.length > 1 ? 'unread-spaced' : ''}
+ `
+ }, JSX_("div", {
+ className: `unread-messages items-${notificationItems.length}`
+ }, notificationItems)) : null));
+ }
+}, (0,applyDecoratedDescriptor.A)(_class.prototype, "eventuallyScrollTo", [_dec], Object.getOwnPropertyDescriptor(_class.prototype, "eventuallyScrollTo"), _class.prototype), (0,applyDecoratedDescriptor.A)(_class.prototype, "render", [_dec2], Object.getOwnPropertyDescriptor(_class.prototype, "render"), _class.prototype), _class);
+
+;// ./js/chat/ui/leftPanel/conversationsList.jsx
+
+
+
+
+
+
+
+const ConversationsList = ({
+ conversations,
+ className,
+ children
+}) => {
+ return JSX_(perfectScrollbar.O, {
+ className: "chat-lp-scroll-area",
+ didMount: (id, ref) => {
+ megaChat.$chatTreePanePs = [...megaChat.$chatTreePanePs, {
+ id,
+ ref
+ }];
+ },
+ willUnmount: id => {
+ megaChat.$chatTreePanePs = megaChat.$chatTreePanePs.filter(ref => ref.id !== id);
+ },
+ conversations
+ }, JSX_("ul", {
+ className: `
+ conversations-pane
+ ${className || ''}
+ `
+ }, children || conversations.map(c => c.roomId && JSX_(ConversationsListItem, (0,esm_extends.A)({
+ key: c.roomId,
+ chatRoom: c
+ }, c.type === 'private' && {
+ contact: M.u[c.getParticipantsExceptMe()[0]]
+ })))));
+};
+const Chats = ({
+ conversations,
+ onArchivedClicked,
+ filter
+}) => {
+ conversations = Object.values(conversations || {}).filter(c => !c.isMeeting && c.isDisplayable() && (!filter || filter === leftPanel_utils.x.UNREAD && c.messagesBuff.getUnreadCount() > 0 || filter === leftPanel_utils.x.MUTED && c.isMuted())).sort(M.sortObjFn(c => c.lastActivity || c.ctime, -1));
+ const noteChat = megaChat.getNoteChat();
+ return JSX_(REaCt().Fragment, null, JSX_("div", {
+ className: "conversations-holder"
+ }, filter ? null : JSX_("div", {
+ className: "conversations-category"
+ }, JSX_("span", null, l.filter_heading__recent)), conversations && conversations.length >= 1 ? JSX_(ConversationsList, {
+ conversations
+ }, megaChat.WITH_SELF_NOTE && noteChat && noteChat.isDisplayable() ? filter ? null : JSX_(ConversationsListItem, {
+ chatRoom: noteChat
+ }) : null, conversations.map(c => c.roomId && !c.isNote && JSX_(ConversationsListItem, (0,esm_extends.A)({
+ key: c.roomId,
+ chatRoom: c
+ }, c.type === 'private' && {
+ contact: M.u[c.getParticipantsExceptMe()[0]]
+ })))) : JSX_("div", {
+ className: `
+ ${leftPanel_utils.C}-nil
+ ${filter ? `${leftPanel_utils.C}-nil--chats` : ''}
+ `
+ }, filter ? JSX_(REaCt().Fragment, null, filter === leftPanel_utils.x.MUTED && JSX_(REaCt().Fragment, null, JSX_("i", {
+ className: "sprite-fm-mono icon-notification-off-filled"
+ }), JSX_("h3", null, l.filter_nil__muted_chats)), filter === leftPanel_utils.x.UNREAD && JSX_(REaCt().Fragment, null, JSX_("i", {
+ className: "sprite-fm-mono icon-eye-thin-solid"
+ }), JSX_("h3", null, l.filter_nil__unread_messages))) : JSX_("span", null, l.no_chats_lhp)), megaChat.WITH_SELF_NOTE && conversations && conversations.length === 1 && noteChat && JSX_(ConversationsList, {
+ conversations
+ }, JSX_(ConversationsListItem, {
+ chatRoom: noteChat
+ }))), JSX_("div", {
+ className: `${leftPanel_utils.C}-bottom`
+ }, JSX_("div", {
+ className: `${leftPanel_utils.C}-bottom-control`
+ }, JSX_("div", {
+ className: "conversations-category",
+ onClick: onArchivedClicked
+ }, JSX_("span", null, l.filter_archived__chats), JSX_("i", {
+ className: "sprite-fm-mono icon-arrow-right"
+ })))));
+};
+const Archived = ({
+ conversations,
+ archivedUnmounting,
+ onClose
+}) => {
+ const archivedChats = Object.values(conversations || {}).filter(c => !c.isMeeting && c.isArchived()).sort(M.sortObjFn(c => c.lastActivity || c.ctime, -1));
+ return JSX_("div", {
+ className: `
+ ${leftPanel_utils.C}-archived
+ ${archivedUnmounting ? 'with-unmount-animation' : ''}
+ `
+ }, JSX_("div", {
+ className: `${leftPanel_utils.C}-archived-head`
+ }, JSX_(meetings_button.A, {
+ className: "mega-button round",
+ icon: "sprite-fm-mono icon-arrow-left-regular-outline",
+ onClick: onClose
+ }), JSX_("h2", null, l.filter_archived__chats)), JSX_("div", {
+ className: `${leftPanel_utils.C}-archived-content`
+ }, archivedChats && archivedChats.length ? JSX_(ConversationsList, {
+ conversations: archivedChats
+ }) : JSX_("div", {
+ className: `${leftPanel_utils.C}-archived-empty`
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-archive"
+ }), JSX_("h3", null, l.filter_archived__nil_chats))));
+};
+class Meetings extends mixins.w9 {
+ constructor(props) {
+ let _megaChat$getCurrentM;
+ super(props);
+ this.TABS = {
+ UPCOMING: 0x00,
+ PAST: 0x01
+ };
+ this.domRef = REaCt().createRef();
+ this.ongoingRef = REaCt().createRef();
+ this.navigationRef = REaCt().createRef();
+ this.state = {
+ tab: this.TABS.UPCOMING
+ };
+ this.Navigation = ({
+ conversations
+ }) => {
+ const {
+ UPCOMING,
+ PAST
+ } = this.TABS;
+ const {
+ tab
+ } = this.state;
+ const unreadMeetings = Object.values(conversations || {}).reduce((acc, curr) => {
+ if (curr.isDisplayable() && curr.isMeeting && curr.messagesBuff.getUnreadCount()) {
+ let _curr$scheduledMeetin;
+ acc[(_curr$scheduledMeetin = curr.scheduledMeeting) != null && _curr$scheduledMeetin.isUpcoming ? UPCOMING : PAST]++;
+ }
+ return acc;
+ }, {
+ [UPCOMING]: 0,
+ [PAST]: 0
+ });
+ return JSX_("div", {
+ ref: this.navigationRef,
+ className: `
+ ${leftPanel_utils.C}-meetings--navigation
+ ${this.props.leftPaneWidth < 230 ? 'narrow-width' : ''}
+ `
+ }, JSX_(meetings_button.A, {
+ converstaions: conversations,
+ className: `
+ mega-button
+ action
+ ${tab === UPCOMING ? 'is-active' : ''}
+ `,
+ onClick: () => this.setState({
+ tab: UPCOMING
+ })
+ }, JSX_("span", null, l.meetings_tab_upcoming, !!unreadMeetings[UPCOMING] && JSX_("div", {
+ className: "notification-indication"
+ }))), JSX_(meetings_button.A, {
+ converstaions: conversations,
+ className: `
+ mega-button
+ action
+ ${tab === PAST ? 'is-active' : ''}
+ `,
+ onClick: () => this.setState({
+ tab: PAST
+ }, () => eventlog(500254))
+ }, JSX_("span", null, l.meetings_tab_past, !!unreadMeetings[PAST] && JSX_("div", {
+ className: "notification-indication"
+ }))));
+ };
+ this.Holder = ({
+ heading,
+ className,
+ children
+ }) => JSX_("div", {
+ className: `
+ conversations-holder
+ ${className || ''}
+ `
+ }, JSX_("div", {
+ className: `
+ conversations-category
+ `
+ }, heading && JSX_("span", null, heading)), children);
+ this.Ongoing = ({
+ ongoingMeetings
+ }) => ongoingMeetings != null && ongoingMeetings.length ? JSX_("div", {
+ ref: this.ongoingRef,
+ className: `${leftPanel_utils.C}-meetings--ongoing`
+ }, JSX_("strong", null, l.happening_now), JSX_(ConversationsList, {
+ conversations: ongoingMeetings
+ })) : null;
+ this.Upcoming = () => {
+ const {
+ upcomingMeetings,
+ nextOccurrences
+ } = megaChat.plugins.meetingsManager.filterUpcomingMeetings(this.props.conversations);
+ const upcomingItem = chatRoom => JSX_(ConversationsListItem, {
+ key: chatRoom.roomId,
+ chatRoom
+ });
+ return JSX_(this.Holder, null, upcomingMeetings && upcomingMeetings.length ? JSX_(ConversationsList, {
+ conversations: upcomingMeetings
+ }, nextOccurrences.today && nextOccurrences.today.length ? JSX_("div", {
+ className: "conversations-group"
+ }, JSX_("div", {
+ className: "conversations-category category--label"
+ }, JSX_("span", null, l.upcoming__today)), nextOccurrences.today.map(upcomingItem)) : null, nextOccurrences.tomorrow && nextOccurrences.tomorrow.length ? JSX_("div", {
+ className: "conversations-group"
+ }, JSX_("div", {
+ className: "conversations-category category--label"
+ }, JSX_("span", null, l.upcoming__tomorrow)), nextOccurrences.tomorrow.map(upcomingItem)) : null, Object.keys(nextOccurrences.rest).length ? Object.keys(nextOccurrences.rest).map(date => JSX_("div", {
+ key: date,
+ className: "conversations-group"
+ }, JSX_("div", {
+ className: "conversations-category category--label"
+ }, JSX_("span", null, date)), nextOccurrences.rest[date].map(upcomingItem))) : null) : JSX_("div", {
+ className: `${leftPanel_utils.C}-nil`
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-calendar-plus-thin-solid"
+ }), JSX_("span", null, l.meetings_upcoming_nil)));
+ };
+ this.Past = () => {
+ const conversations = Object.values(this.props.conversations || {});
+ const pastMeetings = conversations.filter(c => {
+ const {
+ isCanceled,
+ isPast,
+ isCompleted
+ } = c.scheduledMeeting || {};
+ return c.isMeeting && c.isDisplayable() && (!c.scheduledMeeting || isCanceled || isPast || isCompleted) && !c.havePendingCall();
+ }).sort(M.sortObjFn(c => c.lastActivity || c.ctime, -1));
+ const archivedMeetings = conversations.filter(c => c.isMeeting && c.isArchived()).sort(M.sortObjFn(c => c.lastActivity || c.ctime, -1));
+ return JSX_(this.Holder, null, JSX_(ConversationsList, {
+ conversations: pastMeetings
+ }, pastMeetings.length ? pastMeetings.map(chatRoom => chatRoom.roomId && JSX_(ConversationsListItem, {
+ key: chatRoom.roomId,
+ chatRoom
+ })) : JSX_("div", {
+ className: `
+ ${leftPanel_utils.C}-nil
+ ${archivedMeetings.length ? 'half-sized' : ''}
+ `
+ }, archivedMeetings.length ? JSX_("strong", null, l.meetings_past_nil_heading) : null, JSX_("i", {
+ className: "sprite-fm-mono icon-video-thin-solid"
+ }), JSX_("span", null, l.meetings_past_nil)), archivedMeetings.length ? JSX_(REaCt().Fragment, null, JSX_("div", {
+ className: "archived-separator"
+ }), JSX_("div", {
+ className: "conversations-category category--label"
+ }, JSX_("span", null, l.meetings_label_archived)), archivedMeetings.map(chatRoom => chatRoom.roomId && JSX_(ConversationsListItem, {
+ key: chatRoom.roomId,
+ chatRoom
+ }))) : null));
+ };
+ this.getContainerStyles = ongoingMeetings => {
+ if (ongoingMeetings != null && ongoingMeetings.length) {
+ let _this$ongoingRef, _this$navigationRef;
+ const ongoingHeight = (_this$ongoingRef = this.ongoingRef) == null || (_this$ongoingRef = _this$ongoingRef.current) == null ? void 0 : _this$ongoingRef.clientHeight;
+ const navigationHeight = (_this$navigationRef = this.navigationRef) == null || (_this$navigationRef = _this$navigationRef.current) == null ? void 0 : _this$navigationRef.clientHeight;
+ return {
+ style: {
+ maxHeight: `calc(100% - ${ongoingHeight + navigationHeight + 30}px)`
+ }
+ };
+ }
+ return null;
+ };
+ this.state.tab = this.TABS[(_megaChat$getCurrentM = megaChat.getCurrentMeeting()) != null && _megaChat$getCurrentM.isPast ? 'PAST' : 'UPCOMING'];
+ }
+ componentWillUnmount() {
+ super.componentWillUnmount();
+ megaChat.off(`${megaChat.plugins.meetingsManager.EVENTS.OCCURRENCES_UPDATE}.${this.getUniqueId()}`);
+ }
+ componentDidMount() {
+ super.componentDidMount();
+ megaChat.rebind(`${megaChat.plugins.meetingsManager.EVENTS.OCCURRENCES_UPDATE}.${this.getUniqueId()}`, () => this.safeForceUpdate());
+ megaChat.rebind(megaChat.plugins.meetingsManager.EVENTS.INITIALIZE, (ev, scheduledMeeting) => this.isMounted() && this.setState({
+ tab: this.TABS[scheduledMeeting != null && scheduledMeeting.isPast ? 'PAST' : 'UPCOMING']
+ }));
+ }
+ render() {
+ const {
+ UPCOMING,
+ PAST
+ } = this.TABS;
+ const {
+ tab
+ } = this.state;
+ const ongoingMeetings = Object.values(this.props.conversations || {}).filter(c => c.isDisplayable() && c.isMeeting && c.havePendingCall());
+ return JSX_("div", {
+ ref: this.domRef,
+ className: `${leftPanel_utils.C}-meetings`
+ }, JSX_(this.Ongoing, {
+ ongoingMeetings
+ }), JSX_(this.Navigation, {
+ conversations: this.props.conversations
+ }), JSX_("div", (0,esm_extends.A)({
+ className: `
+ ${leftPanel_utils.C}-meetings--content
+ ${tab === UPCOMING ? 'is-upcoming' : ''}
+ ${tab === PAST ? 'is-past' : ''}
+ `
+ }, this.getContainerStyles(ongoingMeetings)), tab === UPCOMING && JSX_(this.Upcoming, null), tab === PAST && JSX_(this.Past, null)));
+ }
+}
+// EXTERNAL MODULE: ./js/chat/ui/updateObserver.jsx
+const updateObserver = REQ_(4372);
+;// ./js/chat/ui/leftPanel/leftPanel.jsx
+
+
+
+
+
+
+
+
+
+class LeftPanel extends mixins.w9 {
+ constructor(props) {
+ super(props);
+ this.domRef = REaCt().createRef();
+ this.contactRequestsListener = undefined;
+ this.fmConfigLeftPaneListener = undefined;
+ this.state = {
+ leftPaneWidth: Math.min(mega.config.get('leftPaneWidth') | 0, 400) || 384,
+ archived: false,
+ archivedUnmounting: false,
+ filter: '',
+ unreadChats: 0,
+ unreadMeetings: 0,
+ contactRequests: 0
+ };
+ this.toggleFilter = filter => {
+ this.setState(state => ({
+ filter: state.filter === filter ? '' : filter
+ }), () => {
+ Object.values(megaChat.$chatTreePanePs).map(({
+ ref
+ }) => ref.reinitialise == null ? void 0 : ref.reinitialise());
+ });
+ };
+ this.state.contactRequests = Object.keys(M.ipc).length;
+ }
+ customIsEventuallyVisible() {
+ return M.chat;
+ }
+ renderLoading() {
+ return JSX_(REaCt().Fragment, null, JSX_("span", {
+ className: "heading loading-sketch"
+ }), JSX_("ul", {
+ className: "conversations-pane loading-sketch"
+ }, Array.from({
+ length: this.props.conversations.length
+ }, (el, i) => {
+ return JSX_("li", {
+ key: i
+ }, JSX_("div", {
+ className: "conversation-avatar"
+ }, JSX_("div", {
+ className: "chat-topic-icon"
+ })), JSX_("div", {
+ className: "conversation-data"
+ }, JSX_("div", {
+ className: "conversation-data-top"
+ }), JSX_("div", {
+ className: "conversation-message-info"
+ }, JSX_("div", {
+ className: "conversation-message"
+ }))));
+ })));
+ }
+ componentWillUnmount() {
+ super.componentWillUnmount();
+ megaChat.unbind(`onUnreadCountUpdate.${leftPanel_utils.C}`);
+ mBroadcaster.removeListener(this.contactRequestsListener);
+ mBroadcaster.removeListener(this.fmConfigLeftPaneListener);
+ }
+ componentDidMount() {
+ let _$$leftPaneResizable;
+ super.componentDidMount();
+ megaChat.rebind(`onUnreadCountUpdate.${leftPanel_utils.C}`, (ev, {
+ unreadChats,
+ unreadMeetings
+ }) => {
+ this.setState({
+ unreadChats,
+ unreadMeetings
+ }, () => this.safeForceUpdate());
+ });
+ this.contactRequestsListener = mBroadcaster.addListener('fmViewUpdate:ipc', () => this.setState({
+ contactRequests: Object.keys(M.ipc).length
+ }));
+ $.leftPaneResizableChat = new FMResizablePane(this.domRef.current, {
+ ...(_$$leftPaneResizable = $.leftPaneResizable) == null ? void 0 : _$$leftPaneResizable.options,
+ minWidth: mega.flags.ab_ads ? 260 : 200
+ });
+ this.fmConfigLeftPaneListener = mBroadcaster.addListener('fmconfig:leftPaneWidth', value => this.setState(state => ({
+ leftPaneWidth: value || state.leftPaneWidth
+ })));
+ }
+ render() {
+ const {
+ view,
+ views,
+ conversations,
+ routingSection,
+ renderView,
+ startMeeting,
+ scheduleMeeting,
+ createNewChat
+ } = this.props;
+ const {
+ CHATS,
+ MEETINGS,
+ LOADING
+ } = views;
+ return JSX_("div", (0,esm_extends.A)({
+ ref: this.domRef,
+ className: `
+ fm-left-panel
+ chat-lp-body
+ ${leftPanel_utils.C}-container
+ ${is_chatlink && 'hidden' || ''}
+ ${megaChat._joinDialogIsShown && 'hidden' || ''}
+ `
+ }, this.state.leftPaneWidth && {
+ width: this.state.leftPaneWidth
+ }), JSX_("div", {
+ className: "left-pane-drag-handle"
+ }), JSX_(SearchPanel, null), JSX_(Navigation, {
+ view,
+ views,
+ routingSection,
+ unreadChats: this.state.unreadChats,
+ unreadMeetings: this.state.unreadMeetings,
+ contactRequests: this.state.contactRequests,
+ renderView: view => this.setState({
+ filter: false
+ }, () => renderView(view))
+ }), JSX_(actions, {
+ view,
+ views,
+ filter: this.state.filter,
+ routingSection,
+ startMeeting,
+ scheduleMeeting,
+ createNewChat,
+ onFilter: this.toggleFilter
+ }), this.state.archived && JSX_(Archived, {
+ conversations,
+ archivedUnmounting: this.state.archivedUnmounting,
+ onClose: () => this.setState({
+ archivedUnmounting: true
+ }, () => tSleep(0.3).then(() => this.setState({
+ archivedUnmounting: false,
+ archived: false
+ })))
+ }), JSX_("div", {
+ className: `
+ ${leftPanel_utils.C}-conversations
+ ${view === MEETINGS ? 'meetings-view' : ''}
+ ${view === CHATS ? 'chats-view' : ''}
+ conversations
+ content-panel
+ active
+ `
+ }, view === LOADING ? this.renderLoading() : JSX_(REaCt().Fragment, null, view === MEETINGS && JSX_(Meetings, {
+ conversations,
+ leftPaneWidth: this.state.leftPaneWidth
+ }), view === CHATS && JSX_(Chats, {
+ conversations,
+ filter: this.state.filter,
+ onArchivedClicked: () => this.setState({
+ archived: true,
+ filter: false
+ })
+ }))));
+ }
+}
+ const leftPanel = (0,mixins.Zz)(updateObserver.Y)(LeftPanel);
+
+ },
+
+ 7677
+(_, EXP_, REQ_) {
+
+ REQ_.d(EXP_, {
+ C: () => withHostsObserver
+ });
+ const _babel_runtime_helpers_extends0__ = REQ_(8168);
+ const react1__ = REQ_(1594);
+ const react1___default = REQ_.n(react1__);
+ const _mixins_js2__ = REQ_(8264);
+ const _ui_modalDialogs_jsx3__ = REQ_(8120);
+ const _contacts_jsx4__ = REQ_(8022);
+ const _ui_buttons_jsx5__ = REQ_(5155);
+
+
+
+
+
+
+const withHostsObserver = Component => {
+ return class extends _mixins_js2__ .w9 {
+ constructor(...args) {
+ super(...args);
+ this.state = {
+ dialog: false,
+ selected: []
+ };
+ this.hasHost = participants => participants.some(handle => this.props.chatRoom.members[handle] === ChatRoom.MembersSet.PRIVILEGE_STATE.OPERATOR);
+ this.toggleDialog = () => {
+ this.setState(state => ({
+ dialog: !state.dialog,
+ selected: []
+ }), () => this.safeForceUpdate());
+ };
+ this.renderDialog = () => {
+ let _this$props$participa;
+ const {
+ selected
+ } = this.state;
+ return JSX_(_ui_modalDialogs_jsx3__ .A.ModalDialog, (0,_babel_runtime_helpers_extends0__ .A)({}, this.state, {
+ className: "assign-host contact-picker-widget",
+ dialogName: "assign-host-dialog",
+ dialogType: "tool",
+ onClose: () => this.setState({
+ dialog: false
+ }, () => this.safeForceUpdate())
+ }), JSX_("header", null, JSX_("h2", null, l.assign_host_title)), JSX_("div", {
+ className: "content-block"
+ }, JSX_(_contacts_jsx4__ .hU, {
+ className: "popup contacts-search small-footer",
+ contacts: (_this$props$participa = this.props.participants) == null ? void 0 : _this$props$participa.filter(h => h !== u_handle),
+ multiple: true,
+ hideSearch: true,
+ disableFrequents: true,
+ participantsList: true,
+ disableDoubleClick: true,
+ emailTooltips: true,
+ nothingSelectedButtonLabel: l.add_hosts_placeholder,
+ onClose: () => this.setState({
+ dialog: false
+ }),
+ onSelected: selected => this.setState({
+ selected
+ }, () => this.safeForceUpdate())
+ })), JSX_("footer", null, JSX_("div", {
+ className: "footer-container"
+ }, JSX_(_ui_buttons_jsx5__ .$, {
+ label: l.msg_dlg_cancel,
+ className: "mega-button",
+ onClick: this.toggleDialog
+ }), JSX_(_ui_buttons_jsx5__ .$, {
+ label: l.assign_and_leave,
+ className: `
+ mega-button
+ positive
+ ${selected.length ? '' : 'disabled'}
+ `,
+ onClick: () => selected.length && this.assignAndLeave()
+ }))));
+ };
+ this.assignAndLeave = () => {
+ const {
+ chatRoom,
+ onLeave
+ } = this.props;
+ const {
+ selected
+ } = this.state;
+ for (let i = selected.length; i--;) {
+ chatRoom.trigger('alterUserPrivilege', [selected[i], ChatRoom.MembersSet.PRIVILEGE_STATE.OPERATOR]);
+ }
+ this.toggleDialog();
+ onLeave == null || onLeave();
+ $(document).trigger('closeDropdowns');
+ };
+ this.confirmLeave = ({
+ title,
+ body,
+ cta,
+ altCta
+ }) => {
+ msgDialog(`confirmationa:!^${cta}!${altCta || l.msg_dlg_cancel}`, null, title, body, cb => {
+ if (cb) {
+ this.toggleDialog();
+ } else if (cb === false) {
+ let _this$props$onConfirm, _this$props;
+ (_this$props$onConfirm = (_this$props = this.props).onConfirmDenied) == null || _this$props$onConfirm.call(_this$props);
+ }
+ }, 1);
+ };
+ }
+ render() {
+ return JSX_(react1___default().Fragment, null, JSX_(Component, (0,_babel_runtime_helpers_extends0__ .A)({}, this.props, {
+ confirmLeave: this.confirmLeave,
+ hasHost: this.hasHost
+ })), this.state.dialog && this.renderDialog());
+ }
+ };
+};
+
+ },
+
+ 2153
+(_, EXP_, REQ_) {
+
+ REQ_.d(EXP_, {
+ j: () => JOIN_VIEW
+ });
+const JOIN_VIEW = {
+ INITIAL: 0,
+ GUEST: 1,
+ ACCOUNT: 2,
+ UNSUPPORTED: 4
+};
+
+ },
+
+ 8025
+(_, EXP_, REQ_) {
+
+
+// EXPORTS
+REQ_.d(EXP_, {
+ A: () => GenericConversationMessage
+});
+
+// EXTERNAL MODULE: ./node_modules/@babel/runtime/helpers/esm/extends.js
+const esm_extends = REQ_(8168);
+// EXTERNAL MODULE: external "React"
+const external_React_ = REQ_(1594);
+const REaCt = REQ_.n(external_React_);
+// EXTERNAL MODULE: ./js/chat/ui/messages/mixin.jsx
+const mixin = REQ_(855);
+// EXTERNAL MODULE: ./js/chat/ui/contacts.jsx
+const ui_contacts = REQ_(8022);
+// EXTERNAL MODULE: ./js/ui/utils.jsx
+const utils = REQ_(6411);
+;// ./js/chat/ui/messages/abstractGenericMessage.jsx
+
+
+
+
+class AbstractGenericMessage extends mixin.M {
+ constructor(...args) {
+ super(...args);
+ this.domRef = REaCt().createRef();
+ }
+ getAvatar() {
+ const contact = this.getContact() || Message.getContactForMessage(this.props.message);
+ if (this.props.grouped) {
+ return null;
+ }
+ return contact ? JSX_(ui_contacts.eu, {
+ contact: this.getContact(),
+ className: "message avatar-wrapper small-rounded-avatar",
+ chatRoom: this.props.chatRoom
+ }) : null;
+ }
+ getName() {
+ const contact = this.getContact() || Message.getContactForMessage(this.props.message);
+ if (this.props.grouped) {
+ return null;
+ }
+ return contact ? JSX_(ui_contacts.bq, {
+ contact,
+ className: "message",
+ label: JSX_(utils.zT, null, M.getNameByHandle(contact.u)),
+ chatRoom: this.props.message.chatRoom,
+ dropdownDisabled: !!this.props.dialog
+ }) : null;
+ }
+ renderMessageActionButtons(buttons) {
+ if (!buttons) {
+ return null;
+ }
+ const cnt = buttons.length;
+ if (cnt === 0) {
+ return null;
+ }
+ return JSX_("div", {
+ className: `right-aligned-msg-buttons ${cnt && cnt > 1 ? `total-${cnt}` : ''}`
+ }, buttons);
+ }
+ render() {
+ const {
+ message,
+ grouped,
+ additionalClasses,
+ hideActionButtons
+ } = this.props;
+ if (message.deleted) {
+ return null;
+ }
+ return JSX_("div", {
+ ref: this.domRef,
+ "data-id": message.messageId,
+ className: `
+ ${this.getClassNames ? this.getClassNames() : grouped ? 'grouped' : ''}
+ ${additionalClasses}
+ ${message.messageId}
+ message
+ body
+ `
+ }, this.getAvatar && this.getAvatar(), JSX_("div", {
+ className: "message content-area selectable-txt"
+ }, this.getName && this.getName(), this.getMessageTimestamp ? this.getMessageTimestamp() : grouped ? null : JSX_("div", {
+ className: "message date-time simpletip",
+ "data-simpletip": time2date(this.getTimestamp(), 17),
+ "data-simpletipposition": "top",
+ "data-simpletipoffset": "4"
+ }, this.getTimestampAsString()), !hideActionButtons && this.getMessageActionButtons && this.renderMessageActionButtons(this.getMessageActionButtons()), this.getContents && this.getContents(), hideActionButtons ? null : this.getEmojisImages()));
+ }
+}
+// EXTERNAL MODULE: ./js/chat/ui/messages/utils.jsx
+const messages_utils = REQ_(187);
+;// ./js/chat/ui/messages/types/local.jsx
+
+
+
+
+
+const MESSAGE_TYPE = {
+ OUTGOING: 'outgoing-call',
+ INCOMING: 'incoming-call',
+ TIMEOUT: 'call-timeout',
+ STARTING: 'call-starting',
+ FEEDBACK: 'call-feedback',
+ INITIALISING: 'call-initialising',
+ ENDED: 'call-ended',
+ ENDED_REMOTE: 'remoteCallEnded',
+ FAILED: 'call-failed',
+ FAILED_MEDIA: 'call-failed-media',
+ HANDLED_ELSEWHERE: 'call-handled-elsewhere',
+ MISSED: 'call-missed',
+ REJECTED: 'call-rejected',
+ CANCELLED: 'call-canceled',
+ STARTED: 'call-started',
+ STARTED_REMOTE: 'remoteCallStarted',
+ ALTER_PARTICIPANTS: 'alterParticipants',
+ PRIVILEGE_CHANGE: 'privilegeChange',
+ TRUNCATED: 'truncated'
+};
+class Local extends AbstractGenericMessage {
+ componentDidMount() {
+ super.componentDidMount();
+ this._setClassNames();
+ }
+ _roomIsGroup() {
+ return this.props.message.chatRoom.type === 'group' || this.props.message.chatRoom.type === 'public';
+ }
+ _getParticipantNames(message) {
+ return message.meta && message.meta.participants && !!message.meta.participants.length && message.meta.participants.map(handle => `[[${megaChat.html(M.getNameByHandle(handle))}]]`);
+ }
+ _getExtraInfo(message) {
+ const {
+ meta,
+ type
+ } = message;
+ const participantNames = this._getParticipantNames(message);
+ const HAS_PARTICIPANTS = participantNames && !!participantNames.length && participantNames.length > 1;
+ const HAS_DURATION = meta && meta.duration;
+ const ENDED = type === MESSAGE_TYPE.ENDED || type === MESSAGE_TYPE.FAILED || type === MESSAGE_TYPE.CANCELLED;
+ let messageExtraInfo = [HAS_PARTICIPANTS ? mega.utils.trans.listToString(participantNames, l[20234]) : ''];
+ if (ENDED) {
+ messageExtraInfo = [...messageExtraInfo, HAS_PARTICIPANTS ? '. ' : '', HAS_DURATION ? l[7208].replace('[X]', `[[${secToDuration(meta.duration)}]]`) : ''];
+ }
+ return messageExtraInfo && messageExtraInfo.reduce((acc, cur) => (acc + cur).replace(/\[\[/g, '').replace(/]]/g, ''));
+ }
+ _setClassNames() {
+ let cssClass;
+ switch (this.props.message.type) {
+ case MESSAGE_TYPE.REJECTED:
+ cssClass = 'sprite-fm-theme icon-handset-rejected';
+ break;
+ case MESSAGE_TYPE.MISSED:
+ cssClass = 'sprite-fm-theme icon-handset-missed';
+ break;
+ case MESSAGE_TYPE.OUTGOING:
+ case MESSAGE_TYPE.HANDLED_ELSEWHERE:
+ cssClass = 'sprite-fm-theme icon-handset-outgoing';
+ break;
+ case MESSAGE_TYPE.FAILED:
+ case MESSAGE_TYPE.FAILED_MEDIA:
+ cssClass = 'sprite-fm-theme icon-handset-failed';
+ break;
+ case MESSAGE_TYPE.ENDED:
+ case MESSAGE_TYPE.TIMEOUT:
+ cssClass = 'sprite-fm-theme icon-handset-ended';
+ break;
+ case MESSAGE_TYPE.CANCELLED:
+ cssClass = 'sprite-fm-theme icon-handset-cancelled';
+ break;
+ case MESSAGE_TYPE.FEEDBACK:
+ case MESSAGE_TYPE.STARTING:
+ case MESSAGE_TYPE.STARTED:
+ cssClass = 'sprite-fm-mono icon-phone';
+ break;
+ case MESSAGE_TYPE.INCOMING:
+ cssClass = 'sprite-fm-theme icon-handset-incoming';
+ break;
+ default:
+ cssClass = `sprite-fm-mono ${ this.props.message.type}`;
+ break;
+ }
+ this.props.message.cssClass = cssClass;
+ }
+ _getIcon(message) {
+ const MESSAGE_ICONS = {
+ [MESSAGE_TYPE.STARTED]: ` `,
+ [MESSAGE_TYPE.ENDED]: ` `,
+ DEFAULT: ` `
+ };
+ return MESSAGE_ICONS[message.type] || MESSAGE_ICONS.DEFAULT;
+ }
+ _getText() {
+ const {
+ message
+ } = this.props;
+ const IS_GROUP = this._roomIsGroup();
+ let messageText = (0,messages_utils.d)(message.type, IS_GROUP, message.chatRoom.isMeeting);
+ if (!messageText) {
+ return console.error(`Message with type: ${message.type} -- no text string defined. Message: ${message}`);
+ }
+ messageText = CallManager2._getMltiStrTxtCntsForMsg(message, messageText.splice ? messageText : [messageText], true);
+ messageText = megaChat.html(messageText);
+ message.textContents = String(messageText).replace("[[", "").replace("]]", "");
+ if (IS_GROUP) {
+ messageText = `
+ ${this._getIcon(message)}
+
+ ${messageText}
+ ${this._getExtraInfo(message)}
+
+ `;
+ }
+ return messageText;
+ }
+ _getAvatarsListing() {
+ const {
+ message
+ } = this.props;
+ if (this._roomIsGroup() && message.type === MESSAGE_TYPE.STARTED && message.messageId === `${MESSAGE_TYPE.STARTED}-${message.chatRoom.getActiveCallMessageId()}`) {
+ const unique = message.chatRoom.uniqueCallParts ? Object.keys(message.chatRoom.uniqueCallParts) : [];
+ return unique.map(handle => JSX_(ui_contacts.eu, {
+ key: handle,
+ contact: M.u[handle],
+ simpletip: true,
+ className: "message avatar-wrapper small-rounded-avatar"
+ }));
+ }
+ return null;
+ }
+ _getButtons() {
+ const {
+ message
+ } = this.props;
+ if (message.buttons && Object.keys(message.buttons).length) {
+ return JSX_("div", {
+ className: "buttons-block"
+ }, Object.keys(message.buttons).map(key => {
+ const button = message.buttons[key];
+ return JSX_("button", {
+ key,
+ className: button.classes,
+ onClick: e => button.callback(e.target)
+ }, button.icon && JSX_("div", null, JSX_("i", {
+ className: `small-icon ${button.icon}`
+ })), JSX_("span", null, button.text));
+ }), JSX_("div", {
+ className: "clear"
+ }));
+ }
+ }
+ getAvatar() {
+ const {
+ message,
+ grouped
+ } = this.props;
+ if (message.type === MESSAGE_TYPE.FEEDBACK) {
+ return null;
+ }
+ const $$AVATAR = JSX_(ui_contacts.eu, {
+ contact: message.authorContact,
+ className: "message avatar-wrapper small-rounded-avatar",
+ chatRoom: message.chatRoom
+ });
+ const $$ICON = JSX_("div", {
+ className: "feedback call-status-block"
+ }, JSX_("i", {
+ className: `sprite-fm-mono ${message.cssClass}`
+ }));
+ return message.showInitiatorAvatar ? grouped ? null : $$AVATAR : $$ICON
+ ;
+ }
+ getMessageTimestamp() {
+ let _this$props$message;
+ const callId = (_this$props$message = this.props.message) == null || (_this$props$message = _this$props$message.meta) == null ? void 0 : _this$props$message.callId;
+ let debugMsg = "";
+ if (d && callId) {
+ debugMsg = `: callId: ${callId}`;
+ }
+ return JSX_("div", {
+ className: "message date-time simpletip",
+ "data-simpletip": time2date(this.getTimestamp(), 17)
+ }, this.getTimestampAsString(), debugMsg);
+ }
+ getClassNames() {
+ const {
+ message: {
+ showInitiatorAvatar,
+ type
+ },
+ grouped
+ } = this.props;
+ const classNames = [showInitiatorAvatar && grouped && 'grouped', this._roomIsGroup() && type !== MESSAGE_TYPE.OUTGOING && type !== MESSAGE_TYPE.INCOMING && 'with-border'];
+ return classNames.filter(className => className).join(' ');
+ }
+ getName() {
+ const {
+ message,
+ grouped
+ } = this.props;
+ const contact = this.getContact();
+ return message.showInitiatorAvatar && !grouped ? JSX_(ui_contacts.bq, {
+ contact,
+ className: "message",
+ label: JSX_(utils.zT, null, message.authorContact ? M.getNameByHandle(message.authorContact.u) : ''),
+ chatRoom: message.chatRoom
+ }) : M.getNameByHandle(contact.u);
+ }
+ getContents() {
+ const {
+ message: {
+ getState
+ }
+ } = this.props;
+ return JSX_(REaCt().Fragment, null, JSX_("div", {
+ className: "message text-block"
+ }, JSX_("div", {
+ className: "message call-inner-block"
+ }, JSX_("div", {
+ className: "call-info"
+ }, JSX_("div", {
+ className: "call-info-container"
+ }, JSX_(utils.P9, {
+ className: "info-wrapper"
+ }, this._getText())), JSX_("div", {
+ className: "call-info-avatars"
+ }, this._getAvatarsListing(), JSX_("div", {
+ className: "clear"
+ }))))), getState && getState() === Message.STATE.NOT_SENT ? null : this._getButtons());
+ }
+}
+// EXTERNAL MODULE: ./js/ui/dropdowns.jsx
+const dropdowns = REQ_(1510);
+// EXTERNAL MODULE: ./js/ui/buttons.jsx
+const buttons = REQ_(5155);
+;// ./js/chat/ui/messages/types/contact.jsx
+
+
+
+
+
+
+class Contact extends AbstractGenericMessage {
+ constructor(...args) {
+ super(...args);
+ this.DIALOG = {
+ ADDED: addedEmail => msgDialog('info', l[150], l[5898].replace('[X]', addedEmail)),
+ DUPLICATE: () => msgDialog('warningb', '', l[17545])
+ };
+ }
+ haveMoreContactListeners() {
+ const {
+ message
+ } = this.props;
+ const textContents = message.textContents.substring(2, message.textContents.length);
+ const attachmentMeta = JSON.parse(textContents);
+ if (!attachmentMeta) {
+ return false;
+ }
+ const contacts = attachmentMeta.map(v => v.u);
+ return contacts.length ? contacts : false;
+ }
+ _doAddContact(contactEmail) {
+ return M.inviteContact(M.u[u_handle] ? M.u[u_handle].m : u_attr.email, contactEmail);
+ }
+ _handleAddContact(contactEmail) {
+ let _this$props$chatRoom;
+ if ((_this$props$chatRoom = this.props.chatRoom) != null && _this$props$chatRoom.isAnonymous()) {
+ return this._doAddContact(contactEmail).then(addedEmail => this.DIALOG.ADDED(addedEmail)).catch(this.DIALOG.DUPLICATE);
+ }
+ return Object.values(M.opc).some(opc => opc.m === contactEmail) ? this.DIALOG.DUPLICATE() : this._doAddContact(contactEmail).then(addedEmail => this.DIALOG.ADDED(addedEmail))
+ ;
+ }
+ _getContactAvatar(contact, className) {
+ return JSX_(ui_contacts.eu, {
+ className: `avatar-wrapper ${className}`,
+ contact: M.u[contact.u],
+ chatRoom: this.props.chatRoom
+ });
+ }
+ _getContactDeleteButton(message) {
+ if (message.isEditable()) {
+ return JSX_(REaCt().Fragment, null, JSX_("hr", null), JSX_(dropdowns.tJ, {
+ icon: "sprite-fm-mono icon-dialog-close",
+ label: l[83],
+ onClick: e => this.props.onDelete(e, message)
+ }));
+ }
+ }
+ _getContactCard(message, contact, contactEmail) {
+ const HAS_RELATIONSHIP = M.u[contact.u].c === 1;
+ let name = JSX_(ui_contacts.uA, {
+ emoji: true,
+ contact: M.u[contact.u]
+ });
+ const {
+ chatRoom
+ } = this.props;
+ const isAnonView = chatRoom.isAnonymous();
+ if (megaChat.FORCE_EMAIL_LOADING) {
+ name += `(${ contact.m })`;
+ }
+ return JSX_(buttons.$, {
+ ref: ref => {
+ this.buttonRef = ref;
+ },
+ className: "tiny-button",
+ icon: "tiny-icon icons-sprite grey-dots"
+ }, JSX_(dropdowns.ms, {
+ className: "white-context-menu shared-contact-dropdown",
+ noArrow: true,
+ positionMy: "left bottom",
+ positionAt: "right bottom",
+ horizOffset: 4
+ }, JSX_("div", {
+ className: "dropdown-avatar rounded"
+ }, this._getContactAvatar(contact, 'context-avatar'), isAnonView ? JSX_("div", {
+ className: "dropdown-user-name"
+ }) : JSX_("div", {
+ className: "dropdown-user-name"
+ }, JSX_("div", {
+ className: "name"
+ }, HAS_RELATIONSHIP && (this.isLoadingContactInfo() ? JSX_("em", {
+ className: "contact-name-loading"
+ }) : name), !HAS_RELATIONSHIP && name, JSX_(ui_contacts.i1, {
+ className: "small",
+ contact
+ })), JSX_("div", {
+ className: "email"
+ }, M.u[contact.u].m))), JSX_(ui_contacts.BE, {
+ contact: M.u[contact.u]
+ }), HAS_RELATIONSHIP && JSX_(REaCt().Fragment, null, JSX_(dropdowns.tJ, {
+ icon: "sprite-fm-mono icon-user-filled",
+ label: l[5868],
+ onClick: () => {
+ loadSubPage(`fm/chat/contacts/${ contact.u}`);
+ mBroadcaster.sendMessage('contact:open');
+ }
+ }), JSX_("hr", null), JSX_(dropdowns.tJ, {
+ icon: "sprite-fm-mono icon-chat-filled",
+ label: l[8632],
+ onClick: () => {
+ loadSubPage(`fm/chat/p/${ contact.u}`);
+ mBroadcaster.sendMessage('chat:open');
+ }
+ })), u_type && u_type > 2 && contact.u !== u_handle && !HAS_RELATIONSHIP && !is_eplusplus && JSX_(dropdowns.tJ, {
+ icon: "sprite-fm-mono icon-add",
+ label: l[71],
+ onClick: () => this._handleAddContact(contactEmail)
+ }), this._getContactDeleteButton(message)));
+ }
+ getContents() {
+ const {
+ message,
+ chatRoom
+ } = this.props;
+ const textContents = message.textContents.substr(2, message.textContents.length);
+ const attachmentMeta = JSON.parse(textContents);
+ const isAnonView = chatRoom.isAnonymous();
+ if (!attachmentMeta) {
+ return console.error(`Message w/ type: ${message.type} -- no attachment meta defined. Message: ${message}`);
+ }
+ let contacts = [];
+ attachmentMeta.forEach(v => {
+ let _this$buttonRef;
+ const contact = M.u && v.u in M.u && M.u[v.u].m ? M.u[v.u] : v;
+ const contactEmail = contact.email ? contact.email : contact.m;
+ if (!M.u[contact.u]) {
+ M.u.set(contact.u, new MegaDataObject(MEGA_USER_STRUCT, {
+ 'u': contact.u,
+ 'name': contact.name,
+ 'm': contact.email ? contact.email : contactEmail,
+ 'c': undefined
+ }));
+ } else if (M.u[contact.u] && !M.u[contact.u].m) {
+ M.u[contact.u].m = contact.email ? contact.email : contactEmail;
+ }
+ contacts = [...contacts, JSX_("div", {
+ key: contact.u
+ }, isAnonView ? JSX_("div", {
+ className: "message shared-info"
+ }) : JSX_("div", {
+ className: "message shared-info"
+ }, JSX_("div", {
+ className: "message data-title selectable-txt",
+ onClick: (_this$buttonRef = this.buttonRef) == null ? void 0 : _this$buttonRef.onClick
+ }, JSX_(utils.zT, null, M.getNameByHandle(contact.u))), M.u[contact.u] ? JSX_(ui_contacts.n4, {
+ className: "right-align",
+ contact: M.u[contact.u]
+ }) : null, JSX_("div", {
+ className: "user-card-email selectable-txt"
+ }, contactEmail)), JSX_("div", {
+ className: "message shared-data"
+ }, JSX_("div", {
+ className: "data-block-view semi-big"
+ }, M.u[contact.u] ? JSX_(ui_contacts.i1, {
+ className: "small",
+ contact: M.u[contact.u]
+ }) : null, this._getContactCard(message, contact, contactEmail), this._getContactAvatar(contact, 'medium-avatar')), JSX_("div", {
+ className: "clear"
+ })))];
+ });
+ return JSX_("div", {
+ className: "message shared-block"
+ }, contacts);
+ }
+}
+;// ./js/chat/ui/messages/types/attachment.jsx
+
+
+
+
+class Attachment extends AbstractGenericMessage {
+ _isRevoked(node) {
+ return !M.chd[node.ch] || node.revoked;
+ }
+ _isUserRegistered() {
+ return typeof u_type !== 'undefined' && u_type > 2;
+ }
+ getContents() {
+ const {
+ message,
+ chatRoom
+ } = this.props;
+ const contact = this.getContact();
+ const NODE_DOESNT_EXISTS_ANYMORE = {};
+ const attachmentMeta = message.getAttachmentMeta() || [];
+ const files = [];
+ for (let i = 0; i < attachmentMeta.length; i++) {
+ var _this$buttonRef;
+ const v = attachmentMeta[i];
+ if (this._isRevoked(v)) {
+ continue;
+ }
+ const {
+ icon,
+ isImage,
+ isVideo,
+ isAudio,
+ isText,
+ showThumbnail,
+ isPreviewable
+ } = M.getMediaProperties(v);
+ let dropdown = null;
+ let noThumbPrev = '';
+ var previewButton = null;
+ if (isPreviewable) {
+ if (!showThumbnail) {
+ noThumbPrev = 'no-thumb-prev';
+ }
+ let previewLabel = isAudio ? l[17828] : isVideo ? l[16275] : l[1899];
+ let previewIcon = isAudio ? 'icon-play' : isVideo ? 'icon-video-call-filled' : 'icon-preview-reveal';
+ if (isText) {
+ previewLabel = l[16797];
+ previewIcon = "icon-file-edit";
+ }
+ previewButton = JSX_("span", {
+ key: "previewButton"
+ }, JSX_(dropdowns.tJ, {
+ label: previewLabel,
+ icon: `sprite-fm-mono ${previewIcon}`,
+ disabled: mega.paywall,
+ onClick: e => {
+ mega.ui.mInfoPanel.hide();
+ this.props.onPreviewStart(v, e);
+ }
+ }));
+ }
+ dropdown = contact.u === u_handle ? JSX_(buttons.$, {
+ ref: ref => {
+ this.buttonRef = ref;
+ },
+ className: "tiny-button",
+ icon: "tiny-icon icons-sprite grey-dots"
+ }, JSX_(dropdowns.ms, {
+ className: "white-context-menu attachments-dropdown",
+ noArrow: true,
+ positionMy: "left top",
+ positionAt: "left bottom",
+ horizOffset: -4,
+ vertOffset: 3,
+ onBeforeActiveChange: newState => {
+ if (newState === true) {
+ this.forceUpdate();
+ }
+ },
+ dropdownItemGenerator: dd => {
+ const linkButtons = [];
+ const firstGroupOfButtons = [];
+ let revokeButton = null;
+ let downloadButton = null;
+ let addToAlbumButton = null;
+ if (message.isEditable && message.isEditable()) {
+ revokeButton = JSX_(dropdowns.tJ, {
+ icon: "sprite-fm-mono icon-dialog-close",
+ label: l[83],
+ onClick: () => {
+ chatRoom.megaChat.plugins.chatdIntegration.updateMessage(chatRoom, message.internalId || message.orderValue, "");
+ }
+ });
+ }
+ if (!M.d[v.h] && !NODE_DOESNT_EXISTS_ANYMORE[v.h]) {
+ dbfetch.acquire(v.h).always(() => {
+ if (!M.d[v.h]) {
+ NODE_DOESNT_EXISTS_ANYMORE[v.h] = true;
+ dd.doRerender();
+ } else {
+ dd.doRerender();
+ }
+ });
+ return JSX_("span", {
+ className: "loading"
+ }, l[5533]);
+ } else if (!NODE_DOESNT_EXISTS_ANYMORE[v.h]) {
+ downloadButton = JSX_(dropdowns.tJ, {
+ icon: "sprite-fm-mono icon-download-small",
+ label: l[1187],
+ disabled: mega.paywall,
+ onClick: () => this.props.onDownloadStart(v)
+ });
+ if (M.getNodeRoot(v.h) !== M.RubbishID) {
+ this.props.onAddLinkButtons(v.h, linkButtons);
+ }
+ firstGroupOfButtons.push(JSX_(dropdowns.tJ, {
+ icon: "sprite-fm-mono icon-info",
+ label: l[6859],
+ key: "infoDialog",
+ onClick: () => {
+ mega.ui.mInfoPanel.show([v.ch]);
+ }
+ }));
+ this.props.onAddFavouriteButtons(v.h, firstGroupOfButtons);
+ linkButtons.push(JSX_(dropdowns.tJ, {
+ icon: "sprite-fm-mono icon-send-to-chat",
+ label: l[17764],
+ key: "sendToChat",
+ disabled: mega.paywall,
+ onClick: () => {
+ $.selected = [v.h];
+ openSendToChatDialog();
+ }
+ }));
+ if (M.isGalleryNode(v)) {
+ addToAlbumButton = JSX_(dropdowns.tJ, {
+ icon: "sprite-fm-mono rectangle-stack-plus-small-regular-outline",
+ label: l.add_to_album,
+ disabled: mega.paywall,
+ onClick: () => mega.gallery.albums.addToAlbum([v.h])
+ });
+ }
+ }
+ if (!previewButton && firstGroupOfButtons.length === 0 && !downloadButton && !addToAlbumButton && linkButtons.length === 0 && !revokeButton) {
+ return null;
+ }
+ if (previewButton && (firstGroupOfButtons.length > 0 || downloadButton || addToAlbumButton || linkButtons.length > 0 || revokeButton)) {
+ previewButton = [previewButton, JSX_("hr", {
+ key: "preview-sep"
+ })];
+ }
+ return JSX_("div", null, previewButton, firstGroupOfButtons, firstGroupOfButtons && firstGroupOfButtons.length > 0 ? JSX_("hr", null) : "", addToAlbumButton, addToAlbumButton ? JSX_("hr", null) : "", downloadButton, linkButtons, revokeButton && downloadButton ? JSX_("hr", null) : "", revokeButton);
+ }
+ })) : JSX_(buttons.$, {
+ ref: ref => {
+ this.buttonRef = ref;
+ },
+ className: "tiny-button",
+ icon: "tiny-icon icons-sprite grey-dots"
+ }, JSX_(dropdowns.ms, {
+ className: "white-context-menu attachments-dropdown",
+ noArrow: true,
+ positionMy: "left top",
+ positionAt: "left bottom",
+ horizOffset: -4,
+ vertOffset: 3
+ }, previewButton, previewButton && JSX_("hr", null), JSX_(dropdowns.tJ, {
+ icon: "sprite-fm-mono icon-download-small",
+ label: l[1187],
+ disabled: mega.paywall,
+ onClick: () => this.props.onDownloadStart(v)
+ }), !is_chatlink && this._isUserRegistered() && JSX_(REaCt().Fragment, null, JSX_(dropdowns.tJ, {
+ icon: "sprite-fm-mono icon-cloud",
+ label: l[1988],
+ disabled: mega.paywall,
+ onClick: () => this.props.onAddToCloudDrive(v, false)
+ }), JSX_(dropdowns.tJ, {
+ icon: "sprite-fm-mono icon-send-to-chat",
+ label: l[17764],
+ disabled: mega.paywall,
+ onClick: () => this.props.onAddToCloudDrive(v, true)
+ }))));
+ if (M.getNodeShare(v.h).down) {
+ dropdown = null;
+ }
+ const attachmentClasses = "message shared-data";
+ let preview = JSX_("div", {
+ className: `data-block-view medium ${ noThumbPrev}`,
+ onClick: ({
+ target
+ }) => {
+ if (isPreviewable && !target.classList.contains('tiny-button')) {
+ mega.ui.mInfoPanel.hide();
+ this.props.onPreviewStart(v);
+ }
+ }
+ }, dropdown, JSX_("div", {
+ className: "data-block-bg"
+ }, JSX_("div", {
+ className: `item-type-icon-90 icon-${ icon }-90`
+ })));
+ if (showThumbnail) {
+ const src = v.src || window.noThumbURI || '';
+ let thumbClass = v.src ? '' : " no-thumb";
+ let thumbOverlay = null;
+ if (isImage) {
+ thumbClass += " image";
+ thumbOverlay = JSX_("div", {
+ className: "thumb-overlay",
+ onClick: () => {
+ mega.ui.mInfoPanel.hide();
+ this.props.onPreviewStart(v);
+ }
+ });
+ } else {
+ thumbClass = `${thumbClass } video ${ isPreviewable ? " previewable" : "non-previewable"}`;
+ thumbOverlay = JSX_("div", {
+ className: "thumb-overlay",
+ onClick: () => {
+ if (isPreviewable) {
+ mega.ui.mInfoPanel.hide();
+ this.props.onPreviewStart(v);
+ }
+ }
+ }, isPreviewable && JSX_("div", {
+ className: "thumb-overlay-play"
+ }, JSX_("div", {
+ className: "thumb-overlay-circle"
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-play"
+ }))), JSX_("div", {
+ className: "video-thumb-details"
+ }, v.playtime && JSX_("i", {
+ className: "sprite-fm-mono icon-play"
+ }), JSX_("span", null, secondsToTimeShort(v.playtime || -1))));
+ }
+ preview = src ? JSX_("div", {
+ id: v.ch,
+ className: `shared-link thumb ${thumbClass}`
+ }, thumbOverlay, dropdown, JSX_("img", {
+ alt: "",
+ className: `thumbnail-placeholder ${ v.h}`,
+ src,
+ key: `thumb-${ v.ch}`,
+ onClick: () => isPreviewable && this.props.onPreviewStart(v)
+ })) : preview;
+ }
+ files.push(JSX_("div", {
+ key: `attachment-${v.ch}`,
+ className: attachmentClasses
+ }, JSX_("div", {
+ className: "message shared-info",
+ onClick: (_this$buttonRef = this.buttonRef) == null ? void 0 : _this$buttonRef.onClick
+ }, JSX_("div", {
+ className: "message data-title selectable-txt"
+ }, l[17669], JSX_("span", {
+ className: "file-name"
+ }, v.name)), JSX_("div", {
+ className: "message file-size"
+ }, bytesToSize(v.s))), preview, JSX_("div", {
+ className: "clear"
+ })));
+ }
+ return JSX_("div", {
+ className: "message shared-block"
+ }, files);
+ }
+}
+// EXTERNAL MODULE: ./js/chat/mixins.js
+const mixins = REQ_(8264);
+;// ./js/chat/ui/messages/types/partials/audioPlayer.jsx
+
+
+class AudioPlayer extends mixins.w9 {
+ constructor(props) {
+ super(props);
+ this.domRef = REaCt().createRef();
+ this.state = {
+ currentTime: null,
+ progressWidth: 0,
+ isBeingPlayed: false,
+ isPaused: false
+ };
+ this.handleOnTimeUpdate = this.handleOnTimeUpdate.bind(this);
+ this.handleOnMouseDown = this.handleOnMouseDown.bind(this);
+ }
+ play() {
+ const audio = this.audioEl;
+ if (audio.paused) {
+ const result = audio.play();
+ if (result instanceof Promise) {
+ result.catch(ex => {
+ if (ex.name !== 'AbortError') {
+ console.error(ex);
+ }
+ });
+ }
+ const audios = document.getElementsByClassName('audio-player__player');
+ Array.prototype.filter.call(audios, audioElement => audioElement.id !== this.props.audioId).forEach(audioElement => {
+ if (!audioElement.paused) {
+ audioElement.pause();
+ }
+ });
+ this.setState({
+ isPaused: false
+ });
+ } else {
+ audio.pause();
+ this.setState({
+ isPaused: true
+ });
+ }
+ }
+ handleOnTimeUpdate() {
+ const {
+ currentTime,
+ duration
+ } = this.audioEl;
+ this.setState({
+ currentTime: secondsToTimeShort(currentTime),
+ progressWidth: currentTime / duration * 100
+ });
+ }
+ handleOnMouseDown(event) {
+ event.preventDefault();
+ const {
+ sliderPin,
+ slider
+ } = this;
+ const shiftX = event.clientX - sliderPin.getBoundingClientRect().left;
+ const onMouseMove = event => {
+ let newLeft = event.clientX - shiftX - slider.getBoundingClientRect().left;
+ if (newLeft < 0) {
+ newLeft = 0;
+ }
+ const rightEdge = slider.offsetWidth - sliderPin.offsetWidth;
+ if (newLeft > rightEdge) {
+ newLeft = rightEdge;
+ }
+ sliderPin.style.left = `${newLeft}px`;
+ const pinPosition = newLeft / slider.getBoundingClientRect().width;
+ const newTime = Math.ceil(this.props.playtime * pinPosition);
+ const newCurrentTime = secondsToTimeShort(newTime);
+ this.audioEl.currentTime = newTime;
+ this.setState({
+ currentTime: newCurrentTime,
+ progressWidth: pinPosition > 1 ? 100 : pinPosition * 100
+ });
+ };
+ function onMouseUp() {
+ document.removeEventListener('mouseup', onMouseUp);
+ document.removeEventListener('mousemove', onMouseMove);
+ }
+ document.addEventListener('mousemove', onMouseMove);
+ document.addEventListener('mouseup', onMouseUp);
+ sliderPin.ondragstart = () => false;
+ }
+ render() {
+ const {
+ source,
+ audioId,
+ loading,
+ playtime
+ } = this.props;
+ const {
+ progressWidth,
+ isBeingPlayed,
+ isPaused,
+ currentTime
+ } = this.state;
+ let playtimeStyles = null;
+ if (isBeingPlayed) {
+ playtimeStyles = {
+ color: 'var(--secondary-red)'
+ };
+ }
+ let btnClass = 'icon-pause';
+ if (!isBeingPlayed || isPaused) {
+ btnClass = 'icon-play';
+ }
+ let controls = JSX_("span", {
+ onClick: () => {
+ this.play();
+ if (this.props.source === null) {
+ this.props.getAudioFile();
+ }
+ }
+ }, JSX_("i", {
+ className: `sprite-fm-mono ${btnClass}`
+ }));
+ if (loading) {
+ controls = JSX_("div", {
+ className: "small-blue-spinner audio-player__spinner"
+ });
+ }
+ return JSX_("div", {
+ ref: this.domRef,
+ className: "audio-player"
+ }, controls, JSX_("div", {
+ className: "slider",
+ ref: slider => {
+ this.slider = slider;
+ }
+ }, JSX_("div", {
+ className: "slider__progress",
+ style: {
+ width: `${progressWidth}%`
+ }
+ }), JSX_("div", {
+ className: "slider__progress__pin",
+ style: {
+ left: `${progressWidth}%`
+ },
+ ref: sliderPin => {
+ this.sliderPin = sliderPin;
+ },
+ onMouseDown: this.handleOnMouseDown
+ })), JSX_("span", {
+ className: "audio-player__time",
+ style: playtimeStyles
+ }, currentTime || secondsToTimeShort(playtime)), JSX_("audio", {
+ src: source,
+ className: "audio-player__player",
+ id: audioId,
+ ref: audio => {
+ this.audioEl = audio;
+ },
+ onPlaying: () => this.setState({
+ isBeingPlayed: true
+ }),
+ onPause: () => this.setState({
+ isPaused: true
+ }),
+ onEnded: () => this.setState({
+ progressWidth: 0,
+ isBeingPlayed: false,
+ currentTime: 0
+ }),
+ onTimeUpdate: this.handleOnTimeUpdate
+ }));
+ }
+}
+;// ./js/chat/ui/messages/types/partials/audioContainer.jsx
+
+
+class AudioContainer extends REaCt().Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ audioBlobUrl: null,
+ loading: false
+ };
+ this.getAudioFile = this.getAudioFile.bind(this);
+ }
+ getAudioFile() {
+ const {
+ mime,
+ h
+ } = this.props;
+ this.setState({
+ loading: true
+ });
+ if (mime !== 'audio/mp4') {
+ if (d) {
+ console.warn('cannot play this file type (%s)', mime, h, [this]);
+ }
+ return false;
+ }
+ M.gfsfetch(h, 0, -1).then(({
+ buffer
+ }) => {
+ this.setState(() => {
+ return {
+ audioBlobUrl: mObjectURL([buffer], 'audio/mp4'),
+ loading: false
+ };
+ });
+ }).catch(ex => {
+ console.error(ex);
+ });
+ return true;
+ }
+ componentWillUnmount() {
+ URL.revokeObjectURL(this.state.audioBlobUrl);
+ }
+ render() {
+ const {
+ audioBlobUrl,
+ loading
+ } = this.state;
+ const {
+ playtime,
+ mime,
+ audioId
+ } = this.props;
+ return JSX_("div", {
+ className: "audio-container"
+ }, JSX_(AudioPlayer, {
+ source: audioBlobUrl,
+ audioId,
+ loading,
+ mime,
+ getAudioFile: this.getAudioFile,
+ playtime
+ }));
+ }
+}
+AudioContainer.defaultProps = {
+ h: null,
+ mime: null
+};
+;// ./js/chat/ui/messages/types/voiceClip.jsx
+
+
+
+
+
+class VoiceClip extends AbstractGenericMessage {
+ _getActionButtons() {
+ const {
+ isBeingEdited,
+ chatRoom,
+ message,
+ dialog,
+ onDelete
+ } = this.props;
+ if (message.isEditable() && !isBeingEdited() && !chatRoom.isReadOnly() && !dialog) {
+ return JSX_(buttons.$, {
+ className: "tiny-button",
+ icon: "tiny-icon icons-sprite grey-dots"
+ }, JSX_(dropdowns.ms, {
+ className: "white-context-menu attachments-dropdown",
+ noArrow: true,
+ positionMy: "left bottom",
+ positionAt: "right bottom",
+ horizOffset: 4
+ }, JSX_(dropdowns.tJ, {
+ icon: "sprite-fm-mono icon-dialog-close",
+ label: l[1730],
+ onClick: ev => onDelete(ev, message)
+ })));
+ }
+ return null;
+ }
+ _getAudioContainer() {
+ const {
+ message
+ } = this.props;
+ const attachmentMeta = message.getAttachmentMeta();
+ if (attachmentMeta && attachmentMeta.length) {
+ return attachmentMeta.map(voiceClip => JSX_(AudioContainer, {
+ key: voiceClip.h,
+ h: voiceClip.h,
+ mime: voiceClip.mime,
+ playtime: voiceClip.playtime,
+ audioId: `vm${message.messageId}`
+ }));
+ }
+ }
+ getContents() {
+ return JSX_(REaCt().Fragment, null, this.props.message.getState() === Message.STATE.NOT_SENT ? null : this._getActionButtons(), this._getAudioContainer());
+ }
+}
+;// ./js/chat/ui/messages/types/partials/metaRichpreviewLoading.jsx
+
+
+class MetaRichpreviewLoading extends mixin.M {
+ render() {
+ return JSX_("div", {
+ className: "loading-spinner light small"
+ }, JSX_("div", {
+ className: "main-loader"
+ }));
+ }
+}
+
+;// ./js/chat/ui/messages/types/partials/metaRichpreview.jsx
+
+
+
+class MetaRichpreview extends mixin.M {
+ getBase64Url(b64incoming) {
+ if (!b64incoming || !b64incoming.split) {
+ return;
+ }
+ let exti = b64incoming.split(":");
+ const b64i = exti[1];
+ exti = exti[0];
+ return `data:image/${ exti };base64,${ b64i}`;
+ }
+ render() {
+ const self = this;
+ const {message} = this.props;
+ const output = [];
+ const metas = message.meta && message.meta.extra ? message.meta.extra : [];
+ const failedToLoad = message.meta.isLoading && unixtime() - message.meta.isLoading > 300;
+ const isLoading = !!message.meta.isLoading;
+ if (failedToLoad) {
+ return null;
+ }
+ for (let i = 0; i < metas.length; i++) {
+ const meta = metas[i];
+ if (!meta.d && !meta.t && !message.meta.isLoading) {
+ continue;
+ }
+ const previewCss = {};
+ if (meta.i) {
+ previewCss.backgroundImage = `url(${ self.getBase64Url(meta.i) })`;
+ previewCss.backgroundRepeat = "no-repeat";
+ previewCss.backgroundPosition = "center center";
+ }
+ var previewContainer;
+ if (isLoading) {
+ previewContainer = JSX_(MetaRichpreviewLoading, {
+ message,
+ isLoading: message.meta.isLoading
+ });
+ } else {
+ let domainName = meta.url;
+ domainName = domainName.replace("https://", "").replace("http://", "").split("/")[0];
+ previewContainer = JSX_("div", {
+ className: "message richpreview body"
+ }, meta.i ? JSX_("div", {
+ className: "message richpreview img-wrapper"
+ }, JSX_("div", {
+ className: "message richpreview preview",
+ style: previewCss
+ })) : undefined, JSX_("div", {
+ className: "message richpreview inner-wrapper"
+ }, JSX_("div", {
+ className: "message richpreview data-title selectable-txt"
+ }, JSX_("span", {
+ className: "message richpreview title"
+ }, meta.t)), JSX_("div", {
+ className: "message richpreview desc"
+ }, ellipsis(meta.d, 'end', 82)), JSX_("div", {
+ className: "message richpreview url-container"
+ }, meta.ic ? JSX_("span", {
+ className: "message richpreview url-favicon"
+ }, JSX_("img", {
+ src: self.getBase64Url(meta.ic),
+ width: 16,
+ height: 16,
+ onError: e => {
+ e.target.parentNode.removeChild(e.target);
+ },
+ alt: ""
+ })) : "", JSX_("span", {
+ className: "message richpreview url"
+ }, domainName))));
+ }
+ output.push(JSX_("div", {
+ key: meta.url,
+ className: `message richpreview container ${ meta.i ? "have-preview" : "no-preview" } ${ meta.d ? "have-description" : "no-description" } ${ isLoading ? "is-loading" : "done-loading"}`,
+ onClick: function (url) {
+ if (!message.meta.isLoading) {
+ window.open(url, "_blank", 'noopener,noreferrer');
+ }
+ }.bind(this, meta.url)
+ }, previewContainer, JSX_("div", {
+ className: "clear"
+ })));
+ }
+ return JSX_("div", {
+ className: "message richpreview previews-container"
+ }, output);
+ }
+}
+
+;// ./js/chat/ui/messages/types/partials/metaRichpreviewConfirmation.jsx
+
+
+class MetaRichprevConfirmation extends mixin.M {
+ doAllow() {
+ const {message} = this.props;
+ const {megaChat} = this.props.message.chatRoom;
+ delete message.meta.requiresConfirmation;
+ RichpreviewsFilter.confirmationDoConfirm();
+ megaChat.plugins.richpreviewsFilter.processMessage({}, message);
+ message.trackDataChange();
+ }
+ doNotNow() {
+ const {message} = this.props;
+ delete message.meta.requiresConfirmation;
+ RichpreviewsFilter.confirmationDoNotNow();
+ message.trackDataChange();
+ }
+ doNever() {
+ const {message} = this.props;
+ msgDialog('confirmation', l[870], l[18687], '', (e) => {
+ if (e) {
+ delete message.meta.requiresConfirmation;
+ RichpreviewsFilter.confirmationDoNever();
+ message.trackDataChange();
+ }
+ });
+ }
+ render() {
+ const self = this;
+ let notNowButton = null;
+ let neverButton = null;
+ if (RichpreviewsFilter.confirmationCount >= 2) {
+ neverButton = JSX_("button", {
+ className: "mega-button right negative",
+ onClick () {
+ self.doNever();
+ }
+ }, JSX_("span", null, l[1051]));
+ }
+ notNowButton = JSX_("button", {
+ className: "mega-button right",
+ onClick () {
+ self.doNotNow();
+ }
+ }, JSX_("span", null, l[18682]));
+ return JSX_("div", {
+ className: "message richpreview previews-container"
+ }, JSX_("div", {
+ className: "message richpreview container confirmation"
+ }, JSX_("div", {
+ className: "message richpreview body"
+ }, JSX_("div", {
+ className: "message richpreview img-wrapper"
+ }, JSX_("div", {
+ className: " message richpreview preview-confirmation sprite-fm-illustration img-chat-url-preview "
+ })), JSX_("div", {
+ className: "message richpreview inner-wrapper"
+ }, JSX_("div", {
+ className: "message richpreview data-title selectable-txt"
+ }, JSX_("span", {
+ className: "message richpreview title"
+ }, l[18679])), JSX_("div", {
+ className: "message richpreview desc"
+ }, l[18680])), JSX_("div", {
+ className: "buttons-block"
+ }, JSX_("button", {
+ className: "mega-button right positive",
+ onClick: () => {
+ self.doAllow();
+ }
+ }, JSX_("span", null, l[18681])), notNowButton, neverButton)), JSX_("div", {
+ className: "clear"
+ })));
+ }
+}
+
+;// ./js/chat/ui/messages/types/partials/geoLocation.jsx
+
+function GeoLocation(props) {
+ const {
+ latitude,
+ lng
+ } = props;
+ const handleOnclick = (lat, lng) => {
+ const openGmaps = () => {
+ window.open(`https://www.google.com/maps/search/?api=1&query=${lat},${lng}`, '_blank', 'noopener,noreferrer');
+ };
+ if (GeoLocationLinks.gmapsConfirmation === -1 || GeoLocationLinks.gmapsConfirmation === false) {
+ msgDialog('confirmation', 'geolocation-link', l[20788], l.confirm_ext_link, answer => {
+ if (answer) {
+ GeoLocationLinks.confirmationDoConfirm();
+ closeDialog();
+ openGmaps();
+ } else {
+ GeoLocationLinks.confirmationDoNever();
+ }
+ });
+ } else if (GeoLocationLinks.gmapsConfirmation) {
+ openGmaps();
+ }
+ };
+ return JSX_("div", {
+ className: "geolocation-container"
+ }, JSX_("div", {
+ className: "geolocation",
+ onClick: () => handleOnclick(latitude, lng)
+ }, JSX_("div", {
+ className: "geolocation__details"
+ }, JSX_("div", {
+ className: "geolocation__icon"
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-location"
+ })), JSX_("ul", {
+ className: "geolocation__data-list"
+ }, JSX_("li", null, JSX_("span", {
+ className: "geolocation__title"
+ }, l[20789])), JSX_("li", null, JSX_("p", null, JSX_("span", {
+ className: "geolocation__coordinates-icon"
+ }), JSX_("span", {
+ className: "geolocation__coordinates"
+ }, "https://maps.google.com")))))));
+}
+ const geoLocation = GeoLocation;
+;// ./js/chat/ui/messages/types/partials/metaRichpreviewMegaLinks.jsx
+
+
+
+
+
+class MetaRichpreviewMegaLinks extends mixin.M {
+ render() {
+ const {message} = this.props;
+ const {chatRoom} = this.props.message;
+ let previewContainer;
+ const output = [];
+ const megaLinks = message.megaLinks ? message.megaLinks : [];
+ for (let i = 0; i < megaLinks.length; i++) {
+ const megaLinkInfo = megaLinks[i];
+ if (megaLinkInfo.failed) {
+ continue;
+ }
+ if (megaLinkInfo.hadLoaded() === false) {
+ if (megaLinkInfo.startedLoading() === false) {
+ megaLinkInfo.getInfo().then(() => {
+ const {
+ megaLinks
+ } = this.props.message;
+ const contactLinkHandles = megaLinks.filter(link => link.is_contactlink).map(link => link.info.h);
+ if (contactLinkHandles.length) {
+ this.addContactListenerIfMissing(contactLinkHandles);
+ }
+ }).catch(reportError).finally(() => {
+ message.trackDataChange();
+ onIdle(() => {
+ this.safeForceUpdate();
+ });
+ });
+ }
+ previewContainer = JSX_(MetaRichpreviewLoading, {
+ message,
+ isLoading: megaLinkInfo.hadLoaded()
+ });
+ } else if (megaLinkInfo.is_contactlink) {
+ const fakeContact = M.u[megaLinkInfo.info.h] ? M.u[megaLinkInfo.info.h] : {
+ 'u': megaLinkInfo.info.h,
+ 'm': megaLinkInfo.info.e,
+ 'firstName': megaLinkInfo.info.fn,
+ 'lastName': megaLinkInfo.info.ln,
+ 'name': `${megaLinkInfo.info.fn } ${ megaLinkInfo.info.ln}`
+ };
+ if (!M.u[fakeContact.u]) {
+ M.u.set(fakeContact.u, new MegaDataObject(MEGA_USER_STRUCT, {
+ 'u': fakeContact.u,
+ 'name': `${fakeContact.firstName } ${ fakeContact.lastName}`,
+ 'm': fakeContact.m ? fakeContact.m : "",
+ 'c': undefined
+ }));
+ }
+ const contact = M.u[megaLinkInfo.info.h];
+ previewContainer = JSX_("div", {
+ key: megaLinkInfo.info.h,
+ className: "message shared-block contact-link"
+ }, JSX_("div", {
+ className: "message shared-info"
+ }, JSX_("div", {
+ className: "message data-title selectable-txt"
+ }, contact.name), JSX_(ui_contacts.n4, {
+ className: "right-align",
+ contact
+ }), JSX_("div", {
+ className: "user-card-email selectable-txt"
+ }, contact.m)), JSX_("div", {
+ className: "message shared-data"
+ }, JSX_("div", {
+ className: "data-block-view semi-big"
+ }, JSX_(ui_contacts.i1, {
+ className: "small",
+ contact
+ }), JSX_(ui_contacts.eu, {
+ className: "avatar-wrapper medium-avatar",
+ contact,
+ chatRoom
+ })), JSX_("div", {
+ className: "clear"
+ })));
+ } else {
+ var desc;
+ const is_icon = megaLinkInfo.is_dir ? true : !(megaLinkInfo.havePreview() && megaLinkInfo.info.preview_url);
+ if (megaLinkInfo.is_chatlink) {
+ desc = l[8876].replace('%1', megaLinkInfo.info.ncm);
+ } else if (!megaLinkInfo.is_dir) {
+ desc = bytesToSize(megaLinkInfo.info.size);
+ } else {
+ const totalNumberOfFiles = megaLinkInfo.info.s[1];
+ const numOfVersionedFiles = megaLinkInfo.info.s[4];
+ const folderCount = megaLinkInfo.info.s[2];
+ const totalFileSize = megaLinkInfo.info.size;
+ const versionsSize = megaLinkInfo.info.s[3];
+ desc = JSX_("span", null, fm_contains(totalNumberOfFiles - numOfVersionedFiles, folderCount - 1), JSX_("br", null), bytesToSize(totalFileSize - versionsSize));
+ }
+ previewContainer = JSX_("div", {
+ className: `message richpreview body ${ is_icon ? "have-icon" : "no-icon" } ${ megaLinkInfo.is_chatlink ? "is-chat" : ""}`
+ }, megaLinkInfo.havePreview() && megaLinkInfo.info.preview_url ? JSX_("div", {
+ className: "message richpreview img-wrapper"
+ }, JSX_("div", {
+ className: "message richpreview preview",
+ style: {
+ "backgroundImage": `url(${ megaLinkInfo.info.preview_url })`
+ }
+ })) : JSX_("div", {
+ className: "message richpreview img-wrapper"
+ }, megaLinkInfo.is_chatlink ? JSX_("i", {
+ className: "huge-icon conversations"
+ }) : JSX_("div", {
+ className: `message richpreview icon item-type-icon-90 icon-${ megaLinkInfo.is_dir ? "folder" : fileIcon(megaLinkInfo.info) }-90`
+ })), JSX_("div", {
+ className: "message richpreview inner-wrapper"
+ }, JSX_("div", {
+ className: "message richpreview data-title selectable-txt"
+ }, JSX_("span", {
+ className: "message richpreview title"
+ }, JSX_(utils.zT, null, megaLinkInfo.info.name || megaLinkInfo.info.topic || ""))), JSX_("div", {
+ className: "message richpreview desc"
+ }, desc), JSX_("div", {
+ className: "message richpreview url-container"
+ }, JSX_("span", {
+ className: "message richpreview url-favicon"
+ }, JSX_("img", {
+ src: `https://mega.${mega.tld}/favicon.ico?v=3&c=1`,
+ width: 16,
+ height: 16,
+ onError: e => {
+ if (e && e.target && e.target.parentNode) {
+ e.target.parentNode.removeChild(e.target);
+ }
+ },
+ alt: ""
+ })), JSX_("span", {
+ className: "message richpreview url"
+ }, ellipsis(megaLinkInfo.getLink(), 'end', 40)))));
+ }
+ output.push(JSX_("div", {
+ key: `${megaLinkInfo.node_key }_${ output.length}`,
+ className: `message richpreview container ${ megaLinkInfo.havePreview() ? "have-preview" : "no-preview" } ${ megaLinkInfo.d ? "have-description" : "no-description" } ${ !megaLinkInfo.hadLoaded() ? "is-loading" : "done-loading"}`,
+ onClick: function (url, megaLinkInfo) {
+ if (megaLinkInfo.hadLoaded()) {
+ if (window.sfuClient && megaLinkInfo.is_chatlink) {
+ const {
+ chatRoom: callRoom
+ } = megaChat.activeCall;
+ const peers = callRoom ? callRoom.getParticipantsExceptMe(callRoom.getCallParticipants()).map(h => M.getNameByHandle(h)) : [];
+ const body = peers.length ? mega.utils.trans.listToString(peers, l.cancel_with_to_join) : l.cancel_to_join;
+ return msgDialog('confirmation', undefined, l.call_in_progress, body, e => e && window.open(url, '_blank', 'noopener,noreferrer'));
+ }
+ window.open(url, '_blank', 'noopener,noreferrer');
+ }
+ }.bind(this, megaLinkInfo.getLink(), megaLinkInfo)
+ }, previewContainer, JSX_("div", {
+ className: "clear"
+ })));
+ }
+ return JSX_("div", {
+ className: "message richpreview previews-container"
+ }, output);
+ }
+}
+
+// EXTERNAL MODULE: ./js/chat/ui/typingArea.jsx + 5 modules
+const typingArea = REQ_(4762);
+// EXTERNAL MODULE: ./js/ui/perfectScrollbar.jsx
+const perfectScrollbar = REQ_(1301);
+;// ./js/chat/ui/messages/types/text.jsx
+
+
+
+
+
+
+
+
+
+
+
+
+class Text extends AbstractGenericMessage {
+ constructor(props) {
+ super(props);
+ this.state = {
+ editText: ''
+ };
+ }
+ isRichPreview(message) {
+ return message.metaType === Message.MESSAGE_META_TYPE.RICH_PREVIEW;
+ }
+ isGeoLocation(message) {
+ return message.metaType === Message.MESSAGE_META_TYPE.GEOLOCATION;
+ }
+ getClassNames() {
+ const {
+ message,
+ isBeingEdited,
+ grouped
+ } = this.props;
+ const REQUIRES_CONFIRMATION = this.isRichPreview(message) && message.meta.requiresConfirmation && !isBeingEdited() && (message.source === Message.SOURCE.SENT || message.confirmed === true);
+ return `
+ ${REQUIRES_CONFIRMATION ? 'preview-requires-confirmation-container' : ''}
+ ${grouped ? 'grouped' : ''}
+ `;
+ }
+ renderMessageIndicators() {
+ const {
+ message,
+ spinnerElement,
+ isBeingEdited,
+ onRetry,
+ onCancelRetry
+ } = this.props;
+ if (!message || spinnerElement || isBeingEdited()) {
+ return null;
+ }
+ const state = message.getState == null ? void 0 : message.getState();
+ if (![Message.STATE.NOT_SENT, Message.STATE.NOT_SENT_EXPIRED].includes(state)) {
+ return null;
+ }
+ const props = {
+ 'data-simpletipposition': 'top',
+ 'data-simpletipoffset': 8
+ };
+ return message.requiresManualRetry ? JSX_("div", {
+ className: "not-sent-indicator clickable"
+ }, JSX_("span", (0,esm_extends.A)({
+ className: "simpletip"
+ }, props, {
+ "data-simpletip": l[8883],
+ onClick: ev => onRetry(ev, message)
+ }), JSX_("i", {
+ className: "small-icon refresh-circle"
+ })), JSX_("span", (0,esm_extends.A)({
+ className: "simpletip"
+ }, props, {
+ "data-simpletip": l[8884],
+ onClick: ev => onCancelRetry(ev, message)
+ }), JSX_("i", {
+ className: "sprite-fm-mono icon-dialog-close"
+ }))) : JSX_("div", (0,esm_extends.A)({
+ className: "not-sent-indicator simpletip"
+ }, props, {
+ "data-simpletip": l[8882]
+ }), JSX_("i", {
+ className: "small-icon yellow-triangle"
+ }));
+ }
+ getMessageActionButtons() {
+ const {
+ chatRoom,
+ message,
+ isBeingEdited
+ } = this.props;
+ if (isBeingEdited()) {
+ return [];
+ }
+ let extraPreButtons = [];
+ let messageActionButtons = null;
+ const IS_GEOLOCATION = this.isGeoLocation(message);
+ if (!message.deleted && this.isRichPreview(message)) {
+ if (!message.meta.requiresConfirmation) {
+ if (message.isEditable()) {
+ if (message.meta.isLoading) {
+ extraPreButtons = [...extraPreButtons, JSX_(dropdowns.tJ, {
+ icon: "sprite-fm-mono icon-eye-hidden",
+ key: "stop-link-preview",
+ label: l[18684],
+ className: "",
+ onClick: e => {
+ e.stopPropagation();
+ e.preventDefault();
+ chatRoom.megaChat.plugins.richpreviewsFilter.cancelLoading(chatRoom, message);
+ }
+ })];
+ } else {
+ extraPreButtons = [...extraPreButtons, JSX_(dropdowns.tJ, {
+ key: "remove-link-preview",
+ icon: "sprite-fm-mono icon-eye-hidden",
+ label: l[18684],
+ className: "",
+ onClick: e => {
+ e.stopPropagation();
+ e.preventDefault();
+ chatRoom.megaChat.plugins.richpreviewsFilter.revertToText(chatRoom, message);
+ }
+ })];
+ }
+ }
+ } else if (!isBeingEdited() && !(message.source === Message.SOURCE.SENT || message.confirmed === true)) {
+ extraPreButtons = [...extraPreButtons, JSX_(dropdowns.tJ, {
+ key: "insert-link-preview",
+ icon: "icons-sprite bold-eye",
+ label: l[18683],
+ className: "",
+ onClick: e => {
+ e.stopPropagation();
+ e.preventDefault();
+ chatRoom.megaChat.plugins.richpreviewsFilter.insertPreview(message);
+ }
+ })];
+ }
+ }
+ if (!message.deleted && message.isEditable() && !isBeingEdited() && !chatRoom.isReadOnly() && !message.requiresManualRetry) {
+ const editButton = !IS_GEOLOCATION && JSX_(dropdowns.tJ, {
+ icon: "sprite-fm-mono icon-rename",
+ label: l[1342],
+ onClick: () => this.props.onEditToggle(true)
+ });
+ messageActionButtons = JSX_(buttons.$, {
+ key: "delete-msg",
+ className: "tiny-button",
+ icon: "sprite-fm-mono icon-options"
+ }, JSX_(dropdowns.ms, {
+ className: "white-context-menu attachments-dropdown",
+ noArrow: true,
+ positionMy: "left bottom",
+ positionAt: "right bottom",
+ horizOffset: 4
+ }, extraPreButtons, editButton, editButton ? JSX_("hr", null) : null, JSX_(dropdowns.tJ, {
+ icon: "sprite-fm-mono icon-dialog-close",
+ label: l[1730],
+ onClick: e => this.props.onDelete(e, message)
+ })));
+ }
+ let parentButtons;
+ if (super.getMessageActionButtons) {
+ parentButtons = super.getMessageActionButtons();
+ }
+ const returnedButtons = [];
+ if (messageActionButtons) {
+ returnedButtons.push(messageActionButtons);
+ }
+ if (message.messageHtml && message.messageHtml.includes('') && message.messageHtml.includes('')) {
+ returnedButtons.push(JSX_(buttons.$, {
+ key: "copy-msg",
+ className: "tiny-button simpletip copy-txt-block",
+ icon: "sprite-fm-mono icon-copy",
+ attrs: {
+ 'data-simpletip': l.copy_txt_block_tip,
+ 'data-simpletipoffset': '3',
+ 'data-simpletipposition': 'top'
+ },
+ onClick: () => {
+ copyToClipboard(message.textContents.replace(/```/g, ''), l.copy_txt_block_toast);
+ }
+ }));
+ }
+ if (parentButtons) {
+ returnedButtons.push(parentButtons);
+ }
+ return returnedButtons;
+ }
+ getContents() {
+ const {
+ message,
+ chatRoom,
+ onUpdate,
+ isBeingEdited,
+ spinnerElement
+ } = this.props;
+ let textMessage = message.messageHtml;
+ const IS_GEOLOCATION = this.isGeoLocation(message);
+ const {
+ lng,
+ la: latitude
+ } = IS_GEOLOCATION && message.meta.extra[0];
+ if (message.textContents === '' && !message.dialogType) {
+ message.deleted = true;
+ }
+ let subMessageComponent = [];
+ if (!message.deleted) {
+ if (this.isRichPreview(message)) {
+ if (!message.meta.requiresConfirmation) {
+ subMessageComponent = [...subMessageComponent, JSX_(MetaRichpreview, {
+ key: "richprev",
+ message,
+ chatRoom
+ })];
+ } else if (!isBeingEdited()) {
+ if (message.source === Message.SOURCE.SENT || message.confirmed === true) {
+ subMessageComponent = [...subMessageComponent, JSX_(MetaRichprevConfirmation, {
+ key: "confirm",
+ message,
+ chatRoom
+ })];
+ }
+ }
+ }
+ if (message.megaLinks) {
+ subMessageComponent = [...subMessageComponent, JSX_(MetaRichpreviewMegaLinks, {
+ key: "richprevml",
+ message,
+ chatRoom
+ })];
+ }
+ }
+ let messageDisplayBlock;
+ if (isBeingEdited() === true) {
+ let msgContents = message.textContents;
+ msgContents = megaChat.plugins.emoticonsFilter.fromUtfToShort(msgContents);
+ messageDisplayBlock = JSX_(typingArea.T, {
+ iconClass: "small-icon writing-pen textarea-icon",
+ initialText: msgContents,
+ text: this.state.editText || msgContents,
+ chatRoom,
+ showButtons: true,
+ editing: true,
+ className: "edit-typing-area",
+ onUpdate: () => onUpdate ? onUpdate : null,
+ onConfirm: messageContents => {
+ this.props.onEditToggle(false);
+ if (this.props.onEditDone) {
+ Soon(() => {
+ const tmpMessageObj = {
+ textContents: messageContents
+ };
+ megaChat.plugins.emoticonsFilter.processOutgoingMessage({}, tmpMessageObj);
+ this.props.onEditDone(tmpMessageObj.textContents);
+ if (this.isMounted()) {
+ this.forceUpdate();
+ }
+ });
+ }
+ return true;
+ },
+ onResized: this.props.onResized ? this.props.onResized : false,
+ onValueChanged: val => {
+ this.setState({
+ editText: val
+ });
+ }
+ });
+ } else {
+ if (message.updated > 0 && !message.metaType) {
+ textMessage = `${textMessage} ${l[8887]} `;
+ }
+ if (this.props.initTextScrolling) {
+ messageDisplayBlock = JSX_(perfectScrollbar.O, {
+ className: "message text-block scroll"
+ }, JSX_("div", {
+ className: "message text-scroll"
+ }, JSX_(utils.P9, null, textMessage)));
+ } else {
+ messageDisplayBlock = JSX_("div", {
+ className: "message text-block"
+ }, JSX_(utils.P9, null, textMessage));
+ }
+ }
+ return JSX_(REaCt().Fragment, null, this.renderMessageIndicators(), IS_GEOLOCATION ? null : messageDisplayBlock, subMessageComponent, spinnerElement, IS_GEOLOCATION && JSX_(geoLocation, {
+ latitude,
+ lng
+ }));
+ }
+}
+// EXTERNAL MODULE: ./js/chat/ui/gifPanel/utils.jsx
+const gifPanel_utils = REQ_(1635);
+;// ./js/chat/ui/messages/types/giphy.jsx
+
+
+
+
+
+class Giphy extends AbstractGenericMessage {
+ constructor(...args) {
+ super(...args);
+ this.gifRef = REaCt().createRef();
+ this.viewStateListener = `viewstateChange.giphy--${this.getUniqueId()}`;
+ this.state = {
+ src: undefined
+ };
+ }
+ componentDidMount() {
+ super.componentDidMount();
+ megaChat.rebind(this.viewStateListener, ({
+ data
+ }) => {
+ const gifRef = this.gifRef && this.gifRef.current;
+ if (gifRef) {
+ const {
+ state
+ } = data;
+ if (state === 'active' && gifRef.paused || state !== 'active' && !gifRef.paused) {
+ this.toggle();
+ }
+ }
+ });
+ }
+ componentWillUnmount() {
+ super.componentWillUnmount();
+ megaChat.off(this.viewStateListener);
+ }
+ onVisibilityChange(isIntersecting) {
+ this.setState({
+ src: isIntersecting ? gifPanel_utils.nC.convert(this.props.message.meta.src) : undefined
+ }, () => {
+ let _this$gifRef;
+ (_this$gifRef = this.gifRef) == null || (_this$gifRef = _this$gifRef.current) == null || _this$gifRef[isIntersecting ? 'load' : 'pause']();
+ this.safeForceUpdate();
+ });
+ }
+ toggle() {
+ const video = this.gifRef.current;
+ Promise.resolve(video[video.paused ? 'play' : 'pause']()).catch(nop);
+ }
+ getMessageActionButtons() {
+ const {
+ onDelete,
+ message
+ } = this.props;
+ const $$BUTTONS = [message.isEditable() && JSX_(buttons.$, {
+ key: "delete-GIPHY-button",
+ className: "tiny-button",
+ icon: "sprite-fm-mono icon-options"
+ }, JSX_(dropdowns.ms, {
+ className: "white-context-menu attachments-dropdown",
+ noArrow: true,
+ positionMy: "left bottom",
+ positionAt: "right bottom",
+ horizOffset: 4
+ }, JSX_(dropdowns.tJ, {
+ icon: "sprite-fm-mono icon-dialog-close",
+ label: l[1730],
+ onClick: e => onDelete(e, message)
+ }))), super.getMessageActionButtons && super.getMessageActionButtons()];
+ return $$BUTTONS.filter(button => button);
+ }
+ getContents() {
+ const {
+ message,
+ hideActionButtons
+ } = this.props;
+ const {
+ s,
+ w,
+ h,
+ src
+ } = message.meta;
+ const autoPlay = parseInt(s, 10) < 4e6;
+ return JSX_("video", {
+ className: "giphy-block",
+ ref: this.gifRef,
+ title: message.textContents,
+ autoPlay,
+ loop: true,
+ muted: true,
+ controls: false,
+ width: w,
+ height: h,
+ style: {
+ cursor: autoPlay ? 'default' : 'pointer',
+ height: `${h}px`
+ },
+ onClick: () => !autoPlay && this.toggle(),
+ src: hideActionButtons ? gifPanel_utils.nC.convert(src) : this.state.src
+ });
+ }
+}
+;// ./js/chat/ui/messages/generic.jsx
+
+
+
+
+
+
+
+
+
+
+class GenericConversationMessage extends mixin.M {
+ constructor(props) {
+ super(props);
+ this.containerRef = REaCt().createRef();
+ this.state = {
+ editing: this.props.editing
+ };
+ this.pid = `__geom_${ String(Math.random()).substr(2)}`;
+ }
+ isBeingEdited() {
+ return this.state.editing === true || this.props.editing === true;
+ }
+ componentDidUpdate(oldProps, oldState) {
+ const isBeingEdited = this.isBeingEdited();
+ const isMounted = this.isMounted();
+ if (isBeingEdited && isMounted) {
+ let _this$containerRef;
+ const $generic = $((_this$containerRef = this.containerRef) == null ? void 0 : _this$containerRef.current);
+ const $textarea = $('textarea', $generic);
+ if ($textarea.length > 0 && !$textarea.is(":focus")) {
+ $textarea.trigger("focus");
+ moveCursortoToEnd($textarea[0]);
+ }
+ if (!oldState.editing && this.props.onEditStarted) {
+ this.props.onEditStarted($generic);
+ moveCursortoToEnd($textarea);
+ }
+ }
+ if (isMounted && !isBeingEdited && oldState.editing === true && this.props.onUpdate) {
+ this.props.onUpdate();
+ }
+ }
+ componentDidMount() {
+ let _this$containerRef2;
+ super.componentDidMount();
+ const $node = $((_this$containerRef2 = this.containerRef) == null ? void 0 : _this$containerRef2.current);
+ if (this.isBeingEdited() && this.isMounted()) {
+ const $textarea = $('textarea', $node);
+ if ($textarea.length > 0 && !$textarea.is(':focus')) {
+ $textarea.trigger('focus');
+ moveCursortoToEnd($textarea[0]);
+ }
+ }
+ }
+ haveMoreContactListeners() {
+ if (!this.props.message || !this.props.message.meta) {
+ return false;
+ }
+ if (this.props.message.meta && this.props.message.meta.participants) {
+ return this.props.message.meta.participants;
+ }
+ return false;
+ }
+ doDelete(e, msg) {
+ e.preventDefault(e);
+ e.stopPropagation(e);
+ if (msg.getState() === Message.STATE.NOT_SENT_EXPIRED) {
+ this.doCancelRetry(e, msg);
+ } else {
+ this.props.onDeleteClicked(this.props.message);
+ }
+ }
+ doCancelRetry(e, msg) {
+ e.preventDefault(e);
+ e.stopPropagation(e);
+ const {chatRoom} = this.props.message;
+ const {messageId} = msg;
+ chatRoom.messagesBuff.messages.removeByKey(messageId);
+ chatRoom.megaChat.plugins.chatdIntegration.discardMessage(chatRoom, messageId);
+ }
+ doRetry(e, msg) {
+ e.preventDefault(e);
+ e.stopPropagation(e);
+ const {chatRoom} = this.props.message;
+ this.doCancelRetry(e, msg);
+ chatRoom._sendMessageToTransport(msg).then(internalId => {
+ msg.internalId = internalId;
+ this.safeForceUpdate();
+ });
+ }
+ _favourite(h) {
+ if (M.isInvalidUserStatus()) {
+ return;
+ }
+ const newFavState = Number(!M.isFavourite(h));
+ M.favourite([h], newFavState);
+ }
+ _addFavouriteButtons(h, arr) {
+ const self = this;
+ if (M.getNodeRights(h) > 1) {
+ const isFav = M.isFavourite(h);
+ arr.push(JSX_(dropdowns.tJ, {
+ icon: `
+ sprite-fm-mono
+ context
+ ${isFav ? 'icon-favourite-removed' : 'icon-favourite'}
+ `,
+ label: isFav ? l[5872] : l[5871],
+ isFav,
+ key: "fav",
+ disabled: mega.paywall,
+ onClick: e => {
+ self._favourite(h);
+ e.stopPropagation();
+ e.preventDefault();
+ return false;
+ }
+ }));
+ return isFav;
+ }
+ return false;
+ }
+ _isNodeHavingALink(h) {
+ return M.getNodeShare(h) !== false;
+ }
+ _addLinkButtons(h, arr) {
+ const self = this;
+ const haveLink = self._isNodeHavingALink(h) === true;
+ const getManageLinkText = haveLink ? l[6909] : l[5622];
+ arr.push(JSX_(dropdowns.tJ, {
+ icon: `sprite-fm-mono icon-link${haveLink ? '-gear' : ''}`,
+ key: "getLinkButton",
+ label: getManageLinkText,
+ disabled: mega.paywall,
+ onClick: self._getLink.bind(self, h)
+ }));
+ if (haveLink) {
+ arr.push(JSX_(dropdowns.tJ, {
+ icon: "sprite-fm-mono context icon-link-remove",
+ key: "removeLinkButton",
+ label: l[6821],
+ disabled: mega.paywall,
+ onClick: self._removeLink.bind(self, h)
+ }));
+ return true;
+ }
+ return false;
+ }
+ _startDownload(v) {
+ M.addDownload([v]);
+ }
+ _addToCloudDrive(v, openSendToChat) {
+ $.selected = [v.h];
+ $.chatAttachmentShare = true;
+ if ($.dialog === 'onboardingDialog') {
+ closeDialog();
+ }
+ if (openSendToChat) {
+ openSendToChatDialog();
+ return;
+ }
+ openSaveToDialog(v, (node, target) => {
+ target = target || M.RootID;
+ M.injectNodes(node, target, res => {
+ if (!Array.isArray(res) || !res.length) {
+ if (d) {
+ console.warn('Unable to inject nodes... no longer existing?', res);
+ }
+ } else {
+ mega.ui.toast.show(mega.icu.format(l.toast_import_file, res.length).replace('%s', M.getNameByHandle(target)), 4, l[16797], {
+ actionButtonCallback() {
+ M.openFolder(target).then(() => {
+ if (window.selectionManager) {
+ let reset = false;
+ for (let i = res.length; i--;) {
+ const n = M.getNodeByHandle(res[i]);
+ if (n.p === target) {
+ if (reset) {
+ selectionManager.add_to_selection(n.h);
+ } else {
+ selectionManager.resetTo(n.h);
+ reset = true;
+ }
+ }
+ }
+ }
+ }).catch(dump);
+ }
+ });
+ }
+ });
+ }, false);
+ }
+ _getLink(h, e) {
+ if (u_type === 0) {
+ ephemeralDialog(l[1005]);
+ } else {
+ $.selected = [h];
+ mega.Share.initCopyrightsDialog([h]);
+ }
+ if (e) {
+ e.preventDefault();
+ e.stopPropagation();
+ }
+ }
+ _removeLink(h, e) {
+ if (u_type === 0) {
+ ephemeralDialog(l[1005]);
+ } else {
+ const exportLink = new mega.Share.ExportLink({
+ 'updateUI': true,
+ 'nodesToProcess': [h]
+ });
+ exportLink.removeExportLink();
+ }
+ if (e) {
+ e.preventDefault();
+ e.stopPropagation();
+ }
+ }
+ _startPreview(v, e) {
+ if ($(e && e.target).is('.tiny-button')) {
+ return;
+ }
+ assert(M.chat, 'Not in chat.');
+ if (e) {
+ e.preventDefault();
+ e.stopPropagation();
+ }
+ M.viewMediaFile(v);
+ }
+ render() {
+ const {
+ message,
+ chatRoom
+ } = this.props;
+ const {megaChat} = this.props.message.chatRoom;
+ const {textContents} = message;
+ let additionalClasses = "";
+ let spinnerElement = null;
+ let messageIsNowBeingSent = false;
+ if (this.props.className) {
+ additionalClasses += this.props.className;
+ }
+ if (message instanceof Message) {
+ if (!message.wasRendered || !message.messageHtml) {
+ message.messageHtml = htmlentities(textContents).replace(/\n/gi, "
").replace(/\t/g, ' ');
+ message.processedBy = {};
+ const evtObj = {
+ message,
+ room: chatRoom
+ };
+ megaChat.trigger('onPreBeforeRenderMessage', evtObj);
+ const event = new MegaDataEvent('onBeforeRenderMessage');
+ megaChat.trigger(event, evtObj);
+ megaChat.trigger('onPostBeforeRenderMessage', evtObj);
+ if (event.isPropagationStopped()) {
+ this.logger.warn(`Event propagation stopped receiving (rendering) of message: ${message}`);
+ return false;
+ }
+ message.wasRendered = 1;
+ }
+ const state = message.getState();
+ const stateText = message.getStateText(state);
+ if (state === Message.STATE.NOT_SENT) {
+ messageIsNowBeingSent = unixtime() - message.delay < 5;
+ if (messageIsNowBeingSent) {
+ additionalClasses += ' sending';
+ spinnerElement = JSX_("div", {
+ className: "small-blue-spinner"
+ });
+ if (!message.sending) {
+ message.sending = true;
+ delay(this.pid + message.messageId, () => {
+ if (chatRoom.messagesBuff.messages[message.messageId] && message.sending === true) {
+ chatRoom.messagesBuff.trackDataChange();
+ if (this.isMounted()) {
+ this.forceUpdate();
+ }
+ }
+ }, (5 - (unixtime() - message.delay)) * 1000);
+ }
+ } else {
+ additionalClasses += ' not-sent';
+ if (message.sending === true) {
+ message.sending = false;
+ message.trigger('onChange', [message, 'sending', true, false]);
+ }
+ if (message.requiresManualRetry) {
+ additionalClasses += ' retrying requires-manual-retry';
+ } else {
+ additionalClasses += ' retrying';
+ }
+ }
+ } else {
+ additionalClasses += ` ${ stateText}`;
+ }
+ }
+ const MESSAGE = {
+ TYPE: {
+ ATTACHMENT: textContents[1] === Message.MANAGEMENT_MESSAGE_TYPES.ATTACHMENT,
+ CONTACT: textContents[1] === Message.MANAGEMENT_MESSAGE_TYPES.CONTACT,
+ REVOKE_ATTACHMENT: textContents[1] === Message.MANAGEMENT_MESSAGE_TYPES.REVOKE_ATTACHMENT,
+ VOICE_CLIP: textContents[1] === Message.MANAGEMENT_MESSAGE_TYPES.VOICE_CLIP,
+ GIPHY: message.metaType && message.metaType === Message.MESSAGE_META_TYPE.GIPHY,
+ TEXT: textContents[0] !== Message.MANAGEMENT_MESSAGE_TYPES.MANAGEMENT,
+ INLINE: !(message instanceof Message) && message.type && !!message.type.length,
+ REVOKED: message.revoked
+ },
+ props: {
+ ...this.props,
+ additionalClasses
+ },
+ isBeingEdited: () => this.isBeingEdited(),
+ onDelete: (e, message) => this.doDelete(e, message)
+ };
+ const $$CONTAINER = children => JSX_("div", {
+ ref: this.containerRef
+ }, children);
+ switch (true) {
+ case MESSAGE.TYPE.REVOKED || MESSAGE.TYPE.REVOKE_ATTACHMENT:
+ return null;
+ case MESSAGE.TYPE.ATTACHMENT:
+ return $$CONTAINER(JSX_(Attachment, (0,esm_extends.A)({}, MESSAGE.props, {
+ onPreviewStart: (v, e) => this._startPreview(v, e),
+ onDownloadStart: v => this._startDownload(v),
+ onAddLinkButtons: (h, arr) => this._addLinkButtons(h, arr),
+ onAddToCloudDrive: (v, openSendToChat) => this._addToCloudDrive(v, openSendToChat),
+ onAddFavouriteButtons: (h, arr) => this._addFavouriteButtons(h, arr)
+ })));
+ case MESSAGE.TYPE.CONTACT:
+ return $$CONTAINER(JSX_(Contact, (0,esm_extends.A)({}, MESSAGE.props, {
+ onDelete: MESSAGE.onDelete
+ })));
+ case MESSAGE.TYPE.VOICE_CLIP:
+ return $$CONTAINER(JSX_(VoiceClip, (0,esm_extends.A)({}, MESSAGE.props, {
+ isBeingEdited: MESSAGE.isBeingEdited,
+ onDelete: MESSAGE.onDelete
+ })));
+ case MESSAGE.TYPE.INLINE:
+ return $$CONTAINER(JSX_(Local, MESSAGE.props));
+ case MESSAGE.TYPE.GIPHY:
+ return $$CONTAINER(JSX_(Giphy, (0,esm_extends.A)({}, MESSAGE.props, {
+ onDelete: MESSAGE.onDelete
+ })));
+ case MESSAGE.TYPE.TEXT:
+ return $$CONTAINER(JSX_(Text, (0,esm_extends.A)({}, MESSAGE.props, {
+ onEditToggle: editing => this.setState({
+ editing
+ }),
+ onDelete: MESSAGE.onDelete,
+ onRetry: (e, message) => this.doRetry(e, message),
+ onCancelRetry: (e, message) => this.doCancelRetry(e, message),
+ isBeingEdited: MESSAGE.isBeingEdited,
+ spinnerElement
+ })));
+ default:
+ return null;
+ }
+ }
+}
+
+ },
+
+ 4762
+(_, EXP_, REQ_) {
+
+
+// EXPORTS
+REQ_.d(EXP_, {
+ T: () => TypingArea
+});
+
+// EXTERNAL MODULE: ./node_modules/@babel/runtime/helpers/esm/applyDecoratedDescriptor.js
+const applyDecoratedDescriptor = REQ_(793);
+// EXTERNAL MODULE: external "React"
+const external_React_ = REQ_(1594);
+const REaCt = REQ_.n(external_React_);
+// EXTERNAL MODULE: ./js/ui/utils.jsx
+const utils = REQ_(6411);
+// EXTERNAL MODULE: ./js/chat/mixins.js
+const mixins = REQ_(8264);
+// EXTERNAL MODULE: ./js/ui/emojiDropdown.jsx
+const emojiDropdown = REQ_(1165);
+// EXTERNAL MODULE: ./js/ui/buttons.jsx
+const ui_buttons = REQ_(5155);
+;// ./js/chat/ui/emojiAutocomplete.jsx
+
+
+
+class EmojiAutocomplete extends mixins.w9 {
+ constructor(props) {
+ super(props);
+ this.domRef = REaCt().createRef();
+ this.state = {
+ 'selected': 0
+ };
+ this.loading = false;
+ this.data_emojis = [];
+ }
+ preload_emojis() {
+ if (this.loading === false) {
+ this.loading = true;
+ megaChat.getEmojiDataSet('emojis').then(emojis => {
+ this.loading = 0;
+ this.data_emojis = emojis;
+ this.safeForceUpdate();
+ });
+ }
+ }
+ unbindKeyEvents() {
+ $(document).off(`keydown.emojiAutocomplete${ this.getUniqueId()}`);
+ }
+ bindKeyEvents() {
+ const self = this;
+ $(document).rebind(`keydown.emojiAutocomplete${ self.getUniqueId()}`, (e) => {
+ if (!self.props.emojiSearchQuery) {
+ self.unbindKeyEvents();
+ return;
+ }
+ let key = e.keyCode || e.which;
+ if (!$(e.target).is("textarea")) {
+ console.error("this should never happen.");
+ return;
+ }
+ if (e.altKey || e.metaKey) {
+ return;
+ }
+ let selected = $.isNumeric(self.state.selected) ? self.state.selected : 0;
+ if (document.body.classList.contains('rtl') && (key === 37 || key === 39)) {
+ key = key === 37 ? 39 : 37;
+ }
+ let handled = false;
+ if (!e.shiftKey && (key === 37 || key === 38)) {
+ selected = selected - 1;
+ selected = selected < 0 ? self.maxFound - 1 : selected;
+ if (self.found[selected] && self.state.selected !== selected) {
+ self.setState({
+ selected,
+ 'prefilled': true
+ });
+ handled = true;
+ self.props.onPrefill(false, `:${ self.found[selected].n }:`);
+ }
+ } else if (!e.shiftKey && (key === 39 || key === 40 || key === 9)) {
+ selected = selected + (key === 9 ? e.shiftKey ? -1 : 1 : 1);
+ selected = selected < 0 ? Object.keys(self.found).length - 1 : selected;
+ selected = selected >= self.props.maxEmojis || selected >= Object.keys(self.found).length ? 0 : selected;
+ if (self.found[selected] && (key === 9 || self.state.selected !== selected)) {
+ self.setState({
+ selected,
+ 'prefilled': true
+ });
+ self.props.onPrefill(false, `:${ self.found[selected].n }:`);
+ handled = true;
+ }
+ } else if (key === 13) {
+ self.unbindKeyEvents();
+ if (selected === -1) {
+ if (self.found.length > 0) {
+ for (let i = 0; i < self.found.length; i++) {
+ if (`:${ self.found[i].n }:` === `${self.props.emojiSearchQuery }:`) {
+ self.props.onSelect(false, `:${ self.found[0].n }:`);
+ handled = true;
+ }
+ }
+ }
+ if (!handled && key === 13) {
+ self.props.onCancel();
+ }
+ return;
+ } else if (self.found.length > 0 && self.found[selected]) {
+ self.props.onSelect(false, `:${ self.found[selected].n }:`);
+ handled = true;
+ } else {
+ self.props.onCancel();
+ }
+ } else if (key === 27) {
+ self.unbindKeyEvents();
+ self.props.onCancel();
+ handled = true;
+ }
+ if (handled) {
+ e.preventDefault();
+ e.stopPropagation();
+ return false;
+ } else {
+ if (self.isMounted()) {
+ self.setState({
+ 'prefilled': false
+ });
+ }
+ }
+ });
+ }
+ componentDidUpdate() {
+ if (!this.props.emojiSearchQuery) {
+ this.unbindKeyEvents();
+ } else {
+ this.bindKeyEvents();
+ }
+ }
+ componentWillUnmount() {
+ super.componentWillUnmount();
+ this.unbindKeyEvents();
+ }
+ render() {
+ const self = this;
+ if (!self.props.emojiSearchQuery) {
+ return null;
+ }
+ self.preload_emojis();
+ if (self.loading) {
+ return JSX_("div", {
+ className: "textarea-autofill-bl"
+ }, JSX_("div", {
+ className: "textarea-autofill-info"
+ }, l[5533]));
+ }
+ const q = self.props.emojiSearchQuery.substr(1, self.props.emojiSearchQuery.length);
+ let exactMatch = [];
+ let partialMatch = [];
+ const emojis = self.data_emojis || [];
+ for (var i = 0; i < emojis.length; i++) {
+ const emoji = emojis[i];
+ const match = emoji.n.indexOf(q);
+ if (match !== -1) {
+ if (match === 0) {
+ exactMatch.push(emoji);
+ } else if (partialMatch.length < self.props.maxEmojis - exactMatch.length) {
+ partialMatch.push(emoji);
+ }
+ }
+ if (exactMatch.length >= self.props.maxEmojis) {
+ break;
+ }
+ }
+ exactMatch.sort((a, b) => {
+ if (a.n === q) {
+ return -1;
+ } else if (b.n === q) {
+ return 1;
+ } else {
+ return 0;
+ }
+ });
+ const found = exactMatch.concat(partialMatch).slice(0, self.props.maxEmojis);
+ exactMatch = partialMatch = null;
+ this.maxFound = found.length;
+ this.found = found;
+ if (!found || found.length === 0) {
+ queueMicrotask(() => {
+ self.props.onCancel();
+ });
+ return null;
+ }
+ const emojisDomList = [];
+ for (var i = 0; i < found.length; i++) {
+ const meta = found[i];
+ const filename = twemoji.convert.toCodePoint(meta.u);
+ emojisDomList.push(JSX_("div", {
+ className: `emoji-preview shadow ${ this.state.selected === i ? "active" : ""}`,
+ key: `${meta.n }_${ this.state.selected === i ? "selected" : "inselected"}`,
+ title: `:${ meta.n }:`,
+ onClick (e) {
+ self.props.onSelect(e, e.target.title);
+ self.unbindKeyEvents();
+ }
+ }, JSX_("img", {
+ width: "20",
+ height: "20",
+ className: "emoji emoji-loading",
+ draggable: "false",
+ alt: meta.u,
+ onLoad: e => {
+ e.target.classList.remove('emoji-loading');
+ },
+ onError: e => {
+ e.target.classList.remove('emoji-loading');
+ e.target.classList.add('emoji-loading-error');
+ },
+ src: `${staticpath }images/mega/twemojis/2_v2/72x72/${ filename }.png`
+ }), JSX_("div", {
+ className: "emoji title"
+ }, `:${ meta.n }:`)));
+ }
+ return JSX_("div", {
+ ref: this.domRef,
+ className: "textarea-autofill-bl"
+ }, JSX_(utils.P9, {
+ tag: "div",
+ className: "textarea-autofill-info"
+ }, l.emoji_suggestion_instruction), JSX_("div", {
+ className: "textarea-autofill-emoji"
+ }, emojisDomList));
+ }
+}
+EmojiAutocomplete.defaultProps = {
+ 'requiresUpdateOnResize': true,
+ 'emojiSearchQuery': false,
+ 'disableCheckingVisibility': true,
+ 'maxEmojis': 12
+};
+// EXTERNAL MODULE: ./js/ui/perfectScrollbar.jsx
+const perfectScrollbar = REQ_(1301);
+// EXTERNAL MODULE: ./js/chat/ui/gifPanel/utils.jsx
+const gifPanel_utils = REQ_(1635);
+;// ./js/chat/ui/gifPanel/searchField.jsx
+let _SearchField;
+
+
+class SearchField extends REaCt().Component {
+ render() {
+ const {
+ value,
+ searching,
+ onChange,
+ onReset,
+ onBack
+ } = this.props;
+ return JSX_("div", {
+ className: "gif-panel-search"
+ }, JSX_("div", {
+ className: "gif-search-field"
+ }, searching ? JSX_("i", {
+ className: "sprite-fm-mono icon-left",
+ onClick: onBack
+ }) : JSX_("i", {
+ className: "sprite-fm-mono icon-preview-reveal"
+ }), JSX_("input", {
+ ref: SearchField.inputRef,
+ type: "text",
+ placeholder: gifPanel_utils.kg.SEARCH,
+ autoFocus: true,
+ value,
+ onChange
+ }), searching && JSX_("i", {
+ className: "sprite-fm-mono icon-close-component",
+ onClick: onReset
+ })), JSX_("div", {
+ className: "giphy-logo"
+ }, JSX_("img", {
+ src: `${staticpath }images/mega/giphy.gif`,
+ alt: "PWRD BY GIPHY"
+ })));
+ }
+}
+_SearchField = SearchField;
+SearchField.inputRef = REaCt().createRef();
+SearchField.focus = () => _SearchField.inputRef && _SearchField.inputRef.current && _SearchField.inputRef.current.focus();
+SearchField.hasValue = () => _SearchField.inputRef && _SearchField.inputRef.current && !!_SearchField.inputRef.current.value.length;
+;// ./js/chat/ui/gifPanel/result.jsx
+
+
+class Result extends REaCt().Component {
+ constructor(...args) {
+ super(...args);
+ this.resultRef = REaCt().createRef();
+ }
+ componentDidMount() {
+ let _this$props$onMount, _this$props;
+ (_this$props$onMount = (_this$props = this.props).onMount) == null || _this$props$onMount.call(_this$props, this.resultRef.current);
+ }
+ componentWillUnmount() {
+ let _this$props$onUnmount, _this$props2;
+ (_this$props$onUnmount = (_this$props2 = this.props).onUnmount) == null || _this$props$onUnmount.call(_this$props2, this.resultRef.current, 'unobserve');
+ }
+ render() {
+ const {
+ image,
+ title,
+ onClick
+ } = this.props;
+ return JSX_("div", {
+ className: `
+ ${NODE_CONTAINER_CLASS}
+ ${onClick ? 'clickable' : ''}
+ `,
+ style: {
+ height: parseInt(image.height)
+ }
+ }, JSX_("div", {
+ ref: this.resultRef,
+ className: NODE_CLASS,
+ style: {
+ backgroundImage: HAS_INTERSECTION_OBSERVER ? '' : `url(${image.url})`
+ },
+ "data-url": image.url,
+ onClick
+ }, JSX_("span", null, title)));
+ }
+}
+;// ./js/chat/ui/gifPanel/resultContainer.jsx
+
+
+
+const HAS_INTERSECTION_OBSERVER = typeof IntersectionObserver !== 'undefined';
+const NODE_CONTAINER_CLASS = 'node-container';
+const NODE_CLASS = 'node';
+const RESULT_CONTAINER_CLASS = 'gif-panel-results';
+const RESULTS_END_CLASS = 'results-end';
+const Nil = ({
+ children
+}) => JSX_("div", {
+ className: "no-results-container"
+}, JSX_("div", {
+ className: "no-results-content"
+}, JSX_("i", {
+ className: "huge-icon sad-smile"
+}), JSX_("span", null, children)));
+class ResultContainer extends REaCt().Component {
+ constructor(...args) {
+ super(...args);
+ this.intersectionObserver = null;
+ this.initializeIntersectionObserver = () => {
+ if (HAS_INTERSECTION_OBSERVER) {
+ this.intersectionObserver = new IntersectionObserver(entries => {
+ for (let i = 0; i < entries.length; i++) {
+ var _target$classList, _target$classList2;
+ const entry = entries[i];
+ const {target} = entry;
+ if ((_target$classList = target.classList) != null && _target$classList.contains(NODE_CLASS)) {
+ target.style.backgroundImage = entry.isIntersecting ? `url(${target.dataset.url})` : null;
+ }
+ if (entry.isIntersecting && (_target$classList2 = target.classList) != null && _target$classList2.contains(RESULTS_END_CLASS)) {
+ this.props.onPaginate();
+ }
+ }
+ });
+ }
+ };
+ this.toggleIntersectionObserver = (node, action = 'observe') => {
+ if (node && this.intersectionObserver) {
+ this.intersectionObserver[action](node);
+ }
+ };
+ }
+ componentDidMount() {
+ this.initializeIntersectionObserver();
+ }
+ componentWillUnmount() {
+ if (this.intersectionObserver) {
+ this.intersectionObserver.disconnect();
+ this.intersectionObserver = null;
+ }
+ }
+ render() {
+ const {
+ loading,
+ results,
+ bottom,
+ unavailable,
+ onClick
+ } = this.props;
+ if (unavailable) {
+ return JSX_(Nil, null, gifPanel_utils.kg.NOT_AVAILABLE);
+ }
+ if (loading && results.length < 1) {
+ return JSX_("div", {
+ className: RESULT_CONTAINER_CLASS
+ }, Array.from({
+ length: gifPanel_utils.nC.LIMIT
+ }, (element, index) => JSX_("div", {
+ key: index,
+ className: NODE_CONTAINER_CLASS
+ }, JSX_("div", {
+ className: NODE_CLASS,
+ style: {
+ height: Math.floor(Math.random() * 150) + 100
+ }
+ }))));
+ }
+ if (!loading && results.length < 1) {
+ return JSX_(Nil, null, gifPanel_utils.kg.NO_RESULTS);
+ }
+ if (results.length) {
+ return JSX_(REaCt().Fragment, null, JSX_("div", {
+ className: RESULT_CONTAINER_CLASS
+ }, results.map(({
+ slug,
+ images: {
+ fixed_width_downsampled
+ },
+ title
+ }, index) => {
+ return JSX_(Result, {
+ key: `${slug}--${index}`,
+ image: fixed_width_downsampled,
+ title,
+ onClick: () => onClick(results[index]),
+ onMount: this.toggleIntersectionObserver,
+ onUnmount: this.toggleIntersectionObserver
+ });
+ })), JSX_("div", {
+ className: RESULTS_END_CLASS,
+ ref: node => this.toggleIntersectionObserver(node),
+ style: {
+ visibility: bottom ? 'visible' : 'hidden'
+ }
+ }, JSX_("img", {
+ className: "emoji",
+ alt: "\\ud83d\\ude10",
+ src: `${staticpath}/images/mega/twemojis/2_v2/72x72/1f610.png`
+ }), JSX_("strong", null, gifPanel_utils.kg.END_OF_RESULTS)));
+ }
+ return null;
+ }
+}
+;// ./js/chat/ui/gifPanel/gifPanel.jsx
+
+
+
+
+
+class GifPanel extends REaCt().Component {
+ constructor(...args) {
+ super(...args);
+ this.domRef = REaCt().createRef();
+ this.pathRef = '';
+ this.controllerRef = null;
+ this.fetchRef = null;
+ this.delayProcID = null;
+ this.defaultState = {
+ value: '',
+ searching: false,
+ results: [],
+ loading: true,
+ offset: 0,
+ bottom: false,
+ unavailable: false
+ };
+ this.state = {
+ ...this.defaultState
+ };
+ this.getContainerHeight = () => window.innerHeight * 0.6 > gifPanel_utils.L9 ? gifPanel_utils.L9 : window.innerHeight * 0.6;
+ this.getFormattedPath = path => {
+ const PATH = path + (path.indexOf('?') === -1 ? '?' : '&');
+ const LIMIT = `limit=${gifPanel_utils.nC.LIMIT}`;
+ return `${gifPanel_utils.nC.HOSTNAME + gifPanel_utils.nC.ENDPOINT}/${PATH + LIMIT}`;
+ };
+ this.clickedOutsideComponent = ev => {
+ const $target = ev && $(ev.target);
+ return $target.parents(`.${gifPanel_utils.Hc}`).length === 0 && ['.small-icon.tiny-reset', '.small-icon.gif'].every(outsideElement => !$target.is(outsideElement));
+ };
+ this.bindEvents = () => {
+ $(document).rebind('mousedown.gifPanel', ev => {
+ if (this.clickedOutsideComponent(ev)) {
+ this.props.onToggle();
+ }
+ }).rebind('keydown.gifPanel', ({
+ keyCode
+ }) => {
+ if (keyCode && keyCode === 27) {
+ return SearchField.hasValue() ? this.doReset() : this.props.onToggle();
+ }
+ });
+ };
+ this.unbindEvents = () => {
+ if (this.delayProcID) {
+ delay.cancel(this.delayProcID);
+ }
+ $(document).unbind('.gifPanel');
+ };
+ this.doFetch = path => {
+ this.setState({
+ loading: true,
+ unavailable: false
+ }, () => {
+ this.pathRef = path;
+ this.controllerRef = typeof AbortController === 'function' && new AbortController();
+ this.fetchRef = fetch(this.getFormattedPath(path), {
+ signal: this.controllerRef.signal
+ }).then(response => response.json()).then(({
+ data
+ }) => {
+ this.fetchRef = this.pathRef = null;
+ if (this.domRef.current) {
+ if (data && data.length) {
+ return this.setState(state => ({
+ results: [...state.results, ...data],
+ loading: false
+ }));
+ }
+ return this.setState({
+ bottom: true,
+ loading: false
+ }, () => this.resultContainerRef && this.resultContainerRef.reinitialise());
+ }
+ }).catch(ex => {
+ return ex.name === 'AbortError' ? null : this.setState({
+ unavailable: true
+ });
+ });
+ });
+ };
+ this.doPaginate = () => {
+ const {
+ value,
+ loading,
+ searching
+ } = this.state;
+ if (!loading) {
+ this.setState(state => ({
+ offset: state.offset + gifPanel_utils.nC.OFFSET
+ }), () => {
+ this.doFetch(searching ? `search?q=${escape(value)}&offset=${this.state.offset}` : `trending?offset=${this.state.offset}`);
+ });
+ }
+ };
+ this.doReset = () => {
+ this.setState({
+ ...this.defaultState
+ }, () => {
+ this.doFetch('trending');
+ onIdle(() => SearchField.focus());
+ this.resultContainerRef.scrollToY(0);
+ });
+ };
+ this.handleChange = ev => {
+ const {
+ value
+ } = ev.target;
+ const searching = value.length >= 2;
+ if (value.length === 0) {
+ return this.doReset();
+ }
+ if (this.fetchRef !== null && this.pathRef === 'trending' && this.controllerRef) {
+ this.controllerRef.abort();
+ this.fetchRef = this.pathRef = null;
+ }
+ this.setState(state => ({
+ ...this.defaultState,
+ value,
+ searching,
+ results: searching ? [] : state.results
+ }), () => {
+ this.resultContainerRef.scrollToY(0);
+ this.delayProcID = searching ? delay('gif-search', () => this.doFetch(`search?q=${escape(value)}`), 1600) : null;
+ });
+ };
+ this.handleBack = () => this.doReset();
+ this.doSend = result => {
+ const {
+ mp4,
+ webp,
+ mp4_size,
+ webp_size,
+ width,
+ height
+ } = result.images.fixed_height;
+ const message = Message.MANAGEMENT_MESSAGE_TYPES.MANAGEMENT + Message.MANAGEMENT_MESSAGE_TYPES.CONTAINS_META + Message.MESSAGE_META_TYPE.GIPHY + JSON.stringify({
+ textMessage: result.title,
+ src: gifPanel_utils.nC.convert(mp4),
+ src_webp: gifPanel_utils.nC.convert(webp),
+ s: mp4_size,
+ s_webp: webp_size,
+ w: width,
+ h: height
+ });
+ this.props.chatRoom.sendMessage(message);
+ this.props.onToggle();
+ };
+ }
+ componentDidMount() {
+ if (this.state.results && this.state.results.length === 0) {
+ this.doFetch('trending');
+ }
+ this.bindEvents();
+ }
+ componentWillUnmount() {
+ this.unbindEvents();
+ }
+ render() {
+ const {
+ value,
+ searching,
+ results,
+ loading,
+ bottom,
+ unavailable
+ } = this.state;
+ return JSX_("div", {
+ ref: this.domRef,
+ className: "gif-panel-wrapper"
+ }, JSX_("div", {
+ className: "gif-panel",
+ style: {
+ height: this.getContainerHeight()
+ }
+ }, JSX_("div", {
+ className: "gif-panel-header"
+ }, JSX_(SearchField, {
+ value,
+ searching,
+ onChange: this.handleChange,
+ onReset: this.doReset,
+ onBack: this.handleBack
+ })), JSX_("div", {
+ className: "gif-panel-content"
+ }, JSX_(perfectScrollbar.O, {
+ ref: container => {
+ this.resultContainerRef = container;
+ },
+ options: {
+ 'suppressScrollX': true
+ }
+ }, JSX_(ResultContainer, {
+ results,
+ loading,
+ bottom,
+ unavailable,
+ onPaginate: this.doPaginate,
+ onClick: this.doSend
+ })))));
+ }
+}
+;// ./js/chat/ui/typingArea.jsx
+
+let _dec, _class;
+
+
+
+
+
+
+
+
+const TypingArea = (_dec = (0,mixins.hG)(54, true), _class = class TypingArea extends mixins.w9 {
+ constructor(props) {
+ super(props);
+ this.domRef = REaCt().createRef();
+ this.state = {
+ emojiSearchQuery: false,
+ textareaHeight: 20,
+ gifPanelActive: false
+ };
+ this.getTextareaMaxHeight = () => {
+ const {
+ containerRef
+ } = this.props;
+ if (containerRef && containerRef.current) {
+ return this.isMounted() ? containerRef.current.offsetHeight * 0.4 : 100;
+ }
+ return 100;
+ };
+ const {
+ chatRoom
+ } = props;
+ this.logger = d && MegaLogger.getLogger("TypingArea", {}, chatRoom && chatRoom.logger || megaChat.logger);
+ this.onEmojiClicked = this.onEmojiClicked.bind(this);
+ this.onTypeAreaKeyUp = this.onTypeAreaKeyUp.bind(this);
+ this.onTypeAreaKeyDown = this.onTypeAreaKeyDown.bind(this);
+ this.onTypeAreaBlur = this.onTypeAreaBlur.bind(this);
+ this.onTypeAreaChange = this.onTypeAreaChange.bind(this);
+ this.onCopyCapture = this.onCopyCapture.bind(this);
+ this.onPasteCapture = this.onPasteCapture.bind(this);
+ this.onCutCapture = this.onCutCapture.bind(this);
+ this.state.typedMessage = this.props.initialText || '';
+ }
+ onEmojiClicked(e, slug) {
+ if (this.props.disabled) {
+ e.preventDefault();
+ e.stopPropagation();
+ return;
+ }
+ slug = slug[0] === ':' || slug.substr(-1) === ':' ? slug : `:${slug}:`;
+ const textarea = $('.messages-textarea', this.domRef.current)[0];
+ const cursorPosition = this.getCursorPosition(textarea);
+ const {
+ text,
+ onValueChanged
+ } = this.props;
+ const val = text.slice(0, cursorPosition) + slug + text.slice(cursorPosition);
+ onValueChanged(val);
+ textarea.selectionEnd = cursorPosition + slug.length;
+ this.onTypeAreaChange(e, val);
+ }
+ stoppedTyping() {
+ if (this.props.disabled || !this.props.chatRoom) {
+ return;
+ }
+ this.iAmTyping = false;
+ this.props.chatRoom.trigger('stoppedTyping');
+ }
+ typing() {
+ if (this.props.disabled || !this.props.chatRoom) {
+ return;
+ }
+ const self = this;
+ const now = Date.now();
+ delay(this.getReactId(), () => self.iAmTyping && self.stoppedTyping(), 4e3);
+ if (!self.iAmTyping || now - self.lastTypingStamp > 4e3) {
+ self.iAmTyping = true;
+ self.lastTypingStamp = now;
+ self.props.chatRoom.trigger('typing');
+ }
+ }
+ triggerOnUpdate(forced) {
+ const self = this;
+ if (!self.props.onUpdate || !self.isMounted()) {
+ return;
+ }
+ let shouldTriggerUpdate = forced ? forced : false;
+ if (!shouldTriggerUpdate && self.props.text !== self.lastTypedMessage) {
+ self.lastTypedMessage = self.props.text;
+ shouldTriggerUpdate = true;
+ }
+ if (!shouldTriggerUpdate) {
+ const $textarea = $('.chat-textarea:visible textarea:visible', self.domRef.current);
+ if (!self._lastTextareaHeight || self._lastTextareaHeight !== $textarea.height()) {
+ self._lastTextareaHeight = $textarea.height();
+ shouldTriggerUpdate = true;
+ if (self.props.onResized) {
+ self.props.onResized();
+ }
+ }
+ }
+ if (shouldTriggerUpdate) {
+ self.props.onUpdate();
+ }
+ }
+ onCancelClicked() {
+ const self = this;
+ self.props.onValueChanged('');
+ if (self.props.chatRoom && self.iAmTyping) {
+ self.stoppedTyping();
+ }
+ self.onConfirmTrigger(false);
+ self.triggerOnUpdate();
+ }
+ onSaveClicked() {
+ const self = this;
+ if (self.props.disabled || !self.isMounted()) {
+ return;
+ }
+ const val = $.trim($('.chat-textarea:visible textarea:visible', this.domRef.current).val());
+ if (self.onConfirmTrigger(val) !== true) {
+ self.props.onValueChanged('');
+ }
+ if (self.props.chatRoom && self.iAmTyping) {
+ self.stoppedTyping();
+ }
+ self.triggerOnUpdate();
+ }
+ onConfirmTrigger(val) {
+ const {
+ onConfirm,
+ persist,
+ chatRoom
+ } = this.props;
+ const result = onConfirm(val);
+ if (val !== false && result !== false) {
+ $('.textarea-scroll', this.domRef.current).scrollTop(0);
+ }
+ if (persist) {
+ const {
+ persistedTypeArea
+ } = chatRoom.megaChat.plugins;
+ if (persistedTypeArea) {
+ if (d > 2) {
+ this.logger.info('Removing persisted-typed value...');
+ }
+ persistedTypeArea.removePersistedTypedValue(chatRoom);
+ }
+ }
+ return result;
+ }
+ onTypeAreaKeyDown(e) {
+ if (this.props.disabled) {
+ e.preventDefault();
+ e.stopPropagation();
+ return;
+ }
+ const self = this;
+ const key = e.keyCode || e.which;
+ const element = e.target;
+ const val = $.trim(element.value);
+ if (self.state.emojiSearchQuery) {
+ return;
+ }
+ if (key === 13 && !e.shiftKey && !e.ctrlKey && !e.altKey) {
+ if (e.isPropagationStopped() || e.isDefaultPrevented()) {
+ return;
+ }
+ if (self.onConfirmTrigger(val) !== true) {
+ self.props.onValueChanged('');
+ $(document).trigger('closeDropdowns');
+ }
+ e.preventDefault();
+ e.stopPropagation();
+ if (self.props.chatRoom && self.iAmTyping) {
+ self.stoppedTyping();
+ }
+ }
+ }
+ onTypeAreaKeyUp(e) {
+ if (this.props.disabled) {
+ e.preventDefault();
+ e.stopPropagation();
+ return;
+ }
+ const self = this;
+ const key = e.keyCode || e.which;
+ const element = e.target;
+ const val = $.trim(element.value);
+ if (key === 13 && !e.shiftKey && !e.ctrlKey && !e.altKey) {
+ e.preventDefault();
+ e.stopPropagation();
+ } else if (key === 13) {
+ if (self.state.emojiSearchQuery) {
+ return;
+ }
+ if (e.altKey) {
+ let content = element.value;
+ const cursorPos = self.getCursorPosition(element);
+ content = `${content.substring(0, cursorPos) }\n${ content.substring(cursorPos, content.length)}`;
+ self.props.onValueChanged(content);
+ self.onUpdateCursorPosition = cursorPos + 1;
+ e.preventDefault();
+ } else if ($.trim(val).length === 0) {
+ e.preventDefault();
+ }
+ } else if (key === 38) {
+ if (self.state.emojiSearchQuery) {
+ return;
+ }
+ if ($.trim(val).length === 0) {
+ if (self.props.onUpEditPressed && self.props.onUpEditPressed() === true) {
+ e.preventDefault();
+ }
+ }
+ } else if (key === 27) {
+ if (self.state.emojiSearchQuery) {
+ return;
+ }
+ if (self.props.showButtons === true) {
+ e.preventDefault();
+ self.onCancelClicked(e);
+ }
+ } else {
+ if (self.prefillMode && (key === 8 || key === 32 || key === 186 || key === 13)) {
+ self.prefillMode = false;
+ }
+ const currentContent = element.value;
+ const currentCursorPos = self.getCursorPosition(element) - 1;
+ if (self.prefillMode && (currentCursorPos > self.state.emojiEndPos || currentCursorPos < self.state.emojiStartPos)) {
+ self.prefillMode = false;
+ self.setState({
+ 'emojiSearchQuery': false,
+ 'emojiStartPos': false,
+ 'emojiEndPos': false
+ });
+ return;
+ }
+ if (self.prefillMode) {
+ return;
+ }
+ const char = String.fromCharCode(key);
+ if (key === 16 || key === 17 || key === 18 || key === 91 || key === 8 || key === 37 || key === 39 || key === 40 || key === 38 || key === 9 || /[\w:-]/.test(char)) {
+ const parsedResult = mega.utils.emojiCodeParser(currentContent, currentCursorPos);
+ self.setState({
+ 'emojiSearchQuery': parsedResult[0],
+ 'emojiStartPos': parsedResult[1],
+ 'emojiEndPos': parsedResult[2]
+ });
+ return;
+ }
+ if (self.state.emojiSearchQuery) {
+ self.setState({
+ 'emojiSearchQuery': false
+ });
+ }
+ }
+ }
+ onTypeAreaBlur(e) {
+ if (this.props.disabled) {
+ e.preventDefault();
+ e.stopPropagation();
+ return;
+ }
+ const self = this;
+ if (self.state.emojiSearchQuery) {
+ setTimeout(() => {
+ if (self.isMounted()) {
+ self.setState({
+ 'emojiSearchQuery': false,
+ 'emojiStartPos': false,
+ 'emojiEndPos': false
+ });
+ }
+ }, 300);
+ }
+ }
+ onTypeAreaChange(e, value) {
+ if (this.props.disabled) {
+ e.preventDefault();
+ e.stopPropagation();
+ return;
+ }
+ const self = this;
+ value = String(value || e.target.value || '').replace(/^\s+/, '');
+ if (self.props.text !== value) {
+ self.props.onValueChanged(value);
+ self.forceUpdate();
+ }
+ if (value.length) {
+ self.typing();
+ } else {
+ self.stoppedTyping();
+ }
+ if (this.props.persist) {
+ const {
+ chatRoom
+ } = this.props;
+ const {
+ megaChat
+ } = chatRoom;
+ const {
+ persistedTypeArea
+ } = megaChat.plugins;
+ if (persistedTypeArea) {
+ if (d > 2) {
+ this.logger.debug('%s persisted-typed value...', value.length ? 'Updating' : 'Removing');
+ }
+ if (value.length) {
+ persistedTypeArea.updatePersistedTypedValue(chatRoom, value);
+ } else {
+ persistedTypeArea.removePersistedTypedValue(chatRoom);
+ }
+ }
+ }
+ self.updateScroll();
+ }
+ focusTypeArea() {
+ if (this.props.disabled) {
+ return;
+ }
+ if ($('.chat-textarea:visible textarea:visible', this.domRef.current).length > 0 && !$('.chat-textarea:visible textarea:visible:first', this.domRef.current).is(":focus")) {
+ moveCursortoToEnd($('.chat-textarea:visible:first textarea', this.domRef.current)[0]);
+ }
+ }
+ componentDidMount() {
+ super.componentDidMount();
+ this._lastTextareaHeight = 20;
+ this.lastTypedMessage = this.props.initialText || this.lastTypedMessage;
+ chatGlobalEventManager.addEventListener('resize', `typingArea${this.getUniqueId()}`, () => this.handleWindowResize());
+ this.triggerOnUpdate(true);
+ this.updateScroll();
+ megaChat.rebind(`viewstateChange.gifpanel${this.getUniqueId()}`, e => {
+ const {
+ gifPanelActive
+ } = this.state;
+ const {
+ state
+ } = e.data;
+ if (state === 'active' && !gifPanelActive && this.gifResume) {
+ this.setState({
+ gifPanelActive: true
+ });
+ delete this.gifResume;
+ } else if (state !== 'active' && gifPanelActive && !this.gifResume) {
+ this.gifResume = true;
+ this.setState({
+ gifPanelActive: false
+ });
+ }
+ });
+ }
+ UNSAFE_componentWillMount() {
+ const {
+ chatRoom,
+ initialText,
+ persist,
+ onValueChanged
+ } = this.props;
+ const {
+ megaChat,
+ roomId
+ } = chatRoom;
+ const {
+ persistedTypeArea
+ } = megaChat.plugins;
+ if (persist && persistedTypeArea) {
+ if (!initialText) {
+ persistedTypeArea.getPersistedTypedValue(chatRoom).then(res => {
+ if (res && this.isMounted() && !this.props.text) {
+ onValueChanged(res);
+ }
+ }).catch(ex => {
+ if (this.logger && ex !== undefined) {
+ this.logger.warn(`Failed to retrieve persistedTypeArea for ${roomId}: ${ex}`, [ex]);
+ }
+ });
+ }
+ persistedTypeArea.addChangeListener(this.getUniqueId(), (e, k, v) => {
+ if (roomId === k) {
+ onValueChanged(v || '');
+ this.triggerOnUpdate(true);
+ }
+ });
+ }
+ }
+ componentWillUnmount() {
+ super.componentWillUnmount();
+ const self = this;
+ self.triggerOnUpdate();
+ if (megaChat.plugins.persistedTypeArea) {
+ megaChat.plugins.persistedTypeArea.removeChangeListener(self.getUniqueId());
+ }
+ chatGlobalEventManager.removeEventListener('resize', `typingArea${ self.getUniqueId()}`);
+ megaChat.off(`viewstateChange.gifpanel${this.getUniqueId()}`);
+ }
+ componentDidUpdate() {
+ if (this.isComponentEventuallyVisible() && !window.getSelection().toString() && $('textarea:focus,select:focus,input:focus').filter(":visible").length === 0) {
+ this.focusTypeArea();
+ }
+ this.updateScroll();
+ if (this.onUpdateCursorPosition) {
+ const el = $('.chat-textarea:visible:first textarea:visible', this.domRef.current)[0];
+ el.selectionStart = el.selectionEnd = this.onUpdateCursorPosition;
+ this.onUpdateCursorPosition = false;
+ }
+ }
+ updateScroll() {
+ if (!this.isComponentEventuallyVisible() || !this.$node && !this.domRef && !this.domRef.current) {
+ return;
+ }
+ const $node = this.$node = this.$node || this.domRef.current;
+ const $textarea = this.$textarea = this.$textarea || $('textarea:first', $node);
+ const $scrollBlock = this.$scrollBlock = this.$scrollBlock || $textarea.closest('.textarea-scroll');
+ const $preview = $('.message-preview', $scrollBlock).safeHTML(`${escapeHTML(this.props.text).replace(/\n/g, '
')}
`);
+ const textareaHeight = $preview.height();
+ $scrollBlock.height(Math.min(textareaHeight, this.getTextareaMaxHeight()));
+ if (textareaHeight !== this._lastTextareaHeight) {
+ this._lastTextareaHeight = textareaHeight;
+ this.setState({
+ textareaHeight
+ });
+ if (this.props.onResized) {
+ this.props.onResized();
+ }
+ $textarea.height(textareaHeight);
+ }
+ if (this.textareaScroll) {
+ this.textareaScroll.reinitialise();
+ }
+ }
+ getCursorPosition(el) {
+ let pos = 0;
+ if ('selectionStart' in el) {
+ pos = el.selectionStart;
+ } else if ('selection' in document) {
+ el.focus();
+ const sel = document.selection.createRange(),
+ selLength = document.selection.createRange().text.length;
+ sel.moveStart('character', -el.value.length);
+ pos = sel.text.length - selLength;
+ }
+ return pos;
+ }
+ customIsEventuallyVisible() {
+ return this.props.chatRoom.isCurrentlyActive;
+ }
+ handleWindowResize(e) {
+ if (!this.isComponentEventuallyVisible()) {
+ return;
+ }
+ if (e) {
+ this.updateScroll();
+ }
+ this.triggerOnUpdate();
+ }
+ isActive() {
+ return document.hasFocus() && this.$messages && this.$messages.is(":visible");
+ }
+ resetPrefillMode() {
+ this.prefillMode = false;
+ }
+ onCopyCapture() {
+ this.resetPrefillMode();
+ }
+ onCutCapture() {
+ this.resetPrefillMode();
+ }
+ onPasteCapture() {
+ this.resetPrefillMode();
+ }
+ render() {
+ const self = this;
+ const room = this.props.chatRoom;
+ let buttons = null;
+ if (self.props.showButtons === true) {
+ buttons = [JSX_(ui_buttons.$, {
+ key: "save",
+ className: `${"mega-button right"} positive`,
+ label: l[776],
+ onClick: self.onSaveClicked.bind(self)
+ }), JSX_(ui_buttons.$, {
+ key: "cancel",
+ className: "mega-button right",
+ label: l.msg_dlg_cancel,
+ onClick: self.onCancelClicked.bind(self)
+ })];
+ }
+ const textareaStyles = {
+ height: self.state.textareaHeight
+ };
+ const textareaScrollBlockStyles = {};
+ const newHeight = Math.min(self.state.textareaHeight, self.getTextareaMaxHeight());
+ if (newHeight > 0) {
+ textareaScrollBlockStyles.height = newHeight;
+ }
+ let emojiAutocomplete = null;
+ if (self.state.emojiSearchQuery) {
+ emojiAutocomplete = JSX_(EmojiAutocomplete, {
+ emojiSearchQuery: self.state.emojiSearchQuery,
+ emojiStartPos: self.state.emojiStartPos,
+ emojiEndPos: self.state.emojiEndPos,
+ typedMessage: self.props.text,
+ onPrefill (e, emojiAlias) {
+ if ($.isNumeric(self.state.emojiStartPos) && $.isNumeric(self.state.emojiEndPos)) {
+ const msg = self.props.text;
+ const pre = msg.substr(0, self.state.emojiStartPos);
+ let post = msg.substr(self.state.emojiEndPos + 1, msg.length);
+ const startPos = self.state.emojiStartPos;
+ const fwdPos = startPos + emojiAlias.length;
+ let endPos = fwdPos;
+ self.onUpdateCursorPosition = fwdPos;
+ self.prefillMode = true;
+ if (post.substr(0, 2) == "::" && emojiAlias.substr(-1) == ":") {
+ emojiAlias = emojiAlias.substr(0, emojiAlias.length - 1);
+ endPos -= 1;
+ } else {
+ post = post ? post.substr(0, 1) !== " " ? ` ${ post}` : post : " ";
+ self.onUpdateCursorPosition++;
+ }
+ self.setState({
+ 'emojiEndPos': endPos
+ });
+ self.props.onValueChanged(pre + emojiAlias + post);
+ }
+ },
+ onSelect (e, emojiAlias, forceSend) {
+ if ($.isNumeric(self.state.emojiStartPos) && $.isNumeric(self.state.emojiEndPos)) {
+ const msg = self.props.text;
+ const pre = msg.substr(0, self.state.emojiStartPos);
+ let post = msg.substr(self.state.emojiEndPos + 1, msg.length);
+ if (post.substr(0, 2) == "::" && emojiAlias.substr(-1) == ":") {
+ emojiAlias = emojiAlias.substr(0, emojiAlias.length - 1);
+ } else {
+ post = post ? post.substr(0, 1) !== " " ? ` ${ post}` : post : " ";
+ }
+ const val = pre + emojiAlias + post;
+ self.prefillMode = false;
+ self.setState({
+ 'emojiSearchQuery': false,
+ 'emojiStartPos': false,
+ 'emojiEndPos': false
+ });
+ self.props.onValueChanged(val);
+ if (forceSend) {
+ if (self.onConfirmTrigger($.trim(val)) !== true) {
+ self.props.onValueChanged('');
+ }
+ }
+ }
+ },
+ onCancel () {
+ self.prefillMode = false;
+ self.setState({
+ 'emojiSearchQuery': false,
+ 'emojiStartPos': false,
+ 'emojiEndPos': false
+ });
+ }
+ });
+ }
+ const disabledTextarea = !!(room.pubCu25519KeyIsMissing === true || this.props.disabled);
+ return JSX_("div", {
+ ref: this.domRef,
+ className: `
+ typingarea-component
+ ${this.props.className}
+ `
+ }, this.state.gifPanelActive && JSX_(GifPanel, {
+ chatRoom: this.props.chatRoom,
+ onToggle: () => {
+ this.setState({
+ gifPanelActive: false
+ });
+ delete this.gifResume;
+ }
+ }), JSX_("div", {
+ className: `
+ chat-textarea
+ ${this.props.className}
+ `
+ }, emojiAutocomplete, self.props.children, self.props.editing ? null : JSX_(ui_buttons.$, {
+ className: `
+ popup-button
+ gif-button
+ ${this.state.gifPanelActive ? 'active' : ''}
+ `,
+ icon: "small-icon gif",
+ disabled: this.props.disabled,
+ onClick: () => this.setState(state => {
+ delete this.gifResume;
+ return {
+ gifPanelActive: !state.gifPanelActive
+ };
+ })
+ }), JSX_(ui_buttons.$, {
+ className: "popup-button emoji-button",
+ icon: "sprite-fm-theme icon-emoji",
+ iconHovered: "sprite-fm-theme icon-emoji-active",
+ disabled: this.props.disabled
+ }, JSX_(emojiDropdown.A, {
+ className: "popup emoji",
+ vertOffset: 17,
+ onClick: this.onEmojiClicked
+ })), JSX_("hr", null), JSX_(perfectScrollbar.O, {
+ chatRoom: self.props.chatRoom,
+ className: "chat-textarea-scroll textarea-scroll",
+ options: {
+ 'suppressScrollX': true
+ },
+ style: textareaScrollBlockStyles,
+ ref: ref => {
+ self.textareaScroll = ref;
+ }
+ }, JSX_("div", {
+ className: "messages-textarea-placeholder"
+ }, self.props.text ? null : JSX_(utils.zT, null, (l[18763] || `Write message to \u201c%s\u201d\u2026`).replace('%s', room.getRoomTitle()))), JSX_("textarea", {
+ className: `
+ ${"messages-textarea"}
+ ${disabledTextarea ? 'disabled' : ''}
+ `,
+ onKeyUp: this.onTypeAreaKeyUp,
+ onKeyDown: this.onTypeAreaKeyDown,
+ onBlur: this.onTypeAreaBlur,
+ onChange: this.onTypeAreaChange,
+ onCopyCapture: this.onCopyCapture,
+ onPasteCapture: this.onPasteCapture,
+ onCutCapture: this.onCutCapture,
+ value: self.props.text,
+ style: textareaStyles,
+ disabled: disabledTextarea,
+ readOnly: disabledTextarea
+ }), JSX_("div", {
+ className: "message-preview"
+ }))), buttons);
+ }
+}, (0,applyDecoratedDescriptor.A)(_class.prototype, "handleWindowResize", [_dec], Object.getOwnPropertyDescriptor(_class.prototype, "handleWindowResize"), _class.prototype), _class);
+
+ },
+
+ 5009
+(_, EXP_, REQ_) {
+
+ REQ_.d(EXP_, {
+ A: () => __WEBPACK_DEFAULT_EXPORT__
+ });
+ const react0__ = REQ_(1594);
+ const react0___default = REQ_.n(react0__);
+ const _chat_mixins1__ = REQ_(8264);
+
+
+class ToggleCheckbox extends _chat_mixins1__ .w9 {
+ constructor(props) {
+ super(props);
+ this.domRef = react0___default().createRef();
+ this.onToggle = () => {
+ const newState = !this.state.value;
+ this.setState({
+ value: newState
+ });
+ if (this.props.onToggle) {
+ this.props.onToggle(newState);
+ }
+ };
+ this.state = {
+ value: this.props.value
+ };
+ }
+ render() {
+ return JSX_("div", {
+ ref: this.domRef,
+ className: `
+ mega-switch
+ ${this.props.className}
+ ${this.state.value ? 'toggle-on' : ''}
+ `,
+ role: "switch",
+ "aria-checked": !!this.state.value,
+ onClick: this.onToggle
+ }, JSX_("div", {
+ className: `mega-feature-switch sprite-fm-mono-after
+ ${this.state.value ? 'icon-check-after' : 'icon-minimise-after'}`
+ }));
+ }
+}
+ const __WEBPACK_DEFAULT_EXPORT__ = {
+ ToggleCheckbox
+};
+
+ }
+
+}]);
\ No newline at end of file
diff --git a/js/chat/bundle.js b/js/chat/bundle.js
index f4a53bcdfd..4febb66f0c 100644
--- a/js/chat/bundle.js
+++ b/js/chat/bundle.js
@@ -1,26872 +1,5208 @@
/** @file automatically generated, do not edit it. */
-(() => { // webpackBootstrap
- const __webpack_modules__ = {
+ (() => { // webpackBootstrap
+ window.JSX_=React.createElement;
+ const __webpack_modules__ = {
-326
+ 8676
(_, EXP_, REQ_) {
"use strict";
+ REQ_.d(EXP_, {
+ r: () => chatGlobalEventManager
+ });
+const ChatGlobalEventManager = function () {};
+lazy(ChatGlobalEventManager.prototype, 'listeners', function () {
+ window.addEventListener('hashchange', ev => this.triggered(ev));
+ $(window).rebind('resize.chatGlobalEventManager', ev => this.triggered(ev));
+ const listeners = Object.create(null);
+ listeners.resize = Object.create(null);
+ listeners.hashchange = Object.create(null);
+ return listeners;
+});
+ChatGlobalEventManager.prototype.addEventListener = function (eventName, namespace, cb) {
+ this.listeners[eventName][namespace] = this.listeners[namespace] || cb;
+};
+ChatGlobalEventManager.prototype.removeEventListener = function (eventName, namespace) {
+ delete this.listeners[eventName][namespace];
+};
+ChatGlobalEventManager.prototype.triggered = SoonFc(140, function _chatEVDispatcher(ev) {
+ if (M.chat) {
+ const listeners = this.listeners[ev.type];
+ for (const k in listeners) {
+ listeners[k](ev);
+ }
+ }
+});
+const chatGlobalEventManager = new ChatGlobalEventManager();
-// UNUSED EXPORTS: default
+ },
-// EXTERNAL MODULE: external "React"
-const React_ = REQ_(594);
-const REaCt = REQ_.n(React_);
-// EXTERNAL MODULE: external "ReactDOM"
-const ReactDOM_ = REQ_(206);
-// EXTERNAL MODULE: ./js/chat/ui/conversations.jsx + 21 modules
-const conversations = REQ_(732);
-;// ./js/chat/chatRouting.jsx
-let _ChatRouting;
-class ChatRouting {
- constructor(megaChatInstance) {
- this.megaChat = megaChatInstance;
+ 7057
+(_, EXP_, REQ_) {
+
+"use strict";
+ REQ_.d(EXP_, {
+ U_: () => MCO_FLAGS,
+ zd: () => RETENTION_FORMAT
+ });
+ const _utils_jsx0__ = REQ_(5779);
+
+const RETENTION_FORMAT = {
+ HOURS: 'hour',
+ DAYS: 'day',
+ WEEKS: 'week',
+ MONTHS: 'month',
+ DISABLED: 'none'
+};
+const MCO_FLAGS = {
+ OPEN_INVITE: 'oi',
+ SPEAK_REQUEST: 'sr',
+ WAITING_ROOM: 'w'
+};
+window.RETENTION_FORMAT = RETENTION_FORMAT;
+window.MCO_FLAGS = MCO_FLAGS;
+const ChatRoom = function (megaChat, roomId, type, users, ctime, lastActivity, chatId, chatShard, chatdUrl, noUI, publicChatHandle, publicChatKey, ck, isMeeting, retentionTime, mcoFlags, organiser) {
+ const self = this;
+ this.logger = MegaLogger.getLogger(`room[${ roomId }]`, {}, megaChat.logger);
+ this.megaChat = megaChat;
+ MegaDataObject.call(this, {
+ state: null,
+ users: [],
+ roomId: null,
+ type: null,
+ messages: [],
+ ctime: 0,
+ lastActivity: 0,
+ callRequest: null,
+ isCurrentlyActive: false,
+ _messagesQueue: [],
+ unreadCount: 0,
+ chatId: undefined,
+ chatdUrl: undefined,
+ chatShard: undefined,
+ members: {},
+ membersSet: false,
+ membersLoaded: false,
+ topic: '',
+ flags: 0x00,
+ publicLink: null,
+ observers: 0,
+ dnd: null,
+ alwaysNotify: null,
+ retentionTime: 0,
+ activeCallIds: null,
+ meetingsLoading: null,
+ options: {},
+ scheduledMeeting: undefined,
+ historyTimedOut: false
+ });
+ this.roomId = roomId;
+ this.instanceIndex = ChatRoom.INSTANCE_INDEX++;
+ this.type = type;
+ this.ctime = ctime;
+ this.lastActivity = lastActivity ? lastActivity : 0;
+ this.chatd = megaChat.plugins.chatdIntegration.chatd;
+ this.chatId = chatId;
+ this.chatIdBin = chatId ? base64urldecode(chatId) : "";
+ this.chatShard = chatShard;
+ this.chatdUrl = chatdUrl;
+ this.publicLink = null;
+ this.publicChatHandle = publicChatHandle;
+ this.publicChatKey = publicChatKey;
+ this.ck = ck;
+ this.scrolledToBottom = 1;
+ this.callRequest = null;
+ this.shownMessages = {};
+ this.retentionTime = retentionTime;
+ this.activeSearches = 0;
+ this.activeCallIds = new MegaDataMap(this);
+ this.ringingCalls = new MegaDataMap(this);
+ this.isMeeting = isMeeting;
+ this.isNote = type === 'private' && roomId === u_handle;
+ this.callUserLimited = false;
+ this.members = Object.create(null);
+ Object.defineProperty(this.members, 'hasOwnProperty', {
+ value(p) {
+ return p in this;
+ }
+ });
+ if (type === "private") {
+ users.forEach((userHandle) => {
+ self.members[userHandle] = 3;
+ });
+ } else {
+ users.forEach((userHandle) => {
+ self.members[userHandle] = 0;
+ });
}
- openCustomView(sectionName) {
- const {megaChat} = this;
- megaChat.routingSection = sectionName;
- megaChat.hideAllChats();
- delete megaChat.lastOpenedChat;
+ this.options = {};
+ mcoFlags = mcoFlags || {};
+ for (const flag of Object.values(MCO_FLAGS)) {
+ this.options[flag] = mcoFlags[flag] || 0;
}
- route(resolve, reject, location, event, isLandingPage) {
- if (!M.chat) {
- console.error('This function is meant to navigate within the chat...');
- return;
+ this.organiser = organiser;
+ this.setState(ChatRoom.STATE.INITIALIZED);
+ this.isCurrentlyActive = false;
+ if (d) {
+ this.rebind('onStateChange.chatRoomDebug', (e, oldState, newState) => {
+ self.logger.debug("Will change state from: ", ChatRoom.stateToText(oldState), " to ", ChatRoom.stateToText(newState));
+ });
+ }
+ self.rebind('onStateChange.chatRoom', (e, oldState, newState) => {
+ if (newState === ChatRoom.STATE.READY && !self.isReadOnly() && self.chatd && self.isOnline() && self.chatIdBin) {
+ if (d > 2) {
+ self.logger.warn('Restoring persisted messages...', self.type, self.isCurrentlyActive);
+ }
+ const cim = self.getChatIdMessages();
+ cim.restore(true);
}
- const args = String(location || '').split('/').map(String.trim).filter(String);
- if (args[0] === 'fm') {
- args.shift();
+ });
+ self.rebind('onMessagesBuffAppend.lastActivity', (e, msg) => {
+ if (is_chatlink || self.isNote) {
+ return;
}
- if (args[0] === 'chat') {
- args.shift();
+ const ts = msg.delay ? msg.delay : msg.ts;
+ if (!ts) {
+ return;
}
- if (args[0] && args[0].length > 8 && args[0].substring(0, 8) === 'contacts') {
- location = location.replace(args[0], 'contacts');
- args[0] = 'contacts';
+ const contactForMessage = msg && Message.getContactForMessage(msg);
+ if (contactForMessage && contactForMessage.u !== u_handle) {
+ if (!contactForMessage.ats || contactForMessage.ats < ts) {
+ contactForMessage.ats = ts;
+ }
}
- const [section] = args;
- const {
- megaChat
- } = this;
- if (d) {
- megaChat.logger.warn('navigate(%s)', location, args);
+ if (self.lastActivity && self.lastActivity >= ts) {
+ if (msg.deleted) {
+ const {
+ delay,
+ ts
+ } = self.messagesBuff.getLastMessageFromServer();
+ self.lastActivity = delay || ts;
+ }
+ return;
}
- args.route = {
- location,
- section,
- args
- };
- if (isLandingPage) {
- megaChat.eventuallyInitMeetingUI();
+ self.lastActivity = ts;
+ if (msg.userId === u_handle) {
+ self.didInteraction(u_handle, ts);
+ return;
}
- megaChat.routingSection = 'chat';
- megaChat.routingSubSection = null;
- megaChat.routingParams = null;
- const handler = ChatRouting.gPageHandlers[section || 'start'];
- if (handler) {
- handler.call(this, args.route).then(resolve).catch(reject);
- resolve = null;
- } else {
- let roomId = String(args[(section === 'c' || section === 'g' || section === 'p') | 0] || '');
- if (roomId.includes('#')) {
- let key = roomId.split('#');
- roomId = key[0];
- key = key[1];
- megaChat.publicChatKeys[roomId] = key;
- roomId = megaChat.handleToId[roomId] || roomId;
- }
- const room = megaChat.getChatById(roomId);
- if (room) {
- room.show();
- args.route.location = room.getRoomUrl();
- } else if (!roomId || roomId === u_handle || roomId.length !== 11 && !is_chatlink) {
- ChatRouting.gPageHandlers.redirect(args.route, 'fm/chat').then(resolve).catch(reject);
- resolve = null;
- } else if (section === 'p') {
- megaChat.smartOpenChat([u_handle, roomId], 'private', undefined, undefined, undefined, true).then(resolve).catch(reject);
- resolve = null;
+ if (self.type === "private") {
+ const targetUserId = self.getParticipantsExceptMe()[0];
+ let targetUserNode;
+ if (M.u[targetUserId]) {
+ targetUserNode = M.u[targetUserId];
+ } else if (msg.userId) {
+ targetUserNode = M.u[msg.userId];
} else {
- megaChat.plugins.chatdIntegration.openChat(roomId).then(chatId => {
- megaChat.getChatById(chatId).show();
- return chatId;
- }).catch(ex => {
- if (d && ex !== ENOENT) {
- console.warn('If "%s" is a chat, something went wrong..', roomId, ex);
- }
- if (page !== location) {
- return EEXPIRED;
- }
- megaChat.cleanup(true);
- if (ex === ENOENT || ex === EBLOCKED && megaChat.publicChatKeys[roomId]) {
- msgDialog('warninga', '', l[20641], l[20642], () => {
- loadSubPage(is_chatlink ? 'start' : 'fm/chat', event);
- });
- } else {
- if (String(location).startsWith('chat')) {
- location = 'fm/chat';
- }
- loadSubPage(location, location.includes('chat') ? 'override' : event);
- }
- return EACCESS;
- }).then(resolve).catch(reject);
- resolve = null;
+ console.error("Missing participant in a 1on1 room.");
+ return;
}
- }
- if (resolve) {
- onIdle(resolve);
- }
- if (args.route.location !== location) {
- location = args.route.location;
- }
- const method = page === 'chat' || page === 'fm/chat' || page === location || event && event.type === 'popstate' ? 'replaceState' : 'pushState';
- mBroadcaster.sendMessage('beforepagechange', location);
- M.currentdirid = String(page = location).replace('fm/', '');
- if (location.substr(0, 13) === "chat/contacts") {
- location = `fm/${ location}`;
- }
- if (location === 'chat') {
- location = 'fm/chat';
- }
- history[method]({
- subpage: location
- }, "", (hashLogic ? '#' : '/') + location);
- mBroadcaster.sendMessage('pagechange', page);
- }
- initFmAndChat(targetChatId) {
- assert(!fminitialized);
- return new Promise((res, rej) => {
- M.currentdirid = targetChatId ? `fm/chat/${ targetChatId}` : undefined;
- loadSubPage('fm');
- mBroadcaster.once('chat_initialized', () => {
- authring.onAuthringReady().then(res, rej);
- });
- });
- }
- reinitAndOpenExistingChat(chatId, publicChatHandle = false, cbBeforeOpen = undefined) {
- const chatUrl = `fm/chat/c/${ chatId}`;
- publicChatHandle = publicChatHandle || megaChat.initialPubChatHandle;
- megaChat.destroy();
- is_chatlink = false;
- loadingDialog.pshow();
- return new Promise((resolve, reject) => {
- this.initFmAndChat(chatId).always(() => {
- megaChat.initialPubChatHandle = publicChatHandle;
- megaChat.initialChatId = chatId;
- const next = () => {
- mBroadcaster.once('pagechange', () => {
- onIdle(() => {
- loadingDialog.phide();
- megaChat.renderListing(chatUrl, true).catch(ex => {
- console.error("Failed to megaChat.renderListing:", ex);
- reject(ex);
- }).always(() => {
- megaChat.updateKeysInProtocolHandlers();
- const chatRoom = megaChat.getChatById(chatId);
- assert(chatRoom);
- if (chatRoom.state === ChatRoom.STATE.READY) {
- resolve(chatRoom);
- } else {
- chatRoom.rebind('onMessagesHistoryDone.reinitAndOpenExistingChat', () => {
- if (chatRoom.state === ChatRoom.STATE.READY) {
- resolve(chatRoom);
- chatRoom.unbind('onMessagesHistoryDone.reinitAndOpenExistingChat');
- }
- });
- }
- });
- });
- });
- loadSubPage(chatUrl);
+ assert(targetUserNode && targetUserNode.u, 'No hash found for participant');
+ assert(M.u[targetUserNode.u], 'User not found in M.u');
+ if (targetUserNode) {
+ self.didInteraction(targetUserNode.u, self.lastActivity);
+ }
+ } else if (self.type === "group" || self.type === "public") {
+ let contactHash;
+ if (msg.authorContact) {
+ contactHash = msg.authorContact.u;
+ } else if (msg.userId) {
+ contactHash = msg.userId;
+ }
+ if (contactHash && M.u[contactHash]) {
+ self.didInteraction(contactHash, self.lastActivity);
+ }
+ assert(contactHash, 'Invalid hash for user (extracted from inc. message)');
+ } else {
+ throw new Error("Not implemented");
+ }
+ });
+ self.rebind('onMembersUpdated.coreRoomDataMngmt', (e, eventData) => {
+ if (self.state === ChatRoom.STATE.LEFT && eventData.priv >= 0 && eventData.priv < 255) {
+ self.membersLoaded = false;
+ self.setState(ChatRoom.STATE.JOINING, true);
+ }
+ let queuedMembersUpdatedEvent = false;
+ if (self.membersLoaded === false) {
+ if (eventData.priv >= 0 && eventData.priv < 255) {
+ const addParticipant = function addParticipant() {
+ self.protocolHandler.addParticipant(eventData.userId);
+ self.members[eventData.userId] = eventData.priv;
+ ChatdIntegration._ensureContactExists([eventData.userId]);
+ self.trigger('onMembersUpdatedUI', eventData);
};
- if (cbBeforeOpen) {
- cbBeforeOpen().then(next, ex => {
- console.error("Failed to execute `cbBeforeOpen`, got a reject of the returned promise:", ex);
+ if (is_chatlink) {
+ megaChat.initContacts([eventData.userId]);
+ }
+ ChatdIntegration._waitForProtocolHandler(self, addParticipant);
+ queuedMembersUpdatedEvent = true;
+ }
+ } else if (eventData.priv === 255 || eventData.priv === -1) {
+ const deleteParticipant = function deleteParticipant() {
+ if (eventData.userId === u_handle) {
+ Object.keys(self.members).forEach((userId) => {
+ self.protocolHandler.removeParticipant(userId);
+ self.members[userId] = userId === u_handle ? ChatRoom.MembersSet.PRIVILEGE_STATE.LEFT : ChatRoom.MembersSet.PRIVILEGE_STATE.READONLY;
});
} else {
- next();
+ self.protocolHandler.removeParticipant(eventData.userId);
+ delete self.members[eventData.userId];
}
- }).catch(ex => reject(ex));
+ self.trigger('onMembersUpdatedUI', eventData);
+ };
+ ChatdIntegration._waitForProtocolHandler(self, deleteParticipant);
+ queuedMembersUpdatedEvent = true;
+ }
+ if (eventData.userId === u_handle) {
+ self.membersLoaded = true;
+ }
+ if (!queuedMembersUpdatedEvent) {
+ self.members[eventData.userId] = eventData.priv;
+ self.trigger('onMembersUpdatedUI', eventData);
+ }
+ });
+ if (is_chatlink && !is_chatlink.callId && !this.options.w) {
+ const unbind = () => {
+ self.unbind('onMessagesHistoryDone.chatlinkAlreadyIn');
+ self.unbind('onMembersUpdated.chatlinkAlreadyIn');
+ };
+ self.rebind('onMembersUpdated.chatlinkAlreadyIn', (e, eventData) => {
+ if (eventData.userId === u_handle && eventData.priv >= 0) {
+ unbind();
+ return this.megaChat.routing.reinitAndOpenExistingChat(this.chatId, this.publicChatHandle);
+ }
});
- }
- reinitAndJoinPublicChat(chatId, initialPubChatHandle, publicChatKey) {
- initialPubChatHandle = initialPubChatHandle || megaChat.initialPubChatHandle;
- megaChat.destroy();
- is_chatlink = false;
- loadingDialog.pshow();
- return new Promise((res, rej) => {
- this.initFmAndChat(chatId).then(() => {
- megaChat.initialPubChatHandle = initialPubChatHandle;
- megaChat.initialChatId = chatId;
- const mciphReq = megaChat.plugins.chatdIntegration.getMciphReqFromHandleAndKey(initialPubChatHandle, publicChatKey);
- const isReady = chatRoom => {
- if (chatRoom.state === ChatRoom.STATE.READY) {
- res(chatRoom);
- loadingDialog.phide();
- } else {
- chatRoom.rebind('onMessagesHistoryDone.reinitAndOpenExistingChat', () => {
- if (chatRoom.state === ChatRoom.STATE.READY) {
- res(chatRoom);
- loadingDialog.phide();
- chatRoom.unbind('onMessagesHistoryDone.reinitAndOpenExistingChat');
- }
- });
- }
- };
- const join = () => {
- const existingRoom = megaChat.getChatById(chatId);
- if (!existingRoom) {
- megaChat.rebind('onRoomInitialized.reinitAndJoinPublicChat', (e, megaRoom) => {
- if (megaRoom.chatId === chatId) {
- megaRoom.setActive();
- isReady(megaRoom);
- megaChat.unbind('onRoomInitialized.reinitAndJoinPublicChat');
- }
- });
- } else {
- existingRoom.setActive();
- isReady(existingRoom);
- }
- };
- join();
- asyncApiReq(mciphReq).then(join).catch(ex => {
- if (ex === EEXIST) {
- join();
- } else {
- loadingDialog.phide();
- console.error("Bad response for mciphReq:", mciphReq, ex);
- rej(ex);
- }
- });
- });
+ self.rebind('onMessagesHistoryDone.chatlinkAlreadyIn', (e, data) => {
+ if (!data.chatdPersist) {
+ unbind();
+ }
});
}
-}
-_ChatRouting = ChatRouting;
-ChatRouting.gPageHandlers = {
- async start({
- location
- }) {
- return megaChat.onChatsHistoryReady(15e3).then(() => {
- return page === location ? megaChat.renderListing() : EACCESS;
- });
- },
- async redirect(target, path = 'fm/chat') {
- target.location = path;
- return _ChatRouting.gPageHandlers.start(target);
- },
- async new_meeting(target) {
- megaChat.trigger('onStartNewMeeting');
- return _ChatRouting.gPageHandlers.redirect(target);
- },
- async contacts({
- section,
- args
- }) {
- this.openCustomView(section);
- const [, target = ''] = args;
- if (target.length === 11) {
- megaChat.routingSubSection = "contact";
- megaChat.routingParams = target;
- } else if (target === "received" || target === "sent") {
- megaChat.routingSubSection = target;
+ self.rebind('onMembersUpdatedUI.chatRoomMembersSync', (e, eventData) => {
+ if (eventData.userId === u_handle) {
+ self.messagesBuff.joined = true;
+ if (eventData.priv === 255 || eventData.priv === -1) {
+ if (self.state === ChatRoom.STATE.JOINING) {
+ self.setState(ChatRoom.STATE.LEFT);
+ }
+ } else {
+ if (self.state === ChatRoom.STATE.JOINING) {
+ self.setState(ChatRoom.STATE.READY);
+ }
+ }
+ }
+ self.trackDataChange();
+ });
+ self.getParticipantsExceptMe().forEach((userHandle) => {
+ const contact = M.u[userHandle];
+ if (contact && contact.c) {
+ getLastInteractionWith(contact.u);
}
+ });
+ self.megaChat.trigger('onRoomCreated', [self]);
+ if (this.type === "public" && self.megaChat.publicChatKeys[self.chatId]) {
+ self.publicChatKey = self.megaChat.publicChatKeys[self.chatId];
}
-};
-// EXTERNAL MODULE: ./js/chat/ui/messages/scheduleMetaChange.jsx
-const scheduleMetaChange = REQ_(757);
-// EXTERNAL MODULE: ./js/chat/chatRoom.jsx + 1 modules
-const chat_chatRoom = REQ_(553);
-// EXTERNAL MODULE: ./js/chat/ui/meetings/schedule/helpers.jsx
-const helpers = REQ_(110);
-;// ./js/chat/meetingsManager.jsx
-
-
-
-class Occurrence {
- constructor(megaChat, occurrence) {
- const {
- decodeData
- } = megaChat.plugins.meetingsManager;
- this.megaChat = megaChat;
- this.id = occurrence.id;
- this.uid = `${occurrence.cid}-${occurrence.o || occurrence.s}`;
- this.chatId = occurrence.cid;
- this.parentId = occurrence.p;
- this.start = occurrence.s * 1000;
- this.startInitial = parseInt(occurrence.o) * 1000 || undefined;
- this.end = occurrence.e * 1000;
- this.timezone = decodeData(occurrence.tz);
- this.title = decodeData(occurrence.t);
- this.description = decodeData(occurrence.d);
- this.ownerHandle = occurrence.u;
- this.flags = occurrence.f;
- this.canceled = occurrence.c;
- this.scheduledMeeting = occurrence.scheduledMeeting;
- }
- get isUpcoming() {
- return !this.canceled && this.end > Date.now();
- }
- cancel() {
- const {
- encodeData
- } = this.megaChat.plugins.meetingsManager;
- const req = {
- a: 'mcsmp',
- p: this.parentId || this.id,
- ...this.parentId && {
- id: this.id
- },
- cid: this.chatId,
- o: this.start / 1000,
- s: this.start / 1000,
- e: this.end / 1000,
- tz: encodeData(this.timezone),
- t: encodeData(this.title),
- d: encodeData(this.description) || '',
- f: this.scheduledMeeting.flags,
- c: 1
- };
- asyncApiReq(req).catch(ex => console.error('Occurrence > cancel ->', ex));
- }
- update(startDateTime, endDateTime) {
- const {
- encodeData
- } = this.megaChat.plugins.meetingsManager;
- const req = {
- a: 'mcsmp',
- cid: this.chatId,
- p: this.parentId || this.id,
- ...this.parentId && {
- id: this.id
- },
- o: this.start / 1000,
- s: startDateTime / 1000,
- e: endDateTime / 1000,
- tz: encodeData(this.timezone),
- t: encodeData(this.title),
- d: encodeData(this.description) || '',
- f: this.scheduledMeeting.flags
- };
- asyncApiReq(req).catch(ex => console.error('Occurrence > update ->', ex));
+ $(window).rebind(`focus.${ self.roomId}`, () => {
+ if (self.isCurrentlyActive) {
+ self.trigger("onChatShown");
+ }
+ });
+ self.megaChat.rebind(`onRoomDestroy.${ self.roomId}`, (e, room) => {
+ if (room.roomId == self.roomId) {
+ $(window).off(`focus.${ self.roomId}`);
+ }
+ });
+ self.initialMessageHistLoaded = false;
+ let timer = null;
+ const _historyIsAvailable = ev => {
+ self.initialMessageHistLoaded = ev ? true : -1;
+ if (timer) {
+ timer.abort();
+ timer = null;
+ }
+ self.unbind('onMarkAsJoinRequested.initHist');
+ self.unbind('onHistoryDecrypted.initHist');
+ self.unbind('onMessagesHistoryDone.initHist');
+ };
+ self.rebind('onHistoryDecrypted.initHist', _historyIsAvailable);
+ self.rebind('onMessagesHistoryDone.initHist', _historyIsAvailable);
+ self.rebind('onMarkAsJoinRequested.initHist', () => {
+ (timer = tSleep(300)).then(() => {
+ if (d) {
+ self.logger.warn("Timed out waiting to load hist for:", self.chatId || self.roomId);
+ }
+ this.historyTimedOut = true;
+ this.trigger('onHistTimeoutChange');
+ timer = null;
+ _historyIsAvailable(false);
+ });
+ });
+ self.rebind('onRoomDisconnected', () => {
+ if (!self.call) {
+ for (const activeCallId of self.activeCallIds.keys()) {
+ self.activeCallIds.remove(activeCallId);
+ }
+ megaChat.updateSectionUnreadCount();
+ }
+ });
+ this.rebind(`onCallUserLimitExceeded.${chatId}`, () => {
+ if (this.callUserLimited) {
+ return;
+ }
+ (this.callUserLimited = tSleep(60)).always(() => {
+ this.callUserLimited = false;
+ this.trackDataChange();
+ });
+ });
+ this.membersSetFromApi = new ChatRoom.MembersSet(this);
+ if (publicChatHandle) {
+ this.onPublicChatRoomInitialized();
}
-}
-class ScheduledMeeting {
- constructor(megaChat, meetingInfo, fromActionPacket) {
- const {
- decodeData
- } = megaChat.plugins.meetingsManager;
- this.megaChat = megaChat;
- this.id = meetingInfo.id;
- this.chatId = meetingInfo.cid;
- this.parentId = meetingInfo.p;
- this.start = meetingInfo.s * 1000;
- this.startInitial = parseInt(meetingInfo.o) * 1000 || undefined;
- this.end = meetingInfo.e * 1000;
- this.timezone = decodeData(meetingInfo.tz);
- this.title = decodeData(meetingInfo.t);
- this.description = decodeData(meetingInfo.d);
- this.flags = meetingInfo.f;
- this.canceled = meetingInfo.c;
- this.recurring = meetingInfo.r && {
- frequency: meetingInfo.r.f || undefined,
- interval: meetingInfo.r.i || 0,
- end: meetingInfo.r.u * 1000 || undefined,
- weekDays: meetingInfo.r.wd || [],
- monthDays: meetingInfo.r.md || [],
- offset: meetingInfo.r.mwd && meetingInfo.r.mwd.length ? {
- value: meetingInfo.r.mwd[0][0],
- weekDay: meetingInfo.r.mwd[0][1]
- } : []
- };
- this.occurrences = new MegaDataMap();
- this.nextOccurrenceStart = this.start;
- this.nextOccurrenceEnd = this.end;
- this.isCompleted = false;
- this.ownerHandle = meetingInfo.u;
- this.chatRoom = meetingInfo.chatRoom;
- this.chatRoom.scheduledMeeting = this.isRoot ? this : this.parent;
- if (fromActionPacket) {
- this.initializeFromActionPacket();
+ return this;
+};
+inherits(ChatRoom, MegaDataObject);
+ChatRoom.STATE = {
+ 'INITIALIZED': 5,
+ 'JOINING': 10,
+ 'JOINED': 20,
+ 'READY': 150,
+ 'ENDED': 190,
+ 'LEAVING': 200,
+ 'LEFT': 250
+};
+ChatRoom.INSTANCE_INDEX = 0;
+ChatRoom.ANONYMOUS_PARTICIPANT = mega.BID;
+ChatRoom.ARCHIVED = 0x01;
+ChatRoom.TOPIC_MAX_LENGTH = 30;
+ChatRoom.SCHEDULED_MEETINGS_INTERVAL = 1.8e6;
+ChatRoom._fnRequireParticipantKeys = function (fn, scope) {
+ return function (...args) {
+ const participants = this.protocolHandler.getTrackedParticipants();
+ return ChatdIntegration._ensureKeysAreLoaded(undefined, participants).then(() => {
+ return fn.apply(scope || this, args);
+ }).catch(ex => {
+ this.logger.error("Failed to retrieve keys..", ex);
+ });
+ };
+};
+ChatRoom.MembersSet = function (chatRoom) {
+ this.chatRoom = chatRoom;
+ this.members = {};
+};
+ChatRoom.MembersSet.PRIVILEGE_STATE = {
+ NOT_AVAILABLE: -5,
+ OPERATOR: 3,
+ FULL: 2,
+ READONLY: 0,
+ LEFT: -1
+};
+ChatRoom.encryptTopic = function (protocolHandler, newTopic, participants, isPublic = false) {
+ if (protocolHandler instanceof strongvelope.ProtocolHandler && participants.size > 0) {
+ const topic = protocolHandler.embeddedEncryptTo(newTopic, strongvelope.MESSAGE_TYPES.TOPIC_CHANGE, participants, undefined, isPublic);
+ if (topic) {
+ return base64urlencode(topic);
}
}
- get isRoot() {
- return !this.parentId;
+ return false;
+};
+ChatRoom.MembersSet.prototype.trackFromActionPacket = function (ap, isMcf) {
+ const self = this;
+ const apMembers = {};
+ (ap.u || []).forEach((r) => {
+ apMembers[r.u] = r.p;
+ });
+ Object.keys(self.members).forEach((u_h) => {
+ if (typeof apMembers[u_h] === 'undefined') {
+ self.remove(u_h);
+ } else if (apMembers[u_h] !== self.members[u_h]) {
+ self.update(u_h, apMembers[u_h]);
+ }
+ });
+ Object.keys(apMembers).forEach((u_h) => {
+ if (typeof self.members[u_h] === 'undefined') {
+ const priv2 = apMembers[u_h];
+ !isMcf ? self.add(u_h, priv2) : self.init(u_h, priv2);
+ } else if (apMembers[u_h] !== self.members[u_h]) {
+ self.update(u_h, apMembers[u_h]);
+ }
+ });
+ if (!isMcf && ap.m === 1 && !ap.n && ap.url && ap.ou !== u_handle && typeof ap.p === 'undefined' && !ap.topicChange) {
+ self.chatRoom.trigger('onMeAdded', ap.ou);
}
- get isCanceled() {
- return !!this.canceled;
+};
+ChatRoom.MembersSet.prototype.init = function (handle, privilege) {
+ this.members[handle] = privilege;
+ this.chatRoom.trackDataChange();
+};
+ChatRoom.MembersSet.prototype.update = function (handle, privilege) {
+ this.members[handle] = privilege;
+ this.chatRoom.trackDataChange();
+};
+ChatRoom.MembersSet.prototype.add = function (handle, privilege) {
+ this.members[handle] = privilege;
+ if (handle === u_handle) {
+ this.chatRoom.trigger('onMeJoined');
}
- get isPast() {
- return (this.isRecurring ? this.recurring.end : this.end) < Date.now();
+ this.chatRoom.trackDataChange();
+};
+ChatRoom.MembersSet.prototype.remove = function (handle) {
+ delete this.members[handle];
+ if (handle === u_handle) {
+ this.chatRoom.trigger('onMeLeft');
}
- get isUpcoming() {
- return !(this.isCanceled || this.isPast || this.isCompleted);
+ this.chatRoom.trackDataChange();
+};
+ChatRoom.prototype.trackMemberUpdatesFromActionPacket = function (ap, isMcf) {
+ if (!ap.u) {
+ return;
}
- get isRecurring() {
- return !!this.recurring;
+ if (this.membersSetFromApi) {
+ this.membersSetFromApi.trackFromActionPacket(ap, isMcf);
}
- get isNear() {
- return this.start - Date.now() < ChatRoom.SCHEDULED_MEETINGS_INTERVAL;
+};
+ChatRoom.prototype.getCallParticipants = function () {
+ const ids = this.activeCallIds.keys();
+ if (ids.length === 0) {
+ return [];
}
- get iAmOwner() {
- if (this.ownerHandle) {
- return this.ownerHandle === u_handle;
- }
- return null;
+ return this.activeCallIds[ids[0]];
+};
+ChatRoom.prototype.getChatIdMessages = function () {
+ return this.chatd.chatIdMessages[this.chatIdBin];
+};
+ChatRoom.prototype.getRetentionFormat = function (retentionTime) {
+ retentionTime = retentionTime || this.retentionTime;
+ switch (true) {
+ case retentionTime === 0:
+ return RETENTION_FORMAT.DISABLED;
+ case retentionTime % daysToSeconds(30) === 0 || retentionTime >= 31536000:
+ return RETENTION_FORMAT.MONTHS;
+ case retentionTime % daysToSeconds(7) === 0:
+ return RETENTION_FORMAT.WEEKS;
+ case retentionTime % daysToSeconds(1) === 0:
+ return RETENTION_FORMAT.DAYS;
+ default:
+ return RETENTION_FORMAT.HOURS;
}
- get parent() {
- return this.isRoot ? null : this.megaChat.plugins.meetingsManager.getMeetingById(this.parentId);
+};
+ChatRoom.prototype.getRetentionTimeFormatted = function (retentionTime) {
+ retentionTime = retentionTime || this.retentionTime;
+ switch (this.getRetentionFormat(retentionTime)) {
+ case RETENTION_FORMAT.MONTHS:
+ return Math.floor(secondsToDays(retentionTime) / 30);
+ case RETENTION_FORMAT.WEEKS:
+ return secondsToDays(retentionTime) / 7;
+ case RETENTION_FORMAT.DAYS:
+ return secondsToDays(retentionTime);
+ case RETENTION_FORMAT.HOURS:
+ return secondsToHours(retentionTime);
+ case RETENTION_FORMAT.DISABLED:
+ return 0;
}
- setNextOccurrence() {
- const upcomingOccurrences = Object.values(this.occurrences).filter(o => o.isUpcoming);
- if (!upcomingOccurrences || !upcomingOccurrences.length) {
- this.isCompleted = this.isRecurring;
- return;
- }
- const sortedOccurrences = upcomingOccurrences.sort((a, b) => a.start - b.start);
- this.nextOccurrenceStart = sortedOccurrences[0].start;
- this.nextOccurrenceEnd = sortedOccurrences[0].end;
+};
+ChatRoom.prototype.getRetentionLabel = function (retentionTime) {
+ retentionTime = retentionTime || this.retentionTime;
+ const days = secondsToDays(retentionTime);
+ const months = Math.floor(days / 30);
+ const hours = secondsToHours(retentionTime);
+ switch (this.getRetentionFormat(retentionTime)) {
+ case RETENTION_FORMAT.DISABLED:
+ return l.disabled_chat_history_cleaning_status;
+ case RETENTION_FORMAT.MONTHS:
+ return mega.icu.format(l.months_chat_history_plural, months);
+ case RETENTION_FORMAT.WEEKS:
+ return mega.icu.format(l.weeks_chat_history_plural, days / 7);
+ case RETENTION_FORMAT.DAYS:
+ return mega.icu.format(l.days_chat_history_plural, days);
+ case RETENTION_FORMAT.HOURS:
+ return mega.icu.format(l.hours_chat_history_plural, hours);
}
- async getOccurrences(options) {
- const {
- from,
- to,
- count
- } = options || {};
- const {
- meetingsManager
- } = this.megaChat.plugins;
- const req = {
- a: 'mcsmfo',
- cid: this.chatId,
- ...from && {
- cf: Math.round(from / 1000)
- },
- ...to && {
- ct: Math.round(to / 1000)
- },
- ...count && {
- cc: count
+};
+ChatRoom.prototype.setRetention = function (time) {
+ asyncApiReq({
+ "a": "mcsr",
+ "id": this.chatId,
+ "d": time,
+ "ds": 1
+ });
+};
+ChatRoom.prototype.removeMessagesByRetentionTime = function () {
+ const self = this;
+ const {messages} = self.messagesBuff;
+ if (messages.length === 0 || this.retentionTime === 0) {
+ return;
+ }
+ const newest = messages.getItem(messages.length - 1);
+ let lowestValue = newest.orderValue;
+ let deleteFrom = null;
+ let lastMessage = null;
+ const deletePreviousTo = (new Date() - self.retentionTime * 1000) / 1000;
+ const cp = self.megaChat.plugins.chatdIntegration.chatd.chatdPersist;
+ let finished = false;
+ if (typeof cp !== 'undefined') {
+ const done = function (message) {
+ if (message) {
+ if (self.retentionTime > 0 && self.messagesBuff.messages.length > 0) {
+ self.messagesBuff._removeMessagesBefore(message.messageId);
+ }
+ cp.removeMessagesBefore(self.chatId, message.orderValue);
}
};
- if (is_chatlink) {
- req.ph = is_chatlink.ph;
- delete req.cid;
- }
- const occurrences = await asyncApiReq(req);
- if (Array.isArray(occurrences)) {
- if (!options) {
- this.occurrences.clear();
- }
- for (let i = 0; i < occurrences.length; i++) {
- const occurrence = new Occurrence(this.megaChat, {
- scheduledMeeting: this,
- ...occurrences[i]
- });
- this.occurrences.set(occurrence.uid, occurrence);
- }
- this.isCompleted = false;
- this.setNextOccurrence();
- this.megaChat.trigger(meetingsManager.EVENTS.OCCURRENCES_UPDATE, this);
+ if (newest.delay < deletePreviousTo) {
+ cp.clearChatHistoryForChat(self.chatId);
+ return;
}
- return this.occurrences;
- }
- getOccurrencesById(occurrenceId) {
- const occurrences = Object.values(this.occurrences.toJS()).filter(o => o.id === occurrenceId);
- return occurrences.length ? occurrences : false;
- }
- initializeFromActionPacket() {
- const {
- megaChat,
- isUpcoming,
- isCanceled,
- isRecurring,
- parent
- } = this;
- if (isUpcoming && isRecurring || parent) {
- return parent ? (() => {
- const occurrences = Object.values(parent.occurrences);
- if (occurrences.length <= 20) {
- return parent.getOccurrences().catch(nop);
- }
- occurrences.sort((a, b) => a.start - b.start);
- const {
- chatId,
- start,
- startInitial
- } = this;
- const currentIndex = occurrences.findIndex(o => o.uid === `${chatId}-${(startInitial || start) / 1000}`);
- const previous = occurrences[currentIndex - 1];
- if (!previous) {
- return parent.getOccurrences().catch(nop);
- }
- const movedBack = start <= previous.start;
- let tmp = 0;
- let newStart = movedBack ? Date.now() : previous.end;
- const maxIdx = movedBack ? currentIndex + 1 : occurrences.length;
- const startIdx = movedBack ? 0 : currentIndex;
- for (let i = startIdx; i < maxIdx; i++) {
- if (++tmp % 20 === 0) {
- parent.getOccurrences({
- from: newStart,
- to: occurrences[i].end,
- count: 20
- }).catch(dump);
- newStart = occurrences[i].end;
- tmp = 0;
+ const removeMsgs = function () {
+ cp._paginateMessages(lowestValue, Chatd.MESSAGE_HISTORY_LOAD_COUNT, self.chatId).then((messages) => {
+ messages = messages[0];
+ if (messages.length) {
+ for (let i = 0; i < messages.length; i++) {
+ const message = messages[i];
+ if (message.msgObject.delay < deletePreviousTo) {
+ deleteFrom = lastMessage || message;
+ break;
+ }
+ lastMessage = message;
+ lowestValue = message.orderValue;
}
- parent.occurrences.remove(occurrences[i].uid);
+ } else {
+ finished = true;
}
- if (tmp) {
- parent.getOccurrences({
- from: newStart,
- count: tmp,
- to: movedBack ? occurrences[currentIndex].end : occurrences[occurrences.length - 1].end
- }).catch(dump);
+ if (!finished && !deleteFrom) {
+ onIdle(removeMsgs);
+ } else {
+ done(deleteFrom);
}
- })() : this.getOccurrences().catch(nop);
- }
- megaChat.trigger(megaChat.plugins.meetingsManager.EVENTS[isCanceled ? 'CANCEL' : 'INITIALIZE'], this);
+ });
+ };
+ removeMsgs();
}
- isSameAsOpts(opts) {
- const {
- timezone,
- startDateTime,
- endDateTime,
- topic,
- description,
- f,
- recurring
- } = opts;
- if (this.timezone !== timezone || this.start !== startDateTime || this.end !== endDateTime) {
- return false;
- }
- if (this.title !== topic) {
- return false;
- }
- if (this.description !== description) {
- return false;
- }
- if (this.flags !== f) {
- return false;
- }
- if (!!this.recurring ^ !!recurring) {
- return false;
- }
- if (this.recurring) {
- if (this.recurring.frequency !== recurring.frequency || this.recurring.interval !== (recurring.interval || 0)) {
- return false;
- }
- if (this.recurring.end !== recurring.end) {
- return false;
- }
- let diff = array.diff(this.recurring.weekDays, recurring.weekDays || []);
- if (diff.removed.length + diff.added.length) {
- return false;
- }
- diff = array.diff(this.recurring.monthDays, recurring.monthDays || []);
- if (diff.removed.length + diff.added.length) {
- return false;
- }
- if (Array.isArray(this.recurring.offset) && !Array.isArray(recurring.offset) || !Array.isArray(this.recurring.offset) && Array.isArray(recurring.offset)) {
- return false;
- }
- if ((this.recurring.offset.value || 0) !== (recurring.offset.value || 0) || (this.recurring.offset.weekDay || 0) !== (recurring.offset.weekDay || 0)) {
- return false;
+ if (self.retentionTime > 0 && self.messagesBuff.messages.length > 0) {
+ let message;
+ while (message = self.messagesBuff.messages.getItem(0)) {
+ if (message.delay < deletePreviousTo) {
+ if (!self.messagesBuff.messages.removeByKey(message.messageId)) {
+ break;
+ }
+ } else {
+ break;
}
}
- return true;
}
-}
-class MeetingsManager {
- constructor(megaChat) {
- this.EVENTS = {
- INITIALIZE: 'onMeetingInitialize',
- EDIT: 'onMeetingEdit',
- CANCEL: 'onMeetingCancel',
- LEAVE: 'onMeetingLeave',
- OCCURRENCES_UPDATE: 'onOccurrencesUpdate'
- };
- this.startDayStrings = [l.schedule_occur_sun, l.schedule_occur_mon, l.schedule_occur_tue, l.schedule_occur_wed, l.schedule_occur_thu, l.schedule_occur_fri, l.schedule_occur_sat];
- this.midDayStrings = [l.schedule_occur_sun_mid, l.schedule_occur_mon_mid, l.schedule_occur_tue_mid, l.schedule_occur_wed_mid, l.schedule_occur_thu_mid, l.schedule_occur_fri_mid, l.schedule_occur_sat_mid];
- this.NOTIF_TITLES = {
- recur: {
- desc: {
- update: l.schedule_notif_update_desc
- },
- name: {
- update: l.schedule_mgmt_title
- },
- time: {
- occur: l.schedule_mgmt_update_occur,
- all: l.schedule_mgmt_update_recur
- },
- convert: l.schedule_mgmt_update_convert_recur,
- inv: l.schedule_notif_invite_recur,
- multi: l.schedule_notif_update_multi,
- cancel: {
- occur: l.schedule_mgmt_cancel_occur,
- all: l.schedule_mgmt_cancel_recur
- }
- },
- once: {
- desc: {
- update: l.schedule_notif_update_desc
- },
- name: {
- update: l.schedule_mgmt_title
- },
- time: {
- occur: '',
- all: l.schedule_mgmt_update
- },
- convert: l.schedule_mgmt_update_convert,
- inv: l.schedule_notif_invite,
- multi: l.schedule_notif_update_multi,
- cancel: {
- occur: '',
- all: l.schedule_mgmt_cancel
- }
- }
- };
- this.OCCUR_STRINGS = {
- recur: {
- daily: {
- continuous: {
- occur: l.schedule_recur_time_daily_cont,
- skip: l.scheduled_recur_time_daily_skip_cont
- },
- limited: {
- occur: l.schedule_recur_time_daily,
- skip: l.scheduled_recur_time_daily_skip
- }
- },
- weekly: {
- continuous: {
- list: l.schedule_recur_time_week_cont_list,
- spec: l.schedule_recur_time_week_cont
- },
- limited: {
- list: l.schedule_recur_time_week_list,
- spec: l.schedule_recur_time_week
- }
- },
- monthly: {
- continuous: {
- num: l.schedule_recur_time_num_day_month_cont,
- pos: [[l.schedule_recur_time_first_day_month_6_cont, l.schedule_recur_time_first_day_month_0_cont, l.schedule_recur_time_first_day_month_1_cont, l.schedule_recur_time_first_day_month_2_cont, l.schedule_recur_time_first_day_month_3_cont, l.schedule_recur_time_first_day_month_4_cont, l.schedule_recur_time_first_day_month_5_cont], [l.schedule_recur_time_second_day_month_6_cont, l.schedule_recur_time_second_day_month_0_cont, l.schedule_recur_time_second_day_month_1_cont, l.schedule_recur_time_second_day_month_2_cont, l.schedule_recur_time_second_day_month_3_cont, l.schedule_recur_time_second_day_month_4_cont, l.schedule_recur_time_second_day_month_5_cont], [l.schedule_recur_time_third_day_month_6_cont, l.schedule_recur_time_third_day_month_0_cont, l.schedule_recur_time_third_day_month_1_cont, l.schedule_recur_time_third_day_month_2_cont, l.schedule_recur_time_third_day_month_3_cont, l.schedule_recur_time_third_day_month_4_cont, l.schedule_recur_time_third_day_month_5_cont], [l.schedule_recur_time_fourth_day_month_6_cont, l.schedule_recur_time_fourth_day_month_0_cont, l.schedule_recur_time_fourth_day_month_1_cont, l.schedule_recur_time_fourth_day_month_2_cont, l.schedule_recur_time_fourth_day_month_3_cont, l.schedule_recur_time_fourth_day_month_4_cont, l.schedule_recur_time_fourth_day_month_5_cont], [l.schedule_recur_time_fifth_day_month_6_cont, l.schedule_recur_time_fifth_day_month_0_cont, l.schedule_recur_time_fifth_day_month_1_cont, l.schedule_recur_time_fifth_day_month_2_cont, l.schedule_recur_time_fifth_day_month_3_cont, l.schedule_recur_time_fifth_day_month_4_cont, l.schedule_recur_time_fifth_day_month_5_cont]],
- last: [l.schedule_recur_time_fifth_day_month_6_cont, l.schedule_recur_time_fifth_day_month_0_cont, l.schedule_recur_time_fifth_day_month_1_cont, l.schedule_recur_time_fifth_day_month_2_cont, l.schedule_recur_time_fifth_day_month_3_cont, l.schedule_recur_time_fifth_day_month_4_cont, l.schedule_recur_time_fifth_day_month_5_cont]
- },
- limited: {
- num: l.schedule_recur_time_num_day_month,
- pos: [[l.schedule_recur_time_first_day_month_6, l.schedule_recur_time_first_day_month_0, l.schedule_recur_time_first_day_month_1, l.schedule_recur_time_first_day_month_2, l.schedule_recur_time_first_day_month_3, l.schedule_recur_time_first_day_month_4, l.schedule_recur_time_first_day_month_5], [l.schedule_recur_time_second_day_month_6, l.schedule_recur_time_second_day_month_0, l.schedule_recur_time_second_day_month_1, l.schedule_recur_time_second_day_month_2, l.schedule_recur_time_second_day_month_3, l.schedule_recur_time_second_day_month_4, l.schedule_recur_time_second_day_month_5], [l.schedule_recur_time_third_day_month_6, l.schedule_recur_time_third_day_month_0, l.schedule_recur_time_third_day_month_1, l.schedule_recur_time_third_day_month_2, l.schedule_recur_time_third_day_month_3, l.schedule_recur_time_third_day_month_4, l.schedule_recur_time_third_day_month_5], [l.schedule_recur_time_fourth_day_month_6, l.schedule_recur_time_fourth_day_month_0, l.schedule_recur_time_fourth_day_month_1, l.schedule_recur_time_fourth_day_month_2, l.schedule_recur_time_fourth_day_month_3, l.schedule_recur_time_fourth_day_month_4, l.schedule_recur_time_fourth_day_month_5], [l.schedule_recur_time_fifth_day_month_6, l.schedule_recur_time_fifth_day_month_0, l.schedule_recur_time_fifth_day_month_1, l.schedule_recur_time_fifth_day_month_2, l.schedule_recur_time_fifth_day_month_3, l.schedule_recur_time_fifth_day_month_4, l.schedule_recur_time_fifth_day_month_5]],
- last: [l.schedule_recur_time_last_day_month_6, l.schedule_recur_time_last_day_month_0, l.schedule_recur_time_last_day_month_1, l.schedule_recur_time_last_day_month_2, l.schedule_recur_time_last_day_month_3, l.schedule_recur_time_last_day_month_4, l.schedule_recur_time_last_day_month_5]
- }
- },
- [scheduleMetaChange.A.MODE.CANCELLED]: {
- occur: l.schedule_occurrence_time,
- all: ''
- }
- },
- once: {
- [scheduleMetaChange.A.MODE.CREATED]: {
- occur: l.schedule_occurrence_time
- },
- [scheduleMetaChange.A.MODE.EDITED]: {
- occur: l.schedule_occurrence_time_recur
- },
- [scheduleMetaChange.A.MODE.CANCELLED]: {
- occur: ''
- }
- }
- };
- this.megaChat = megaChat;
- this.scheduledMeetings = megaChat.scheduledMeetings || new MegaDataMap();
- this._goneOccurrences = {};
- this.megaChat.rebind(this.EVENTS.CANCEL, ({
- data
- }) => this.archiveMeeting(data));
- this.megaChat.rebind(this.EVENTS.LEAVE, ({
- data
- }) => this.detachMeeting(data));
- this.megaChat.rebind(`${this.EVENTS.OCCURRENCES_UPDATE}.tracker`, ({
- data
- }) => {
- if (!this._goneOccurrences[data.chatId]) {
- return;
- }
- const {
- chatId
- } = data;
- for (const scheduledId of Object.keys(this._goneOccurrences[chatId])) {
- if (this._goneOccurrences[chatId][scheduledId] === -1) {
- this._goneOccurrences[chatId][scheduledId] = this.scheduledMeetings[scheduledId] ? 0 : 1;
- }
- }
- });
+};
+ChatRoom.prototype.isOnline = function () {
+ const shard = this.chatd.shards[this.chatShard];
+ return shard ? shard.isOnline() : false;
+};
+ChatRoom.prototype.isOnlineForCalls = function () {
+ const chatdChat = this.getChatIdMessages();
+ if (!chatdChat) {
+ return false;
}
- checkForNotifications() {
- const time = Date.now();
- const upcomingMeetings = Object.values(this.scheduledMeetings.toJS()).filter(c => c.isUpcoming);
- for (const meeting of upcomingMeetings) {
- if (pushNotificationSettings.isAllowedForChatId(meeting.chatId)) {
- if (meeting.nextOccurrenceStart >= time + 9e5 && meeting.nextOccurrenceStart <= time + 96e4) {
- const ss = Math.floor(meeting.nextOccurrenceStart / 1000);
- const ns = Math.floor(time / 1000) + 900;
- if (ss - ns <= 10) {
- this.megaChat.trigger('onScheduleUpcoming', meeting);
- } else {
- tSleep(ss - ns).always(() => {
- this.megaChat.trigger('onScheduleUpcoming', meeting);
- });
- }
- } else if (meeting.nextOccurrenceStart >= time && meeting.nextOccurrenceStart < time + 6e4) {
- const ss = Math.floor(meeting.nextOccurrenceStart / 1000);
- const ns = Math.floor(time / 1000);
- tSleep(ss - ns).always(() => {
- this.megaChat.trigger('onScheduleStarting', meeting);
- });
- }
- }
+ return chatdChat.loginState() >= LoginState.HISTDONE;
+};
+ChatRoom.prototype.isArchived = function () {
+ const self = this;
+ return self.flags & ChatRoom.ARCHIVED;
+};
+ChatRoom.prototype.isAnonymous = function () {
+ return is_chatlink && this.type === "public" && this.publicChatHandle && this.publicChatKey && this.publicChatHandle === megaChat.initialPubChatHandle;
+};
+ChatRoom.prototype.isDisplayable = function () {
+ return !this.isArchived() || this.call;
+};
+ChatRoom.prototype.isMuted = function () {
+ return pushNotificationSettings.getDnd(this.chatId) || pushNotificationSettings.getDnd(this.chatId) === 0;
+};
+ChatRoom.prototype.persistToFmdb = function () {
+ const self = this;
+ if (fmdb) {
+ const users = [];
+ if (self.members) {
+ Object.keys(self.members).forEach((user_handle) => {
+ users.push({
+ u: user_handle,
+ p: self.members[user_handle]
+ });
+ });
+ }
+ if (self.chatId && self.chatShard !== undefined) {
+ const roomInfo = {
+ 'id': self.chatId,
+ 'cs': self.chatShard,
+ 'g': self.type === "group" || self.type === "public" ? 1 : 0,
+ 'u': users,
+ 'ts': self.ctime,
+ 'ct': self.ct,
+ 'ck': self.ck ? self.ck : null,
+ 'f': self.flags,
+ 'm': self.type === "public" ? 1 : 0
+ };
+ fmdb.add('mcf', {
+ id: roomInfo.id,
+ d: roomInfo
+ });
}
}
- encodeData(data) {
- return data && base64urlencode(to8(data));
- }
- decodeData(data) {
- return data && from8(base64urldecode(data));
+};
+ChatRoom.prototype.updateFlags = function (f, updateUI) {
+ const self = this;
+ const flagChange = self.flags !== f;
+ self.flags = f;
+ if (self.isArchived()) {
+ megaChat.archivedChatsCount++;
+ } else {
+ megaChat.archivedChatsCount--;
}
- getMeetingById(meetingId) {
- return this.scheduledMeetings[meetingId];
+ self.persistToFmdb();
+ if (updateUI && flagChange) {
+ if (megaChat.currentlyOpenedChat && megaChat.chats[megaChat.currentlyOpenedChat] && megaChat.chats[megaChat.currentlyOpenedChat].chatId === self.chatId) {
+ loadSubPage('fm/chat/');
+ } else {
+ megaChat.refreshConversations();
+ }
}
- getMeetingOrOccurrenceParent(meetingId) {
- const meeting = this.scheduledMeetings[meetingId];
- if (!meeting) {
+ this.trackDataChange();
+};
+ChatRoom.stateToText = function (state) {
+ let txt = null;
+ $.each(ChatRoom.STATE, (k, v) => {
+ if (state === v) {
+ txt = k;
return false;
}
- if (meeting.parentId) {
- return this.getMeetingOrOccurrenceParent(meeting.parentId);
- }
- return meeting;
+ });
+ return txt;
+};
+ChatRoom.prototype.setState = function (newState, isRecover) {
+ const self = this;
+ assert(newState, 'Missing state');
+ if (newState === self.state) {
+ self.logger.debug("Ignoring .setState, newState === oldState, current state: ", self.getStateAsText());
+ return;
}
- getRoomByMeetingId() {}
- async createMeeting(meetingInfo) {
- await this.megaChat.createAndShowGroupRoomFor(meetingInfo.participants, meetingInfo.topic, {
- keyRotation: false,
- createChatLink: meetingInfo.link,
- isMeeting: true,
- openInvite: meetingInfo.openInvite,
- waitingRoom: meetingInfo.waitingRoom,
- scheduledMeeting: {
- a: 'mcsmp',
- s: meetingInfo.startDateTime / 1000,
- e: meetingInfo.endDateTime / 1000,
- tz: this.encodeData(meetingInfo.timezone),
- t: this.encodeData(meetingInfo.topic),
- d: this.encodeData(meetingInfo.description),
- f: meetingInfo.sendInvite ? 0x01 : 0x00,
- ...meetingInfo.recurring && {
- r: {
- f: meetingInfo.recurring.frequency,
- wd: meetingInfo.recurring.weekDays,
- md: meetingInfo.recurring.monthDays,
- mwd: meetingInfo.recurring.offset,
- ...meetingInfo.recurring.end && {
- u: meetingInfo.recurring.end / 1000
- },
- ...meetingInfo.recurring.interval && {
- i: meetingInfo.recurring.interval
- }
- }
- }
- }
- });
+ if (self.state) {
+ assert(newState === ChatRoom.STATE.JOINING && isRecover || newState === ChatRoom.STATE.INITIALIZED && isRecover || newState > self.state, `Invalid state change. Current:${ ChatRoom.stateToText(self.state) }to${ ChatRoom.stateToText(newState)}`);
}
- async updateMeeting(meetingInfo, chatRoom) {
- const {
- scheduledMeeting,
- chatId,
- publicLink,
- options
- } = chatRoom;
- await megaChat.plugins.chatdIntegration.updateScheduledMeeting(meetingInfo, scheduledMeeting.id, chatId);
- const nextParticipants = meetingInfo.participants;
- const prevParticipants = chatRoom.getParticipantsExceptMe();
- const participantsDiff = JSON.stringify(nextParticipants) !== JSON.stringify(prevParticipants);
- if (participantsDiff) {
- const removed = prevParticipants.filter(h => !nextParticipants.includes(h));
- const added = nextParticipants.filter(h => !prevParticipants.includes(h));
- if (removed.length) {
- for (let i = removed.length; i--;) {
- chatRoom.trigger('onRemoveUserRequest', [removed[i]]);
- }
- }
- if (added.length) {
- chatRoom.trigger('onAddUserRequest', [added]);
- }
- }
- if (!!meetingInfo.link !== !!publicLink) {
- chatRoom.updatePublicHandle(!meetingInfo.link, meetingInfo.link);
- }
- if (meetingInfo.waitingRoom !== options[chat_chatRoom.MCO_FLAGS.WAITING_ROOM]) {
- chatRoom.toggleWaitingRoom();
+ const oldState = self.state;
+ self.state = newState;
+ self.trigger('onStateChange', [oldState, newState]);
+};
+ChatRoom.prototype.getStateAsText = function () {
+ const self = this;
+ return ChatRoom.stateToText(self.state);
+};
+ChatRoom.prototype.getParticipants = function () {
+ const self = this;
+ return Object.keys(self.members);
+};
+ChatRoom.prototype.getParticipantsExceptMe = function (userHandles) {
+ const res = clone(userHandles || this.getParticipants());
+ array.remove(res, u_handle, true);
+ return res;
+};
+ChatRoom.prototype.getParticipantsTruncated = function (maxMembers = 5, maxLength = ChatRoom.TOPIC_MAX_LENGTH) {
+ const truncatedParticipantNames = [];
+ const members = Object.keys(this.members);
+ for (let i = 0; i < members.length; i++) {
+ const handle = members[i];
+ const name = M.getNameByHandle(handle);
+ if (!handle || !name || handle === u_handle) {
+ continue;
}
- if (meetingInfo.openInvite !== options[chat_chatRoom.MCO_FLAGS.OPEN_INVITE]) {
- chatRoom.toggleOpenInvite();
+ if (i > maxMembers) {
+ break;
}
+ truncatedParticipantNames.push(name.length > maxLength ? `${name.substr(0, maxLength) }...` : name);
}
- cancelMeeting(scheduledMeeting, chatId) {
- return this.megaChat.plugins.chatdIntegration.cancelScheduledMeeting(scheduledMeeting, chatId);
+ if (truncatedParticipantNames.length === maxMembers) {
+ truncatedParticipantNames.push('...');
}
- deleteMeeting(scheduledMeetingId, chatId) {
- return this.megaChat.plugins.chatdIntegration.deleteScheduledMeeting(scheduledMeetingId, chatId);
+ return truncatedParticipantNames.join(', ');
+};
+ChatRoom.prototype.getRoomTitle = function () {
+ const formattedDate = l[19077].replace('%s1', new Date(this.ctime * 1000).toLocaleString());
+ if (this.isNote) {
+ return l.note_label;
}
- attachMeeting(meetingInfo, fromActionPacket) {
- const chatRoom = meetingInfo.chatRoom || this.megaChat.getChatById(meetingInfo.cid);
- if (chatRoom) {
- const scheduledMeeting = new ScheduledMeeting(this.megaChat, {
- chatRoom,
- ...meetingInfo
- }, fromActionPacket);
- this.scheduledMeetings.set(meetingInfo.id, scheduledMeeting);
- return scheduledMeeting;
- }
+ if (this.type === 'private') {
+ const participants = this.getParticipantsExceptMe();
+ return participants && Array.isArray(participants) ? M.getNameByHandle(participants[0]) : formattedDate;
}
- detachMeeting(scheduledMeeting) {
- if (scheduledMeeting) {
- this.archiveMeeting(scheduledMeeting);
- scheduledMeeting.chatRoom.scheduledMeeting = null;
- this.scheduledMeetings.remove(scheduledMeeting.id);
- if (fmdb) {
- fmdb.del('mcsm', scheduledMeeting.id);
- }
+ if (this.topic === '' || !this.topic) {
+ return this.getParticipantsTruncated() || formattedDate;
+ }
+ const formattedTopic = this.getTruncatedRoomTopic();
+ const isCanceled = this.scheduledMeeting && this.scheduledMeeting.isCanceled;
+ return isCanceled ? `${formattedTopic} ${l.canceled_meeting}` : formattedTopic;
+};
+ChatRoom.prototype.getTruncatedRoomTopic = function (maxLength = ChatRoom.TOPIC_MAX_LENGTH) {
+ return this.topic && this.topic.length > maxLength ? `${this.topic.substr(0, maxLength) }...` : this.topic;
+};
+ChatRoom.prototype.setRoomTopic = async function (newTopic) {
+ if (newTopic && newTopic.trim().length && newTopic !== this.getRoomTitle()) {
+ this.scrolledToBottom = true;
+ const participants = this.protocolHandler.getTrackedParticipants();
+ await ChatdIntegration._ensureKeysAreLoaded(undefined, participants);
+ const topic = this.protocolHandler.embeddedEncryptTo(newTopic, strongvelope.MESSAGE_TYPES.TOPIC_CHANGE, participants, undefined, this.type === 'public');
+ if (topic) {
+ return api.req({
+ a: 'mcst',
+ id: this.chatId,
+ ct: base64urlencode(topic),
+ v: Chatd.VERSION
+ });
}
}
- archiveMeeting(scheduledMeeting) {
- const {
- chatRoom
- } = scheduledMeeting;
- tSleep(2).then(() => chatRoom.hasMessages(true) ? null : chatRoom.archive());
+};
+ChatRoom.prototype.leave = function (notify) {
+ const valid = this.type === 'group' || this.type === 'public';
+ console.assert(valid, `Can't leave room "${this.roomId}" of type "${this.type}"`);
+ if (!valid) {
+ return;
}
- filterUpcomingMeetings(conversations) {
- const upcomingMeetings = Object.values(conversations || {}).filter(c => {
- return c.isDisplayable() && c.isMeeting && c.scheduledMeeting && c.scheduledMeeting.isUpcoming && c.iAmInRoom() && !c.havePendingCall();
- }).sort((a, b) => a.scheduledMeeting.nextOccurrenceStart - b.scheduledMeeting.nextOccurrenceStart || a.ctime - b.ctime);
- const nextOccurrences = upcomingMeetings.reduce((nextOccurrences, chatRoom) => {
- const {
- nextOccurrenceStart
- } = chatRoom.scheduledMeeting;
- if ((0,helpers.cK)(nextOccurrenceStart)) {
- nextOccurrences.today.push(chatRoom);
- } else if ((0,helpers.ef)(nextOccurrenceStart)) {
- nextOccurrences.tomorrow.push(chatRoom);
- } else {
- const date = time2date(nextOccurrenceStart / 1000, 19);
- if (!nextOccurrences.rest[date]) {
- nextOccurrences.rest[date] = [];
- }
- nextOccurrences.rest[date].push(chatRoom);
- }
- return nextOccurrences;
- }, {
- today: [],
- tomorrow: [],
- rest: {}
- });
- return {
- upcomingMeetings,
- nextOccurrences
- };
+ this._leaving = true;
+ this.topic = '';
+ if (notify) {
+ this.trigger('onLeaveChatRequested');
}
- getOccurrenceStrings(meta) {
- const res = [];
- const {
- prevTiming,
- timeRules,
- mode,
- occurrence,
- recurring,
- converted
- } = meta;
- const {
- MODE
- } = scheduleMetaChange.A;
- if (!mode) {
- return res;
- }
- const {
- OCCUR_STRINGS
- } = this;
- let string;
- if (recurring) {
- res.push(this._parseOccurrence(timeRules, mode, occurrence));
- if (prevTiming && !(occurrence && mode === MODE.CANCELLED)) {
- res.push(this._parseOccurrence(prevTiming, mode, occurrence));
- }
- } else {
- const {
- startTime,
- endTime
- } = timeRules;
- string = OCCUR_STRINGS.once[mode].occur;
- res.push(string.replace('%1', toLocaleTime(startTime)).replace('%2', toLocaleTime(endTime)).replace('%6', time2date(startTime, 20)).replace('%s', time2date(startTime, 11)));
- if (prevTiming) {
- const {
- startTime: pStartTime,
- endTime: pEndTime
- } = prevTiming;
- if (converted) {
- res.push(this._parseOccurrence(prevTiming, mode, occurrence));
- } else {
- res.push(string.replace('%1', toLocaleTime(pStartTime)).replace('%2', toLocaleTime(pEndTime)).replace('%6', time2date(pStartTime, 20)).replace('%s', time2date(pStartTime, 11)));
- }
- }
+ if (this.state !== ChatRoom.STATE.LEFT) {
+ this.setState(ChatRoom.STATE.LEAVING);
+ this.setState(ChatRoom.STATE.LEFT);
+ }
+ if (this.activeCallIds.length) {
+ for (const activeCallId of this.activeCallIds.keys()) {
+ this.activeCallIds.remove(activeCallId);
}
- return res;
+ megaChat.updateSectionUnreadCount();
}
- _parseOccurrence(timeRules, mode, occurrence) {
- const {
- startTime,
- endTime,
- days,
- dayInt,
- interval,
- month,
- recurEnd,
- skipDay
- } = timeRules;
- const {
- recur,
- once
- } = this.OCCUR_STRINGS;
- const occurrenceEnd = recurEnd ? 'limited' : 'continuous';
- let string = '';
- if (recur[mode]) {
- return occurrence ? recur[mode].occur.replace('%1', toLocaleTime(startTime)).replace('%2', toLocaleTime(endTime)).replace('%s', time2date(startTime, 11)) : recur[mode].all;
- } else if (month) {
- const {
- count,
- occur
- } = month;
- string = count < 0 ? mega.icu.format(recur.monthly[occurrenceEnd].last[occur], interval) : mega.icu.format(recur.monthly[occurrenceEnd].pos[count][occur], interval);
- return string.replace('%1', toLocaleTime(startTime)).replace('%2', toLocaleTime(endTime)).replace('%3', time2date(startTime, 2)).replace('%4', time2date(recurEnd, 2));
- } else if (days) {
- if (days.length > 1) {
- if (days.length === 7) {
- return recur.daily[occurrenceEnd].occur.replace('%1', toLocaleTime(startTime)).replace('%2', toLocaleTime(endTime)).replace('%3', time2date(startTime, 2)).replace('%4', time2date(recurEnd, 2));
- }
- const weekDays = days.map((day, idx) => {
- if (idx) {
- return this.midDayStrings[day];
- }
- return this.startDayStrings[day];
- });
- string = mega.icu.format(recur.weekly[occurrenceEnd].list, interval);
- string = mega.utils.trans.listToString(weekDays, string);
- } else {
- string = mega.icu.format(recur.weekly[occurrenceEnd].spec, interval).replace('%s', this.startDayStrings[days[0]]);
- }
- return string.replace('%1', toLocaleTime(startTime)).replace('%2', toLocaleTime(endTime)).replace('%3', time2date(startTime, 2)).replace('%4', time2date(recurEnd, 2));
- } else if (dayInt) {
- string = mega.icu.format(recur.monthly[occurrenceEnd].num, interval);
- return string.replace('%1', toLocaleTime(startTime)).replace('%2', toLocaleTime(endTime)).replace('%3', time2date(startTime, 2)).replace('%4', time2date(recurEnd, 2)).replace('%5', dayInt);
- } else if (skipDay) {
- string = mega.icu.format(recur.daily[occurrenceEnd].skip, interval);
- return string.replace('%1', toLocaleTime(startTime)).replace('%2', toLocaleTime(endTime)).replace('%3', time2date(startTime, 2)).replace('%4', time2date(recurEnd, 2));
- }
- string = once[mode].occur;
- return string.replace('%1', toLocaleTime(startTime)).replace('%2', toLocaleTime(endTime)).replace('%6', time2date(startTime, 20)).replace('%s', time2date(startTime, 11));
- }
- getFormattingMeta(scheduledId, data, chatRoom) {
- const {
- MODE
- } = scheduleMetaChange.A;
- const meta = {
- userId: data.sender || false,
- timeRules: {},
- mode: MODE.EDITED,
- handle: scheduledId,
- cid: chatRoom.chatId
- };
- const changeSet = data.schedChange || data.cs || false;
- if (changeSet) {
- const {
- s,
- e,
- c,
- r,
- t,
- d: desc
- } = changeSet;
- let onlyTitle = typeof t !== 'undefined';
- if (Array.isArray(c) && c[1]) {
- meta.mode = MODE.CANCELLED;
- }
- if (Array.isArray(s)) {
- meta.prevTiming = {
- startTime: s[0]
- };
- meta.timeRules.startTime = s[1] || s[0];
- }
- const meeting = this.getMeetingOrOccurrenceParent(scheduledId);
- if (Array.isArray(e)) {
- if (!meta.prevTiming) {
- meta.prevTiming = {
- startTime: meeting ? Math.floor(meeting.start / 1000) : 0
- };
- meta.timeRules.startTime = meta.prevTiming.startTime;
- }
- meta.prevTiming.endTime = e[0];
- meta.timeRules.endTime = e[1] || e[0];
- onlyTitle = false;
- }
- if (desc) {
- meta.description = true;
- onlyTitle = false;
- }
- if (Array.isArray(r)) {
- const parseR = r => r ? typeof r === 'string' ? JSON.parse(r) : r : false;
- const prev = parseR(r[0]);
- const next = parseR(r[1]);
- if (r.length === 1) {
- meta.converted = false;
- meta.timeRules = this._recurringTimings(prev, meta.timeRules || {});
- meta.prevTiming = this._recurringTimings(prev, meta.prevTiming);
- meta.recurring = r[0] !== '';
- } else {
- meta.converted = !!(!!prev ^ !!next);
- if (prev) {
- meta.prevTiming = this._recurringTimings(prev, meta.prevTiming || {});
- }
- meta.timeRules = this._recurringTimings(next, meta.timeRules || {});
- meta.recurring = next !== false;
- }
- onlyTitle = false;
- }
- if (!meeting || meeting.id !== scheduledId) {
- meta.occurrence = true;
- meta.recurring = true;
- }
- if (Array.isArray(t)) {
- meta.topicChange = true;
- meta.onlyTitle = onlyTitle;
- meta.topic = this.decodeData(t[1]);
- meta.oldTopic = this.decodeData(t[0]);
- }
- return meta;
- }
- return this.noCsMeta(scheduledId, data, chatRoom);
- }
- _recurringTimings(meta, obj) {
- if (!meta) {
- return obj;
- }
- obj.recurEnd = meta.u || false;
- obj.interval = meta.i || 1;
- if (meta.wd) {
- obj.days = meta.wd.sort((a, b) => a - b).map(wd => wd === 7 ? 0 : wd);
- }
- if (meta.md) {
- obj.dayInt = meta.md[0];
+};
+ChatRoom.prototype.archive = function () {
+ const self = this;
+ const mask = 0x01;
+ const flags = ChatRoom.ARCHIVED;
+ asyncApiReq({
+ 'a': 'mcsf',
+ 'id': self.chatId,
+ 'm': 1,
+ 'f': flags,
+ 'v': Chatd.VERSION
+ }).then(r => {
+ if (r === 0) {
+ self.updateFlags(flags, true);
}
- if (meta.mwd) {
- obj.month = meta.mwd.map(oc => {
- return {
- count: (oc[0] || 1) - 1,
- occur: oc[1] ? oc[1] === 7 ? 0 : oc[1] : 1
- };
- })[0];
+ });
+};
+ChatRoom.prototype.unarchive = function () {
+ const self = this;
+ const mask = 0x01;
+ const flags = 0x00;
+ asyncApiReq({
+ 'a': 'mcsf',
+ 'id': self.chatId,
+ 'm': 1,
+ 'f': 0,
+ 'v': Chatd.VERSION
+ }).then(res => {
+ if (res === 0) {
+ self.updateFlags(0, true);
}
- if (meta.f === 'd' && meta.i > 1) {
- obj.skipDay = true;
- } else if (meta.f === 'd' && meta.i === 1) {
- obj.days = [1, 2, 3, 4, 5, 6, 0];
+ });
+};
+ChatRoom.prototype.destroy = function (notifyOtherDevices, noRedirect) {
+ const self = this;
+ self.megaChat.trigger('onRoomDestroy', [self]);
+ const mc = self.megaChat;
+ const roomJid = self.roomId;
+ if (!self.stateIsLeftOrLeaving()) {
+ self.leave(notifyOtherDevices);
+ } else if (self.type === "public" && self.publicChatHandle) {
+ if (typeof self.members[u_handle] === 'undefined') {
+ self.megaChat.plugins.chatdIntegration.handleLeave(self);
}
- return obj;
}
- noCsMeta(scheduledId, data, chatRoom) {
- const meta = {
- timeRules: {},
- userId: data.sender || false,
- ap: data,
- handle: scheduledId,
- cid: chatRoom.chatId
- };
- if (!this.getMeetingOrOccurrenceParent(scheduledId) && !chatRoom.scheduledMeeting) {
- const res = this._checkOccurrenceAwait(chatRoom, scheduledId, meta);
- if (res) {
- return res;
- }
+ if (self.isCurrentlyActive) {
+ self.isCurrentlyActive = false;
+ }
+ Soon(() => {
+ mc.chats.remove(roomJid);
+ if (!noRedirect && u_type === 3) {
+ loadSubPage('fm/chat');
}
- const meeting = this.getMeetingOrOccurrenceParent(scheduledId) || chatRoom.scheduledMeeting;
- assert(meeting, `Invalid scheduled meeting state for ${scheduledId} msg`);
- const toS = ms => Math.floor(ms / 1000);
- const {
- MODE
- } = scheduleMetaChange.A;
- meta.timeRules.startTime = toS(meeting.start);
- meta.timeRules.endTime = toS(meeting.end);
- meta.topic = meeting.title;
- meta.recurring = !!meeting.recurring;
- meta.mode = meeting.canceled ? MODE.CANCELLED : MODE.CREATED;
- meta.occurrence = meta.recurring && meeting.id !== scheduledId;
- if (!meta.occurrence && !meeting.canceled) {
- meta.mode = MODE.CREATED;
+ });
+};
+ChatRoom.prototype.updatePublicHandle = async function (remove, cim, force) {
+ if (force) {
+ this.publicLink = null;
+ }
+ if (!remove && this.publicLink) {
+ return this.publicLink;
+ }
+ return asyncApiReq({
+ a: 'mcph',
+ id: this.chatId,
+ v: Chatd.VERSION,
+ cim: cim ? 1 : 0,
+ d: remove ? 1 : undefined
+ }).then(res => {
+ assert(remove && res === 0 || Array.isArray(res) && res[1].length === 8);
+ this.publicLink = remove ? null : `chat/${res[1]}#${this.protocolHandler.getUnifiedKey()}`;
+ }).catch(ex => {
+ this.logger.warn('updatePublicHandle', ex);
+ this.publicLink = null;
+ });
+};
+ChatRoom.prototype.iAmInRoom = function () {
+ return !(!this.members.hasOwnProperty(u_handle) || this.members[u_handle] === -1);
+};
+ChatRoom.prototype.joinViaPublicHandle = function () {
+ const self = this;
+ if (!fminitialized && is_chatlink) {
+ if (u_type) {
+ return new Promise((res, rej) => {
+ self.megaChat.plugins.chatdIntegration.joinChatViaPublicHandle(self).then(() => {
+ self.megaChat.routing.reinitAndOpenExistingChat(self.chatId, self.publicChatHandle).then(res, rej);
+ }, ex => {
+ console.error("Failed joining a chat room (u_type)", ex);
+ rej(ex);
+ });
+ });
}
- const cal = ms => {
- const date = new Date(ms);
- return {
- date: date.getDate(),
- month: time2date(toS(ms), 12)
- };
- };
- if (meta.occurrence) {
- const occurrences = meeting.getOccurrencesById(scheduledId);
- if (!occurrences) {
- meta.mode = MODE.EDITED;
- const res = this._checkOccurrenceAwait(chatRoom, scheduledId, meta);
- if (res) {
- return res;
- }
- meta.ap = data;
- return meta;
- }
- meta.mode = occurrences.some(o => o.canceled) ? MODE.CANCELLED : MODE.EDITED;
- meta.calendar = cal(occurrences[0].start);
- const timeDiff = meta.timeRules.endTime - meta.timeRules.startTime;
- meta.timeRules.startTime = toS(occurrences[0].start);
- meta.timeRules.endTime = toS(occurrences[0].end);
- if (occurrences.length === 1 && occurrences[0].startInitial) {
- meta.prevTiming = {
- startTime: toS(occurrences[0].startInitial)
- };
- meta.prevTiming.endTime = meta.prevTiming.startTime + timeDiff;
- }
- } else if (meta.recurring) {
- const {
- end,
- weekDays = [],
- interval,
- monthDays = [],
- offset,
- frequency
- } = meeting.recurring;
- meta.recurring = true;
- meta.timeRules.recurEnd = end ? toS(end) : false;
- meta.timeRules.interval = interval || 1;
- if (frequency === 'd' && interval > 1) {
- meta.timeRules.skipDay = true;
- } else if (frequency === 'd' && interval === 1) {
- meta.timeRules.days = [1, 2, 3, 4, 5, 6, 0];
- }
- if (weekDays.length) {
- meta.timeRules.days = weekDays.sort((a, b) => a - b).map(wd => wd === 7 ? 0 : wd);
- }
- if (monthDays.length) {
- meta.timeRules.dayInt = monthDays[0];
- }
- if (!Array.isArray(offset)) {
- meta.timeRules.month = {
- count: (offset.value || 1) - 1,
- occur: offset.weekDay ? offset.weekDay === 7 ? 0 : offset.weekDay : 1
- };
- }
- meta.calendar = cal(meeting.start);
- } else {
- meta.calendar = cal(meeting.start);
- }
- if (!meta.occurrence && meeting.canceled && $.len(meta.timeRules)) {
- meta.mode = MODE.CREATED;
- }
- delete meta.ap;
- return meta;
+ return;
}
- _checkOccurrenceAwait(chatRoom, scheduledId, meta) {
- if (!this._goneOccurrences[chatRoom.chatId]) {
- this._goneOccurrences[chatRoom.chatId] = {};
- }
- if (typeof this._goneOccurrences[chatRoom.chatId][scheduledId] === 'undefined') {
- this._goneOccurrences[chatRoom.chatId][scheduledId] = -1;
- return meta;
- }
- const datum = this._goneOccurrences[chatRoom.chatId];
- if (datum[scheduledId] === -1) {
- return meta;
- } else if (datum[scheduledId] === 1) {
- meta.gone = true;
- return meta;
- }
+ if (!self.iAmInRoom() && self.type === "public" && self.publicChatHandle) {
+ return megaChat.plugins.chatdIntegration.joinChatViaPublicHandle(self);
+ }
+ return Promise.reject();
+};
+ChatRoom.prototype.switchOffPublicMode = ChatRoom._fnRequireParticipantKeys(function () {
+ let {
+ topic,
+ protocolHandler,
+ chatId
+ } = this;
+ if (topic) {
+ topic = protocolHandler.embeddedEncryptTo(topic, strongvelope.MESSAGE_TYPES.TOPIC_CHANGE, protocolHandler.getTrackedParticipants(), true, false);
+ topic = base64urlencode(topic);
+ }
+ return asyncApiReq({
+ a: 'mcscm',
+ id: chatId,
+ ct: topic || undefined,
+ v: Chatd.VERSION
+ }).then(() => {
+ protocolHandler.switchOffOpenMode();
+ });
+});
+ChatRoom.prototype.show = function () {
+ if (this.isCurrentlyActive) {
return false;
}
- areMetaObjectsSame(obj1, obj2) {
- if (obj1 && !obj2 || !obj1 && obj2) {
- return false;
- }
- const keys = Object.keys(obj1);
- if (keys.length !== $.len(obj2)) {
- return false;
- }
- const diff = array.diff(keys, Object.keys(obj2));
- if (diff.removed.length + diff.added.length) {
- return false;
- }
- for (const key of keys) {
- if (!obj2.hasOwnProperty(key)) {
- return false;
- }
- if (obj1[key] instanceof Object && obj2[key] instanceof Object) {
- if (!this.areMetaObjectsSame(obj1[key], obj2[key])) {
- return false;
- }
- } else if (Array.isArray(obj1[key]) && Array.isArray(obj2[key])) {
- const keyDiff = array.diff(obj1[key], obj2[key]);
- if (keyDiff.removed.length + keyDiff.added.length) {
- return false;
- }
- } else if (obj1[key] !== obj2[key]) {
- return false;
- }
+ this.megaChat.hideAllChats();
+ if (d) {
+ this.logger.debug(' ---- show');
+ }
+ $.tresizer();
+ onIdle(() => {
+ this.scrollToChat();
+ this.trackDataChange();
+ });
+ this.isCurrentlyActive = true;
+ this.lastShownInUI = Date.now();
+ this.megaChat.setAttachments(this.roomId);
+ this.megaChat.lastOpenedChat = this.roomId;
+ this.megaChat.currentlyOpenedChat = this.roomId;
+ this.trigger('activity');
+ this.trigger('onChatShown');
+ let tmp = this.megaChat.rootDOMNode;
+ if (tmp = tmp.querySelector('.conversation-panels')) {
+ tmp.classList.remove('hidden');
+ if (tmp = tmp.querySelector(`.conversation-panel[data-room-id="${this.chatId}"]`)) {
+ tmp.classList.remove('hidden');
}
- return true;
}
-}
-const meetingsManager = MeetingsManager;
-window.MeetingsManager = MeetingsManager;
-// EXTERNAL MODULE: ./node_modules/@babel/runtime/helpers/esm/applyDecoratedDescriptor.js
-const applyDecoratedDescriptor = REQ_(793);
-// EXTERNAL MODULE: ./js/chat/mixins.js
-const mixins = REQ_(137);
-;// ./js/chat/chatOnboarding.jsx
-
-let _dec, _class;
-
-
-const ChatOnboarding = (_dec = (0,mixins.hG)(1000), _class = class ChatOnboarding {
- constructor(megaChat) {
- this.finished = false;
- if (u_type === 3 && !is_mobile) {
- this.state = {
- [OBV4_FLAGS.CHAT]: -1
- };
- this.megaChat = megaChat;
- this.flagMap = attribCache.bitMapsManager.exists('obv4') ? attribCache.bitMapsManager.get('obv4') : new MegaDataBitMap('obv4', false, Object.values(OBV4_FLAGS));
- const keys = Object.keys(this.state);
- const promises = keys.map(key => this.flagMap.get(key));
- Promise.allSettled(promises).then(res => {
- for (let i = 0; i < res.length; ++i) {
- const v = res[i];
- if (v.status === 'fulfilled') {
- this.handleFlagChange(null, null, keys[i], v.value);
+ if (tmp = document.getElementById(`conversation_${this.roomId}`)) {
+ tmp.classList.add('active');
+ }
+ if (mega.ui.mInfoPanel) {
+ mega.ui.mInfoPanel.hide();
+ }
+};
+ChatRoom.prototype.scrollToChat = function () {
+ this._scrollToOnUpdate = true;
+ const {
+ $chatTreePanePs
+ } = megaChat;
+ if ($chatTreePanePs && $chatTreePanePs.length) {
+ const li = document.querySelector(`ul.conversations-pane li#conversation_${this.roomId}`);
+ if (li && !verge.inViewport(li, -72)) {
+ Object.values($chatTreePanePs).forEach(({
+ ref
+ }) => {
+ if (ref.domNode) {
+ const wrapOuterHeight = $(ref.domNode).outerHeight();
+ const itemOuterHeight = $('li:first', ref.domNode).outerHeight();
+ const pos = li.offsetTop;
+ if (ref.domNode.contains(li)) {
+ ref.doProgramaticScroll == null || ref.doProgramaticScroll(Math.max(0, pos - wrapOuterHeight / 2 + itemOuterHeight), true);
}
}
});
- this.interval = setInterval(() => {
- if (!$.dialog) {
- this._checkAndShowStep();
- }
- }, 10000);
- this.initListeners();
+ this._scrollToOnUpdate = false;
}
}
- initListeners() {
- this.flagMap.addChangeListener((...args) => this.handleFlagChange(...args));
- this.megaChat.chatUIFlags.addChangeListener(SoonFc(200, () => {
- if (this.megaChat.chatUIFlags.convPanelCollapse && $.dialog === 'onboardingDialog') {
- closeDialog();
- }
- this._checkAndShowStep();
- }));
- this.megaChat.addChangeListener(() => {
- const room = this.megaChat.getCurrentRoom();
- if (!room) {
- return;
- }
- this.checkAndShowStep();
- });
- }
- checkAndShowStep() {
- this._checkAndShowStep();
- }
- _shouldSkipShow() {
- if (!M.chat || !mega.ui.onboarding || $.dialog || loadingDialog.active || u_type < 3 || is_mobile || $.msgDialog) {
- return true;
+};
+ChatRoom.prototype.isActive = function () {
+ return document.hasFocus() && this.isCurrentlyActive;
+};
+ChatRoom.prototype.setActive = function () {
+ loadSubPage(this.getRoomUrl());
+};
+ChatRoom.prototype.isLoading = function () {
+ const mb = this.messagesBuff;
+ return mb.messagesHistoryIsLoading() || mb.isDecrypting;
+};
+ChatRoom.prototype.getRoomUrl = function (getRawLink) {
+ const self = this;
+ if (self.type === "private") {
+ const participants = self.getParticipantsExceptMe();
+ const contact = M.u[participants[0] || u_handle];
+ if (contact) {
+ return `fm/chat/p/${ contact.u}`;
}
- this.$topRightMenu = this.$topRightMenu || $('.top-menu-popup', '#topmenu');
- if (!this.$topRightMenu.hasClass('o-hidden')) {
- return true;
+ } else if (!getRawLink && is_chatlink && self.type === "public" && self.publicChatHandle && self.publicChatKey) {
+ return `chat/${ self.publicChatHandle }#${ self.publicChatKey}`;
+ } else if (self.type === "public") {
+ return `fm/chat/c/${ self.roomId}`;
+ } else if (self.type === "group" || self.type === "public") {
+ return `fm/chat/g/${ self.roomId}`;
+ } else {
+ throw new Error("Can't get room url for unknown room type.");
+ }
+};
+ChatRoom.prototype.activateWindow = function () {
+ const self = this;
+ loadSubPage(self.getRoomUrl());
+};
+ChatRoom.prototype.hide = function () {
+ let _tmp;
+ if (d) {
+ this.logger.debug(' ---- hide', this.isCurrentlyActive);
+ }
+ this.isCurrentlyActive = false;
+ this.lastShownInUI = Date.now();
+ if (this.megaChat.currentlyOpenedChat === this.roomId) {
+ this.megaChat.currentlyOpenedChat = null;
+ }
+ let tmp = this.megaChat.rootDOMNode.querySelector(`.conversation-panel[data-room-id="${this.chatId}"]`);
+ (_tmp = tmp) == null || _tmp.classList.add('hidden');
+ if (tmp = document.getElementById(`conversation_${this.roomId}`)) {
+ tmp.classList.remove('active');
+ }
+ this.trigger('onChatHidden', this.isCurrentlyActive);
+};
+ChatRoom.prototype.appendMessage = function (message) {
+ const self = this;
+ if (message.deleted) {
+ return false;
+ }
+ if (self.shownMessages[message.messageId]) {
+ return false;
+ }
+ if (!message.orderValue) {
+ const mb = self.messagesBuff;
+ if (mb.messages.length > 0) {
+ const prevMsg = mb.messages.getItem(mb.messages.length - 1);
+ if (!prevMsg) {
+ self.logger.error("self.messages got out of sync...maybe there are some previous JS exceptions that caused that? note that messages may be displayed OUT OF ORDER in the UI.");
+ } else {
+ let nextVal = prevMsg.orderValue + 0.1;
+ if (!prevMsg.sent) {
+ const cid = megaChat.plugins.chatdIntegration.chatd.chatIdMessages[self.chatIdBin];
+ if (cid && cid.highnum) {
+ nextVal = ++cid.highnum;
+ }
+ }
+ message.orderValue = nextVal;
+ }
}
- this.$topAccDropdown = this.$topAccDropdown || $('.js-dropdown-account', '#topmenu');
- if (this.$topAccDropdown.hasClass('show')) {
- return true;
+ }
+ message.source = Message.SOURCE.SENT;
+ self.trigger('onMessageAppended', message);
+ self.messagesBuff.messages.push(message);
+ self.shownMessages[message.messageId] = true;
+};
+ChatRoom.prototype.getNavElement = function () {
+ const self = this;
+ return $(`.nw-conversations-item[data-room-id="${ self.chatId }"]`);
+};
+ChatRoom.prototype.sendMessage = function (message) {
+ const self = this;
+ const {megaChat} = this;
+ const messageId = megaChat.generateTempMessageId(self.roomId, message);
+ const msgObject = new Message(self, self.messagesBuff, {
+ messageId,
+ 'userId': u_handle,
+ message,
+ 'textContents': message,
+ 'delay': unixtime(),
+ 'sent': Message.STATE.NOT_SENT
+ });
+ self.trigger('onSendMessage');
+ self.appendMessage(msgObject);
+ return self._sendMessageToTransport(msgObject).then(internalId => {
+ if (!internalId) {
+ this.logger.warn(`Got unexpected(?) 'sendingnum'...`, internalId);
}
- this.$topNotifDropdown = this.$topNotifDropdown || $('.js-dropdown-notification', '#topmenu');
- if (this.$topNotifDropdown.hasClass('show')) {
- return true;
+ msgObject.internalId = internalId;
+ msgObject.orderValue = internalId;
+ return internalId || -0xBADF;
+ }).catch(ex => {
+ this.logger.error(`sendMessage failed..`, msgObject, ex);
+ });
+};
+ChatRoom.prototype._sendMessageToTransport = function (messageObject) {
+ const self = this;
+ const {megaChat} = this;
+ megaChat.trigger('onPreBeforeSendMessage', messageObject);
+ megaChat.trigger('onBeforeSendMessage', messageObject);
+ megaChat.trigger('onPostBeforeSendMessage', messageObject);
+ return megaChat.plugins.chatdIntegration.sendMessage(self, messageObject);
+};
+ChatRoom.prototype._sendNodes = async function (nodeids, users) {
+ const u = this.type === 'public' ? [strongvelope.COMMANDER] : users;
+ const promises = nodeids.map(nodeId => asyncApiReq({
+ a: 'mcga',
+ n: [nodeId],
+ u,
+ id: this.chatId,
+ v: Chatd.VERSION
+ }));
+ const res = await Promise.allSettled(promises);
+ const sent = [];
+ for (let i = res.length; i--;) {
+ if (res[i].status === 'fulfilled') {
+ sent.push(nodeids[i]);
}
- this.$searchPanel = this.$searchPanel || $('.search-panel', '.conversationsApp');
- return this.$searchPanel.hasClass('expanded');
}
- _checkAndShowStep() {
- if (this._shouldSkipShow()) {
- return;
- }
- const {
- sections
- } = mega.ui.onboarding;
- if (!sections) {
- return;
+ if (!sent.length) {
+ throw ENOENT;
+ }
+ return sent;
+};
+ChatRoom.prototype.attachNodes = async function (nodes, names) {
+ if (!Array.isArray(nodes)) {
+ nodes = [nodes];
+ }
+ const handles = new Set();
+ for (let i = nodes.length; i--;) {
+ const n = nodes[i];
+ const h = String(crypto_keyok(n) && n.h || n);
+ if (!M.getNodeByHandle(h)) {
+ handles.add(h);
}
- const {
- chat: obChat
- } = sections;
- if (!obChat) {
- return;
+ }
+ if (handles.size) {
+ await dbfetch.acquire([...handles]);
+ }
+ return this._attachNodes(nodes, names);
+};
+ChatRoom.prototype._attachNodes = mutex('chatroom-attach-nodes', function _(resolve, reject, nodes, names) {
+ let i;
+ let step = 0;
+ const users = [];
+ const self = this;
+ let result = null;
+ let copy = Object.create(null);
+ let send = Object.create(null);
+ let link = Object.create(null);
+ let nmap = Object.create(null);
+ const members = self.getParticipantsExceptMe();
+ const sendMessage = nodes => {
+ return new Promise(resolve => {
+ for (let i = nodes.length; i--;) {
+ const n = nmap[nodes[i]] || M.getNodeByHandle(nodes[i]);
+ console.assert(n.h, `Node not found... ${nodes[i]}`);
+ if (n.h) {
+ const name = names && (names[n.hash] || names[n.h]) || n.name;
+ this.sendMessage(Message.MANAGEMENT_MESSAGE_TYPES.MANAGEMENT + Message.MANAGEMENT_MESSAGE_TYPES.ATTACHMENT + JSON.stringify([{
+ h: n.h,
+ k: n.k,
+ t: n.t,
+ s: n.s,
+ fa: n.fa,
+ ts: n.ts,
+ hash: n.hash,
+ name,
+ des: n.des
+ }]));
+ }
+ }
+ resolve();
+ });
+ };
+ const attach = nodes => {
+ console.assert(this.type === 'public' || users.length || this.isNote, 'No users to send to?!');
+ return this.isNote ? sendMessage(nodes) : this._sendNodes(nodes, users).then(res => sendMessage(res));
+ };
+ const done = function () {
+ if (--step < 1) {
+ nmap = null;
+ resolve(result);
}
- if (this.state[OBV4_FLAGS.CHAT]) {
- return;
+ };
+ const fail = function (ex) {
+ if (ex === EBLOCKED) {
+ result = ex;
+ } else if (ex === ENOENT) {
+ result = result || ex;
+ } else if (d) {
+ _.logger.error(ex);
}
- this.showDefaultNextStep(obChat);
+ done();
+ };
+ if (d && !_.logger) {
+ _.logger = new MegaLogger('attachNodes', {}, self.logger);
}
- showDefaultNextStep(obChat) {
- const nextIdx = obChat.searchNextOpenStep();
- if (nextIdx !== false && (!this.$obDialog || !this.$obDialog.is(':visible')) && (this.obToggleDrawn || $('.conversations-category', '.conversationsApp').length)) {
- this.obToggleDrawn = true;
- if (obChat.steps && obChat.steps[nextIdx] && obChat.steps[nextIdx].isComplete) {
- return;
- }
- obChat.startNextOpenSteps(nextIdx);
- this.$obDialog = this.$obDialog || $('#ob-dialog');
+ for (i = members.length; i--;) {
+ const usr = M.getUserByHandle(members[i]);
+ if (usr.u) {
+ users.push(usr.u);
}
}
- handleFlagChange(...args) {
- if (args.length >= 4 && typeof args[2] === 'string' && typeof args[3] === 'number' && this.state.hasOwnProperty(args[2])) {
- if (d) {
- console.debug(`Chat onboarding flag ${args[2]}: ${this.state[args[2]]} -> ${args[3]}`);
- }
- this.state[args[2]] = args[3];
- if (args[2] === OBV4_FLAGS.CHAT && args[3] === 1 && this.interval) {
- clearInterval(this.interval);
- delete this.interval;
+ for (i = nodes.length; i--;) {
+ const h = nodes[i];
+ const n = crypto_keyok(h) ? h : M.getNodeByHandle(h);
+ if (n.t) {
+ link[n.h] = 1;
+ continue;
+ }
+ if (n.hash) {
+ nmap[n.hash] = n;
+ if (names && names[n.h]) {
+ names[n.hash] = names[n.h];
}
}
- }
- destroy() {
- if (this.interval) {
- clearInterval(this.interval);
- delete this.interval;
+ let op = send;
+ if (n.u !== u_handle || M.getNodeRoot(n.h) === 'shares') {
+ op = copy;
}
+ op[n.h] = 1;
+ nmap[n.h] = n;
}
-}, (0,applyDecoratedDescriptor.A)(_class.prototype, "checkAndShowStep", [_dec], Object.getOwnPropertyDescriptor(_class.prototype, "checkAndShowStep"), _class.prototype), _class);
-
-// EXTERNAL MODULE: ./js/chat/ui/meetings/call.jsx + 11 modules
-const call = REQ_(3);
-;// ./js/chat/chat.jsx
-
-
-
-REQ_(623);
-REQ_(553);
-REQ_(269);
-
-
-
-
-const EMOJI_DATASET_VERSION = 5;
-const CHAT_ONHISTDECR_RECNT = "onHistoryDecrypted.recent";
-const LOAD_ORIGINALS = {
- 'image/gif': 25e6,
- 'image/png': 2e5,
- 'image/webp': 2e5
-};
-const CHATUIFLAGS_MAPPING = {
- 'convPanelCollapse': 'cPC'
-};
-function Chat() {
- const self = this;
- this.is_initialized = false;
- this.logger = MegaLogger.getLogger("chat");
- this.mbListeners = [];
- this.chats = new MegaDataMap();
- this.scheduledMeetings = new MegaDataMap();
- this.chatUIFlags = new MegaDataMap();
- this.$chatTreePanePs = [];
- this.initChatUIFlagsManagement();
- this.currentlyOpenedChat = null;
- this.currentlyOpenedView = null;
- this.lastOpenedChat = null;
- this.archivedChatsCount = 0;
- this.FORCE_EMAIL_LOADING = localStorage.fel;
- this.WITH_SELF_NOTE = mega.flags.ff_n2s || localStorage.withSelfNote;
- this._imageLoadCache = Object.create(null);
- this._imagesToBeLoaded = Object.create(null);
- this._imageAttributeCache = Object.create(null);
- this._queuedMccPackets = [];
- this._queuedMcsmPackets = {};
- this._queuedMessageUpdates = [];
- this._queuedChatRoomEvents = Object.create(null);
- this.handleToId = Object.create(null);
- this.publicChatKeys = Object.create(null);
- this.SOUNDS = {
- ALERT: 'alert_info_message',
- INCOMING_MSG: 'incoming_chat_message',
- INCOMING_CALL: 'incoming_voice_video_call',
- CALL_JOIN: 'user_join_call',
- CALL_LEFT: 'user_left_call',
- CALL_END: 'end_call',
- CALL_JOIN_WAITING: 'user_join_waiting',
- RECONNECT: 'reconnecting',
- SPEAKER_TEST: 'test_speaker'
- };
- this.options = {
- 'delaySendMessageIfRoomNotAvailableTimeout': 3000,
- 'plugins': {
- 'chatdIntegration': ChatdIntegration,
- 'callManager2': CallManager2,
- 'urlFilter': UrlFilter,
- 'emoticonShortcutsFilter': EmoticonShortcutsFilter,
- 'emoticonsFilter': EmoticonsFilter,
- 'callFeedback': CallFeedback,
- 'presencedIntegration': PresencedIntegration,
- 'persistedTypeArea': PersistedTypeArea,
- 'btRtfFilter': BacktickRtfFilter,
- 'rtfFilter': RtfFilter,
- 'richpreviewsFilter': RichpreviewsFilter,
- 'chatToastIntegration': ChatToastIntegration,
- 'chatStats': ChatStats,
- 'geoLocationLinks': GeoLocationLinks,
- meetingsManager,
- 'chatOnboarding': ChatOnboarding,
- 'userHelper': ChatUserHelper
- },
- 'chatNotificationOptions': {
- 'textMessages': {
- 'incoming-chat-message': {
- title: l.notif_title_incoming_msg,
- 'icon' (notificationObj) {
- return notificationObj.options.icon;
- },
- 'body' (notificationObj, params) {
- if (params.type === 'private') {
- return l.notif_body_incoming_msg.replace('%s', params.from);
- }
- return l.notif_body_incoming_msg_group.replace('%1', params.from).replace('%2', params.roomTitle);
- }
- },
- 'incoming-voice-video-call': {
- 'title': l[17878] || "Incoming call",
- 'icon' (notificationObj) {
- return notificationObj.options.icon;
- },
- 'body' (notificationObj, params) {
- return l[5893].replace('[X]', params.from);
- }
- },
- 'screen-share-error': {
- title: l.screenshare_failed_notif || 'You are no longer sharing your screen',
- icon: notificationObj => {
- return notificationObj.options.icon;
- },
- body: ''
- },
- 'upcoming-scheduled-occurrence': {
- title: ({
- options
- }) => {
- return options.meeting.title;
- },
- icon: `${staticpath}/images/mega/mega-icon.svg`,
- body: l.notif_body_scheduled_upcoming
- },
- 'starting-scheduled-occurrence': {
- title: ({
- options
- }) => {
- return options.meeting.title;
- },
- icon: `${staticpath}/images/mega/mega-icon.svg`,
- body: l.notif_body_scheduled_starting
- }
- },
- sounds: Object.values(this.SOUNDS)
- },
- 'chatStoreOptions': {
- 'autoPurgeMaxMessagesPerRoom': 1024
- }
- };
- this.SOUNDS.buffers = Object.create(null);
- this.plugins = {};
- self.filePicker = null;
- self._chatsAwaitingAps = {};
- MegaDataObject.call(this, {
- "currentlyOpenedChat": null,
- "activeCall": null,
- 'routingSection': null,
- 'routingSubSection': null,
- 'routingParams': null
- });
- this.routing = new ChatRouting(this);
- Object.defineProperty(this, 'hasSupportForCalls', {
- get () {
- return typeof SfuClient !== 'undefined' && typeof TransformStream !== 'undefined' && window.RTCRtpSender && !!RTCRtpSender.prototype.createEncodedStreams;
- }
- });
- this.minuteClockInterval = setInterval(() => this._syncChats(), 6e4);
- return this;
-}
-inherits(Chat, MegaDataObject);
-Object.defineProperty(Chat, 'mcf', {
- value: Object.create(null)
-});
-Object.defineProperty(Chat, 'mcsm', {
- value: Object.create(null)
-});
-Chat.prototype.init = promisify(function (resolve, reject) {
- const self = this;
- if (self.is_initialized) {
- self.destroy();
- }
- if (d) {
- console.time('megachat:plugins:init');
- }
- self.plugins = Object.create(null);
- self.plugins.chatNotifications = new ChatNotifications(self, self.options.chatNotificationOptions);
- self.plugins.chatNotifications.notifications.rebind('onAfterNotificationCreated.megaChat', () => {
- self.updateSectionUnreadCount();
- });
- Object.keys(self.options.plugins).forEach(plugin => {
- self.plugins[plugin] = new self.options.plugins[plugin](self);
- });
+ copy = Object.keys(copy);
+ send = Object.keys(send);
+ link = Object.keys(link);
if (d) {
- console.timeEnd('megachat:plugins:init');
+ _.logger.debug('copy:%d, send:%d, link:%d', copy.length, send.length, link.length, copy, send, link);
}
- $(document.body);
- if (!is_chatlink) {
- $(mega.ui.header.setStatus).rebind('mousedown.megachat', '.sub-menu.status button', function () {
- const presence = $(this).data("presence");
- self._myPresence = presence;
- const targetPresence = PresencedIntegration.cssClassToPresence(presence);
- self.plugins.presencedIntegration.setPresence(targetPresence);
- if (targetPresence !== UserPresence.PRESENCE.OFFLINE) {
- Object.keys(self.plugins.chatdIntegration.chatd.shards).forEach(k => {
- const v = self.plugins.chatdIntegration.chatd.shards[k];
- v.connectionRetryManager.requiresConnection();
- });
+ if (link.length) {
+ ++step;
+ Promise.resolve(mega.fileRequestCommon.storage.isDropExist(link)).then(res => {
+ if (res.length) {
+ return mega.fileRequest.showRemoveWarning(res);
}
- });
+ }).then(() => {
+ const createLink = h => M.createPublicLink(h).then(({
+ link
+ }) => this.sendMessage(link));
+ return Promise.all(link.map(createLink));
+ }).then(done).catch(fail);
}
- self.$container = $('.fm-chat-block');
- if (M.chat && !is_chatlink) {
- $('.activity-status-block, .activity-status').removeClass('hidden');
- $('.js-dropdown-account .status-dropdown').removeClass('hidden');
+ if (send.length) {
+ step++;
+ attach(send).then(done).catch(fail);
}
- if (is_chatlink) {
- const {
- ph,
- key
- } = is_chatlink;
- Chat.mcf[ph] = key;
- this.publicChatKeys[ph] = key;
+ if (copy.length) {
+ step++;
+ this._copyNodesToAttach(copy, nmap).then(res => attach(res)).then(done).catch(fail);
}
- const promises = [];
- const rooms = Object.keys(Chat.mcf);
- for (let i = rooms.length; i--;) {
- const roomId = rooms[i];
- const room = Chat.mcf[roomId];
- if (!this.publicChatKeys[rooms[i]]) {
- promises.push(self.plugins.chatdIntegration.openChat(room, true));
+ if (!step) {
+ if (d) {
+ _.logger.warn('Nothing to do here...');
}
- delete Chat.mcf[rooms[i]];
+ queueMicrotask(done);
}
- Promise.allSettled(promises).then(res => {
- const pub = Object.keys(this.publicChatKeys);
- return Promise.allSettled([res].concat(pub.map(pch => {
- return this.plugins.chatdIntegration.openChat(pch, true);
- })));
- }).then(res => {
- res = res[0].value.concat(res.slice(1));
- this.logger.info('chats settled...', res);
- if (is_mobile) {
- return;
- }
- if (is_chatlink) {
- const start = document.getElementById('startholder');
- this.flyoutStartHolder = start.querySelector('.flyout-holder') || mCreateElement('div', {
- class: 'flyout-holder'
- }, start);
- }
- const selector = is_chatlink ? '.chat-links-preview > .chat-app-container' : '.section.conversations';
- const rootDOMNode = this.rootDOMNode = document.querySelector(selector);
- const $$root = this.$$root = (0,ReactDOM_.createRoot)(rootDOMNode);
- $$root.render(REaCt().createElement(conversations.Ay.ConversationsApp, {
- megaChat: this,
- routingSection: this.routingSection,
- routingSubSection: this.routingSubSection,
- routingParams: this.routingParams
- }));
- this.onChatsHistoryReady().then(() => {
- const room = this.getCurrentRoom();
- if (room) {
- room.scrollToChat();
- }
- return room;
- }).dump('on-chat-history-loaded');
- this.is_initialized = true;
- this.registerUploadListeners();
- this.trigger('onInit');
- mBroadcaster.sendMessage('chat_initialized');
- setInterval(this.removeMessagesByRetentionTime.bind(this, null), 2e4);
- this.autoJoinIfNeeded();
- const scheduledMeetings = Object.values(Chat.mcsm);
- if (scheduledMeetings && scheduledMeetings.length) {
- for (let i = scheduledMeetings.length; i--;) {
- const scheduledMeeting = scheduledMeetings[i];
- this.plugins.meetingsManager.attachMeeting(scheduledMeeting);
- delete Chat.mcsm[scheduledMeeting.id];
- }
- }
- if (notify) {
- notify.countAndShowNewNotifications();
- }
- return true;
- }).then(resolve).catch(reject);
});
-Chat.prototype.showUpgradeDialog = function () {
- return is_extension ? msgDialog('warningb', l[1900], l[8841]) : msgDialog('confirmation', l[1900], l[8840], '', cb => cb && location.reload());
-};
-Chat.prototype._syncChats = function () {
- if (!this.is_initialized) {
- return;
- }
- this.plugins.meetingsManager.checkForNotifications();
+ChatRoom.prototype._copyNodesToAttach = async function (copy, nmap) {
const {
- chats,
- logger
- } = this;
- if (chats && chats.length) {
- chats.forEach(({
- chatId,
- scheduledMeeting
- }) => {
- const dnd = pushNotificationSettings.getDnd(chatId);
- if (dnd && dnd < unixtime()) {
- pushNotificationSettings.disableDnd(chatId);
- if (logger) {
- logger.debug(`Chat.prototype._syncDnd chatId=${chatId}`);
- }
- }
- const {
- isUpcoming,
- chatRoom,
- id
- } = scheduledMeeting || {};
- if (isUpcoming) {
- scheduledMeeting.setNextOccurrence();
- chatRoom.trackDataChange();
- if (logger) {
- logger.debug(`Chat.prototype.__syncScheduledMeetings id=${id} chatId=${chatId}`);
+ h: target
+ } = await M.myChatFilesFolder.get(true);
+ if (!M.c[target]) {
+ await dbfetch.get(target);
+ }
+ const dir = Object.keys(M.c[target] || {});
+ const rem = [];
+ for (let i = copy.length; i--;) {
+ const n = nmap[copy[i]] || M.getNodeByHandle(copy[i]);
+ console.assert(n.h, `Node not found.. ${copy[i]}`);
+ for (let y = dir.length; y--;) {
+ const b = M.getNodeByHandle(dir[y]);
+ if (n.h === b.h || b.hash === n.hash) {
+ if (d) {
+ this.logger.info('deduplication %s:%s', n.h, b.h, [n], [b]);
}
+ rem.push(n.h);
+ copy.splice(i, 1);
+ break;
}
+ }
+ }
+ let res = [];
+ if (copy.length) {
+ res = await M.copyNodes(copy, target, false, false, {
+ targetChatId: this.chatId
});
+ } else if (d) {
+ this.logger.info('No new nodes to copy.', rem);
}
-};
-Chat.prototype.loadChatUIFlagsFromConfig = function (val) {
- let hadChanged = false;
- let flags = val || mega.config.get("cUIF");
- if (flags) {
- if (typeof flags !== 'object') {
- flags = {};
+ assert(Array.isArray(res), `Unexpected response, ${res && res.message || res}`, res);
+ const [h] = res;
+ res = [...rem, ...res];
+ assert(res.length, 'Unexpected condition... nothing to attach ?!');
+ for (let i = res.length; i--;) {
+ const n = nmap[res[i]] || M.getNodeByHandle(res[i]);
+ if (n.fv) {
+ if (d) {
+ this.logger.info('Skipping file-version %s', n.h, n);
+ }
+ res.splice(i, 1);
}
- Object.keys(CHATUIFLAGS_MAPPING).forEach(k => {
- const v = flags[CHATUIFLAGS_MAPPING[k]];
- hadChanged = v !== undefined && this.chatUIFlags.set(k, v) !== false || hadChanged;
- });
}
- return hadChanged;
+ if (h && !res.length) {
+ if (d) {
+ this.logger.info('Adding nothing but a file-version?..', h);
+ }
+ res = [h];
+ }
+ return res;
};
-Chat.prototype.cleanup = function (clean) {
- const room = this.getCurrentRoom();
- if (room) {
- room.hide();
+ChatRoom.prototype.onUploadStart = function (data) {
+ const self = this;
+ if (d) {
+ self.logger.debug('onUploadStart', data);
}
- M.chat = false;
- this.routingParams = null;
- this.routingSection = null;
- this.routingSubSection = null;
- if (clean) {
- M.currentdirid = page = false;
+};
+ChatRoom.prototype.uploadFromComputer = function () {
+ this.scrolledToBottom = true;
+ $('#fileselect1').trigger('click');
+};
+ChatRoom.prototype.attachContacts = function (ids) {
+ for (let i = 0; i < ids.length; i++) {
+ const nodeId = ids[i];
+ const node = M.u[nodeId];
+ this.sendMessage(Message.MANAGEMENT_MESSAGE_TYPES.MANAGEMENT + Message.MANAGEMENT_MESSAGE_TYPES.CONTACT + JSON.stringify([{
+ u: node.u,
+ email: node.m,
+ name: node.name || node.m
+ }]));
}
};
-Chat.prototype.initChatUIFlagsManagement = function () {
+ChatRoom.prototype.getMessageById = function (messageId) {
const self = this;
- self.loadChatUIFlagsFromConfig();
- this.chatUIFlags.addChangeListener((hashmap, extraArg) => {
- const flags = mega.config.get("cUIF") || {};
- let hadChanged = false;
- let hadLocalChanged = false;
- Object.keys(CHATUIFLAGS_MAPPING).forEach((k) => {
- if (flags[CHATUIFLAGS_MAPPING[k]] !== self.chatUIFlags[k]) {
- if (extraArg === 0xDEAD) {
- self.chatUIFlags._data[k] = flags[CHATUIFLAGS_MAPPING[k]];
- hadLocalChanged = true;
- } else {
- flags[CHATUIFLAGS_MAPPING[k]] = self.chatUIFlags[k];
- hadChanged = true;
- }
- }
- });
- if (hadLocalChanged) {
- if (extraArg !== 0xDEAD) {
- self.chatUIFlags.trackDataChange(0xDEAD);
- }
- $.tresizer();
- }
- if (extraArg === 0xDEAD) {
- return;
- }
- if (hadChanged) {
- mega.config.set("cUIF", flags);
- }
- });
- this.mbListeners.push(mBroadcaster.addListener('fmconfig:cUIF', tryCatch(v => {
- if (self.loadChatUIFlagsFromConfig(v)) {
- self.chatUIFlags.trackDataChange(0xDEAD);
+ const msgs = self.messagesBuff.messages;
+ const msgKeys = msgs.keys();
+ for (let i = 0; i < msgKeys.length; i++) {
+ const k = msgKeys[i];
+ const v = msgs[k];
+ if (v && v.messageId === messageId) {
+ return v;
}
- })), mBroadcaster.addListener('statechange', state => {
- this.trigger('viewstateChange', state);
- }));
+ }
+ return false;
};
-Chat.prototype.unregisterUploadListeners = function (destroy) {
- 'use strict';
-
+ChatRoom.prototype.hasMessages = function (userMessagesOnly = false) {
+ return this.messagesBuff.messages.some(m => !userMessagesOnly || m.messageHtml);
+};
+ChatRoom.prototype.renderContactTree = function () {
const self = this;
- mBroadcaster.removeListener(self._uplDone);
- mBroadcaster.removeListener(self._uplError);
- mBroadcaster.removeListener(self._uplAbort);
- mBroadcaster.removeListener(self._uplFAError);
- mBroadcaster.removeListener(self._uplFAReady);
- if (destroy) {
- mBroadcaster.removeListener(self._uplStart);
+ const $navElement = self.getNavElement();
+ const $count = $('.nw-conversations-unread', $navElement);
+ const count = self.messagesBuff.getUnreadCount();
+ if (count > 0) {
+ $count.text(count > 9 ? "9+" : count);
+ $navElement.addClass("unread");
+ } else if (count === 0) {
+ $count.text("");
+ $navElement.removeClass("unread");
}
- delete self._uplError;
+ $navElement.data('chatroom', self);
};
-Chat.prototype.registerUploadListeners = function () {
+ChatRoom.prototype.getUnreadCount = function () {
const self = this;
- const logger = d && MegaLogger.getLogger('chatUploadListener', false, self.logger);
- const ufo = Object.create(null);
- self.unregisterUploadListeners(true);
- const forEachChat = function (chats, callback) {
- let result = 0;
- if (!Array.isArray(chats)) {
- chats = [chats];
+ return self.messagesBuff.getUnreadCount();
+};
+ChatRoom.prototype.recover = function () {
+ const self = this;
+ self.callRequest = null;
+ if (self.state !== ChatRoom.STATE.LEFT) {
+ self.membersLoaded = false;
+ self.setState(ChatRoom.STATE.JOINING, true);
+ self.megaChat.trigger("onRoomCreated", [self]);
+ return MegaPromise.resolve();
+ } else {
+ return MegaPromise.reject();
+ }
+};
+ChatRoom.prototype.showMissingUnifiedKeyDialog = function () {
+ return msgDialog(`warningb:!^${l.msg_dlg_cancel}!${l[23433]}`, null, l[200], l.chat_key_failed_dlg_text, reload => reload ? M.reload() : null, 1);
+};
+ChatRoom.prototype.hasInvalidKeys = function () {
+ if (!is_chatlink && this.type === 'public') {
+ const {
+ unifiedKey
+ } = this.protocolHandler || {};
+ if (!unifiedKey || unifiedKey && unifiedKey.length !== 16 || !this.ck || this.ck && this.ck.length !== 32) {
+ console.error('Error instantiating room/call -- missing `unifiedKey`/malformed `ck` for public chat.');
+ const {
+ owner,
+ actors
+ } = mBroadcaster.crossTab;
+ eventlog(99751, JSON.stringify([1, buildVersion.website || 'dev', String(this.chatId).length | 0, this.type | 0, this.isMeeting | 0, typeof unifiedKey, String(unifiedKey || '').length | 0, typeof this.ck, String(this.ck).length | 0, !!owner | 0, Object(actors).length | 0]));
+ return true;
}
- for (let i = chats.length; i--;) {
- const room = self.getRoomFromUrlHash(chats[i]);
- if (room) {
- callback(room, ++result);
- }
- }
- return result;
+ }
+ return false;
+};
+ChatRoom.prototype.joinCall = ChatRoom._fnRequireParticipantKeys(function (audio, video, callId) {
+ if (!megaChat.hasSupportForCalls || this.activeCallIds.length === 0 || this.meetingsLoading) {
+ return;
+ }
+ if (this.hasInvalidKeys()) {
+ return this.showMissingUnifiedKeyDialog();
+ }
+ this.meetingsLoading = {
+ title: l.joining,
+ audio,
+ video
};
- const lookupPendingUpload = function (id) {
- console.assert((id | 0) > 0 || String(id).length === 8, 'Invalid lookupPendingUpload arguments...');
- for (const uid in ulmanager.ulEventData) {
- if (ulmanager.ulEventData[uid].faid === id || ulmanager.ulEventData[uid].h === id) {
- return uid;
- }
- }
+ callId = callId || this.activeCallIds.keys()[0];
+ return asyncApiReq({
+ 'a': 'mcmj',
+ 'cid': this.chatId,
+ "mid": callId
+ }).then(r => {
+ this.startOrJoinCall(callId, r.url, audio, video, r.organiser);
+ });
+});
+ChatRoom.prototype.startOrJoinCall = function (callId, url, audio, video, organiser) {
+ tryCatch(() => {
+ const call = this.call = megaChat.activeCall = megaChat.plugins.callManager2.createCall(this, callId, this.protocolHandler.chatMode === strongvelope.CHAT_MODE.PUBLIC && str_to_ab(this.protocolHandler.unifiedKey));
+ call.setOrganiser(organiser);
+ return call.connect(url, audio, video);
+ }, ex => {
+ let _this$call;
+ (_this$call = this.call) == null || _this$call.destroy();
+ this.call = megaChat.activeCall = null;
+ this.meetingsLoading = false;
+ console.error('Failed to start/join call:', ex);
+ })();
+};
+ChatRoom.prototype.rejectCall = function (callId) {
+ if (this.activeCallIds.length === 0) {
+ return;
+ }
+ callId = callId || this.activeCallIds.keys()[0];
+ if (this.type === "private") {
+ return asyncApiReq({
+ 'a': 'mcme',
+ 'cid': this.chatId,
+ 'mid': callId
+ });
+ }
+ const shard = this.chatd.shards[this.chatShard];
+ if (shard) {
+ shard.sendCallReject(base64urldecode(this.chatId), base64urldecode(callId));
+ }
+ return Promise.resolve();
+};
+ChatRoom.prototype.ringUser = function (userId, callId, callstate) {
+ assert(userId, 'Missing user handle.');
+ assert(callId, 'Missing chat handle.');
+ assert(this.type !== 'private', 'Unexpected chat type.');
+ const shard = this.chatd.shards[this.chatShard];
+ if (shard) {
+ api.req({
+ a: 'mcru',
+ u: userId,
+ cid: this.chatId
+ }).then(() => shard.ringUser(this.chatIdBin, base64urldecode(userId), base64urldecode(callId), callstate)).catch(dump);
+ }
+};
+ChatRoom.prototype.endCallForAll = function (callId) {
+ if (this.activeCallIds.length && this.type !== 'private') {
+ callId = callId || this.activeCallIds.keys()[0];
+ asyncApiReq({
+ 'a': 'mcme',
+ 'cid': this.chatId,
+ 'mid': callId
+ });
+ eventlog(99761, JSON.stringify([this.chatId, callId, this.isMeeting | 0]));
+ }
+};
+ChatRoom.prototype.startAudioCall = function (scheduled) {
+ return this.startCall(true, false, scheduled);
+};
+ChatRoom.prototype.startVideoCall = function (scheduled) {
+ return this.startCall(true, true, scheduled);
+};
+ChatRoom.prototype.startCall = ChatRoom._fnRequireParticipantKeys(function (audio, video, scheduled) {
+ if (!megaChat.hasSupportForCalls || this.meetingsLoading) {
+ return;
+ }
+ if (this.activeCallIds.length > 0) {
+ this.joinCall(this.activeCallIds.keys()[0]);
+ return;
+ }
+ if (this.hasInvalidKeys()) {
+ return this.showMissingUnifiedKeyDialog();
+ }
+ this.meetingsLoading = {
+ title: l.starting,
+ audio,
+ video
};
- const unregisterListeners = function () {
- if (!$.len(ulmanager.ulEventData)) {
- self.unregisterUploadListeners();
- if (d) {
- logger.warn('Revoked upload listeners.');
- }
- }
+ const opts = {
+ a: 'mcms',
+ cid: this.chatId,
+ sm: scheduled && this.scheduledMeeting && this.scheduledMeeting.id
};
- const onUploadComplete = function (ul) {
- if (ulmanager.ulEventData[ul && ul.uid]) {
- forEachChat(ul.chat, (room) => {
- if (d) {
- logger.debug('Attaching node[%s] to chat room[%s]...', ul.h, room.chatId, ul.uid, ul, M.d[ul.h]);
- }
- room.attachNodes([ul.h]).catch(dump);
- });
- delete ulmanager.ulEventData[ul.uid];
- unregisterListeners();
- } else if (d) {
- logger.warn('could not complete upload...', ul);
+ if (localStorage.sfuId) {
+ opts.sfu = parseInt(localStorage.sfuId, 10);
+ }
+ return asyncApiReq(opts).then(r => {
+ this.startOrJoinCall(r.callId, r.sfu, audio, video, r.organiser);
+ }).catch(ex => {
+ this.meetingsLoading = false;
+ this.logger.error(`Failed to start call: ${ex}`);
+ });
+});
+ChatRoom.prototype.subscribeForCallEvents = function () {
+ const callMgr = megaChat.plugins.callManager2;
+ this.rebind("onChatdPeerJoinedCall.callManager", (e, data) => {
+ if (!this.activeCallIds.exists(data.callId)) {
+ this.activeCallIds.set(data.callId, []);
}
- };
- const onUploadCompletion = function (uid, handle, faid, chat) {
- if (!chat) {
- if (d > 1) {
- logger.debug('ignoring upload:completion that is unrelated to chat.', arguments);
+ this.activeCallIds.set(data.callId, [...this.activeCallIds[data.callId], ...data.participants]);
+ const parts = data.participants;
+ for (let i = 0; i < parts.length; i++) {
+ if (this.type === "private" || parts[i] === u_handle && this.ringingCalls.exists(data.callId)) {
+ this.ringingCalls.remove(data.callId);
+ callMgr.trigger("onRingingStopped", {
+ callId: data.callId,
+ chatRoom: this
+ });
}
+ }
+ megaChat.updateSectionUnreadCount();
+ this.callParticipantsUpdated();
+ });
+ this.rebind("onChatdPeerLeftCall.callManager", (e, data) => {
+ if (!this.activeCallIds[data.callId]) {
return;
}
- const n = M.getNodeByHandle(handle);
- const ul = ulmanager.ulEventData[uid] || false;
- if (d) {
- logger.info('upload:completion', uid, handle, faid, ul, n);
+ const parts = data.participants;
+ for (let i = 0; i < parts.length; i++) {
+ array.remove(this.activeCallIds[data.callId], parts[i], true);
+ if (parts[i] === u_handle && this.ringingCalls.exists(data.callId)) {
+ this.ringingCalls.remove(data.callId);
+ callMgr.trigger("onRingingStopped", {
+ callId: data.callId,
+ chatRoom: this
+ });
+ }
}
- if (!ul) {
+ this.callParticipantsUpdated();
+ });
+ this.rebind("onCallLeft.callManager", (e, data) => {
+ console.warn("onCallLeft:", JSON.stringify(data));
+ const {
+ call
+ } = this;
+ if (!call || call.callId !== data.callId) {
if (d) {
- logger.error('Upload event data store missing...', uid, n, ul);
- }
- } else {
- ul.h = handle;
- if (ul.efa && !n) {
- if (d) {
- logger.error('Invalid state, efa set on deduplication?', ul.efa, ul);
- }
- ul.efa = 0;
- } else if (ufo[faid]) {
- if (d) {
- logger.info(`Recovering fa:error state for ${faid}`, ufo[faid], ul.efa);
- }
- ul.efa = Math.max(0, ul.efa - ufo[faid]) | 0;
- }
- if (ul.efa && (!n.fa || String(n.fa).split('/').length < ul.efa)) {
- console.assert(!ul.faid || ul.faid === faid, `${faid} != ${ul.faid}`);
- ul.faid = faid;
- if (d) {
- logger.info('Waiting for file attribute to arrive.', handle, ul.efa, n.fa, n.name, ul, [n]);
- }
- } else {
- onUploadComplete(ul);
+ console.warn("... no active call or event not for it");
}
+ return;
}
- };
- const onUploadError = function (uid, error) {
- const ul = ulmanager.ulEventData[uid];
+ this.meetingsLoading = false;
+ call.hangUp(data.reason);
+ megaChat.activeCall = this.call = null;
+ });
+ this.rebind("onChatdCallEnd.callManager", (e, data) => {
if (d) {
- logger.debug(error === -0xDEADBEEF ? 'upload:abort' : 'upload.error', uid, error, [ul]);
+ console.warn("onChatdCallEnd:", JSON.stringify(data));
}
- if (ul) {
- delete ulmanager.ulEventData[uid];
- unregisterListeners();
- } else if (d) {
- logger.warn(`No upload association for #${uid}`, error);
+ this.meetingsLoading = false;
+ this.activeCallIds.remove(data.callId);
+ if (this.callUserLimited) {
+ this.callUserLimited.abort();
}
- };
- const onAttributeReady = function (handle, fa) {
- delay(`chat:fa-ready:${ handle}`, () => {
- const uid = lookupPendingUpload(handle);
- const ul = ulmanager.ulEventData[uid] || false;
- if (d) {
- logger.debug('fa:ready', handle, fa, ul.efa, uid, ul);
- }
- if (ul.h && String(fa).split('/').length >= ul.efa) {
- onUploadComplete(ul);
- } else if (d) {
- logger.debug('Not enough file attributes yet, holding...', handle, fa, ul.efa, ul);
- }
- });
- };
- const onAttributeError = function (faid, error, onStorageAPIError, nFAiled) {
- const uid = lookupPendingUpload(faid);
- const ul = ulmanager.ulEventData[uid] || false;
- if (d) {
- logger.debug('fa:error', faid, error, onStorageAPIError, uid, ul, nFAiled, ul.efa);
+ this.callUserLimited = false;
+ this.stopRinging(data.callId);
+ this.callParticipantsUpdated();
+ megaChat.updateSectionUnreadCount();
+ });
+ this.rebind('onCallState.callManager', function (e, data) {
+ const ac = this.activeCallIds[data.callId];
+ console.assert(ac, `unknown call: ${data.callId}`);
+ if (ac) {
+ callMgr.onCallState(data, this);
+ this.callParticipantsUpdated();
}
- if (ul) {
- ul.efa = Math.max(0, ul.efa - nFAiled) | 0;
- if (ul.h) {
- const n = M.getNodeByHandle(ul.h);
- if (!ul.efa || n.fa && String(n.fa).split('/').length >= ul.efa) {
- onUploadComplete(ul);
- }
- }
- } else {
- if (d) {
- logger.warn(`No upload association for ${faid} (yet?)`, nFAiled, error);
- }
- ufo[faid] = (ufo[faid] | 0) + nFAiled;
+ });
+ this.rebind('onRoomDisconnected.callManager', function () {
+ this.activeCallIds.clear();
+ megaChat.updateSectionUnreadCount();
+ if (navigator.onLine) {
+ return;
}
- };
- const registerLocalListeners = function () {
- self._uplError = mBroadcaster.addListener('upload:error', onUploadError);
- self._uplAbort = mBroadcaster.addListener('upload:abort', onUploadError);
- self._uplFAReady = mBroadcaster.addListener('fa:ready', onAttributeReady);
- self._uplFAError = mBroadcaster.addListener('fa:error', onAttributeError);
- self._uplDone = mBroadcaster.addListener('upload:completion', onUploadCompletion);
- };
- self._uplStart = mBroadcaster.addListener('upload:start', (data) => {
- if (d) {
- logger.info('onUploadStart', [data]);
+ if (this.call) {
+ this.trigger('ChatDisconnected', this);
}
- const notify = function (room) {
- room.onUploadStart(data);
- };
- for (const k in data) {
- const chats = data[k].chat;
- if (chats && forEachChat(chats, notify) && !self._uplError) {
- registerLocalListeners();
- }
+ this.callParticipantsUpdated();
+ });
+ this.rebind('onStateChange.callManager', function (e, oldState, newState) {
+ if (newState === ChatRoom.STATE.LEFT && this.call) {
+ this.call.hangUp(SfuClient.TermCode.kLeavingRoom);
}
});
-};
-Chat.prototype.getRoomFromUrlHash = function (urlHash) {
- if (urlHash.indexOf("#") === 0) {
- urlHash = urlHash.subtr(1, urlHash.length);
- }
- if (urlHash.indexOf("chat/g/") > -1 || urlHash.indexOf("chat/c/") > -1) {
- var foundRoom = null;
- urlHash = urlHash.replace("chat/g/", "").replace("chat/c/", "");
- megaChat.chats.forEach((room) => {
- if (!foundRoom && room.chatId === urlHash) {
- foundRoom = room;
- }
- });
- return foundRoom;
- } else if (urlHash.indexOf("chat/p/") > -1) {
- const contactHash = urlHash.replace("chat/p/", "");
- if (!contactHash) {
+ this.rebind('onCallPeerLeft.callManager', (e, data) => {
+ const {
+ call
+ } = this;
+ if (!call || call.isDestroyed || call.hasOtherParticipant() || SfuClient.isTermCodeRetriable(data.reason)) {
return;
}
- const chatRoom = this.getPrivateRoom(contactHash);
- return chatRoom;
- } else if (urlHash.indexOf("chat/") > -1 && urlHash[13] === "#") {
- var foundRoom = null;
- const pubHandle = urlHash.replace("chat/", "").split("#")[0];
- urlHash = urlHash.replace("chat/g/", "");
- const chatIds = megaChat.chats.keys();
- for (let i = 0; i < chatIds.length; i++) {
- const cid = chatIds[i];
- const room = megaChat.chats[cid];
- if (room.publicChatHandle === pubHandle) {
- foundRoom = room;
- break;
- }
- }
- return foundRoom;
- } else {
- return null;
- }
-};
-Chat.prototype.updateSectionUnreadCount = SoonFc(function () {
- if (!this.is_initialized) {
- return;
- }
- let unreadCount = 0;
- const notificationsCount = {
- unreadChats: 0,
- unreadMeetings: 0,
- unreadUpcoming: 0,
- chatsCall: false,
- meetingCall: false
- };
- let havePendingCall = false;
- let haveAdHocMessage = false;
- this.chats.forEach(chatRoom => {
- if (chatRoom.isArchived() || chatRoom.state === ChatRoom.STATE.LEFT) {
- return;
+ if (this.type === 'private') {
+ return this.trigger('onCallLeft', {
+ callId: call.callId
+ });
}
- const unreads = parseInt(chatRoom.messagesBuff.getUnreadCount(), 10);
- unreadCount += unreads;
- if (unreads) {
- notificationsCount[chatRoom.isMeeting ? 'unreadMeetings' : 'unreadChats'] += unreads;
- if (chatRoom.scheduledMeeting && chatRoom.scheduledMeeting.isUpcoming) {
- notificationsCount.unreadUpcoming += unreads;
+ setTimeout(() => {
+ if (this.call === call) {
+ this.call.initCallTimeout();
}
- }
- if (chatRoom.havePendingCall() && chatRoom.uniqueCallParts && !chatRoom.uniqueCallParts[u_handle]) {
- havePendingCall = true;
- if (chatRoom.isMeeting) {
- notificationsCount.meetingCall = true;
- if (!chatRoom.scheduledMeeting && unreads) {
- haveAdHocMessage = true;
- }
- } else {
- notificationsCount.chatsCall = true;
+ }, 3000);
+ });
+ this.rebind('onMeAdded', (e, addedBy) => {
+ if (this.activeCallIds.length > 0) {
+ const callId = this.activeCallIds.keys()[0];
+ if (this.ringingCalls.exists(callId)) {
+ return;
}
+ this.ringingCalls.set(callId, addedBy);
+ this.megaChat.trigger('onIncomingCall', [this, callId, addedBy, callMgr]);
+ this.fakedLocalRing = true;
+ setTimeout(() => {
+ delete this.fakedLocalRing;
+ if (this.ringingCalls.exists(callId)) {
+ callMgr.trigger("onRingingStopped", {
+ callId,
+ chatRoom: this
+ });
+ }
+ }, 30e3);
}
});
- unreadCount = unreadCount > 9 ? "9+" : unreadCount;
- if (!is_chatlink && mega.ui.header) {
- if (notificationsCount.unreadChats || notificationsCount.unreadUpcoming || haveAdHocMessage) {
- mega.ui.header.chatsButton.addClass('decorated');
- } else {
- mega.ui.header.chatsButton.removeClass('decorated');
- }
- const phoneIcon = mega.ui.header.domNode.querySelector('.top-chats-call');
- if (phoneIcon) {
- phoneIcon.classList[havePendingCall ? 'remove' : 'add']('hidden');
+};
+ChatRoom.prototype.stateIsLeftOrLeaving = function () {
+ return this.state == ChatRoom.STATE.LEFT || this.state == ChatRoom.STATE.LEAVING || (!is_chatlink && this.state === ChatRoom.STATE.READY && this.membersSetFromApi && !this.membersSetFromApi.members.hasOwnProperty(u_handle) || is_chatlink && !this.members.hasOwnProperty(u_handle));
+};
+ChatRoom.prototype._clearChatMessagesFromChatd = function () {
+ this.chatd.shards[this.chatShard].retention(base64urldecode(this.chatId), 1);
+};
+ChatRoom.prototype.isReadOnly = function () {
+ if (this.type === "private") {
+ const members = this.getParticipantsExceptMe();
+ if (members[0] && !Object(M.u[members[0]]).c) {
+ return true;
}
}
- if (this._lastUnreadCount !== unreadCount) {
- this._lastUnreadCount = unreadCount;
- notify.updateNotificationIndicator();
- }
- if (!this._lastNotifications || !shallowEqual(this._lastNotifications, notificationsCount)) {
- this._lastNotifications = notificationsCount;
- megaChat.trigger('onUnreadCountUpdate', notificationsCount);
+ return this.members && this.members[u_handle] <= 0 || !this.members.hasOwnProperty(u_handle) || this.privateReadOnlyChat || this.state === ChatRoom.STATE.LEAVING || this.state === ChatRoom.STATE.LEFT;
+};
+ChatRoom.prototype.iAmOperator = function () {
+ return this.type === 'private' || this.members && this.members[u_handle] === ChatRoom.MembersSet.PRIVILEGE_STATE.OPERATOR;
+};
+ChatRoom.prototype.iAmReadOnly = function () {
+ return this.type !== 'private' && this.members && this.members[u_handle] === ChatRoom.MembersSet.PRIVILEGE_STATE.READONLY;
+};
+ChatRoom.prototype.iAmWaitingRoomPeer = function () {
+ return this.options.w && !this.iAmOperator();
+};
+ChatRoom.prototype.didInteraction = function (user_handle, ts) {
+ const self = this;
+ const newTs = ts || unixtime();
+ if (user_handle === u_handle) {
+ Object.keys(self.members).forEach((user_handle) => {
+ const contact = M.u[user_handle];
+ if (contact && user_handle !== u_handle && contact.c === 1) {
+ setLastInteractionWith(contact.u, `1:${ newTs}`);
+ }
+ });
+ } else {
+ const contact = M.u[user_handle];
+ if (contact && user_handle !== u_handle && contact.c === 1) {
+ setLastInteractionWith(contact.u, `1:${ newTs}`);
+ }
}
-}, 100);
-Chat.prototype.dropAllDatabases = promisify(function (resolve, reject) {
- const chatd = this.plugins.chatdIntegration.chatd || false;
- const promises = [];
- if (chatd.chatdPersist) {
- promises.push(chatd.chatdPersist.drop());
+};
+ChatRoom.prototype.retrieveAllHistory = function () {
+ const self = this;
+ self.messagesBuff.retrieveChatHistory().done(() => {
+ if (self.messagesBuff.haveMoreHistory()) {
+ self.retrieveAllHistory();
+ }
+ });
+};
+ChatRoom.prototype.seedRoomKeys = async function (keys) {
+ assert(Array.isArray(keys) && keys.length, `Invalid keys parameter for seedRoomKeys.`, keys);
+ if (d > 2) {
+ this.logger.warn('Seeding room keys...', keys);
}
- if ('messagesQueueKvStorage' in chatd) {
- promises.push(chatd.messagesQueueKvStorage.destroy());
+ const promises = [ChatdIntegration._ensureKeysAreLoaded(keys, undefined, this.publicChatHandle)];
+ if (!this.protocolHandler) {
+ promises.push(ChatdIntegration._waitForProtocolHandler(this));
}
- if (Reactions.ready) {
- promises.push(Reactions._db.destroy());
+ if (!this.notDecryptedKeys) {
+ this.notDecryptedKeys = Object.create(null);
}
- if (PersistedTypeArea.ready) {
- promises.push(PersistedTypeArea._db.destroy());
+ for (let i = keys.length; i--;) {
+ const {
+ key,
+ keyid,
+ keylen,
+ userId
+ } = keys[i];
+ this.notDecryptedKeys[`${userId}-${keyid}`] = {
+ userId,
+ keyid,
+ keylen,
+ key
+ };
}
- Promise.allSettled(promises).then(resolve).catch(reject);
-});
-Chat.prototype.destroy = function (isLogout) {
- if (!this.is_initialized) {
- return;
- }
- this.isLoggingOut = isLogout;
- for (let i = 0; i < this.mbListeners.length; i++) {
- mBroadcaster.removeListener(this.mbListeners[i]);
- }
- this.unregisterUploadListeners(true);
- this.trigger('onDestroy', [isLogout]);
- tryCatch(() => this.$$root.unmount())();
- this.chats.forEach((chatRoom, chatId) => {
- if (!isLogout) {
- chatRoom.destroy(false, true);
+ const promise = this._keysAreSeeding = Promise.all(promises).then(() => {
+ const res = this.protocolHandler.seedKeys(keys);
+ for (let i = res.length; i--;) {
+ delete this.notDecryptedKeys[res[i]];
+ }
+ return res;
+ }).catch(ex => {
+ this.logger.error('Failed to seed room keys!', ex, keys);
+ throw ex;
+ }).finally(() => {
+ if (promise === this._keysAreSeeding) {
+ delete this._keysAreSeeding;
}
- this.chats.remove(chatId);
});
- this.is_initialized = false;
- if (this.plugins.chatdIntegration && this.plugins.chatdIntegration.chatd && this.plugins.chatdIntegration.chatd.shards) {
- const {
- shards
- } = this.plugins.chatdIntegration.chatd;
- Object.keys(shards).forEach(shard => shards[shard].connectionRetryManager.options.functions.forceDisconnect());
- }
- for (const pluginName in this.plugins) {
- const plugin = this.plugins[pluginName];
- if (plugin.destroy) {
- plugin.destroy();
+ return promise;
+};
+ChatRoom.prototype.truncate = function () {
+ const self = this;
+ const chatMessages = self.messagesBuff.messages;
+ if (chatMessages.length > 0) {
+ let lastChatMessageId = null;
+ let i = chatMessages.length - 1;
+ while (lastChatMessageId == null && i >= 0) {
+ const message = chatMessages.getItem(i);
+ if (message instanceof Message && message.dialogType !== "truncated") {
+ lastChatMessageId = message.messageId;
+ }
+ i--;
+ }
+ if (lastChatMessageId) {
+ asyncApiReq({
+ a: 'mct',
+ id: self.chatId,
+ m: lastChatMessageId,
+ v: Chatd.VERSION
+ }).catch(ex => {
+ if (ex === -2) {
+ msgDialog('warninga', l[135], l[8880]);
+ }
+ });
}
- }
- if (this.minuteClockInterval) {
- clearInterval(this.minuteClockInterval);
- }
- if (megaChat.flyoutStartHolder && mega.ui.flyout) {
- mega.ui.flyout.reinit(megaChat.flyoutStartHolder);
- delete megaChat.flyoutStartHolder;
}
};
-Chat.prototype.getContacts = function () {
- const results = [];
- M.u.forEach((k, v) => {
- if (v.c == 1 || v.c == 2) {
- results.push(v);
- }
+ChatRoom.prototype.getActiveCalls = function () {
+ return this.activeCallIds.map((parts, id) => {
+ return parts.indexOf(u_handle) > -1 ? id : undefined;
});
- return results;
};
-Chat.prototype.userPresenceToCssClass = function (presence) {
- if (presence === UserPresence.PRESENCE.ONLINE) {
- return 'online';
- } else if (presence === UserPresence.PRESENCE.AWAY) {
- return 'away';
- } else if (presence === UserPresence.PRESENCE.DND) {
- return 'busy';
- } else if (presence === UserPresence.PRESENCE.OFFLINE) {
- return 'offline';
- } else {
- return 'black';
+ChatRoom.prototype.haveActiveCall = function () {
+ return this.getActiveCalls().length > 0;
+};
+ChatRoom.prototype.haveActiveOnHoldCall = function () {
+ const activeCallIds = this.getActiveCalls();
+ for (let i = 0; i < activeCallIds.length; i++) {
+ const call = megaChat.plugins.callManager2.calls[`${this.chatId }_${ activeCallIds[i]}`];
+ if (call && call.av & SfuClient.Av.onHold) {
+ return true;
+ }
+ }
+ return false;
+};
+ChatRoom.prototype.havePendingGroupCall = function () {
+ if (this.type !== "group" && this.type !== "public") {
+ return false;
}
+ return this.activeCallIds.length > 0;
};
-Chat.prototype._renderMyStatus = function () {
+ChatRoom.prototype.havePendingCall = function () {
+ return this.activeCallIds.length > 0;
+};
+ChatRoom.prototype.getActiveCallMessageId = function (ignoreActive) {
const self = this;
- if (!self.is_initialized) {
- return;
+ if (!ignoreActive && !self.havePendingCall() && !self.haveActiveCall()) {
+ return false;
}
- if (typeof megaChat.userPresence === 'undefined') {
- return;
+ const msgs = self.messagesBuff.messages;
+ for (let i = msgs.length - 1; i >= 0; i--) {
+ const msg = msgs.getItem(i);
+ if (msg.dialogType === "remoteCallEnded") {
+ return false;
+ }
+ if (msg.dialogType === "remoteCallStarted") {
+ return msg.messageId;
+ }
}
- const $status = $('.activity-status-block .activity-status', 'body');
- $('.top-user-status-popup .dropdown-item').removeClass("active");
- $status.removeClass('online').removeClass('away').removeClass('busy').removeClass('offline').removeClass('black');
- const actualPresence = self.plugins.presencedIntegration.getMyPresenceSetting();
- const userPresenceConRetMan = megaChat.userPresence.connectionRetryManager;
- const presence = self.plugins.presencedIntegration.getMyPresence();
- let cssClass = PresencedIntegration.presenceToCssClass(presence);
- if (userPresenceConRetMan.getConnectionState() !== ConnectionRetryManager.CONNECTION_STATE.CONNECTED) {
- cssClass = "offline";
+};
+ChatRoom.prototype.stopRinging = function (callId) {
+ if (this.ringingCalls.exists(callId)) {
+ this.ringingCalls.remove(callId);
}
- const $activityStatus = $('.activity-text', '.js-topbar');
- if (actualPresence === UserPresence.PRESENCE.ONLINE) {
- $('.top-user-status-popup .dropdown-item[data-presence="chat"]').addClass("active");
- $activityStatus.text(l[5923]);
- } else if (actualPresence === UserPresence.PRESENCE.AWAY) {
- $('.top-user-status-popup .dropdown-item[data-presence="away"]').addClass("active");
- $activityStatus.text(l[5924]);
- } else if (actualPresence === UserPresence.PRESENCE.DND) {
- $('.top-user-status-popup .dropdown-item[data-presence="dnd"]').addClass("active");
- $activityStatus.text(l[5925]);
- } else if (actualPresence === UserPresence.PRESENCE.OFFLINE) {
- $('.top-user-status-popup .dropdown-item[data-presence="unavailable"]').addClass("active");
- $activityStatus.text(l[5926]);
- } else {
- $('.top-user-status-popup .dropdown-item[data-presence="unavailable"]').addClass("active");
- $activityStatus.text(l[5926]);
+ megaChat.plugins.callManager2.trigger("onRingingStopped", {
+ callId,
+ chatRoom: this
+ });
+};
+ChatRoom.prototype.callParticipantsUpdated = function () {
+ const self = this;
+ let msgId = self.getActiveCallMessageId();
+ if (!msgId) {
+ msgId = self.getActiveCallMessageId(true);
}
- $status.addClass(cssClass);
- if (userPresenceConRetMan.getConnectionState() === ConnectionRetryManager.CONNECTION_STATE.CONNECTING) {
- $status.parent().addClass("fadeinout");
- } else {
- $status.parent().removeClass("fadeinout");
+ const callParts = self.getCallParticipants() || [];
+ self.uniqueCallParts = {};
+ for (let i = 0; i < callParts.length; i++) {
+ self.uniqueCallParts[callParts[i]] = true;
+ }
+ if (this.callUserLimited && this.canJoinLimitedCall()) {
+ this.callUserLimited.abort();
+ this.callUserLimited = false;
}
+ const msg = self.messagesBuff.getMessageById(msgId);
+ msg && msg.wrappedChatDialogMessage && msg.wrappedChatDialogMessage.trackDataChange();
+ self.trackDataChange();
};
-Chat.prototype.renderMyStatus = SoonFc(Chat.prototype._renderMyStatus, 100);
-Chat.prototype.openChat = function (userHandles, type, chatId, chatShard, chatdUrl, setAsActive, chatHandle, publicChatKey, ck, isMeeting, mcoFlags, organiser) {
+ChatRoom.prototype.onPublicChatRoomInitialized = function () {
const self = this;
- let room = false;
- type = type || "private";
- setAsActive = setAsActive === true;
- let roomId = chatId;
- if (!publicChatKey && chatHandle && self.publicChatKeys[chatHandle]) {
- if (type !== "public") {
- console.error("this should never happen.", type);
- type = "public";
- }
- publicChatKey = self.publicChatKeys[chatHandle];
- }
- const $promise = new MegaPromise();
- if (type === "private") {
- this.initContacts(userHandles, 2);
- roomId = userHandles.length > 1 ? array.one(userHandles, u_handle) : u_handle;
- if (self.chats[roomId]) {
- $promise.resolve(roomId, self.chats[roomId]);
- return [roomId, self.chats[roomId], $promise];
- }
- } else {
- assert(roomId, 'Tried to create a group chat, without passing the chatId.');
- roomId = chatId;
+ if (self.type !== "public" || !localStorage.autoJoinOnLoginChat) {
+ return;
}
- if (type === "group" || type === "public") {
- if (d) {
- console.time(`openchat:${ chatId }.${ type}`);
- }
- const newUsers = this.initContacts(userHandles);
- if (newUsers.length) {
- const chats = self.chats._data;
- if (d) {
- console.debug('openchat:%s.%s: processing %s new users...', chatId, type, newUsers.length);
- }
- for (const k in chats) {
- const chatRoom = self.chats[k];
- const participants = array.to.object(chatRoom.getParticipantsExceptMe());
- for (let j = newUsers.length; j--;) {
- const u = newUsers[j];
- if (participants[u]) {
- chatRoom.trackDataChange();
- break;
- }
+ const autoLoginChatInfo = tryCatch(JSON.parse.bind(JSON))(localStorage.autoJoinOnLoginChat) || false;
+ if (autoLoginChatInfo[0] === self.publicChatHandle) {
+ localStorage.removeItem("autoJoinOnLoginChat");
+ if (unixtime() - 7200 < autoLoginChatInfo[1]) {
+ const doJoinEventually = function (state) {
+ if (state === ChatRoom.STATE.READY) {
+ self.joinViaPublicHandle();
+ self.unbind(`onStateChange.${ self.publicChatHandle}`);
}
- }
- self.renderMyStatus();
- }
- if (d) {
- console.timeEnd(`openchat:${ chatId }.${ type}`);
- }
- if (type === "group") {
- ChatdIntegration._ensureKeysAreLoaded([], userHandles, chatHandle).catch(dump);
+ };
+ self.rebind(`onStateChange.${ self.publicChatHandle}`, (e, oldState, newState) => {
+ doJoinEventually(newState);
+ });
+ doJoinEventually(self.state);
}
- ChatdIntegration._ensureContactExists(userHandles, chatHandle);
}
- if (self.chats[roomId]) {
- room = self.chats[roomId];
- if (setAsActive) {
- room.show();
- }
- $promise.resolve(roomId, room);
- return [roomId, room, $promise];
- }
- if (setAsActive && self.currentlyOpenedChat && self.currentlyOpenedChat !== roomId) {
- self.hideChat(self.currentlyOpenedChat);
- self.currentlyOpenedChat = null;
- }
- room = new ChatRoom(self, roomId, type, userHandles, unixtime(), undefined, chatId, chatShard, chatdUrl, null, chatHandle, publicChatKey, ck, isMeeting, 0, mcoFlags, organiser);
- self.chats.set(room.roomId, room);
- if (setAsActive && !self.currentlyOpenedChat || self.currentlyOpenedChat === room.roomId) {
- room.setActive();
- }
- room.showAfterCreation = setAsActive !== false;
- return [roomId, room, new Promise((resolve, reject) => {
- this.trigger('onRoomInitialized', [room, resolve, reject]);
- room.setState(ChatRoom.STATE.JOINING);
- const q = this._queuedChatRoomEvents[chatId];
- if (q) {
- delete this._queuedChatRoomEvents[chatId];
- for (let i = 0; i < q.length; ++i) {
- const [event, data] = q[i];
- if (d) {
- this.logger.debug(`Dispatching deferred event '${event}'`, data);
- }
- room.trigger(event, data);
- }
- q.timer.abort();
- }
- this.processQueuedMcsmPackets();
- })];
};
-Chat.prototype.initContacts = function (userHandles, c) {
- const newUsers = [];
- for (let i = userHandles.length; i--;) {
- const u = userHandles[i];
- const e = u in M.u;
- M.addUser(e ? {
- u
- } : {
- u,
- c
- }, e || !newUsers.push(u));
+ChatRoom.prototype.isUIMounted = function () {
+ return this._uiIsMounted;
+};
+ChatRoom.prototype.attachSearch = function () {
+ this.activeSearches++;
+};
+ChatRoom.prototype.detachSearch = function () {
+ if (--this.activeSearches === 0) {
+ this.messagesBuff.detachMessages();
}
- return newUsers;
+ this.activeSearches = Math.max(this.activeSearches, 0);
+ this.trackDataChange();
};
-Chat.prototype.smartOpenChat = function (...args) {
+ChatRoom.prototype.scrollToMessageId = function (msgId, index, retryActive) {
const self = this;
- if (typeof args[0] === 'string') {
- args[0] = [u_handle, args[0]];
- if (args.length < 2) {
- args.push('private');
- }
+ if (!self.isCurrentlyActive && !retryActive) {
+ tSleep(1.5).then(() => {
+ self.scrollToMessageId(msgId, index, true);
+ });
+ return;
}
- return new Promise((resolve, reject) => {
- const waitForReadyState = function (aRoom, aShow) {
- const verify = function () {
- return aRoom.state === ChatRoom.STATE.READY;
- };
- const ready = function () {
- if (aShow) {
- aRoom.show();
- }
- resolve(aRoom);
- };
- if (verify()) {
- return ready();
- }
- const {
- roomId
- } = aRoom;
- createTimeoutPromise(verify, 300, 3e4, false, `waitForReadyState(${roomId})`).then(ready).catch(reject);
- };
- const [members, type] = args;
- if (members.length === 2 && type === 'private') {
- const chatRoom = self.chats[members.every(h => h === members[0]) ? u_handle : array.one(members, u_handle)];
- if (chatRoom) {
- if (args[5]) {
- chatRoom.show();
- }
- return waitForReadyState(chatRoom, args[5]);
- }
- }
- const result = self.openChat.apply(self, args);
- if (result instanceof MegaPromise) {
- result.then(reject).catch(reject);
- } else if (!Array.isArray(result)) {
- reject(EINTERNAL);
- } else {
- const room = result[1];
- const roomId = result[0];
- const promise = result[2];
- if (!(promise instanceof Promise)) {
- self.logger.error('Unexpected openChat() response...');
- return reject(EINTERNAL);
- }
- self.logger.debug('Waiting for chat "%s" to be ready...', roomId, [room]);
- promise.then(aRoom => {
- const aRoomId = aRoom && aRoom.roomId;
- if (aRoomId !== roomId || room && room !== aRoom || !(aRoom instanceof ChatRoom)) {
- self.logger.error('Unexpected openChat() procedure...', aRoomId, [aRoom]);
- return reject(EINTERNAL);
- }
- waitForReadyState(aRoom);
- }).catch(ex => {
- if (ex === EACCESS) {
- room.destroy();
- }
- reject(ex);
+ assert(self.isCurrentlyActive, 'chatRoom is not visible');
+ self.isScrollingToMessageId = true;
+ if (!self.$rConversationPanel) {
+ self.one(`onHistoryPanelComponentDidMount.scrollToMsgId${ msgId}`, () => {
+ self.scrollToMessageId(msgId, index);
+ });
+ return;
+ }
+ const ps = self.$rConversationPanel.messagesListScrollable;
+ assert(ps);
+ const msgObj = self.messagesBuff.getMessageById(msgId);
+ if (msgObj) {
+ const elem = $(`.${ msgId }.message.body`)[0];
+ self.scrolledToBottom = false;
+ ps.scrollToElement(elem, true);
+ self.$rConversationPanel.lastScrollPosition = undefined;
+ self.isScrollingToMessageId = false;
+ } else if (self.messagesBuff.isRetrievingHistory) {
+ self.one(`onHistoryDecrypted.scrollToMsgId${ msgId}`, () => {
+ self.one(`onComponentDidUpdate.scrollToMsgId${ msgId}`, () => {
+ self.scrollToMessageId(msgId, index);
});
- }
- });
-};
-Chat.prototype.hideAllChats = function () {
- const self = this;
- self.chats.forEach(chatRoom => {
- if (chatRoom.isCurrentlyActive) {
- chatRoom.hide();
- }
- });
-};
-Chat.prototype.retrieveSharedFilesHistory = async function (len = 47, chatRoom = null) {
- chatRoom = len instanceof ChatRoom ? len : chatRoom || this.getCurrentRoom();
- return chatRoom.messagesBuff.retrieveSharedFilesHistory(len);
-};
-Chat.prototype.getCurrentRoom = function () {
- return this.chats[this.currentlyOpenedChat];
-};
-Chat.prototype.getCurrentMeeting = function () {
- const chatRoom = this.getCurrentRoom();
- return chatRoom && chatRoom.scheduledMeeting || null;
-};
-Chat.prototype.getCurrentRoomJid = function () {
- return this.currentlyOpenedChat;
-};
-Chat.prototype.hideChat = function (roomJid) {
- const self = this;
- const room = self.chats[roomJid];
- if (room) {
- room.hide();
+ });
+ } else if (self.messagesBuff.haveMoreHistory()) {
+ self.messagesBuff.retrieveChatHistory(!index || index <= 0 ? undefined : index);
+ ps.doProgramaticScroll(0, true);
+ self.one(`onHistoryDecrypted.scrollToMsgId${ msgId}`, () => {
+ self.one(`onComponentDidUpdate.scrollToMsgId${ msgId}`, () => {
+ self.scrollToMessageId(msgId);
+ });
+ });
} else {
- self.logger.warn("Room not found: ", roomJid);
+ self.isScrollingToMessageId = false;
}
};
-Chat.prototype.sendMessage = function (roomJid, val) {
- const fail = ex => {
- this.logger.error(`sendMessage(${roomJid}) failed.`, ex);
+ChatRoom.prototype.setMcoFlags = function (flags) {
+ const req = {
+ a: 'mco',
+ cid: this.chatId,
+ ...flags
};
- if (!this.chats[roomJid]) {
- this.logger.warn("Queueing message for room: ", roomJid, val);
- const timeout = this.options.delaySendMessageIfRoomNotAvailableTimeout;
- return createTimeoutPromise(() => !!this.chats[roomJid], 500, timeout).then(() => {
- return this.chats[roomJid].sendMessage(val);
- }).catch(fail);
+ asyncApiReq(req).dump('roomSetCallFlags');
+};
+ChatRoom.prototype.toggleOpenInvite = function () {
+ if (this.type === 'private' || !this.iAmOperator()) {
+ return;
}
- return this.chats[roomJid].sendMessage(val).catch(fail);
+ this.setMcoFlags({
+ [MCO_FLAGS.OPEN_INVITE]: Math.abs(this.options[MCO_FLAGS.OPEN_INVITE] - 1)
+ });
};
-Chat.prototype.processNewUser = function (u, isNewChat) {
- const self = this;
- if (self.plugins.presencedIntegration) {
- const user = M.u[u] || false;
- if (user.c === 1) {
- self.plugins.presencedIntegration.addContact(u, isNewChat);
- }
+ChatRoom.prototype.toggleWaitingRoom = function () {
+ if (this.type === 'private' || !this.iAmOperator()) {
+ return;
}
- self.chats.forEach((chatRoom) => {
- if (chatRoom.getParticipantsExceptMe().indexOf(u) > -1) {
- chatRoom.trackDataChange();
- }
+ this.setMcoFlags({
+ [MCO_FLAGS.WAITING_ROOM]: Math.abs(this.options[MCO_FLAGS.WAITING_ROOM] - 1)
});
- self.renderMyStatus();
};
-Chat.prototype.processRemovedUser = function (u) {
- const self = this;
- if (self.plugins.presencedIntegration) {
- self.plugins.presencedIntegration.removeContact(u);
+ChatRoom.prototype.exportToFile = function () {
+ if (this.messagesBuff.messages.length === 0 || this.exportIo) {
+ return;
}
- self.chats.forEach((chatRoom) => {
- if (chatRoom.getParticipantsExceptMe().indexOf(u) > -1) {
- chatRoom.trackDataChange();
+ loadingDialog.show('chat_export');
+ eventlog(99874);
+ this._exportChat().then(() => {
+ eventlog(99875, JSON.stringify([1]));
+ }).catch(ex => {
+ if (d) {
+ console.warn('Chat export: ', ex);
+ }
+ const report = [String(ex && ex.message || ex).replace(/\s+/g, '').substring(0, 64)];
+ report.unshift(report[0] === 'Aborted' ? 1 : 0);
+ if (!report[0]) {
+ msgDialog('error', '', l.export_chat_failed, '', undefined, 1);
}
+ eventlog(99875, JSON.stringify(report));
+ }).finally(() => {
+ loadingDialog.hide('chat_export');
+ this.isScrollingToMessageId = false;
+ onIdle(() => this.messagesBuff.detachMessages());
});
- self.renderMyStatus();
};
-Chat.prototype.refreshConversations = function () {
- const self = this;
- if (!u_type && !self.$container && !megaChatIsReady) {
- $('.fm-chat-block').hide();
- return false;
- }
- $('.section.conversations .fm-chat-is-loading').addClass('hidden');
- if (self.$container.parent('.section.conversations .fm-right-files-block').length == 0) {
- $('.section.conversations .fm-right-files-block').append(self.$container);
- }
- self.$leftPane = self.$leftPane || $('.conversationsApp .fm-left-panel');
- if (is_chatlink || megaChat._joinDialogIsShown) {
- self.$leftPane.addClass('hidden');
- } else {
- self.$leftPane.removeClass('hidden');
- }
-};
-Chat.prototype.navigate = function megaChatNavigate(location, event, isLandingPage) {
- return new Promise((resolve, reject) => {
- this.routing.route(resolve, reject, location, event, isLandingPage);
- });
-};
-if (is_mobile) {
- Chat.prototype.navigate = function (location, event, isLandingPage) {
- if (d) {
- this.logger.warn('mobile-nop navigate(%s)', location, event, isLandingPage);
- }
- if (is_chatlink) {
- mobile.chatlink.show(is_chatlink.ph, is_chatlink.key);
- } else {
- loadSubPage('fm', event);
- }
- return Promise.resolve();
- };
-}
-Chat.prototype.renderListing = async function megaChatRenderListing(location, isInitial) {
- if (!isInitial && !M.chat) {
- console.debug('renderListing: Not in chat.');
- throw EACCESS;
- }
- M.hideEmptyGrids();
- this.refreshConversations();
- this.hideAllChats();
- if (!is_chatlink && mega.ui.flyout && (mega.ui.flyout.name.startsWith('contact') || mega.ui.flyout.name === 'chat')) {
- mega.ui.flyout.hide();
+ChatRoom.prototype._exportChat = async function () {
+ this.isScrollingToMessageId = true;
+ while (this.messagesBuff.haveMoreHistory()) {
+ await this.messagesBuff.retrieveChatHistory(100);
}
- $('.files-grid-view').addClass('hidden');
- $('.fm-blocks-view').addClass('hidden');
- $('.fm-chat-block').addClass('hidden');
- $('.fm-right-files-block').addClass('hidden');
- $('.fm-right-files-block.in-chat').removeClass('hidden');
- $('.nw-conversations-item').removeClass('selected');
- $('.fm-empty-conversations').removeClass('hidden');
- M.onSectionUIOpen('conversations');
- let room;
- if (!location && this.chats.length) {
- const valid = room => room && room._leaving !== true && !room.isNote && room.isDisplayable() && room;
- room = valid(this.chats[this.lastOpenedChat]);
- if (!room) {
- let idx = 0;
- const rooms = Object.values(this.chats).filter(r => this.currentlyOpenedView === null || r.isMeeting === !!this.currentlyOpenedView).sort(M.sortObjFn('lastActivity', -1));
- do {
- room = valid(rooms[idx]);
- } while (!room && ++idx < rooms.length);
- }
- if (room) {
- location = room.getRoomUrl();
+ await Promise.allSettled([this.messagesBuff.isDecrypting || Promise.resolve(), this.messagesBuff.$sharedFilesLoading || Promise.resolve(), this.messagesBuff.$isDecryptingSharedFiles || Promise.resolve()]);
+ do {
+ await this.messagesBuff.retrieveSharedFilesHistory(100);
+ } while (this.messagesBuff.haveMoreSharedFiles);
+ let withMedia = !!M.v.length;
+ if (withMedia) {
+ withMedia = await asyncMsgDialog(`*confirmation:!^${l.export_chat_media_dlg_conf}!${l.export_chat_media_dlg_rej}`, '', l.export_chat_media_dlg_title, l.export_chat_media_dlg_text);
+ if (withMedia === null) {
+ throw new Error('Aborted');
}
}
- if (location) {
- $('.fm-empty-conversations').addClass('hidden');
- return this.navigate(location, undefined, isInitial).catch(ex => {
- if (d) {
- this.logger.warn('Failed to navigate to %s...', location, room, ex);
+ let {
+ attachNodes,
+ stringNodes
+ } = this.messagesBuff.getExportContent(withMedia);
+ stringNodes = stringNodes.join('\n');
+ const basename = M.getSafeName(this.getRoomTitle());
+ const zname = l.export_chat_zip_file.replace('%s', basename);
+ const bufferName = l.export_chat_text_file.replace('%s', basename);
+ if (attachNodes.length) {
+ const p = [];
+ const n = [];
+ let s = 0;
+ for (const node of attachNodes) {
+ s += node.s;
+ if (node.ph) {
+ p.push(node.ph);
+ } else {
+ n.push(node.h);
}
- if (!room) {
- return this.renderListing(null);
+ }
+ const res = await asyncApiReq({
+ a: 'qbq',
+ s,
+ n,
+ p
+ });
+ if (res === 1 || res === 2) {
+ const fallback = await asyncMsgDialog('confirmation', '', l.export_chat_media_obq_title, l.export_chat_media_obq_text);
+ if (fallback) {
+ return M.saveAs(stringNodes, bufferName);
}
- onIdle(() => {
- room.destroy();
+ } else if (res === 0) {
+ await M.require('clientzip_js');
+ const data = new TextEncoder().encode(stringNodes);
+ const dl = {
+ size: data.byteLength + s,
+ n: bufferName,
+ t: unixtime(),
+ id: this.chatId,
+ p: '',
+ io: Object.create(null),
+ writer: Object.create(null),
+ offset: 0,
+ zname
+ };
+ const io = await (0,_utils_jsx0__ .O1)(dl);
+ const t = new Date((this.lastActivity || this.ctime) * 1000);
+ let failedCount = 0;
+ const src = (0,_utils_jsx0__ .VV)(attachNodes, size => {
+ failedCount++;
+ dl.done += size;
});
- throw ex;
- });
+ src.unshift({
+ name: bufferName,
+ lastModified: t,
+ input: data.buffer
+ });
+ dl.done = 0;
+ const reader = clientZip.downloadZip(src).body.getReader();
+ dl.nextChunk = async () => {
+ const read = await reader.read().catch(dump);
+ if (!read) {
+ reader.cancel().catch(ex => {
+ if (ex !== EOVERQUOTA) {
+ msgDialog('error', '', l.export_chat_failed, ex < 0 ? api_strerror(ex) : ex, undefined, 1);
+ }
+ });
+ io.abort();
+ delete this.exportIo;
+ loadingDialog.hideProgress();
+ return;
+ }
+ if (read.done) {
+ loadingDialog.hideProgress();
+ io.download(zname);
+ delete this.exportIo;
+ if (failedCount) {
+ msgDialog('error', '', l.export_chat_failed, l.export_chat_partial_fail, undefined, 1);
+ }
+ } else {
+ dl.done += read.value.byteLength;
+ loadingDialog.showProgress(dl.done / dl.size * 100);
+ io.write(read.value, dl.offset, dl.nextChunk);
+ dl.offset += read.value.length;
+ }
+ };
+ io.begin = dl.nextChunk;
+ io.setCredentials(false, dl.size, zname);
+ this.exportIo = io;
+ } else {
+ throw new Error(`Unexpected qbq response ${res}`);
+ }
+ } else {
+ return M.saveAs(stringNodes, bufferName);
}
- return ENOENT;
};
-Chat.prototype.setAttachments = function (roomId) {
- 'use strict';
+ChatRoom.prototype.canJoinLimitedCall = function () {
+ const callParts = this.getCallParticipants();
+ return this.iAmOperator() && callParts.length < CallManager2.CALL_USER_LIMIT || callParts.length < CallManager2.CALL_USER_LIMIT - 1;
+};
+window.ChatRoom = ChatRoom;
+ const __WEBPACK_DEFAULT_EXPORT__ = {
+ ChatRoom
+};
- if (M.chat) {
- if (d) {
- console.assert(this.chats[roomId] && this.chats[roomId].isCurrentlyActive, 'check this...');
+ },
+
+ 8264
+(_, EXP_, REQ_) {
+
+"use strict";
+ REQ_.d(EXP_, {
+ LP: () => getUniqueId,
+ N9: () => timing,
+ Zz: () => compose,
+ hG: () => SoonFcWrap,
+ u9: () => ContactAwareComponent,
+ w9: () => MegaRenderMixin
+ });
+
+ const _babel_runtime_helpers_applyDecoratedDescriptor0__ = REQ_(793);
+
+let _dec, _dec2, _dec3, _dec4, _dec5, _class;
+const INTERSECTION_OBSERVER_AVAILABLE = typeof IntersectionObserver !== 'undefined';
+const RESIZE_OBSERVER_AVAILABLE = typeof ResizeObserver !== 'undefined';
+function shallowEqual(objA, objB) {
+ if (objA === objB) {
+ return true;
+ }
+ for (var key in objA) {
+ if (key === "children") {
+ continue;
}
- M.v = Object.values(M.chc[roomId] || {});
- if (M.v.length) {
- let _this$chats$roomId;
- const sv = (_this$chats$roomId = this.chats[roomId]) == null || (_this$chats$roomId = _this$chats$roomId.messagesBuff) == null || (_this$chats$roomId = _this$chats$roomId.sharedFiles) == null ? void 0 : _this$chats$roomId._sortedVals;
- if (sv && sv.length === M.v.length) {
- M.v.sort((a, b) => sv.indexOf(a.m) - sv.indexOf(b.m));
- } else {
- if (d) {
- this.logger.info('falling back to order-value sorting.', sv);
- }
- M.v.sort(M.sortObjFn('co'));
- }
- for (let i = M.v.length; i--;) {
- const n = M.v[i];
- if (!n.revoked && !n.seen) {
- n.seen = -1;
- if (this._shallLoadImageFor(n)) {
- this._enqueueImageLoad(n);
+ if (objA.hasOwnProperty(key)) {
+ if (!objB.hasOwnProperty(key)) {
+ return false;
+ } else if (objA[key] !== objB[key]) {
+ if (typeof objA[key] === 'function' && typeof objB[key] === 'function') {
+ if (objA[key].toString() !== objB[key].toString()) {
+ return false;
}
+ } else {
+ return false;
}
}
- if ($.triggerSlideShow) {
- delay('chat:refresh-slideshow-on-single-entry', () => {
- const {
- slideshowid: id
- } = window;
- if (id && $.triggerSlideShow === id) {
- slideshow(id);
- }
- delete $.triggerSlideShow;
- });
- }
}
- } else if (d) {
- console.warn('Not in chat...');
}
-};
-Chat.prototype._enqueueMessageUpdate = function (message) {
- this._queuedMessageUpdates.push(message);
- delay('chat:enqueue-message-updates', () => {
- const queue = this._queuedMessageUpdates;
- this._queuedMessageUpdates = [];
- for (let i = queue.length; i--;) {
- queue[i].trackDataChange();
- }
- }, 400);
-};
-Chat.prototype._shallLoadImageFor = function (n) {
- return n && /:[01]\*/.test(n.fa);
-};
-Chat.prototype._enqueueImageLoad = function (n) {
- 'use strict';
- let cc = previews[n.h] || previews[n.hash];
- if (cc) {
- if (cc.poster) {
- n.src = cc.poster;
- } else {
- if (cc.full && n.mime !== 'image/png' && n.mime !== 'image/webp') {
- cc = cc.prev || false;
- }
- if (String(cc.type).startsWith('image/')) {
- n.src = cc.src;
- }
+ for (key in objB) {
+ if (objB.hasOwnProperty(key) && !objA.hasOwnProperty(key)) {
+ return false;
}
}
- let cached = n.src;
- if (this._shallLoadImageFor(n)) {
- let load = false;
- let dedup = true;
- if (this._imageAttributeCache[n.fa]) {
- this._imageAttributeCache[n.fa].push(n.ch);
- } else {
- this._imageAttributeCache[n.fa] = [n.ch];
- load = !cached;
+ return true;
+}
+window.shallowEqual = shallowEqual;
+const MAX_ALLOWED_DEBOUNCED_UPDATES = 5;
+const DEBOUNCED_UPDATE_TIMEOUT = 60;
+const REENABLE_UPDATES_AFTER_TIMEOUT = 300;
+const MAX_TRACK_CHANGES_RECURSIVE_DEPTH = 1;
+let _propertyTrackChangesVars = Object.create(null);
+_propertyTrackChangesVars._listenersMap = Object.create(null);
+_propertyTrackChangesVars._dataChangedHistory = Object.create(null);
+if (window._propertyTrackChangesVars) {
+ _propertyTrackChangesVars = window._propertyTrackChangesVars;
+} else {
+ window._propertyTrackChangesVars = _propertyTrackChangesVars;
+}
+window.megaRenderMixinId = window.megaRenderMixinId ? window.megaRenderMixinId : 0;
+const FUNCTIONS = ['render', 'shouldComponentUpdate', 'doProgramaticScroll', 'componentDidMount', 'componentDidUpdate', 'componentWillUnmount', 'refreshUI', 'eventuallyInit', 'handleWindowResize', 'focusTypeArea', 'initScrolling', 'updateScroll', 'isActive', 'onMessagesScrollReinitialise', 'specShouldComponentUpdate', 'attachAnimationEvents', 'eventuallyReinitialise', 'reinitialise', 'reinitialised', 'getContentHeight', 'getScrollWidth', 'isAtBottom', 'onResize', 'isComponentEventuallyVisible', 'getCursorPosition', 'getTextareaMaxHeight'];
+const localStorageProfileRenderFns = localStorage.profileRenderFns;
+if (localStorageProfileRenderFns) {
+ window.REACT_RENDER_CALLS = {};
+}
+let ID_CURRENT = 1;
+const DEBUG_THIS = d > 1 ? d : false;
+const scheduler = (func, name, debug) => {
+ const dbug = debug !== false && DEBUG_THIS;
+ let idnt = null;
+ let task = null;
+ const fire = () => {
+ if (dbug) {
+ console.warn('Dispatching scheduled task for %s.%s...', idnt, name);
}
- if (this._imageLoadCache[n.fa]) {
- this._imageLoadCache[n.fa].push(n.ch);
- } else {
- this._imageLoadCache[n.fa] = [n.ch];
- if (load) {
- this._imagesToBeLoaded[n.fa] = n;
- dedup = false;
- }
+ if (task) {
+ queueMicrotask(task);
+ task = null;
}
- if (dedup) {
- cached = true;
- } else {
- delay('chat:enqueue-image-load', this._doLoadImages.bind(this), 350);
+ };
+ const _scheduler = function () {
+ if (dbug) {
+ if (!idnt) {
+ idnt = name[0] === '(' && this.getReactId && this.getReactId() || this;
+ }
+ console.warn('Scheduling task from %s.%s...', idnt, name, [this], !!task);
}
- }
- if (cached) {
- this._doneLoadingImage(n.fa);
- }
-};
-Chat.prototype._doLoadImages = function () {
- "use strict";
-
- const self = this;
- const originals = Object.create(null);
- let imagesToBeLoaded = self._imagesToBeLoaded;
- self._imagesToBeLoaded = Object.create(null);
- const chatImageParser = function (h, data) {
- const n = M.chd[(self._imageLoadCache[h] || [])[0]] || false;
- if (n && data !== 0xDEAD) {
- n.src = mObjectURL([data.buffer || data], 'image/jpeg');
- n.srcBuffer = data;
- } else if (d) {
- console.warn('Failed to load image for %s', h, n);
+ if (!task) {
+ queueMicrotask(fire);
}
- self._doneLoadingImage(h);
- };
- for (const k in imagesToBeLoaded) {
- const node = imagesToBeLoaded[k];
- const mime = filemime(node);
- if (node.s < LOAD_ORIGINALS[mime]) {
- originals[node.fa] = node;
- delete imagesToBeLoaded[k];
+ let idx = arguments.length;
+ const args = new Array(idx);
+ while (idx--) {
+ args[idx] = arguments[idx];
}
- }
- const onSuccess = function (ctx, origNodeHandle, data) {
- chatImageParser(origNodeHandle, data);
- };
- const onError = function (origNodeHandle) {
- chatImageParser(origNodeHandle, 0xDEAD);
- };
- const loadOriginal = function (n) {
- const origFallback = ex => {
- const type = String(n.fa).indexOf(':1*') > 0 ? 1 : 0;
- if (d) {
- console.debug('Failed to load original image on chat.', n.h, n, ex);
- }
- imagesToBeLoaded[n.fa] = originals[n.fa];
- delete originals[n.fa];
- delay(`ChatRoom[${ self.roomId }]:origFallback${ type}`, () => {
- api_getfileattr(imagesToBeLoaded, type, onSuccess, onError);
- });
+ task = () => {
+ func.apply(this, args);
};
- M.gfsfetch(n.h, 0, -1).then((data) => {
- const handler = is_image(n);
- if (typeof handler === 'function') {
- handler(data, buffer => {
- if (buffer) {
- chatImageParser(n.fa, buffer);
- } else {
- origFallback(EFAILED);
- }
- });
- } else {
- chatImageParser(n.fa, data);
- }
- }).catch(origFallback);
};
- if ($.len(originals)) {
- Object.values(originals).map(loadOriginal);
- }
- api_getfileattr(imagesToBeLoaded, 1, onSuccess, onError);
- [imagesToBeLoaded, originals].forEach((obj) => {
- Object.keys(obj).forEach((handle) => {
- self._startedLoadingImage(handle);
+ if (DEBUG_THIS) {
+ Object.defineProperty(_scheduler, smbl(name), {
+ value: func
});
- });
- imagesToBeLoaded = Object.create(null);
+ }
+ return _scheduler;
};
-Chat.prototype._getImageNodes = function (h, src) {
- let nodes = this._imageLoadCache[h] || [];
- let handles = [].concat(nodes);
- for (let i = nodes.length; i--;) {
- const n = M.chd[nodes[i]] || false;
- if (this._imageAttributeCache[n.fa]) {
- handles = handles.concat(this._imageAttributeCache[n.fa]);
+const timing = (min, max) => {
+ return function (target, key, de) {
+ if (DEBUG_THIS > 2) {
+ de[key] = de.value;
+ _timing(de, min, max);
+ de.value = de[key];
}
- }
- handles = array.unique(handles);
- nodes = handles.map((ch) => {
- const n = M.chd[ch] || false;
- if (src && n.src) {
- Object.assign(src, n);
+ return de;
+ };
+};
+const logcall = () => {
+ return function (target, key, descriptor) {
+ if (DEBUG_THIS > 3) {
+ const func = descriptor.value;
+ descriptor.value = function () {
+ console.group('[logcall] Entering into %s.%s...', this, key);
+ const r = func.apply(this, arguments);
+ console.info('[logcall] Leaving %s.%s...', this, key);
+ console.groupEnd();
+ return r;
+ };
}
- return n;
- });
- return nodes;
+ return descriptor;
+ };
};
-Chat.prototype._startedLoadingImage = function (h) {
- "use strict";
-
- const nodes = this._getImageNodes(h);
- for (let i = nodes.length; i--;) {
- const n = nodes[i];
- if (!n.src && n.seen !== 2) {
- let imgNode = document.getElementById(n.ch);
- if (imgNode && (imgNode = imgNode.querySelector('img'))) {
- imgNode.parentNode.parentNode.classList.add('thumb-loading');
- }
+const schedule = (local, debug) => {
+ return function (target, property, descriptor) {
+ if (local) {
+ const func = descriptor.value;
+ descriptor = {
+ configurable: true,
+ get: function _unusedScheduler() {
+ Object.defineProperty(this, property, {
+ value: scheduler(func, `(${ property })`, debug)
+ });
+ return this[property];
+ }
+ };
+ } else {
+ descriptor.value = scheduler(descriptor.value, property, debug);
}
- }
+ return descriptor;
+ };
};
-Chat.prototype._doneLoadingImage = function (h) {
- const self = this;
- const setSource = function (n, img, src) {
- const message = n.mo;
- img.onload = function () {
- img.onload = null;
- n.srcWidth = this.naturalWidth;
- n.srcHeight = this.naturalHeight;
- if (message) {
- self._enqueueMessageUpdate(message);
- }
+const compose = (...funcs) => funcs.reduce((a, b) => (...args) => a(b(...args)), arg => arg);
+const replaceAt = (i, o, n) => `${o.slice(0, i)}${n}${o.slice(i + n.length)}`;
+const SoonFcWrap = (milliseconds, local) => {
+ return function (target, propertyKey, descriptor) {
+ descriptor.value = SoonFc(descriptor.value, !local, milliseconds);
+ return descriptor;
+ };
+};
+const rAFWrap = () => {
+ return function (target, propertyKey, descriptor) {
+ const old = descriptor.value;
+ descriptor.value = function () {
+ return old.apply(this, arguments);
};
- img.setAttribute('src', src);
+ return descriptor;
};
- const root = {};
- const nodes = this._getImageNodes(h, root);
- const {src} = root;
- for (let i = nodes.length; i--;) {
- const n = nodes[i];
- let imgNode = document.getElementById(n.ch);
- if (imgNode && (imgNode = imgNode.querySelector('img'))) {
- const parent = imgNode.parentNode;
- const container = parent.parentNode;
- if (src) {
- container.classList.add('thumb');
- parent.classList.remove('no-thumb');
- } else {
- container.classList.add('thumb-failed');
+};
+const trycatcher = () => (t, p, d) => (d.value = tryCatch(d.value)) && d;
+const getUniqueId = () => makeUUID().slice(-12);
+const MegaRenderMixin = (_dec = logcall(), _dec2 = SoonFcWrap(50, true), _dec3 = logcall(), _dec4 = SoonFcWrap(80, true), _dec5 = SoonFcWrap(350, true), _class = class MegaRenderMixin extends React.Component {
+ constructor(props) {
+ super(props);
+ lazy(this, '__internalReactID', function () {
+ let key = '';
+ let fib = DEBUG_THIS && this._reactInternalFiber;
+ while (fib) {
+ let tmp = fib.key;
+ if (tmp && tmp[0] !== '.' && key.indexOf(tmp) < 0) {
+ key += `${tmp }/`;
+ }
+ if (tmp = fib.memoizedProps) {
+ if (tmp.contact) {
+ tmp = tmp.contact.u + (tmp.chatRoom ? `@${ tmp.chatRoom.roomId}` : '');
+ } else if (tmp.chatRoom) {
+ tmp = tmp.chatRoom.roomId;
+ } else {
+ tmp = 0;
+ }
+ if (tmp && key.indexOf(tmp) < 0) {
+ key += `${tmp }/`;
+ }
+ }
+ fib = fib._debugOwner;
}
- n.seen = 2;
- container.classList.remove('thumb-loading');
- setSource(n, imgNode, src || window.noThumbURI || '');
+ key = key ? `[${ key.substr(0, key.length - 1) }]` : '';
+ return `::${ this.constructor.name }[${ `000${ ID_CURRENT++}`.slice(-4) }]${ key}`;
+ });
+ lazy(this, '__internalUniqueID', function () {
+ return (this.__internalReactID + makeUUID().substr(-12)).replace(/[^a-zA-Z0-9]/g, '');
+ });
+ Object.defineProperty(this, 'isMounted', {
+ value: function MegaRenderMixin_isMounted() {
+ return !!this.__isMounted;
+ }
+ });
+ if (DEBUG_THIS > 2) {
+ Object.defineProperty(this, 'safeForceUpdate', {
+ value: function MegaRenderMixin_safeForceUpdate_debug() {
+ console.group('%s.safeForceUpdate: mounted:%s, visible:%s', this.getReactId(), this.__isMounted, this.isComponentEventuallyVisible());
+ if (this.__isMounted) {
+ this.forceUpdate(() => {
+ console.warn('%s.safeForceUpdate finished.', this.getReactId());
+ console.groupEnd();
+ });
+ }
+ }
+ });
+ Object.keys(this).forEach(k => {
+ if (this[k] && this[k].apply) {
+ const orig = this[k];
+ this[k] = function () {
+ let s = performance.now();
+ const r = orig.apply(this, arguments);
+ s = performance.now() - s;
+ if (s > 30) {
+ console.error(k, this, "took", s, "ms", 'returned', r);
+ }
+ return r;
+ };
+ }
+ });
}
- if (src) {
- n.src = src;
- if (root.srcBuffer && root.srcBuffer.byteLength) {
- n.srcBuffer = root.srcBuffer;
+ if (DEBUG_THIS) {
+ if (!megaChat.__components) {
+ megaChat.__components = new WeakMap();
}
- if (n.srcBuffer && !previews[n.h] && is_image3(n)) {
- preqs[n.h] = 1;
- previewimg(n.h, n.srcBuffer, 'image/jpeg');
- previews[n.h].fromChat = Date.now();
+ megaChat.__components.set(this, Object.getPrototypeOf(this));
+ }
+ }
+ componentWillUnmount() {
+ if (super.componentWillUnmount) {
+ super.componentWillUnmount();
+ }
+ this.__isMounted = false;
+ chatGlobalEventManager.removeEventListener('resize', `megaRenderMixing${ this.getUniqueId()}`);
+ chatGlobalEventManager.removeEventListener('hashchange', `hc${ this.getUniqueId()}`);
+ const node = this.findDOMNode();
+ if (this.__intersectionObserverInstance) {
+ if (node) {
+ this.__intersectionObserverInstance.unobserve(node);
}
+ this.__intersectionObserverInstance.disconnect();
+ this.__intersectionObserverInstance = undefined;
+ }
+ if (this.onResizeObserved) {
+ if (!RESIZE_OBSERVER_AVAILABLE) {
+ $(document.body).unbind(`resize.resObs${ this.getUniqueId()}`);
+ } else {
+ this.__resizeObserverInstance.unobserve(node);
+ this.__resizeObserverInstance.disconnect();
+ this.__resizeObserverInstance = undefined;
+ }
+ }
+ const instanceId = this.getUniqueId();
+ const listeners = _propertyTrackChangesVars._listenersMap[instanceId];
+ if (listeners) {
+ for (const k in listeners) {
+ const v = listeners[k];
+ v[0].removeChangeListener(v[1]);
+ }
+ }
+ _propertyTrackChangesVars._listenersMap[instanceId] = null;
+ _propertyTrackChangesVars._dataChangedHistory[instanceId] = null;
+ if (this._dataStructListeners) {
+ this._internalDetachRenderCallbacks();
+ }
+ if (this.detachRerenderCallbacks) {
+ this.detachRerenderCallbacks();
}
- delete n.mo;
}
- if (src) {
- mBroadcaster.sendMessage('chat_image_preview');
+ getReactId() {
+ return this.__internalReactID;
}
-};
-Chat.prototype.onChatsHistoryReady = promisify(function (resolve, reject, timeout) {
- if (this.allChatsHadInitialLoadedHistory()) {
- return resolve();
+ getUniqueId() {
+ return this.__internalUniqueID;
}
- let timer = null;
- const {chatd} = this.plugins.chatdIntegration;
- const eventName = `onMessagesHistoryDone.ochr${ makeid(16)}`;
- const ready = () => {
- queueMicrotask(resolve);
- chatd.off(eventName);
- if (timer) {
- timer.abort();
- timer = null;
+ debouncedForceUpdate() {
+ this.eventuallyUpdate();
+ }
+ componentDidMount() {
+ if (super.componentDidMount) {
+ super.componentDidMount();
}
- };
- chatd.on(eventName, () => {
- if (this.allChatsHadInitialLoadedHistory()) {
- ready();
+ this.__isMounted = true;
+ this._wasRendered = true;
+ if (this.props.requiresUpdateOnResize || this.requiresUpdateOnResize || !this.props.skipQueuedUpdatesOnResize) {
+ chatGlobalEventManager.addEventListener('resize', `megaRenderMixing${ this.getUniqueId()}`, () => this.onResizeDoUpdate());
+ }
+ chatGlobalEventManager.addEventListener('hashchange', `hc${ this.getUniqueId()}`, () => this.onResizeDoUpdate());
+ if (this.props) {
+ this._recurseAddListenersIfNeeded("p", this.props);
+ }
+ if (this.state) {
+ this._recurseAddListenersIfNeeded("s", this.state);
+ }
+ const node = this.findDOMNode();
+ if (INTERSECTION_OBSERVER_AVAILABLE && !this.customIsEventuallyVisible && node && node.nodeType) {
+ this.__intersectionVisibility = false;
+ onIdle(() => {
+ this.__intersectionObserverInstance = new IntersectionObserver(entries => {
+ const entry = entries.pop();
+ if (entry.intersectionRatio < 0.2 && !entry.isIntersecting) {
+ this.__intersectionVisibility = false;
+ } else {
+ this.__intersectionVisibility = true;
+ if (this._requiresUpdateOnResize) {
+ this.debouncedForceUpdate();
+ }
+ }
+ if (this.onVisibilityChange) {
+ this.onVisibilityChange(this.__intersectionVisibility);
+ }
+ }, {
+ threshold: 0.1
+ });
+ this.__intersectionObserverInstance.observe(node);
+ });
+ }
+ if (this.onResizeObserved) {
+ if (!RESIZE_OBSERVER_AVAILABLE) {
+ $(document.body).rebind(`resize.resObs${ this.getUniqueId()}`, () => {
+ this.onResizeObserved(node.offsetWidth, node.offsetHeight);
+ });
+ } else {
+ this.__resizeObserverInstance = new ResizeObserver(entries => {
+ this.onResizeObserved(entries[0].contentRect.width, entries[0].contentRect.height);
+ });
+ this.__resizeObserverInstance.observe(node);
+ }
+ }
+ if (this.attachRerenderCallbacks) {
+ this.attachRerenderCallbacks();
}
- });
- if (timeout > 0) {
- (timer = tSleep(timeout / 1e3)).then(ready);
}
-});
-Chat.prototype.allChatsHadLoadedHistory = function () {
- const chatIds = this.chats.keys();
- for (let i = chatIds.length; i--;) {
- const room = this.chats[chatIds[i]];
- if (room.isLoading()) {
- return false;
+ findDOMNode() {
+ if (!this.domNode) {
+ let _this$domRef;
+ this.domNode = (_this$domRef = this.domRef) == null ? void 0 : _this$domRef.current;
}
+ return this.domNode;
}
- return true;
-};
-Chat.prototype.allChatsHadInitialLoadedHistory = function () {
- const self = this;
- const chatIds = self.chats.keys();
- for (let i = chatIds.length; i--;) {
- const room = self.chats[chatIds[i]];
- if (room.chatId && room.initialMessageHistLoaded === false) {
+ isComponentVisible() {
+ if (!this.__isMounted) {
+ return false;
+ }
+ if (this.customIsEventuallyVisible) {
+ const ciev = this.customIsEventuallyVisible;
+ const result = typeof ciev === "function" ? ciev.call(this) : ciev;
+ if (result !== -1) {
+ return result;
+ }
+ }
+ if (this.__intersectionVisibility === false) {
+ return false;
+ } else if (this.__intersectionVisibility === true) {
+ return true;
+ }
+ const domNode = this.findDOMNode();
+ if (!this.props.hideable && (!domNode || domNode.offsetParent === null)) {
+ return false;
+ }
+ if (!$(domNode).is(":visible")) {
return false;
}
+ return verge.inViewport(domNode);
}
- return true;
-};
-Chat.prototype.getPrivateRoom = function (h) {
- 'use strict';
-
- return this.chats[h] || false;
-};
-Chat.prototype.createAndShowPrivateRoom = promisify(function (resolve, reject, h) {
- M.openFolder(`chat/p/${ h}`).then(() => {
- const room = this.getPrivateRoom(h);
- assert(room, 'room not found..');
- resolve(room);
- }).catch(reject);
-});
-Chat.prototype.createAndShowGroupRoomFor = function (contactHashes, topic = '', opts = {}) {
- this.trigger('onNewGroupChatRequest', [contactHashes, {
- topic,
- ...opts
- }]);
-};
-Chat.prototype.createAndStartMeeting = function (topic, audio, video) {
- megaChat.createAndShowGroupRoomFor([], topic, {
- keyRotation: false,
- createChatLink: true,
- isMeeting: true
- });
- megaChat.rebind('onRoomInitialized.meetingCreate', (e, room) => {
- room.rebind('onNewMeetingReady.meetingCreate', () => {
- room.startCall(audio, video);
- });
- });
-};
-Chat.prototype._destroyAllChatsFromChatd = function () {
- const self = this;
- asyncApiReq({
- 'a': 'mcf',
- 'v': Chatd.VERSION
- }).then(r => {
- r.c.forEach((chatRoomMeta) => {
- if (chatRoomMeta.g === 1) {
- chatRoomMeta.u.forEach((u) => {
- if (u.u !== u_handle) {
- api_req({
- a: 'mcr',
- id: chatRoomMeta.id,
- u: u.u,
- v: Chatd.VERSION
- });
- }
- });
- api_req({
- a: 'mcr',
- id: chatRoomMeta.id,
- u: u_handle,
- v: Chatd.VERSION
- });
- }
- });
- });
-};
-Chat.prototype._leaveAllGroupChats = function () {
- asyncApiReq({
- 'a': 'mcf',
- 'v': Chatd.VERSION
- }).then(r => {
- r.c.forEach((chatRoomMeta) => {
- if (chatRoomMeta.g === 1) {
- asyncApiReq({
- "a": "mcr",
- "id": chatRoomMeta.id,
- "v": Chatd.VERSION
- });
- }
- });
- });
-};
-Chat.prototype.getEmojiDataSet = async function (name) {
- assert(name === "categories" || name === "emojis", "Invalid emoji dataset name passed.");
- if (!this._emojiDataLoading) {
- this._emojiDataLoading = Object.create(null);
- }
- if (!this._emojiData) {
- this._emojiData = {
- 'emojisUtf': Object.create(null),
- 'emojisSlug': Object.create(null)
- };
- }
- if (this._emojiData[name]) {
- return this._emojiData[name];
- }
- if (this._emojiDataLoading[name]) {
- return this._emojiDataLoading[name];
- }
- if (name === "categories") {
- this._emojiData[name] = ["people", "nature", "food", "activity", "travel", "objects", "symbols", "flags"];
- return this._emojiData[name];
+ isComponentEventuallyVisible() {
+ if (!this.__isMounted) {
+ return false;
+ }
+ if (this.customIsEventuallyVisible) {
+ const ciev = this.customIsEventuallyVisible;
+ return typeof ciev === "function" ? ciev.call(this) : !!ciev;
+ }
+ if (typeof this.props.isVisible !== 'undefined') {
+ return this.props.isVisible;
+ }
+ return this.__intersectionVisibility !== false;
}
- const {
- promise
- } = mega;
- this._emojiDataLoading[name] = promise;
- M.xhr({
- type: 'json',
- url: `${staticpath}js/chat/emojidata/${name}_v${EMOJI_DATASET_VERSION}.json`
- }).then((ev, data) => {
- if (!data) {
- promise.reject(EFAILED);
+ eventuallyUpdate() {
+ if (!window.megaChat || megaChat.isLoggingOut || this._updatesDisabled || !this._wasRendered || !this.__isMounted) {
return;
}
- this._emojiData[name] = data;
- delete this._emojiDataLoading[name];
- if (name === "emojis") {
- this._mapEmojisToAliases();
- }
- promise.resolve(data);
- }).catch((ex, error) => {
- if (d) {
- this.logger.warn('Failed to load emoji data "%s": %s', name, error, [ex]);
+ if (!this.isComponentEventuallyVisible()) {
+ this._requiresUpdateOnResize = true;
+ return;
}
- delete this._emojiDataLoading[name];
- promise.reject(error || ex);
- });
- return promise;
-};
-Chat.prototype._mapEmojisToAliases = function () {
- const {
- emojis
- } = this._emojiData;
- if (emojis) {
- this._emojiData.emojisUtf = Object.create(null);
- this._emojiData.emojisSlug = Object.create(null);
- for (let i = emojis.length; i--;) {
- const emoji = emojis[i];
- this._emojiData.emojisUtf[emoji.u] = emoji;
- this._emojiData.emojisSlug[emoji.n] = emoji;
+ if (this._requiresUpdateOnResize) {
+ this._requiresUpdateOnResize = false;
}
+ this.forceUpdate();
}
-};
-Chat.prototype.isValidEmojiSlug = function (slug) {
- const self = this;
- const emojiData = self._emojiData.emojis;
- if (!emojiData) {
- self.getEmojiDataSet('emojis');
- return false;
- }
- for (let i = 0; i < emojiData.length; i++) {
- if (emojiData[i].n === slug) {
- return true;
+ tempDisableUpdates(forHowLong) {
+ const self = this;
+ self._updatesDisabled = true;
+ if (self._updatesReenableTimer) {
+ clearTimeout(self._updatesReenableTimer);
}
+ const timeout = forHowLong ? forHowLong : self.REENABLE_UPDATES_AFTER_TIMEOUT ? self.REENABLE_UPDATES_AFTER_TIMEOUT : REENABLE_UPDATES_AFTER_TIMEOUT;
+ self._updatesReenableTimer = setTimeout(() => {
+ self.tempEnableUpdates();
+ }, timeout);
}
-};
-Chat.prototype.getPresence = function (user_handle) {
- if (user_handle && this.plugins.presencedIntegration) {
- return this.plugins.presencedIntegration.getPresence(user_handle);
- }
-};
-Chat.prototype.getPresenceAsCssClass = function (user_handle) {
- const presence = this.getPresence(user_handle);
- return this.presenceStringToCssClass(presence);
-};
-Chat.prototype.presenceStringToCssClass = function (presence) {
- if (presence === UserPresence.PRESENCE.ONLINE) {
- return 'online';
- } else if (presence === UserPresence.PRESENCE.AWAY) {
- return 'away';
- } else if (presence === UserPresence.PRESENCE.DND) {
- return 'busy';
- } else if (!presence || presence === UserPresence.PRESENCE.OFFLINE) {
- return 'offline';
- } else {
- return 'black';
- }
-};
-Chat.prototype.generateTempMessageId = function (roomId, messageAndMeta) {
- let messageIdHash = u_handle + roomId;
- if (messageAndMeta) {
- messageIdHash += messageAndMeta;
+ tempEnableUpdates() {
+ clearTimeout(this._updatesReenableTimer);
+ this._updatesDisabled = false;
+ this.eventuallyUpdate();
}
- return `m${ fastHashFunction(messageIdHash) }_${ unixtime()}`;
-};
-Chat.prototype.getChatById = function (chatdId) {
- const self = this;
- if (self.chats[chatdId]) {
- return self.chats[chatdId];
- } else if (self.chatIdToRoomId && self.chatIdToRoomId[chatdId] && self.chats[self.chatIdToRoomId[chatdId]]) {
- return self.chats[self.chatIdToRoomId[chatdId]];
+ onResizeDoUpdate() {
+ this.eventuallyUpdate();
}
- if (this.chats[this.handleToId[chatdId]]) {
- return this.chats[this.handleToId[chatdId]];
+ _getUniqueIDForMap(map, payload) {
+ return `${map }.${ payload}`;
}
- let found = false;
- self.chats.forEach((chatRoom) => {
- if (!found && chatRoom.chatId === chatdId) {
- found = chatRoom;
- return false;
+ _recurseAddListenersIfNeeded(idx, map, depth) {
+ depth |= 0;
+ if (map instanceof MegaDataMap && !(this._contactChangeListeners && this._contactChangeListeners.includes(map))) {
+ const cacheKey = this._getUniqueIDForMap(map, idx);
+ const instanceId = this.getUniqueId();
+ if (!_propertyTrackChangesVars._listenersMap[instanceId]) {
+ _propertyTrackChangesVars._listenersMap[instanceId] = Object.create(null);
+ }
+ if (!_propertyTrackChangesVars._listenersMap[instanceId][cacheKey]) {
+ _propertyTrackChangesVars._listenersMap[instanceId][cacheKey] = [map, map.addChangeListener(() => this.onPropOrStateUpdated())];
+ }
}
- });
- return found;
-};
-Chat.prototype.getNoteChat = function () {
- return Object.values(this.chats).find(c => c.isNote);
-};
-Chat.prototype.getMessageByMessageId = async function (chatId, messageId) {
- const chatRoom = this.getChatById(chatId);
- const msg = chatRoom.messagesBuff.getMessageById(messageId);
- if (msg) {
- return msg;
- }
- const {
- chatdPersist
- } = this.plugins.chatdIntegration.chatd;
- if (chatdPersist) {
- const [msg] = await chatdPersist.getMessageByMessageId(chatId, messageId).catch(dump) || [];
- if (msg) {
- return Message.fromPersistableObject(chatRoom, msg);
+ if (depth++ < MAX_TRACK_CHANGES_RECURSIVE_DEPTH && !this.props.manualDataChangeTracking) {
+ const mapKeys = map instanceof MegaDataMap ? map.keys() : Object.keys(map);
+ for (let i = 0; i < mapKeys.length; i++) {
+ const k = mapKeys[i];
+ if (map[k]) {
+ this._recurseAddListenersIfNeeded(`${idx }_${ k}`, map[k], depth);
+ }
+ }
}
}
- if (d) {
- this.logger.debug('getMessageByMessageId: Cannot find %s on %s', messageId, chatId);
- }
- return Promise.reject(ENOENT);
-};
-Chat.prototype.haveAnyActiveCall = function () {
- const self = this;
- const chatIds = self.chats.keys();
- for (let i = 0; i < chatIds.length; i++) {
- if (self.chats[chatIds[i]].haveActiveCall()) {
- return true;
+ _checkDataStructForChanges(idx, v, rv, depth) {
+ if (!v && v === rv) {
+ return false;
}
- }
- return false;
-};
-Chat.prototype.haveAnyOnHoldCall = function () {
- const self = this;
- const chatIds = self.chats.keys();
- for (let i = 0; i < chatIds.length; i++) {
- if (self.chats[chatIds[i]].haveActiveOnHoldCall()) {
+ if (!rv && v) {
return true;
}
- }
- return false;
-};
-Chat.prototype.openChatAndSendFilesDialog = function (user_handle) {
- 'use strict';
-
- this.smartOpenChat(user_handle).then((room) => {
- if (room.$rConversationPanel && room.$rConversationPanel.isMounted()) {
- room.trigger('openSendFilesDialog');
- } else {
- room.one('onComponentDidMount.sendFilesDialog', () => {
- onIdle(() => room.trigger('openSendFilesDialog'));
- });
+ if (v === null) {
+ return rv !== null;
}
- room.setActive();
- }).catch(this.logger.error.bind(this.logger));
-};
-Chat.prototype.openChatAndAttachNodes = async function (targets, nodes, silent) {
- const promises = [];
- if (d) {
- console.group('Attaching nodes to chat room(s)...', targets, nodes);
- }
- const attachNodes = roomId => this.smartOpenChat(roomId).then(room => {
- return room.attachNodes(nodes).then(res => {
- if (res !== EBLOCKED && res !== ENOENT) {
- return room;
+ if (v instanceof MegaDataMap) {
+ const cacheKey = this._getUniqueIDForMap(v, idx);
+ const dataChangeHistory = _propertyTrackChangesVars._dataChangedHistory;
+ const instanceId = this.getUniqueId();
+ if (!dataChangeHistory[instanceId]) {
+ dataChangeHistory[instanceId] = Object.create(null);
}
- });
- }).catch(ex => {
- if (d) {
- this.logger.warn('Cannot openChat for %s and hence nor attach nodes to it.', roomId, ex);
- }
- throw ex;
- });
- if (!Array.isArray(targets)) {
- targets = [targets];
- }
- for (let i = targets.length; i--;) {
- promises.push(attachNodes(targets[i]));
- }
- const result = (await Promise.allSettled(promises)).map(e => e.value).filter(Boolean);
- let folderCount = 0;
- let fileCount = 0;
- for (let i = nodes.length; i--;) {
- const {
- t
- } = M.getNodeByHandle(nodes[i]) || {};
- if (t === 1) {
- folderCount++;
- } else {
- fileCount++;
- }
- }
- let message = mega.icu.format(l.toast_send_chat_items, nodes.length);
- if (fileCount === 0 && folderCount) {
- message = mega.icu.format(l.toast_send_chat_folders, folderCount);
- } else if (folderCount === 0 && fileCount) {
- message = mega.icu.format(l.toast_send_chat_files, fileCount);
- }
- for (let i = result.length; i--;) {
- if (result[i] instanceof ChatRoom) {
- const room = result[i];
- mega.ui.toast.show(message);
- if (!silent) {
- await M.openFolder(room.getRoomUrl().replace('fm/', '')).catch(dump);
+ if (dataChangeHistory[instanceId][cacheKey] !== v._dataChangeIndex) {
+ if (window.RENDER_DEBUG) {
+ console.error("changed: ", this.getElementName(), cacheKey, v._dataChangeTrackedId, v._dataChangeIndex, v);
+ }
+ dataChangeHistory[instanceId][cacheKey] = v._dataChangeIndex;
+ return true;
}
- break;
+ return false;
}
+ return depth < MAX_TRACK_CHANGES_RECURSIVE_DEPTH && v && v.byteLength === undefined && typeof v === "object" && this._recursiveSearchForDataChanges(idx, v, rv, depth + 1) === true;
}
- if (d) {
- console.groupEnd();
- }
- return result;
-};
-Chat.prototype.toggleUIFlag = function (name) {
- this.chatUIFlags.set(name, this.chatUIFlags[name] ? 0 : 1);
-};
-Chat.prototype.onSnActionPacketReceived = function () {
- if (this._queuedMccPackets.length > 0) {
- const aps = this._queuedMccPackets;
- this._queuedMccPackets = [];
- for (let i = 0; i < aps.length; i++) {
- mBroadcaster.sendMessage('onChatdChatUpdatedActionPacket', aps[i]);
+ _recursiveSearchForDataChanges(idx, map, referenceMap, depth) {
+ const self = this;
+ depth = depth || 0;
+ if (!this.isMounted() || this._updatesDisabled === true) {
+ return;
}
- }
- this.processQueuedMcsmPackets();
-};
-Chat.prototype.processQueuedMcsmPackets = function () {
- const aps = Object.values(this._queuedMcsmPackets);
- if (aps.length) {
- for (let i = 0; i < aps.length; i++) {
- const ap = aps[i];
- const {
- type,
- data
- } = ap;
- const {
- meetingsManager
- } = this.plugins;
- if (type === 'mcsmp') {
- const chatRoom = this.getChatById(data.cid);
- if (chatRoom) {
- const scheduledMeeting = meetingsManager.attachMeeting(data, true);
- delete this._queuedMcsmPackets[scheduledMeeting.id];
- return scheduledMeeting.iAmOwner ? null : notify.notifyFromActionPacket({
- ...data,
- a: type
- });
+ if (!this._wasRendered) {
+ if (window.RENDER_DEBUG) console.error("First time render", self.getElementName(), map, referenceMap);
+ this._wasRendered = true;
+ return true;
+ }
+ if (idx === "p_children") {
+ if (map.map && referenceMap.map) {
+ const oldKeys = map.map((child) => {
+ return child ? child.key : child;
+ });
+ const newKeys = referenceMap.map((child) => {
+ return child ? child.key : child;
+ });
+ if (!shallowEqual(oldKeys, newKeys)) {
+ return true;
+ }
+ } else if (!map && referenceMap || map && !referenceMap) {
+ return true;
+ } else if (map.$$typeof && referenceMap.$$typeof) {
+ if (!shallowEqual(map.props, referenceMap.props) || !shallowEqual(map.state, referenceMap.state)) {
+ return true;
}
}
- if (type === 'mcsmr') {
- meetingsManager.detachMeeting(data);
- delete this._queuedMcsmPackets[data.id];
+ } else if (map && !referenceMap || !map && referenceMap || map && referenceMap && !shallowEqual(map, referenceMap)) {
+ return true;
+ }
+ const mapKeys = map instanceof MegaDataMap ? map.keys() : Object.keys(map);
+ for (let i = mapKeys.length; i--;) {
+ const k = mapKeys[i];
+ if (this._checkDataStructForChanges(`${idx }_${ k}`, map[k], referenceMap[k], depth)) {
+ return true;
}
}
+ return false;
}
-};
-Chat.prototype.getFrequentContacts = function () {
- if (Chat._frequentsCache) {
- return Chat._frequentsCache;
- }
- const {chats} = this;
- const recentContacts = {};
- const promises = [];
- const finishedLoadingChats = {};
- const loadingMoreChats = {};
- const _calculateLastTsFor = function (r, maxMessages) {
- const mb = r.messagesBuff;
- const len = mb.messages.length;
- const msgs = mb.messages.slice(Math.max(0, len - maxMessages), len);
- for (let i = 0; i < msgs.length; i++) {
- const msg = msgs[i];
- let contactHandle = msg.userId === mega.BID && msg.meta ? msg.meta.userId : msg.userId;
- if (r.type === "private" && contactHandle === u_handle) {
- contactHandle = contactHandle || r.getParticipantsExceptMe()[0];
+ shouldComponentUpdate(nextProps, nextState) {
+ let shouldRerender = false;
+ if (megaChat && megaChat.isLoggingOut) {
+ return false;
+ }
+ if (!this.isMounted() || this._updatesDisabled === true) {
+ if (window.RENDER_DEBUG) {
+ console.error("shouldUpdate? No.", "F1", this.getElementName(), this.props, nextProps, this.state, nextState);
}
- if (contactHandle !== mega.BID && contactHandle !== strongvelope.COMMANDER && contactHandle in M.u && M.u[contactHandle].c === 1 && contactHandle !== u_handle) {
- if (!recentContacts[contactHandle] || recentContacts[contactHandle].ts < msg.delay) {
- recentContacts[contactHandle] = {
- 'userId': contactHandle,
- 'ts': msg.delay
- };
+ return false;
+ }
+ if (this.customIsEventuallyVisible) {
+ let ciev = this.customIsEventuallyVisible;
+ ciev = typeof ciev === "function" ? ciev.call(this) : !!ciev;
+ if (!this._queueUpdateWhenVisible && !ciev) {
+ this._queueUpdateWhenVisible = true;
+ if (window.RENDER_DEBUG) {
+ console.error("shouldUpdate? No.", "F1.1", this.getElementName(), this.props, nextProps, this.state, nextState);
}
+ } else if (this._queueUpdateWhenVisible && ciev) {
+ delete this._queueUpdateWhenVisible;
+ return true;
}
}
- };
- const _histDecryptedCb = function () {
- const mb = this.messagesBuff;
- if (!loadingMoreChats[this.chatId] && mb.messages.length < 32 && mb.haveMoreHistory()) {
- loadingMoreChats[this.chatId] = true;
- mb.retrieveChatHistory(false);
- } else {
- this.unbind(CHAT_ONHISTDECR_RECNT);
- _calculateLastTsFor(this, 32);
- delete loadingMoreChats[this.chatId];
- finishedLoadingChats[this.chatId] = true;
- mb.detachMessages();
+ if (this.specShouldComponentUpdate) {
+ const r = this.specShouldComponentUpdate(nextProps, nextState);
+ if (r === false) {
+ if (window.RENDER_DEBUG) {
+ console.error("shouldUpdate? No.", "F2", this.getElementName(), this.props, nextProps, this.state, nextState);
+ }
+ this._requiresUpdateOnResize = true;
+ return false;
+ } else if (r === true) {
+ return true;
+ }
}
- };
- const _checkFinished = function (chatId) {
- return function () {
- return finishedLoadingChats[chatId] === true;
- };
- };
- chats.forEach(chatRoom => {
- const name = `getFrequentContacts(${chatRoom.roomId})`;
- if (chatRoom.isLoading()) {
- finishedLoadingChats[chatRoom.chatId] = false;
- chatRoom.rebind(CHAT_ONHISTDECR_RECNT, _histDecryptedCb);
- promises.push(createTimeoutPromise(_checkFinished(chatRoom.chatId), 300, 10000, false, name));
- } else if (chatRoom.messagesBuff.messages.length < 32 && chatRoom.messagesBuff.haveMoreHistory()) {
- loadingMoreChats[chatRoom.chatId] = true;
- finishedLoadingChats[chatRoom.chatId] = false;
- chatRoom.messagesBuff.retrieveChatHistory(false);
- chatRoom.rebind(CHAT_ONHISTDECR_RECNT, _histDecryptedCb);
- promises.push(createTimeoutPromise(_checkFinished(chatRoom.chatId), 300, 15000, false, name));
- } else {
- _calculateLastTsFor(chatRoom, 32);
+ if (!this.props.disableCheckingVisibility && !this.isComponentEventuallyVisible()) {
+ if (window.RENDER_DEBUG) {
+ console.error("shouldUpdate? No.", "FVis", this.getElementName(), this.props, nextProps, this.state, nextState);
+ }
+ this._requiresUpdateOnResize = true;
+ return false;
}
- });
- Chat._frequentsCache = new Promise((resolve, reject) => {
- Promise.allSettled(promises).then(() => {
- const result = Object.values(recentContacts).sort((a, b) => a.ts < b.ts ? 1 : b.ts < a.ts ? -1 : 0).reverse();
- tSleep(300).then(() => {
- delete Chat._frequentsCache;
- });
- return result;
- }).then(resolve).catch(reject);
- });
- return Chat._frequentsCache;
-};
-Chat.prototype.lastRoomContacts = async function (chatRoom) {
- let timeout;
- let loaded = false;
- let loadMore = false;
- const {
- promise
- } = mega;
- const proc = () => {
- if (timeout) {
- timeout.abort();
+ if (this.props !== null) {
+ shouldRerender = this._recursiveSearchForDataChanges("p", nextProps, this.props);
}
- const {
- messages
- } = chatRoom.messagesBuff;
- const arr = messages.slice(Math.max(0, messages.length - 32));
- let first = '';
- let second = '';
- for (let i = arr.length; i--;) {
- const message = arr[i];
- const h = message.userId === mega.BID && message.meta ? message.meta.userId : message.userId;
- if (h !== mega.BID && h !== strongvelope.COMMANDER && h !== u_handle && h in M.u && M.u[h].c === 1) {
- if (first && first !== h) {
- second = h;
- break;
- }
- first = h;
+ if (shouldRerender === false) {
+ if (window.RENDER_DEBUG) {
+ console.error("shouldUpdate? No.", "F3", this.getElementName(), this.props, nextProps, this.state, nextState);
}
}
- if (second) {
- promise.resolve([first, second]);
- } else if (first) {
- promise.resolve([first]);
- } else {
- promise.resolve([]);
+ if (shouldRerender === false && this.state !== null) {
+ shouldRerender = this._recursiveSearchForDataChanges("s", nextState, this.state);
}
- chatRoom.messagesBuff.detachMessages();
- };
- const next = () => {
- if (!loadMore && chatRoom.messagesBuff.messages.length < 32 && chatRoom.messagesBuff.haveMoreHistory()) {
- if (timeout) {
- timeout.restart();
+ if (window.RENDER_DEBUG) {
+ if (shouldRerender) {}
+ console.error("shouldRerender?", shouldRerender, "rendered: ", this.getElementName(), "props:", this.props, "nextProps:", this.props, "state:", this.state);
+ }
+ if (shouldRerender === true) {
+ if (this.props) {
+ this._recurseAddListenersIfNeeded("p", this.props);
+ }
+ if (this.state) {
+ this._recurseAddListenersIfNeeded("s", this.state);
}
- loadMore = true;
- chatRoom.messagesBuff.retrieveChatHistory(false);
} else {
- chatRoom.off('onHistoryDecrypted.lrc');
- proc();
+ if (window.RENDER_DEBUG) {
+ console.error("shouldUpdate? No.", "F4", this.getElementName(), this.props, nextProps, this.state, nextState);
+ }
}
- };
- if (chatRoom.isLoading()) {
- loaded = false;
- chatRoom.rebind('onHistoryDecrypted.lrc', next);
- timeout = tSleep(10);
- } else if (chatRoom.messagesBuff.messages.length < 32 && chatRoom.messagesBuff.haveMoreHistory()) {
- loaded = false;
- loadMore = true;
- chatRoom.rebind('onHistoryDecrypted.lrc', next);
- chatRoom.messagesBuff.retrieveChatHistory(false);
- timeout = tSleep(10);
- } else {
- proc();
+ return shouldRerender;
}
- if (timeout) {
- timeout.then(() => {
- if (!loaded) {
- chatRoom.off('onHistoryDecrypted.lrc');
- promise.resolve([]);
- }
- });
+ onPropOrStateUpdated() {
+ this.eventuallyUpdate();
}
- return promise;
-};
-Chat.prototype.eventuallyAddDldTicketToReq = function (req) {
- if (!u_handle) {
- return;
+ getElementName() {
+ return this._reactInternalFiber.elementType.name;
}
- const currentRoom = this.getCurrentRoom();
- if (currentRoom && currentRoom.type === "public" && currentRoom.publicChatHandle && (is_chatlink || currentRoom.membersSetFromApi && !currentRoom.membersSetFromApi.members[u_handle])) {
- req.cauth = currentRoom.publicChatHandle;
+ safeForceUpdate() {
+ if (this.__isMounted) {
+ this.forceUpdate();
+ }
}
-};
-Chat.prototype.removeMessagesByRetentionTime = function (chatId) {
- if (this.chats.length > 0) {
- if (chatId) {
- if (this.logger && d > 3) {
- this.logger.debug(`Chat.prototype.removeMessagesByRetentionTime chatId=${chatId}`);
+ componentDidUpdate() {
+ if (window.RENDER_DEBUG) {
+ const self = this;
+ const getElementName = function () {
+ if (!self.constructor) {
+ return "unknown";
+ }
+ return self.constructor.name;
+ };
+ console.error("renderedX: ", getElementName(), "props:", this.props, "state:", this.state);
+ }
+ if (this.domNode && !this.domNode.isConnected) {
+ delete this.domNode;
+ }
+ }
+ UNSAFE_componentWillReceiveProps(nextProps, nextContext) {
+ if (localStorageProfileRenderFns) {
+ const self = this;
+ const componentName = self.constructor ? self.constructor.name : "unknown";
+ if (!this._wrappedRender) {
+ FUNCTIONS.forEach((fnName) => {
+ const _origFn = self[fnName];
+ if (_origFn) {
+ self[fnName] = function () {
+ const start = performance.now();
+ const res = _origFn.apply(this, arguments);
+ REACT_RENDER_CALLS[`${componentName }.${ fnName}`] = REACT_RENDER_CALLS[`${componentName }.${ fnName}`] || 0;
+ REACT_RENDER_CALLS[`${componentName }.${ fnName}`] += performance.now() - start;
+ return res;
+ };
+ }
+ });
+ self._wrappedRender = true;
}
- const room = this.getChatById(chatId);
- if (room) {
- room.removeMessagesByRetentionTime();
+ REACT_RENDER_CALLS.sorted = function () {
+ const sorted = [];
+ Object.keys(REACT_RENDER_CALLS).sort((a, b) => {
+ if (REACT_RENDER_CALLS[a] < REACT_RENDER_CALLS[b]) {
+ return 1;
+ } else if (REACT_RENDER_CALLS[a] > REACT_RENDER_CALLS[b]) {
+ return -1;
+ } else {
+ return 0;
+ }
+ }).forEach((k) => {
+ if (typeof REACT_RENDER_CALLS[k] !== 'function') {
+ sorted.push([k, REACT_RENDER_CALLS[k]]);
+ }
+ });
+ return sorted;
+ };
+ REACT_RENDER_CALLS.clear = function () {
+ Object.keys(REACT_RENDER_CALLS).forEach((k) => {
+ if (typeof REACT_RENDER_CALLS[k] !== 'function') {
+ delete REACT_RENDER_CALLS[k];
+ }
+ });
+ };
+ }
+ }
+ _internalDetachRenderCallbacks() {
+ const items = this._dataStructListeners || false;
+ for (let i = items.length; i--;) {
+ const item = items[i];
+ if (item[0] === 'dsprops') {
+ console.assert(item[2].removeChangeListener(item[1]), 'listener not found..');
}
+ }
+ }
+ addDataStructListenerForProperties(obj, properties) {
+ if (!(obj instanceof MegaDataMap)) {
return;
}
- const chatIds = this.chats.keys();
- for (let i = 0; i < chatIds.length; i++) {
- const chatRoom = this.chats[chatIds[i]];
- if (chatRoom.retentionTime > 0 && chatRoom.state === ChatRoom.STATE.READY) {
- if (this.logger && d > 3) {
- this.logger.debug(`Chat.prototype.removeMessagesByRetentionTime roomId=${chatRoom.roomId}`);
- }
- chatRoom.removeMessagesByRetentionTime();
- }
+ if (!this._dataStructListeners) {
+ this._dataStructListeners = [];
}
+ properties = array.to.object(properties);
+ const id = obj.addChangeListener((obj, data, k) => properties[k] && this.onPropOrStateUpdated());
+ this._dataStructListeners.push(['dsprops', id, obj]);
}
-};
-Chat.prototype.loginOrRegisterBeforeJoining = function (chatHandle, forceRegister, forceLogin, notJoinReq, onLoginSuccessCb) {
- if (!chatHandle && page !== 'securechat' && (page === 'chat' || page.indexOf('chat') > -1)) {
- chatHandle = getSitePath().split("chat/")[1].split("#")[0];
+}, (0,_babel_runtime_helpers_applyDecoratedDescriptor0__ .A)(_class.prototype, "componentWillUnmount", [_dec], Object.getOwnPropertyDescriptor(_class.prototype, "componentWillUnmount"), _class.prototype), (0,_babel_runtime_helpers_applyDecoratedDescriptor0__ .A)(_class.prototype, "debouncedForceUpdate", [_dec2], Object.getOwnPropertyDescriptor(_class.prototype, "debouncedForceUpdate"), _class.prototype), (0,_babel_runtime_helpers_applyDecoratedDescriptor0__ .A)(_class.prototype, "componentDidMount", [_dec3], Object.getOwnPropertyDescriptor(_class.prototype, "componentDidMount"), _class.prototype), (0,_babel_runtime_helpers_applyDecoratedDescriptor0__ .A)(_class.prototype, "eventuallyUpdate", [_dec4], Object.getOwnPropertyDescriptor(_class.prototype, "eventuallyUpdate"), _class.prototype), (0,_babel_runtime_helpers_applyDecoratedDescriptor0__ .A)(_class.prototype, "onResizeDoUpdate", [_dec5], Object.getOwnPropertyDescriptor(_class.prototype, "onResizeDoUpdate"), _class.prototype), _class);
+class ContactAwareComponent extends MegaRenderMixin {
+ constructor(props) {
+ super(props);
+ this.loadContactInfo();
}
- assert(chatHandle, 'missing chat handle when calling megaChat.loginOrRegisterBeforeJoining');
- const chatRoom = megaChat.getCurrentRoom();
- const chatKey = `#${ window.location.hash.split("#").pop()}`;
- const finish = function (stay) {
- if (!notJoinReq) {
- localStorage.autoJoinOnLoginChat = JSON.stringify([chatHandle, unixtime(), chatKey, chatRoom.chatId]);
+ _validContact() {
+ const {
+ contact
+ } = this.props;
+ if (!contact) {
+ return false;
}
- if (!stay) {
- window.location.reload();
+ return (contact.h || contact.u) in M.u;
+ }
+ _attachRerenderCbContacts(others) {
+ if (!this._validContact()) {
+ return;
}
- return stay;
- };
- const doShowLoginDialog = function () {
- mega.ui.showLoginRequiredDialog({
- minUserType: 3,
- skipInitialDialog: 1,
- onLoginSuccessCb
- }).done(() => {
- if (page !== 'login' && onLoginSuccessCb) {
- onLoginSuccessCb();
- }
- });
- };
- const doShowRegisterDialog = function () {
- mega.ui.showRegisterDialog({
- title: l[5840],
- onCreatingAccount () {},
- onLoginAttemptFailed () {
- msgDialog(`warninga:${ l[171]}`, l[1578], l[218], null, (e) => {
- if (e) {
- $('.pro-register-dialog').addClass('hidden');
- if (signupPromptDialog) {
- signupPromptDialog.hide();
- }
- doShowLoginDialog();
- }
- });
- },
- onAccountCreated (gotLoggedIn, registerData) {
- if (finish(!gotLoggedIn)) {
- security.register.cacheRegistrationData(registerData);
- mega.ui.sendSignupLinkDialog(registerData);
- megaChat.destroy();
- }
- },
- onLoginSuccessCb
- });
- };
- if (u_handle && u_handle !== "AAAAAAAAAAA") {
- return finish();
- }
- if (forceRegister) {
- return doShowRegisterDialog();
- } else if (forceLogin) {
- return doShowLoginDialog();
+ this.addDataStructListenerForProperties(this.props.contact, ['name', 'firstName', 'lastName', 'nickname', 'm', 'avatar'].concat(Array.isArray(others) ? others : []));
}
- if (u_wasloggedin()) {
- doShowLoginDialog();
- } else {
- doShowRegisterDialog();
+ attachRerenderCallbacks() {
+ this._attachRerenderCbContacts();
}
-};
-Chat.prototype.highlight = (text, matches, dontEscape) => {
- if (text && matches) {
- text = dontEscape ? text : escapeHTML(text);
- const tags = [];
- text = text.replace(/<[^>]+>/g, match => `@@!${ tags.push(match) - 1 }!@@`).split(' ');
- const done = [];
- for (let i = 0; i < matches.length; i++) {
- const match = matches[i].str;
- if (!done.includes(match)) {
- done.push(match);
- for (let j = 0; j < text.length; j++) {
- const word = text[j];
- const wordNormalized = ChatSearch._normalize_str(word);
- const matchPos = wordNormalized.indexOf(match);
- if (matchPos > -1) {
- const split = wordNormalized.split(match);
- text[j] = wordNormalized === word ? split.join(`[$]${match}[/$]`) : megaChat._highlightDiacritics(word, matchPos, split, match);
- }
- }
+ loadContactInfo() {
+ let _contact$avatar;
+ if (!this._validContact()) {
+ return;
+ }
+ const {
+ contact,
+ chatRoom
+ } = this.props;
+ const contactHandle = contact.h || contact.u;
+ const syncName = !ContactAwareComponent.unavailableNames[contactHandle] && !contact.firstName && !contact.lastName;
+ const syncMail = megaChat.FORCE_EMAIL_LOADING || (contact.c === 1 || contact.c === 2) && !contact.m && !is_chatlink;
+ const syncAvtr = (is_chatlink && (!contact.avatar || ((_contact$avatar = contact.avatar) == null ? void 0 : _contact$avatar.type) === "text") || !contact.avatar) && !avatars[contactHandle] && !ContactAwareComponent.unavailableAvatars[contactHandle];
+ const loader = () => {
+ if (!this.isComponentEventuallyVisible()) {
+ this.__isLoadingContactInfo = null;
+ this._requiresUpdateOnResize = true;
+ return;
}
+ const promises = [];
+ const chatHandle = is_chatlink.ph || chatRoom && chatRoom.publicChatHandle;
+ if (syncName) {
+ promises.push(megaChat.plugins.userHelper.getUserName(contactHandle, chatHandle));
+ }
+ if (syncMail) {
+ promises.push(M.syncContactEmail(contactHandle));
+ }
+ if (syncAvtr) {
+ promises.push(useravatar.loadAvatar(contactHandle, chatHandle).catch(() => {
+ ContactAwareComponent.unavailableAvatars[contactHandle] = true;
+ }));
+ }
+ return Promise.allSettled(promises).always(() => {
+ this.eventuallyUpdate();
+ this.__isLoadingContactInfo = false;
+ if (!contact.firstName && !contact.lastName) {
+ ContactAwareComponent.unavailableNames[contactHandle] = true;
+ }
+ });
+ };
+ if (syncName || syncMail || syncAvtr) {
+ (this.__isLoadingContactInfo = tSleep(0.3)).then(loader).catch(dump);
}
- text = text.join(' ').replace(/\@\@\!\d+\!\@\@/g, match => {
- return tags[parseInt(match.replace("@@!", "").replace("!@@"), 10)];
- });
- return text.replace(/\[\$]/g, '').replace(/\[\/\$]/g, '');
- }
- return null;
-};
-Chat.prototype._highlightDiacritics = function (word, matchPos, split, match) {
- const parts = [];
- const origMatch = word.substring(matchPos, matchPos + match.length);
- let pos = 0;
- for (let k = 0; k < split.length; k++) {
- parts.push(word.substring(pos, pos + split[k].length));
- pos = pos + split[k].length + match.length;
}
- return parts.join(`[$]${origMatch}[/$]`);
-};
-Chat.prototype.html = function (content) {
- if (content) {
- return this.plugins.emoticonsFilter.processHtmlMessage(escapeHTML(content));
+ componentDidUpdate() {
+ super.componentDidUpdate();
+ if (this.__isLoadingContactInfo === null) {
+ this.loadContactInfo();
+ }
}
- return '';
-};
-Chat.prototype.updateKeysInProtocolHandlers = function () {
- this.chats.forEach(r => {
- const ph = r.protocolHandler;
- if (ph) {
- ph.reinitWithNewData(u_handle, u_privCu25519, u_privEd25519, u_pubEd25519, ph.chatMode);
+ componentWillUnmount() {
+ super.componentWillUnmount();
+ if (this.__isLoadingContactInfo) {
+ this.__isLoadingContactInfo.abort();
+ this.__isLoadingContactInfo = false;
}
- });
-};
-Chat.prototype.eventuallyInitMeetingUI = function () {
- if (!window.location.hash) {
- return;
}
- let loc = page.split("#")[0];
- loc = loc.replace("fm/", "/");
- if (loc.indexOf("chat/") === 0) {
- this.initialPubChatHandle = loc.substr(5).split("?")[0];
+ isLoadingContactInfo() {
+ return !!this.__isLoadingContactInfo;
}
+}
+ContactAwareComponent.unavailableAvatars = Object.create(null);
+ContactAwareComponent.unavailableNames = Object.create(null);
+
+ },
+
+ 8022
+(_, EXP_, REQ_) {
+
+"use strict";
+ REQ_.d(EXP_, {
+ BE: () => ContactFingerprint,
+ U5: () => MembersAmount,
+ bq: () => ContactButton,
+ eu: () => Avatar,
+ hU: () => ContactPickerWidget,
+ hm: () => ContactPickerDialog,
+ i1: () => ContactPresence,
+ lO: () => MAX_FREQUENTS,
+ n4: () => ContactVerified,
+ nB: () => ContactCard,
+ uA: () => ContactAwareName
+ });
+
+ const _babel_runtime_helpers_extends0__ = REQ_(8168);
+ const react1__ = REQ_(1594);
+ const react1___default = REQ_.n(react1__);
+ const _mixins2__ = REQ_(8264);
+ const _ui_utils_jsx3__ = REQ_(6411);
+ const _ui_perfectScrollbar_jsx4__ = REQ_(1301);
+ const _ui_buttons_jsx5__ = REQ_(5155);
+ const _ui_dropdowns_jsx6__ = REQ_(1510);
+ const _ui_modalDialogs7__ = REQ_(8120);
+ const _link_jsx8__ = REQ_(4649);
+ const _updateObserver_jsx9__ = REQ_(4372);
+ const _contactsPanel_utils_jsx10__ = REQ_(836);
+
+
+
+
+
+
+
+
+
+
+
+
+const MAX_FREQUENTS = 3;
+const closeDropdowns = () => {
+ document.dispatchEvent(new Event('closeDropdowns'));
};
-Chat.prototype.enqueueChatRoomEvent = function (eventName, eventData) {
- if (!this.is_initialized) {
- return;
+class ContactButton extends _mixins2__ .u9 {
+ constructor(props) {
+ super(props);
+ this.dropdownItemGenerator = this.dropdownItemGenerator.bind(this);
}
- const {
- chatId
- } = eventData;
- if (!this._queuedChatRoomEvents[chatId]) {
- this._queuedChatRoomEvents[chatId] = [];
- (this._queuedChatRoomEvents[chatId].timer = tSleep(15)).then(() => {
- if (d) {
- this.logger.warn('Timer ran out, events lost...', this._queuedChatRoomEvents[chatId]);
- }
- delete this._queuedChatRoomEvents[chatId];
- });
+ customIsEventuallyVisible() {
+ if (this.props.chatRoom) {
+ return this.props.chatRoom.isCurrentlyActive;
+ }
+ return -1;
}
- this._queuedChatRoomEvents[chatId].push([eventName, eventData]);
-};
-Chat.prototype.autoJoinIfNeeded = function () {
- const rawAutoLoginInfo = localStorage.autoJoinOnLoginChat;
- if (u_type && rawAutoLoginInfo) {
- const autoLoginChatInfo = tryCatch(JSON.parse.bind(JSON))(rawAutoLoginInfo) || false;
- if (unixtime() - 7200 < autoLoginChatInfo[1]) {
- const req = this.plugins.chatdIntegration.getMciphReqFromHandleAndKey(autoLoginChatInfo[0], autoLoginChatInfo[2].substr(1));
- megaChat.rebind('onRoomInitialized.autoJoin', (e, megaRoom) => {
- if (megaRoom.chatId === autoLoginChatInfo[3]) {
- megaRoom.setActive();
- megaChat.unbind('onRoomInitialized.autoJoin');
- localStorage.removeItem("autoJoinOnLoginChat");
+ dropdownItemGenerator() {
+ let {
+ contact,
+ dropdowns,
+ chatRoom,
+ dropdownRemoveButton
+ } = this.props;
+ dropdowns = dropdowns ? dropdowns : [];
+ const moreDropdowns = [];
+ moreDropdowns.push(JSX_("div", {
+ className: "dropdown-avatar rounded",
+ key: "mainContactInfo",
+ onClick: () => {
+ if (contact.c === 2) {
+ loadSubPage('fm/account');
}
- });
- asyncApiReq(req).catch(dump);
- } else {
- localStorage.removeItem("autoJoinOnLoginChat");
+ if (contact.c === 1) {
+ loadSubPage(`fm/chat/contacts/${ contact.u}`);
+ }
+ }
+ }, JSX_(Avatar, {
+ className: "avatar-wrapper context-avatar",
+ chatRoom,
+ contact,
+ hideVerifiedBadge: "true"
+ }), JSX_("div", {
+ className: "dropdown-user-name"
+ }, JSX_("div", {
+ className: "name"
+ }, JSX_(ContactAwareName, {
+ overflow: true,
+ contact
+ }), JSX_(ContactPresence, {
+ className: "small",
+ contact
+ })), contact && (megaChat.FORCE_EMAIL_LOADING || contact.c === 1 || contact.c === 2) && JSX_("span", {
+ className: "email"
+ }, contact.m))));
+ moreDropdowns.push(JSX_(ContactFingerprint, {
+ key: "fingerprint",
+ contact
+ }));
+ if (dropdowns.length && contact.c !== 2) {
+ moreDropdowns.push(dropdowns);
+ moreDropdowns.push(JSX_("hr", {
+ key: "top-separator"
+ }));
}
- }
-};
-Chat.prototype.openScheduledMeeting = function (meetingId, toCall) {
- const meeting = this.scheduledMeetings[meetingId];
- if (!meeting) {
- console.warn('Meeting does not exist', meetingId);
- return;
- }
- window.focus();
- meeting.chatRoom.activateWindow();
- meeting.chatRoom.show();
- if (toCall && this.hasSupportForCalls) {
- this.openScheduledMeeting._queue = this.openScheduledMeeting._queue || [];
- this.openScheduledMeeting._queue.push(meetingId);
- delay('megachat:openScheduledMeetingCall', () => {
- const meetingId = this.openScheduledMeeting._queue[0];
- delete this.openScheduledMeeting._queue;
- const meetingRoom = this.scheduledMeetings[meetingId].chatRoom;
- meetingRoom.activateWindow();
- meetingRoom.show();
- const haveCall = this.haveAnyActiveCall();
- if (haveCall && window.sfuClient) {
- const {
- chatRoom
- } = this.activeCall;
- if (chatRoom && chatRoom.chatId === meetingRoom.chatId) {
- const peers = chatRoom.getCallParticipants();
- if (peers.includes(u_handle)) {
- return d && console.warn('Already in this call');
+ if (contact.u === u_handle) {
+ moreDropdowns.push(JSX_(_ui_dropdowns_jsx6__ .tJ, {
+ key: "view0",
+ icon: "sprite-fm-mono icon-user-filled",
+ label: l[187],
+ onClick: () => loadSubPage('fm/account')
+ }));
+ }
+ if (contact.c === 1) {
+ const startAudioCall = () => {
+ megaChat.createAndShowPrivateRoom(contact.u).then(room => {
+ room.setActive();
+ room.startAudioCall();
+ });
+ };
+ if (megaChat.currentlyOpenedChat && megaChat.currentlyOpenedChat === contact.u) {
+ moreDropdowns.push(JSX_("div", {
+ key: "startAudioVideoCall",
+ "data-simpletipposition": "top",
+ className: "simpletip",
+ "data-simpletip": !megaChat.hasSupportForCalls ? l.call_not_suported : ''
+ }, JSX_(_ui_dropdowns_jsx6__ .tJ, {
+ disabled: !megaChat.hasSupportForCalls,
+ key: "startCall",
+ className: "sprite-fm-mono-before icon-arrow-right-before",
+ icon: "sprite-fm-mono icon-phone",
+ submenu: megaChat.hasSupportForCalls,
+ label: l[19125]
+ }), JSX_("div", {
+ className: "dropdown body submenu",
+ key: "dropdownGroup"
+ }, JSX_("div", null, JSX_(_ui_dropdowns_jsx6__ .tJ, {
+ key: "startAudio",
+ icon: "sprite-fm-mono icon-phone",
+ disabled: !megaChat.hasSupportForCalls,
+ label: l[1565],
+ onClick: startAudioCall
+ })), JSX_("div", null, JSX_(_ui_dropdowns_jsx6__ .tJ, {
+ key: "startVideo",
+ icon: "sprite-fm-mono icon-video-call-filled",
+ disabled: !megaChat.hasSupportForCalls,
+ label: l[1566],
+ onClick: () => {
+ megaChat.createAndShowPrivateRoom(contact.u).then(room => {
+ room.setActive();
+ room.startVideoCall();
+ });
+ }
+ })))));
+ } else {
+ moreDropdowns.push(JSX_(_ui_dropdowns_jsx6__ .tJ, {
+ key: "startChat",
+ icon: "sprite-fm-mono icon-chat",
+ label: l[5885],
+ onClick: () => {
+ loadSubPage(`fm/chat/p/${ contact.u}`);
+ }
+ }));
+ }
+ moreDropdowns.push(JSX_("hr", {
+ key: "files-separator"
+ }));
+ moreDropdowns.push(JSX_(_ui_dropdowns_jsx6__ .tJ, {
+ key: "send-files-item",
+ icon: "sprite-fm-mono icon-send-files",
+ label: l[6834],
+ disabled: mega.paywall,
+ onClick: () => {
+ megaChat.openChatAndSendFilesDialog(contact.u);
+ }
+ }));
+ moreDropdowns.push(JSX_(_ui_dropdowns_jsx6__ .tJ, {
+ key: "share-item",
+ icon: "sprite-fm-mono icon-folder-outgoing-share",
+ label: l[6775],
+ onClick: () => {
+ openCopyShareDialog(contact.u);
+ }
+ }));
+ } else if (!is_chatlink && !is_eplusplus && (!contact.c || contact.c === 2 && contact.u !== u_handle)) {
+ moreDropdowns.push(JSX_(_ui_dropdowns_jsx6__ .tJ, {
+ key: "view2",
+ icon: "sprite-fm-mono icon-add",
+ label: l[101],
+ onClick: () => {
+ const isAnonymousUser = !u_handle || u_type !== 3;
+ const ADD_CONTACT = 'addContact';
+ if (is_chatlink && isAnonymousUser) {
+ megaChat.loginOrRegisterBeforeJoining(undefined, undefined, undefined, true);
+ if (localStorage.getItem(ADD_CONTACT) === null) {
+ localStorage.setItem(ADD_CONTACT, JSON.stringify({
+ u: contact.u,
+ unixTime: unixtime()
+ }));
+ }
+ } else {
+ loadingDialog.show();
+ M.syncContactEmail(contact.u, true).then(email => {
+ if (Object.values(M.opc || {}).some(cr => cr.m === email)) {
+ closeDialog();
+ msgDialog('warningb', '', l[17545]);
+ } else {
+ M.inviteContact(M.u[u_handle].m, email);
+ const title = l[150];
+ const msg = l[5898].replace('[X]', email);
+ closeDialog();
+ msgDialog('info', title, msg.replace('[X]', email));
+ }
+ }).catch(() => {
+ const {
+ chatRoom
+ } = this.props;
+ const {
+ u: userHandle
+ } = contact;
+ if (chatRoom.call) {
+ return mBroadcaster.sendMessage('meetings:ephemeralAdd', userHandle);
+ }
+ const name = M.getNameByHandle(userHandle);
+ return msgDialog('info', '', l.ephemeral_title ? l.ephemeral_title.replace('%1', name) : `${name} is using an ephemeral session.`, l.ephemeral_info);
+ }).finally(() => loadingDialog.hide());
}
}
+ }));
+ }
+ if (u_attr && contact.u !== u_handle) {
+ if (moreDropdowns.length > 0 && !(moreDropdowns.length === 2 && moreDropdowns[1] && moreDropdowns[1].key === "fingerprint")) {
+ moreDropdowns.push(JSX_("hr", {
+ key: "nicknames-separator"
+ }));
}
- (0,call.dQ)(true, meetingRoom).then(() => meetingRoom.startAudioCall(true)).catch(ex => d && console.warn('Already in a call.', ex));
- });
+ moreDropdowns.push(JSX_(_ui_dropdowns_jsx6__ .tJ, {
+ key: "set-nickname",
+ icon: "sprite-fm-mono icon-rename",
+ label: contact.nickname === '' ? l.set_nickname_label : l.edit_nickname_label,
+ onClick: () => nicknames.setNicknameDialog.init(contact.u)
+ }));
+ }
+ if (dropdownRemoveButton && dropdownRemoveButton.length) {
+ moreDropdowns.push(JSX_("hr", {
+ key: "remove-separator"
+ }));
+ moreDropdowns.push(dropdownRemoveButton);
+ }
+ return moreDropdowns;
+ }
+ render() {
+ let {
+ label = '',
+ className = '',
+ contact,
+ dropdownIconClasses = [],
+ verticalOffset,
+ dropdownDisabled,
+ noLoading,
+ noContextMenu
+ } = this.props;
+ let dropdownPosition = "left top";
+ let vertOffset = 0;
+ let horizOffset = -30;
+ if (!contact) {
+ return null;
+ }
+ if (label) {
+ className = `user-card-name ${className}${className.includes('message') ? '' : ' selectable-txt'}`;
+ dropdownIconClasses = '';
+ dropdownPosition = 'left bottom';
+ vertOffset = 25;
+ horizOffset = 0;
+ }
+ if (typeof verticalOffset !== 'undefined') {
+ vertOffset = verticalOffset;
+ }
+ if (!contact.name && !contact.m && !noLoading && this.isLoadingContactInfo()) {
+ label = JSX_("em", {
+ className: "contact-name-loading"
+ });
+ className = `contact-button-loading ${className}`;
+ }
+ return noContextMenu ? JSX_("div", {
+ className: "user-card-name light selectable-txt"
+ }, label) : JSX_(_ui_buttons_jsx5__ .$, {
+ className,
+ icon: dropdownIconClasses,
+ disabled: dropdownDisabled,
+ label
+ }, JSX_(_ui_dropdowns_jsx6__ .ms, {
+ className: "context contact-card-dropdown",
+ positionMy: dropdownPosition,
+ positionAt: dropdownPosition,
+ vertOffset,
+ horizOffset,
+ dropdownItemGenerator: this.dropdownItemGenerator,
+ noArrow: true
+ }));
}
+}
+ContactButton.defaultProps = {
+ 'manualDataChangeTracking': true,
+ 'skipQueuedUpdatesOnResize': true
};
-Chat.prototype.playSound = tryCatch((sound, options, stop) => {
- if (options === true) {
- stop = true;
- options = undefined;
+class ContactVerified extends _mixins2__ .w9 {
+ attachRerenderCallbacks() {
+ this.addDataStructListenerForProperties(this.props.contact, ['fingerprint']);
}
- if (stop) {
- ion.sound.stop(sound);
+ render() {
+ if (is_chatlink) {
+ return null;
+ }
+ const {contact} = this.props;
+ if (!contact) {
+ return null;
+ }
+ if (u_authring && u_authring.Ed25519) {
+ const verifyState = u_authring.Ed25519[contact.u] || {};
+ if (verifyState.method >= authring.AUTHENTICATION_METHOD.FINGERPRINT_COMPARISON) {
+ return JSX_("div", {
+ className: `
+ user-card-verified
+ ${this.props.className || ''}
+ `
+ });
+ }
+ } else if (!pubEd25519[contact.u]) {
+ crypt.getPubEd25519(contact.u).then(() => {
+ if (pubEd25519[contact.u]) {
+ this.safeForceUpdate();
+ }
+ });
+ }
+ return null;
}
- return ion.sound.play(sound, options);
-});
-Chat.prototype.fetchSoundBuffer = async function (sound) {
- if (this.SOUNDS.buffers[sound]) {
- return this.SOUNDS.buffers[sound].slice();
+}
+ContactVerified.defaultProps = {
+ 'manualDataChangeTracking': true,
+ 'skipQueuedUpdatesOnResize': true
+};
+class ContactPresence extends _mixins2__ .w9 {
+ constructor(...args) {
+ super(...args);
+ this.domRef = react1___default().createRef();
}
- let res = await M.xhr({
- url: `${staticpath}media/${sound}.mp3`,
- type: 'arraybuffer'
- }).catch(() => {
- console.warn('Failed to fetch sound .mp3 file', sound);
- });
- if (!res) {
- res = await M.xhr({
- url: `${staticpath}media/${sound}.ogg`,
- type: 'arraybuffer'
- }).catch(() => {
- console.error('Failed to fetch sound .ogg file', sound);
- });
- }
- if (!res) {
- throw ENOENT;
+ attachRerenderCallbacks() {
+ this.addDataStructListenerForProperties(this.props.contact, ['presence']);
}
- this.SOUNDS.buffers[sound] = res.target.response.slice();
- return res.target.response;
-};
-window.Chat = Chat;
-if (false) // removed by dead control flow
-{}
-const chat = {
- Chat
-};
-
-},
-
-623
-() {
-
-(function () {
- const ChatGlobalEventManager = function () {};
- lazy(ChatGlobalEventManager.prototype, 'listeners', function () {
- window.addEventListener('hashchange', ev => this.triggered(ev));
- $(window).rebind('resize.chatGlobalEventManager', ev => this.triggered(ev));
- const listeners = Object.create(null);
- listeners.resize = Object.create(null);
- listeners.hashchange = Object.create(null);
- return listeners;
- });
- ChatGlobalEventManager.prototype.addEventListener = function (eventName, namespace, cb) {
- this.listeners[eventName][namespace] = this.listeners[namespace] || cb;
- };
- ChatGlobalEventManager.prototype.removeEventListener = function (eventName, namespace) {
- delete this.listeners[eventName][namespace];
- };
- ChatGlobalEventManager.prototype.triggered = SoonFc(140, function _chatEVDispatcher(ev) {
- if (M.chat) {
- const listeners = this.listeners[ev.type];
- for (const k in listeners) {
- listeners[k](ev);
- }
+ render() {
+ const {
+ contact,
+ className
+ } = this.props;
+ if (!contact || !contact.c) {
+ return null;
}
- });
- window.chatGlobalEventManager = new ChatGlobalEventManager();
-})();
-
-},
-
-553
-(_, EXP_, REQ_) {
-
-"use strict";
-// ESM COMPAT FLAG
-REQ_.r(EXP_);
-
-// EXPORTS
-REQ_.d(EXP_, {
- MCO_FLAGS: () => MCO_FLAGS,
- RETENTION_FORMAT: () => RETENTION_FORMAT,
- "default": () => chatRoom
-});
-
-;// ./js/chat/utils.jsx
-async function prepareExportIo(dl) {
- const {
- zname,
- size
- } = dl;
- if (window.isSecureContext && typeof showSaveFilePicker === 'function' && typeof FileSystemFileHandle !== 'undefined' && 'createWritable' in FileSystemFileHandle.prototype && typeof FileSystemWritableFileStream !== 'undefined' && 'seek' in FileSystemWritableFileStream.prototype) {
- const file = await window.showSaveFilePicker({
- suggestedName: zname
- }).catch(ex => {
- if (String(ex).includes('aborted')) {
- throw new Error('Aborted');
- }
- dump(ex);
+ return JSX_("div", {
+ ref: this.domRef,
+ className: `
+ user-card-presence
+ ${megaChat.userPresenceToCssClass(contact.presence)}
+ ${className || ''}
+ `
});
- if (file) {
- const stream = await file.createWritable().catch(dump);
- if (stream) {
- return {
- stream,
- write (data, position, done) {
- this.stream.write({
- type: 'write',
- position,
- data
- }).then(done).catch(dump);
- },
- download () {
- this.abort();
- },
- abort () {
- this.stream.close();
- },
- setCredentials () {
- this.begin();
- }
- };
- }
- }
- }
- if (MemoryIO.usable() && Math.min(MemoryIO.fileSizeLimit, 94371840) > size) {
- return new MemoryIO('chat_0', dl);
- } else if (window.requestFileSystem) {
- return new FileSystemAPI('chat_0', dl);
}
- throw new Error('Download methods are unsupported');
-}
-function prepareExportStreams(attachNodes, onEmpty) {
- return attachNodes.map(node => {
- return {
- name: node.name,
- lastModified: new Date((node.mtime || node.ts) * 1000),
- input: M.gfsfetch.getReadableStream(node, {
- error(ex, n) {
- if (d) {
- console.error(`${n.h}: ${ex}`);
- }
- onEmpty(n.s);
- }
- })
- };
- });
}
-;// ./js/chat/chatRoom.jsx
-
-const RETENTION_FORMAT = {
- HOURS: 'hour',
- DAYS: 'day',
- WEEKS: 'week',
- MONTHS: 'month',
- DISABLED: 'none'
-};
-const MCO_FLAGS = {
- OPEN_INVITE: 'oi',
- SPEAK_REQUEST: 'sr',
- WAITING_ROOM: 'w'
+ContactPresence.defaultProps = {
+ manualDataChangeTracking: true,
+ skipQueuedUpdatesOnResize: true
};
-window.RETENTION_FORMAT = RETENTION_FORMAT;
-window.MCO_FLAGS = MCO_FLAGS;
-const ChatRoom = function (megaChat, roomId, type, users, ctime, lastActivity, chatId, chatShard, chatdUrl, noUI, publicChatHandle, publicChatKey, ck, isMeeting, retentionTime, mcoFlags, organiser) {
- const self = this;
- this.logger = MegaLogger.getLogger(`room[${ roomId }]`, {}, megaChat.logger);
- this.megaChat = megaChat;
- MegaDataObject.call(this, {
- state: null,
- users: [],
- roomId: null,
- type: null,
- messages: [],
- ctime: 0,
- lastActivity: 0,
- callRequest: null,
- isCurrentlyActive: false,
- _messagesQueue: [],
- unreadCount: 0,
- chatId: undefined,
- chatdUrl: undefined,
- chatShard: undefined,
- members: {},
- membersSet: false,
- membersLoaded: false,
- topic: '',
- flags: 0x00,
- publicLink: null,
- observers: 0,
- dnd: null,
- alwaysNotify: null,
- retentionTime: 0,
- activeCallIds: null,
- meetingsLoading: null,
- options: {},
- scheduledMeeting: undefined,
- historyTimedOut: false
- });
- this.roomId = roomId;
- this.instanceIndex = ChatRoom.INSTANCE_INDEX++;
- this.type = type;
- this.ctime = ctime;
- this.lastActivity = lastActivity ? lastActivity : 0;
- this.chatd = megaChat.plugins.chatdIntegration.chatd;
- this.chatId = chatId;
- this.chatIdBin = chatId ? base64urldecode(chatId) : "";
- this.chatShard = chatShard;
- this.chatdUrl = chatdUrl;
- this.publicLink = null;
- this.publicChatHandle = publicChatHandle;
- this.publicChatKey = publicChatKey;
- this.ck = ck;
- this.scrolledToBottom = 1;
- this.callRequest = null;
- this.shownMessages = {};
- this.retentionTime = retentionTime;
- this.activeSearches = 0;
- this.activeCallIds = new MegaDataMap(this);
- this.ringingCalls = new MegaDataMap(this);
- this.isMeeting = isMeeting;
- this.isNote = type === 'private' && roomId === u_handle;
- this.callUserLimited = false;
- this.members = Object.create(null);
- Object.defineProperty(this.members, 'hasOwnProperty', {
- value(p) {
- return p in this;
- }
- });
- if (type === "private") {
- users.forEach((userHandle) => {
- self.members[userHandle] = 3;
- });
- } else {
- users.forEach((userHandle) => {
- self.members[userHandle] = 0;
- });
- }
- this.options = {};
- mcoFlags = mcoFlags || {};
- for (const flag of Object.values(MCO_FLAGS)) {
- this.options[flag] = mcoFlags[flag] || 0;
+const LastActivity = (0,_mixins2__ .Zz)(_updateObserver_jsx9__ .Y)((() => class LastActivity extends _mixins2__ .u9 {
+ attachRerenderCallbacks() {
+ this._attachRerenderCbContacts(['ats', 'lastGreen', 'presence']);
}
- this.organiser = organiser;
- this.setState(ChatRoom.STATE.INITIALIZED);
- this.isCurrentlyActive = false;
- if (d) {
- this.rebind('onStateChange.chatRoomDebug', (e, oldState, newState) => {
- self.logger.debug("Will change state from: ", ChatRoom.stateToText(oldState), " to ", ChatRoom.stateToText(newState));
- });
+ shouldComponentUpdate() {
+ return true;
}
- self.rebind('onStateChange.chatRoom', (e, oldState, newState) => {
- if (newState === ChatRoom.STATE.READY && !self.isReadOnly() && self.chatd && self.isOnline() && self.chatIdBin) {
- if (d > 2) {
- self.logger.warn('Restoring persisted messages...', self.type, self.isCurrentlyActive);
- }
- const cim = self.getChatIdMessages();
- cim.restore(true);
+ render() {
+ const {
+ contact,
+ showLastGreen
+ } = this.props;
+ if (!contact) {
+ return null;
}
- });
- self.rebind('onMessagesBuffAppend.lastActivity', (e, msg) => {
- if (is_chatlink || self.isNote) {
- return;
+ const lastActivity = !contact.ats || contact.lastGreen > contact.ats ? contact.lastGreen : contact.ats;
+ const SECONDS = Date.now() / 1000 - lastActivity;
+ const timeToLast = SECONDS > 3888000 ? l[20673] : time2last(lastActivity, true);
+ const hasActivityStatus = showLastGreen && contact.presence <= 2 && lastActivity;
+ return JSX_("span", null, hasActivityStatus ? (l[19994] || 'Last seen %s').replace('%s', timeToLast) : M.onlineStatusClass(contact.presence)[0]);
+ }
+})());
+class ContactAwareName extends _mixins2__ .u9 {
+ render() {
+ const {
+ contact,
+ emoji,
+ overflow
+ } = this.props;
+ if (!contact || !M.u[contact.u || contact.h]) {
+ return null;
}
- const ts = msg.delay ? msg.delay : msg.ts;
- if (!ts) {
- return;
+ const name = M.getNameByHandle(contact.u || contact.h);
+ if (emoji || overflow) {
+ const EmojiComponent = overflow ? _ui_utils_jsx3__ .sp : _ui_utils_jsx3__ .zT;
+ return JSX_(EmojiComponent, this.props, name);
}
- const contactForMessage = msg && Message.getContactForMessage(msg);
- if (contactForMessage && contactForMessage.u !== u_handle) {
- if (!contactForMessage.ats || contactForMessage.ats < ts) {
- contactForMessage.ats = ts;
- }
+ return JSX_("span", null, name);
+ }
+}
+class MembersAmount extends _mixins2__ .u9 {
+ render() {
+ const {
+ chatRoom
+ } = this.props;
+ return JSX_("span", null, mega.icu.format(l[20233], Object.keys(chatRoom.members).length));
+ }
+}
+class ContactFingerprint extends _mixins2__ .w9 {
+ constructor(...args) {
+ super(...args);
+ this.domRef = react1___default().createRef();
+ }
+ attachRerenderCallbacks() {
+ this.addDataStructListenerForProperties(this.props.contact, ['fingerprint']);
+ }
+ render() {
+ const {
+ contact,
+ className
+ } = this.props;
+ if (!contact || !contact.u || is_chatlink) {
+ return null;
}
- if (self.lastActivity && self.lastActivity >= ts) {
- if (msg.deleted) {
- const {
- delay,
- ts
- } = self.messagesBuff.getLastMessageFromServer();
- self.lastActivity = delay || ts;
+ const infoBlocks = [];
+ userFingerprint(contact.u, (fingerprints) => {
+ fingerprints.forEach((v, k) => {
+ infoBlocks.push(JSX_("span", {
+ key: `fingerprint-${ k}`
+ }, v));
+ });
+ });
+ let verifyButton = null;
+ if (contact.c === 1 && u_authring && u_authring.Ed25519) {
+ const verifyState = u_authring.Ed25519[contact.u] || {};
+ if (typeof verifyState.method === "undefined" || verifyState.method < authring.AUTHENTICATION_METHOD.FINGERPRINT_COMPARISON) {
+ verifyButton = JSX_(_ui_buttons_jsx5__ .$, {
+ className: "dropdown-verify active",
+ label: l.verify_credentials,
+ icon: "sprite-fm-mono icon-key",
+ onClick: () => {
+ closeDropdowns();
+ fingerprintDialog(contact.u);
+ }
+ });
}
- return;
}
- self.lastActivity = ts;
- if (msg.userId === u_handle) {
- self.didInteraction(u_handle, ts);
- return;
+ return infoBlocks.length ? JSX_("div", {
+ ref: this.domRef,
+ className: `
+ dropdown-fingerprint
+ ${className || ''}
+ `
+ }, JSX_("div", {
+ className: "contact-fingerprint-title"
+ }, JSX_("span", null, l[6872])), JSX_("div", {
+ className: "contact-fingerprint-txt selectable-txt"
+ }, infoBlocks), verifyButton) : null;
+ }
+}
+ContactFingerprint.defaultProps = {
+ 'manualDataChangeTracking': true,
+ 'skipQueuedUpdatesOnResize': true
+};
+class Avatar extends _mixins2__ .u9 {
+ render() {
+ const self = this;
+ const {contact} = this.props;
+ if (!contact) {
+ return null;
}
- if (self.type === "private") {
- const targetUserId = self.getParticipantsExceptMe()[0];
- let targetUserNode;
- if (M.u[targetUserId]) {
- targetUserNode = M.u[targetUserId];
- } else if (msg.userId) {
- targetUserNode = M.u[msg.userId];
+ if (!contact.m && contact.email) {
+ contact.m = contact.email;
+ }
+ const avatarMeta = useravatar.generateContactAvatarMeta(contact);
+ let classes = `${this.props.className ? this.props.className : ' avatar-wrapper small-rounded-avatar' } ${ contact.u } in-chat`;
+ classes += " chat-avatar";
+ let displayedAvatar;
+ let verifiedElement = null;
+ if (!this.props.hideVerifiedBadge && !is_chatlink) {
+ verifiedElement = JSX_(ContactVerified, {
+ contact: this.props.contact,
+ className: this.props.verifiedClassName
+ });
+ }
+ const extraProps = {};
+ if (this.props.simpletip) {
+ classes += " simpletip";
+ if (this.props.simpletip === true) {
+ extraProps['data-simpletip'] = M.getNameByHandle(contact.h || contact.u) || megaChat.plugins.userHelper.SIMPLETIP_USER_LOADER;
} else {
- console.error("Missing participant in a 1on1 room.");
- return;
+ extraProps['data-simpletip'] = this.props.simpletip;
}
- assert(targetUserNode && targetUserNode.u, 'No hash found for participant');
- assert(M.u[targetUserNode.u], 'User not found in M.u');
- if (targetUserNode) {
- self.didInteraction(targetUserNode.u, self.lastActivity);
+ if (this.props.simpletipWrapper) {
+ extraProps['data-simpletipwrapper'] = this.props.simpletipWrapper;
}
- } else if (self.type === "group" || self.type === "public") {
- let contactHash;
- if (msg.authorContact) {
- contactHash = msg.authorContact.u;
- } else if (msg.userId) {
- contactHash = msg.userId;
+ if (this.props.simpletipOffset) {
+ extraProps['data-simpletipoffset'] = this.props.simpletipOffset;
}
- if (contactHash && M.u[contactHash]) {
- self.didInteraction(contactHash, self.lastActivity);
+ if (this.props.simpletipPosition) {
+ extraProps['data-simpletipposition'] = this.props.simpletipPosition;
+ }
+ if (this.props.simpletipClass) {
+ extraProps['data-simpletip-class'] = this.props.simpletipClass;
}
- assert(contactHash, 'Invalid hash for user (extracted from inc. message)');
- } else {
- throw new Error("Not implemented");
- }
- });
- self.rebind('onMembersUpdated.coreRoomDataMngmt', (e, eventData) => {
- if (self.state === ChatRoom.STATE.LEFT && eventData.priv >= 0 && eventData.priv < 255) {
- self.membersLoaded = false;
- self.setState(ChatRoom.STATE.JOINING, true);
}
- let queuedMembersUpdatedEvent = false;
- if (self.membersLoaded === false) {
- if (eventData.priv >= 0 && eventData.priv < 255) {
- const addParticipant = function addParticipant() {
- self.protocolHandler.addParticipant(eventData.userId);
- self.members[eventData.userId] = eventData.priv;
- ChatdIntegration._ensureContactExists([eventData.userId]);
- self.trigger('onMembersUpdatedUI', eventData);
- };
- if (is_chatlink) {
- megaChat.initContacts([eventData.userId]);
- }
- ChatdIntegration._waitForProtocolHandler(self, addParticipant);
- queuedMembersUpdatedEvent = true;
+ if (avatarMeta.type === "image") {
+ displayedAvatar = JSX_("div", (0,_babel_runtime_helpers_extends0__ .A)({
+ className: classes,
+ style: this.props.style
+ }, extraProps, {
+ onClick: self.props.onClick ? e => {
+ closeDropdowns();
+ self.props.onClick(e);
+ } : self.onClick
+ }), verifiedElement, JSX_("img", {
+ src: avatarMeta.avatar,
+ style: this.props.imgStyles
+ }));
+ } else {
+ classes += ` color${ avatarMeta.avatar.colorIndex}`;
+ const isLoading = self.isLoadingContactInfo();
+ if (isLoading) {
+ classes += " default-bg";
}
- } else if (eventData.priv === 255 || eventData.priv === -1) {
- const deleteParticipant = function deleteParticipant() {
- if (eventData.userId === u_handle) {
- Object.keys(self.members).forEach((userId) => {
- self.protocolHandler.removeParticipant(userId);
- self.members[userId] = userId === u_handle ? ChatRoom.MembersSet.PRIVILEGE_STATE.LEFT : ChatRoom.MembersSet.PRIVILEGE_STATE.READONLY;
- });
- } else {
- self.protocolHandler.removeParticipant(eventData.userId);
- delete self.members[eventData.userId];
- }
- self.trigger('onMembersUpdatedUI', eventData);
- };
- ChatdIntegration._waitForProtocolHandler(self, deleteParticipant);
- queuedMembersUpdatedEvent = true;
+ displayedAvatar = JSX_("div", (0,_babel_runtime_helpers_extends0__ .A)({
+ className: classes,
+ style: this.props.style
+ }, extraProps, {
+ onClick: self.props.onClick ? e => {
+ closeDropdowns();
+ self.props.onClick(e);
+ } : self.onClick
+ }), verifiedElement, JSX_("span", null, isLoading ? "" : avatarMeta.avatar.letters));
}
- if (eventData.userId === u_handle) {
- self.membersLoaded = true;
+ return displayedAvatar;
+ }
+}
+Avatar.defaultProps = {
+ 'manualDataChangeTracking': true,
+ 'skipQueuedUpdatesOnResize': true
+};
+class ContactCard extends _mixins2__ .u9 {
+ attachRerenderCallbacks() {
+ this._attachRerenderCbContacts(['presence']);
+ }
+ specShouldComponentUpdate(nextProps, nextState) {
+ const foundKeys = Object.keys(this.props);
+ if (foundKeys.includes('dropdowns')) {
+ array.remove(foundKeys, 'dropdowns', true);
}
- if (!queuedMembersUpdatedEvent) {
- self.members[eventData.userId] = eventData.priv;
- self.trigger('onMembersUpdatedUI', eventData);
+ let shouldUpdate;
+ if (foundKeys.length) {
+ const k = foundKeys[0];
+ shouldUpdate = shallowEqual(nextProps[k], this.props[k]);
}
- });
- if (is_chatlink && !is_chatlink.callId && !this.options.w) {
- const unbind = () => {
- self.unbind('onMessagesHistoryDone.chatlinkAlreadyIn');
- self.unbind('onMembersUpdated.chatlinkAlreadyIn');
- };
- self.rebind('onMembersUpdated.chatlinkAlreadyIn', (e, eventData) => {
- if (eventData.userId === u_handle && eventData.priv >= 0) {
- unbind();
- return this.megaChat.routing.reinitAndOpenExistingChat(this.chatId, this.publicChatHandle);
- }
- });
- self.rebind('onMessagesHistoryDone.chatlinkAlreadyIn', (e, data) => {
- if (!data.chatdPersist) {
- unbind();
- }
- });
- }
- self.rebind('onMembersUpdatedUI.chatRoomMembersSync', (e, eventData) => {
- if (eventData.userId === u_handle) {
- self.messagesBuff.joined = true;
- if (eventData.priv === 255 || eventData.priv === -1) {
- if (self.state === ChatRoom.STATE.JOINING) {
- self.setState(ChatRoom.STATE.LEFT);
- }
- } else {
- if (self.state === ChatRoom.STATE.JOINING) {
- self.setState(ChatRoom.STATE.READY);
- }
- }
+ if (!shouldUpdate) {
+ shouldUpdate = shallowEqual(nextState, this.state);
}
- self.trackDataChange();
- });
- self.getParticipantsExceptMe().forEach((userHandle) => {
- const contact = M.u[userHandle];
- if (contact && contact.c) {
- getLastInteractionWith(contact.u);
+ if (!shouldUpdate && this.state.props.dropdowns && nextProps.state.dropdowns && this.state.props.dropdowns.map && nextProps.state.dropdowns.map) {
+ const oldKeys = this.state.props.dropdowns.map(child => child.key);
+ const newKeys = nextProps.state.dropdowns.map(child => child.key);
+ if (!shallowEqual(oldKeys, newKeys)) {
+ shouldUpdate = true;
+ }
}
- });
- self.megaChat.trigger('onRoomCreated', [self]);
- if (this.type === "public" && self.megaChat.publicChatKeys[self.chatId]) {
- self.publicChatKey = self.megaChat.publicChatKeys[self.chatId];
+ return shouldUpdate;
}
- $(window).rebind(`focus.${ self.roomId}`, () => {
- if (self.isCurrentlyActive) {
- self.trigger("onChatShown");
- }
- });
- self.megaChat.rebind(`onRoomDestroy.${ self.roomId}`, (e, room) => {
- if (room.roomId == self.roomId) {
- $(window).off(`focus.${ self.roomId}`);
+ render() {
+ let _this$props$chatRoom;
+ const {
+ contact
+ } = this.props;
+ if (!contact) {
+ return null;
}
- });
- self.initialMessageHistLoaded = false;
- let timer = null;
- const _historyIsAvailable = ev => {
- self.initialMessageHistLoaded = ev ? true : -1;
- if (timer) {
- timer.abort();
- timer = null;
+ const pres = megaChat.userPresenceToCssClass(contact.presence);
+ let username = (this.props.namePrefix || '') + (M.getNameByHandle(contact.u) || contact.m);
+ if (contact.u === u_handle) {
+ username += ` (${escapeHTML(l[8885])})`;
}
- self.unbind('onMarkAsJoinRequested.initHist');
- self.unbind('onHistoryDecrypted.initHist');
- self.unbind('onMessagesHistoryDone.initHist');
- };
- self.rebind('onHistoryDecrypted.initHist', _historyIsAvailable);
- self.rebind('onMessagesHistoryDone.initHist', _historyIsAvailable);
- self.rebind('onMarkAsJoinRequested.initHist', () => {
- (timer = tSleep(300)).then(() => {
- if (d) {
- self.logger.warn("Timed out waiting to load hist for:", self.chatId || self.roomId);
- }
- this.historyTimedOut = true;
- this.trigger('onHistTimeoutChange');
- timer = null;
- _historyIsAvailable(false);
- });
- });
- self.rebind('onRoomDisconnected', () => {
- if (!self.call) {
- for (const activeCallId of self.activeCallIds.keys()) {
- self.activeCallIds.remove(activeCallId);
+ let escapedUsername = JSX_(_ui_utils_jsx3__ .sp, null, username);
+ const dropdowns = this.props.dropdowns || [];
+ const noContextMenu = this.props.noContextMenu || '';
+ const noContextButton = this.props.noContextButton || '';
+ const dropdownRemoveButton = this.props.dropdownRemoveButton || [];
+ const highlightSearchValue = this.props.highlightSearchValue || false;
+ const emailTooltips = this.props.emailTooltips || false;
+ const searchValue = this.props.searchValue || "";
+ let usernameBlock;
+ if (!noContextMenu) {
+ usernameBlock = JSX_(ContactButton, {
+ key: "lnk",
+ dropdowns,
+ noContextMenu,
+ contact,
+ className: "light",
+ label: escapedUsername,
+ chatRoom: this.props.chatRoom,
+ dropdownRemoveButton,
+ verticalOffset: 0
+ });
+ } else {
+ if (highlightSearchValue && searchValue.length > 0) {
+ const matches = [];
+ const regex = new RegExp(RegExpEscape(searchValue), 'gi');
+ let result;
+ while (result = regex.exec(username)) {
+ matches.push({
+ idx: result.index,
+ str: result[0]
+ });
+ }
+ if (matches.length > 0) {
+ escapedUsername = JSX_(_ui_utils_jsx3__ .P9, null, megaChat.highlight(megaChat.html(username), matches, true));
+ }
}
- megaChat.updateSectionUnreadCount();
- }
- });
- this.rebind(`onCallUserLimitExceeded.${chatId}`, () => {
- if (this.callUserLimited) {
- return;
- }
- (this.callUserLimited = tSleep(60)).always(() => {
- this.callUserLimited = false;
- this.trackDataChange();
- });
- });
- this.membersSetFromApi = new ChatRoom.MembersSet(this);
- if (publicChatHandle) {
- this.onPublicChatRoomInitialized();
- }
- return this;
-};
-inherits(ChatRoom, MegaDataObject);
-ChatRoom.STATE = {
- 'INITIALIZED': 5,
- 'JOINING': 10,
- 'JOINED': 20,
- 'READY': 150,
- 'ENDED': 190,
- 'LEAVING': 200,
- 'LEFT': 250
-};
-ChatRoom.INSTANCE_INDEX = 0;
-ChatRoom.ANONYMOUS_PARTICIPANT = mega.BID;
-ChatRoom.ARCHIVED = 0x01;
-ChatRoom.TOPIC_MAX_LENGTH = 30;
-ChatRoom.SCHEDULED_MEETINGS_INTERVAL = 1.8e6;
-ChatRoom._fnRequireParticipantKeys = function (fn, scope) {
- return function (...args) {
- const participants = this.protocolHandler.getTrackedParticipants();
- return ChatdIntegration._ensureKeysAreLoaded(undefined, participants).then(() => {
- return fn.apply(scope || this, args);
- }).catch(ex => {
- this.logger.error("Failed to retrieve keys..", ex);
- });
- };
-};
-ChatRoom.MembersSet = function (chatRoom) {
- this.chatRoom = chatRoom;
- this.members = {};
-};
-ChatRoom.MembersSet.PRIVILEGE_STATE = {
- NOT_AVAILABLE: -5,
- OPERATOR: 3,
- FULL: 2,
- READONLY: 0,
- LEFT: -1
-};
-ChatRoom.encryptTopic = function (protocolHandler, newTopic, participants, isPublic = false) {
- if (protocolHandler instanceof strongvelope.ProtocolHandler && participants.size > 0) {
- const topic = protocolHandler.embeddedEncryptTo(newTopic, strongvelope.MESSAGE_TYPES.TOPIC_CHANGE, participants, undefined, isPublic);
- if (topic) {
- return base64urlencode(topic);
+ usernameBlock = emailTooltips ? JSX_("div", {
+ className: "user-card-name light simpletip selectable-txt",
+ "data-simpletip": contact.m,
+ "data-simpletipposition": "top"
+ }, escapedUsername) : JSX_("div", {
+ className: "user-card-name light selectable-txt"
+ }, escapedUsername);
}
+ let userCard = null;
+ const className = this.props.className || '';
+ userCard = className.includes('short') ? JSX_("div", {
+ className: "user-card-data"
+ }, usernameBlock, JSX_("div", {
+ className: "user-card-status"
+ }, this.props.isInCall ? JSX_("div", {
+ className: "audio-call"
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-phone"
+ })) : null, JSX_(LastActivity, {
+ contact,
+ showLastGreen: this.props.showLastGreen
+ }))) : JSX_("div", {
+ className: "user-card-data"
+ }, usernameBlock, JSX_(ContactPresence, {
+ contact,
+ className: this.props.presenceClassName
+ }), this.props.isInCall ? JSX_("div", {
+ className: "audio-call"
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-phone"
+ })) : null, JSX_("div", {
+ className: "user-card-email selectable-txt"
+ }, contact.m));
+ return JSX_("div", {
+ className: `
+ contacts-info body
+ ${pres === 'offline' ? 'offline' : ''}
+ ${className || ''}
+ `,
+ style: this.props.style,
+ onClick: ev => {
+ let _this$props$onClick, _this$props;
+ return (_this$props$onClick = (_this$props = this.props).onClick) == null ? void 0 : _this$props$onClick.call(_this$props, contact, ev);
+ },
+ onDoubleClick: ev => {
+ let _this$props$onDoubleC, _this$props2;
+ return (_this$props$onDoubleC = (_this$props2 = this.props).onDoubleClick) == null ? void 0 : _this$props$onDoubleC.call(_this$props2, contact, ev);
+ }
+ }, this.props.withSelfNote ? JSX_("div", {
+ className: `
+ note-chat-signifier
+ ${(_this$props$chatRoom = this.props.chatRoom) != null && _this$props$chatRoom.hasMessages() ? '' : 'note-chat-empty'}
+ `
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-file-text-thin-outline note-chat-icon"
+ })) : JSX_(Avatar, {
+ className: "avatar-wrapper small-rounded-avatar",
+ contact,
+ chatRoom: this.props.chatRoom
+ }), is_chatlink || noContextButton ? null : JSX_(ContactButton, {
+ key: "button",
+ dropdowns,
+ dropdownIconClasses: this.props.dropdownIconClasses || '',
+ disabled: this.props.dropdownDisabled,
+ noContextMenu,
+ contact,
+ className: this.props.dropdownButtonClasses,
+ dropdownRemoveButton,
+ noLoading: this.props.noLoading,
+ chatRoom: this.props.chatRoom,
+ verticalOffset: 0
+ }), this.props.selectable ? JSX_("div", {
+ className: "user-card-tick-wrap"
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-check"
+ })) : null, megaChat.WITH_SELF_NOTE && this.props.withSelfNote ? JSX_("div", {
+ className: "user-card-data"
+ }, JSX_("div", {
+ className: "user-card-name light selectable-txt note-chat-label"
+ }, l.note_label), JSX_("div", {
+ className: "user-card-status"
+ })) : userCard);
}
- return false;
+}
+ContactCard.defaultProps = {
+ dropdownButtonClasses: "tiny-button",
+ dropdownIconClasses: "tiny-icon icons-sprite grey-dots",
+ presenceClassName: '',
+ manualDataChangeTracking: true,
+ skipQueuedUpdatesOnResize: true
};
-ChatRoom.MembersSet.prototype.trackFromActionPacket = function (ap, isMcf) {
- const self = this;
- const apMembers = {};
- (ap.u || []).forEach((r) => {
- apMembers[r.u] = r.p;
- });
- Object.keys(self.members).forEach((u_h) => {
- if (typeof apMembers[u_h] === 'undefined') {
- self.remove(u_h);
- } else if (apMembers[u_h] !== self.members[u_h]) {
- self.update(u_h, apMembers[u_h]);
- }
- });
- Object.keys(apMembers).forEach((u_h) => {
- if (typeof self.members[u_h] === 'undefined') {
- const priv2 = apMembers[u_h];
- !isMcf ? self.add(u_h, priv2) : self.init(u_h, priv2);
- } else if (apMembers[u_h] !== self.members[u_h]) {
- self.update(u_h, apMembers[u_h]);
+class ContactItem extends _mixins2__ .u9 {
+ render() {
+ const self = this;
+ const {contact} = this.props;
+ if (!contact) {
+ return null;
}
- });
- if (!isMcf && ap.m === 1 && !ap.n && ap.url && ap.ou !== u_handle && typeof ap.p === 'undefined' && !ap.topicChange) {
- self.chatRoom.trigger('onMeAdded', ap.ou);
+ const username = this.props.namePrefix ? this.props.namePrefix : `${ M.getNameByHandle(contact.u)}`;
+ return JSX_("div", {
+ className: "selected-contact-card short"
+ }, JSX_("div", {
+ className: "remove-contact-bttn",
+ onClick: e => {
+ if (self.props.onClick) {
+ self.props.onClick(contact, e);
+ }
+ }
+ }, JSX_("i", {
+ className: "tiny-icon small-cross"
+ })), JSX_(Avatar, {
+ contact,
+ className: "avatar-wrapper small-rounded-avatar",
+ hideVerifiedBadge: true,
+ chatRoom: this.props.chatRoom
+ }), JSX_("div", {
+ className: "user-card-data simpletip",
+ "data-simpletip": username || megaChat.plugins.userHelper.SIMPLETIP_USER_LOADER,
+ "data-simpletipposition": "top"
+ }, JSX_(ContactButton, {
+ noContextMenu: this.props.noContextMenu,
+ contact,
+ className: "light",
+ label: JSX_(_ui_utils_jsx3__ .zT, null, username),
+ chatRoom: this.props.chatRoom
+ })));
}
+}
+ContactItem.defaultProps = {
+ 'manualDataChangeTracking': true,
+ 'skipQueuedUpdatesOnResize': true
};
-ChatRoom.MembersSet.prototype.init = function (handle, privilege) {
- this.members[handle] = privilege;
- this.chatRoom.trackDataChange();
-};
-ChatRoom.MembersSet.prototype.update = function (handle, privilege) {
- this.members[handle] = privilege;
- this.chatRoom.trackDataChange();
-};
-ChatRoom.MembersSet.prototype.add = function (handle, privilege) {
- this.members[handle] = privilege;
- if (handle === u_handle) {
- this.chatRoom.trigger('onMeJoined');
- }
- this.chatRoom.trackDataChange();
-};
-ChatRoom.MembersSet.prototype.remove = function (handle) {
- delete this.members[handle];
- if (handle === u_handle) {
- this.chatRoom.trigger('onMeLeft');
- }
- this.chatRoom.trackDataChange();
-};
-ChatRoom.prototype.trackMemberUpdatesFromActionPacket = function (ap, isMcf) {
- if (!ap.u) {
- return;
- }
- if (this.membersSetFromApi) {
- this.membersSetFromApi.trackFromActionPacket(ap, isMcf);
- }
-};
-ChatRoom.prototype.getCallParticipants = function () {
- const ids = this.activeCallIds.keys();
- if (ids.length === 0) {
- return [];
- }
- return this.activeCallIds[ids[0]];
-};
-ChatRoom.prototype.getChatIdMessages = function () {
- return this.chatd.chatIdMessages[this.chatIdBin];
-};
-ChatRoom.prototype.getRetentionFormat = function (retentionTime) {
- retentionTime = retentionTime || this.retentionTime;
- switch (true) {
- case retentionTime === 0:
- return RETENTION_FORMAT.DISABLED;
- case retentionTime % daysToSeconds(30) === 0 || retentionTime >= 31536000:
- return RETENTION_FORMAT.MONTHS;
- case retentionTime % daysToSeconds(7) === 0:
- return RETENTION_FORMAT.WEEKS;
- case retentionTime % daysToSeconds(1) === 0:
- return RETENTION_FORMAT.DAYS;
- default:
- return RETENTION_FORMAT.HOURS;
+class ContactPickerWidget extends _mixins2__ .w9 {
+ constructor(...args) {
+ super(...args);
+ this.contactLinkListener = null;
+ this.domRef = react1___default().createRef();
+ this.state = {
+ searchValue: '',
+ selected: this.props.selected || [],
+ publicLink: M.account && M.account.contactLink || undefined
+ };
+ this.normalize = input => ChatSearch._normalize_str(String(input || '').toLowerCase());
+ this.onSearchChange = ev => {
+ this.setState({
+ searchValue: ev.target.value
+ });
+ };
+ this.renderParticipantsList = () => {
+ const {
+ contacts,
+ emailTooltips,
+ onSelected
+ } = this.props;
+ const {
+ selected
+ } = this.state;
+ const $$list = contacts.map(handle => {
+ const added = selected.includes(handle);
+ return JSX_(ContactCard, {
+ key: handle,
+ className: `
+ contacts-search short
+ ${added ? 'selected' : ''}
+ `,
+ contact: M.u[handle],
+ selectable: true,
+ emailTooltips,
+ noContextButton: true,
+ noContextMenu: true,
+ onClick: () => {
+ this.setState({
+ selected: added ? selected.filter(h => h !== handle) : [...selected, handle]
+ }, () => onSelected(this.state.selected));
+ }
+ });
+ });
+ return JSX_(_ui_perfectScrollbar_jsx4__ .O, {
+ className: "contacts-search-scroll",
+ selected,
+ contacts
+ }, JSX_("div", {
+ className: "contacts-search-subsection"
+ }, JSX_("div", {
+ className: "contacts-list-header"
+ }, megaChat.activeCall ? l.call_participants : l[16217]), JSX_("div", {
+ className: "contacts-search-list"
+ }, $$list)));
+ };
}
-};
-ChatRoom.prototype.getRetentionTimeFormatted = function (retentionTime) {
- retentionTime = retentionTime || this.retentionTime;
- switch (this.getRetentionFormat(retentionTime)) {
- case RETENTION_FORMAT.MONTHS:
- return Math.floor(secondsToDays(retentionTime) / 30);
- case RETENTION_FORMAT.WEEKS:
- return secondsToDays(retentionTime) / 7;
- case RETENTION_FORMAT.DAYS:
- return secondsToDays(retentionTime);
- case RETENTION_FORMAT.HOURS:
- return secondsToHours(retentionTime);
- case RETENTION_FORMAT.DISABLED:
- return 0;
+ renderInviteWarning() {
+ const {
+ chatRoom
+ } = this.props;
+ const {
+ activeCall
+ } = megaChat;
+ if (!activeCall || activeCall.chatRoom.chatId !== chatRoom.chatId || !activeCall.sfuClient.callLimits || !activeCall.sfuClient.callLimits.usr || chatRoom.getCallParticipants().length < activeCall.sfuClient.callLimits.usr) {
+ return null;
+ }
+ return JSX_("div", {
+ className: "picker-user-limit-banner"
+ }, activeCall.organiser === u_handle ? (0,_ui_utils_jsx3__ .lI)(l.invite_limit_banner_organiser, '[A]', _link_jsx8__ .A, {
+ onClick() {
+ window.open(`${getBaseUrl()}/pro`, '_blank', 'noopener,noreferrer');
+ eventlog(500263);
+ }
+ }) : l.invite_limit_banner_host);
}
-};
-ChatRoom.prototype.getRetentionLabel = function (retentionTime) {
- retentionTime = retentionTime || this.retentionTime;
- const days = secondsToDays(retentionTime);
- const months = Math.floor(days / 30);
- const hours = secondsToHours(retentionTime);
- switch (this.getRetentionFormat(retentionTime)) {
- case RETENTION_FORMAT.DISABLED:
- return l.disabled_chat_history_cleaning_status;
- case RETENTION_FORMAT.MONTHS:
- return mega.icu.format(l.months_chat_history_plural, months);
- case RETENTION_FORMAT.WEEKS:
- return mega.icu.format(l.weeks_chat_history_plural, days / 7);
- case RETENTION_FORMAT.DAYS:
- return mega.icu.format(l.days_chat_history_plural, days);
- case RETENTION_FORMAT.HOURS:
- return mega.icu.format(l.hours_chat_history_plural, hours);
+ componentDidMount() {
+ super.componentDidMount();
+ setContactLink(this.domRef && this.domRef.current);
+ this.contactLinkListener = mBroadcaster.addListener('contact:setContactLink', publicLink => this.state.publicLink ? null : this.setState({
+ publicLink
+ }));
}
-};
-ChatRoom.prototype.setRetention = function (time) {
- asyncApiReq({
- "a": "mcsr",
- "id": this.chatId,
- "d": time,
- "ds": 1
- });
-};
-ChatRoom.prototype.removeMessagesByRetentionTime = function () {
- const self = this;
- const {messages} = self.messagesBuff;
- if (messages.length === 0 || this.retentionTime === 0) {
- return;
+ componentDidUpdate() {
+ const self = this;
+ if (self.scrollToLastSelected && self.psSelected) {
+ self.scrollToLastSelected = false;
+ self.psSelected.scrollToPercentX(100, false);
+ }
+ if (self.searchContactsScroll) {
+ self.searchContactsScroll.reinitialise();
+ }
}
- const newest = messages.getItem(messages.length - 1);
- let lowestValue = newest.orderValue;
- let deleteFrom = null;
- let lastMessage = null;
- const deletePreviousTo = (new Date() - self.retentionTime * 1000) / 1000;
- const cp = self.megaChat.plugins.chatdIntegration.chatd.chatdPersist;
- let finished = false;
- if (typeof cp !== 'undefined') {
- const done = function (message) {
- if (message) {
- if (self.retentionTime > 0 && self.messagesBuff.messages.length > 0) {
- self.messagesBuff._removeMessagesBefore(message.messageId);
- }
- cp.removeMessagesBefore(self.chatId, message.orderValue);
- }
- };
- if (newest.delay < deletePreviousTo) {
- cp.clearChatHistoryForChat(self.chatId);
- return;
+ UNSAFE_componentWillMount() {
+ if (super.UNSAFE_componentWillMount) {
+ super.UNSAFE_componentWillMount();
}
- const removeMsgs = function () {
- cp._paginateMessages(lowestValue, Chatd.MESSAGE_HISTORY_LOAD_COUNT, self.chatId).then((messages) => {
- messages = messages[0];
- if (messages.length) {
- for (let i = 0; i < messages.length; i++) {
- const message = messages[i];
- if (message.msgObject.delay < deletePreviousTo) {
- deleteFrom = lastMessage || message;
- break;
+ const self = this;
+ if (self.props.multiple) {
+ $(document.body).rebind(`keypress.contactPicker${ self.getUniqueId()}`, (e) => {
+ const keyCode = e.which || e.keyCode;
+ if (keyCode === 13) {
+ if (self.state.selected) {
+ e.preventDefault();
+ e.stopPropagation();
+ closeDropdowns();
+ if (self.props.onSelectDone) {
+ self.props.onSelectDone(self.state.selected);
}
- lastMessage = message;
- lowestValue = message.orderValue;
}
- } else {
- finished = true;
- }
- if (!finished && !deleteFrom) {
- onIdle(removeMsgs);
- } else {
- done(deleteFrom);
}
});
- };
- removeMsgs();
+ }
}
- if (self.retentionTime > 0 && self.messagesBuff.messages.length > 0) {
- let message;
- while (message = self.messagesBuff.messages.getItem(0)) {
- if (message.delay < deletePreviousTo) {
- if (!self.messagesBuff.messages.removeByKey(message.messageId)) {
- break;
- }
- } else {
- break;
- }
+ componentWillUnmount() {
+ super.componentWillUnmount();
+ const self = this;
+ delete self._foundFrequents;
+ if (self.props.multiple) {
+ $(document.body).off(`keypress.contactPicker${ self.getUniqueId()}`);
+ }
+ if (this.contactLinkListener) {
+ mBroadcaster.removeListener(this.contactLinkListener);
}
}
-};
-ChatRoom.prototype.isOnline = function () {
- const shard = this.chatd.shards[this.chatShard];
- return shard ? shard.isOnline() : false;
-};
-ChatRoom.prototype.isOnlineForCalls = function () {
- const chatdChat = this.getChatIdMessages();
- if (!chatdChat) {
- return false;
- }
- return chatdChat.loginState() >= LoginState.HISTDONE;
-};
-ChatRoom.prototype.isArchived = function () {
- const self = this;
- return self.flags & ChatRoom.ARCHIVED;
-};
-ChatRoom.prototype.isAnonymous = function () {
- return is_chatlink && this.type === "public" && this.publicChatHandle && this.publicChatKey && this.publicChatHandle === megaChat.initialPubChatHandle;
-};
-ChatRoom.prototype.isDisplayable = function () {
- return !this.isArchived() || this.call;
-};
-ChatRoom.prototype.isMuted = function () {
- return pushNotificationSettings.getDnd(this.chatId) || pushNotificationSettings.getDnd(this.chatId) === 0;
-};
-ChatRoom.prototype.persistToFmdb = function () {
- const self = this;
- if (fmdb) {
- const users = [];
- if (self.members) {
- Object.keys(self.members).forEach((user_handle) => {
- users.push({
- u: user_handle,
- p: self.members[user_handle]
- });
- });
- }
- if (self.chatId && self.chatShard !== undefined) {
- const roomInfo = {
- 'id': self.chatId,
- 'cs': self.chatShard,
- 'g': self.type === "group" || self.type === "public" ? 1 : 0,
- 'u': users,
- 'ts': self.ctime,
- 'ct': self.ct,
- 'ck': self.ck ? self.ck : null,
- 'f': self.flags,
- 'm': self.type === "public" ? 1 : 0
- };
- fmdb.add('mcf', {
- id: roomInfo.id,
- d: roomInfo
- });
- }
- }
-};
-ChatRoom.prototype.updateFlags = function (f, updateUI) {
- const self = this;
- const flagChange = self.flags !== f;
- self.flags = f;
- if (self.isArchived()) {
- megaChat.archivedChatsCount++;
- } else {
- megaChat.archivedChatsCount--;
- }
- self.persistToFmdb();
- if (updateUI && flagChange) {
- if (megaChat.currentlyOpenedChat && megaChat.chats[megaChat.currentlyOpenedChat] && megaChat.chats[megaChat.currentlyOpenedChat].chatId === self.chatId) {
- loadSubPage('fm/chat/');
- } else {
- megaChat.refreshConversations();
+ _eventuallyAddContact(v, contacts, selectableContacts, forced) {
+ const self = this;
+ const withSelfNote = this.props.withSelfNote && v.u === u_handle;
+ if (v.u === u_handle && !this.props.step && !withSelfNote) {
+ return false;
}
- }
- this.trackDataChange();
-};
-ChatRoom.stateToText = function (state) {
- let txt = null;
- $.each(ChatRoom.STATE, (k, v) => {
- if (state === v) {
- txt = k;
+ if (!forced && v.c !== 1 && v.u !== u_handle) {
return false;
}
- });
- return txt;
-};
-ChatRoom.prototype.setState = function (newState, isRecover) {
- const self = this;
- assert(newState, 'Missing state');
- if (newState === self.state) {
- self.logger.debug("Ignoring .setState, newState === oldState, current state: ", self.getStateAsText());
- return;
- }
- if (self.state) {
- assert(newState === ChatRoom.STATE.JOINING && isRecover || newState === ChatRoom.STATE.INITIALIZED && isRecover || newState > self.state, `Invalid state change. Current:${ ChatRoom.stateToText(self.state) }to${ ChatRoom.stateToText(newState)}`);
- }
- const oldState = self.state;
- self.state = newState;
- self.trigger('onStateChange', [oldState, newState]);
-};
-ChatRoom.prototype.getStateAsText = function () {
- const self = this;
- return ChatRoom.stateToText(self.state);
-};
-ChatRoom.prototype.getParticipants = function () {
- const self = this;
- return Object.keys(self.members);
-};
-ChatRoom.prototype.getParticipantsExceptMe = function (userHandles) {
- const res = clone(userHandles || this.getParticipants());
- array.remove(res, u_handle, true);
- return res;
-};
-ChatRoom.prototype.getParticipantsTruncated = function (maxMembers = 5, maxLength = ChatRoom.TOPIC_MAX_LENGTH) {
- const truncatedParticipantNames = [];
- const members = Object.keys(this.members);
- for (let i = 0; i < members.length; i++) {
- const handle = members[i];
- const name = M.getNameByHandle(handle);
- if (!handle || !name || handle === u_handle) {
- continue;
+ if (self.props.exclude && self.props.exclude.indexOf(v.u) > -1) {
+ return false;
}
- if (i > maxMembers) {
- break;
+ let isDisabled = false;
+ if (!self.wasMissingKeysForContacts) {
+ self.wasMissingKeysForContacts = {};
}
- truncatedParticipantNames.push(name.length > maxLength ? `${name.substr(0, maxLength) }...` : name);
- }
- if (truncatedParticipantNames.length === maxMembers) {
- truncatedParticipantNames.push('...');
- }
- return truncatedParticipantNames.join(', ');
-};
-ChatRoom.prototype.getRoomTitle = function () {
- const formattedDate = l[19077].replace('%s1', new Date(this.ctime * 1000).toLocaleString());
- if (this.isNote) {
- return l.note_label;
- }
- if (this.type === 'private') {
- const participants = this.getParticipantsExceptMe();
- return participants && Array.isArray(participants) ? M.getNameByHandle(participants[0]) : formattedDate;
- }
- if (this.topic === '' || !this.topic) {
- return this.getParticipantsTruncated() || formattedDate;
- }
- const formattedTopic = this.getTruncatedRoomTopic();
- const isCanceled = this.scheduledMeeting && this.scheduledMeeting.isCanceled;
- return isCanceled ? `${formattedTopic} ${l.canceled_meeting}` : formattedTopic;
-};
-ChatRoom.prototype.getTruncatedRoomTopic = function (maxLength = ChatRoom.TOPIC_MAX_LENGTH) {
- return this.topic && this.topic.length > maxLength ? `${this.topic.substr(0, maxLength) }...` : this.topic;
-};
-ChatRoom.prototype.setRoomTopic = async function (newTopic) {
- if (newTopic && newTopic.trim().length && newTopic !== this.getRoomTitle()) {
- this.scrolledToBottom = true;
- const participants = this.protocolHandler.getTrackedParticipants();
- await ChatdIntegration._ensureKeysAreLoaded(undefined, participants);
- const topic = this.protocolHandler.embeddedEncryptTo(newTopic, strongvelope.MESSAGE_TYPES.TOPIC_CHANGE, participants, undefined, this.type === 'public');
- if (topic) {
- return api.req({
- a: 'mcst',
- id: this.chatId,
- ct: base64urlencode(topic),
- v: Chatd.VERSION
+ if (!self.wasMissingKeysForContacts[v.u] && (!pubCu25519[v.u] || !pubEd25519[v.u])) {
+ self.wasMissingKeysForContacts[v.u] = true;
+ ChatdIntegration._ensureKeysAreLoaded(undefined, [v.u]).always(() => {
+ if (self.isMounted()) {
+ self.safeForceUpdate();
+ }
});
+ isDisabled = true;
+ return true;
+ } else if (self.wasMissingKeysForContacts[v.u] && (!pubCu25519[v.u] || !pubEd25519[v.u])) {
+ return false;
}
- }
-};
-ChatRoom.prototype.leave = function (notify) {
- const valid = this.type === 'group' || this.type === 'public';
- console.assert(valid, `Can't leave room "${this.roomId}" of type "${this.type}"`);
- if (!valid) {
- return;
- }
- this._leaving = true;
- this.topic = '';
- if (notify) {
- this.trigger('onLeaveChatRequested');
- }
- if (this.state !== ChatRoom.STATE.LEFT) {
- this.setState(ChatRoom.STATE.LEAVING);
- this.setState(ChatRoom.STATE.LEFT);
- }
- if (this.activeCallIds.length) {
- for (const activeCallId of this.activeCallIds.keys()) {
- this.activeCallIds.remove(activeCallId);
- }
- megaChat.updateSectionUnreadCount();
- }
-};
-ChatRoom.prototype.archive = function () {
- const self = this;
- const mask = 0x01;
- const flags = ChatRoom.ARCHIVED;
- asyncApiReq({
- 'a': 'mcsf',
- 'id': self.chatId,
- 'm': 1,
- 'f': flags,
- 'v': Chatd.VERSION
- }).then(r => {
- if (r === 0) {
- self.updateFlags(flags, true);
+ if (self.state.searchValue && self.state.searchValue.length > 0) {
+ const searchValue = this.normalize(this.state.searchValue);
+ const {
+ name,
+ nickname,
+ fullname,
+ u,
+ m
+ } = {
+ ...v,
+ name: withSelfNote ? l.note_label : v.name
+ };
+ const matches = [name, nickname, fullname, M.getNameByHandle(u), !this.props.skipMailSearch && m].some(field => this.normalize(field).includes(searchValue));
+ if (!matches) {
+ return false;
+ }
}
- });
-};
-ChatRoom.prototype.unarchive = function () {
- const self = this;
- const mask = 0x01;
- const flags = 0x00;
- asyncApiReq({
- 'a': 'mcsf',
- 'id': self.chatId,
- 'm': 1,
- 'f': 0,
- 'v': Chatd.VERSION
- }).then(res => {
- if (res === 0) {
- self.updateFlags(0, true);
+ let selectedClass = "";
+ if (self.state.selected && self.state.selected.indexOf(v.u) !== -1) {
+ selectedClass = "selected";
}
- });
-};
-ChatRoom.prototype.destroy = function (notifyOtherDevices, noRedirect) {
- const self = this;
- self.megaChat.trigger('onRoomDestroy', [self]);
- const mc = self.megaChat;
- const roomJid = self.roomId;
- if (!self.stateIsLeftOrLeaving()) {
- self.leave(notifyOtherDevices);
- } else if (self.type === "public" && self.publicChatHandle) {
- if (typeof self.members[u_handle] === 'undefined') {
- self.megaChat.plugins.chatdIntegration.handleLeave(self);
- }
- }
- if (self.isCurrentlyActive) {
- self.isCurrentlyActive = false;
- }
- Soon(() => {
- mc.chats.remove(roomJid);
- if (!noRedirect && u_type === 3) {
- loadSubPage('fm/chat');
- }
- });
-};
-ChatRoom.prototype.updatePublicHandle = async function (remove, cim, force) {
- if (force) {
- this.publicLink = null;
- }
- if (!remove && this.publicLink) {
- return this.publicLink;
- }
- return asyncApiReq({
- a: 'mcph',
- id: this.chatId,
- v: Chatd.VERSION,
- cim: cim ? 1 : 0,
- d: remove ? 1 : undefined
- }).then(res => {
- assert(remove && res === 0 || Array.isArray(res) && res[1].length === 8);
- this.publicLink = remove ? null : `chat/${res[1]}#${this.protocolHandler.getUnifiedKey()}`;
- }).catch(ex => {
- this.logger.warn('updatePublicHandle', ex);
- this.publicLink = null;
- });
-};
-ChatRoom.prototype.iAmInRoom = function () {
- return !(!this.members.hasOwnProperty(u_handle) || this.members[u_handle] === -1);
-};
-ChatRoom.prototype.joinViaPublicHandle = function () {
- const self = this;
- if (!fminitialized && is_chatlink) {
- if (u_type) {
- return new Promise((res, rej) => {
- self.megaChat.plugins.chatdIntegration.joinChatViaPublicHandle(self).then(() => {
- self.megaChat.routing.reinitAndOpenExistingChat(self.chatId, self.publicChatHandle).then(res, rej);
- }, ex => {
- console.error("Failed joining a chat room (u_type)", ex);
- rej(ex);
- });
- });
- }
- return;
- }
- if (!self.iAmInRoom() && self.type === "public" && self.publicChatHandle) {
- return megaChat.plugins.chatdIntegration.joinChatViaPublicHandle(self);
- }
- return Promise.reject();
-};
-ChatRoom.prototype.switchOffPublicMode = ChatRoom._fnRequireParticipantKeys(function () {
- let {
- topic,
- protocolHandler,
- chatId
- } = this;
- if (topic) {
- topic = protocolHandler.embeddedEncryptTo(topic, strongvelope.MESSAGE_TYPES.TOPIC_CHANGE, protocolHandler.getTrackedParticipants(), true, false);
- topic = base64urlencode(topic);
- }
- return asyncApiReq({
- a: 'mcscm',
- id: chatId,
- ct: topic || undefined,
- v: Chatd.VERSION
- }).then(() => {
- protocolHandler.switchOffOpenMode();
- });
-});
-ChatRoom.prototype.show = function () {
- if (this.isCurrentlyActive) {
- return false;
- }
- this.megaChat.hideAllChats();
- if (d) {
- this.logger.debug(' ---- show');
- }
- $.tresizer();
- onIdle(() => {
- this.scrollToChat();
- this.trackDataChange();
- });
- this.isCurrentlyActive = true;
- this.lastShownInUI = Date.now();
- this.megaChat.setAttachments(this.roomId);
- this.megaChat.lastOpenedChat = this.roomId;
- this.megaChat.currentlyOpenedChat = this.roomId;
- this.trigger('activity');
- this.trigger('onChatShown');
- let tmp = this.megaChat.rootDOMNode;
- if (tmp = tmp.querySelector('.conversation-panels')) {
- tmp.classList.remove('hidden');
- if (tmp = tmp.querySelector(`.conversation-panel[data-room-id="${this.chatId}"]`)) {
- tmp.classList.remove('hidden');
- }
- }
- if (tmp = document.getElementById(`conversation_${this.roomId}`)) {
- tmp.classList.add('active');
- }
- if (mega.ui.mInfoPanel) {
- mega.ui.mInfoPanel.hide();
- }
-};
-ChatRoom.prototype.scrollToChat = function () {
- this._scrollToOnUpdate = true;
- const {
- $chatTreePanePs
- } = megaChat;
- if ($chatTreePanePs && $chatTreePanePs.length) {
- const li = document.querySelector(`ul.conversations-pane li#conversation_${this.roomId}`);
- if (li && !verge.inViewport(li, -72)) {
- Object.values($chatTreePanePs).forEach(({
- ref
- }) => {
- if (ref.domNode) {
- const wrapOuterHeight = $(ref.domNode).outerHeight();
- const itemOuterHeight = $('li:first', ref.domNode).outerHeight();
- const pos = li.offsetTop;
- if (ref.domNode.contains(li)) {
- ref.doProgramaticScroll == null || ref.doProgramaticScroll(Math.max(0, pos - wrapOuterHeight / 2 + itemOuterHeight), true);
- }
- }
- });
- this._scrollToOnUpdate = false;
- }
- }
-};
-ChatRoom.prototype.isActive = function () {
- return document.hasFocus() && this.isCurrentlyActive;
-};
-ChatRoom.prototype.setActive = function () {
- loadSubPage(this.getRoomUrl());
-};
-ChatRoom.prototype.isLoading = function () {
- const mb = this.messagesBuff;
- return mb.messagesHistoryIsLoading() || mb.isDecrypting;
-};
-ChatRoom.prototype.getRoomUrl = function (getRawLink) {
- const self = this;
- if (self.type === "private") {
- const participants = self.getParticipantsExceptMe();
- const contact = M.u[participants[0] || u_handle];
- if (contact) {
- return `fm/chat/p/${ contact.u}`;
- }
- } else if (!getRawLink && is_chatlink && self.type === "public" && self.publicChatHandle && self.publicChatKey) {
- return `chat/${ self.publicChatHandle }#${ self.publicChatKey}`;
- } else if (self.type === "public") {
- return `fm/chat/c/${ self.roomId}`;
- } else if (self.type === "group" || self.type === "public") {
- return `fm/chat/g/${ self.roomId}`;
- } else {
- throw new Error("Can't get room url for unknown room type.");
- }
-};
-ChatRoom.prototype.activateWindow = function () {
- const self = this;
- loadSubPage(self.getRoomUrl());
-};
-ChatRoom.prototype.hide = function () {
- let _tmp;
- if (d) {
- this.logger.debug(' ---- hide', this.isCurrentlyActive);
- }
- this.isCurrentlyActive = false;
- this.lastShownInUI = Date.now();
- if (this.megaChat.currentlyOpenedChat === this.roomId) {
- this.megaChat.currentlyOpenedChat = null;
- }
- let tmp = this.megaChat.rootDOMNode.querySelector(`.conversation-panel[data-room-id="${this.chatId}"]`);
- (_tmp = tmp) == null || _tmp.classList.add('hidden');
- if (tmp = document.getElementById(`conversation_${this.roomId}`)) {
- tmp.classList.remove('active');
- }
- this.trigger('onChatHidden', this.isCurrentlyActive);
-};
-ChatRoom.prototype.appendMessage = function (message) {
- const self = this;
- if (message.deleted) {
- return false;
- }
- if (self.shownMessages[message.messageId]) {
- return false;
- }
- if (!message.orderValue) {
- const mb = self.messagesBuff;
- if (mb.messages.length > 0) {
- const prevMsg = mb.messages.getItem(mb.messages.length - 1);
- if (!prevMsg) {
- self.logger.error("self.messages got out of sync...maybe there are some previous JS exceptions that caused that? note that messages may be displayed OUT OF ORDER in the UI.");
- } else {
- let nextVal = prevMsg.orderValue + 0.1;
- if (!prevMsg.sent) {
- const cid = megaChat.plugins.chatdIntegration.chatd.chatIdMessages[self.chatIdBin];
- if (cid && cid.highnum) {
- nextVal = ++cid.highnum;
- }
- }
- message.orderValue = nextVal;
- }
- }
- }
- message.source = Message.SOURCE.SENT;
- self.trigger('onMessageAppended', message);
- self.messagesBuff.messages.push(message);
- self.shownMessages[message.messageId] = true;
-};
-ChatRoom.prototype.getNavElement = function () {
- const self = this;
- return $(`.nw-conversations-item[data-room-id="${ self.chatId }"]`);
-};
-ChatRoom.prototype.sendMessage = function (message) {
- const self = this;
- const {megaChat} = this;
- const messageId = megaChat.generateTempMessageId(self.roomId, message);
- const msgObject = new Message(self, self.messagesBuff, {
- messageId,
- 'userId': u_handle,
- message,
- 'textContents': message,
- 'delay': unixtime(),
- 'sent': Message.STATE.NOT_SENT
- });
- self.trigger('onSendMessage');
- self.appendMessage(msgObject);
- return self._sendMessageToTransport(msgObject).then(internalId => {
- if (!internalId) {
- this.logger.warn(`Got unexpected(?) 'sendingnum'...`, internalId);
- }
- msgObject.internalId = internalId;
- msgObject.orderValue = internalId;
- return internalId || -0xBADF;
- }).catch(ex => {
- this.logger.error(`sendMessage failed..`, msgObject, ex);
- });
-};
-ChatRoom.prototype._sendMessageToTransport = function (messageObject) {
- const self = this;
- const {megaChat} = this;
- megaChat.trigger('onPreBeforeSendMessage', messageObject);
- megaChat.trigger('onBeforeSendMessage', messageObject);
- megaChat.trigger('onPostBeforeSendMessage', messageObject);
- return megaChat.plugins.chatdIntegration.sendMessage(self, messageObject);
-};
-ChatRoom.prototype._sendNodes = async function (nodeids, users) {
- const u = this.type === 'public' ? [strongvelope.COMMANDER] : users;
- const promises = nodeids.map(nodeId => asyncApiReq({
- a: 'mcga',
- n: [nodeId],
- u,
- id: this.chatId,
- v: Chatd.VERSION
- }));
- const res = await Promise.allSettled(promises);
- const sent = [];
- for (let i = res.length; i--;) {
- if (res[i].status === 'fulfilled') {
- sent.push(nodeids[i]);
- }
- }
- if (!sent.length) {
- throw ENOENT;
- }
- return sent;
-};
-ChatRoom.prototype.attachNodes = async function (nodes, names) {
- if (!Array.isArray(nodes)) {
- nodes = [nodes];
- }
- const handles = new Set();
- for (let i = nodes.length; i--;) {
- const n = nodes[i];
- const h = String(crypto_keyok(n) && n.h || n);
- if (!M.getNodeByHandle(h)) {
- handles.add(h);
- }
- }
- if (handles.size) {
- await dbfetch.acquire([...handles]);
- }
- return this._attachNodes(nodes, names);
-};
-ChatRoom.prototype._attachNodes = mutex('chatroom-attach-nodes', function _(resolve, reject, nodes, names) {
- let i;
- let step = 0;
- const users = [];
- const self = this;
- let result = null;
- let copy = Object.create(null);
- let send = Object.create(null);
- let link = Object.create(null);
- let nmap = Object.create(null);
- const members = self.getParticipantsExceptMe();
- const sendMessage = nodes => {
- return new Promise(resolve => {
- for (let i = nodes.length; i--;) {
- const n = nmap[nodes[i]] || M.getNodeByHandle(nodes[i]);
- console.assert(n.h, `Node not found... ${nodes[i]}`);
- if (n.h) {
- const name = names && (names[n.hash] || names[n.h]) || n.name;
- this.sendMessage(Message.MANAGEMENT_MESSAGE_TYPES.MANAGEMENT + Message.MANAGEMENT_MESSAGE_TYPES.ATTACHMENT + JSON.stringify([{
- h: n.h,
- k: n.k,
- t: n.t,
- s: n.s,
- fa: n.fa,
- ts: n.ts,
- hash: n.hash,
- name,
- des: n.des
- }]));
- }
- }
- resolve();
- });
- };
- const attach = nodes => {
- console.assert(this.type === 'public' || users.length || this.isNote, 'No users to send to?!');
- return this.isNote ? sendMessage(nodes) : this._sendNodes(nodes, users).then(res => sendMessage(res));
- };
- const done = function () {
- if (--step < 1) {
- nmap = null;
- resolve(result);
- }
- };
- const fail = function (ex) {
- if (ex === EBLOCKED) {
- result = ex;
- } else if (ex === ENOENT) {
- result = result || ex;
- } else if (d) {
- _.logger.error(ex);
- }
- done();
- };
- if (d && !_.logger) {
- _.logger = new MegaLogger('attachNodes', {}, self.logger);
- }
- for (i = members.length; i--;) {
- const usr = M.getUserByHandle(members[i]);
- if (usr.u) {
- users.push(usr.u);
- }
- }
- for (i = nodes.length; i--;) {
- const h = nodes[i];
- const n = crypto_keyok(h) ? h : M.getNodeByHandle(h);
- if (n.t) {
- link[n.h] = 1;
- continue;
- }
- if (n.hash) {
- nmap[n.hash] = n;
- if (names && names[n.h]) {
- names[n.hash] = names[n.h];
- }
- }
- let op = send;
- if (n.u !== u_handle || M.getNodeRoot(n.h) === 'shares') {
- op = copy;
- }
- op[n.h] = 1;
- nmap[n.h] = n;
- }
- copy = Object.keys(copy);
- send = Object.keys(send);
- link = Object.keys(link);
- if (d) {
- _.logger.debug('copy:%d, send:%d, link:%d', copy.length, send.length, link.length, copy, send, link);
- }
- if (link.length) {
- ++step;
- Promise.resolve(mega.fileRequestCommon.storage.isDropExist(link)).then(res => {
- if (res.length) {
- return mega.fileRequest.showRemoveWarning(res);
- }
- }).then(() => {
- const createLink = h => M.createPublicLink(h).then(({
- link
- }) => this.sendMessage(link));
- return Promise.all(link.map(createLink));
- }).then(done).catch(fail);
- }
- if (send.length) {
- step++;
- attach(send).then(done).catch(fail);
- }
- if (copy.length) {
- step++;
- this._copyNodesToAttach(copy, nmap).then(res => attach(res)).then(done).catch(fail);
- }
- if (!step) {
- if (d) {
- _.logger.warn('Nothing to do here...');
- }
- queueMicrotask(done);
- }
-});
-ChatRoom.prototype._copyNodesToAttach = async function (copy, nmap) {
- const {
- h: target
- } = await M.myChatFilesFolder.get(true);
- if (!M.c[target]) {
- await dbfetch.get(target);
- }
- const dir = Object.keys(M.c[target] || {});
- const rem = [];
- for (let i = copy.length; i--;) {
- const n = nmap[copy[i]] || M.getNodeByHandle(copy[i]);
- console.assert(n.h, `Node not found.. ${copy[i]}`);
- for (let y = dir.length; y--;) {
- const b = M.getNodeByHandle(dir[y]);
- if (n.h === b.h || b.hash === n.hash) {
- if (d) {
- this.logger.info('deduplication %s:%s', n.h, b.h, [n], [b]);
- }
- rem.push(n.h);
- copy.splice(i, 1);
- break;
- }
- }
- }
- let res = [];
- if (copy.length) {
- res = await M.copyNodes(copy, target, false, false, {
- targetChatId: this.chatId
- });
- } else if (d) {
- this.logger.info('No new nodes to copy.', rem);
- }
- assert(Array.isArray(res), `Unexpected response, ${res && res.message || res}`, res);
- const [h] = res;
- res = [...rem, ...res];
- assert(res.length, 'Unexpected condition... nothing to attach ?!');
- for (let i = res.length; i--;) {
- const n = nmap[res[i]] || M.getNodeByHandle(res[i]);
- if (n.fv) {
- if (d) {
- this.logger.info('Skipping file-version %s', n.h, n);
- }
- res.splice(i, 1);
- }
- }
- if (h && !res.length) {
- if (d) {
- this.logger.info('Adding nothing but a file-version?..', h);
- }
- res = [h];
- }
- return res;
-};
-ChatRoom.prototype.onUploadStart = function (data) {
- const self = this;
- if (d) {
- self.logger.debug('onUploadStart', data);
- }
-};
-ChatRoom.prototype.uploadFromComputer = function () {
- this.scrolledToBottom = true;
- $('#fileselect1').trigger('click');
-};
-ChatRoom.prototype.attachContacts = function (ids) {
- for (let i = 0; i < ids.length; i++) {
- const nodeId = ids[i];
- const node = M.u[nodeId];
- this.sendMessage(Message.MANAGEMENT_MESSAGE_TYPES.MANAGEMENT + Message.MANAGEMENT_MESSAGE_TYPES.CONTACT + JSON.stringify([{
- u: node.u,
- email: node.m,
- name: node.name || node.m
- }]));
- }
-};
-ChatRoom.prototype.getMessageById = function (messageId) {
- const self = this;
- const msgs = self.messagesBuff.messages;
- const msgKeys = msgs.keys();
- for (let i = 0; i < msgKeys.length; i++) {
- const k = msgKeys[i];
- const v = msgs[k];
- if (v && v.messageId === messageId) {
- return v;
- }
- }
- return false;
-};
-ChatRoom.prototype.hasMessages = function (userMessagesOnly = false) {
- return this.messagesBuff.messages.some(m => !userMessagesOnly || m.messageHtml);
-};
-ChatRoom.prototype.renderContactTree = function () {
- const self = this;
- const $navElement = self.getNavElement();
- const $count = $('.nw-conversations-unread', $navElement);
- const count = self.messagesBuff.getUnreadCount();
- if (count > 0) {
- $count.text(count > 9 ? "9+" : count);
- $navElement.addClass("unread");
- } else if (count === 0) {
- $count.text("");
- $navElement.removeClass("unread");
- }
- $navElement.data('chatroom', self);
-};
-ChatRoom.prototype.getUnreadCount = function () {
- const self = this;
- return self.messagesBuff.getUnreadCount();
-};
-ChatRoom.prototype.recover = function () {
- const self = this;
- self.callRequest = null;
- if (self.state !== ChatRoom.STATE.LEFT) {
- self.membersLoaded = false;
- self.setState(ChatRoom.STATE.JOINING, true);
- self.megaChat.trigger("onRoomCreated", [self]);
- return MegaPromise.resolve();
- } else {
- return MegaPromise.reject();
- }
-};
-ChatRoom.prototype.showMissingUnifiedKeyDialog = function () {
- return msgDialog(`warningb:!^${l.msg_dlg_cancel}!${l[23433]}`, null, l[200], l.chat_key_failed_dlg_text, reload => reload ? M.reload() : null, 1);
-};
-ChatRoom.prototype.hasInvalidKeys = function () {
- if (!is_chatlink && this.type === 'public') {
- const {
- unifiedKey
- } = this.protocolHandler || {};
- if (!unifiedKey || unifiedKey && unifiedKey.length !== 16 || !this.ck || this.ck && this.ck.length !== 32) {
- console.error('Error instantiating room/call -- missing `unifiedKey`/malformed `ck` for public chat.');
- const {
- owner,
- actors
- } = mBroadcaster.crossTab;
- eventlog(99751, JSON.stringify([1, buildVersion.website || 'dev', String(this.chatId).length | 0, this.type | 0, this.isMeeting | 0, typeof unifiedKey, String(unifiedKey || '').length | 0, typeof this.ck, String(this.ck).length | 0, !!owner | 0, Object(actors).length | 0]));
- return true;
- }
- }
- return false;
-};
-ChatRoom.prototype.joinCall = ChatRoom._fnRequireParticipantKeys(function (audio, video, callId) {
- if (!megaChat.hasSupportForCalls || this.activeCallIds.length === 0 || this.meetingsLoading) {
- return;
- }
- if (this.hasInvalidKeys()) {
- return this.showMissingUnifiedKeyDialog();
- }
- this.meetingsLoading = {
- title: l.joining,
- audio,
- video
- };
- callId = callId || this.activeCallIds.keys()[0];
- return asyncApiReq({
- 'a': 'mcmj',
- 'cid': this.chatId,
- "mid": callId
- }).then(r => {
- this.startOrJoinCall(callId, r.url, audio, video, r.organiser);
- });
-});
-ChatRoom.prototype.startOrJoinCall = function (callId, url, audio, video, organiser) {
- tryCatch(() => {
- const call = this.call = megaChat.activeCall = megaChat.plugins.callManager2.createCall(this, callId, this.protocolHandler.chatMode === strongvelope.CHAT_MODE.PUBLIC && str_to_ab(this.protocolHandler.unifiedKey));
- call.setOrganiser(organiser);
- return call.connect(url, audio, video);
- }, ex => {
- let _this$call;
- (_this$call = this.call) == null || _this$call.destroy();
- this.call = megaChat.activeCall = null;
- this.meetingsLoading = false;
- console.error('Failed to start/join call:', ex);
- })();
-};
-ChatRoom.prototype.rejectCall = function (callId) {
- if (this.activeCallIds.length === 0) {
- return;
- }
- callId = callId || this.activeCallIds.keys()[0];
- if (this.type === "private") {
- return asyncApiReq({
- 'a': 'mcme',
- 'cid': this.chatId,
- 'mid': callId
- });
- }
- const shard = this.chatd.shards[this.chatShard];
- if (shard) {
- shard.sendCallReject(base64urldecode(this.chatId), base64urldecode(callId));
- }
- return Promise.resolve();
-};
-ChatRoom.prototype.ringUser = function (userId, callId, callstate) {
- assert(userId, 'Missing user handle.');
- assert(callId, 'Missing chat handle.');
- assert(this.type !== 'private', 'Unexpected chat type.');
- const shard = this.chatd.shards[this.chatShard];
- if (shard) {
- api.req({
- a: 'mcru',
- u: userId,
- cid: this.chatId
- }).then(() => shard.ringUser(this.chatIdBin, base64urldecode(userId), base64urldecode(callId), callstate)).catch(dump);
- }
-};
-ChatRoom.prototype.endCallForAll = function (callId) {
- if (this.activeCallIds.length && this.type !== 'private') {
- callId = callId || this.activeCallIds.keys()[0];
- asyncApiReq({
- 'a': 'mcme',
- 'cid': this.chatId,
- 'mid': callId
- });
- eventlog(99761, JSON.stringify([this.chatId, callId, this.isMeeting | 0]));
- }
-};
-ChatRoom.prototype.startAudioCall = function (scheduled) {
- return this.startCall(true, false, scheduled);
-};
-ChatRoom.prototype.startVideoCall = function (scheduled) {
- return this.startCall(true, true, scheduled);
-};
-ChatRoom.prototype.startCall = ChatRoom._fnRequireParticipantKeys(function (audio, video, scheduled) {
- if (!megaChat.hasSupportForCalls || this.meetingsLoading) {
- return;
- }
- if (this.activeCallIds.length > 0) {
- this.joinCall(this.activeCallIds.keys()[0]);
- return;
- }
- if (this.hasInvalidKeys()) {
- return this.showMissingUnifiedKeyDialog();
- }
- this.meetingsLoading = {
- title: l.starting,
- audio,
- video
- };
- const opts = {
- a: 'mcms',
- cid: this.chatId,
- sm: scheduled && this.scheduledMeeting && this.scheduledMeeting.id
- };
- if (localStorage.sfuId) {
- opts.sfu = parseInt(localStorage.sfuId, 10);
- }
- return asyncApiReq(opts).then(r => {
- this.startOrJoinCall(r.callId, r.sfu, audio, video, r.organiser);
- }).catch(ex => {
- this.meetingsLoading = false;
- this.logger.error(`Failed to start call: ${ex}`);
- });
-});
-ChatRoom.prototype.subscribeForCallEvents = function () {
- const callMgr = megaChat.plugins.callManager2;
- this.rebind("onChatdPeerJoinedCall.callManager", (e, data) => {
- if (!this.activeCallIds.exists(data.callId)) {
- this.activeCallIds.set(data.callId, []);
- }
- this.activeCallIds.set(data.callId, [...this.activeCallIds[data.callId], ...data.participants]);
- const parts = data.participants;
- for (let i = 0; i < parts.length; i++) {
- if (this.type === "private" || parts[i] === u_handle && this.ringingCalls.exists(data.callId)) {
- this.ringingCalls.remove(data.callId);
- callMgr.trigger("onRingingStopped", {
- callId: data.callId,
- chatRoom: this
- });
- }
- }
- megaChat.updateSectionUnreadCount();
- this.callParticipantsUpdated();
- });
- this.rebind("onChatdPeerLeftCall.callManager", (e, data) => {
- if (!this.activeCallIds[data.callId]) {
- return;
- }
- const parts = data.participants;
- for (let i = 0; i < parts.length; i++) {
- array.remove(this.activeCallIds[data.callId], parts[i], true);
- if (parts[i] === u_handle && this.ringingCalls.exists(data.callId)) {
- this.ringingCalls.remove(data.callId);
- callMgr.trigger("onRingingStopped", {
- callId: data.callId,
- chatRoom: this
- });
- }
- }
- this.callParticipantsUpdated();
- });
- this.rebind("onCallLeft.callManager", (e, data) => {
- console.warn("onCallLeft:", JSON.stringify(data));
- const {
- call
- } = this;
- if (!call || call.callId !== data.callId) {
- if (d) {
- console.warn("... no active call or event not for it");
- }
- return;
- }
- this.meetingsLoading = false;
- call.hangUp(data.reason);
- megaChat.activeCall = this.call = null;
- });
- this.rebind("onChatdCallEnd.callManager", (e, data) => {
- if (d) {
- console.warn("onChatdCallEnd:", JSON.stringify(data));
- }
- this.meetingsLoading = false;
- this.activeCallIds.remove(data.callId);
- if (this.callUserLimited) {
- this.callUserLimited.abort();
- }
- this.callUserLimited = false;
- this.stopRinging(data.callId);
- this.callParticipantsUpdated();
- megaChat.updateSectionUnreadCount();
- });
- this.rebind('onCallState.callManager', function (e, data) {
- const ac = this.activeCallIds[data.callId];
- console.assert(ac, `unknown call: ${data.callId}`);
- if (ac) {
- callMgr.onCallState(data, this);
- this.callParticipantsUpdated();
- }
- });
- this.rebind('onRoomDisconnected.callManager', function () {
- this.activeCallIds.clear();
- megaChat.updateSectionUnreadCount();
- if (navigator.onLine) {
- return;
- }
- if (this.call) {
- this.trigger('ChatDisconnected', this);
- }
- this.callParticipantsUpdated();
- });
- this.rebind('onStateChange.callManager', function (e, oldState, newState) {
- if (newState === ChatRoom.STATE.LEFT && this.call) {
- this.call.hangUp(SfuClient.TermCode.kLeavingRoom);
- }
- });
- this.rebind('onCallPeerLeft.callManager', (e, data) => {
- const {
- call
- } = this;
- if (!call || call.isDestroyed || call.hasOtherParticipant() || SfuClient.isTermCodeRetriable(data.reason)) {
- return;
- }
- if (this.type === 'private') {
- return this.trigger('onCallLeft', {
- callId: call.callId
- });
- }
- setTimeout(() => {
- if (this.call === call) {
- this.call.initCallTimeout();
- }
- }, 3000);
- });
- this.rebind('onMeAdded', (e, addedBy) => {
- if (this.activeCallIds.length > 0) {
- const callId = this.activeCallIds.keys()[0];
- if (this.ringingCalls.exists(callId)) {
- return;
- }
- this.ringingCalls.set(callId, addedBy);
- this.megaChat.trigger('onIncomingCall', [this, callId, addedBy, callMgr]);
- this.fakedLocalRing = true;
- setTimeout(() => {
- delete this.fakedLocalRing;
- if (this.ringingCalls.exists(callId)) {
- callMgr.trigger("onRingingStopped", {
- callId,
- chatRoom: this
- });
- }
- }, 30e3);
- }
- });
-};
-ChatRoom.prototype.stateIsLeftOrLeaving = function () {
- return this.state == ChatRoom.STATE.LEFT || this.state == ChatRoom.STATE.LEAVING || (!is_chatlink && this.state === ChatRoom.STATE.READY && this.membersSetFromApi && !this.membersSetFromApi.members.hasOwnProperty(u_handle) || is_chatlink && !this.members.hasOwnProperty(u_handle));
-};
-ChatRoom.prototype._clearChatMessagesFromChatd = function () {
- this.chatd.shards[this.chatShard].retention(base64urldecode(this.chatId), 1);
-};
-ChatRoom.prototype.isReadOnly = function () {
- if (this.type === "private") {
- const members = this.getParticipantsExceptMe();
- if (members[0] && !Object(M.u[members[0]]).c) {
- return true;
- }
- }
- return this.members && this.members[u_handle] <= 0 || !this.members.hasOwnProperty(u_handle) || this.privateReadOnlyChat || this.state === ChatRoom.STATE.LEAVING || this.state === ChatRoom.STATE.LEFT;
-};
-ChatRoom.prototype.iAmOperator = function () {
- return this.type === 'private' || this.members && this.members[u_handle] === ChatRoom.MembersSet.PRIVILEGE_STATE.OPERATOR;
-};
-ChatRoom.prototype.iAmReadOnly = function () {
- return this.type !== 'private' && this.members && this.members[u_handle] === ChatRoom.MembersSet.PRIVILEGE_STATE.READONLY;
-};
-ChatRoom.prototype.iAmWaitingRoomPeer = function () {
- return this.options.w && !this.iAmOperator();
-};
-ChatRoom.prototype.didInteraction = function (user_handle, ts) {
- const self = this;
- const newTs = ts || unixtime();
- if (user_handle === u_handle) {
- Object.keys(self.members).forEach((user_handle) => {
- const contact = M.u[user_handle];
- if (contact && user_handle !== u_handle && contact.c === 1) {
- setLastInteractionWith(contact.u, `1:${ newTs}`);
- }
- });
- } else {
- const contact = M.u[user_handle];
- if (contact && user_handle !== u_handle && contact.c === 1) {
- setLastInteractionWith(contact.u, `1:${ newTs}`);
- }
- }
-};
-ChatRoom.prototype.retrieveAllHistory = function () {
- const self = this;
- self.messagesBuff.retrieveChatHistory().done(() => {
- if (self.messagesBuff.haveMoreHistory()) {
- self.retrieveAllHistory();
- }
- });
-};
-ChatRoom.prototype.seedRoomKeys = async function (keys) {
- assert(Array.isArray(keys) && keys.length, `Invalid keys parameter for seedRoomKeys.`, keys);
- if (d > 2) {
- this.logger.warn('Seeding room keys...', keys);
- }
- const promises = [ChatdIntegration._ensureKeysAreLoaded(keys, undefined, this.publicChatHandle)];
- if (!this.protocolHandler) {
- promises.push(ChatdIntegration._waitForProtocolHandler(this));
- }
- if (!this.notDecryptedKeys) {
- this.notDecryptedKeys = Object.create(null);
- }
- for (let i = keys.length; i--;) {
- const {
- key,
- keyid,
- keylen,
- userId
- } = keys[i];
- this.notDecryptedKeys[`${userId}-${keyid}`] = {
- userId,
- keyid,
- keylen,
- key
- };
- }
- const promise = this._keysAreSeeding = Promise.all(promises).then(() => {
- const res = this.protocolHandler.seedKeys(keys);
- for (let i = res.length; i--;) {
- delete this.notDecryptedKeys[res[i]];
- }
- return res;
- }).catch(ex => {
- this.logger.error('Failed to seed room keys!', ex, keys);
- throw ex;
- }).finally(() => {
- if (promise === this._keysAreSeeding) {
- delete this._keysAreSeeding;
- }
- });
- return promise;
-};
-ChatRoom.prototype.truncate = function () {
- const self = this;
- const chatMessages = self.messagesBuff.messages;
- if (chatMessages.length > 0) {
- let lastChatMessageId = null;
- let i = chatMessages.length - 1;
- while (lastChatMessageId == null && i >= 0) {
- const message = chatMessages.getItem(i);
- if (message instanceof Message && message.dialogType !== "truncated") {
- lastChatMessageId = message.messageId;
- }
- i--;
- }
- if (lastChatMessageId) {
- asyncApiReq({
- a: 'mct',
- id: self.chatId,
- m: lastChatMessageId,
- v: Chatd.VERSION
- }).catch(ex => {
- if (ex === -2) {
- msgDialog('warninga', l[135], l[8880]);
- }
- });
- }
- }
-};
-ChatRoom.prototype.getActiveCalls = function () {
- return this.activeCallIds.map((parts, id) => {
- return parts.indexOf(u_handle) > -1 ? id : undefined;
- });
-};
-ChatRoom.prototype.haveActiveCall = function () {
- return this.getActiveCalls().length > 0;
-};
-ChatRoom.prototype.haveActiveOnHoldCall = function () {
- const activeCallIds = this.getActiveCalls();
- for (let i = 0; i < activeCallIds.length; i++) {
- const call = megaChat.plugins.callManager2.calls[`${this.chatId }_${ activeCallIds[i]}`];
- if (call && call.av & SfuClient.Av.onHold) {
- return true;
- }
- }
- return false;
-};
-ChatRoom.prototype.havePendingGroupCall = function () {
- if (this.type !== "group" && this.type !== "public") {
- return false;
- }
- return this.activeCallIds.length > 0;
-};
-ChatRoom.prototype.havePendingCall = function () {
- return this.activeCallIds.length > 0;
-};
-ChatRoom.prototype.getActiveCallMessageId = function (ignoreActive) {
- const self = this;
- if (!ignoreActive && !self.havePendingCall() && !self.haveActiveCall()) {
- return false;
- }
- const msgs = self.messagesBuff.messages;
- for (let i = msgs.length - 1; i >= 0; i--) {
- const msg = msgs.getItem(i);
- if (msg.dialogType === "remoteCallEnded") {
- return false;
- }
- if (msg.dialogType === "remoteCallStarted") {
- return msg.messageId;
- }
- }
-};
-ChatRoom.prototype.stopRinging = function (callId) {
- if (this.ringingCalls.exists(callId)) {
- this.ringingCalls.remove(callId);
- }
- megaChat.plugins.callManager2.trigger("onRingingStopped", {
- callId,
- chatRoom: this
- });
-};
-ChatRoom.prototype.callParticipantsUpdated = function () {
- const self = this;
- let msgId = self.getActiveCallMessageId();
- if (!msgId) {
- msgId = self.getActiveCallMessageId(true);
- }
- const callParts = self.getCallParticipants() || [];
- self.uniqueCallParts = {};
- for (let i = 0; i < callParts.length; i++) {
- self.uniqueCallParts[callParts[i]] = true;
- }
- if (this.callUserLimited && this.canJoinLimitedCall()) {
- this.callUserLimited.abort();
- this.callUserLimited = false;
- }
- const msg = self.messagesBuff.getMessageById(msgId);
- msg && msg.wrappedChatDialogMessage && msg.wrappedChatDialogMessage.trackDataChange();
- self.trackDataChange();
-};
-ChatRoom.prototype.onPublicChatRoomInitialized = function () {
- const self = this;
- if (self.type !== "public" || !localStorage.autoJoinOnLoginChat) {
- return;
- }
- const autoLoginChatInfo = tryCatch(JSON.parse.bind(JSON))(localStorage.autoJoinOnLoginChat) || false;
- if (autoLoginChatInfo[0] === self.publicChatHandle) {
- localStorage.removeItem("autoJoinOnLoginChat");
- if (unixtime() - 7200 < autoLoginChatInfo[1]) {
- const doJoinEventually = function (state) {
- if (state === ChatRoom.STATE.READY) {
- self.joinViaPublicHandle();
- self.unbind(`onStateChange.${ self.publicChatHandle}`);
- }
- };
- self.rebind(`onStateChange.${ self.publicChatHandle}`, (e, oldState, newState) => {
- doJoinEventually(newState);
- });
- doJoinEventually(self.state);
- }
- }
-};
-ChatRoom.prototype.isUIMounted = function () {
- return this._uiIsMounted;
-};
-ChatRoom.prototype.attachSearch = function () {
- this.activeSearches++;
-};
-ChatRoom.prototype.detachSearch = function () {
- if (--this.activeSearches === 0) {
- this.messagesBuff.detachMessages();
- }
- this.activeSearches = Math.max(this.activeSearches, 0);
- this.trackDataChange();
-};
-ChatRoom.prototype.scrollToMessageId = function (msgId, index, retryActive) {
- const self = this;
- if (!self.isCurrentlyActive && !retryActive) {
- tSleep(1.5).then(() => {
- self.scrollToMessageId(msgId, index, true);
- });
- return;
- }
- assert(self.isCurrentlyActive, 'chatRoom is not visible');
- self.isScrollingToMessageId = true;
- if (!self.$rConversationPanel) {
- self.one(`onHistoryPanelComponentDidMount.scrollToMsgId${ msgId}`, () => {
- self.scrollToMessageId(msgId, index);
- });
- return;
- }
- const ps = self.$rConversationPanel.messagesListScrollable;
- assert(ps);
- const msgObj = self.messagesBuff.getMessageById(msgId);
- if (msgObj) {
- const elem = $(`.${ msgId }.message.body`)[0];
- self.scrolledToBottom = false;
- ps.scrollToElement(elem, true);
- self.$rConversationPanel.lastScrollPosition = undefined;
- self.isScrollingToMessageId = false;
- } else if (self.messagesBuff.isRetrievingHistory) {
- self.one(`onHistoryDecrypted.scrollToMsgId${ msgId}`, () => {
- self.one(`onComponentDidUpdate.scrollToMsgId${ msgId}`, () => {
- self.scrollToMessageId(msgId, index);
- });
- });
- } else if (self.messagesBuff.haveMoreHistory()) {
- self.messagesBuff.retrieveChatHistory(!index || index <= 0 ? undefined : index);
- ps.doProgramaticScroll(0, true);
- self.one(`onHistoryDecrypted.scrollToMsgId${ msgId}`, () => {
- self.one(`onComponentDidUpdate.scrollToMsgId${ msgId}`, () => {
- self.scrollToMessageId(msgId);
- });
- });
- } else {
- self.isScrollingToMessageId = false;
- }
-};
-ChatRoom.prototype.setMcoFlags = function (flags) {
- const req = {
- a: 'mco',
- cid: this.chatId,
- ...flags
- };
- asyncApiReq(req).dump('roomSetCallFlags');
-};
-ChatRoom.prototype.toggleOpenInvite = function () {
- if (this.type === 'private' || !this.iAmOperator()) {
- return;
- }
- this.setMcoFlags({
- [MCO_FLAGS.OPEN_INVITE]: Math.abs(this.options[MCO_FLAGS.OPEN_INVITE] - 1)
- });
-};
-ChatRoom.prototype.toggleWaitingRoom = function () {
- if (this.type === 'private' || !this.iAmOperator()) {
- return;
- }
- this.setMcoFlags({
- [MCO_FLAGS.WAITING_ROOM]: Math.abs(this.options[MCO_FLAGS.WAITING_ROOM] - 1)
- });
-};
-ChatRoom.prototype.exportToFile = function () {
- if (this.messagesBuff.messages.length === 0 || this.exportIo) {
- return;
- }
- loadingDialog.show('chat_export');
- eventlog(99874);
- this._exportChat().then(() => {
- eventlog(99875, JSON.stringify([1]));
- }).catch(ex => {
- if (d) {
- console.warn('Chat export: ', ex);
- }
- const report = [String(ex && ex.message || ex).replace(/\s+/g, '').substring(0, 64)];
- report.unshift(report[0] === 'Aborted' ? 1 : 0);
- if (!report[0]) {
- msgDialog('error', '', l.export_chat_failed, '', undefined, 1);
- }
- eventlog(99875, JSON.stringify(report));
- }).finally(() => {
- loadingDialog.hide('chat_export');
- this.isScrollingToMessageId = false;
- onIdle(() => this.messagesBuff.detachMessages());
- });
-};
-ChatRoom.prototype._exportChat = async function () {
- this.isScrollingToMessageId = true;
- while (this.messagesBuff.haveMoreHistory()) {
- await this.messagesBuff.retrieveChatHistory(100);
- }
- await Promise.allSettled([this.messagesBuff.isDecrypting || Promise.resolve(), this.messagesBuff.$sharedFilesLoading || Promise.resolve(), this.messagesBuff.$isDecryptingSharedFiles || Promise.resolve()]);
- do {
- await this.messagesBuff.retrieveSharedFilesHistory(100);
- } while (this.messagesBuff.haveMoreSharedFiles);
- let withMedia = !!M.v.length;
- if (withMedia) {
- withMedia = await asyncMsgDialog(`*confirmation:!^${l.export_chat_media_dlg_conf}!${l.export_chat_media_dlg_rej}`, '', l.export_chat_media_dlg_title, l.export_chat_media_dlg_text);
- if (withMedia === null) {
- throw new Error('Aborted');
- }
- }
- let {
- attachNodes,
- stringNodes
- } = this.messagesBuff.getExportContent(withMedia);
- stringNodes = stringNodes.join('\n');
- const basename = M.getSafeName(this.getRoomTitle());
- const zname = l.export_chat_zip_file.replace('%s', basename);
- const bufferName = l.export_chat_text_file.replace('%s', basename);
- if (attachNodes.length) {
- const p = [];
- const n = [];
- let s = 0;
- for (const node of attachNodes) {
- s += node.s;
- if (node.ph) {
- p.push(node.ph);
- } else {
- n.push(node.h);
- }
- }
- const res = await asyncApiReq({
- a: 'qbq',
- s,
- n,
- p
- });
- if (res === 1 || res === 2) {
- const fallback = await asyncMsgDialog('confirmation', '', l.export_chat_media_obq_title, l.export_chat_media_obq_text);
- if (fallback) {
- return M.saveAs(stringNodes, bufferName);
- }
- } else if (res === 0) {
- await M.require('clientzip_js');
- const data = new TextEncoder().encode(stringNodes);
- const dl = {
- size: data.byteLength + s,
- n: bufferName,
- t: unixtime(),
- id: this.chatId,
- p: '',
- io: Object.create(null),
- writer: Object.create(null),
- offset: 0,
- zname
- };
- const io = await prepareExportIo(dl);
- const t = new Date((this.lastActivity || this.ctime) * 1000);
- let failedCount = 0;
- const src = prepareExportStreams(attachNodes, size => {
- failedCount++;
- dl.done += size;
- });
- src.unshift({
- name: bufferName,
- lastModified: t,
- input: data.buffer
- });
- dl.done = 0;
- const reader = clientZip.downloadZip(src).body.getReader();
- dl.nextChunk = async () => {
- const read = await reader.read().catch(dump);
- if (!read) {
- reader.cancel().catch(ex => {
- if (ex !== EOVERQUOTA) {
- msgDialog('error', '', l.export_chat_failed, ex < 0 ? api_strerror(ex) : ex, undefined, 1);
- }
- });
- io.abort();
- delete this.exportIo;
- loadingDialog.hideProgress();
- return;
- }
- if (read.done) {
- loadingDialog.hideProgress();
- io.download(zname);
- delete this.exportIo;
- if (failedCount) {
- msgDialog('error', '', l.export_chat_failed, l.export_chat_partial_fail, undefined, 1);
- }
- } else {
- dl.done += read.value.byteLength;
- loadingDialog.showProgress(dl.done / dl.size * 100);
- io.write(read.value, dl.offset, dl.nextChunk);
- dl.offset += read.value.length;
- }
- };
- io.begin = dl.nextChunk;
- io.setCredentials(false, dl.size, zname);
- this.exportIo = io;
- } else {
- throw new Error(`Unexpected qbq response ${res}`);
- }
- } else {
- return M.saveAs(stringNodes, bufferName);
- }
-};
-ChatRoom.prototype.canJoinLimitedCall = function () {
- const callParts = this.getCallParticipants();
- return this.iAmOperator() && callParts.length < CallManager2.CALL_USER_LIMIT || callParts.length < CallManager2.CALL_USER_LIMIT - 1;
-};
-window.ChatRoom = ChatRoom;
-const chatRoom = {
- ChatRoom
-};
-
-},
-
-137
-(_, EXP_, REQ_) {
-
-"use strict";
-REQ_.d(EXP_, {
-LP: () => getUniqueId,
-N9: () => timing,
-Zz: () => compose,
-hG: () => SoonFcWrap,
-u9: () => ContactAwareComponent,
-w9: () => MegaRenderMixin
-});
-
-const _applyDecoratedDescriptor0__ = REQ_(793);
-const react_dom1__ = REQ_(206);
-const react_dom1 = REQ_.n(react_dom1__);
-const react2__ = REQ_(594);
-const react2 = REQ_.n(react2__);
-
-let _dec, _dec2, _dec3, _dec4, _dec5, _class;
-
-
-const INTERSECTION_OBSERVER_AVAILABLE = typeof IntersectionObserver !== 'undefined';
-const RESIZE_OBSERVER_AVAILABLE = typeof ResizeObserver !== 'undefined';
-function shallowEqual(objA, objB) {
- if (objA === objB) {
- return true;
- }
- for (var key in objA) {
- if (key === "children") {
- continue;
- }
- if (objA.hasOwnProperty(key)) {
- if (!objB.hasOwnProperty(key)) {
- return false;
- } else if (objA[key] !== objB[key]) {
- if (typeof objA[key] === 'function' && typeof objB[key] === 'function') {
- if (objA[key].toString() !== objB[key].toString()) {
- return false;
- }
- } else {
- return false;
- }
- }
- }
- }
- for (key in objB) {
- if (objB.hasOwnProperty(key) && !objA.hasOwnProperty(key)) {
- return false;
- }
- }
- return true;
-}
-window.shallowEqual = shallowEqual;
-const MAX_ALLOWED_DEBOUNCED_UPDATES = 5;
-const DEBOUNCED_UPDATE_TIMEOUT = 60;
-const REENABLE_UPDATES_AFTER_TIMEOUT = 300;
-const MAX_TRACK_CHANGES_RECURSIVE_DEPTH = 1;
-let _propertyTrackChangesVars = Object.create(null);
-_propertyTrackChangesVars._listenersMap = Object.create(null);
-_propertyTrackChangesVars._dataChangedHistory = Object.create(null);
-if (window._propertyTrackChangesVars) {
- _propertyTrackChangesVars = window._propertyTrackChangesVars;
-} else {
- window._propertyTrackChangesVars = _propertyTrackChangesVars;
-}
-window.megaRenderMixinId = window.megaRenderMixinId ? window.megaRenderMixinId : 0;
-const FUNCTIONS = ['render', 'shouldComponentUpdate', 'doProgramaticScroll', 'componentDidMount', 'componentDidUpdate', 'componentWillUnmount', 'refreshUI', 'eventuallyInit', 'handleWindowResize', 'focusTypeArea', 'initScrolling', 'updateScroll', 'isActive', 'onMessagesScrollReinitialise', 'specShouldComponentUpdate', 'attachAnimationEvents', 'eventuallyReinitialise', 'reinitialise', 'reinitialised', 'getContentHeight', 'getScrollWidth', 'isAtBottom', 'onResize', 'isComponentEventuallyVisible', 'getCursorPosition', 'getTextareaMaxHeight'];
-const localStorageProfileRenderFns = localStorage.profileRenderFns;
-if (localStorageProfileRenderFns) {
- window.REACT_RENDER_CALLS = {};
-}
-let ID_CURRENT = 1;
-const DEBUG_THIS = d > 1 ? d : false;
-const scheduler = (func, name, debug) => {
- const dbug = debug !== false && DEBUG_THIS;
- let idnt = null;
- let task = null;
- const fire = () => {
- if (dbug) {
- console.warn('Dispatching scheduled task for %s.%s...', idnt, name);
- }
- if (task) {
- queueMicrotask(task);
- task = null;
- }
- };
- const _scheduler = function () {
- if (dbug) {
- if (!idnt) {
- idnt = name[0] === '(' && this.getReactId && this.getReactId() || this;
- }
- console.warn('Scheduling task from %s.%s...', idnt, name, [this], !!task);
- }
- if (!task) {
- queueMicrotask(fire);
- }
- let idx = arguments.length;
- const args = new Array(idx);
- while (idx--) {
- args[idx] = arguments[idx];
- }
- task = () => {
- func.apply(this, args);
- };
- };
- if (DEBUG_THIS) {
- Object.defineProperty(_scheduler, smbl(name), {
- value: func
- });
- }
- return _scheduler;
-};
-const timing = (min, max) => {
- return function (target, key, de) {
- if (DEBUG_THIS > 2) {
- de[key] = de.value;
- _timing(de, min, max);
- de.value = de[key];
- }
- return de;
- };
-};
-const logcall = () => {
- return function (target, key, descriptor) {
- if (DEBUG_THIS > 3) {
- const func = descriptor.value;
- descriptor.value = function () {
- console.group('[logcall] Entering into %s.%s...', this, key);
- const r = func.apply(this, arguments);
- console.info('[logcall] Leaving %s.%s...', this, key);
- console.groupEnd();
- return r;
- };
- }
- return descriptor;
- };
-};
-const schedule = (local, debug) => {
- return function (target, property, descriptor) {
- if (local) {
- const func = descriptor.value;
- descriptor = {
- configurable: true,
- get: function _unusedScheduler() {
- Object.defineProperty(this, property, {
- value: scheduler(func, `(${ property })`, debug)
- });
- return this[property];
- }
- };
- } else {
- descriptor.value = scheduler(descriptor.value, property, debug);
- }
- return descriptor;
- };
-};
-const compose = (...funcs) => funcs.reduce((a, b) => (...args) => a(b(...args)), arg => arg);
-const replaceAt = (i, o, n) => `${o.slice(0, i)}${n}${o.slice(i + n.length)}`;
-const SoonFcWrap = (milliseconds, local) => {
- return function (target, propertyKey, descriptor) {
- descriptor.value = SoonFc(descriptor.value, !local, milliseconds);
- return descriptor;
- };
-};
-const rAFWrap = () => {
- return function (target, propertyKey, descriptor) {
- const old = descriptor.value;
- descriptor.value = function () {
- return old.apply(this, arguments);
- };
- return descriptor;
- };
-};
-const trycatcher = () => (t, p, d) => (d.value = tryCatch(d.value)) && d;
-const getUniqueId = () => makeUUID().slice(-12);
-const MegaRenderMixin = (_dec = logcall(), _dec2 = SoonFcWrap(50, true), _dec3 = logcall(), _dec4 = SoonFcWrap(80, true), _dec5 = SoonFcWrap(350, true), _class = class MegaRenderMixin extends react2().Component {
- constructor(props) {
- super(props);
- lazy(this, '__internalReactID', function () {
- let key = '';
- let fib = DEBUG_THIS && this._reactInternalFiber;
- while (fib) {
- let tmp = fib.key;
- if (tmp && tmp[0] !== '.' && key.indexOf(tmp) < 0) {
- key += `${tmp }/`;
- }
- if (tmp = fib.memoizedProps) {
- if (tmp.contact) {
- tmp = tmp.contact.u + (tmp.chatRoom ? `@${ tmp.chatRoom.roomId}` : '');
- } else if (tmp.chatRoom) {
- tmp = tmp.chatRoom.roomId;
- } else {
- tmp = 0;
- }
- if (tmp && key.indexOf(tmp) < 0) {
- key += `${tmp }/`;
- }
- }
- fib = fib._debugOwner;
- }
- key = key ? `[${ key.substr(0, key.length - 1) }]` : '';
- return `::${ this.constructor.name }[${ `000${ ID_CURRENT++}`.slice(-4) }]${ key}`;
- });
- lazy(this, '__internalUniqueID', function () {
- return (this.__internalReactID + makeUUID().substr(-12)).replace(/[^a-zA-Z0-9]/g, '');
- });
- Object.defineProperty(this, 'isMounted', {
- value: function MegaRenderMixin_isMounted() {
- return !!this.__isMounted;
- }
- });
- if (DEBUG_THIS > 2) {
- Object.defineProperty(this, 'safeForceUpdate', {
- value: function MegaRenderMixin_safeForceUpdate_debug() {
- console.group('%s.safeForceUpdate: mounted:%s, visible:%s', this.getReactId(), this.__isMounted, this.isComponentEventuallyVisible());
- if (this.__isMounted) {
- this.forceUpdate(() => {
- console.warn('%s.safeForceUpdate finished.', this.getReactId());
- console.groupEnd();
- });
- }
- }
- });
- Object.keys(this).forEach(k => {
- if (this[k] && this[k].apply) {
- const orig = this[k];
- this[k] = function () {
- let s = performance.now();
- const r = orig.apply(this, arguments);
- s = performance.now() - s;
- if (s > 30) {
- console.error(k, this, "took", s, "ms", 'returned', r);
- }
- return r;
- };
- }
- });
- }
- if (DEBUG_THIS) {
- if (!megaChat.__components) {
- megaChat.__components = new WeakMap();
- }
- megaChat.__components.set(this, Object.getPrototypeOf(this));
- }
- }
- componentWillUnmount() {
- if (super.componentWillUnmount) {
- super.componentWillUnmount();
- }
- this.__isMounted = false;
- chatGlobalEventManager.removeEventListener('resize', `megaRenderMixing${ this.getUniqueId()}`);
- chatGlobalEventManager.removeEventListener('hashchange', `hc${ this.getUniqueId()}`);
- const node = this.findDOMNode();
- if (this.__intersectionObserverInstance) {
- if (node) {
- this.__intersectionObserverInstance.unobserve(node);
- }
- this.__intersectionObserverInstance.disconnect();
- this.__intersectionObserverInstance = undefined;
- }
- if (this.onResizeObserved) {
- if (!RESIZE_OBSERVER_AVAILABLE) {
- $(document.body).unbind(`resize.resObs${ this.getUniqueId()}`);
- } else {
- this.__resizeObserverInstance.unobserve(node);
- this.__resizeObserverInstance.disconnect();
- this.__resizeObserverInstance = undefined;
- }
- }
- const instanceId = this.getUniqueId();
- const listeners = _propertyTrackChangesVars._listenersMap[instanceId];
- if (listeners) {
- for (const k in listeners) {
- const v = listeners[k];
- v[0].removeChangeListener(v[1]);
- }
- }
- _propertyTrackChangesVars._listenersMap[instanceId] = null;
- _propertyTrackChangesVars._dataChangedHistory[instanceId] = null;
- if (this._dataStructListeners) {
- this._internalDetachRenderCallbacks();
- }
- if (this.detachRerenderCallbacks) {
- this.detachRerenderCallbacks();
- }
- }
- getReactId() {
- return this.__internalReactID;
- }
- getUniqueId() {
- return this.__internalUniqueID;
- }
- debouncedForceUpdate() {
- this.eventuallyUpdate();
- }
- componentDidMount() {
- if (super.componentDidMount) {
- super.componentDidMount();
- }
- this.__isMounted = true;
- this._wasRendered = true;
- if (this.props.requiresUpdateOnResize || this.requiresUpdateOnResize || !this.props.skipQueuedUpdatesOnResize) {
- chatGlobalEventManager.addEventListener('resize', `megaRenderMixing${ this.getUniqueId()}`, () => this.onResizeDoUpdate());
- }
- chatGlobalEventManager.addEventListener('hashchange', `hc${ this.getUniqueId()}`, () => this.onResizeDoUpdate());
- if (this.props) {
- this._recurseAddListenersIfNeeded("p", this.props);
- }
- if (this.state) {
- this._recurseAddListenersIfNeeded("s", this.state);
- }
- const node = this.findDOMNode();
- if (INTERSECTION_OBSERVER_AVAILABLE && !this.customIsEventuallyVisible && node && node.nodeType) {
- this.__intersectionVisibility = false;
- onIdle(() => {
- this.__intersectionObserverInstance = new IntersectionObserver(entries => {
- const entry = entries.pop();
- if (entry.intersectionRatio < 0.2 && !entry.isIntersecting) {
- this.__intersectionVisibility = false;
- } else {
- this.__intersectionVisibility = true;
- if (this._requiresUpdateOnResize) {
- this.debouncedForceUpdate();
- }
- }
- if (this.onVisibilityChange) {
- this.onVisibilityChange(this.__intersectionVisibility);
- }
- }, {
- threshold: 0.1
- });
- this.__intersectionObserverInstance.observe(node);
- });
- }
- if (this.onResizeObserved) {
- if (!RESIZE_OBSERVER_AVAILABLE) {
- $(document.body).rebind(`resize.resObs${ this.getUniqueId()}`, () => {
- this.onResizeObserved(node.offsetWidth, node.offsetHeight);
- });
- } else {
- this.__resizeObserverInstance = new ResizeObserver(entries => {
- this.onResizeObserved(entries[0].contentRect.width, entries[0].contentRect.height);
- });
- this.__resizeObserverInstance.observe(node);
- }
- }
- if (this.attachRerenderCallbacks) {
- this.attachRerenderCallbacks();
- }
- }
- findDOMNode() {
- if (!this.domNode) {
- let _this$domRef;
- this.domNode = (_this$domRef = this.domRef) == null ? void 0 : _this$domRef.current;
- }
- return this.domNode;
- }
- isComponentVisible() {
- if (!this.__isMounted) {
- return false;
- }
- if (this.customIsEventuallyVisible) {
- const ciev = this.customIsEventuallyVisible;
- const result = typeof ciev === "function" ? ciev.call(this) : ciev;
- if (result !== -1) {
- return result;
- }
- }
- if (this.__intersectionVisibility === false) {
- return false;
- } else if (this.__intersectionVisibility === true) {
- return true;
- }
- const domNode = this.findDOMNode();
- if (!this.props.hideable && (!domNode || domNode.offsetParent === null)) {
- return false;
- }
- if (!$(domNode).is(":visible")) {
- return false;
- }
- return verge.inViewport(domNode);
- }
- isComponentEventuallyVisible() {
- if (!this.__isMounted) {
- return false;
- }
- if (this.customIsEventuallyVisible) {
- const ciev = this.customIsEventuallyVisible;
- return typeof ciev === "function" ? ciev.call(this) : !!ciev;
- }
- if (typeof this.props.isVisible !== 'undefined') {
- return this.props.isVisible;
- }
- return this.__intersectionVisibility !== false;
- }
- eventuallyUpdate() {
- if (!window.megaChat || megaChat.isLoggingOut || this._updatesDisabled || !this._wasRendered || !this.__isMounted) {
- return;
- }
- if (!this.isComponentEventuallyVisible()) {
- this._requiresUpdateOnResize = true;
- return;
- }
- if (this._requiresUpdateOnResize) {
- this._requiresUpdateOnResize = false;
- }
- this.forceUpdate();
- }
- tempDisableUpdates(forHowLong) {
- const self = this;
- self._updatesDisabled = true;
- if (self._updatesReenableTimer) {
- clearTimeout(self._updatesReenableTimer);
- }
- const timeout = forHowLong ? forHowLong : self.REENABLE_UPDATES_AFTER_TIMEOUT ? self.REENABLE_UPDATES_AFTER_TIMEOUT : REENABLE_UPDATES_AFTER_TIMEOUT;
- self._updatesReenableTimer = setTimeout(() => {
- self.tempEnableUpdates();
- }, timeout);
- }
- tempEnableUpdates() {
- clearTimeout(this._updatesReenableTimer);
- this._updatesDisabled = false;
- this.eventuallyUpdate();
- }
- onResizeDoUpdate() {
- this.eventuallyUpdate();
- }
- _getUniqueIDForMap(map, payload) {
- return `${map }.${ payload}`;
- }
- _recurseAddListenersIfNeeded(idx, map, depth) {
- depth |= 0;
- if (map instanceof MegaDataMap && !(this._contactChangeListeners && this._contactChangeListeners.includes(map))) {
- const cacheKey = this._getUniqueIDForMap(map, idx);
- const instanceId = this.getUniqueId();
- if (!_propertyTrackChangesVars._listenersMap[instanceId]) {
- _propertyTrackChangesVars._listenersMap[instanceId] = Object.create(null);
- }
- if (!_propertyTrackChangesVars._listenersMap[instanceId][cacheKey]) {
- _propertyTrackChangesVars._listenersMap[instanceId][cacheKey] = [map, map.addChangeListener(() => this.onPropOrStateUpdated())];
- }
- }
- if (depth++ < MAX_TRACK_CHANGES_RECURSIVE_DEPTH && !this.props.manualDataChangeTracking) {
- const mapKeys = map instanceof MegaDataMap ? map.keys() : Object.keys(map);
- for (let i = 0; i < mapKeys.length; i++) {
- const k = mapKeys[i];
- if (map[k]) {
- this._recurseAddListenersIfNeeded(`${idx }_${ k}`, map[k], depth);
- }
- }
- }
- }
- _checkDataStructForChanges(idx, v, rv, depth) {
- if (!v && v === rv) {
- return false;
- }
- if (!rv && v) {
- return true;
- }
- if (v === null) {
- return rv !== null;
- }
- if (v instanceof MegaDataMap) {
- const cacheKey = this._getUniqueIDForMap(v, idx);
- const dataChangeHistory = _propertyTrackChangesVars._dataChangedHistory;
- const instanceId = this.getUniqueId();
- if (!dataChangeHistory[instanceId]) {
- dataChangeHistory[instanceId] = Object.create(null);
- }
- if (dataChangeHistory[instanceId][cacheKey] !== v._dataChangeIndex) {
- if (window.RENDER_DEBUG) {
- console.error("changed: ", this.getElementName(), cacheKey, v._dataChangeTrackedId, v._dataChangeIndex, v);
- }
- dataChangeHistory[instanceId][cacheKey] = v._dataChangeIndex;
- return true;
- }
- return false;
- }
- return depth < MAX_TRACK_CHANGES_RECURSIVE_DEPTH && v && v.byteLength === undefined && typeof v === "object" && this._recursiveSearchForDataChanges(idx, v, rv, depth + 1) === true;
- }
- _recursiveSearchForDataChanges(idx, map, referenceMap, depth) {
- const self = this;
- depth = depth || 0;
- if (!this.isMounted() || this._updatesDisabled === true) {
- return;
- }
- if (!this._wasRendered) {
- if (window.RENDER_DEBUG) console.error("First time render", self.getElementName(), map, referenceMap);
- this._wasRendered = true;
- return true;
- }
- if (idx === "p_children") {
- if (map.map && referenceMap.map) {
- const oldKeys = map.map((child) => {
- return child ? child.key : child;
- });
- const newKeys = referenceMap.map((child) => {
- return child ? child.key : child;
- });
- if (!shallowEqual(oldKeys, newKeys)) {
- return true;
- }
- } else if (!map && referenceMap || map && !referenceMap) {
- return true;
- } else if (map.$$typeof && referenceMap.$$typeof) {
- if (!shallowEqual(map.props, referenceMap.props) || !shallowEqual(map.state, referenceMap.state)) {
- return true;
- }
- }
- } else if (map && !referenceMap || !map && referenceMap || map && referenceMap && !shallowEqual(map, referenceMap)) {
- return true;
- }
- const mapKeys = map instanceof MegaDataMap ? map.keys() : Object.keys(map);
- for (let i = mapKeys.length; i--;) {
- const k = mapKeys[i];
- if (this._checkDataStructForChanges(`${idx }_${ k}`, map[k], referenceMap[k], depth)) {
- return true;
- }
- }
- return false;
- }
- shouldComponentUpdate(nextProps, nextState) {
- let shouldRerender = false;
- if (megaChat && megaChat.isLoggingOut) {
- return false;
- }
- if (!this.isMounted() || this._updatesDisabled === true) {
- if (window.RENDER_DEBUG) {
- console.error("shouldUpdate? No.", "F1", this.getElementName(), this.props, nextProps, this.state, nextState);
- }
- return false;
- }
- if (this.customIsEventuallyVisible) {
- let ciev = this.customIsEventuallyVisible;
- ciev = typeof ciev === "function" ? ciev.call(this) : !!ciev;
- if (!this._queueUpdateWhenVisible && !ciev) {
- this._queueUpdateWhenVisible = true;
- if (window.RENDER_DEBUG) {
- console.error("shouldUpdate? No.", "F1.1", this.getElementName(), this.props, nextProps, this.state, nextState);
- }
- } else if (this._queueUpdateWhenVisible && ciev) {
- delete this._queueUpdateWhenVisible;
- return true;
- }
- }
- if (this.specShouldComponentUpdate) {
- const r = this.specShouldComponentUpdate(nextProps, nextState);
- if (r === false) {
- if (window.RENDER_DEBUG) {
- console.error("shouldUpdate? No.", "F2", this.getElementName(), this.props, nextProps, this.state, nextState);
- }
- this._requiresUpdateOnResize = true;
- return false;
- } else if (r === true) {
- return true;
- }
- }
- if (!this.props.disableCheckingVisibility && !this.isComponentEventuallyVisible()) {
- if (window.RENDER_DEBUG) {
- console.error("shouldUpdate? No.", "FVis", this.getElementName(), this.props, nextProps, this.state, nextState);
- }
- this._requiresUpdateOnResize = true;
- return false;
- }
- if (this.props !== null) {
- shouldRerender = this._recursiveSearchForDataChanges("p", nextProps, this.props);
- }
- if (shouldRerender === false) {
- if (window.RENDER_DEBUG) {
- console.error("shouldUpdate? No.", "F3", this.getElementName(), this.props, nextProps, this.state, nextState);
- }
- }
- if (shouldRerender === false && this.state !== null) {
- shouldRerender = this._recursiveSearchForDataChanges("s", nextState, this.state);
- }
- if (window.RENDER_DEBUG) {
- if (shouldRerender) {}
- console.error("shouldRerender?", shouldRerender, "rendered: ", this.getElementName(), "props:", this.props, "nextProps:", this.props, "state:", this.state);
- }
- if (shouldRerender === true) {
- if (this.props) {
- this._recurseAddListenersIfNeeded("p", this.props);
- }
- if (this.state) {
- this._recurseAddListenersIfNeeded("s", this.state);
- }
- } else {
- if (window.RENDER_DEBUG) {
- console.error("shouldUpdate? No.", "F4", this.getElementName(), this.props, nextProps, this.state, nextState);
- }
- }
- return shouldRerender;
- }
- onPropOrStateUpdated() {
- this.eventuallyUpdate();
- }
- getElementName() {
- return this._reactInternalFiber.elementType.name;
- }
- safeForceUpdate() {
- if (this.__isMounted) {
- this.forceUpdate();
- }
- }
- componentDidUpdate() {
- if (window.RENDER_DEBUG) {
- const self = this;
- const getElementName = function () {
- if (!self.constructor) {
- return "unknown";
- }
- return self.constructor.name;
- };
- console.error("renderedX: ", getElementName(), "props:", this.props, "state:", this.state);
- }
- if (this.domNode && !this.domNode.isConnected) {
- delete this.domNode;
- }
- }
- UNSAFE_componentWillReceiveProps(nextProps, nextContext) {
- if (localStorageProfileRenderFns) {
- const self = this;
- const componentName = self.constructor ? self.constructor.name : "unknown";
- if (!this._wrappedRender) {
- FUNCTIONS.forEach((fnName) => {
- const _origFn = self[fnName];
- if (_origFn) {
- self[fnName] = function () {
- const start = performance.now();
- const res = _origFn.apply(this, arguments);
- REACT_RENDER_CALLS[`${componentName }.${ fnName}`] = REACT_RENDER_CALLS[`${componentName }.${ fnName}`] || 0;
- REACT_RENDER_CALLS[`${componentName }.${ fnName}`] += performance.now() - start;
- return res;
- };
- }
- });
- self._wrappedRender = true;
- }
- REACT_RENDER_CALLS.sorted = function () {
- const sorted = [];
- Object.keys(REACT_RENDER_CALLS).sort((a, b) => {
- if (REACT_RENDER_CALLS[a] < REACT_RENDER_CALLS[b]) {
- return 1;
- } else if (REACT_RENDER_CALLS[a] > REACT_RENDER_CALLS[b]) {
- return -1;
- } else {
- return 0;
- }
- }).forEach((k) => {
- if (typeof REACT_RENDER_CALLS[k] !== 'function') {
- sorted.push([k, REACT_RENDER_CALLS[k]]);
- }
- });
- return sorted;
- };
- REACT_RENDER_CALLS.clear = function () {
- Object.keys(REACT_RENDER_CALLS).forEach((k) => {
- if (typeof REACT_RENDER_CALLS[k] !== 'function') {
- delete REACT_RENDER_CALLS[k];
- }
- });
- };
- }
- }
- _internalDetachRenderCallbacks() {
- const items = this._dataStructListeners || false;
- for (let i = items.length; i--;) {
- const item = items[i];
- if (item[0] === 'dsprops') {
- console.assert(item[2].removeChangeListener(item[1]), 'listener not found..');
- }
- }
- }
- addDataStructListenerForProperties(obj, properties) {
- if (!(obj instanceof MegaDataMap)) {
- return;
- }
- if (!this._dataStructListeners) {
- this._dataStructListeners = [];
- }
- properties = array.to.object(properties);
- const id = obj.addChangeListener((obj, data, k) => properties[k] && this.onPropOrStateUpdated());
- this._dataStructListeners.push(['dsprops', id, obj]);
- }
-}, (0,_applyDecoratedDescriptor0__.A)(_class.prototype, "componentWillUnmount", [_dec], Object.getOwnPropertyDescriptor(_class.prototype, "componentWillUnmount"), _class.prototype), (0,_applyDecoratedDescriptor0__.A)(_class.prototype, "debouncedForceUpdate", [_dec2], Object.getOwnPropertyDescriptor(_class.prototype, "debouncedForceUpdate"), _class.prototype), (0,_applyDecoratedDescriptor0__.A)(_class.prototype, "componentDidMount", [_dec3], Object.getOwnPropertyDescriptor(_class.prototype, "componentDidMount"), _class.prototype), (0,_applyDecoratedDescriptor0__.A)(_class.prototype, "eventuallyUpdate", [_dec4], Object.getOwnPropertyDescriptor(_class.prototype, "eventuallyUpdate"), _class.prototype), (0,_applyDecoratedDescriptor0__.A)(_class.prototype, "onResizeDoUpdate", [_dec5], Object.getOwnPropertyDescriptor(_class.prototype, "onResizeDoUpdate"), _class.prototype), _class);
-class ContactAwareComponent extends MegaRenderMixin {
- constructor(props) {
- super(props);
- this.loadContactInfo();
- }
- _validContact() {
- const {
- contact
- } = this.props;
- if (!contact) {
- return false;
- }
- return (contact.h || contact.u) in M.u;
- }
- _attachRerenderCbContacts(others) {
- if (!this._validContact()) {
- return;
- }
- this.addDataStructListenerForProperties(this.props.contact, ['name', 'firstName', 'lastName', 'nickname', 'm', 'avatar'].concat(Array.isArray(others) ? others : []));
- }
- attachRerenderCallbacks() {
- this._attachRerenderCbContacts();
- }
- loadContactInfo() {
- let _contact$avatar;
- if (!this._validContact()) {
- return;
- }
- const {
- contact,
- chatRoom
- } = this.props;
- const contactHandle = contact.h || contact.u;
- const syncName = !ContactAwareComponent.unavailableNames[contactHandle] && !contact.firstName && !contact.lastName;
- const syncMail = megaChat.FORCE_EMAIL_LOADING || (contact.c === 1 || contact.c === 2) && !contact.m && !is_chatlink;
- const syncAvtr = (is_chatlink && (!contact.avatar || ((_contact$avatar = contact.avatar) == null ? void 0 : _contact$avatar.type) === "text") || !contact.avatar) && !avatars[contactHandle] && !ContactAwareComponent.unavailableAvatars[contactHandle];
- const loader = () => {
- if (!this.isComponentEventuallyVisible()) {
- this.__isLoadingContactInfo = null;
- this._requiresUpdateOnResize = true;
- return;
- }
- const promises = [];
- const chatHandle = is_chatlink.ph || chatRoom && chatRoom.publicChatHandle;
- if (syncName) {
- promises.push(megaChat.plugins.userHelper.getUserName(contactHandle, chatHandle));
- }
- if (syncMail) {
- promises.push(M.syncContactEmail(contactHandle));
- }
- if (syncAvtr) {
- promises.push(useravatar.loadAvatar(contactHandle, chatHandle).catch(() => {
- ContactAwareComponent.unavailableAvatars[contactHandle] = true;
- }));
- }
- return Promise.allSettled(promises).always(() => {
- this.eventuallyUpdate();
- this.__isLoadingContactInfo = false;
- if (!contact.firstName && !contact.lastName) {
- ContactAwareComponent.unavailableNames[contactHandle] = true;
- }
- });
- };
- if (syncName || syncMail || syncAvtr) {
- (this.__isLoadingContactInfo = tSleep(0.3)).then(loader).catch(dump);
- }
- }
- componentDidUpdate() {
- super.componentDidUpdate();
- if (this.__isLoadingContactInfo === null) {
- this.loadContactInfo();
- }
- }
- componentWillUnmount() {
- super.componentWillUnmount();
- if (this.__isLoadingContactInfo) {
- this.__isLoadingContactInfo.abort();
- this.__isLoadingContactInfo = false;
- }
- }
- isLoadingContactInfo() {
- return !!this.__isLoadingContactInfo;
- }
-}
-ContactAwareComponent.unavailableAvatars = Object.create(null);
-ContactAwareComponent.unavailableNames = Object.create(null);
-
-},
-
-424
-(_, EXP_, REQ_) {
-
-"use strict";
-REQ_.d(EXP_, {
-A: () => ChatToaster
-});
-const react0__ = REQ_(594);
-const react0 = REQ_.n(react0__);
-const _mixins1__ = REQ_(137);
-const _meetings_call_jsx2__ = REQ_(3);
-const _ui_buttons3__ = REQ_(994);
-
-
-
-
-const NAMESPACE = 'chat-toast';
-class ChatToaster extends react0().Component {
- constructor(props) {
- super(props);
- this.uid = `${this.constructor.name}--${(0,_mixins1__.LP)()}`;
- this.domRef = react0().createRef();
- this.state = {
- toast: null,
- endTime: 0,
- fmToastId: null,
- persistentToast: null
- };
- this.toasts = [];
- this.persistentToasts = [];
- }
- enqueueToast(e) {
- if (this.props.showDualNotifications && e.data.options && e.data.options.persistent) {
- this.persistentToasts.push(e.data);
- } else {
- this.toasts.push(e.data);
- }
- this.pollToasts();
- }
- pollToasts() {
- const {
- toast: shownToast,
- persistentToast: shownPersistentToast
- } = this.state;
- const {
- isRootToaster,
- showDualNotifications,
- onShownToast
- } = this.props;
- const now = Date.now();
- if (this.toasts.length + this.persistentToasts.length) {
- if (this.domRef.current && (!isRootToaster && _meetings_call_jsx2__.Ay.isExpanded() || M.chat)) {
- if (this.toasts.length && !shownToast) {
- this.dispatchToast(this.toasts.shift(), now);
- }
- if (showDualNotifications && this.persistentToasts.length && !shownPersistentToast) {
- const persistentToast = this.persistentToasts.shift();
- this.setState({
- persistentToast
- }, () => this.pollToasts());
- if (typeof onShownToast === 'function') {
- onShownToast(persistentToast);
- }
- }
- } else if (isRootToaster && this.toasts.length && !shownToast) {
- const toast = this.toasts.shift();
- this.dispatchToast(toast, now, {
- fmToastId: 'tmp'
- });
- this.dispatchFMToast(toast);
- }
- }
- }
- dispatchFMToast(toast, redraw) {
- window.toaster.alerts.medium(...toast.renderFM()).then(fmToastId => {
- if (!redraw) {
- toast.onShown(fmToastId);
- }
- this.setState({
- fmToastId
- });
- if (toast.updater && typeof toast.updater === 'function') {
- toast.updater();
- toast.updateInterval = setInterval(() => {
- toast.updater();
- const value = toast.render();
- if (!value) {
- window.toaster.alerts.hide(fmToastId);
- return this.onClose(toast.options && toast.options.persistent);
- }
- if (value !== $('span', `#${fmToastId}`).text()) {
- $('span', `#${fmToastId}`).text(value);
- }
- }, 250);
- }
- });
- }
- dispatchToast(toast, now, options = {}) {
- const {
- fmToastId,
- endTime,
- silent
- } = options;
- const {
- onShownToast,
- onHideToast
- } = this.props;
- this.setState({
- toast,
- endTime: endTime || now + toast.getTTL(),
- fmToastId
- }, () => {
- if (!silent) {
- toast.onShown();
- }
- this.timeout = setTimeout(() => {
- delete this.timeout;
- this.setState({
- toast: null,
- endTime: 0
- }, () => this.pollToasts());
- if (typeof toast.onEnd === 'function') {
- toast.onEnd();
- }
- if (typeof onHideToast === 'function') {
- onHideToast(toast);
- }
- if (toast.updateInterval) {
- clearInterval(toast.updateInterval);
- delete toast.updateInterval;
- }
- }, endTime ? endTime - now : toast.getTTL());
- });
- if (typeof onShownToast === 'function') {
- onShownToast(toast);
- }
- }
- onClose(persistent) {
- const {
- showDualNotifications,
- onHideToast
- } = this.props;
- const {
- toast,
- persistentToast
- } = this.state;
- if (showDualNotifications && persistent) {
- if (typeof persistentToast.onEnd === 'function') {
- persistentToast.onEnd();
- }
- this.setState({
- persistentToast: null
- }, () => this.pollToasts());
- if (typeof onHideToast === 'function') {
- onHideToast(persistentToast);
- }
- return;
- }
- if (toast.updateInterval) {
- clearInterval(toast.updateInterval);
- delete toast.updateInterval;
- }
- clearTimeout(this.timeout);
- delete this.timeout;
- if (typeof toast.onEnd === 'function') {
- toast.onEnd();
- }
- if (typeof onHideToast === 'function') {
- onHideToast(toast);
- }
- this.setState({
- toast: null,
- endTime: 0
- }, () => this.pollToasts());
- }
- flush() {
- const {
- toast,
- persistentToast,
- fmToastId
- } = this.state;
- this.endToastIntervals();
- if (fmToastId && fmToastId !== 'tmp') {
- window.toaster.alerts.hide(fmToastId);
- }
- this.toasts = [];
- this.persistentToasts = [];
- if (this.timeout) {
- clearTimeout(this.timeout);
- delete this.timeout;
- }
- if (toast) {
- this.onClose(toast.persistent);
- }
- if (persistentToast) {
- this.onClose(true);
- }
- this.setState({
- toast: null,
- endTime: 0,
- fmToastId: null,
- persistentToast: null
- });
- }
- endToastIntervals() {
- if (!this.props.isRootToaster) {
- return;
- }
- for (const toast of this.toasts) {
- if (toast.updateInterval) {
- clearInterval(toast.updateInterval);
- }
- }
- for (const toast of this.persistentToasts) {
- if (toast.updateInterval) {
- clearInterval(toast.updateInterval);
- }
- }
- }
- componentDidMount() {
- megaChat.rebind(`onChatToast.toaster${this.uid}`, e => this.enqueueToast(e));
- megaChat.rebind(`onChatToastFlush.toaster${this.uid}`, () => this.flush());
- onIdle(() => this.pollToasts());
- if (this.props.isRootToaster) {
- this.bpcListener = mBroadcaster.addListener('beforepagechange', tpage => {
- const {
- toast,
- endTime,
- fmToastId
- } = this.state;
- const now = Date.now();
- if (toast && endTime - 500 > now) {
- const toChat = tpage.includes('chat') && tpage !== 'securechat';
- if (toChat && !M.chat) {
- clearTimeout(this.timeout);
- window.toaster.alerts.hide(fmToastId);
- if (toast.updateInterval) {
- clearInterval(toast.updateInterval);
- delete toast.updateInterval;
- }
- this.dispatchToast(toast, now, {
- endTime,
- silent: true
- });
- } else if (!toChat && M.chat) {
- clearTimeout(this.timeout);
- this.dispatchToast(toast, now, {
- fmToastId: 'tmp',
- endTime,
- silent: true
- });
- this.dispatchFMToast(toast, true);
- }
- } else if (toast && typeof toast.onEnd === 'function') {
- toast.onEnd();
- }
- });
- }
- }
- componentWillUnmount() {
- megaChat.off(`onChatToast.toaster${this.uid}`);
- megaChat.off(`onChatToastFlush.toaster${this.uid}`);
- if (this.bpcListener) {
- mBroadcaster.removeListener(this.bpcListener);
- }
- if (this.timeout) {
- clearTimeout(this.timeout);
- }
- this.endToastIntervals();
- }
- render() {
- const {
- hidden,
- isRootToaster,
- showDualNotifications
- } = this.props;
- const {
- toast,
- fmToastId,
- persistentToast
- } = this.state;
- return !hidden && !fmToastId && react0().createElement("div", {
- ref: this.domRef,
- className: `chat-toast-bar ${isRootToaster ? 'toaster-root' : ''}`
- }, showDualNotifications && persistentToast && react0().createElement(ChatToastMsg, {
- toast: persistentToast,
- isRootToaster,
- usePersistentStyle: true,
- onClose: p => this.onClose(p)
- }), toast && react0().createElement(ChatToastMsg, {
- toast,
- isRootToaster,
- isDualToast: !!persistentToast,
- onClose: p => this.onClose(p)
- }));
- }
-}
-class ChatToastMsg extends react0().Component {
- constructor(...args) {
- super(...args);
- this.state = {
- value: ''
- };
- }
- componentDidMount() {
- const {
- toast,
- onClose
- } = this.props;
- if (toast.updater && typeof toast.updater === 'function') {
- toast.updater();
- this.updateInterval = setInterval(() => {
- toast.updater();
- const value = toast.render();
- if (!value) {
- return onClose(toast.options && toast.options.persistent);
- }
- if (value !== this.state.value) {
- this.setState({
- value
- });
- }
- }, 250);
- }
- const value = toast.render();
- if (value) {
- this.setState({
- value
- });
- } else {
- onClose(toast.options && toast.options.persistent);
- }
- }
- componentWillUnmount() {
- if (this.updateInterval) {
- clearInterval(this.updateInterval);
- }
- }
- render() {
- const {
- toast,
- isRootToaster,
- isDualToast,
- usePersistentStyle,
- onClose
- } = this.props;
- const {
- value
- } = this.state;
- if (usePersistentStyle && toast.options.persistent) {
- return react0().createElement("div", {
- className: `${NAMESPACE} chat-persistent-toast`
- }, value || toast.render());
- }
- const closeButton = toast.close && react0().createElement(_ui_buttons3__.$, {
- className: "chat-toast-close",
- icon: "sprite-fm-mono icon-close-component",
- onClick: onClose
- });
- const icon = toast.icon && react0().createElement("i", {
- className: toast.icon
- });
- if (isRootToaster) {
- return react0().createElement("div", {
- className: `${NAMESPACE} chat-toast-wrapper root-toast`
- }, react0().createElement("div", {
- className: "toast-value-wrapper"
- }, icon, react0().createElement("div", {
- className: "toast-value"
- }, value || toast.render())), closeButton);
- }
- return react0().createElement("div", {
- className: `${NAMESPACE} chat-toast-wrapper theme-light-forced ${isDualToast ? 'dual-toast' : ''}`
- }, react0().createElement("div", {
- className: "toast-value"
- }, value || toast.render()));
- }
-}
-
-},
-
-77
-(_, EXP_, REQ_) {
-
-"use strict";
-
-// EXPORTS
-REQ_.d(EXP_, {
- A: () => composedTextArea
-});
-
-// EXTERNAL MODULE: external "React"
-const React_ = REQ_(594);
-const REaCt = REQ_.n(React_);
-;// ./js/chat/ui/whosTyping.jsx
-
-class WhosTyping extends REaCt().Component {
- constructor(...args) {
- super(...args);
- this.domRef = REaCt().createRef();
- this.state = {
- currentlyTyping: {}
- };
- }
- componentDidMount() {
- const {
- chatRoom
- } = this.props;
- chatRoom.rebind('onParticipantTyping.whosTyping', (e, user_handle, bCastCode) => {
- if (user_handle === u_handle) {
- return;
- }
- const u_h = user_handle;
- if (u_h === u_handle) {
- return;
- } else if (!M.u[u_h]) {
- return;
- }
- const currentlyTyping = {
- ...this.state.currentlyTyping
- };
- if (currentlyTyping[u_h]) {
- currentlyTyping[u_h].abort();
- }
- if (bCastCode === 1) {
- const timer = tSleep(5);
- timer.then(() => {
- this.stoppedTyping(u_h);
- });
- currentlyTyping[u_h] = timer;
- this.setState({
- currentlyTyping
- });
- } else {
- this.stoppedTyping(u_h);
- }
- this.forceUpdate();
- });
- }
- componentWillUnmount() {
- this.props.chatRoom.off('onParticipantTyping.whosTyping');
- }
- stoppedTyping(u_h) {
- if (this.domRef.current) {
- const {
- currentlyTyping
- } = this.state;
- if (currentlyTyping[u_h]) {
- const newState = {
- ...currentlyTyping
- };
- if (!newState[u_h].aborted) {
- newState[u_h].abort();
- }
- delete newState[u_h];
- this.setState({
- currentlyTyping: newState
- });
- }
- }
- }
- render() {
- const users = Object.keys(this.state.currentlyTyping);
- if (users.length > 0) {
- const names = users.map(u_h => M.getNameByHandle(u_h)).filter(String);
- let namesDisplay = "";
- let areMultipleUsersTyping = false;
- if (names.length > 1) {
- areMultipleUsersTyping = true;
- namesDisplay = [names.splice(0, names.length - 1).join(", "), names[0]];
- } else {
- areMultipleUsersTyping = false;
- namesDisplay = [names[0]];
- }
- return REaCt().createElement("div", {
- ref: this.domRef,
- className: "typing-block"
- }, REaCt().createElement("div", {
- className: "typing-text"
- }, areMultipleUsersTyping ? l[8872].replace("%1", namesDisplay[0]).replace("%2", namesDisplay[1]) : l[8629].replace("%1", namesDisplay[0])), REaCt().createElement("div", {
- className: "typing-bounce"
- }, REaCt().createElement("div", {
- className: "typing-bounce1"
- }), REaCt().createElement("div", {
- className: "typing-bounce2"
- }), REaCt().createElement("div", {
- className: "typing-bounce3"
- })));
- }
- return null;
- }
-}
-// EXTERNAL MODULE: ./js/chat/ui/typingArea.jsx + 1 modules
-const typingArea = REQ_(795);
-// EXTERNAL MODULE: ./js/ui/buttons.jsx
-const buttons = REQ_(994);
-// EXTERNAL MODULE: ./js/ui/dropdowns.jsx
-const dropdowns = REQ_(911);
-;// ./js/chat/ui/composedTextArea.jsx
-
-
-
-
-
-const ComposedTextArea = ({
- chatRoom,
- parent,
- containerRef,
- typingAreaText,
- onTypingAreaChanged
-}) => REaCt().createElement("div", {
- className: "chat-textarea-block"
-}, REaCt().createElement(WhosTyping, {
- chatRoom
-}), REaCt().createElement(typingArea.T, {
- chatRoom,
- className: "main-typing-area",
- containerRef,
- disabled: chatRoom.isReadOnly(),
- persist: true,
- text: typingAreaText,
- onValueChanged: onTypingAreaChanged,
- onUpEditPressed: () => {
- const keys = chatRoom.messagesBuff.messages.keys();
- for (let i = keys.length; i--;) {
- const message = chatRoom.messagesBuff.messages[keys[i]];
- const contact = M.u[message.userId];
- if (!contact) {
- continue;
- }
- if (message.isEditable() && !message.requiresManualRetry && !message.deleted && (!message.type || message instanceof Message) && (!message.isManagement || !message.isManagement())) {
- parent.historyPanel.editMessage(message.messageId);
- return true;
- }
- }
- return false;
- },
- onResized: () => {
- parent.historyPanel.handleWindowResize();
- },
- onConfirm: messageContents => {
- const {
- messagesListScrollable
- } = parent.historyPanel;
- if (messageContents && messageContents.length > 0) {
- if (!chatRoom.scrolledToBottom) {
- chatRoom.scrolledToBottom = true;
- parent.lastScrollPosition = 0;
- chatRoom.rebind('onMessagesBuffAppend.pull', () => {
- if (messagesListScrollable) {
- messagesListScrollable.scrollToBottom(false);
- delay('messagesListScrollable', () => {
- messagesListScrollable.enable();
- }, 1500);
- }
- });
- chatRoom.sendMessage(messageContents);
- messagesListScrollable == null || messagesListScrollable.disable();
- messagesListScrollable == null || messagesListScrollable.scrollToBottom(true);
- } else {
- chatRoom.sendMessage(messageContents);
- }
- }
- }
-}, REaCt().createElement(buttons.$, {
- className: "popup-button left",
- icon: "sprite-fm-mono icon-add",
- disabled: chatRoom.isReadOnly()
-}, REaCt().createElement(dropdowns.Dropdown, {
- className: "wide-dropdown attach-to-chat-popup light",
- noArrow: "true",
- positionMy: "left top",
- positionAt: "left bottom",
- vertOffset: 4,
- wrapper: "#fmholder"
-}, REaCt().createElement("div", {
- className: "dropdown info-txt"
-}, l[23753] || 'Send...'), REaCt().createElement(dropdowns.DropdownItem, {
- className: "link-button",
- icon: "sprite-fm-mono icon-cloud",
- label: l[19794] || 'My Cloud Drive',
- disabled: mega.paywall,
- onClick: () => chatRoom.trigger('openAttachCloudDialog')
-}), REaCt().createElement(dropdowns.DropdownItem, {
- className: "link-button",
- icon: "sprite-fm-mono icon-session-history",
- label: l[19795] || 'My computer',
- disabled: mega.paywall,
- onClick: () => chatRoom.uploadFromComputer()
-}), !is_eplusplus && !is_chatlink && !chatRoom.isNote && REaCt().createElement(REaCt().Fragment, null, REaCt().createElement("hr", null), REaCt().createElement(dropdowns.DropdownItem, {
- className: "link-button",
- icon: "sprite-fm-mono icon-send-contact",
- label: l.share_contact_button,
- onClick: () => chatRoom.trigger('openSendContactDialog')
-}))))));
-const composedTextArea = ComposedTextArea;
-
-},
-
-251
-(_, EXP_, REQ_) {
-
-"use strict";
-REQ_.r(EXP_);
-REQ_.d(EXP_, {
-Avatar: () => Avatar,
-ContactAwareName: () => ContactAwareName,
-ContactButton: () => ContactButton,
-ContactCard: () => ContactCard,
-ContactFingerprint: () => ContactFingerprint,
-ContactItem: () => ContactItem,
-ContactPickerDialog: () => ContactPickerDialog,
-ContactPickerWidget: () => ContactPickerWidget,
-ContactPresence: () => ContactPresence,
-ContactVerified: () => ContactVerified,
-LastActivity: () => LastActivity,
-MAX_FREQUENTS: () => MAX_FREQUENTS,
-MembersAmount: () => MembersAmount
-});
-const _extends0__ = REQ_(168);
-const react1__ = REQ_(594);
-const react1 = REQ_.n(react1__);
-const _mixins2__ = REQ_(137);
-const _ui_utils_jsx3__ = REQ_(314);
-const _ui_perfectScrollbar_jsx4__ = REQ_(486);
-const _ui_buttons_jsx5__ = REQ_(994);
-const _ui_dropdowns_jsx6__ = REQ_(911);
-const _contactsPanel_contactsPanel_jsx7__ = REQ_(173);
-const _ui_modalDialogs8__ = REQ_(318);
-const _link_jsx9__ = REQ_(280);
-const _updateObserver_jsx10__ = REQ_(501);
-
-
-
-
-
-
-
-
-
-
-
-
-const MAX_FREQUENTS = 3;
-const closeDropdowns = () => {
- document.dispatchEvent(new Event('closeDropdowns'));
-};
-class ContactButton extends _mixins2__.u9 {
- constructor(props) {
- super(props);
- this.dropdownItemGenerator = this.dropdownItemGenerator.bind(this);
- }
- customIsEventuallyVisible() {
- if (this.props.chatRoom) {
- return this.props.chatRoom.isCurrentlyActive;
- }
- return -1;
- }
- dropdownItemGenerator() {
- let {
- contact,
- dropdowns,
- chatRoom,
- dropdownRemoveButton
- } = this.props;
- dropdowns = dropdowns ? dropdowns : [];
- const moreDropdowns = [];
- moreDropdowns.push(react1().createElement("div", {
- className: "dropdown-avatar rounded",
- key: "mainContactInfo",
- onClick: () => {
- if (contact.c === 2) {
- loadSubPage('fm/account');
- }
- if (contact.c === 1) {
- loadSubPage(`fm/chat/contacts/${ contact.u}`);
- }
- }
- }, react1().createElement(Avatar, {
- className: "avatar-wrapper context-avatar",
- chatRoom,
- contact,
- hideVerifiedBadge: "true"
- }), react1().createElement("div", {
- className: "dropdown-user-name"
- }, react1().createElement("div", {
- className: "name"
- }, react1().createElement(ContactAwareName, {
- overflow: true,
- contact
- }), react1().createElement(ContactPresence, {
- className: "small",
- contact
- })), contact && (megaChat.FORCE_EMAIL_LOADING || contact.c === 1 || contact.c === 2) && react1().createElement("span", {
- className: "email"
- }, contact.m))));
- moreDropdowns.push(react1().createElement(ContactFingerprint, {
- key: "fingerprint",
- contact
- }));
- if (dropdowns.length && contact.c !== 2) {
- moreDropdowns.push(dropdowns);
- moreDropdowns.push(react1().createElement("hr", {
- key: "top-separator"
- }));
- }
- if (contact.u === u_handle) {
- moreDropdowns.push(react1().createElement(_ui_dropdowns_jsx6__.DropdownItem, {
- key: "view0",
- icon: "sprite-fm-mono icon-user-filled",
- label: l[187],
- onClick: () => loadSubPage('fm/account')
- }));
- }
- if (contact.c === 1) {
- const startAudioCall = () => {
- megaChat.createAndShowPrivateRoom(contact.u).then(room => {
- room.setActive();
- room.startAudioCall();
- });
- };
- if (megaChat.currentlyOpenedChat && megaChat.currentlyOpenedChat === contact.u) {
- moreDropdowns.push(react1().createElement("div", {
- key: "startAudioVideoCall",
- "data-simpletipposition": "top",
- className: "simpletip",
- "data-simpletip": !megaChat.hasSupportForCalls ? l.call_not_suported : ''
- }, react1().createElement(_ui_dropdowns_jsx6__.DropdownItem, {
- disabled: !megaChat.hasSupportForCalls,
- key: "startCall",
- className: "sprite-fm-mono-before icon-arrow-right-before",
- icon: "sprite-fm-mono icon-phone",
- submenu: megaChat.hasSupportForCalls,
- label: l[19125]
- }), react1().createElement("div", {
- className: "dropdown body submenu",
- key: "dropdownGroup"
- }, react1().createElement("div", null, react1().createElement(_ui_dropdowns_jsx6__.DropdownItem, {
- key: "startAudio",
- icon: "sprite-fm-mono icon-phone",
- disabled: !megaChat.hasSupportForCalls,
- label: l[1565],
- onClick: startAudioCall
- })), react1().createElement("div", null, react1().createElement(_ui_dropdowns_jsx6__.DropdownItem, {
- key: "startVideo",
- icon: "sprite-fm-mono icon-video-call-filled",
- disabled: !megaChat.hasSupportForCalls,
- label: l[1566],
- onClick: () => {
- megaChat.createAndShowPrivateRoom(contact.u).then(room => {
- room.setActive();
- room.startVideoCall();
- });
- }
- })))));
- } else {
- moreDropdowns.push(react1().createElement(_ui_dropdowns_jsx6__.DropdownItem, {
- key: "startChat",
- icon: "sprite-fm-mono icon-chat",
- label: l[5885],
- onClick: () => {
- loadSubPage(`fm/chat/p/${ contact.u}`);
- }
- }));
- }
- moreDropdowns.push(react1().createElement("hr", {
- key: "files-separator"
- }));
- moreDropdowns.push(react1().createElement(_ui_dropdowns_jsx6__.DropdownItem, {
- key: "send-files-item",
- icon: "sprite-fm-mono icon-send-files",
- label: l[6834],
- disabled: mega.paywall,
- onClick: () => {
- megaChat.openChatAndSendFilesDialog(contact.u);
- }
- }));
- moreDropdowns.push(react1().createElement(_ui_dropdowns_jsx6__.DropdownItem, {
- key: "share-item",
- icon: "sprite-fm-mono icon-folder-outgoing-share",
- label: l[6775],
- onClick: () => {
- openCopyShareDialog(contact.u);
- }
- }));
- } else if (!is_chatlink && !is_eplusplus && (!contact.c || contact.c === 2 && contact.u !== u_handle)) {
- moreDropdowns.push(react1().createElement(_ui_dropdowns_jsx6__.DropdownItem, {
- key: "view2",
- icon: "sprite-fm-mono icon-add",
- label: l[101],
- onClick: () => {
- const isAnonymousUser = !u_handle || u_type !== 3;
- const ADD_CONTACT = 'addContact';
- if (is_chatlink && isAnonymousUser) {
- megaChat.loginOrRegisterBeforeJoining(undefined, undefined, undefined, true);
- if (localStorage.getItem(ADD_CONTACT) === null) {
- localStorage.setItem(ADD_CONTACT, JSON.stringify({
- u: contact.u,
- unixTime: unixtime()
- }));
- }
- } else {
- loadingDialog.show();
- M.syncContactEmail(contact.u, true).then(email => {
- if (Object.values(M.opc || {}).some(cr => cr.m === email)) {
- closeDialog();
- msgDialog('warningb', '', l[17545]);
- } else {
- M.inviteContact(M.u[u_handle].m, email);
- const title = l[150];
- const msg = l[5898].replace('[X]', email);
- closeDialog();
- msgDialog('info', title, msg.replace('[X]', email));
- }
- }).catch(() => {
- const {
- chatRoom
- } = this.props;
- const {
- u: userHandle
- } = contact;
- if (chatRoom.call) {
- return mBroadcaster.sendMessage('meetings:ephemeralAdd', userHandle);
- }
- const name = M.getNameByHandle(userHandle);
- return msgDialog('info', '', l.ephemeral_title ? l.ephemeral_title.replace('%1', name) : `${name} is using an ephemeral session.`, l.ephemeral_info);
- }).finally(() => loadingDialog.hide());
- }
- }
- }));
- }
- if (u_attr && contact.u !== u_handle) {
- if (moreDropdowns.length > 0 && !(moreDropdowns.length === 2 && moreDropdowns[1] && moreDropdowns[1].key === "fingerprint")) {
- moreDropdowns.push(react1().createElement("hr", {
- key: "nicknames-separator"
- }));
- }
- moreDropdowns.push(react1().createElement(_ui_dropdowns_jsx6__.DropdownItem, {
- key: "set-nickname",
- icon: "sprite-fm-mono icon-rename",
- label: contact.nickname === '' ? l.set_nickname_label : l.edit_nickname_label,
- onClick: () => nicknames.setNicknameDialog.init(contact.u)
- }));
- }
- if (dropdownRemoveButton && dropdownRemoveButton.length) {
- moreDropdowns.push(react1().createElement("hr", {
- key: "remove-separator"
- }));
- moreDropdowns.push(dropdownRemoveButton);
- }
- return moreDropdowns;
- }
- render() {
- let {
- label = '',
- className = '',
- contact,
- dropdownIconClasses = [],
- verticalOffset,
- dropdownDisabled,
- noLoading,
- noContextMenu
- } = this.props;
- let dropdownPosition = "left top";
- let vertOffset = 0;
- let horizOffset = -30;
- if (!contact) {
- return null;
- }
- if (label) {
- className = `user-card-name ${className}${className.includes('message') ? '' : ' selectable-txt'}`;
- dropdownIconClasses = '';
- dropdownPosition = 'left bottom';
- vertOffset = 25;
- horizOffset = 0;
- }
- if (typeof verticalOffset !== 'undefined') {
- vertOffset = verticalOffset;
- }
- if (!contact.name && !contact.m && !noLoading && this.isLoadingContactInfo()) {
- label = react1().createElement("em", {
- className: "contact-name-loading"
- });
- className = `contact-button-loading ${className}`;
- }
- return noContextMenu ? react1().createElement("div", {
- className: "user-card-name light selectable-txt"
- }, label) : react1().createElement(_ui_buttons_jsx5__.$, {
- className,
- icon: dropdownIconClasses,
- disabled: dropdownDisabled,
- label
- }, react1().createElement(_ui_dropdowns_jsx6__.Dropdown, {
- className: "context contact-card-dropdown",
- positionMy: dropdownPosition,
- positionAt: dropdownPosition,
- vertOffset,
- horizOffset,
- dropdownItemGenerator: this.dropdownItemGenerator,
- noArrow: true
- }));
- }
-}
-ContactButton.defaultProps = {
- 'manualDataChangeTracking': true,
- 'skipQueuedUpdatesOnResize': true
-};
-class ContactVerified extends _mixins2__.w9 {
- attachRerenderCallbacks() {
- this.addDataStructListenerForProperties(this.props.contact, ['fingerprint']);
- }
- render() {
- if (is_chatlink) {
- return null;
- }
- const {contact} = this.props;
- if (!contact) {
- return null;
- }
- if (u_authring && u_authring.Ed25519) {
- const verifyState = u_authring.Ed25519[contact.u] || {};
- if (verifyState.method >= authring.AUTHENTICATION_METHOD.FINGERPRINT_COMPARISON) {
- return react1().createElement("div", {
- className: `
- user-card-verified
- ${this.props.className || ''}
- `
- });
- }
- } else if (!pubEd25519[contact.u]) {
- crypt.getPubEd25519(contact.u).then(() => {
- if (pubEd25519[contact.u]) {
- this.safeForceUpdate();
- }
- });
- }
- return null;
- }
-}
-ContactVerified.defaultProps = {
- 'manualDataChangeTracking': true,
- 'skipQueuedUpdatesOnResize': true
-};
-class ContactPresence extends _mixins2__.w9 {
- constructor(...args) {
- super(...args);
- this.domRef = react1().createRef();
- }
- attachRerenderCallbacks() {
- this.addDataStructListenerForProperties(this.props.contact, ['presence']);
- }
- render() {
- const {
- contact,
- className
- } = this.props;
- if (!contact || !contact.c) {
- return null;
- }
- return react1().createElement("div", {
- ref: this.domRef,
- className: `
- user-card-presence
- ${megaChat.userPresenceToCssClass(contact.presence)}
- ${className || ''}
- `
- });
- }
-}
-ContactPresence.defaultProps = {
- manualDataChangeTracking: true,
- skipQueuedUpdatesOnResize: true
-};
-const LastActivity = (0,_mixins2__.Zz)(_updateObserver_jsx10__.Y)((() => class LastActivity extends _mixins2__.u9 {
- attachRerenderCallbacks() {
- this._attachRerenderCbContacts(['ats', 'lastGreen', 'presence']);
- }
- shouldComponentUpdate() {
- return true;
- }
- render() {
- const {
- contact,
- showLastGreen
- } = this.props;
- if (!contact) {
- return null;
- }
- const lastActivity = !contact.ats || contact.lastGreen > contact.ats ? contact.lastGreen : contact.ats;
- const SECONDS = Date.now() / 1000 - lastActivity;
- const timeToLast = SECONDS > 3888000 ? l[20673] : time2last(lastActivity, true);
- const hasActivityStatus = showLastGreen && contact.presence <= 2 && lastActivity;
- return react1().createElement("span", null, hasActivityStatus ? (l[19994] || 'Last seen %s').replace('%s', timeToLast) : M.onlineStatusClass(contact.presence)[0]);
- }
-})());
-class ContactAwareName extends _mixins2__.u9 {
- render() {
- const {
- contact,
- emoji,
- overflow
- } = this.props;
- if (!contact || !M.u[contact.u || contact.h]) {
- return null;
- }
- const name = M.getNameByHandle(contact.u || contact.h);
- if (emoji || overflow) {
- const EmojiComponent = overflow ? _ui_utils_jsx3__.sp : _ui_utils_jsx3__.zT;
- return react1().createElement(EmojiComponent, this.props, name);
- }
- return react1().createElement("span", null, name);
- }
-}
-class MembersAmount extends _mixins2__.u9 {
- render() {
- const {
- chatRoom
- } = this.props;
- return react1().createElement("span", null, mega.icu.format(l[20233], Object.keys(chatRoom.members).length));
- }
-}
-class ContactFingerprint extends _mixins2__.w9 {
- constructor(...args) {
- super(...args);
- this.domRef = react1().createRef();
- }
- attachRerenderCallbacks() {
- this.addDataStructListenerForProperties(this.props.contact, ['fingerprint']);
- }
- render() {
- const {
- contact,
- className
- } = this.props;
- if (!contact || !contact.u || is_chatlink) {
- return null;
- }
- const infoBlocks = [];
- userFingerprint(contact.u, (fingerprints) => {
- fingerprints.forEach((v, k) => {
- infoBlocks.push(react1().createElement("span", {
- key: `fingerprint-${ k}`
- }, v));
- });
- });
- let verifyButton = null;
- if (contact.c === 1 && u_authring && u_authring.Ed25519) {
- const verifyState = u_authring.Ed25519[contact.u] || {};
- if (typeof verifyState.method === "undefined" || verifyState.method < authring.AUTHENTICATION_METHOD.FINGERPRINT_COMPARISON) {
- verifyButton = react1().createElement(_ui_buttons_jsx5__.$, {
- className: "dropdown-verify active",
- label: l.verify_credentials,
- icon: "sprite-fm-mono icon-key",
- onClick: () => {
- closeDropdowns();
- fingerprintDialog(contact.u);
- }
- });
- }
- }
- return infoBlocks.length ? react1().createElement("div", {
- ref: this.domRef,
- className: `
- dropdown-fingerprint
- ${className || ''}
- `
- }, react1().createElement("div", {
- className: "contact-fingerprint-title"
- }, react1().createElement("span", null, l[6872])), react1().createElement("div", {
- className: "contact-fingerprint-txt selectable-txt"
- }, infoBlocks), verifyButton) : null;
- }
-}
-ContactFingerprint.defaultProps = {
- 'manualDataChangeTracking': true,
- 'skipQueuedUpdatesOnResize': true
-};
-class Avatar extends _mixins2__.u9 {
- render() {
- const self = this;
- const {contact} = this.props;
- if (!contact) {
- return null;
- }
- if (!contact.m && contact.email) {
- contact.m = contact.email;
- }
- const avatarMeta = useravatar.generateContactAvatarMeta(contact);
- let classes = `${this.props.className ? this.props.className : ' avatar-wrapper small-rounded-avatar' } ${ contact.u } in-chat`;
- classes += " chat-avatar";
- let displayedAvatar;
- let verifiedElement = null;
- if (!this.props.hideVerifiedBadge && !is_chatlink) {
- verifiedElement = react1().createElement(ContactVerified, {
- contact: this.props.contact,
- className: this.props.verifiedClassName
- });
- }
- const extraProps = {};
- if (this.props.simpletip) {
- classes += " simpletip";
- if (this.props.simpletip === true) {
- extraProps['data-simpletip'] = M.getNameByHandle(contact.h || contact.u) || megaChat.plugins.userHelper.SIMPLETIP_USER_LOADER;
- } else {
- extraProps['data-simpletip'] = this.props.simpletip;
- }
- if (this.props.simpletipWrapper) {
- extraProps['data-simpletipwrapper'] = this.props.simpletipWrapper;
- }
- if (this.props.simpletipOffset) {
- extraProps['data-simpletipoffset'] = this.props.simpletipOffset;
- }
- if (this.props.simpletipPosition) {
- extraProps['data-simpletipposition'] = this.props.simpletipPosition;
- }
- if (this.props.simpletipClass) {
- extraProps['data-simpletip-class'] = this.props.simpletipClass;
- }
- }
- if (avatarMeta.type === "image") {
- displayedAvatar = react1().createElement("div", (0,_extends0__.A)({
- className: classes,
- style: this.props.style
- }, extraProps, {
- onClick: self.props.onClick ? e => {
- closeDropdowns();
- self.props.onClick(e);
- } : self.onClick
- }), verifiedElement, react1().createElement("img", {
- src: avatarMeta.avatar,
- style: this.props.imgStyles
- }));
- } else {
- classes += ` color${ avatarMeta.avatar.colorIndex}`;
- const isLoading = self.isLoadingContactInfo();
- if (isLoading) {
- classes += " default-bg";
- }
- displayedAvatar = react1().createElement("div", (0,_extends0__.A)({
- className: classes,
- style: this.props.style
- }, extraProps, {
- onClick: self.props.onClick ? e => {
- closeDropdowns();
- self.props.onClick(e);
- } : self.onClick
- }), verifiedElement, react1().createElement("span", null, isLoading ? "" : avatarMeta.avatar.letters));
- }
- return displayedAvatar;
- }
-}
-Avatar.defaultProps = {
- 'manualDataChangeTracking': true,
- 'skipQueuedUpdatesOnResize': true
-};
-class ContactCard extends _mixins2__.u9 {
- attachRerenderCallbacks() {
- this._attachRerenderCbContacts(['presence']);
- }
- specShouldComponentUpdate(nextProps, nextState) {
- const foundKeys = Object.keys(this.props);
- if (foundKeys.includes('dropdowns')) {
- array.remove(foundKeys, 'dropdowns', true);
- }
- let shouldUpdate;
- if (foundKeys.length) {
- const k = foundKeys[0];
- shouldUpdate = shallowEqual(nextProps[k], this.props[k]);
- }
- if (!shouldUpdate) {
- shouldUpdate = shallowEqual(nextState, this.state);
- }
- if (!shouldUpdate && this.state.props.dropdowns && nextProps.state.dropdowns && this.state.props.dropdowns.map && nextProps.state.dropdowns.map) {
- const oldKeys = this.state.props.dropdowns.map(child => child.key);
- const newKeys = nextProps.state.dropdowns.map(child => child.key);
- if (!shallowEqual(oldKeys, newKeys)) {
- shouldUpdate = true;
- }
- }
- return shouldUpdate;
- }
- render() {
- let _this$props$chatRoom;
- const {
- contact
- } = this.props;
- if (!contact) {
- return null;
- }
- const pres = megaChat.userPresenceToCssClass(contact.presence);
- let username = (this.props.namePrefix || '') + (M.getNameByHandle(contact.u) || contact.m);
- if (contact.u === u_handle) {
- username += ` (${escapeHTML(l[8885])})`;
- }
- let escapedUsername = react1().createElement(_ui_utils_jsx3__.sp, null, username);
- const dropdowns = this.props.dropdowns || [];
- const noContextMenu = this.props.noContextMenu || '';
- const noContextButton = this.props.noContextButton || '';
- const dropdownRemoveButton = this.props.dropdownRemoveButton || [];
- const highlightSearchValue = this.props.highlightSearchValue || false;
- const emailTooltips = this.props.emailTooltips || false;
- const searchValue = this.props.searchValue || "";
- let usernameBlock;
- if (!noContextMenu) {
- usernameBlock = react1().createElement(ContactButton, {
- key: "lnk",
- dropdowns,
- noContextMenu,
- contact,
- className: "light",
- label: escapedUsername,
- chatRoom: this.props.chatRoom,
- dropdownRemoveButton,
- verticalOffset: 0
- });
- } else {
- if (highlightSearchValue && searchValue.length > 0) {
- const matches = [];
- const regex = new RegExp(RegExpEscape(searchValue), 'gi');
- let result;
- while (result = regex.exec(username)) {
- matches.push({
- idx: result.index,
- str: result[0]
- });
- }
- if (matches.length > 0) {
- escapedUsername = react1().createElement(_ui_utils_jsx3__.P9, null, megaChat.highlight(megaChat.html(username), matches, true));
- }
- }
- usernameBlock = emailTooltips ? react1().createElement("div", {
- className: "user-card-name light simpletip selectable-txt",
- "data-simpletip": contact.m,
- "data-simpletipposition": "top"
- }, escapedUsername) : react1().createElement("div", {
- className: "user-card-name light selectable-txt"
- }, escapedUsername);
- }
- let userCard = null;
- const className = this.props.className || '';
- userCard = className.includes('short') ? react1().createElement("div", {
- className: "user-card-data"
- }, usernameBlock, react1().createElement("div", {
- className: "user-card-status"
- }, this.props.isInCall ? react1().createElement("div", {
- className: "audio-call"
- }, react1().createElement("i", {
- className: "sprite-fm-mono icon-phone"
- })) : null, react1().createElement(LastActivity, {
- contact,
- showLastGreen: this.props.showLastGreen
- }))) : react1().createElement("div", {
- className: "user-card-data"
- }, usernameBlock, react1().createElement(ContactPresence, {
- contact,
- className: this.props.presenceClassName
- }), this.props.isInCall ? react1().createElement("div", {
- className: "audio-call"
- }, react1().createElement("i", {
- className: "sprite-fm-mono icon-phone"
- })) : null, react1().createElement("div", {
- className: "user-card-email selectable-txt"
- }, contact.m));
- return react1().createElement("div", {
- className: `
- contacts-info body
- ${pres === 'offline' ? 'offline' : ''}
- ${className || ''}
- `,
- style: this.props.style,
- onClick: ev => {
- let _this$props$onClick, _this$props;
- return (_this$props$onClick = (_this$props = this.props).onClick) == null ? void 0 : _this$props$onClick.call(_this$props, contact, ev);
- },
- onDoubleClick: ev => {
- let _this$props$onDoubleC, _this$props2;
- return (_this$props$onDoubleC = (_this$props2 = this.props).onDoubleClick) == null ? void 0 : _this$props$onDoubleC.call(_this$props2, contact, ev);
- }
- }, this.props.withSelfNote ? react1().createElement("div", {
- className: `
- note-chat-signifier
- ${(_this$props$chatRoom = this.props.chatRoom) != null && _this$props$chatRoom.hasMessages() ? '' : 'note-chat-empty'}
- `
- }, react1().createElement("i", {
- className: "sprite-fm-mono icon-file-text-thin-outline note-chat-icon"
- })) : react1().createElement(Avatar, {
- className: "avatar-wrapper small-rounded-avatar",
- contact,
- chatRoom: this.props.chatRoom
- }), is_chatlink || noContextButton ? null : react1().createElement(ContactButton, {
- key: "button",
- dropdowns,
- dropdownIconClasses: this.props.dropdownIconClasses || '',
- disabled: this.props.dropdownDisabled,
- noContextMenu,
- contact,
- className: this.props.dropdownButtonClasses,
- dropdownRemoveButton,
- noLoading: this.props.noLoading,
- chatRoom: this.props.chatRoom,
- verticalOffset: 0
- }), this.props.selectable ? react1().createElement("div", {
- className: "user-card-tick-wrap"
- }, react1().createElement("i", {
- className: "sprite-fm-mono icon-check"
- })) : null, megaChat.WITH_SELF_NOTE && this.props.withSelfNote ? react1().createElement("div", {
- className: "user-card-data"
- }, react1().createElement("div", {
- className: "user-card-name light selectable-txt note-chat-label"
- }, l.note_label), react1().createElement("div", {
- className: "user-card-status"
- })) : userCard);
- }
-}
-ContactCard.defaultProps = {
- dropdownButtonClasses: "tiny-button",
- dropdownIconClasses: "tiny-icon icons-sprite grey-dots",
- presenceClassName: '',
- manualDataChangeTracking: true,
- skipQueuedUpdatesOnResize: true
-};
-class ContactItem extends _mixins2__.u9 {
- render() {
- const self = this;
- const {contact} = this.props;
- if (!contact) {
- return null;
- }
- const username = this.props.namePrefix ? this.props.namePrefix : `${ M.getNameByHandle(contact.u)}`;
- return react1().createElement("div", {
- className: "selected-contact-card short"
- }, react1().createElement("div", {
- className: "remove-contact-bttn",
- onClick: e => {
- if (self.props.onClick) {
- self.props.onClick(contact, e);
- }
- }
- }, react1().createElement("i", {
- className: "tiny-icon small-cross"
- })), react1().createElement(Avatar, {
- contact,
- className: "avatar-wrapper small-rounded-avatar",
- hideVerifiedBadge: true,
- chatRoom: this.props.chatRoom
- }), react1().createElement("div", {
- className: "user-card-data simpletip",
- "data-simpletip": username || megaChat.plugins.userHelper.SIMPLETIP_USER_LOADER,
- "data-simpletipposition": "top"
- }, react1().createElement(ContactButton, {
- noContextMenu: this.props.noContextMenu,
- contact,
- className: "light",
- label: react1().createElement(_ui_utils_jsx3__.zT, null, username),
- chatRoom: this.props.chatRoom
- })));
- }
-}
-ContactItem.defaultProps = {
- 'manualDataChangeTracking': true,
- 'skipQueuedUpdatesOnResize': true
-};
-class ContactPickerWidget extends _mixins2__.w9 {
- constructor(...args) {
- super(...args);
- this.contactLinkListener = null;
- this.domRef = react1().createRef();
- this.state = {
- searchValue: '',
- selected: this.props.selected || [],
- publicLink: M.account && M.account.contactLink || undefined
- };
- this.normalize = input => ChatSearch._normalize_str(String(input || '').toLowerCase());
- this.onSearchChange = ev => {
- this.setState({
- searchValue: ev.target.value
- });
- };
- this.renderParticipantsList = () => {
- const {
- contacts,
- emailTooltips,
- onSelected
- } = this.props;
- const {
- selected
- } = this.state;
- const $$list = contacts.map(handle => {
- const added = selected.includes(handle);
- return react1().createElement(ContactCard, {
- key: handle,
- className: `
- contacts-search short
- ${added ? 'selected' : ''}
- `,
- contact: M.u[handle],
- selectable: true,
- emailTooltips,
- noContextButton: true,
- noContextMenu: true,
- onClick: () => {
- this.setState({
- selected: added ? selected.filter(h => h !== handle) : [...selected, handle]
- }, () => onSelected(this.state.selected));
- }
- });
- });
- return react1().createElement(_ui_perfectScrollbar_jsx4__.O, {
- className: "contacts-search-scroll",
- selected,
- contacts
- }, react1().createElement("div", {
- className: "contacts-search-subsection"
- }, react1().createElement("div", {
- className: "contacts-list-header"
- }, megaChat.activeCall ? l.call_participants : l[16217]), react1().createElement("div", {
- className: "contacts-search-list"
- }, $$list)));
- };
- }
- renderInviteWarning() {
- const {
- chatRoom
- } = this.props;
- const {
- activeCall
- } = megaChat;
- if (!activeCall || activeCall.chatRoom.chatId !== chatRoom.chatId || !activeCall.sfuClient.callLimits || !activeCall.sfuClient.callLimits.usr || chatRoom.getCallParticipants().length < activeCall.sfuClient.callLimits.usr) {
- return null;
- }
- return react1().createElement("div", {
- className: "picker-user-limit-banner"
- }, activeCall.organiser === u_handle ? (0,_ui_utils_jsx3__.lI)(l.invite_limit_banner_organiser, '[A]', _link_jsx9__.A, {
- onClick() {
- window.open(`${getBaseUrl()}/pro`, '_blank', 'noopener,noreferrer');
- eventlog(500263);
- }
- }) : l.invite_limit_banner_host);
- }
- componentDidMount() {
- super.componentDidMount();
- setContactLink(this.domRef && this.domRef.current);
- this.contactLinkListener = mBroadcaster.addListener('contact:setContactLink', publicLink => this.state.publicLink ? null : this.setState({
- publicLink
- }));
- }
- componentDidUpdate() {
- const self = this;
- if (self.scrollToLastSelected && self.psSelected) {
- self.scrollToLastSelected = false;
- self.psSelected.scrollToPercentX(100, false);
- }
- if (self.searchContactsScroll) {
- self.searchContactsScroll.reinitialise();
- }
- }
- UNSAFE_componentWillMount() {
- if (super.UNSAFE_componentWillMount) {
- super.UNSAFE_componentWillMount();
- }
- const self = this;
- if (self.props.multiple) {
- $(document.body).rebind(`keypress.contactPicker${ self.getUniqueId()}`, (e) => {
- const keyCode = e.which || e.keyCode;
- if (keyCode === 13) {
- if (self.state.selected) {
- e.preventDefault();
- e.stopPropagation();
- closeDropdowns();
- if (self.props.onSelectDone) {
- self.props.onSelectDone(self.state.selected);
- }
- }
- }
- });
- }
- }
- componentWillUnmount() {
- super.componentWillUnmount();
- const self = this;
- delete self._foundFrequents;
- if (self.props.multiple) {
- $(document.body).off(`keypress.contactPicker${ self.getUniqueId()}`);
- }
- if (this.contactLinkListener) {
- mBroadcaster.removeListener(this.contactLinkListener);
- }
- }
- _eventuallyAddContact(v, contacts, selectableContacts, forced) {
- const self = this;
- const withSelfNote = this.props.withSelfNote && v.u === u_handle;
- if (v.u === u_handle && !this.props.step && !withSelfNote) {
- return false;
- }
- if (!forced && v.c !== 1 && v.u !== u_handle) {
- return false;
- }
- if (self.props.exclude && self.props.exclude.indexOf(v.u) > -1) {
- return false;
- }
- let isDisabled = false;
- if (!self.wasMissingKeysForContacts) {
- self.wasMissingKeysForContacts = {};
- }
- if (!self.wasMissingKeysForContacts[v.u] && (!pubCu25519[v.u] || !pubEd25519[v.u])) {
- self.wasMissingKeysForContacts[v.u] = true;
- ChatdIntegration._ensureKeysAreLoaded(undefined, [v.u]).always(() => {
- if (self.isMounted()) {
- self.safeForceUpdate();
- }
- });
- isDisabled = true;
- return true;
- } else if (self.wasMissingKeysForContacts[v.u] && (!pubCu25519[v.u] || !pubEd25519[v.u])) {
- return false;
- }
- if (self.state.searchValue && self.state.searchValue.length > 0) {
- const searchValue = this.normalize(this.state.searchValue);
- const {
- name,
- nickname,
- fullname,
- u,
- m
- } = {
- ...v,
- name: withSelfNote ? l.note_label : v.name
- };
- const matches = [name, nickname, fullname, M.getNameByHandle(u), !this.props.skipMailSearch && m].some(field => this.normalize(field).includes(searchValue));
- if (!matches) {
- return false;
- }
- }
- let selectedClass = "";
- if (self.state.selected && self.state.selected.indexOf(v.u) !== -1) {
- selectedClass = "selected";
- }
- contacts.push(react1().createElement(ContactCard, {
- withSelfNote,
- disabled: isDisabled,
- contact: v,
- chatRoom: withSelfNote && megaChat.getNoteChat(),
- className: `contacts-search short ${ selectedClass }${isDisabled ? " disabled" : ""}`,
- noContextButton: "true",
- selectable: selectableContacts,
- onClick: self.props.readOnly ? () => {} : contact => {
- if (isDisabled) {
- return false;
- }
- const contactHash = contact.u;
- if (contactHash === self.lastClicked && new Date() - self.clickTime < 500 && !self.props.disableDoubleClick || !self.props.multiple) {
- if (self.props.onSelected) {
- self.props.onSelected([contactHash]);
- }
- self.props.onSelectDone([contactHash]);
- closeDropdowns();
- return;
- } else {
- const selected = clone(self.state.selected || []);
- if (selected.indexOf(contactHash) === -1) {
- selected.push(contactHash);
- self.scrollToLastSelected = true;
- if (self.props.onSelected) {
- self.props.onSelected(selected);
- }
- } else {
- if (selected.indexOf(contactHash) >= 0) {
- array.remove(selected, contactHash);
- }
- if (self.props.onSelected) {
- self.props.onSelected(selected);
- }
- }
- self.setState({
- selected
- });
- if (self.props.selectCleanSearchRes) {
- self.setState({
- 'searchValue': ''
- });
- }
- if (self.props.autoFocusSearchField) {
- let _self$contactSearchFi;
- (_self$contactSearchFi = self.contactSearchField) == null || _self$contactSearchFi.focus();
- }
- }
- self.clickTime = new Date();
- self.lastClicked = contactHash;
- },
- noContextMenu: true,
- searchValue: self.state.searchValue,
- highlightSearchValue: self.props.highlightSearchValue,
- emailTooltips: self.props.emailTooltips,
- key: v.u
- }));
- if (typeof this.props.onEventuallyUpdated === 'function') {
- this.props.onEventuallyUpdated();
- }
- return true;
- }
- render() {
- const self = this;
- let contacts = [];
- const frequentContacts = [];
- let extraClasses = "";
- const contactsSelected = [];
- let multipleContacts = null;
- let selectableContacts = false;
- let selectFooter = null;
- let selectedContacts = false;
- const isSearching = !!self.state.searchValue;
- megaChat.getNoteChat();
- const onAddContact = e => {
- e.preventDefault();
- e.stopPropagation();
- contactAddDialog();
- if (this.props.onClose) {
- this.props.onClose();
- }
- };
- if (self.props.readOnly) {
- const sel = self.state.selected || [];
- for (let i = 0; i < sel.length; i++) {
- const v = sel[i];
- contactsSelected.push(react1().createElement(ContactItem, {
- contact: M.u[v],
- key: v,
- chatRoom: self.props.chatRoom
- }));
- }
- } else if (self.props.multiple) {
- selectableContacts = true;
- const onSelectDoneCb = e => {
- e.preventDefault();
- e.stopPropagation();
- closeDropdowns();
- if (self.props.onSelectDone) {
- self.props.onSelectDone(self.state.selected);
- }
- };
- let onContactSelectDoneCb = contact => {
- const contactHash = contact.u;
- if (contactHash === self.lastClicked && new Date() - self.clickTime < 500) {
- if (self.props.onSelected) {
- self.props.onSelected([contactHash]);
- }
- self.props.onSelectDone([contactHash]);
- return;
- } else {
- const selected = clone(self.state.selected || []);
- if (selected.indexOf(contactHash) === -1) {
- selected.push(contactHash);
- self.scrollToLastSelected = true;
- if (self.props.onSelected) {
- self.props.onSelected(selected);
- }
- } else {
- if (selected.indexOf(contactHash) >= 0) {
- array.remove(selected, contactHash);
- }
- if (self.props.onSelected) {
- self.props.onSelected(selected);
- }
- }
- self.setState({
- selected
- });
- if (self.props.selectCleanSearchRes) {
- self.setState({
- 'searchValue': ''
- });
- }
- if (self.props.autoFocusSearchField) {
- let _self$contactSearchFi2;
- (_self$contactSearchFi2 = self.contactSearchField) == null || _self$contactSearchFi2.focus();
- }
- }
- self.clickTime = new Date();
- self.lastClicked = contactHash;
- };
- const selectedWidthSize = self.props.selectedWidthSize || 54;
- const selectedWidth = self.state.selected.length * selectedWidthSize;
- if (!self.state.selected || self.state.selected.length === 0) {
- selectedContacts = false;
- const emptySelectionMsg = self.props.emptySelectionMsg || l[8889];
- multipleContacts = react1().createElement("div", {
- className: "horizontal-contacts-list"
- }, react1().createElement("div", {
- className: "contacts-list-empty-txt"
- }, self.props.nothingSelectedButtonLabel ? self.props.nothingSelectedButtonLabel : emptySelectionMsg));
- } else {
- selectedContacts = true;
- onContactSelectDoneCb = onContactSelectDoneCb.bind(self);
- const sel2 = self.state.selected || [];
- for (let i2 = 0; i2 < sel2.length; i2++) {
- const v2 = sel2[i2];
- contactsSelected.push(react1().createElement(ContactItem, {
- key: v2,
- chatRoom: self.props.chatRoom || false,
- contact: M.u[v2],
- noContextMenu: true,
- onClick: onContactSelectDoneCb
- }));
- }
- multipleContacts = react1().createElement("div", {
- className: "horizontal-contacts-list"
- }, react1().createElement(_ui_perfectScrollbar_jsx4__.O, {
- className: "perfectScrollbarContainer selected-contact-block horizontal-only",
- selected: this.state.selected,
- ref (psSelected) {
- self.psSelected = psSelected;
- }
- }, react1().createElement("div", {
- className: "select-contact-centre",
- style: {
- width: selectedWidth
- }
- }, contactsSelected)));
- }
- if (self.props.selectFooter) {
- selectFooter = react1().createElement("footer", null, react1().createElement("button", {
- className: "mega-button",
- onClick: onAddContact.bind(self)
- }, react1().createElement("span", null, l[71])), react1().createElement("div", {
- className: "footer-spacing"
- }), react1().createElement("button", {
- className: `mega-button ${selectedContacts ? '' : 'disabled'}`,
- onClick (e) {
- if (self.state.selected.length > 0) {
- onSelectDoneCb(e);
- }
- }
- }, react1().createElement("span", null, this.props.multipleSelectedButtonLabel ? this.props.multipleSelectedButtonLabel : l[8890])));
- }
- }
- const alreadyAdded = {};
- let hideFrequents = !self.props.readOnly && !self.state.searchValue && frequentContacts.length > 0;
- let frequentsLoading = false;
- if (this.props.readOnly || this.props.disableFrequents) {
- hideFrequents = true;
- this._foundFrequents = [];
- } else if (!self._foundFrequents) {
- frequentsLoading = true;
- this._foundFrequents = [];
- megaChat.getFrequentContacts().then(res => {
- this._foundFrequents = res.slice(Math.max(res.length - 30, 0), res.length).reverse();
- }).catch(dump).finally(() => {
- if (this.isMounted()) {
- this.safeForceUpdate();
- }
- });
- }
- for (let i = this._foundFrequents.length, total = 0; total < MAX_FREQUENTS && i--;) {
- const v = this._foundFrequents[i];
- if (v.userId in M.u && this._eventuallyAddContact(M.u[v.userId], frequentContacts, selectableContacts)) {
- alreadyAdded[v.userId] = 1;
- total++;
- }
- }
- self.props.contacts.forEach((v) => {
- alreadyAdded[v.h] || self._eventuallyAddContact(v, contacts, selectableContacts);
- });
- const sortFn = M.getSortByNameFn2(1);
- contacts.sort((a, b) => {
- return b.props.withSelfNote - a.props.withSelfNote || sortFn(a.props.contact, b.props.contact);
- });
- if (Object.keys(alreadyAdded).length === 0) {
- hideFrequents = true;
- }
- const innerDivStyles = {};
- if (this.props.showMeAsSelected) {
- self._eventuallyAddContact(M.u[u_handle], contacts, selectableContacts, true);
- }
- let noOtherContacts = false;
- if (contacts.length === 0 || !_contactsPanel_contactsPanel_jsx7__.A.hasContacts() && this.props.step !== 1) {
- noOtherContacts = true;
- let noContactsMsg = "";
- if (M.u.length < 2) {
- noContactsMsg = l[8877];
- } else {
- noContactsMsg = l[8878];
- }
- if (hideFrequents) {
- contacts = react1().createElement("em", null, noContactsMsg);
- }
- }
- const haveContacts = isSearching || frequentContacts.length !== 0 || !noOtherContacts;
- let contactsList;
- if (haveContacts) {
- if (frequentContacts.length === 0 && noOtherContacts) {
- if (self.props.newEmptySearchResult) {
- contactsList = react1().createElement("div", {
- className: "chat-contactspicker-no-contacts flex flex-column flex-center searching mt-2"
- }, react1().createElement("div", {
- className: "section-icon sprite-fm-mono icon-contacts"
- }), react1().createElement("div", {
- className: "fm-empty-cloud-txt small"
- }, l[8674]));
- } else {
- contactsList = react1().createElement("div", {
- className: "chat-contactspicker-no-contacts flex flex-column mt-2"
- }, react1().createElement("div", {
- className: "contacts-list-header"
- }, l[165]), react1().createElement("div", {
- className: "flex flex-1 flex-column flex-center"
- }, react1().createElement("div", {
- className: "section-icon sprite-fm-mono icon-contacts"
- }), react1().createElement("div", {
- className: "fm-empty-cloud-txt small"
- }, l[784]), react1().createElement("div", {
- className: "fm-empty-description small"
- }, l[19115])));
- }
- } else {
- contactsList = react1().createElement(_ui_perfectScrollbar_jsx4__.O, {
- ref: ref => {
- self.searchContactsScroll = ref;
- },
- className: "contacts-search-scroll",
- selected: this.state.selected,
- changedHashProp: this.props.changedHashProp,
- contacts,
- frequentContacts,
- searchValue: this.state.searchValue
- }, react1().createElement(react1().Fragment, null, react1().createElement("div", {
- className: "contacts-search-subsection",
- style: {
- display: hideFrequents ? 'none' : ''
- }
- }, react1().createElement("div", {
- className: "contacts-list-header"
- }, l[20141]), frequentsLoading ? react1().createElement("div", {
- className: "loading-spinner"
- }, "...") : react1().createElement("div", {
- className: "contacts-search-list",
- style: innerDivStyles
- }, frequentContacts)), contacts.length > 0 ? react1().createElement("div", {
- className: "contacts-search-subsection"
- }, react1().createElement("div", {
- className: "contacts-list-header"
- }, frequentContacts && frequentContacts.length === 0 ? this.props.readOnly ? l[16217] : l[165] : l[165]), react1().createElement("div", {
- className: "contacts-search-list",
- style: innerDivStyles
- }, contacts)) : null));
- }
- } else if (self.props.newNoContact) {
- multipleContacts = "";
- contactsList = react1().createElement("div", {
- className: "chat-contactspicker-no-contacts flex flex-column flex-center mt-2"
- }, react1().createElement("div", {
- className: "section-icon sprite-fm-mono icon-contacts"
- }), react1().createElement("div", {
- className: "fm-empty-cloud-txt small"
- }, l[784]), react1().createElement("div", {
- className: "fm-empty-description small"
- }, l[19115]));
- extraClasses += " no-contacts";
- } else {
- contactsList = react1().createElement("div", {
- className: "chat-contactspicker-no-contacts flex flex-column flex-center mt-16"
- }, react1().createElement("div", {
- className: "section-icon sprite-fm-mono icon-contacts"
- }), react1().createElement("div", {
- className: "fm-empty-cloud-txt small"
- }, l[784]), react1().createElement("div", {
- className: "fm-empty-description small"
- }, l[19115]), react1().createElement("button", {
- className: "mega-button positive large fm-empty-button",
- onClick: () => {
- contactAddDialog();
- self.props.onClose == null || self.props.onClose();
- }
- }, react1().createElement("span", null, l[101])), react1().createElement("div", {
- className: `
- ${this.state.publicLink ? '' : 'loading'}
- empty-share-public
- `
- }, react1().createElement("i", {
- className: "sprite-fm-mono icon-link-circle"
- }), react1().createElement(_ui_utils_jsx3__.P9, null, l[19111])));
- extraClasses += " no-contacts";
- }
- const totalContactsNum = contacts.length + frequentContacts.length;
- const searchPlaceholderMsg = mega.icu.format(l.search_contact_placeholder, totalContactsNum);
- return react1().createElement("div", {
- ref: this.domRef,
- className: `
- ${this.props.className || ''}
- ${extraClasses}
- `
- }, this.props.topButtons && react1().createElement("div", {
- className: "contacts-search-buttons"
- }, this.props.topButtons.map(button => {
- const {
- key,
- icon,
- className,
- title,
- onClick
- } = button || {};
- return react1().createElement("div", {
- key,
- className: "button-wrapper",
- onClick: e => {
- closeDropdowns();
- onClick(e);
- }
- }, react1().createElement(_ui_buttons_jsx5__.$, {
- className: `
- ${className || ''}
- ${key === 'newChatLink' ? 'branded-blue' : ''}
- mega-button
- `,
- icon,
- label: title
- }));
- })), multipleContacts, !this.props.readOnly && haveContacts && !this.props.hideSearch && react1().createElement(react1().Fragment, null, react1().createElement("div", {
- className: `
- contacts-search-header
- ${this.props.headerClasses}
- `
- }, react1().createElement("i", {
- className: "sprite-fm-mono icon-preview-reveal"
- }), react1().createElement("input", {
- autoFocus: true,
- type: "search",
- placeholder: searchPlaceholderMsg,
- ref: nodeRef => {
- this.contactSearchField = nodeRef;
- },
- onChange: this.onSearchChange,
- value: this.state.searchValue
- }), react1().createElement("div", {
- className: `
- search-result-clear
- ${this.state.searchValue && this.state.searchValue.length > 0 ? '' : 'hidden'}
- `,
- onClick: () => {
- this.setState({
- searchValue: ''
- }, () => {
- let _this$contactSearchFi;
- return (_this$contactSearchFi = this.contactSearchField) == null ? void 0 : _this$contactSearchFi.focus();
- });
- }
- }, react1().createElement("i", {
- className: "sprite-fm-mono icon-close-component"
- })))), this.props.inviteWarningLabel && this.props.chatRoom && this.renderInviteWarning(), !this.props.readOnly && haveContacts && !this.props.hideSearch && react1().createElement("div", {
- className: "contacts-search-header-separator"
- }), this.props.participantsList ? this.renderParticipantsList() : contactsList, selectFooter, this.props.showAddContact && _contactsPanel_contactsPanel_jsx7__.A.hasContacts() ? react1().createElement("div", {
- className: "contacts-search-bottom"
- }, react1().createElement(_ui_buttons_jsx5__.$, {
- className: "mega-button action positive",
- icon: "sprite-fm-mono icon-add-circle",
- label: l[71],
- onClick: () => {
- let _this$props$onAddCont, _this$props3;
- contactAddDialog();
- closeDropdowns();
- (_this$props$onAddCont = (_this$props3 = this.props).onAddContact) == null || _this$props$onAddCont.call(_this$props3);
- }
- })) : null);
- }
-}
-ContactPickerWidget.defaultProps = {
- multipleSelectedButtonLabel: false,
- singleSelectedButtonLabel: false,
- nothingSelectedButtonLabel: false,
- allowEmpty: false,
- disableFrequents: false,
- skipMailSearch: false,
- autoFocusSearchField: true,
- selectCleanSearchRes: true,
- disableDoubleClick: false,
- newEmptySearchResult: false,
- newNoContact: false,
- emailTooltips: false
-};
-class ContactPickerDialog extends _mixins2__.w9 {
- constructor(...args) {
- super(...args);
- this.dialogName = 'contact-picker-dialog';
- }
- componentDidMount() {
- super.componentDidMount();
- M.safeShowDialog(this.dialogName, () => $(`.${this.dialogName}`));
- }
- componentWillUnmount() {
- super.componentWillUnmount();
- if ($.dialog === this.dialogName) {
- closeDialog();
- }
- }
- render() {
- const {
- active,
- allowEmpty,
- className,
- exclude,
- megaChat,
- multiple,
- multipleSelectedButtonLabel,
- name,
- nothingSelectedButtonLabel,
- selectFooter,
- singleSelectedButtonLabel,
- inviteWarningLabel,
- chatRoom,
- onClose,
- onSelectDone
- } = this.props;
- return react1().createElement(_ui_modalDialogs8__.A.ModalDialog, {
- name,
- className: `
- ${className}
- ${this.dialogName}
- contacts-search
- `,
- onClose
- }, react1().createElement(ContactPickerWidget, {
- active,
- allowEmpty,
- className: "popup contacts-search small-footer",
- contacts: M.u,
- exclude,
- megaChat,
- multiple,
- multipleSelectedButtonLabel,
- nothingSelectedButtonLabel,
- selectFooter,
- singleSelectedButtonLabel,
- inviteWarningLabel,
- chatRoom,
- onClose,
- onSelectDone
- }));
- }
-}
-
-},
-
-173
-(_, EXP_, REQ_) {
-
-"use strict";
-
-// EXPORTS
-REQ_.d(EXP_, {
- A: () => ContactsPanel
-});
-
-// EXTERNAL MODULE: external "React"
-const React_ = REQ_(594);
-const REaCt = REQ_.n(React_);
-// EXTERNAL MODULE: ./js/chat/mixins.js
-const mixins = REQ_(137);
-// EXTERNAL MODULE: ./js/ui/buttons.jsx
-const buttons = REQ_(994);
-;// ./js/chat/ui/contactsPanel/navigation.jsx
-
-
-
-const Navigation = ({
- view,
- receivedRequestsCount
-}) => {
- const {
- VIEW,
- LABEL
- } = ContactsPanel;
- return REaCt().createElement("div", {
- className: "contacts-navigation"
- }, REaCt().createElement("ul", null, Object.keys(VIEW).map(key => {
- let activeClass = view === VIEW[key] ? 'active' : '';
- if (view === VIEW.PROFILE && VIEW[key] === VIEW.CONTACTS) {
- activeClass = 'active';
- }
- if (VIEW[key] !== VIEW.PROFILE) {
- return REaCt().createElement("li", {
- key,
- onClick: () => {
- let page = key.toLowerCase().split("_")[0];
- page = page === 'contacts' ? '' : page;
- loadSubPage(`fm/chat/contacts/${page}`);
- }
- }, REaCt().createElement(buttons.$, {
- className: `
- mega-button
- action
- ${activeClass}
- `,
- receivedRequestsCount
- }, REaCt().createElement("span", null, LABEL[key]), receivedRequestsCount > 0 && VIEW[key] === VIEW.RECEIVED_REQUESTS && REaCt().createElement("div", {
- className: "notifications-count"
- }, receivedRequestsCount > 9 ? '9+' : receivedRequestsCount)));
- }
- return null;
- })));
-};
-const navigation = Navigation;
-// EXTERNAL MODULE: ./js/ui/utils.jsx
-const utils = REQ_(314);
-;// ./js/chat/ui/contactsPanel/nil.jsx
-
-
-
-class Nil extends REaCt().Component {
- componentDidMount() {
- setContactLink();
- }
- render() {
- const {
- title
- } = this.props;
- return REaCt().createElement("div", {
- className: "fm-empty-section fm-empty-contacts"
- }, REaCt().createElement("div", {
- className: "fm-empty-pad"
- }, REaCt().createElement("i", {
- className: "section-icon sprite-fm-mono icon-contacts"
- }), REaCt().createElement("div", {
- className: "fm-empty-cloud-txt"
- }, title), REaCt().createElement("div", {
- className: "fm-empty-description"
- }, l[19115]), REaCt().createElement(buttons.$, {
- className: "mega-button positive large fm-empty-button",
- onClick: () => contactAddDialog()
- }, REaCt().createElement("span", null, l[71])), REaCt().createElement("div", {
- className: "empty-share-public"
- }, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-link-circle"
- }), REaCt().createElement(utils.P9, null, l[19111]))));
- }
-}
-// EXTERNAL MODULE: ./js/ui/jsx/fm/fmView.jsx + 10 modules
-const fmView = REQ_(701);
-// EXTERNAL MODULE: ./js/chat/ui/contacts.jsx
-const contacts = REQ_(251);
-// EXTERNAL MODULE: ./js/ui/jsx/fm/nodes/genericNodePropsComponent.jsx + 1 modules
-const genericNodePropsComponent = REQ_(984);
-;// ./js/ui/jsx/fm/nodes/columns/columnContactName.jsx
-
-
-
-
-class ColumnContactName extends genericNodePropsComponent.B {
- constructor(...args) {
- super(...args);
- this.Mail = (0,utils.T9)(() => REaCt().createElement("span", {
- className: "contact-item-email"
- }, this.props.nodeAdapter.props.node.m));
- }
- static get label() {
- return l[86];
- }
- get name() {
- const {
- nodeAdapter,
- node
- } = this.props;
- if (nodeAdapter.nodeProps) {
- return nodeAdapter.nodeProps.title;
- }
- return M.getNameByEmail(node.m);
- }
- _renderAvatar() {
- const {
- nodeAdapter
- } = this.props;
- const {
- node
- } = nodeAdapter.props;
- if (nodeAdapter.nodeProps || node.name !== '') {
- return REaCt().createElement(contacts.Avatar, {
- contact: node,
- className: "avatar-wrapper box-avatar"
- });
- } else if (node.name === '') {
- return REaCt().createElement(utils.P9, null, useravatar.contact(node.m, 'box-avatar'));
- }
- return null;
- }
- render() {
- return REaCt().createElement("td", null, this._renderAvatar(), REaCt().createElement("div", {
- className: "contact-item"
- }, REaCt().createElement("div", {
- className: "contact-item-user"
- }, REaCt().createElement(utils.sp, null, this.name)), REaCt().createElement(this.Mail, null)), REaCt().createElement("div", {
- className: "clear"
- }));
- }
-}
-ColumnContactName.sortable = true;
-ColumnContactName.id = "name";
-ColumnContactName.megatype = "name";
-;// ./js/ui/jsx/fm/nodes/columns/columnContactStatus.jsx
-
-
-class ColumnContactStatus extends genericNodePropsComponent.B {
- static get label() {
- return l[89];
- }
- render() {
- const {
- nodeAdapter
- } = this.props;
- const {onlineStatus} = nodeAdapter.nodeProps;
- return REaCt().createElement("td", {
- megatype: ColumnContactStatus.megatype,
- className: ColumnContactStatus.megatype
- }, REaCt().createElement("div", {
- className: "contact-item"
- }, REaCt().createElement("div", {
- className: "contact-item-status"
- }, REaCt().createElement("div", {
- className: `user-card-presence ${ onlineStatus[1]}`
- }), onlineStatus[0])));
- }
-}
-ColumnContactStatus.sortable = true;
-ColumnContactStatus.id = "status";
-ColumnContactStatus.megatype = "status";
-;// ./js/ui/jsx/fm/nodes/columns/columnContactLastInteraction.jsx
-
-
-class ColumnContactLastInteraction extends genericNodePropsComponent.B {
- constructor(...args) {
- super(...args);
- this.getLastInteractionIcon = handle => {
- const {
- interactions
- } = this.props;
- const interaction = interactions[handle];
- const {
- type,
- time
- } = interaction || {
- type: undefined,
- time: undefined
- };
- return REaCt().createElement("i", {
- className: `
- sprite-fm-mono
- ${parseInt(type, 10) === 0 ? 'icon-cloud' : ''}
- ${parseInt(type, 10) === 1 ? 'icon-chat' : ''}
- ${!time ? 'icon-minimise' : ''}
- `
- });
- };
- this.getLastInteractionTime = handle => {
- const {
- interactions
- } = this.props;
- const interaction = interactions[handle];
- return interaction ? time2last(interaction.time) : l[1051];
- };
- }
- static get label() {
- return l[5904];
- }
- render() {
- const {
- nodeAdapter
- } = this.props;
- const {
- node
- } = nodeAdapter.props;
- return REaCt().createElement("td", {
- megatype: ColumnContactLastInteraction.megatype,
- className: ColumnContactLastInteraction.megatype
- }, REaCt().createElement("div", {
- className: "contact-item"
- }, REaCt().createElement("div", {
- className: "contact-item-time"
- }, this.getLastInteractionIcon(node.h), this.getLastInteractionTime(node.h))));
- }
-}
-ColumnContactLastInteraction.sortable = true;
-ColumnContactLastInteraction.id = "interaction";
-ColumnContactLastInteraction.megatype = "interaction";
-;// ./js/ui/jsx/fm/nodes/columns/columnContactVerifiedStatus.jsx
-
-
-
-class ColumnContactVerifiedStatus extends genericNodePropsComponent.B {
- constructor(...args) {
- super(...args);
- this.getFingerPrintDialogLink = handle => {
- const onVerifyContactClicked = handle => {
- ContactsPanel.verifyCredentials(this.props.contacts[handle]);
- };
- return REaCt().createElement("div", {
- className: "verify-contact-link-container"
- }, REaCt().createElement("div", {
- className: "verify-contact-link",
- onClick: () => onVerifyContactClicked(handle)
- }, l.verify_credentials));
- };
- }
- render() {
- const {
- nodeAdapter
- } = this.props;
- const {
- node
- } = nodeAdapter.props;
- return REaCt().createElement("td", {
- megatype: ColumnContactVerifiedStatus.megatype,
- className: ColumnContactVerifiedStatus.megatype
- }, REaCt().createElement("div", {
- className: "contact-item"
- }, REaCt().createElement("div", {
- className: "contact-item-verification"
- }, ContactsPanel.isVerified(this.props.contacts[node.h]) ? ColumnContactVerifiedStatus.verifiedLabel : this.getFingerPrintDialogLink(node.h))));
- }
-}
-ColumnContactVerifiedStatus.sortable = true;
-ColumnContactVerifiedStatus.id = "verification";
-ColumnContactVerifiedStatus.megatype = "verification";
-ColumnContactVerifiedStatus.label = REaCt().createElement(REaCt().Fragment, null, l.contact_ver_verification, "\xA0", REaCt().createElement("i", {
- className: "simpletip sprite-fm-mono contacts-verification-icon icon-info",
- "data-simpletip": l.contact_ver_tooltip_content,
- "data-simpletip-class": "contacts-verification-icon-simpletip"
-}));
-ColumnContactVerifiedStatus.verifiedLabel = REaCt().createElement("div", {
- className: "verified-contact-label-container"
-}, REaCt().createElement("i", {
- className: "small-icon icons-sprite tiny-green-tick"
-}), l[6776]);
-// EXTERNAL MODULE: ./js/ui/dropdowns.jsx
-const dropdowns = REQ_(911);
-// EXTERNAL MODULE: ./js/chat/ui/meetings/call.jsx + 11 modules
-const call = REQ_(3);
-// EXTERNAL MODULE: ./js/chat/ui/conversations.jsx + 21 modules
-const conversations = REQ_(732);
-;// ./js/chat/ui/contactsPanel/contextMenu.jsx
-
-
-
-
-
-
-
-class ContextMenu extends REaCt().Component {
- constructor(...args) {
- super(...args);
- this.EVENT_CLOSE = new Event('closeDropdowns');
- this.close = callback => {
- if (callback && typeof callback === 'function' && !M.isInvalidUserStatus()) {
- callback();
- }
- document.dispatchEvent(this.EVENT_CLOSE);
- };
- this.handleSetNickname = handle => this.close(() => nicknames.setNicknameDialog.init(handle));
- this.handleAddContact = handle => {
- M.syncContactEmail(handle, true).then(email => {
- const OPC = Object.values(M.opc);
- const ALREADY_SENT = OPC && OPC.length && OPC.some(opc => opc.m === email);
- this.close(() => {
- if (ALREADY_SENT) {
- return msgDialog('warningb', '', l[17545]);
- }
- msgDialog('info', l[150], l[5898]);
- M.inviteContact(M.u[u_handle].m, email);
- });
- }).catch(nop);
- };
- }
- render() {
- const {
- contact,
- selected,
- withProfile
- } = this.props;
- if (ContactsPanel.hasRelationship(contact)) {
- return REaCt().createElement(REaCt().Fragment, null, withProfile && REaCt().createElement("div", {
- className: "dropdown-avatar rounded",
- onClick: e => {
- e.stopPropagation();
- loadSubPage(`fm/chat/contacts/${contact.h}`);
- }
- }, REaCt().createElement(contacts.Avatar, {
- contact,
- className: "avatar-wrapper context-avatar"
- }), REaCt().createElement("div", {
- className: "dropdown-profile"
- }, REaCt().createElement("span", null, REaCt().createElement(utils.zT, null, M.getNameByHandle(contact.u))), REaCt().createElement(contacts.ContactPresence, {
- contact
- }))), REaCt().createElement(dropdowns.DropdownItem, {
- icon: "sprite-fm-mono icon-chat",
- label: l[8632],
- onClick: () => this.close(() => {
- if (selected && selected.length) {
- return megaChat.createAndShowGroupRoomFor(selected, '', {
- keyRotation: true,
- createChatLink: false
- });
- }
- loadSubPage(`fm/chat/p/${contact.u}`);
- megaChat.trigger(conversations.qY.NAV_RENDER_VIEW, conversations.Vw.CHATS);
- })
- }), REaCt().createElement(dropdowns.DropdownItem, {
- icon: "sprite-fm-mono icon-send-files",
- label: l[6834],
- onClick: () => this.close(() => megaChat.openChatAndSendFilesDialog(contact.u))
- }), REaCt().createElement(dropdowns.DropdownItem, {
- icon: "sprite-fm-mono icon-folder-outgoing-share",
- label: l[5631],
- onClick: () => this.close(() => openCopyShareDialog(contact.u))
- }), REaCt().createElement("div", {
- "data-simpletipposition": "top",
- className: "simpletip",
- "data-simpletip": !megaChat.hasSupportForCalls ? l.call_not_suported : ''
- }, REaCt().createElement(dropdowns.DropdownItem, {
- submenu: megaChat.hasSupportForCalls,
- disabled: !navigator.onLine || !megaChat.hasSupportForCalls,
- icon: "sprite-fm-mono icon-phone",
- className: "sprite-fm-mono-before icon-arrow-right-before",
- label: l[19125]
- }), REaCt().createElement("div", {
- className: "dropdown body submenu"
- }, REaCt().createElement(dropdowns.DropdownItem, {
- icon: "sprite-fm-mono icon-phone",
- disabled: !navigator.onLine || !megaChat.hasSupportForCalls,
- label: l[5896],
- onClick: () => (0,call.dQ)().then(() => this.close(() => megaChat.createAndShowPrivateRoom(contact.u).then(room => {
- room.setActive();
- room.startAudioCall();
- }))).catch(() => d && console.warn('Already in a call.'))
- }), REaCt().createElement(dropdowns.DropdownItem, {
- icon: "sprite-fm-mono icon-video-call-filled",
- disabled: !navigator.onLine || !megaChat.hasSupportForCalls,
- label: l[5897],
- onClick: () => (0,call.dQ)().then(() => this.close(() => megaChat.createAndShowPrivateRoom(contact.u).then(room => {
- room.setActive();
- room.startVideoCall();
- }))).catch(() => d && console.warn('Already in a call.'))
- }))), REaCt().createElement("hr", null), withProfile && REaCt().createElement(dropdowns.DropdownItem, {
- icon: "sprite-fm-mono icon-my-account",
- label: l[5868],
- onClick: () => loadSubPage(`fm/chat/contacts/${contact.u}`)
- }), REaCt().createElement(dropdowns.DropdownItem, {
- icon: "sprite-fm-mono icon-rename",
- label: contact.nickname === '' ? l.set_nickname_label : l.edit_nickname_label,
- onClick: () => this.handleSetNickname(contact.u)
- }), REaCt().createElement("hr", null), REaCt().createElement(dropdowns.DropdownItem, {
- submenu: true,
- icon: "sprite-fm-mono icon-key",
- className: "sprite-fm-mono-before icon-arrow-right-before",
- label: l[6872]
- }), REaCt().createElement("div", {
- className: "dropdown body white-context-menu submenu"
- }, ContactsPanel.isVerified(contact) ? REaCt().createElement(dropdowns.DropdownItem, {
- label: l[742],
- onClick: () => this.close(() => ContactsPanel.resetCredentials(contact))
- }) : REaCt().createElement(dropdowns.DropdownItem, {
- label: l[1960],
- onClick: () => this.close(() => ContactsPanel.verifyCredentials(contact))
- })), REaCt().createElement("div", {
- className: "dropdown-credentials"
- }, ContactsPanel.getUserFingerprint(contact.u)), REaCt().createElement("hr", null), REaCt().createElement(dropdowns.DropdownItem, {
- icon: "sprite-fm-mono icon-disable",
- label: l[1001],
- disabled: !!contact.b,
- className: "",
- onClick: () => this.close(() => fmremove(contact.u))
- }));
- }
- return REaCt().createElement(REaCt().Fragment, null, REaCt().createElement(dropdowns.DropdownItem, {
- icon: "sprite-fm-mono icon-disabled-filled",
- label: l[71],
- onClick: () => this.handleAddContact(contact.u)
- }), REaCt().createElement(dropdowns.DropdownItem, {
- icon: "sprite-fm-mono icon-rename",
- label: contact.nickname === '' ? l.set_nickname_label : l.edit_nickname_label,
- onClick: () => this.handleSetNickname(contact.u)
- }));
- }
-}
-;// ./js/ui/jsx/fm/nodes/columns/columnContactButtons.jsx
-
-
-
-
-
-
-
-class ColumnContactButtons extends genericNodePropsComponent.B {
- render() {
- const {
- nodeAdapter
- } = this.props;
- const {
- node,
- selected
- } = nodeAdapter.props;
- const handle = node.h;
- return REaCt().createElement("td", {
- megatype: ColumnContactButtons.megatype,
- className: ColumnContactButtons.megatype
- }, REaCt().createElement("div", {
- className: "contact-item"
- }, REaCt().createElement("div", {
- className: "contact-item-controls"
- }, REaCt().createElement(buttons.$, {
- className: "mega-button action simpletip",
- icon: "sprite-fm-mono icon-phone",
- attrs: {
- 'data-simpletip': !megaChat.hasSupportForCalls ? l.unsupported_browser_audio : l[5896]
- },
- disabled: !navigator.onLine || !megaChat.hasSupportForCalls,
- onClick: () => M.isInvalidUserStatus() || (0,call.dQ)().then(() => megaChat.createAndShowPrivateRoom(handle).then(room => {
- room.setActive();
- room.startAudioCall();
- })).catch(() => d && console.warn('Already in a call.'))
- }), REaCt().createElement(buttons.$, {
- className: "mega-button action simpletip",
- icon: "sprite-fm-mono icon-chat",
- attrs: {
- 'data-simpletip': l[8632]
- },
- onClick: () => {
- loadSubPage(`fm/chat/p/${handle}`);
- megaChat.trigger(conversations.qY.NAV_RENDER_VIEW, conversations.Vw.CHATS);
- }
- }), REaCt().createElement(buttons.$, {
- className: "mega-button action simpletip",
- icon: "sprite-fm-mono icon-send-files",
- attrs: {
- 'data-simpletip': l[6834]
- },
- onClick: () => M.isInvalidUserStatus() || megaChat.openChatAndSendFilesDialog(handle)
- }), REaCt().createElement(buttons.$, {
- ref: node => {
- this.props.onContextMenuRef(handle, node);
- },
- className: "mega-button action contact-more",
- icon: "sprite-fm-mono icon-options"
- }, REaCt().createElement(dropdowns.Dropdown, {
- className: "context",
- noArrow: true,
- positionMy: "left bottom",
- positionAt: "right bottom",
- positionLeft: this.props.contextMenuPosition || null,
- horizOffset: 4,
- onActiveChange: opened => {
- this.props.onActiveChange(opened);
- }
- }, REaCt().createElement(ContextMenu, {
- contact: node,
- selected,
- withProfile: true
- }))))));
- }
-}
-ColumnContactButtons.sortable = false;
-ColumnContactButtons.id = "grid-url-header-nw";
-ColumnContactButtons.label = "";
-ColumnContactButtons.megatype = "grid-url-header-nw";
-// EXTERNAL MODULE: ./js/chat/ui/updateObserver.jsx
-const updateObserver = REQ_(501);
-;// ./js/chat/ui/contactsPanel/contactList.jsx
-
-
-
-
-
-
-
-
-
-
-class ContactList extends mixins.w9 {
- constructor(props) {
- super(props);
- this.domRef = REaCt().createRef();
- this.contextMenuRefs = [];
- this.state = {
- selected: [],
- searchValue: null,
- interactions: {},
- contextMenuPosition: null
- };
- this.onSelected = this.onSelected.bind(this);
- this.onHighlighted = this.onHighlighted.bind(this);
- this.onExpand = this.onExpand.bind(this);
- this.onAttachClicked = this.onAttachClicked.bind(this);
- this.getLastInteractions = this.getLastInteractions.bind(this);
- }
- getLastInteractions() {
- const {
- contacts
- } = this.props;
- const promises = [];
- const push = handle => {
- promises.push(Promise.resolve(getLastInteractionWith(handle, true, true)).then(ts => [ts, handle]));
- };
- for (const handle in contacts) {
- if (contacts[handle].c === 1) {
- push(handle);
- }
- }
- Promise.allSettled(promises).then(res => {
- if (this.isMounted()) {
- const interactions = {};
- for (let i = res.length; i--;) {
- if (res[i].status !== 'fulfilled') {
- if (d && res[i].reason !== false) {
- console.warn('getLastInteractions', res[i].reason);
- }
- } else {
- const [ts, u] = res[i].value;
- const [type, time] = ts.split(':');
- interactions[u] = {
- u,
- type,
- time
- };
- }
- }
- this.setState({
- interactions
- });
- }
- }).catch(ex => {
- console.error("Failed to handle last interactions!", ex);
- });
- }
- handleContextMenu(ev, handle) {
- ev.preventDefault();
- ev.persist();
- if (this.state.selected.length > 1) {
- return null;
- }
- const $$REF = this.contextMenuRefs[handle];
- if ($$REF && $$REF.isMounted()) {
- let _$$REF$domRef;
- const refNodePosition = ((_$$REF$domRef = $$REF.domRef) == null ? void 0 : _$$REF$domRef.current) && $$REF.domRef.current.getBoundingClientRect().x;
- this.setState({
- contextMenuPosition: ev.clientX > refNodePosition ? null : ev.clientX
- }, () => $$REF.onClick(ev));
- }
- }
- onSelected(handle) {
- this.setState({
- 'selected': handle
- });
- }
- onHighlighted(handle) {
- this.setState({
- 'highlighted': handle
- });
- }
- onExpand(handle) {
- loadSubPage(`/fm/chat/contacts/${ handle}`);
- }
- onAttachClicked() {
- if (this.state.selected[0]) {
- this.onExpand(this.state.selected[0]);
- }
- }
- componentDidMount() {
- super.componentDidMount();
- this.getLastInteractions();
- }
- render() {
- const {
- contacts
- } = this.props;
- if (contacts && contacts.length > 1) {
- return REaCt().createElement("div", {
- ref: this.domRef,
- className: "contacts-list"
- }, REaCt().createElement(fmView.A, {
- dataSource: contacts,
- customFilterFn: r => {
- return r.c === 1;
- },
- currentlyViewedEntry: "contacts",
- onSelected: this.onSelected,
- onHighlighted: this.onHighlighted,
- searchValue: this.state.searchValue,
- onExpand: this.onExpand,
- onAttachClicked: this.onAttachClicked,
- viewMode: 0,
- currentdirid: "contacts",
- megaListItemHeight: 59,
- headerContainerClassName: "contacts-table contacts-table-head",
- containerClassName: "contacts-table contacts-table-results",
- onContextMenu: (ev, handle) => this.handleContextMenu(ev, handle),
- listAdapterColumns: [ColumnContactName, ColumnContactStatus, [ColumnContactLastInteraction, {
- interactions: this.state.interactions
- }], [ColumnContactVerifiedStatus, {
- contacts
- }], [ColumnContactButtons, {
- onContextMenuRef: (handle, node) => {
- this.contextMenuRefs[handle] = node;
- },
- onActiveChange: opened => {
- if (!opened) {
- this.setState({
- contextMenuPosition: null
- });
- }
- },
- contextMenuPosition: this.state.contextMenuPosition
- }]],
- initialSortBy: ['status', 'asc'],
- fmConfigSortEnabled: true,
- fmConfigSortId: "contacts",
- NilComponent: REaCt().createElement(Nil, {
- title: l[5737]
- })
- }));
- }
- return REaCt().createElement(Nil, {
- title: l[5737]
- });
- }
-}
-ContactList.updateListener = 'getLastInteractions';
-ContactList.updateInterval = 6e4;
-const contactList = (0,mixins.Zz)(updateObserver.Y)(ContactList);
-;// ./js/ui/jsx/fm/nodes/columns/columnContactRequestsEmail.jsx
-
-
-
-class ColumnContactRequestsEmail extends mixins.w9 {
- constructor(...args) {
- super(...args);
- this.domRef = REaCt().createRef();
- }
- static get label() {
- return l[95];
- }
- render() {
- const {
- nodeAdapter,
- currView
- } = this.props;
- const {
- node
- } = nodeAdapter.props;
- return REaCt().createElement("td", {
- ref: this.domRef
- }, currView && currView === 'opc' ? REaCt().createElement("span", null, REaCt().createElement("i", {
- className: "sprite-fm-uni icon-send-requests"
- })) : REaCt().createElement(utils.P9, null, useravatar.contact(node.m, 'box-avatar')), REaCt().createElement("div", {
- className: "contact-item"
- }, REaCt().createElement("div", {
- className: "contact-item-user"
- }, node.m)), REaCt().createElement("div", {
- className: "clear"
- }));
- }
-}
-ColumnContactRequestsEmail.sortable = true;
-ColumnContactRequestsEmail.id = "email";
-ColumnContactRequestsEmail.megatype = "email";
-;// ./js/ui/jsx/fm/nodes/columns/columnContactRequestsTs.jsx
-
-
-class ColumnContactRequestsTs extends mixins.w9 {
- constructor(...args) {
- super(...args);
- this.domRef = REaCt().createRef();
- }
- static get label() {
- return l[19506];
- }
- render() {
- const {
- nodeAdapter
- } = this.props;
- const {
- node
- } = nodeAdapter.props;
- let timestamp = node.rts || node.ts;
- if (timestamp) {
- timestamp = time2last(timestamp);
- } else {
- timestamp = node.dts ? l[6112] : "";
- }
- return REaCt().createElement("td", {
- ref: this.domRef
- }, REaCt().createElement("div", {
- className: "contact-item"
- }, REaCt().createElement("div", {
- className: "contact-item-time"
- }, timestamp)), REaCt().createElement("div", {
- className: "clear"
- }));
- }
-}
-ColumnContactRequestsTs.sortable = true;
-ColumnContactRequestsTs.id = "ts";
-ColumnContactRequestsTs.megatype = "ts";
-;// ./js/ui/jsx/fm/nodes/columns/columnContactRequestsRcvdBtns.jsx
-
-
-
-class ColumnContactRequestsRcvdBtns extends mixins.w9 {
- constructor(...args) {
- super(...args);
- this.domRef = REaCt().createRef();
- }
- render() {
- const {
- nodeAdapter
- } = this.props;
- const {
- node
- } = nodeAdapter.props;
- return REaCt().createElement("td", {
- ref: this.domRef,
- megatype: ColumnContactRequestsRcvdBtns.megatype,
- className: ColumnContactRequestsRcvdBtns.megatype
- }, REaCt().createElement("div", {
- className: "contact-item-controls"
- }, REaCt().createElement(buttons.$, {
- className: "mega-button action contact-reject",
- icon: "sprite-fm-mono icon-close-component",
- label: l[20981],
- onClick: () => this.props.onReject(node.p)
- }), REaCt().createElement(buttons.$, {
- className: "mega-button action contact-block",
- icon: "sprite-fm-mono icon-disable",
- label: l[20980],
- onClick: () => this.props.onBlock(node.p)
- }), REaCt().createElement(buttons.$, {
- className: "mega-button action contact-accept",
- icon: "sprite-fm-mono icon-check",
- label: l[5856],
- onClick: () => this.props.onAccept(node.p)
- })));
- }
-}
-ColumnContactRequestsRcvdBtns.sortable = true;
-ColumnContactRequestsRcvdBtns.id = "grid-url-header-nw";
-ColumnContactRequestsRcvdBtns.label = "";
-ColumnContactRequestsRcvdBtns.megatype = "grid-url-header-nw contact-controls-container";
-;// ./js/chat/ui/contactsPanel/receivedRequests.jsx
-
-
-
-
-
-
-
-const ReceivedRequests = ({
- received
-}) => {
- const nameOrEmailColumn = received.mixed ? ColumnContactName : [ColumnContactRequestsEmail, {
- currView: "ipc"
- }];
- return REaCt().createElement("div", {
- className: "contacts-list"
- }, REaCt().createElement(fmView.A, {
- sortFoldersFirst: false,
- dataSource: received.data,
- customFilterFn: r => {
- return !r.dts;
- },
- currentlyViewedEntry: "ipc",
- onSelected: nop,
- onHighlighted: nop,
- onExpand: nop,
- onAttachClicked: nop,
- viewMode: 0,
- currentdirid: "ipc",
- megaListItemHeight: 59,
- headerContainerClassName: "contacts-table requests-table contacts-table-head",
- containerClassName: "contacts-table requests-table contacts-table-results",
- listAdapterColumns: [nameOrEmailColumn, [ColumnContactRequestsTs, {
- label: l[19505]
- }], [ColumnContactRequestsRcvdBtns, {
- onReject: handle => {
- M.denyPendingContactRequest(handle).catch(dump);
- },
- onBlock: handle => {
- M.ignorePendingContactRequest(handle).catch(dump);
- },
- onAccept: handle => {
- M.acceptPendingContactRequest(handle).catch(dump);
- }
- }]],
- keyProp: "p",
- nodeAdapterProps: {
- 'className': node => {
- return `
- ${node.dts || node.s && node.s === 3 ? 'deleted' : ''}
- ${node.s && node.s === 1 ? 'ignored' : ''}
- `;
- }
- },
- NilComponent: () => {
- return REaCt().createElement(Nil, {
- title: l[6196]
- });
- },
- initialSortBy: ['email', 'asc'],
- fmConfigSortEnabled: true,
- fmConfigSortId: "ipc"
- }));
-};
-const receivedRequests = ReceivedRequests;
-;// ./js/ui/jsx/fm/nodes/columns/columnContactRequestsSentBtns.jsx
-
-
-
-class ColumnContactRequestsSentBtns extends mixins.w9 {
- constructor(...args) {
- super(...args);
- this.domRef = REaCt().createRef();
- this.reinviteAllowed = rts => {
- const UTC_DATE_NOW = Math.floor(Date.now() / 1000);
- return UTC_DATE_NOW > rts + 1209600;
- };
- }
- render() {
- const {
- nodeAdapter
- } = this.props;
- const {
- node
- } = nodeAdapter.props;
- return REaCt().createElement("td", {
- ref: this.domRef,
- megatype: ColumnContactRequestsSentBtns.megatype,
- className: ColumnContactRequestsSentBtns.megatype
- }, REaCt().createElement("div", {
- className: "contact-item-controls contact-request-sent"
- }, !node.dts && this.reinviteAllowed(node.rts) && REaCt().createElement(buttons.$, {
- className: "mega-button action",
- icon: "sprite-fm-mono icon-rewind",
- label: l[5861],
- onClick: () => this.props.onReinvite(node.m)
- }), !node.dts && REaCt().createElement(buttons.$, {
- className: "mega-button action contact-reject",
- icon: "sprite-fm-mono icon-close-component",
- label: l.msg_dlg_cancel,
- onClick: () => this.props.onReject(node.m)
- })));
- }
-}
-ColumnContactRequestsSentBtns.sortable = true;
-ColumnContactRequestsSentBtns.id = "grid-url-header-nw";
-ColumnContactRequestsSentBtns.label = "";
-ColumnContactRequestsSentBtns.megatype = "grid-url-header-nw contact-controls-container";
-;// ./js/ui/jsx/fm/nodes/columns/columnContactRequestsRts.jsx
-
-
-class ColumnContactRequestsRts extends ColumnContactRequestsTs {
- static get label() {
- return l[19506];
- }
-}
-ColumnContactRequestsRts.sortable = true;
-ColumnContactRequestsRts.id = "rts";
-ColumnContactRequestsRts.megatype = "rts";
-;// ./js/chat/ui/contactsPanel/sentRequests.jsx
-
-
-
-
-
-
-const SentRequests = ({
- sent
-}) => {
- return REaCt().createElement("div", {
- className: "contacts-list"
- }, REaCt().createElement(fmView.A, {
- sortFoldersFirst: false,
- dataSource: sent,
- currentlyViewedEntry: "opc",
- onSelected: nop,
- onHighlighted: nop,
- onExpand: nop,
- onAttachClicked: nop,
- viewMode: 0,
- currentdirid: "opc",
- megaListItemHeight: 59,
- headerContainerClassName: "contacts-table requests-table contacts-table-head",
- containerClassName: "contacts-table requests-table contacts-table-results",
- listAdapterColumns: [[ColumnContactRequestsEmail, {
- currView: "opc"
- }], ColumnContactRequestsRts, [ColumnContactRequestsSentBtns, {
- onReject: email => {
- M.cancelPendingContactRequest(email).catch(ex => {
- if (ex === EARGS) {
- msgDialog('info', '', 'This pending contact is already deleted.');
- } else {
- tell(ex);
- }
- });
- },
- onReinvite: email => {
- M.reinvitePendingContactRequest(email).then(() => contactsInfoDialog(l[19126], email, l[19127])).catch(tell);
- }
- }]],
- NilComponent: () => {
- return REaCt().createElement(Nil, {
- title: l[6196]
- });
- },
- listAdapterOpts: {
- 'className': node => node.dts && ' disabled'
- },
- keyProp: "p",
- initialSortBy: ['email', 'asc'],
- fmConfigSortEnabled: true,
- fmConfigSortMap: {
- 'rts': 'rTimeStamp'
- },
- fmConfigSortId: "opc"
- }));
-};
-const sentRequests = SentRequests;
-// EXTERNAL MODULE: ./js/ui/jsx/fm/nodes/columns/columnFavIcon.jsx
-const columnFavIcon = REQ_(161);
-;// ./js/ui/jsx/fm/nodes/columns/columnSharedFolderName.jsx
-
-
-class ColumnSharedFolderName extends genericNodePropsComponent.B {
- static get label() {
- return l[86];
- }
- render() {
- const {
- nodeAdapter
- } = this.props;
- const {
- node
- } = nodeAdapter.props;
- return REaCt().createElement("td", {
- megatype: ColumnSharedFolderName.megatype,
- className: ColumnSharedFolderName.megatype
- }, REaCt().createElement("div", {
- className: "item-type-icon-90 icon-folder-incoming-90 sprite-fm-uni-after icon-warning-after"
- }), REaCt().createElement("div", {
- className: "shared-folder-info-block"
- }, REaCt().createElement("div", {
- className: "shared-folder-name"
- }, missingkeys[node.h] ? l[8686] : nodeAdapter.nodeProps.title), REaCt().createElement("div", {
- className: "shared-folder-info"
- }, fm_contains(node.tf, node.td))));
- }
-}
-ColumnSharedFolderName.sortable = true;
-ColumnSharedFolderName.id = "name";
-ColumnSharedFolderName.megatype = "name";
-;// ./js/ui/jsx/fm/nodes/columns/columnSharedFolderAccess.jsx
-
-
-class ColumnSharedFolderAccess extends genericNodePropsComponent.B {
- static get label() {
- return l[5906];
- }
- render() {
- const {
- nodeAdapter
- } = this.props;
- return REaCt().createElement("td", {
- megatype: ColumnSharedFolderAccess.megatype,
- className: ColumnSharedFolderAccess.megatype
- }, REaCt().createElement("div", {
- className: "shared-folder-access"
- }, REaCt().createElement("i", {
- className: `
- sprite-fm-mono
- ${nodeAdapter.nodeProps.incomingShareData.accessIcon}
- `
- }), REaCt().createElement("span", null, nodeAdapter.nodeProps.incomingShareData.accessLabel)));
- }
-}
-ColumnSharedFolderAccess.sortable = true;
-ColumnSharedFolderAccess.id = 'access';
-ColumnSharedFolderAccess.megatype = 'access';
-;// ./js/ui/jsx/fm/nodes/columns/columnSharedFolderButtons.jsx
-
-
-
-class ColumnSharedFolderButtons extends genericNodePropsComponent.B {
- render() {
- const {
- nodeAdapter
- } = this.props;
- const {
- node
- } = nodeAdapter.props;
- const handle = node.h;
- return REaCt().createElement("td", {
- megatype: ColumnSharedFolderButtons.megatype,
- className: ColumnSharedFolderButtons.megatype
- }, REaCt().createElement("div", {
- className: "contact-item"
- }, REaCt().createElement("div", {
- className: "contact-item-controls"
- }, REaCt().createElement(buttons.$, {
- className: "mega-button action contact-more",
- icon: "sprite-fm-mono icon-options",
- onClick: (button, e) => {
- e.persist();
- $.selected = [handle];
- e.preventDefault();
- e.stopPropagation();
- e.delegateTarget = $(e.target).parents('td')[0];
- e.currentTarget = $(e.target).parents('tr');
- if (!$(e.target).hasClass('active')) {
- M.contextMenuUI(e, 1);
- $(this).addClass('active');
- } else {
- $.hideContextMenu();
- $(e.target).removeClass('active');
- }
- }
- }))));
- }
-}
-ColumnSharedFolderButtons.sortable = true;
-ColumnSharedFolderButtons.id = "grid-url-header-nw";
-ColumnSharedFolderButtons.label = "";
-ColumnSharedFolderButtons.megatype = "grid-url-header-nw";
-// EXTERNAL MODULE: ./js/chat/ui/link.jsx
-const ui_link = REQ_(280);
-;// ./js/chat/ui/contactsPanel/contactProfile.jsx
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-class ContactProfile extends mixins.w9 {
- constructor(...args) {
- super(...args);
- this.domRef = REaCt().createRef();
- this.state = {
- selected: [],
- loading: true
- };
- this.onAttachClicked = () => {
- const {
- selected
- } = this.state;
- if (selected[0]) {
- this.onExpand(selected[0]);
- }
- };
- this.onExpand = handle => loadSubPage(`fm/${handle}`);
- this.Breadcrumb = () => {
- const {
- handle
- } = this.props;
- return REaCt().createElement("div", {
- className: "profile-breadcrumb"
- }, REaCt().createElement("ul", null, REaCt().createElement("li", null, REaCt().createElement(ui_link.A, {
- to: "/fm/chat/contacts"
- }, ContactsPanel.LABEL.CONTACTS), REaCt().createElement("i", {
- className: "sprite-fm-mono icon-arrow-right"
- })), REaCt().createElement("li", null, REaCt().createElement(utils.zT, null, M.getNameByHandle(handle)))));
- };
- this.Credentials = () => {
- const {
- handle
- } = this.props;
- const contact = M.u[handle];
- if (handle && contact && contact.c === 1) {
- const IS_VERIFIED = ContactsPanel.isVerified(contact);
- return REaCt().createElement("div", {
- className: "profile-credentials"
- }, REaCt().createElement("span", {
- className: "credentials-head"
- }, l[6872]), REaCt().createElement("div", {
- className: "credentials-fingerprints"
- }, ContactsPanel.getUserFingerprint(handle)), REaCt().createElement("button", {
- className: `
- mega-button
- small
- ${IS_VERIFIED ? '' : 'positive'}
- `,
- onClick: () => ContactsPanel[IS_VERIFIED ? 'resetCredentials' : 'verifyCredentials'](contact)
- }, IS_VERIFIED ? l[742] : l.verify_credentials));
- }
- return null;
- };
- this.handleContextMenu = (e, handle) => {
- e.persist();
- e.preventDefault();
- e.stopPropagation();
- e.delegateTarget = e.target.tagName === "TR" ? e.target : $(e.target).parents('tr')[0];
- e.currentTarget = $(e.delegateTarget);
- $.selected = [handle];
- M.contextMenuUI(e, 1);
- };
- }
- UNSAFE_componentWillMount() {
- if (super.UNSAFE_componentWillMount) {
- super.UNSAFE_componentWillMount();
- }
- const {
- handle
- } = this.props;
- if (handle) {
- const contact = M.u[handle];
- if (contact) {
- this._listener = contact.addChangeListener(() => {
- if (contact && contact.c === 1) {
- this.safeForceUpdate();
- } else {
- loadSubPage("/fm/chat/contacts");
- return 0xDEAD;
- }
- });
- }
- }
- }
- componentWillUnmount() {
- super.componentWillUnmount();
- if (this._listener) {
- const {
- handle
- } = this.props;
- const contact = M.u[handle];
- contact.removeChangeListener(this._listener);
- }
- }
- componentDidMount() {
- super.componentDidMount();
- dbfetch.geta(Object.keys(M.c.shares || {}), new MegaPromise()).finally(() => {
- if (this.isMounted()) {
- this.setState({
- 'loading': false
- });
- }
- });
- }
- getSharedFoldersView() {
- return this.state.loading ? null : REaCt().createElement(fmView.A, {
- currentlyViewedEntry: this.props.handle,
- onSelected: handle => this.setState({
- selected: handle
- }),
- onHighlighted: nop,
- searchValue: this.state.searchValue,
- onExpand: this.onExpand,
- onAttachClicked: this.onAttachClicked,
- viewMode: 0,
- currentdirid: "shares",
- megaListItemHeight: 65,
- headerContainerClassName: "grid-table-header",
- containerClassName: "grid-table shared-with-me",
- onContextMenu: (ev, handle) => this.handleContextMenu(ev, handle),
- listAdapterColumns: [columnFavIcon.$, [ColumnSharedFolderName, {
- 'label': `${l.shared_folders_from.replace('%NAME', M.getNameByHandle(this.props.handle))}`
- }], ColumnSharedFolderAccess, ColumnSharedFolderButtons]
- });
- }
- render() {
- const {
- handle
- } = this.props;
- if (handle) {
- const contact = M.u[handle];
- if (!contact || contact.c !== 1) {
- return REaCt().createElement(Nil, {
- title: l.contact_not_found
- });
- }
- const HAS_RELATIONSHIP = ContactsPanel.hasRelationship(contact);
- return REaCt().createElement("div", {
- ref: this.domRef,
- className: "contacts-profile"
- }, REaCt().createElement(this.Breadcrumb, null), REaCt().createElement("div", {
- className: "profile-content"
- }, REaCt().createElement("div", {
- className: "profile-head"
- }, HAS_RELATIONSHIP && REaCt().createElement(this.Credentials, null), REaCt().createElement(contacts.Avatar, {
- contact,
- className: "profile-photo avatar-wrapper contacts-medium-avatar"
- }), REaCt().createElement("div", {
- className: "profile-info"
- }, REaCt().createElement("h2", null, REaCt().createElement(utils.zT, null, M.getNameByHandle(handle)), REaCt().createElement(contacts.ContactPresence, {
- contact
- })), REaCt().createElement("span", null, contact.m)), HAS_RELATIONSHIP && REaCt().createElement("div", {
- className: "profile-controls"
- }, REaCt().createElement(buttons.$, {
- className: "mega-button round simpletip",
- icon: "sprite-fm-mono icon-chat-filled",
- attrs: {
- 'data-simpletip': l[8632]
- },
- onClick: () => {
- loadSubPage(`fm/chat/p/${handle}`);
- megaChat.trigger(conversations.qY.NAV_RENDER_VIEW, conversations.Vw.CHATS);
- }
- }), REaCt().createElement(buttons.$, {
- className: "mega-button round simpletip",
- icon: "sprite-fm-mono icon-send-files",
- attrs: {
- 'data-simpletip': l[6834]
- },
- onClick: () => {
- if (M.isInvalidUserStatus()) {
- return;
- }
- megaChat.openChatAndSendFilesDialog(handle);
- }
- }), REaCt().createElement(buttons.$, {
- className: "mega-button round",
- icon: "sprite-fm-mono icon-options"
- }, REaCt().createElement(dropdowns.Dropdown, {
- className: "context",
- noArrow: true,
- positionMy: "left bottom",
- positionAt: "right bottom",
- horizOffset: 4
- }, REaCt().createElement(ContextMenu, {
- contact
- }))))), REaCt().createElement("div", {
- className: "profile-shared-folders"
- }, this.getSharedFoldersView())));
- }
- return null;
- }
-}
-;// ./js/chat/ui/contactsPanel/contactsPanel.jsx
-
-
-
-
-
-
-
-class ContactsPanel extends mixins.w9 {
- get view() {
- switch (megaChat.routingSubSection) {
- case null:
- return ContactsPanel.VIEW.CONTACTS;
- case "contact":
- return ContactsPanel.VIEW.PROFILE;
- case "received":
- return ContactsPanel.VIEW.RECEIVED_REQUESTS;
- case "sent":
- return ContactsPanel.VIEW.SENT_REQUESTS;
- default:
- console.error("Shouldn't happen.");
- return false;
- }
- }
- constructor(props) {
- super(props);
- this.domRef = REaCt().createRef();
- this.requestReceivedListener = null;
- this.state = {
- receivedRequestsCount: 0
- };
- this.handleToggle = ({
- keyCode
- }) => {
- if (keyCode === 27) {
- const HAS_DIALOG_OPENED = $.dialog || ['.contact-nickname-dialog', '.fingerprint-dialog', '.context'].some(selector => {
- const dialog = document.querySelector(selector);
- return dialog && dialog.offsetHeight > 0;
- });
- return HAS_DIALOG_OPENED ? keyCode : loadSubPage('fm/chat');
- }
- };
- this.handleAcceptAllRequests = () => {
- const {
- data: received
- } = this.props.received;
- const receivedKeys = Object.keys(received || {});
- if (receivedKeys.length) {
- for (let i = receivedKeys.length; i--;) {
- M.acceptPendingContactRequest(receivedKeys[i]).catch(dump);
- }
- }
- };
- this.renderView = () => {
- const {
- contacts,
- received,
- sent
- } = this.props;
- const {
- view
- } = this;
- switch (view) {
- case ContactsPanel.VIEW.CONTACTS:
- return REaCt().createElement(contactList, {
- contacts
- });
- case ContactsPanel.VIEW.PROFILE:
- return REaCt().createElement(ContactProfile, {
- handle: view === ContactsPanel.VIEW.PROFILE && megaChat.routingParams
- });
- case ContactsPanel.VIEW.RECEIVED_REQUESTS:
- return REaCt().createElement(receivedRequests, {
- received
- });
- case ContactsPanel.VIEW.SENT_REQUESTS:
- return REaCt().createElement(sentRequests, {
- sent
- });
- }
- };
- this.state.receivedRequestsCount = Object.keys(M.ipc).length;
- }
- componentWillUnmount() {
- super.componentWillUnmount();
- document.documentElement.removeEventListener(ContactsPanel.EVENTS.KEYDOWN, this.handleToggle);
- if (this.requestReceivedListener) {
- mBroadcaster.removeListener(this.requestReceivedListener);
- }
- }
- componentDidMount() {
- super.componentDidMount();
- document.documentElement.addEventListener(ContactsPanel.EVENTS.KEYDOWN, this.handleToggle);
- this.requestReceivedListener = mBroadcaster.addListener('fmViewUpdate:ipc', () => this.setState({
- receivedRequestsCount: Object.keys(M.ipc).length
- }));
- }
- render() {
- const {
- view,
- state
- } = this;
- const {
- receivedRequestsCount
- } = state;
- return REaCt().createElement("div", {
- ref: this.domRef,
- className: "contacts-panel"
- }, REaCt().createElement(navigation, {
- view,
- contacts: this.props.contacts,
- receivedRequestsCount
- }), view !== ContactsPanel.VIEW.PROFILE && REaCt().createElement("div", {
- className: "contacts-actions"
- }, view === ContactsPanel.VIEW.RECEIVED_REQUESTS && receivedRequestsCount > 1 && REaCt().createElement("button", {
- className: "mega-button action",
- onClick: this.handleAcceptAllRequests
- }, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-check"
- }), REaCt().createElement("span", null, l[19062]))), REaCt().createElement("div", {
- className: "contacts-content"
- }, this.renderView()));
- }
-}
-ContactsPanel.EVENTS = {
- KEYDOWN: 'keydown'
-};
-ContactsPanel.VIEW = {
- CONTACTS: 0x00,
- RECEIVED_REQUESTS: 0x01,
- SENT_REQUESTS: 0x02,
- PROFILE: 0x03
-};
-ContactsPanel.LABEL = {
- CONTACTS: l[165],
- RECEIVED_REQUESTS: l[5863],
- SENT_REQUESTS: l[5862]
-};
-ContactsPanel.hasContacts = () => M.u.some(contact => contact.c === 1);
-ContactsPanel.hasRelationship = contact => contact && contact.c === 1;
-ContactsPanel.isVerified = contact => {
- if (contact && contact.u) {
- const {
- u: handle
- } = contact;
- const verificationState = u_authring.Ed25519[handle] || {};
- return verificationState.method >= authring.AUTHENTICATION_METHOD.FINGERPRINT_COMPARISON;
- }
- return null;
-};
-ContactsPanel.verifyCredentials = contact => {
- if (contact.c === 1 && u_authring && u_authring.Ed25519) {
- const verifyState = u_authring.Ed25519[contact.u] || {};
- if (typeof verifyState.method === "undefined" || verifyState.method < authring.AUTHENTICATION_METHOD.FINGERPRINT_COMPARISON) {
- fingerprintDialog(contact.u);
- }
- }
-};
-ContactsPanel.resetCredentials = contact => {
- if (M.isInvalidUserStatus()) {
- return;
- }
- authring.resetFingerprintsForUser(contact.u).then(() => contact.trackDataChange()).catch(dump);
-};
-ContactsPanel.getUserFingerprint = handle => {
- const $$FINGERPRINT = [];
- userFingerprint(handle, fingerprints => {
- for (let i = 0; i < fingerprints.length; i++) {
- $$FINGERPRINT.push(REaCt().createElement("span", {
- key: i
- }, fingerprints[i]));
- }
- });
- return $$FINGERPRINT;
-};
-
-},
-
-438
-(_, EXP_, REQ_) {
-
-"use strict";
-
-// EXPORTS
-REQ_.d(EXP_, {
- $h: () => ConversationPanels,
- Yk: () => EmptyConvPanel,
- e4: () => allContactsInChat,
- zV: () => excludedParticipants
-});
-
-// UNUSED EXPORTS: ConversationPanel, ConversationRightArea, JoinCallNotification
-
-// EXTERNAL MODULE: ./node_modules/@babel/runtime/helpers/esm/applyDecoratedDescriptor.js
-const applyDecoratedDescriptor = REQ_(793);
-// EXTERNAL MODULE: ./node_modules/@babel/runtime/helpers/esm/extends.js
-const esm_extends = REQ_(168);
-// EXTERNAL MODULE: external "React"
-const React_ = REQ_(594);
-const REaCt = REQ_.n(React_);
-// EXTERNAL MODULE: ./js/ui/utils.jsx
-const utils = REQ_(314);
-// EXTERNAL MODULE: ./js/chat/mixins.js
-const mixins = REQ_(137);
-// EXTERNAL MODULE: ./js/ui/buttons.jsx
-const buttons = REQ_(994);
-// EXTERNAL MODULE: ./js/ui/modalDialogs.jsx + 1 modules
-const modalDialogs = REQ_(318);
-;// ./js/ui/jsx/fm/viewModeSelector.jsx
-
-const VIEW_MODE = {
- 'GRID': 1,
- 'LIST': undefined
-};
-const ViewModeSelector = ({
- viewMode,
- onChange
-}) => {
- return REaCt().createElement("div", {
- className: "chat-fm-view-mode-selector"
- }, REaCt().createElement("i", {
- className: `
- sprite-fm-mono
- icon-view-medium-list
- ${viewMode ? '' : 'active'}
- `,
- title: l[5553],
- onClick: () => onChange == null ? void 0 : onChange(VIEW_MODE.LIST)
- }), REaCt().createElement("i", {
- className: `
- sprite-fm-mono
- icon-view-grid
- ${viewMode ? " active" : ""}
- `,
- title: l[5552],
- onClick: () => onChange == null ? void 0 : onChange(VIEW_MODE.GRID)
- }));
-};
-const viewModeSelector = ViewModeSelector;
-;// ./js/ui/jsx/fm/breadcrumbs.jsx
-
-
-class Breadcrumbs extends mixins.w9 {
- constructor(props) {
- super(props);
- this.domRef = REaCt().createRef();
- this.state = {
- 'breadcrumbDropdownVisible': false
- };
- this.onGlobalClickHandler = this.onGlobalClickHandler.bind(this);
- this.onBreadcrumbNodeClick = this.onBreadcrumbNodeClick.bind(this);
- }
- getBreadcrumbNodeText(nodeId, prevNodeId) {
- const backupsId = M.BackupsId || 'backups';
- switch (nodeId) {
- case M.RootID:
- return l[164];
- case M.RubbishID:
- return l[167];
- case backupsId:
- return l.restricted_folder_button;
- case 'shares':
- return prevNodeId && M.d[prevNodeId] ? M.d[prevNodeId].m : l[5589];
- default:
- return M.d[nodeId] && M.d[nodeId].name;
- }
- }
- getBreadcrumbDropdownContents(items) {
- const contents = [];
- for (const item of items) {
- if (!item.name) {
- continue;
- }
- contents.push(REaCt().createElement("a", {
- className: "crumb-drop-link",
- key: `drop_link_${ item.nodeId}`,
- onClick: e => this.onBreadcrumbNodeClick(e, item.nodeId)
- }, REaCt().createElement("i", {
- className: `sprite-fm-mono icon24 ${{
- 'cloud-drive': 'icon-cloud',
- 'backups': 'icon-database-filled',
- 's4-object-storage': 'icon-bucket-triangle-thin-solid',
- 's4-buckets': 'icon-bucket-outline'
- }[item.type] || 'folder'}`
- }), REaCt().createElement("span", null, item.name)));
- }
- return contents;
- }
- onBreadcrumbNodeClick(e, nodeId) {
- e.preventDefault();
- e.stopPropagation();
- if (this._clickToHideListener) {
- this.removeGlobalClickHandler();
- this.setState({
- 'breadcrumbDropdownVisible': false
- });
- }
- this.props.onNodeClick(nodeId);
- }
- customIsEventuallyVisible() {
- return true;
- }
- onGlobalClickHandler(e) {
- let _this$domRef;
- const node = (_this$domRef = this.domRef) == null ? void 0 : _this$domRef.current;
- if (node.contains(e.target) || node === e.target) {
- return;
- }
- if (this._clickToHideListener) {
- this.removeGlobalClickHandler();
- }
- this.setState({
- 'breadcrumbDropdownVisible': false
- });
- }
- removeGlobalClickHandler() {
- this._clickToHideListener = false;
- document.body.removeEventListener("click", this.onGlobalClickHandler);
- }
- componentDidUpdate() {
- super.componentDidUpdate();
- if (this.state.breadcrumbDropdownVisible) {
- if (!this._clickToHideListener) {
- this._clickToHideListener = true;
- document.body.addEventListener("click", this.onGlobalClickHandler);
- }
- } else if (this._clickToHideListener) {
- this.removeGlobalClickHandler();
- }
- }
- componentWillUnmount() {
- super.componentWillUnmount();
- this.removeGlobalClickHandler();
- }
- render() {
- const {
- className,
- highlighted,
- currentlyViewedEntry,
- isSearch,
- path
- } = this.props;
- const breadcrumb = [];
- const extraPathItems = [];
- let breadcrumbDropdownContents = [];
- const entryId = isSearch ? highlighted[0] : currentlyViewedEntry;
- if (entryId !== undefined) {
- (path || M.getPath(entryId)).forEach((nodeId, k, path) => {
- let breadcrumbClasses = '';
- let folderType = 'folder';
- if (nodeId === M.RootID) {
- breadcrumbClasses += " cloud-drive";
- } else {
- breadcrumbClasses += " folder";
- }
- if (nodeId.length === 11 && M.u[nodeId]) {
- return;
- }
- if (nodeId === "shares") {
- breadcrumbClasses += " shared-with-me";
- }
- const prevNodeId = path[k - 1];
- let nodeName = this.getBreadcrumbNodeText(nodeId, prevNodeId);
- if ('utils' in s4) {
- const data = s4.utils.getBreadcrumbsData(nodeId);
- if (data) {
- ({
- type: folderType,
- localeName: nodeName
- } = data);
- }
- }
- if (!nodeName) {
- return;
- }
- ((nodeId, k) => {
- if (k < 4) {
- breadcrumb.unshift(REaCt().createElement("a", {
- className: `fm-breadcrumbs contains-directories ${ breadcrumbClasses}`,
- key: nodeId,
- onClick: e => this.onBreadcrumbNodeClick(e, nodeId)
- }, REaCt().createElement("span", {
- className: `right-arrow-bg simpletip`,
- "data-simpletip": nodeName
- }, REaCt().createElement("span", {
- className: "selectable-txt"
- }, nodeName)), k !== 0 && REaCt().createElement("i", {
- className: "next-arrow sprite-fm-mono icon-arrow-right icon16"
- })));
- } else {
- folderType = nodeId === M.RootID ? 'cloud-drive' : folderType;
- if (M.BackupsId && nodeId === M.BackupsId) {
- folderType = 'backups';
- }
- extraPathItems.push({
- name: nodeName,
- type: folderType,
- nodeId
- });
- }
- })(nodeId, k);
- });
- if (extraPathItems.length > 0) {
- breadcrumbDropdownContents = this.getBreadcrumbDropdownContents(extraPathItems);
- }
- }
- return REaCt().createElement("div", {
- ref: this.domRef,
- className: `
- fm-breadcrumbs-wrapper
- ${className || ''}
- `
- }, REaCt().createElement("div", {
- className: "fm-breadcrumbs-block"
- }, breadcrumbDropdownContents.length ? REaCt().createElement(REaCt().Fragment, null, REaCt().createElement("div", {
- className: "crumb-overflow-link"
- }, REaCt().createElement("a", {
- className: "breadcrumb-dropdown-link dropdown",
- onClick: () => {
- this.setState({
- breadcrumbDropdownVisible: !this.state.breadcrumbDropdownVisible
- });
- }
- }, REaCt().createElement("i", {
- className: "menu-icon sprite-fm-mono icon-options icon16"
- })), REaCt().createElement("i", {
- className: "sprite-fm-mono icon-arrow-right icon16"
- })), breadcrumb) : breadcrumb), breadcrumbDropdownContents.length ? REaCt().createElement("div", {
- className: this.state.breadcrumbDropdownVisible ? 'breadcrumb-dropdown active' : 'breadcrumb-dropdown'
- }, breadcrumbDropdownContents) : '');
- }
-}
-// EXTERNAL MODULE: ./js/ui/jsx/fm/fmView.jsx + 10 modules
-const fmView = REQ_(701);
-;// ./js/ui/cloudBrowserModalDialog.jsx
-
-
-
-
-
-const MIN_SEARCH_LENGTH = 2;
-class CloudBrowserDialog extends modalDialogs.A.SafeShowDialogController {
- static getFilterFunction(customFilterFn) {
- return tryCatch(n => {
- if (n.s4 && n.p === M.RootID && M.getS4NodeType(n) === 'container') {
- return false;
- }
- if (!n.name || missingkeys[n.h] || M.getNodeShare(n).down) {
- return false;
- }
- return !customFilterFn || customFilterFn(n);
- });
- }
- constructor(props) {
- super(props);
- this.domRef = REaCt().createRef();
- this.dialogName = 'attach-cloud-dialog';
- this.state = {
- 'isActiveSearch': false,
- 'selected': [],
- 'highlighted': [],
- 'currentlyViewedEntry': M.RootID,
- 'selectedTab': M.RootID,
- 'searchValue': '',
- 'searchText': ''
- };
- this.onAttachClicked = this.onAttachClicked.bind(this);
- this.onClearSearchIconClick = this.onClearSearchIconClick.bind(this);
- this.onPopupDidMount = this.onPopupDidMount.bind(this);
- this.onSearchChange = this.onSearchChange.bind(this);
- this.onSearchIconClick = this.onSearchIconClick.bind(this);
- this.onSelected = this.onSelected.bind(this);
- this.onHighlighted = this.onHighlighted.bind(this);
- this.handleTabChange = this.handleTabChange.bind(this);
- this.onViewModeSwitch = this.onViewModeSwitch.bind(this);
- this.onBreadcrumbNodeClick = this.onBreadcrumbNodeClick.bind(this);
- this.onExpand = this.onExpand.bind(this);
- }
- onViewModeSwitch(newMode) {
- const currentViewMode = mega.config.get('cbvm') | 0;
- if (newMode === currentViewMode) {
- return;
- }
- mega.config.set('cbvm', newMode);
- this.forceUpdate();
- }
- getHeaderButtonsClass() {
- const classes = ['fm-header-buttons'];
- if (this.state.isActiveSearch) {
- classes.push('active-search');
- }
- return classes.join(' ');
- }
- getSearchIconClass() {
- const classes = ['sprite-fm-mono', 'icon-preview-reveal'];
- if (this.state.isActiveSearch && this.state.searchText.length > 0) {
- classes.push('disabled');
- }
- return classes.join(' ');
- }
- onSearchIconClick() {
- const isActiveSearch = !this.state.isActiveSearch;
- if (isActiveSearch) {
- this.searchInput.focus();
- this.setState({
- isActiveSearch
- });
- }
- }
- onClearSearchIconClick() {
- this.setState({
- 'isActiveSearch': false,
- 'searchValue': '',
- 'searchText': '',
- 'currentlyViewedEntry': this.state.selectedTab
- });
- }
- handleTabChange(selectedTab) {
- const s4Cn = selectedTab === 's4' && M.tree.s4 && Object.keys(M.tree.s4);
- this.clearSelectionAndHighlight();
- this.setState({
- selectedTab,
- currentlyViewedEntry: s4Cn && s4Cn.length === 1 ? s4Cn[0] : selectedTab,
- searchValue: '',
- searchText: '',
- isLoading: false
- });
- }
- onSearchBlur() {
- if (this.state.searchText === '') {
- this.setState({
- 'isActiveSearch': false
- });
- }
- }
- onSearchChange(e) {
- const searchValue = e.target.value;
- const newState = {
- searchText: searchValue,
- nodeLoading: searchValue.length >= MIN_SEARCH_LENGTH
- };
- if (searchValue && searchValue.length >= MIN_SEARCH_LENGTH) {
- this.setState(newState);
- delay('cbd:search-proc', this.searchProc.bind(this), 500);
- return;
- }
- if (this.state.currentlyViewedEntry === 'search' && (!searchValue || searchValue.length < MIN_SEARCH_LENGTH)) {
- newState.currentlyViewedEntry = this.state.selectedTab;
- newState.searchValue = undefined;
- }
- this.setState(newState);
- this.clearSelectionAndHighlight();
- }
- searchProc() {
- const {
- searchText
- } = this.state;
- const newState = {
- nodeLoading: true
- };
- if (searchText && searchText.length >= MIN_SEARCH_LENGTH) {
- this.setState(newState);
- M.fmSearchNodes(searchText).then(() => {
- newState.nodeLoading = false;
- newState.searchValue = searchText;
- newState.currentlyViewedEntry = 'search';
- this.setState(newState);
- this.clearSelectionAndHighlight();
- });
- }
- }
- onSelected(nodes) {
- this.setState({
- 'selected': nodes
- });
- this.props.onSelected(nodes);
- }
- onHighlighted(nodes) {
- this.setState({
- 'highlighted': nodes
- });
- if (this.props.onHighlighted) {
- this.props.onHighlighted(nodes);
- }
- }
- clearSelectionAndHighlight() {
- this.onSelected([]);
- this.onHighlighted([]);
- if (selectionManager) {
- selectionManager.clear_selection();
- }
- }
- onPopupDidMount(elem) {
- this.domNode = elem;
- }
- onAttachClicked() {
- this.props.onAttachClicked();
- }
- onBreadcrumbNodeClick(nodeId) {
- if (nodeId === 'shares' || nodeId === 's4') {
- return this.handleTabChange(nodeId);
- }
- if (M.getNodeByHandle(nodeId).t) {
- const nodeRoot = M.getNodeRoot(nodeId);
- this.setState({
- selectedTab: nodeRoot === "contacts" ? 'shares' : nodeRoot,
- currentlyViewedEntry: nodeId,
- selected: [],
- searchValue: '',
- searchText: ''
- });
- }
- }
- onExpand(nodeId) {
- this.setState({
- 'currentlyViewedEntry': nodeId,
- 'searchValue': '',
- 'searchText': '',
- 'selected': [],
- 'highlighted': []
- });
- }
- render() {
- assert(this.dialogBecameVisible);
- const self = this;
- const viewMode = mega.config.get('cbvm') | 0;
- const classes = `add-from-cloud ${self.props.className} dialog-template-tool `;
- let folderIsHighlighted = false;
- let share = false;
- let isS4Cn = false;
- const isSearch = this.state.currentlyViewedEntry === 'search';
- const entryId = isSearch ? self.state.highlighted[0] : self.state.currentlyViewedEntry;
- const filterFn = CloudBrowserDialog.getFilterFunction(this.props.customFilterFn);
- const isIncomingShare = M.getNodeRoot(entryId) === "shares";
- this.state.highlighted.forEach(nodeId => {
- if (M.getNodeByHandle(nodeId).t) {
- folderIsHighlighted = true;
- if (M.tree.s4 && M.tree.s4[nodeId]) {
- isS4Cn = true;
- }
- }
- share = M.getNodeShare(nodeId);
- });
- const buttons = [{
- "label": this.props.cancelLabel,
- "key": "cancel",
- "onClick": e => {
- e.preventDefault();
- e.stopPropagation();
- if (this.props.onCancel) {
- this.props.onCancel(this);
- }
- this.props.onClose(this);
- }
- }];
- if (folderIsHighlighted) {
- const {
- highlighted
- } = this.state;
- const className = `${share && share.down ? 'disabled' : ''}`;
- const highlightedNode = highlighted && highlighted.length && highlighted[0];
- const allowAttachFolders = this.props.allowAttachFolders && !isIncomingShare && !isS4Cn;
- buttons.push({
- "label": this.props.openLabel,
- "key": "select",
- className: `positive ${className} ${highlighted.length > 1 ? 'disabled' : ''}`,
- onClick: e => {
- e.preventDefault();
- e.stopPropagation();
- if (highlighted.length > 1) {
- return;
- }
- this.setState({
- currentlyViewedEntry: highlightedNode
- });
- this.clearSelectionAndHighlight();
- this.setState({
- selected: [],
- searchValue: '',
- searchText: '',
- highlighted: []
- });
- }
- }, allowAttachFolders ? {
- "label": l[8023],
- "key": "attach",
- className: `positive ${ className}`,
- onClick: () => {
- this.props.onClose();
- onIdle(() => {
- const createPublicLink = h => {
- M.createPublicLink(h).then(({
- link
- }) => this.props.room.sendMessage(link));
- };
- const frs = [];
- const files = [];
- for (let i = 0; i < highlighted.length; i++) {
- const node = M.getNodeByHandle(highlighted[i]);
- if (node && M.isFileNode(node)) {
- if (!M.getNodeShare(node).down) {
- files.push(node);
- }
- } else if (mega.fileRequestCommon.storage.isDropExist(highlighted[i]).length) {
- frs.push(highlighted[i]);
- } else {
- createPublicLink(highlighted[i]);
- }
- }
- if (files.length) {
- this.props.onSelected(files);
- this.props.onAttachClicked();
- }
- if (frs.length) {
- const fldName = frs.length > 1 ? l[17626] : l[17403].replace('%1', escapeHTML(M.getNameByHandle(frs[0])) || l[1049]);
- msgDialog('confirmation', l[1003], fldName, l[18229], e => {
- if (e) {
- mega.fileRequest.removeList(frs).then(() => {
- for (let i = 0; i < frs.length; i++) {
- createPublicLink(frs[i]);
- }
- }).catch(dump);
- }
- });
- }
- });
- }
- } : null);
- }
- if (!folderIsHighlighted || this.props.folderSelectable && (!this.props.noShareFolderAttach || !(isIncomingShare && folderIsHighlighted))) {
- buttons.push({
- "label": this.props.selectLabel,
- "key": "select",
- "className": `positive ${ this.state.selected.length === 0 || share && share.down || isS4Cn ? "disabled" : ""}`,
- "onClick": e => {
- if (this.state.selected.length > 0) {
- this.props.onSelected(this.state.selected);
- this.props.onAttachClicked();
- }
- e.preventDefault();
- e.stopPropagation();
- }
- });
- }
- let clearSearchBtn = null;
- if (self.state.searchText.length >= MIN_SEARCH_LENGTH) {
- clearSearchBtn = REaCt().createElement("i", {
- className: "sprite-fm-mono icon-close-component",
- onClick: () => {
- self.onClearSearchIconClick();
- }
- });
- }
- const breadcrumbPath = M.getPath(entryId);
- return REaCt().createElement(modalDialogs.A.ModalDialog, {
- title: self.props.title || l[8011],
- className: classes + (isSearch && this.state.selected.length > 0 ? 'has-breadcrumbs-bottom' : '') + this.dialogName,
- onClose: () => {
- self.props.onClose(self);
- },
- dialogName: "add-from-cloud-dialog dialog-template-tool",
- popupDidMount: self.onPopupDidMount,
- buttons
- }, REaCt().createElement("section", {
- ref: this.domRef,
- className: "content"
- }, REaCt().createElement("div", {
- className: "content-block"
- }, REaCt().createElement("div", {
- className: "fm-dialog-tabs"
- }, REaCt().createElement("div", {
- className: `
- fm-dialog-tab cloud
- ${self.state.selectedTab === M.RootID ? 'active' : ''}
- `,
- onClick: () => self.handleTabChange(M.RootID)
- }, l[164]), REaCt().createElement("div", {
- className: `
- fm-dialog-tab incoming
- ${self.state.selectedTab === 'shares' ? 'active' : ''}
- `,
- onClick: () => self.handleTabChange('shares')
- }, l[5542]), REaCt().createElement("div", {
- className: `
- fm-dialog-tab s4
- ${self.state.selectedTab === 's4' ? 'active' : ''}
- ${u_attr.s4 ? '' : 'hidden'}
- `,
- onClick: () => self.handleTabChange('s4')
- }, l.obj_storage), REaCt().createElement("div", {
- className: "clear"
- })), REaCt().createElement("div", {
- className: "fm-picker-header"
- }, REaCt().createElement("div", {
- className: self.getHeaderButtonsClass()
- }, REaCt().createElement(viewModeSelector, {
- viewMode,
- onChange: this.onViewModeSwitch
- }), REaCt().createElement("div", {
- className: "fm-files-search"
- }, REaCt().createElement("i", {
- className: self.getSearchIconClass(),
- onClick: () => {
- self.onSearchIconClick();
- }
- }), REaCt().createElement("input", {
- ref: input => {
- this.searchInput = input;
- },
- type: "search",
- placeholder: l[102],
- value: self.state.searchText,
- onChange: self.onSearchChange,
- onBlur: () => {
- self.onSearchBlur();
- }
- }), clearSearchBtn), REaCt().createElement("div", {
- className: "clear"
- })), !isSearch && REaCt().createElement(Breadcrumbs, {
- className: "add-from-cloud",
- nodeId: entryId,
- path: breadcrumbPath,
- onNodeClick: this.onBreadcrumbNodeClick,
- isSearch,
- highlighted: this.state.highlighted,
- currentlyViewedEntry: this.state.currentlyViewedEntry
- })), REaCt().createElement(fmView.A, {
- nodeLoading: this.state.nodeLoading,
- sortFoldersFirst: true,
- currentlyViewedEntry: this.state.currentlyViewedEntry,
- customFilterFn: filterFn,
- folderSelectNotAllowed: this.props.folderSelectNotAllowed,
- folderSelectable: this.props.folderSelectable,
- onSelected: this.onSelected,
- onHighlighted: this.onHighlighted,
- onAttachClicked: this.onAttachClicked,
- initialSelected: this.state.selected,
- initialHighlighted: this.state.highlighted,
- searchValue: this.state.searchValue,
- minSearchLength: MIN_SEARCH_LENGTH,
- onExpand: this.onExpand,
- viewMode,
- initialSortBy: ['name', 'asc'],
- fmConfigSortEnabled: true,
- fmConfigSortId: "cbd"
- }), isSearch && breadcrumbPath.length > 0 && REaCt().createElement("div", {
- className: `
- fm-breadcrumbs-wrapper add-from-cloud breadcrumbs-bottom
- `
- }, REaCt().createElement("div", {
- className: "fm-breadcrumbs-block"
- }, REaCt().createElement(Breadcrumbs, {
- nodeId: entryId,
- path: breadcrumbPath,
- onNodeClick: this.onBreadcrumbNodeClick,
- isSearch,
- highlighted: this.state.highlighted,
- currentlyViewedEntry: this.state.currentlyViewedEntry
- }), REaCt().createElement("div", {
- className: "clear"
- }))))));
- }
-}
-CloudBrowserDialog.defaultProps = {
- 'selectLabel': l[8023],
- 'openLabel': l[1710],
- 'cancelLabel': l.msg_dlg_cancel,
- 'hideable': true,
- 'className': ''
-};
-Object.defineProperty(mega, 'CloudBrowserDialog', {
- value: CloudBrowserDialog
-});
-const cloudBrowserModalDialog = {
- CloudBrowserDialog
-};
-// EXTERNAL MODULE: ./js/chat/chatRoom.jsx + 1 modules
-const chat_chatRoom = REQ_(553);
-;// ./js/ui/historyRetentionDialog.jsx
-
-
-
-
-const LIMIT = {
- CHARS: 2,
- HOURS: 24,
- DAYS: 31,
- WEEKS: 4,
- MONTHS: 12
-};
-class HistoryRetentionDialog extends React_.Component {
- constructor(props) {
- super(props);
- this.dialogName = 'msg-retention-dialog';
- this.inputRef = REaCt().createRef();
- this.state = {
- selectedTimeFormat: chat_chatRoom.RETENTION_FORMAT.HOURS,
- timeRange: undefined
- };
- this.handleRadioChange = e => {
- const selectedTimeFormat = e.target.value;
- this.setState(prevState => ({
- selectedTimeFormat,
- timeRange: this.filterTimeRange(prevState.timeRange, selectedTimeFormat)
- }));
- };
- this.handleOnTimeCheck = e => {
- const checkingValue = e.type === 'paste' ? e.clipboardData.getData('text') : e.key;
- if (e.keyCode !== 8 && isNaN(checkingValue)) {
- e.preventDefault();
- }
- };
- this.handleOnTimeChange = e => {
- const timeValue = e.target.value;
- this.setState(prevState => ({
- timeRange: this.filterTimeRange(timeValue, prevState.selectedTimeFormat)
- }));
- };
- const {
- chatRoom
- } = props;
- this.state.timeRange = chatRoom.getRetentionTimeFormatted();
- if (this.state.timeRange === 0) {
- this.state.timeRange = '';
- }
- this.state.selectedTimeFormat = chatRoom.getRetentionFormat();
- this.state.selectedTimeFormat = this.state.selectedTimeFormat === chat_chatRoom.RETENTION_FORMAT.DISABLED ? chat_chatRoom.RETENTION_FORMAT.HOURS : this.state.selectedTimeFormat;
- }
- hasInput() {
- return this.state.timeRange && parseInt(this.state.timeRange, 10) >= 1;
- }
- getMaxTimeRange(selectedTimeFormat) {
- switch (selectedTimeFormat) {
- case chat_chatRoom.RETENTION_FORMAT.HOURS:
- return LIMIT.HOURS;
- case chat_chatRoom.RETENTION_FORMAT.DAYS:
- return LIMIT.DAYS;
- case chat_chatRoom.RETENTION_FORMAT.WEEKS:
- return LIMIT.WEEKS;
- case chat_chatRoom.RETENTION_FORMAT.MONTHS:
- return LIMIT.MONTHS;
- }
- }
- getParsedLabel(label, timeRange) {
- timeRange = timeRange ? parseInt(timeRange, 10) : this.getMaxTimeRange(label);
- switch (label) {
- case chat_chatRoom.RETENTION_FORMAT.HOURS:
- return mega.icu.format(l.plural_hour, timeRange);
- case chat_chatRoom.RETENTION_FORMAT.DAYS:
- return mega.icu.format(l.plural_day, timeRange);
- case chat_chatRoom.RETENTION_FORMAT.WEEKS:
- return mega.icu.format(l.plural_week, timeRange);
- case chat_chatRoom.RETENTION_FORMAT.MONTHS:
- return mega.icu.format(l.plural_month, timeRange);
- }
- }
- filterTimeRange(timeRange, selectedTimeFormat) {
- if (timeRange.length > LIMIT.CHARS) {
- return timeRange.substring(0, LIMIT.CHARS);
- }
- timeRange = parseInt(timeRange, 10);
- if (timeRange === 0 || isNaN(timeRange)) {
- return '';
- }
- return Math.min(this.getMaxTimeRange(selectedTimeFormat), timeRange);
- }
- handleOnSubmit(e) {
- if (!this.hasInput()) {
- return;
- }
- e.preventDefault();
- e.stopPropagation();
- const {
- chatRoom,
- onClose
- } = this.props;
- const {
- selectedTimeFormat,
- timeRange
- } = this.state;
- let time = 0;
- switch (selectedTimeFormat) {
- case chat_chatRoom.RETENTION_FORMAT.HOURS:
- time = hoursToSeconds(Number(timeRange));
- break;
- case chat_chatRoom.RETENTION_FORMAT.DAYS:
- time = daysToSeconds(Number(timeRange));
- break;
- case chat_chatRoom.RETENTION_FORMAT.WEEKS:
- time = daysToSeconds(Number(timeRange) * 7);
- break;
- case chat_chatRoom.RETENTION_FORMAT.MONTHS:
- time = daysToSeconds(Number(timeRange) * 30);
- break;
- }
- chatRoom.setRetention(time);
- onClose();
- }
- renderCustomRadioButton() {
- return [chat_chatRoom.RETENTION_FORMAT.HOURS, chat_chatRoom.RETENTION_FORMAT.DAYS, chat_chatRoom.RETENTION_FORMAT.WEEKS, chat_chatRoom.RETENTION_FORMAT.MONTHS].map(label => {
- return REaCt().createElement(CustomRadioButton, {
- checked: this.state.selectedTimeFormat === label,
- label: this.getParsedLabel(label, this.state.timeRange),
- name: "time-selector",
- value: label,
- onChange: this.handleRadioChange,
- key: label
- });
- });
- }
- componentDidMount() {
- M.safeShowDialog(this.dialogName, () => {
- $(document.body).rebind('keydown.historyRetentionDialog', e => {
- const key = e.keyCode || e.which;
- if (key === 13) {
- this.handleOnSubmit(e);
- }
- });
- });
- }
- componentWillUnmount() {
- $(document.body).off('keydown.historyRetentionDialog');
- if ($.dialog === this.dialogName) {
- closeDialog();
- }
- }
- render() {
- const {
- chatRoom,
- onClose
- } = this.props;
- const {
- selectedTimeFormat,
- timeRange
- } = this.state;
- return REaCt().createElement(modalDialogs.A.ModalDialog, (0,esm_extends.A)({}, this.state, {
- chatRoom,
- onClose,
- dialogName: this.dialogName,
- dialogType: "tool",
- onClick: () => this.inputRef.current.focus()
- }), REaCt().createElement("header", null, REaCt().createElement("h2", {
- id: "msg-retention-dialog-title"
- }, l[23434])), REaCt().createElement("section", {
- className: "content"
- }, REaCt().createElement("div", {
- className: "content-block"
- }, REaCt().createElement("p", null, l[23435])), REaCt().createElement("div", {
- className: "content-block form"
- }, REaCt().createElement("div", {
- className: "form-section"
- }, REaCt().createElement("span", {
- className: "form-section-placeholder"
- }, this.getParsedLabel(selectedTimeFormat, timeRange)), REaCt().createElement("input", {
- type: "number",
- min: "0",
- step: "1",
- max: this.getMaxTimeRange(selectedTimeFormat),
- className: "form-section-time",
- placeholder: this.getMaxTimeRange(selectedTimeFormat),
- ref: this.inputRef,
- autoFocus: true,
- value: timeRange,
- onChange: this.handleOnTimeChange,
- onKeyPress: this.handleOnTimeCheck,
- onPaste: this.handleOnTimeCheck
- })), REaCt().createElement("div", {
- className: "form-section"
- }, REaCt().createElement("div", {
- className: "form-section-radio"
- }, this.renderCustomRadioButton())))), REaCt().createElement("footer", null, REaCt().createElement("div", {
- className: "footer-container"
- }, REaCt().createElement("button", {
- className: "mega-button",
- onClick: onClose
- }, REaCt().createElement("span", null, l.msg_dlg_cancel)), REaCt().createElement("button", {
- className: `
- mega-button positive
- ${this.hasInput() ? '' : 'disabled'}
- `,
- onClick: e => this.handleOnSubmit(e)
- }, REaCt().createElement("span", null, l[726])))));
- }
-}
-function CustomRadioButton({
- checked = false,
- label,
- name,
- value,
- onChange
-}) {
- return REaCt().createElement("label", {
- key: value,
- className: "radio-txt"
- }, label, REaCt().createElement("div", {
- className: `custom-radio small green-active ${ checked ? "radioOn" : "radioOff"}`
- }, REaCt().createElement("input", {
- type: "radio",
- name,
- value,
- checked,
- onChange
- })));
-}
-// EXTERNAL MODULE: ./js/ui/dropdowns.jsx
-const dropdowns = REQ_(911);
-// EXTERNAL MODULE: ./js/chat/ui/contacts.jsx
-const ui_contacts = REQ_(251);
-// EXTERNAL MODULE: ./js/ui/perfectScrollbar.jsx
-const perfectScrollbar = REQ_(486);
-;// ./js/ui/accordion.jsx
-const React = REQ_(594);
-
-class AccordionPanel extends mixins.w9 {
- constructor(...args) {
- super(...args);
- this.domRef = React.createRef();
- }
- render() {
- const {
- accordionClass,
- expanded,
- title,
- className,
- children,
- onToggle
- } = this.props;
- return React.createElement("div", {
- ref: this.domRef,
- className: `
- chat-dropdown
- container
- ${accordionClass || ''}
- `
- }, React.createElement("div", {
- className: `
- chat-dropdown
- header
- ${expanded ? 'expanded' : ''}
- `,
- onClick: onToggle
- }, React.createElement("span", null, title), React.createElement("i", {
- className: "sprite-fm-mono icon-arrow-down"
- })), expanded ? React.createElement("div", {
- className: `
- chat-dropdown
- content
- have-animation
- ${className | ''}
- `
- }, children) : null);
- }
-}
-class Accordion extends mixins.w9 {
- constructor(...args) {
- super(...args);
- this.domRef = React.createRef();
- this.state = {
- expandedPanel: this.props.expandedPanel
- };
- }
- onToggle(e, key) {
- const obj = {};
- obj[key] = !(this.state.expandedPanel || {})[key];
- this.setState({
- 'expandedPanel': obj
- });
- this.props.onToggle && this.props.onToggle(key);
- }
- render() {
- const self = this;
- const classes = `accordion-panels ${ self.props.className ? self.props.className : ''}`;
- const accordionPanels = [];
- let x = 0;
- React.Children.forEach(self.props.children, child => {
- if (!child) {
- return;
- }
- if (child.type.name === 'AccordionPanel' || child.type.name && child.type.name.indexOf('AccordionPanel') > -1) {
- accordionPanels.push(React.cloneElement(child, {
- key: child.key,
- expanded: !!self.state.expandedPanel[child.key],
- accordion: self,
- onToggle (e) {
- self.onToggle(e, child.key);
- }
- }));
- } else {
- accordionPanels.push(React.cloneElement(child, {
- key: x++,
- accordion: self
- }));
- }
- });
- return React.createElement("div", {
- ref: this.domRef,
- className: classes
- }, accordionPanels);
- }
-}
-
-;// ./js/chat/ui/participantsList.jsx
-
-
-const DropdownsUI = REQ_(911);
-const ContactsUI = REQ_(251);
-const PerfectScrollbar = REQ_(486).O;
-class ParticipantsList extends mixins.w9 {
- constructor(props) {
- super(props);
- this.domRef = REaCt().createRef();
- this.state = {
- 'scrollPositionY': 0,
- 'scrollHeight': 144
- };
- this.doResizesOnComponentUpdate = SoonFc(10, function () {
- let _self$domRef;
- const self = this;
- if (!self.isMounted()) {
- return;
- }
- let fitHeight = self.contactsListScroll.getContentHeight();
- if (!fitHeight) {
- return null;
- }
- const $node = $((_self$domRef = self.domRef) == null ? void 0 : _self$domRef.current);
- const $parentContainer = $node.closest('.chat-right-pad');
- const maxHeight = $parentContainer.outerHeight(true) - $('.chat-right-head', $parentContainer).outerHeight(true) - 72;
- if (fitHeight < $('.buttons-block', $parentContainer).outerHeight(true)) {
- fitHeight = Math.max(fitHeight, 53);
- } else if (maxHeight < fitHeight) {
- fitHeight = Math.max(maxHeight, 53);
- }
- fitHeight = Math.min(self.calculateListHeight($parentContainer), fitHeight);
- const $contactsList = $('.chat-contacts-list', $parentContainer);
- if ($contactsList.height() !== fitHeight) {
- $('.chat-contacts-list', $parentContainer).height(fitHeight);
- if (self.contactsListScroll) {
- self.contactsListScroll.reinitialise();
- }
- }
- if (self.state.scrollHeight !== fitHeight) {
- self.setState({
- 'scrollHeight': fitHeight
- });
- }
- self.onUserScroll();
- });
- }
- onUserScroll() {
- if (!this.contactsListScroll) {
- return;
- }
- const scrollPosY = this.contactsListScroll.getScrollPositionY();
- if (this.state.scrollPositionY !== scrollPosY) {
- this.setState({
- 'scrollPositionY': scrollPosY
- });
- }
- }
- calculateListHeight($parentContainer) {
- const room = this.props.chatRoom;
- return ($parentContainer ? $parentContainer : $('.conversationsApp')).outerHeight() - 144 - 10 - (room.type === "public" && room.observers > 0 ? 48 : 0) - (room.isReadOnly() ? 12 : 0);
- }
- componentDidUpdate() {
- const self = this;
- if (!self.isMounted()) {
- return;
- }
- if (!self.contactsListScroll) {
- return null;
- }
- self.doResizesOnComponentUpdate();
- }
- render() {
- const {
- chatRoom
- } = this.props;
- if (!chatRoom) {
- return null;
- }
- return REaCt().createElement("div", {
- ref: this.domRef,
- className: "chat-contacts-list"
- }, REaCt().createElement(PerfectScrollbar, {
- chatRoom,
- members: chatRoom.members,
- ref: ref => {
- this.contactsListScroll = ref;
- },
- disableCheckingVisibility: true,
- onUserScroll: SoonFc(this.onUserScroll.bind(this), 76),
- requiresUpdateOnResize: true,
- isVisible: chatRoom.isCurrentlyActive,
- options: {
- suppressScrollX: true
- }
- }, REaCt().createElement(ParticipantsListInner, {
- chatRoom,
- members: chatRoom.members,
- scrollPositionY: this.state.scrollPositionY,
- scrollHeight: this.state.scrollHeight,
- disableCheckingVisibility: true
- })));
- }
-}
-ParticipantsList.defaultProps = {
- 'requiresUpdateOnResize': true,
- 'contactCardHeight': 36
-};
-class ParticipantsListInner extends mixins.w9 {
- constructor(...args) {
- super(...args);
- this.domRef = REaCt().createRef();
- }
- render() {
- const room = this.props.chatRoom;
- const {contactCardHeight} = this.props;
- const {scrollPositionY} = this.props;
- const {scrollHeight} = this.props;
- const {
- OPERATOR,
- FULL,
- READONLY
- } = ChatRoom.MembersSet.PRIVILEGE_STATE;
- if (!room) {
- return null;
- }
- if (!room.isCurrentlyActive) {
- return false;
- }
- const contacts = room.getParticipantsExceptMe();
- const contactsList = [];
- const firstVisibleUserNum = Math.floor(scrollPositionY / contactCardHeight);
- const visibleUsers = Math.ceil(scrollHeight / contactCardHeight);
- const contactListInnerStyles = {
- 'height': contacts.length * contactCardHeight
- };
- if ((room.type === "group" || room.type === "public") && !room.stateIsLeftOrLeaving() && room.members.hasOwnProperty(u_handle)) {
- contacts.unshift(u_handle);
- contactListInnerStyles.height += contactCardHeight;
- }
- const onRemoveClicked = contactHash => {
- room.trigger('onRemoveUserRequest', [contactHash]);
- };
- const onSetPrivClicked = (contactHash, priv) => {
- if (room.members[contactHash] !== priv) {
- room.trigger('alterUserPrivilege', [contactHash, priv]);
- }
- };
- for (let i = 0; i < contacts.length; i++) {
- const contactHash = contacts[i];
- if (!(contactHash in M.u)) {
- continue;
- }
- const contact = M.u[contactHash];
- if (i < firstVisibleUserNum || i > firstVisibleUserNum + visibleUsers) {
- continue;
- }
- const dropdowns = [];
- let dropdownIconClasses = "small-icon tiny-icon icons-sprite grey-dots";
- const dropdownRemoveButton = [];
- if (room.type === "public" || room.type === "group" && room.members) {
- if (room.iAmOperator() && contactHash !== u_handle) {
- dropdownRemoveButton.push(REaCt().createElement(DropdownsUI.DropdownItem, {
- className: "red",
- key: "remove",
- icon: "sprite-fm-mono icon-disabled-filled",
- label: l[8867],
- onClick: onRemoveClicked.bind(this, contactHash)
- }));
- }
- if (room.iAmOperator()) {
- dropdowns.push(REaCt().createElement("div", {
- key: "setPermLabel",
- className: "dropdown-items-info"
- }, l[8868]));
- dropdowns.push(REaCt().createElement(DropdownsUI.DropdownItem, {
- key: "privOperator",
- icon: "sprite-fm-mono icon-admin-outline",
- label: l[8875],
- className: `
- tick-item
- ${room.members[contactHash] === OPERATOR ? 'active' : ''}
- `,
- disabled: contactHash === u_handle,
- onClick: () => onSetPrivClicked(contactHash, OPERATOR)
- }));
- dropdowns.push(REaCt().createElement(DropdownsUI.DropdownItem, {
- key: "privFullAcc",
- icon: "sprite-fm-mono icon-chat",
- className: `
- tick-item
- ${room.members[contactHash] === FULL ? 'active' : ''}
- `,
- disabled: contactHash === u_handle,
- label: l[8874],
- onClick: () => onSetPrivClicked(contactHash, FULL)
- }));
- dropdowns.push(REaCt().createElement(DropdownsUI.DropdownItem, {
- key: "privReadOnly",
- icon: "sprite-fm-mono icon-read-only",
- className: `
- tick-item
- ${room.members[contactHash] === READONLY ? 'active' : ''}
- `,
- disabled: contactHash === u_handle,
- label: l[8873],
- onClick: () => onSetPrivClicked(contactHash, READONLY)
- }));
- }
- const baseClassName = 'sprite-fm-mono';
- switch (room.members[contactHash]) {
- case OPERATOR:
- dropdownIconClasses = `${baseClassName} icon-admin`;
- break;
- case FULL:
- dropdownIconClasses = `${baseClassName} icon-chat-filled`;
- break;
- case READONLY:
- dropdownIconClasses = `${baseClassName} icon-read-only`;
- break;
- default:
- break;
- }
- contactsList.push(REaCt().createElement(ContactsUI.ContactCard, {
- key: contact.u,
- contact,
- chatRoom: room,
- className: "right-chat-contact-card",
- dropdownPositionMy: "left top",
- dropdownPositionAt: "left top",
- dropdowns,
- dropdownDisabled: contactHash === u_handle || is_chatlink || is_eplusplus,
- dropdownButtonClasses: "contacts-icon",
- dropdownRemoveButton,
- dropdownIconClasses,
- noLoading: true,
- isInCall: room.uniqueCallParts && room.uniqueCallParts[contactHash],
- style: {
- width: 234,
- position: 'absolute',
- top: i * contactCardHeight
- }
- }));
- }
- }
- return REaCt().createElement("div", {
- ref: this.domRef,
- className: "chat-contacts-list-inner default-bg",
- style: contactListInnerStyles
- }, contactsList);
- }
-}
-ParticipantsListInner.defaultProps = {
- requiresUpdateOnResize: true,
- contactCardHeight: 32,
- scrollPositionY: 0,
- scrollHeight: 128,
- chatRoom: undefined
-};
-
-// EXTERNAL MODULE: ./js/chat/ui/messages/generic.jsx + 14 modules
-const generic = REQ_(890);
-;// ./js/chat/ui/sharedFilesAccordionPanel.jsx
-
-let _dec, _class;
-const sharedFilesAccordionPanel_React = REQ_(594);
-
-
-class SharedFileItem extends mixins.u9 {
- render() {
- const self = this;
- const {message} = this.props;
- const contact = Message.getContactForMessage(message);
- const name = M.getNameByHandle(contact.u);
- const timestamp = time2date(message.delay);
- const {node} = this.props;
- const {icon} = this.props;
- return sharedFilesAccordionPanel_React.createElement("div", {
- className: `chat-shared-block ${ self.props.isLoading ? "is-loading" : ""}`,
- key: `${message.messageId }_${ node.h}`,
- onClick: () => this.props.isPreviewable ? M.viewMediaFile(node) : M.addDownload([node]),
- onDoubleClick: () => M.addDownload([node])
- }, sharedFilesAccordionPanel_React.createElement("div", {
- className: `icon-or-thumb ${thumbnails.has(node.fa) ? "thumb" : ""}`
- }, sharedFilesAccordionPanel_React.createElement("div", {
- className: `item-type-icon-90 icon-${icon}-90`
- }), sharedFilesAccordionPanel_React.createElement("div", {
- className: "img-wrapper",
- id: this.props.imgId
- }, sharedFilesAccordionPanel_React.createElement("img", {
- alt: "",
- src: thumbnails.get(node.fa) || ""
- }))), sharedFilesAccordionPanel_React.createElement("div", {
- className: "chat-shared-info"
- }, sharedFilesAccordionPanel_React.createElement("span", {
- className: "txt"
- }, node.name), sharedFilesAccordionPanel_React.createElement("span", {
- className: "txt small"
- }, sharedFilesAccordionPanel_React.createElement(utils.zT, null, name)), sharedFilesAccordionPanel_React.createElement("span", {
- className: "txt small grey"
- }, timestamp)));
- }
-}
-const SharedFilesAccordionPanel = (_dec = utils.Ay.SoonFcWrap(350), _class = class SharedFilesAccordionPanel extends mixins.w9 {
- constructor(...args) {
- super(...args);
- this.domRef = sharedFilesAccordionPanel_React.createRef();
- }
- eventuallyRenderThumbnails() {
- if (this.allShownNodes) {
- const pending = [];
- const nodes = new Map(this.allShownNodes);
- const render = n => {
- if (thumbnails.has(n.fa)) {
- const src = thumbnails.get(n.fa);
- const batch = [...nodes.get(n.fa)];
- for (let i = batch.length; i--;) {
- const n = batch[i];
- let img = document.getElementById(`sharedFiles!${n.ch}`);
- if (img && (img = img.querySelector('img'))) {
- img.src = src;
- if (img = Object(img.parentNode).parentNode) {
- img.classList.add('thumb');
- }
- }
- }
- return true;
- }
- };
- for (const [, [n]] of nodes) {
- if (!render(n)) {
- pending.push(n);
- }
- }
- this.allShownNodes.clear();
- if (pending.length) {
- fm_thumbnails('standalone', pending, render);
- }
- }
- }
- UNSAFE_componentWillMount() {
- this.allShownNodes = new MapSet();
- }
- componentWillUnmount() {
- super.componentWillUnmount();
- delete this.allShownNodes;
- }
- componentDidUpdate() {
- this.eventuallyRenderThumbnails();
- }
- render() {
- const self = this;
- const room = self.props.chatRoom;
- const mb = room.messagesBuff;
- let contents = null;
- let currentPage = mb.sharedFilesPage;
- const startPos = currentPage * 12;
- const endPos = startPos + 12;
- let totalPages = mb.haveMoreSharedFiles ? "..." : Math.ceil(mb.sharedFiles.length / 12);
- totalPages = mb.sharedFiles.length && !totalPages ? 1 : totalPages;
- const haveMore = mb.haveMoreSharedFiles || currentPage + 1 < totalPages;
- const files = [];
- if (!mb.haveMoreSharedFiles && currentPage === totalPages) {
- currentPage = mb.sharedFilesPage = Math.max(totalPages - 1, 0);
- }
- if (this.props.expanded) {
- let prev = null;
- let next = null;
- if (currentPage > 0) {
- prev = sharedFilesAccordionPanel_React.createElement("div", {
- className: "chat-share-nav button prev",
- onClick () {
- mb.sharedFilesPage--;
- self.safeForceUpdate();
- }
- });
- }
- if (haveMore) {
- next = sharedFilesAccordionPanel_React.createElement("div", {
- className: "chat-share-nav button next",
- onClick () {
- if (self.isLoadingMore) {
- return;
- }
- if (mb.sharedFiles.length < endPos + 12) {
- self.isLoadingMore = true;
- mb.retrieveSharedFilesHistory(12).catch(dump).finally(() => {
- self.isLoadingMore = false;
- mb.sharedFilesPage++;
- if (!mb.haveMoreSharedFiles && mb.sharedFilesPage > totalPages) {
- mb.sharedFilesPage = totalPages - 1;
- }
- Soon(() => {
- self.safeForceUpdate();
- });
- });
- } else {
- mb.sharedFilesPage++;
- }
- Soon(() => {
- self.safeForceUpdate();
- });
- }
- });
- }
- if (!mb.sharedFilesLoadedOnce) {
- mb.retrieveSharedFilesHistory(12).then(() => this.safeForceUpdate()).catch(dump);
- }
- let sharedNodesContainer = null;
- if (mb.isRetrievingSharedFiles && !self.isLoadingMore) {
- sharedNodesContainer = sharedFilesAccordionPanel_React.createElement("div", {
- className: "chat-dropdown empty-txt loading-initial"
- }, sharedFilesAccordionPanel_React.createElement("div", {
- className: "loading-spinner light small"
- }, sharedFilesAccordionPanel_React.createElement("div", {
- className: "main-loader"
- })));
- } else if (!mb.haveMoreSharedFiles && !mb.sharedFiles.length) {
- sharedNodesContainer = sharedFilesAccordionPanel_React.createElement("div", {
- className: "chat-dropdown empty-txt"
- }, l[19985]);
- } else {
- const keys = clone(mb.sharedFiles.keys()).reverse();
- for (let i = startPos; i < endPos; i++) {
- var message = mb.sharedFiles[keys[i]];
- if (!message) {
- continue;
- }
- const nodes = message.getAttachmentMeta();
- nodes.forEach((node) => {
- const imgId = `sharedFiles!${ node.ch}`;
- const {
- icon,
- showThumbnail,
- isPreviewable
- } = M.getMediaProperties(node);
- files.push(sharedFilesAccordionPanel_React.createElement(SharedFileItem, {
- message,
- key: `${node.h}_${message.messageId}`,
- isLoading: self.isLoadingMore,
- node,
- icon,
- imgId,
- showThumbnail,
- isPreviewable,
- chatRoom: room,
- contact: Message.getContactForMessage(message)
- }));
- if (showThumbnail) {
- self.allShownNodes.set(node.fa, node);
- }
- });
- }
- sharedNodesContainer = sharedFilesAccordionPanel_React.createElement("div", null, files);
- }
- contents = sharedFilesAccordionPanel_React.createElement("div", {
- className: "chat-dropdown content have-animation"
- }, room.hasMessages() ? sharedNodesContainer : sharedFilesAccordionPanel_React.createElement("div", {
- className: "chat-dropdown empty-txt"
- }, l[19985]), self.isLoadingMore ? sharedFilesAccordionPanel_React.createElement("div", {
- className: "loading-spinner light small"
- }, sharedFilesAccordionPanel_React.createElement("div", {
- className: "main-loader"
- })) : null, files.length > 0 ? sharedFilesAccordionPanel_React.createElement("div", {
- className: "chat-share-nav body"
- }, prev, next, sharedFilesAccordionPanel_React.createElement("div", {
- className: "chat-share-nav pages"
- }, (l[19988] ? l[19988] : "Page %1").replace("%1", currentPage + 1))) : null);
- }
- return sharedFilesAccordionPanel_React.createElement("div", {
- ref: this.domRef,
- className: "chat-dropdown container"
- }, sharedFilesAccordionPanel_React.createElement("div", {
- className: `
- chat-dropdown
- header
- ${this.props.expanded ? 'expanded' : ''}
- `,
- onClick: this.props.onToggle
- }, sharedFilesAccordionPanel_React.createElement("span", null, this.props.title), sharedFilesAccordionPanel_React.createElement("i", {
- className: "sprite-fm-mono icon-arrow-down"
- })), sharedFilesAccordionPanel_React.createElement("div", {
- className: `
- chat-shared-files-container
- ${this.isLoadingMore ? 'is-loading' : ''}
- `
- }, contents));
- }
-}, (0,applyDecoratedDescriptor.A)(_class.prototype, "eventuallyRenderThumbnails", [_dec], Object.getOwnPropertyDescriptor(_class.prototype, "eventuallyRenderThumbnails"), _class.prototype), _class);
-
-;// ./js/chat/ui/incomingSharesAccordionPanel.jsx
-const incomingSharesAccordionPanel_React = REQ_(594);
-
-const SharedFolderItem = ({
- node,
- isLoading
-}) => {
- return incomingSharesAccordionPanel_React.createElement("div", {
- key: node.h,
- className: `
- chat-shared-block
- incoming
- ${isLoading ? 'is-loading' : ''}
- `,
- onClick: () => M.openFolder(node.h),
- onDoubleClick: () => M.openFolder(node.h)
- }, incomingSharesAccordionPanel_React.createElement("div", {
- className: "item-type-icon-90 icon-folder-incoming-90"
- }), incomingSharesAccordionPanel_React.createElement("div", {
- className: "chat-shared-info"
- }, incomingSharesAccordionPanel_React.createElement("span", {
- className: "txt"
- }, node.name), incomingSharesAccordionPanel_React.createElement("span", {
- className: "txt small"
- }, fm_contains(node.tf, node.td))));
-};
-class IncSharesAccordionPanel extends mixins.w9 {
- constructor(...args) {
- super(...args);
- this.domRef = incomingSharesAccordionPanel_React.createRef();
- }
- UNSAFE_componentWillMount() {
- this.hadLoaded = false;
- }
- getContactHandle() {
- const self = this;
- const room = self.props.chatRoom;
- const contactHandle = room.getParticipantsExceptMe()[0];
- if (!contactHandle || room.type !== "private") {
- return {};
- }
- return contactHandle;
- }
- render() {
- const self = this;
- const room = self.props.chatRoom;
- const contactHandle = self.getContactHandle();
- let contents = null;
- if (this.props.expanded) {
- if (!this.hadLoaded) {
- this.hadLoaded = true;
- self.isLoadingMore = true;
- dbfetch.geta(Object.keys(M.c.shares || {}), new MegaPromise()).always(() => {
- self.isLoadingMore = false;
- Soon(() => {
- if (self.isComponentEventuallyVisible()) {
- self.safeForceUpdate();
- }
- }, 5000);
- });
- }
- let incomingSharesContainer = null;
- const sharedFolders = M.c[contactHandle] && Object.keys(M.c[contactHandle]) || [];
- if (!self.isLoadingMore && (!sharedFolders || sharedFolders.length === 0)) {
- incomingSharesContainer = incomingSharesAccordionPanel_React.createElement("div", {
- className: "chat-dropdown empty-txt"
- }, l[19986]);
- } else {
- const haveMore = sharedFolders.length > 10;
- const defSortFn = M.getSortByNameFn();
- sharedFolders.sort((a, b) => {
- const nodeA = M.d[a];
- const nodeB = M.d[b];
- return defSortFn(nodeA, nodeB, -1);
- });
- const renderNodes = [];
- for (let i = 0; i < Math.min(sharedFolders.length, 10); i++) {
- const nodeHandle = sharedFolders[i];
- const node = M.d[nodeHandle];
- if (!node) {
- continue;
- }
- renderNodes.push(incomingSharesAccordionPanel_React.createElement(SharedFolderItem, {
- key: node.h,
- isLoading: self.isLoadingMore,
- node,
- chatRoom: room
- }));
- }
- incomingSharesContainer = incomingSharesAccordionPanel_React.createElement("div", null, renderNodes, haveMore ? incomingSharesAccordionPanel_React.createElement("div", {
- className: "chat-share-nav body"
- }, incomingSharesAccordionPanel_React.createElement("div", {
- className: "chat-share-nav show-all",
- onClick () {
- M.openFolder(contactHandle);
- }
- }, incomingSharesAccordionPanel_React.createElement("span", {
- className: "item-type-icon icon-folder-incoming-24"
- }, incomingSharesAccordionPanel_React.createElement("span", {
- className: "item-type-icon icon-folder-incoming-24"
- })), incomingSharesAccordionPanel_React.createElement("span", {
- className: "txt"
- }, l[19797] ? l[19797] : "Show All"))) : null);
- }
- contents = incomingSharesAccordionPanel_React.createElement("div", {
- className: "chat-dropdown content have-animation"
- }, incomingSharesContainer, self.isLoadingMore ? incomingSharesAccordionPanel_React.createElement("div", {
- className: "chat-dropdown empty-txt"
- }, incomingSharesAccordionPanel_React.createElement("div", {
- className: "loading-spinner light small"
- }, incomingSharesAccordionPanel_React.createElement("div", {
- className: "main-loader"
- }))) : null);
- }
- return incomingSharesAccordionPanel_React.createElement("div", {
- ref: this.domRef,
- className: "chat-dropdown container"
- }, incomingSharesAccordionPanel_React.createElement("div", {
- className: `
- chat-dropdown
- header
- ${this.props.expanded ? 'expanded' : ''}
- `,
- onClick: this.props.onToggle
- }, incomingSharesAccordionPanel_React.createElement("span", null, this.props.title), incomingSharesAccordionPanel_React.createElement("i", {
- className: "sprite-fm-mono icon-arrow-down"
- })), incomingSharesAccordionPanel_React.createElement("div", {
- className: `
- chat-shared-files-container
- ${this.isLoadingMore ? 'is-loading' : ''}
- `
- }, contents));
- }
-}
-
-;// ./js/chat/ui/chatlinkDialog.jsx
-
-
-
-
-class ChatlinkDialog extends REaCt().Component {
- constructor(...args) {
- super(...args);
- this.domRef = REaCt().createRef();
- this.state = {
- link: l[5533],
- newTopic: ''
- };
- this.onClose = () => {
- if (this.props.onClose) {
- this.props.onClose();
- }
- };
- }
- retrieveChatLink(forced) {
- const {
- chatRoom
- } = this.props;
- if (is_chatlink) {
- return this.setState({
- link: `${getBaseUrl()}/chat/${is_chatlink.ph}#${is_chatlink.key}`
- });
- }
- if (!chatRoom.topic && !forced) {
- delete this.loading;
- return;
- }
- this.loading = chatRoom.updatePublicHandle(false, true).always(() => {
- this.loading = false;
- if (this.domRef.current) {
- this.setState({
- link: chatRoom.publicLink ? `${getBaseUrl()}/${chatRoom.publicLink}` : l[20660]
- });
- }
- });
- }
- componentDidMount() {
- this.retrieveChatLink();
- M.safeShowDialog(ChatlinkDialog.NAMESPACE, () => {
- if (!this.domRef.current) {
- throw new Error(`${ChatlinkDialog.NAMESPACE} dialog: component not mounted.`);
- }
- return $(`#${ChatlinkDialog.NAMESPACE}`);
- });
- }
- componentWillUnmount() {
- if ($.dialog === ChatlinkDialog.NAMESPACE) {
- closeDialog();
- }
- }
- render() {
- const {
- chatRoom
- } = this.props;
- const {
- newTopic,
- link
- } = this.state;
- const closeButton = this.loading ? null : REaCt().createElement("button", {
- key: "close",
- className: "mega-button negative links-button",
- onClick: this.onClose
- }, REaCt().createElement("span", null, l[148]));
- const publicLinkDetails = chatRoom.isMeeting ? l.meeting_link_details : l[20644];
- return REaCt().createElement("div", {
- ref: this.domRef
- }, REaCt().createElement(modalDialogs.A.ModalDialog, (0,esm_extends.A)({}, this.state, {
- id: ChatlinkDialog.NAMESPACE,
- title: chatRoom.iAmOperator() && !chatRoom.topic ? chatRoom.isMeeting ? l.rename_meeting : l[9080] : '',
- className: `
- chat-rename-dialog
- export-chat-links-dialog
- group-chat-link
- ${chatRoom.topic ? '' : 'requires-topic'}
- `,
- onClose: this.onClose,
- dialogName: "chat-link-dialog",
- dialogType: chatRoom.iAmOperator() && !chatRoom.topic ? 'main' : 'graphic',
- chatRoom,
- popupDidMount: this.onPopupDidMount
- }), chatRoom.iAmOperator() && !chatRoom.topic ? REaCt().createElement("section", {
- className: "content"
- }, REaCt().createElement("div", {
- className: "content-block"
- }, REaCt().createElement("div", {
- className: "export-chat-ink-warning"
- }, l[20617]), REaCt().createElement("div", {
- className: "rename-input-bl",
- style: {
- margin: '10px auto 20px auto'
- }
- }, REaCt().createElement("input", {
- type: "text",
- name: "newTopic",
- value: newTopic,
- style: {
- paddingLeft: 8
- },
- onChange: ev => this.setState({
- newTopic: ev.target.value
- }),
- onKeyPress: ev => ev.which === 13 && chatRoom.setRoomTopic(newTopic).then(() => this.retrieveChatLink(true)).catch(dump),
- placeholder: l[20616],
- maxLength: ChatRoom.TOPIC_MAX_LENGTH
- })))) : REaCt().createElement(REaCt().Fragment, null, REaCt().createElement("header", null, chatRoom.isMeeting ? REaCt().createElement("div", {
- className: "chat-topic-icon meeting-icon"
- }, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-video-call-filled"
- })) : REaCt().createElement("i", {
- className: "sprite-fm-uni icon-chat-group"
- }), REaCt().createElement("h2", {
- id: "chat-link-dialog-title"
- }, REaCt().createElement(utils.zT, null, chatRoom.getRoomTitle()))), REaCt().createElement("section", {
- className: "content"
- }, REaCt().createElement("div", {
- className: "content-block"
- }, REaCt().createElement("div", {
- className: "chat-link-input"
- }, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-link-small"
- }), REaCt().createElement("input", {
- type: "text",
- readOnly: true,
- value: this.loading ? l[5533] : !chatRoom.topic ? l[20660] : link
- })), REaCt().createElement("div", {
- className: "info"
- }, chatRoom.publicLink || is_chatlink ? publicLinkDetails : null)))), REaCt().createElement("footer", null, REaCt().createElement("div", {
- className: "footer-container"
- }, chatRoom.iAmOperator() && chatRoom.publicLink && REaCt().createElement("button", {
- key: "deleteLink",
- className: `
- mega-button
- links-button
- ${this.loading ? 'disabled' : ''}
- `,
- onClick: () => {
- chatRoom.updatePublicHandle(1);
- this.onClose();
- }
- }, REaCt().createElement("span", null, chatRoom.isMeeting ? l.meeting_link_delete : l[20487])), chatRoom.topic ? chatRoom.publicLink || is_chatlink ? REaCt().createElement("button", {
- className: `
- mega-button
- positive
- copy-to-clipboard
- ${this.loading ? 'disabled' : ''}
- `,
- onClick: () => {
- copyToClipboard(link, l[7654]);
- if (chatRoom.isMeeting) {
- eventlog(500231);
- }
- }
- }, REaCt().createElement("span", null, l[63])) : closeButton : chatRoom.iAmOperator() ? REaCt().createElement("button", {
- key: "setTopic",
- className: `
- mega-button
- positive
- links-button
- ${newTopic && newTopic.trim() ? '' : 'disabled'}
- `,
- onClick: () => chatRoom.setRoomTopic(newTopic).then(() => this.retrieveChatLink(true)).catch(dump)
- }, REaCt().createElement("span", null, l[20615])) : closeButton))));
- }
-}
-ChatlinkDialog.defaultProps = {
- requiresUpdateOnResize: true,
- disableCheckingVisibility: true
-};
-ChatlinkDialog.NAMESPACE = 'chat-link-dialog';
-;// ./js/chat/ui/pushSettingsDialog.jsx
-
-let _PushSettingsDialog;
-
-
-class PushSettingsDialog extends REaCt().Component {
- constructor(props) {
- super(props);
- this.renderOptions = () => {
- return Object.keys(PushSettingsDialog.options).map(key => {
- key = parseInt(key, 10) || Infinity;
- return REaCt().createElement("label", {
- key,
- className: "radio-txt"
- }, PushSettingsDialog.options[key], REaCt().createElement("div", {
- className: `custom-radio small green-active ${ this.state.pushSettingsValue === key ? "radioOn" : "radioOff"}`
- }, REaCt().createElement("input", {
- type: "radio",
- name: "time-selector",
- value: key,
- checked: this.state.pushSettingsValue === key,
- onChange: () => this.setState({
- pushSettingsValue: key
- })
- })));
- });
- };
- this.state = {
- pushSettingsValue: this.props.pushSettingsValue || Infinity
- };
- }
- render() {
- return REaCt().createElement(modalDialogs.A.ModalDialog, (0,esm_extends.A)({}, this.state, {
- name: "push-settings",
- title: l.dnd_mute_title,
- subtitle: this.props.room.isMeeting ? l.meeting_dnd_subtitle : l[22015],
- className: "push-settings-dialog",
- dialogName: "push-settings-chat-dialog",
- dialogType: "tool",
- onClose: this.props.onClose
- }), REaCt().createElement("section", {
- className: "content"
- }, REaCt().createElement("div", {
- className: "content-block"
- }, REaCt().createElement("div", null, this.renderOptions()))), REaCt().createElement("footer", null, REaCt().createElement("div", {
- className: "footer-container"
- }, REaCt().createElement("button", {
- className: "mega-button",
- onClick: this.props.onClose
- }, REaCt().createElement("span", null, l.msg_dlg_cancel)), REaCt().createElement("button", {
- className: "mega-button positive",
- onClick: () => this.props.onConfirm(this.state.pushSettingsValue)
- }, REaCt().createElement("span", null, l[726])))));
- }
-}
-_PushSettingsDialog = PushSettingsDialog;
-PushSettingsDialog.options = {
- 30: l[22012],
- 60: l[19048],
- 360: l[22013],
- 1440: l[22014],
- Infinity: l[22011]
-};
-PushSettingsDialog.default = _PushSettingsDialog.options[_PushSettingsDialog.options.length - 1];
-// EXTERNAL MODULE: ./js/chat/ui/meetings/call.jsx + 11 modules
-const call = REQ_(3);
-// EXTERNAL MODULE: ./js/chat/ui/historyPanel.jsx + 7 modules
-const historyPanel = REQ_(814);
-// EXTERNAL MODULE: ./js/chat/ui/composedTextArea.jsx + 1 modules
-const composedTextArea = REQ_(77);
-;// ./js/chat/ui/meetings/workflow/loading.jsx
-
-class Loading extends REaCt().Component {
- constructor(...args) {
- super(...args);
- this.domRef = REaCt().createRef();
- this.PERMISSIONS = {
- VIDEO: 'camera',
- AUDIO: 'microphone'
- };
- this.state = {
- pendingPermissions: false
- };
- this.queryPermissions = name => {
- navigator.permissions.query({
- name
- }).then(status => {
- const {
- name,
- state
- } = status;
- status.onchange = () => name === 'audio_capture' && this.queryPermissions(this.PERMISSIONS.VIDEO);
- if (state === 'prompt') {
- return this.domRef.current && this.setState({
- pendingPermissions: name
- });
- }
- }).catch(ex => console.warn(`Failed to get permissions state: ${ex}`));
- };
- this.renderLoading = () => {
- return REaCt().createElement(REaCt().Fragment, null, REaCt().createElement("span", null, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-video-call-filled"
- })), REaCt().createElement("h3", null, this.props.title || l[5533]), REaCt().createElement("div", {
- className: "loading-container"
- }, REaCt().createElement("div", {
- className: "loading-indication"
- })));
- };
- this.renderDebug = () => {
- const {
- chatRoom
- } = this.props;
- if (chatRoom && chatRoom.call) {
- return REaCt().createElement("div", {
- className: `${Loading.NAMESPACE}-debug`
- }, REaCt().createElement("div", null, "callId: ", chatRoom.call.callId), REaCt().createElement("div", null, "roomId: ", chatRoom.roomId), REaCt().createElement("div", null, "isMeeting: ", chatRoom.isMeeting ? 'true' : 'false'));
- }
- };
- }
- componentWillUnmount() {
- megaChat.unbind(`onLocalMediaQueryError.${Loading.NAMESPACE}`);
- }
- componentDidMount() {
- let _notify, _alarm;
- document.dispatchEvent(new Event('closeDropdowns'));
- if ($.dialog) {
- closeDialog == null || closeDialog();
- }
- mega.ui.mInfoPanel.hide();
- (_notify = notify) == null || _notify.closePopup();
- (_alarm = alarm) == null || _alarm.hideAllWarningPopups();
- document.querySelectorAll('.js-dropdown-account').forEach(({
- classList
- }) => classList.contains('show') && classList.remove('show'));
- const {
- chatRoom
- } = this.props;
- const {
- audio,
- video
- } = chatRoom.meetingsLoading;
- const isVideoCall = audio && video;
- if (audio && !video) {
- this.queryPermissions(this.PERMISSIONS.AUDIO);
- }
- if (isVideoCall) {
- Object.values(this.PERMISSIONS).forEach(name => this.queryPermissions(name));
- }
- megaChat.rebind(`onLocalMediaQueryError.${Loading.NAMESPACE}`, (ev, {
- type,
- err
- }) => {
- if (isVideoCall && type === 'mic' && String(err).includes('dismissed')) {
- this.queryPermissions(this.PERMISSIONS.VIDEO);
- }
- });
- }
- render() {
- const {
- pendingPermissions
- } = this.state;
- return REaCt().createElement("div", {
- ref: this.domRef,
- className: Loading.NAMESPACE
- }, REaCt().createElement("div", {
- className: `${Loading.NAMESPACE}-content`
- }, pendingPermissions ? REaCt().createElement("h2", null, pendingPermissions === 'audio_capture' ? l.permissions_allow_mic : l.permissions_allow_camera) : this.renderLoading()), d ? this.renderDebug() : '');
- }
-}
-Loading.NAMESPACE = 'meetings-loading';
-// EXTERNAL MODULE: ./js/chat/ui/meetings/button.jsx
-const meetings_button = REQ_(959);
-// EXTERNAL MODULE: ./js/chat/ui/meetings/workflow/preview.jsx
-const preview = REQ_(485);
-// EXTERNAL MODULE: ./js/chat/ui/link.jsx
-const ui_link = REQ_(280);
-;// ./js/chat/ui/meetings/workflow/join.jsx
-
-
-
-
-
-
-
-class Join extends REaCt().Component {
- constructor(props) {
- super(props);
- this.state = {
- preview: false,
- view: Join.VIEW.INITIAL,
- firstName: '',
- lastName: '',
- previewAudio: true,
- previewVideo: false,
- ephemeralDialog: false
- };
- this.handleKeyDown = ({
- key
- }) => {
- let _this$props$onClose, _this$props;
- return key && key === 'Escape' ? (_this$props$onClose = (_this$props = this.props).onClose) == null ? void 0 : _this$props$onClose.call(_this$props) : true;
- };
- this.showPanels = () => {
- return [document.querySelector('.nw-fm-left-icons-panel'), document.querySelector('.chat-app-container')].map(el => el && el.classList.remove('hidden'));
- };
- this.hidePanels = () => {
- return [document.querySelector('.nw-fm-left-icons-panel'), document.querySelector('.chat-app-container')].map(el => el && el.classList.add('hidden'));
- };
- this.showConfirmationDialog = () => {
- megaChat.destroy();
- return mega.ui.sendSignupLinkDialog(JSON.parse(localStorage.awaitingConfirmationAccount), () => {
- delete localStorage.awaitingConfirmationAccount;
- u_logout(true).then(() => location.reload());
- });
- };
- this.Ephemeral = () => {
- const onCancel = () => this.setState({
- ephemeralDialog: false
- });
- const msgFragments = l.ephemeral_data_lost.split(/\[A]|\[\/A]/);
- return REaCt().createElement(modalDialogs.A.ModalDialog, {
- name: "end-ephemeral",
- dialogType: "message",
- icon: "sprite-fm-uni icon-warning",
- title: l.ephemeral_data_lost_title,
- noCloseOnClickOutside: true,
- buttons: [{
- key: 'cancel',
- label: l.msg_dlg_cancel,
- onClick: onCancel
- }, {
- key: 'continue',
- label: l[507],
- className: 'positive',
- onClick: () => {
- u_logout(true).then(() => location.reload());
- sessionStorage.guestForced = true;
- }
- }],
- onClose: onCancel
- }, REaCt().createElement("p", null, msgFragments[0], REaCt().createElement(ui_link.A, {
- to: "/register",
- onClick: () => loadSubPage('register')
- }, msgFragments[1]), msgFragments[2]));
- };
- this.Head = () => {
- let _this$props$chatRoom;
- return REaCt().createElement("div", {
- className: `${Join.NAMESPACE}-head`
- }, REaCt().createElement("div", {
- className: `${Join.NAMESPACE}-logo`
- }, REaCt().createElement("i", {
- className: `
- sprite-fm-illustration-wide
- ${mega.ui.isDarkTheme() ? 'mega-logo-dark' : 'img-mega-logo-light'}
- `
- })), REaCt().createElement("h1", null, REaCt().createElement(utils.zT, null, l.you_have_invitation.replace('%1', (_this$props$chatRoom = this.props.chatRoom) == null ? void 0 : _this$props$chatRoom.topic))), isEphemeral() && REaCt().createElement("div", {
- className: "ephemeral-info"
- }, REaCt().createElement("i", {
- className: "sprite-fm-uni icon-warning"
- }), REaCt().createElement("p", null, l.ephemeral_data_store_lost)));
- };
- this.Intro = () => {
- const $$CONTAINER = ({
- children
- }) => REaCt().createElement(REaCt().Fragment, null, REaCt().createElement("div", {
- className: `${Join.NAMESPACE}-content`
- }, children), this.Chat());
- if (isEphemeral()) {
- return REaCt().createElement($$CONTAINER, null, REaCt().createElement(meetings_button.A, {
- className: "mega-button positive",
- onClick: () => this.setState({
- ephemeralDialog: true
- })
- }, l.join_as_guest), REaCt().createElement(meetings_button.A, {
- className: "mega-button",
- onClick: () => loadSubPage('register')
- }, l[5582]), REaCt().createElement("span", null, l[5585], REaCt().createElement("a", {
- href: "#",
- onClick: () => mega.ui.showLoginRequiredDialog({
- minUserType: 3,
- skipInitialDialog: 1
- }).done(() => this.setState({
- view: Join.VIEW.ACCOUNT
- }))
- }, l[171])));
- }
- return REaCt().createElement($$CONTAINER, null, REaCt().createElement(meetings_button.A, {
- className: "mega-button positive",
- onClick: () => this.setState({
- view: Join.VIEW.GUEST
- })
- }, l.join_as_guest), REaCt().createElement(meetings_button.A, {
- className: "mega-button",
- onClick: () => {
- let _this$props$chatRoom2;
- megaChat.loginOrRegisterBeforeJoining((_this$props$chatRoom2 = this.props.chatRoom) == null ? void 0 : _this$props$chatRoom2.publicChatHandle, false, true, undefined, () => this.setState({
- view: Join.VIEW.ACCOUNT
- }));
- }
- }, l[171]), REaCt().createElement("p", null, REaCt().createElement(utils.P9, {
- onClick: e => {
- e.preventDefault();
- megaChat.loginOrRegisterBeforeJoining(this.props.chatRoom.publicChatHandle, true, undefined, undefined, () => this.setState({
- view: Join.VIEW.ACCOUNT
- }));
- }
- }, l[20635])));
- };
- this.Chat = () => {
- const {
- chatRoom
- } = this.props;
- const {
- preview
- } = this.state;
- return REaCt().createElement("div", {
- className: `
- ${Join.NAMESPACE}-chat
- ${preview ? 'expanded' : ''}
- `
- }, REaCt().createElement("div", {
- className: "chat-content"
- }, REaCt().createElement("div", {
- className: "chat-content-head",
- onClick: () => this.setState({
- preview: !preview
- })
- }, REaCt().createElement(utils.zT, null, chatRoom.topic), REaCt().createElement(meetings_button.A, {
- icon: "icon-minimise"
- })), preview && REaCt().createElement("div", {
- className: "chat-body"
- }, REaCt().createElement(historyPanel.A, {
- chatRoom,
- onMount: cmp => {
- let _cmp$messagesListScro;
- return (_cmp$messagesListScro = cmp.messagesListScrollable) == null ? void 0 : _cmp$messagesListScro.scrollToBottom();
- }
- }))));
- };
- this.Card = ({
- children
- }) => {
- const {
- previewAudio,
- previewVideo
- } = this.state;
- return REaCt().createElement("div", {
- className: "card"
- }, REaCt().createElement("div", {
- className: "card-body"
- }, children, REaCt().createElement("div", null, REaCt().createElement(ui_link.A, {
- to: "https://mega.io/chatandmeetings",
- target: "_blank"
- }, l.how_meetings_work))), REaCt().createElement("div", {
- className: "card-preview"
- }, REaCt().createElement(preview.A, {
- audio: previewAudio,
- video: previewVideo,
- context: Join.NAMESPACE,
- onToggle: (audio, video) => this.setState({
- previewAudio: audio,
- previewVideo: video
- })
- })));
- };
- this.Field = ({
- name,
- children
- }) => {
- let _this$state$name;
- return REaCt().createElement("div", {
- className: `
- mega-input
- title-ontop
- ${(_this$state$name = this.state[name]) != null && _this$state$name.length ? 'valued' : ''}
- `
- }, REaCt().createElement("div", {
- className: "mega-input-title"
- }, children, REaCt().createElement("span", {
- className: "required-red"
- }, "*")), REaCt().createElement("input", {
- type: "text",
- name,
- className: "titleTop required megaInputs",
- placeholder: children,
- value: this.state[name] || '',
- maxLength: 40,
- onChange: ev => this.setState({
- [name]: ev.target.value
- })
- }));
- };
- this.Guest = () => REaCt().createElement(this.Card, null, REaCt().createElement("h2", null, l.enter_name_join_meeting), REaCt().createElement("div", {
- className: "card-fields"
- }, REaCt().createElement(this.Field, {
- name: "firstName"
- }, l[1096]), REaCt().createElement(this.Field, {
- name: "lastName"
- }, l[1097])), REaCt().createElement(meetings_button.A, {
- className: `
- mega-button
- positive
- large
- ${this.state.firstName.length && this.state.lastName.length ? '' : 'disabled'}
- ${this.state.joining && " loading disabled"}
- `,
- onClick: () => {
- if (this.state.joining) {
- return;
- }
- let {
- firstName,
- lastName,
- previewAudio,
- previewVideo
- } = this.state;
- firstName = firstName && firstName.trim();
- lastName = lastName && lastName.trim();
- if (firstName && lastName && firstName.length > 0 && lastName.length > 0) {
- this.setState({
- 'joining': true
- });
- if (this.props.chatRoom.scheduledMeeting) {
- delay('chat-event-sm-guest-join', () => eventlog(99929));
- }
- this.props.onJoinGuestClick(firstName, lastName, previewAudio, previewVideo);
- }
- }
- }, l.join_chat_button));
- this.Account = () => REaCt().createElement(this.Card, null, REaCt().createElement("h4", null, l.join_meeting), REaCt().createElement(meetings_button.A, {
- className: `mega-button positive large ${this.state.joining && " loading disabled"}`,
- onClick: () => {
- if (!this.state.joining) {
- this.setState({
- 'joining': true
- });
- this.props.onJoinClick(this.state.previewAudio, this.state.previewVideo);
- }
- }
- }, l.join_chat_button));
- this.Unsupported = () => REaCt().createElement("div", {
- className: "meetings-unsupported-container"
- }, REaCt().createElement("i", {
- className: "sprite-fm-uni icon-error"
- }), REaCt().createElement("div", {
- className: "unsupported-info"
- }, REaCt().createElement("h3", null, l.heading_unsupported_browser), REaCt().createElement("h3", null, l.join_meeting_methods), REaCt().createElement("ul", null, REaCt().createElement("li", null, l.join_via_link), REaCt().createElement("li", null, REaCt().createElement(utils.P9, null, l.join_via_mobile.replace('[A]', '').replace('[/A]', ''))))));
- this.View = view => {
- switch (view) {
- default:
- return this.Intro();
- case Join.VIEW.GUEST:
- return this.Guest();
- case Join.VIEW.ACCOUNT:
- return this.Account();
- case Join.VIEW.UNSUPPORTED:
- return this.Unsupported();
- }
- };
- this.state.view = sessionStorage.guestForced ? Join.VIEW.GUEST : props.initialView || this.state.view;
- if (localStorage.awaitingConfirmationAccount) {
- this.showConfirmationDialog();
- }
- }
- componentDidMount() {
- document.addEventListener('keydown', this.handleKeyDown);
- this.hidePanels();
- megaChat._joinDialogIsShown = true;
- alarm.hideAllWarningPopups();
- sessionStorage.removeItem('guestForced');
- if (!megaChat.hasSupportForCalls) {
- this.setState({
- view: Join.VIEW.UNSUPPORTED
- });
- }
- }
- componentWillUnmount() {
- document.removeEventListener('keydown', this.handleKeyDown);
- this.showPanels();
- megaChat._joinDialogIsShown = false;
- if (this.props.onClose) {
- this.props.onClose();
- }
- }
- render() {
- const {
- view,
- ephemeralDialog
- } = this.state;
- return REaCt().createElement(utils.Ay.RenderTo, {
- element: document.body
- }, REaCt().createElement("div", {
- className: Join.NAMESPACE
- }, this.Head(), this.View(view), ephemeralDialog && REaCt().createElement(this.Ephemeral, null)));
- }
-}
-Join.NAMESPACE = 'join-meeting';
-Join.VIEW = {
- INITIAL: 0,
- GUEST: 1,
- ACCOUNT: 2,
- UNSUPPORTED: 4
-};
-;// ./js/chat/ui/meetings/workflow/alert.jsx
-
-
-const NAMESPACE = 'meetings-alert';
-class Alert extends mixins.w9 {
- constructor(...args) {
- super(...args);
- this.domRef = REaCt().createRef();
- }
- componentWillUnmount() {
- let _this$props$onTransit, _this$props;
- super.componentWillUnmount();
- (_this$props$onTransit = (_this$props = this.props).onTransition) == null || _this$props$onTransit.call(_this$props);
- }
- componentDidUpdate() {
- let _this$props$onTransit2, _this$props2;
- super.componentDidUpdate();
- (_this$props$onTransit2 = (_this$props2 = this.props).onTransition) == null || _this$props$onTransit2.call(_this$props2, this.domRef);
- }
- componentDidMount() {
- let _this$props$onTransit3, _this$props3;
- super.componentDidMount();
- (_this$props$onTransit3 = (_this$props3 = this.props).onTransition) == null || _this$props$onTransit3.call(_this$props3, this.domRef);
- }
- render() {
- const {
- type,
- className,
- content,
- children,
- offset,
- onClose
- } = this.props;
- if (content || children) {
- return REaCt().createElement("div", {
- ref: this.domRef,
- className: `
- ${NAMESPACE}
- ${type ? `${NAMESPACE}-${type}` : ''}
- ${className || ''}
- `,
- style: offset ? {
- marginTop: `${offset}px`
- } : undefined
- }, REaCt().createElement("div", {
- className: `${NAMESPACE}-content`
- }, content || children), onClose && REaCt().createElement("span", {
- className: `${NAMESPACE}-close`,
- onClick: onClose
- }, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-close-component"
- })));
- }
- return null;
- }
-}
-Alert.TYPE = {
- LIGHT: 'light',
- NEUTRAL: 'neutral',
- MEDIUM: 'medium',
- HIGH: 'high',
- ERROR: 'error'
-};
-// EXTERNAL MODULE: ./js/chat/ui/meetings/schedule/helpers.jsx
-const helpers = REQ_(110);
-// EXTERNAL MODULE: ./js/chat/ui/meetings/hostsObserver.jsx
-const hostsObserver = REQ_(972);
-;// ./js/chat/ui/meetings/waitingRoom/waitingRoom.jsx
-
-
-
-
-
-
-const waitingRoom_NAMESPACE = 'waiting-room';
-const VIEW = {
- INTRO: 0,
- ACCOUNT: 1,
- GUEST: 2,
- AWAIT: 3,
- UNSUPPORTED: 4,
- REDIRECT: 5
-};
-class WaitingRoom extends mixins.w9 {
- constructor(props) {
- super(props);
- this.domRef = REaCt().createRef();
- this.redirectInterval = undefined;
- this.state = {
- view: VIEW.ACCOUNT,
- call: false,
- audio: false,
- video: false,
- firstName: '',
- lastName: '',
- countdown: 4,
- loading: false
- };
- this.renderLeaveDialog = () => msgDialog(`confirmation:!^${l.wr_leave}!${l.wr_do_not_leave}`, null, l.wr_leave_confirmation, '', cb => {
- if (cb) {
- delay('chat-event-wr-leave', () => eventlog(99938));
- this.doLeave();
- }
- }, 1);
- this.renderDeniedDialog = () => msgDialog('error', '', l.wr_denied, l.wr_denied_details, this.doLeave);
- this.renderTimeoutDialog = () => msgDialog('error', '', l.wr_timeout, l.wr_timeout_details, this.doLeave);
- this.renderWaitingRoomInfo = () => {
- const {
- chatRoom
- } = this.props;
- const {
- nextOccurrenceStart,
- nextOccurrenceEnd
- } = chatRoom.scheduledMeeting || {};
- return REaCt().createElement(REaCt().Fragment, null, REaCt().createElement(utils.P9, {
- tag: "h2",
- content: megaChat.html(chatRoom.topic)
- }), REaCt().createElement("div", {
- className: `${waitingRoom_NAMESPACE}-schedule`
- }, REaCt().createElement("span", null, time2date(nextOccurrenceStart / 1000, 20)), REaCt().createElement("span", null, toLocaleTime(nextOccurrenceStart), " - ", toLocaleTime(nextOccurrenceEnd))));
- };
- this.doLeave = () => this.setState({
- view: VIEW.REDIRECT
- }, () => {
- tSleep(this.state.countdown).then(() => this.props.onWaitingRoomLeave());
- this.redirectInterval = setInterval(() => this.setState(({
- countdown
- }) => ({
- countdown: countdown > 0 ? countdown - 1 : 0
- })), 1e3);
- sessionStorage.removeItem('previewMedia');
- });
- this.setInitialView = () => {
- if (u_type || is_eplusplus) {
- let _this$props$chatRoom;
- return (_this$props$chatRoom = this.props.chatRoom) != null && _this$props$chatRoom.iAmInRoom() ? VIEW.AWAIT : VIEW.ACCOUNT;
- }
- return VIEW.INTRO;
- };
- this.requestJoin = () => {
- let _this$props$chatRoom2;
- const {
- audio,
- video
- } = this.state;
- (_this$props$chatRoom2 = this.props.chatRoom) == null || _this$props$chatRoom2.joinCall(audio, video);
- };
- this.Field = ({
- name,
- children
- }) => {
- let _this$state$name;
- return REaCt().createElement("div", {
- className: `
- mega-input
- title-ontop
- ${(_this$state$name = this.state[name]) != null && _this$state$name.length ? 'valued' : ''}
- `
- }, REaCt().createElement("div", {
- className: "mega-input-title"
- }, children, REaCt().createElement("span", {
- className: "required-red"
- }, "*")), REaCt().createElement("input", {
- type: "text",
- name,
- className: "titleTop required megaInputs",
- placeholder: children,
- value: this.state[name] || '',
- maxLength: 40,
- onChange: ev => this.setState({
- [name]: ev.target.value
- })
- }));
- };
- this.Card = ({
- className,
- children
- }) => {
- const {
- audio,
- video
- } = this.state;
- return REaCt().createElement("div", {
- className: `
- card
- ${className || ''}
- `
- }, REaCt().createElement("div", {
- className: "card-body"
- }, children), REaCt().createElement("div", {
- className: "card-preview"
- }, REaCt().createElement(preview.A, {
- audio,
- video,
- onToggle: (audio, video) => {
- this.setState({
- audio,
- video
- }, () => {
- sessionStorage.previewMedia = JSON.stringify({
- audio,
- video
- });
- });
- }
- })));
- };
- this.Head = ({
- title
- }) => {
- let _this$props$chatRoom3;
- return REaCt().createElement("div", {
- className: `${waitingRoom_NAMESPACE}-head`
- }, REaCt().createElement("div", {
- className: `${waitingRoom_NAMESPACE}-logo`
- }, REaCt().createElement("i", {
- className: `
- sprite-fm-illustration-wide
- ${mega.ui.isDarkTheme() ? 'mega-logo-dark' : 'img-mega-logo-light'}
- `
- })), REaCt().createElement("h1", {
- className: (megaChat.initialChatId || is_chatlink) && this.state.view !== VIEW.INTRO ? 'hidden' : ''
- }, REaCt().createElement(utils.zT, null, title || l.you_have_invitation.replace('%1', (_this$props$chatRoom3 = this.props.chatRoom) == null ? void 0 : _this$props$chatRoom3.topic))));
- };
- this.Await = () => {
- return REaCt().createElement(REaCt().Fragment, null, megaChat.initialChatId ? REaCt().createElement(this.Head, null) : null, REaCt().createElement(this.Card, {
- className: megaChat.initialChatId ? '' : 'fit-spacing'
- }, this.renderWaitingRoomInfo(), REaCt().createElement("div", {
- className: `${waitingRoom_NAMESPACE}-message`
- }, this.state.call ? l.wr_wait_to_admit : l.wr_wait_to_start), REaCt().createElement(meetings_button.A, {
- icon: "sprite-fm-mono icon-log-out-thin-solid",
- className: `${waitingRoom_NAMESPACE}-leave`,
- onClick: () => this.renderLeaveDialog()
- }, l.wr_leave)));
- };
- this.Account = () => {
- const {
- loading,
- audio,
- video
- } = this.state;
- return REaCt().createElement(REaCt().Fragment, null, REaCt().createElement(this.Head, null), REaCt().createElement(this.Card, null, this.renderWaitingRoomInfo(), REaCt().createElement(meetings_button.A, {
- className: `
- mega-button
- positive
- large
- ${loading ? 'disabled' : ''}
- `,
- onClick: () => {
- return loading ? null : this.setState({
- loading: true
- }, () => {
- const {
- chatRoom
- } = this.props;
- const {
- chatId,
- publicChatHandle,
- publicChatKey
- } = chatRoom;
- if (chatRoom.iAmInRoom()) {
- return megaChat.routing.reinitAndOpenExistingChat(chatId, publicChatHandle).then(() => {
- megaChat.getChatById(chatId).joinCall(audio, video);
- }).catch(ex => console.error(`Failed to open existing room and join call: ${ex}`));
- }
- megaChat.routing.reinitAndJoinPublicChat(chatId, publicChatHandle, publicChatKey).then(() => {
- delete megaChat.initialPubChatHandle;
- }).catch(ex => console.error(`Failed to join room: ${ex}`));
- });
- }
- }, l.wr_ask_to_join), REaCt().createElement("div", null, REaCt().createElement(ui_link.A, {
- to: "https://mega.io/chatandmeetings",
- target: "_blank"
- }, l.how_meetings_work))));
- };
- this.Redirect = () => REaCt().createElement(REaCt().Fragment, null, REaCt().createElement(this.Head, {
- title: l.wr_left_heading
- }), REaCt().createElement("h5", null, l.wr_left_countdown.replace('%1', this.state.countdown)));
- this.Guest = () => {
- const {
- chatRoom
- } = this.props;
- const {
- loading,
- firstName,
- lastName
- } = this.state;
- const isDisabled = !firstName.length || !lastName.length;
- return REaCt().createElement(REaCt().Fragment, null, REaCt().createElement(this.Head, null), REaCt().createElement(this.Card, null, this.renderWaitingRoomInfo(), REaCt().createElement("div", {
- className: "card-fields"
- }, REaCt().createElement(this.Field, {
- name: "firstName"
- }, l[1096]), REaCt().createElement(this.Field, {
- name: "lastName"
- }, l[1097])), REaCt().createElement(meetings_button.A, {
- className: `
- mega-button
- positive
- large
- ${isDisabled || loading ? 'disabled' : ''}
- `,
- onClick: () => {
- if (isDisabled || loading) {
- return false;
- }
- return this.setState({
- loading: true
- }, () => {
- u_eplusplus(this.state.firstName, this.state.lastName).then(() => {
- return megaChat.routing.reinitAndJoinPublicChat(chatRoom.chatId, chatRoom.publicChatHandle, chatRoom.publicChatKey);
- }).catch(ex => d && console.error(`E++ account failure: ${ex}`));
- });
- }
- }, l.wr_ask_to_join), REaCt().createElement("div", null, REaCt().createElement(ui_link.A, {
- to: "https://mega.io/chatandmeetings",
- target: "_blank"
- }, l.how_meetings_work))));
- };
- this.Intro = () => {
- const {
- chatRoom
- } = this.props;
- return REaCt().createElement(REaCt().Fragment, null, REaCt().createElement(this.Head, null), REaCt().createElement("div", {
- className: "join-meeting-content"
- }, REaCt().createElement(meetings_button.A, {
- className: "mega-button positive",
- onClick: () => {
- megaChat.loginOrRegisterBeforeJoining(chatRoom.publicChatHandle, false, true, undefined, () => this.setState({
- view: VIEW.ACCOUNT
- }));
- }
- }, l[171]), REaCt().createElement(meetings_button.A, {
- className: "mega-button",
- onClick: () => this.setState({
- view: VIEW.GUEST
- })
- }, l.join_as_guest), REaCt().createElement("p", null, REaCt().createElement(utils.P9, {
- onClick: e => {
- e.preventDefault();
- megaChat.loginOrRegisterBeforeJoining(chatRoom.publicChatHandle, true, undefined, undefined, () => this.setState({
- view: VIEW.ACCOUNT
- }));
- }
- }, l[20635]))));
- };
- this.Unsupported = () => {
- let _this$props$chatRoom4;
- return REaCt().createElement(REaCt().Fragment, null, REaCt().createElement(this.Head, null), REaCt().createElement("h1", null, l.you_have_invitation.replace('%1', (_this$props$chatRoom4 = this.props.chatRoom) == null ? void 0 : _this$props$chatRoom4.topic)), REaCt().createElement("div", {
- className: "meetings-unsupported-container"
- }, REaCt().createElement("i", {
- className: "sprite-fm-uni icon-error"
- }), REaCt().createElement("div", {
- className: "unsupported-info"
- }, REaCt().createElement("h3", null, l.heading_unsupported_browser), REaCt().createElement("h3", null, l.join_meeting_methods), REaCt().createElement("ul", null, REaCt().createElement("li", null, l.join_via_link), REaCt().createElement("li", null, REaCt().createElement(utils.P9, null, l.join_via_mobile.replace('[A]', '').replace('[/A]', '')))))));
- };
- this.renderView = view => {
- switch (view) {
- default:
- return this.Await();
- case VIEW.INTRO:
- return this.Intro();
- case VIEW.GUEST:
- return this.Guest();
- case VIEW.ACCOUNT:
- return this.Account();
- case VIEW.REDIRECT:
- return this.Redirect();
- case VIEW.UNSUPPORTED:
- return this.Unsupported();
- }
- };
- this.state.call = this.props.havePendingCall;
- this.state.view = megaChat.hasSupportForCalls ? this.setInitialView() : VIEW.UNSUPPORTED;
- if (sessionStorage.previewMedia) {
- const {
- audio,
- video
- } = JSON.parse(sessionStorage.previewMedia);
- this.state.audio = audio;
- this.state.video = video;
- sessionStorage.removeItem('previewMedia');
- }
- }
- UNSAFE_componentWillReceiveProps(nextProps) {
- if (this.props.havePendingCall !== nextProps.havePendingCall) {
- this.setState({
- call: nextProps.havePendingCall
- }, () => this.state.view === VIEW.AWAIT && nextProps.havePendingCall && this.requestJoin());
- }
- }
- componentWillUnmount() {
- super.componentWillUnmount();
- clearInterval(this.redirectInterval);
- this.props.chatRoom.unbind(`onCallLeft.${waitingRoom_NAMESPACE}`);
- this.props.chatRoom.unbind(`onModeratorAdd.${waitingRoom_NAMESPACE}`);
- }
- componentDidMount() {
- super.componentDidMount();
- const {
- chatRoom
- } = this.props;
- const {
- call,
- view
- } = this.state;
- if (call && view === VIEW.AWAIT) {
- this.requestJoin();
- }
- chatRoom.rebind(`onCallLeft.${waitingRoom_NAMESPACE}`, (ev, {
- termCode
- }) => {
- if (termCode === SfuClient.TermCode.kKickedFromWaitingRoom) {
- return this.renderDeniedDialog();
- }
- if (termCode === SfuClient.TermCode.kWaitingRoomAllowTimeout) {
- delay('chat-event-wr-timeout', () => eventlog(99939));
- return this.renderTimeoutDialog();
- }
- });
- chatRoom.rebind(`onModeratorAdd.${waitingRoom_NAMESPACE}`, (ev, user) => {
- if (user === u_handle) {
- chatRoom.meetingsLoading = false;
- this.requestJoin();
- }
- });
- }
- render() {
- const {
- view
- } = this.state;
- return REaCt().createElement(utils.Ay.RenderTo, {
- element: document.body
- }, REaCt().createElement("div", {
- ref: this.domRef,
- className: `
- ${waitingRoom_NAMESPACE}
- join-meeting
- ${view === VIEW.AWAIT ? `${waitingRoom_NAMESPACE}--await` : ''}
- ${view === VIEW.AWAIT && !megaChat.initialChatId ? 'theme-dark-forced' : ''}
- ${view === VIEW.REDIRECT ? `${waitingRoom_NAMESPACE}--redirect` : ''}
- ${megaChat.initialChatId || is_chatlink ? `${waitingRoom_NAMESPACE}--chatlink-landing` : ''}
- `
- }, this.renderView(view)));
- }
-}
-// EXTERNAL MODULE: ./js/chat/ui/meetings/streamControls.jsx
-const streamControls = REQ_(489);
-// EXTERNAL MODULE: ./js/chat/ui/inviteParticipantsPanel.jsx
-const inviteParticipantsPanel = REQ_(815);
-;// ./js/chat/ui/chatOverlay.jsx
-
-
-
-const chatOverlay_NAMESPACE = 'chat-overlay';
-const ChatOverlays = {
- PARTICIPANT_LIMIT: 'participants-limit'
-};
-class ChatOverlay extends REaCt().Component {
- constructor(...args) {
- super(...args);
- this.MegaLogo = () => REaCt().createElement("div", {
- className: `${chatOverlay_NAMESPACE}-logo`
- }, REaCt().createElement("i", {
- className: `sprite-fm-illustration-wide ${mega.ui.isDarkTheme() ? 'mega-logo-dark' : 'img-mega-logo-light'}`
- }));
- }
- renderParticipantsLimit() {
- return REaCt().createElement(REaCt().Fragment, null, REaCt().createElement("div", {
- className: `${chatOverlay_NAMESPACE}-head`
- }, REaCt().createElement(this.MegaLogo, null), REaCt().createElement("h1", null, l.join_call_user_limit_title)), REaCt().createElement("div", {
- className: `${chatOverlay_NAMESPACE}-body`
- }, REaCt().createElement("p", null, l.call_join_user_limit_banner), REaCt().createElement(buttons.$, {
- className: "mega-button positive",
- onClick: () => {
- let _this$props$onClose, _this$props;
- (_this$props$onClose = (_this$props = this.props).onClose) == null || _this$props$onClose.call(_this$props);
- }
- }, l.call_link_user_limit_button)));
- }
- render() {
- const {
- overlayType
- } = this.props;
- let body = null;
- if (overlayType === ChatOverlays.PARTICIPANT_LIMIT) {
- body = this.renderParticipantsLimit();
- }
- if (!body) {
- if (d) {
- console.error('Invalid ChatOverlay', overlayType);
- }
- return null;
- }
- return REaCt().createElement(utils.Ay.RenderTo, {
- element: document.body
- }, REaCt().createElement("div", {
- className: `${chatOverlay_NAMESPACE} ${overlayType}`
- }, body));
- }
-}
-
-;// ./js/chat/ui/conversationpanel.jsx
-
-
-let conversationpanel_dec, _dec2, conversationpanel_class;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-const ENABLE_GROUP_CALLING_FLAG = true;
-const MAX_USERS_CHAT_PRIVATE = 100;
-const ALERTS_BASE_OFFSET = 4;
-const DISMISS_TRANSITIONS = {
- NOT_SHOWN: 0,
- SHOWN: 1,
- DISMISSED: 2
-};
-class EndCallButton extends REaCt().Component {
- constructor(...args) {
- super(...args);
- this.IS_MODERATOR = call.Ay.isModerator(this.props.chatRoom, u_handle);
- this.LeaveButton = (0,hostsObserver.C)(({
- hasHost,
- chatRoom,
- confirmLeave,
- onLeave
- }) => {
- return REaCt().createElement(dropdowns.DropdownItem, {
- className: "link-button",
- icon: "sprite-fm-mono icon-leave-call",
- label: l.leave,
- persistent: true,
- onClick: () => {
- const doLeave = () => hasHost(chatRoom.call ? chatRoom.call.peers.map(a => a.userHandle) : []) ? onLeave() : confirmLeave({
- title: l.assign_host_leave_call,
- body: l.assign_host_leave_call_details,
- cta: l.assign_host_button,
- altCta: l.leave_anyway
- });
- const {
- recorderCid,
- sfuClient
- } = chatRoom.call;
- return recorderCid && recorderCid === sfuClient.cid ? (0,streamControls.sX)(doLeave, () => sfuClient.recordingStop()) : doLeave();
- }
- });
- });
- }
- renderButton({
- label,
- onClick,
- children = null,
- disabled
- }) {
- return REaCt().createElement(buttons.$, {
- className: `
- link-button
- light
- red
- dropdown-element
- ${disabled ? 'disabled' : ''}
- `,
- icon: "small-icon colorized horizontal-red-handset",
- label,
- onClick: disabled ? null : onClick
- }, children);
- }
- render() {
- const {
- chatRoom
- } = this.props;
- const {
- type,
- call
- } = chatRoom;
- if (call) {
- const peers = call.peers && call.peers.length;
- if (type === 'private') {
- return this.renderButton({
- label: l[5884],
- onClick: () => call.hangUp()
- });
- }
- if (this.IS_MODERATOR) {
- const doEnd = () => chatRoom.endCallForAll();
- return this.renderButton({
- label: l[5884],
- onClick: peers ? null : () => call.hangUp(),
- children: peers && REaCt().createElement(dropdowns.Dropdown, {
- className: "wide-dropdown light end-call-selector",
- noArrow: "true",
- vertOffset: 4,
- horizOffset: 0
- }, REaCt().createElement(this.LeaveButton, {
- chatRoom,
- participants: chatRoom.getCallParticipants(),
- onLeave: () => call.hangUp(),
- onConfirmDenied: () => call.hangUp()
- }), REaCt().createElement(dropdowns.DropdownItem, {
- className: "link-button",
- icon: "sprite-fm-mono icon-contacts",
- label: l.end_for_all,
- onClick: () => {
- const {
- recorderCid,
- sfuClient
- } = call;
- return recorderCid && recorderCid === u_handle ? (0,streamControls._F)(doEnd, () => sfuClient.recordingStop()) : doEnd();
- }
- }))
- });
- }
- return this.renderButton({
- label: peers ? l[5883] : l[5884],
- onClick: () => call.hangUp()
- })
- ;
- }
- if (chatRoom.havePendingGroupCall()) {
- return this.IS_MODERATOR ? this.renderButton({
- label: l.end_call_for_all,
- onClick: () => msgDialog('confirmation', null, l.end_call_for_all_title, l.end_call_for_all_text, cb => cb ? chatRoom.endCallForAll() : 0xDEAD),
- disabled: !chatRoom.iAmInRoom()
- }) : null;
- }
- return null;
- }
-}
-const StartMeetingNotification = ({
- chatRoom,
- offset,
- onWaitingRoomJoin,
- onStartCall
-}) => {
- if (chatRoom.call || !megaChat.hasSupportForCalls) {
- return null;
- }
- return REaCt().createElement("div", {
- className: "in-call-notif neutral start",
- style: {
- marginTop: offset
- },
- onClick: () => {
- eventlog(500288);
- if (chatRoom.options.w && !chatRoom.iAmOperator()) {
- return onWaitingRoomJoin();
- }
- return onStartCall(call.ZE.AUDIO);
- }
- }, REaCt().createElement("button", {
- className: "mega-button positive small"
- }, l.schedule_start_aot));
-};
-const JoinCallNotification = ({
- chatRoom,
- offset,
- rhpCollapsed
-}) => {
- if (chatRoom.call) {
- return null;
- }
- if (!megaChat.hasSupportForCalls) {
- return REaCt().createElement(Alert, {
- className: `
- ${rhpCollapsed ? 'full-span' : ''}
- ${offset === ALERTS_BASE_OFFSET ? 'single-alert' : ''}
- unsupported-call-alert-progress
- `,
- offset: offset === ALERTS_BASE_OFFSET ? 0 : offset,
- type: Alert.TYPE.MEDIUM,
- content: l.active_call_not_supported
- });
- }
- if (chatRoom.callUserLimited && !chatRoom.canJoinLimitedCall()) {
- return REaCt().createElement("div", {
- className: "call-user-limit-banner",
- style: {
- marginTop: offset
- }
- }, l.call_join_user_limit_banner);
- }
- return REaCt().createElement("div", {
- className: "in-call-notif neutral join",
- style: {
- marginTop: offset
- }
- }, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-phone"
- }), REaCt().createElement(utils.P9, {
- onClick: () => {
- return (0,call.dQ)(true, chatRoom).then(() => chatRoom.joinCall()).catch(ex => d && console.warn('Already in a call.', ex));
- }
- }, (l[20460] || 'There is an active group call. [A]Join[/A]').replace('[A]', '')));
-};
-const allContactsInChat = participants => {
- const currentContacts = M.u.keys();
- for (let i = 0; i < currentContacts.length; i++) {
- const k = currentContacts[i];
- if (M.u[k].c === 1 && !participants.includes(k)) {
- return false;
- }
- }
- return true;
-};
-const excludedParticipants = room => {
- const excParticipants = room.type === "group" || room.type === "public" ? room.members && Object.keys(room.members).length > 0 ? Object.keys(room.members) : room.getParticipants() : room.getParticipants();
- if (excParticipants.includes(u_handle)) {
- array.remove(excParticipants, u_handle, false);
- }
- return excParticipants;
-};
-class Occurrences extends mixins.w9 {
- constructor(...args) {
- super(...args);
- this.domRef = REaCt().createRef();
- this.loadingMore = false;
- this.state = {
- editDialog: false,
- occurrenceId: undefined
- };
- }
- loadOccurrences() {
- if (!this.loadingMore) {
- const {
- scheduledMeeting,
- occurrences
- } = this.props;
- const occurrenceItems = Object.values(occurrences || {});
- const lastOccurrence = occurrenceItems[occurrenceItems.length - 1];
- if (lastOccurrence) {
- this.loadingMore = true;
- scheduledMeeting.getOccurrences({
- from: lastOccurrence.start
- }).catch(dump).finally(() => {
- this.loadingMore = false;
- });
- }
- }
- }
- renderCancelConfirmation(occurrence) {
- const {
- scheduledMeeting,
- chatRoom
- } = this.props;
- const nextOccurrences = Object.values(scheduledMeeting.occurrences).filter(o => o.isUpcoming);
- if (nextOccurrences.length > 1) {
- return msgDialog(`confirmation:!^${l.cancel_meeting_occurrence_button}!${l.schedule_cancel_abort}`, 'cancel-occurrence', l.schedule_cancel_occur_dlg_title, l.schedule_cancel_occur_dlg_text, cb => cb && occurrence.cancel(), 1);
- }
- return chatRoom.hasMessages(true) ? msgDialog(`confirmation:!^${l.cancel_meeting_button}!${l.schedule_cancel_abort}`, 'cancel-occurrence', l.schedule_cancel_all_dialog_title, l.schedule_cancel_all_dialog_move, cb => cb && megaChat.plugins.meetingsManager.cancelMeeting(scheduledMeeting, scheduledMeeting.chatId), 1) : msgDialog(`confirmation:!^${l.cancel_meeting_button}!${l.schedule_cancel_abort}`, 'cancel-occurrence', l.schedule_cancel_all_dialog_title, l.schedule_cancel_all_dialog_archive, cb => cb && megaChat.plugins.meetingsManager.cancelMeeting(scheduledMeeting, scheduledMeeting.chatId), 1);
- }
- renderLoading() {
- return REaCt().createElement("div", {
- className: "loading-sketch"
- }, Array.from({
- length: 10
- }, (el, i) => {
- return REaCt().createElement("div", {
- key: i,
- className: "chat-occurrence"
- }, REaCt().createElement("div", {
- className: "chat-occurrence-date"
- }), REaCt().createElement("div", {
- className: "chat-occurrence-content"
- }, REaCt().createElement("div", {
- className: "chat-occurrence-title"
- }), REaCt().createElement("div", {
- className: "chat-occurrence-time"
- })));
- }));
- }
- renderOccurrences() {
- const {
- chatRoom,
- occurrences,
- occurrencesLoading,
- scheduledMeeting
- } = this.props;
- if (occurrencesLoading) {
- return this.renderLoading();
- }
- if (occurrences && occurrences.length > 0) {
- const sortedOccurrences = Object.values(occurrences).sort((a, b) => a.start - b.start);
- return REaCt().createElement(REaCt().Fragment, null, sortedOccurrences.map(occurrence => occurrence.isUpcoming ? REaCt().createElement("div", {
- key: occurrence.uid,
- className: `
- chat-occurrence
- ${occurrence.uid}
- `
- }, REaCt().createElement("div", {
- className: "chat-occurrence-date"
- }, (0,helpers.cK)(occurrence.start) && REaCt().createElement("span", null, l.today_occurrence_label, " -"), (0,helpers.ef)(occurrence.start) && REaCt().createElement("span", null, l.tomorrow_occurrence_label, " -"), REaCt().createElement("span", null, time2date(occurrence.start / 1000, 19))), REaCt().createElement("div", {
- className: "chat-occurrence-content"
- }, REaCt().createElement("div", {
- className: "chat-occurrence-title"
- }, scheduledMeeting.title), REaCt().createElement("div", {
- className: "chat-occurrence-time"
- }, toLocaleTime(occurrence.start), " - \xA0", toLocaleTime(occurrence.end)), chatRoom.iAmOperator() && REaCt().createElement("div", {
- className: "chat-occurrence-controls"
- }, REaCt().createElement("div", {
- className: "chat-occurrence-control simpletip",
- "data-simpletip": l[1342],
- "data-simpletipposition": "top",
- "data-simpletipoffset": "5"
- }, REaCt().createElement(buttons.$, {
- icon: "sprite-fm-mono icon-rename",
- onClick: () => {
- megaChat.trigger(megaChat.plugins.meetingsManager.EVENTS.EDIT, occurrence);
- }
- })), REaCt().createElement("div", {
- className: "chat-occurrence-control simpletip",
- "data-simpletip": l.msg_dlg_cancel,
- "data-simpletipposition": "top",
- "data-simpletipoffset": "5"
- }, REaCt().createElement(buttons.$, {
- icon: "sprite-fm-mono icon-bin",
- onClick: () => this.renderCancelConfirmation(occurrence)
- }))))) : null));
- }
- return REaCt().createElement("span", null, l.no_occurrences_remain);
- }
- render() {
- return REaCt().createElement("div", {
- ref: this.domRef,
- className: "chat-occurrences-list"
- }, REaCt().createElement(perfectScrollbar.O, {
- chatRoom: this.props.chatRoom,
- ref: ref => {
- this.contactsListScroll = ref;
- },
- disableCheckingVisibility: true,
- onUserScroll: ps => ps.isCloseToBottom(30) && this.loadOccurrences(),
- isVisible: this.isCurrentlyActive,
- options: {
- suppressScrollX: true
- }
- }, REaCt().createElement("div", {
- className: "chat-occurrences-list-inner"
- }, this.renderOccurrences())));
- }
-}
-class ConversationRightArea extends mixins.w9 {
- constructor(...args) {
- super(...args);
- this.domRef = REaCt().createRef();
- this.state = {
- contactPickerDialog: false,
- inviteDialog: false
- };
- this.LeaveButton = (0,hostsObserver.C)(({
- chatRoom,
- hasHost,
- confirmLeave,
- onLeave
- }) => {
- const isDisabled = chatRoom.call || is_chatlink || !chatRoom.iAmInRoom();
- const participants = chatRoom.getParticipantsExceptMe();
- return REaCt().createElement("div", {
- className: `
- link-button
- light
- ${isDisabled ? 'disabled' : ''}
- `,
- onClick: isDisabled ? null : () => hasHost(participants) || !participants.length ? onLeave() : confirmLeave({
- title: chatRoom.isMeeting ? l.assign_host_to_leave : l.assign_host_to_leave_group,
- body: chatRoom.isMeeting ? l.assign_host_to_details : l.assign_host_to_details_group,
- cta: l.assign_host_button
- })
- }, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-disabled-filled"
- }), REaCt().createElement("span", null, chatRoom.isMeeting ? l.meeting_leave : l[8633]));
- });
- this.OptionsButton = ({
- icon,
- label,
- secondLabel,
- toggled,
- disabled,
- onClick
- }) => {
- const {
- chatRoom
- } = this.props;
- const isDisabled = !chatRoom.iAmOperator() || disabled;
- return REaCt().createElement(buttons.$, {
- className: `
- link-button
- light
- room-settings-button
- `,
- disabled: isDisabled,
- icon: `
- sprite-fm-mono
- ${icon}
- `,
- label,
- secondLabel,
- secondLabelClass: "label--green",
- toggle: {
- enabled: toggled,
- onClick: isDisabled ? null : onClick
- },
- onClick: isDisabled ? null : onClick
- });
- };
- this.handleCancelMeeting = () => {
- const {
- chatRoom
- } = this.props;
- const {
- scheduledMeeting,
- chatId
- } = chatRoom || {};
- if (scheduledMeeting) {
- const {
- isRecurring,
- title
- } = scheduledMeeting;
- const doConfirm = res => {
- if (res) {
- megaChat.plugins.meetingsManager.cancelMeeting(scheduledMeeting, chatId);
- delay('chat-event-sm-cancel', () => eventlog(99925));
- }
- };
- if (isRecurring) {
- return chatRoom.hasMessages(true) ? msgDialog(`confirmation:!^${l.cancel_meeting_button}!${l.schedule_cancel_abort}`, null, l.schedule_cancel_dialog_title.replace('%s', megaChat.html(title)), l.schedule_cancel_dialog_move_recurring, doConfirm, 1) : msgDialog(`confirmation:!^${l.schedule_cancel_dialog_confirm}!${l.schedule_cancel_abort}`, null, l.schedule_cancel_dialog_title.replace('%s', megaChat.html(title)), l.schedule_cancel_dialog_archive_recurring, doConfirm, 1);
- }
- return chatRoom.hasMessages(true) ? msgDialog(`confirmation:!^${l.cancel_meeting_button}!${l.schedule_cancel_abort}`, null, l.schedule_cancel_dialog_title.replace('%s', megaChat.html(title)), l.schedule_cancel_dialog_move_single, doConfirm, 1) : msgDialog(`confirmation:!^${l.schedule_cancel_dialog_confirm}!${l.schedule_cancel_abort}`, null, l.schedule_cancel_dialog_title.replace('%s', megaChat.html(title)), l.schedule_cancel_dialog_archive_single, doConfirm, 1);
- }
- };
- }
- customIsEventuallyVisible() {
- return this.props.chatRoom.isCurrentlyActive;
- }
- setRetention(chatRoom, retentionTime) {
- chatRoom.setRetention(retentionTime);
- $(document).trigger('closeDropdowns');
- }
- renderOptionsBanner() {
- const {
- chatRoom
- } = this.props;
- return !!chatRoom.options[MCO_FLAGS.WAITING_ROOM] && !!chatRoom.options[MCO_FLAGS.OPEN_INVITE] ? REaCt().createElement("div", {
- className: "room-settings-banner"
- }, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-info"
- }), REaCt().createElement(utils.P9, null, l.waiting_room_invite.replace('[A]', ``).replace('[/A]', ''))) : null;
- }
- handleAddParticipants() {
- if (Object.values(M.u.toJS()).some(u => u.c === 1)) {
- if (allContactsInChat(excludedParticipants(this.props.chatRoom))) {
- return msgDialog(`confirmationa:!^${l[8726]}!${l.msg_dlg_cancel}`, null, `${l.all_contacts_added}`, `${l.all_contacts_added_to_chat}`, res => {
- if (res) {
- contactAddDialog(null, false);
- }
- }, 1);
- }
- return this.setState({
- contactPickerDialog: true
- });
- }
- msgDialog(`confirmationa:!^${l[8726]}!${l.msg_dlg_cancel}`, null, `${l.no_contacts}`, `${l.no_contacts_text}`, resp => {
- if (resp) {
- contactAddDialog(null, false);
- }
- }, 1);
- }
- renderPushSettingsButton() {
- const {
- pushSettingsValue,
- chatRoom,
- onPushSettingsToggled,
- onPushSettingsClicked
- } = this.props;
- const icon = pushSettingsValue || pushSettingsValue === 0 ? 'icon-notification-off-filled' : 'icon-notification-filled';
- return REaCt().createElement("div", {
- className: "push-settings"
- }, REaCt().createElement("div", {
- className: "chat-button-separator"
- }), REaCt().createElement(buttons.$, {
- className: `
- link-button
- light
- push-settings-button
- ${chatRoom.isReadOnly() ? 'disabled' : ''}
- `,
- icon: `
- sprite-fm-mono
- ${icon}
- `,
- label: chatRoom.isMeeting ? l.meeting_notifications : l[16709],
- secondLabel: (() => {
- if (pushSettingsValue !== null && pushSettingsValue !== undefined) {
- return pushSettingsValue === 0 ? PushSettingsDialog.options[Infinity] : l[23539].replace('%s', toLocaleTime(pushSettingsValue));
- }
- })(),
- secondLabelClass: "label--green",
- toggle: chatRoom.isReadOnly() ? null : {
- enabled: !pushSettingsValue && pushSettingsValue !== 0,
- onClick: () => !pushSettingsValue && pushSettingsValue !== 0 ? onPushSettingsClicked() : onPushSettingsToggled()
- },
- onClick: () => chatRoom.isReadOnly() ? null : onPushSettingsClicked()
- }), REaCt().createElement("div", {
- className: "chat-button-separator"
- }));
- }
- componentDidMount() {
- super.componentDidMount();
- megaChat.rebind(`${megaChat.plugins.meetingsManager.EVENTS.OCCURRENCES_UPDATE}.${this.getUniqueId()}`, () => {
- if (this.isMounted()) {
- this.safeForceUpdate();
- }
- });
- megaChat.rebind(`onPrepareIncomingCallDialog.${this.getUniqueId()}`, () => {
- if (this.isMounted() && this.state.inviteDialog) {
- this.setState({
- inviteDialog: false
- });
- }
- });
- }
- render() {
- let _room$messagesBuff, _room$messagesBuff2, _room$messagesBuff3, _room$messagesBuff4, _room$messagesBuff5;
- const self = this;
- const {
- chatRoom: room,
- onStartCall,
- occurrencesLoading,
- onShowScheduledDescription
- } = self.props;
- if (!room || !room.roomId) {
- return null;
- }
- if (!room.isCurrentlyActive && !self._wasAppendedEvenOnce) {
- return null;
- }
- self._wasAppendedEvenOnce = true;
- const startCallDisabled = isStartCallDisabled(room) || room.iAmWaitingRoomPeer();
- let startAudioCallButton;
- let startVideoCallButton;
- const isInCall = !!room.call;
- if (isInCall) {
- startAudioCallButton = startVideoCallButton = null;
- }
- if (room.type === "group" || room.type === "public") {
- if (room.getCallParticipants().length > 0 && !isInCall) {
- startAudioCallButton = startVideoCallButton = null;
- }
- }
- if (startAudioCallButton !== null) {
- startAudioCallButton = REaCt().createElement("div", {
- "data-simpletip": l.unsupported_browser_audio,
- "data-simpletipposition": "top",
- "data-simpletipoffset": "7",
- className: `
- link-button light
- ${megaChat.hasSupportForCalls ? '' : 'simpletip'}
- ${startCallDisabled ? 'disabled' : ''}
- `,
- onClick: () => onStartCall(call.ZE.AUDIO)
- }, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-phone"
- }), REaCt().createElement("span", null, l[5896]));
- }
- if (startVideoCallButton !== null) {
- startVideoCallButton = REaCt().createElement("div", {
- "data-simpletip": l.unsupported_browser_video,
- "data-simpletipposition": "top",
- "data-simpletipoffset": "7",
- className: `
- link-button light
- ${megaChat.hasSupportForCalls ? '' : 'simpletip'}
- ${startCallDisabled ? 'disabled' : ''}
- `,
- onClick: () => onStartCall(call.ZE.VIDEO)
- }, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-video-call-filled"
- }), REaCt().createElement("span", null, l[5897]));
- }
- const AVseperator = REaCt().createElement("div", {
- className: "chat-button-separator"
- });
- let isReadOnlyElement = null;
- if (room.isReadOnly()) {
- isReadOnlyElement = REaCt().createElement("center", {
- className: "center",
- style: {
- margin: "6px"
- }
- }, l.read_only_chat);
- }
- const exParticipants = excludedParticipants(room);
- let dontShowTruncateButton = false;
- if (!room.iAmOperator() || room.isReadOnly() || ((_room$messagesBuff = room.messagesBuff) == null ? void 0 : _room$messagesBuff.messages.length) === 0 || ((_room$messagesBuff2 = room.messagesBuff) == null ? void 0 : _room$messagesBuff2.messages.length) === 1 && ((_room$messagesBuff3 = room.messagesBuff) == null ? void 0 : _room$messagesBuff3.messages.getItem(0).dialogType) === "truncated") {
- dontShowTruncateButton = true;
- }
- const renameButtonClass = `
- link-button
- light
- ${(0,call.P)() || room.isReadOnly() || !room.iAmOperator() ? 'disabled' : ''}
- `;
- const getChatLinkClass = `
- link-button
- light
- ${(0,call.P)() || room.isReadOnly() ? 'disabled' : ''}
- `;
- let participantsList = null;
- if (room.type === "group" || room.type === "public") {
- participantsList = REaCt().createElement("div", null, isReadOnlyElement, REaCt().createElement(buttons.$, {
- className: "mega-button action invite-dialog-btn",
- icon: "sprite-fm-mono icon-user-plus-thin-outline",
- label: l[8726],
- disabled: (0,call.P)() || room.isReadOnly() || !room.iAmOperator() && !room.publicLink && !room.options[MCO_FLAGS.OPEN_INVITE],
- onClick: () => {
- delay('chat-event-inv-rhp', () => eventlog(99963));
- if (room.type === 'group') {
- return this.handleAddParticipants();
- }
- loadingDialog.show('fetchchatlink');
- room.updatePublicHandle(false, false, true).catch(dump).always(() => {
- loadingDialog.hide('fetchchatlink');
- if (!this.isMounted()) {
- return;
- }
- if (!room.iAmOperator() && room.options[MCO_FLAGS.OPEN_INVITE] && !room.publicLink) {
- this.handleAddParticipants();
- } else if (room.type === 'public' && !room.topic) {
- this.handleAddParticipants();
- } else {
- this.setState({
- inviteDialog: true
- });
- }
- });
- }
- }), REaCt().createElement(ParticipantsList, {
- ref (r) {
- self.participantsListRef = r;
- },
- chatRoom: room,
- members: room.members,
- isCurrentlyActive: room.isCurrentlyActive
- }));
- }
- const addParticipantBtn = room.type === 'private' && REaCt().createElement(buttons.$, {
- className: "link-button light",
- icon: "sprite-fm-mono icon-add-small",
- label: l[8007],
- disabled: (0,call.P)() || room.isReadOnly() || !(room.iAmOperator() || room.type !== 'private' && room.options[MCO_FLAGS.OPEN_INVITE]),
- onClick: () => Object.values(M.u.toJS()).some(u => u.c === 1) ? !allContactsInChat(exParticipants) ? this.setState({
- contactPickerDialog: true
- }) : msgDialog(`confirmationa:!^${l[8726]}!${l.msg_dlg_cancel}`, null, `${l.all_contacts_added}`, `${l.all_contacts_added_to_chat}`, res => {
- if (res) {
- contactAddDialog(null, false);
- }
- }, 1) : msgDialog(`confirmationa:!^${l[8726]}!${l.msg_dlg_cancel}`, null, `${l.no_contacts}`, `${l.no_contacts_text}`, resp => {
- if (resp) {
- contactAddDialog(null, false);
- }
- }, 1)
- });
- const waitingRoomButton = {
- icon: 'icon-clock-user-thin-solid',
- label: l.waiting_room,
- secondLabel: l.waiting_room_info,
- toggled: room.options[MCO_FLAGS.WAITING_ROOM],
- disabled: room.havePendingCall(),
- onClick: () => {
- room.toggleWaitingRoom();
- delay('chat-event-wr-create-button', () => eventlog(99937));
- }
- };
- const openInviteButton = {
- icon: 'icon-user-filled',
- label: room.isMeeting ? l.meeting_open_invite_label : l.chat_open_invite_label,
- secondLabel: l.open_invite_desc,
- toggled: room.options[MCO_FLAGS.OPEN_INVITE],
- onClick: () => {
- room.toggleOpenInvite();
- if (room.scheduledMeeting) {
- delay('chat-event-sm-allow-non-hosts', () => eventlog(99928));
- }
- }
- };
- const retentionTime = room.retentionTime ? secondsToDays(room.retentionTime) : 0;
- const ICON_ACTIVE = REaCt().createElement("i", {
- className: "sprite-fm-mono icon-check"
- });
- const retentionHistoryBtn = REaCt().createElement(buttons.$, {
- className: "link-button light history-retention-btn",
- icon: "sprite-fm-mono icon-recents-filled",
- label: l[23436],
- disabled: !room.iAmOperator() || room.isReadOnly() || (0,call.P)(),
- secondLabel: room.getRetentionLabel(),
- secondLabelClass: "label--red",
- chatRoom: room
- }, room.iAmOperator() ? REaCt().createElement(dropdowns.Dropdown, {
- className: "retention-history-menu light",
- noArrow: "false",
- vertOffset: -53,
- horizOffset: -205
- }, REaCt().createElement("div", {
- className: "retention-history-menu__list"
- }, REaCt().createElement("div", {
- className: "dropdown-item link-button retention-history-menu__list__elem",
- onClick: () => this.setRetention(room, 0)
- }, REaCt().createElement("span", null, l.disabled_chat_history_cleaning_status), retentionTime === 0 && ICON_ACTIVE), REaCt().createElement("div", {
- className: "dropdown-item link-button retention-history-menu__list__elem",
- onClick: () => this.setRetention(room, daysToSeconds(1))
- }, REaCt().createElement("span", null, l[23437]), retentionTime === 1 && ICON_ACTIVE), REaCt().createElement("div", {
- className: "dropdown-item link-button retention-history-menu__list__elem",
- onClick: () => this.setRetention(room, daysToSeconds(7))
- }, REaCt().createElement("span", null, l[23438]), retentionTime === 7 && ICON_ACTIVE), REaCt().createElement("div", {
- className: "dropdown-item link-button retention-history-menu__list__elem",
- onClick: () => this.setRetention(room, daysToSeconds(30))
- }, REaCt().createElement("span", null, l[23439]), retentionTime === 30 && ICON_ACTIVE), REaCt().createElement("div", {
- className: "dropdown-item link-button retention-history-menu__list__elem",
- onClick: () => {
- $(document).trigger('closeDropdowns');
- self.props.onHistoryRetentionConfig();
- }
- }, REaCt().createElement("span", null, l[23440]), [0, 1, 7, 30].indexOf(retentionTime) === -1 && ICON_ACTIVE))) : null);
- const MEMBERS_LIMITED = Object.keys(room.members).length > MAX_USERS_CHAT_PRIVATE;
- const {
- scheduledMeeting,
- isMeeting
- } = room;
- const {
- isRecurring,
- isUpcoming,
- occurrences
- } = scheduledMeeting || {};
- let archiveText = room.isMeeting ? l.archive_meeting_btn : l.archive_chat_btn;
- if (room.isArchived()) {
- archiveText = room.isMeeting ? l.unarchive_meeting_btn : l[19065];
- }
- return REaCt().createElement("div", {
- ref: this.domRef,
- className: "chat-right-area"
- }, REaCt().createElement(perfectScrollbar.O, {
- className: "chat-right-area conversation-details-scroll",
- options: {
- 'suppressScrollX': true
- },
- ref: ref => {
- this.rightScroll = ref;
- },
- triggerGlobalResize: true,
- isVisible: room.isCurrentlyActive,
- chatRoom: room
- }, REaCt().createElement("div", {
- className: "chat-right-pad"
- }, REaCt().createElement(Accordion, (0,esm_extends.A)({}, this.state, {
- chatRoom: room,
- onToggle: SoonFc(20, () => {
- if (this.rightScroll) {
- this.rightScroll.reinitialise();
- }
- if (this.participantsListRef) {
- let _this$participantsLis, _this$participantsLis2;
- (_this$participantsLis = (_this$participantsLis2 = this.participantsListRef).safeForceUpdate) == null || _this$participantsLis.call(_this$participantsLis2);
- }
- }),
- expandedPanel: {
- participants: false,
- options: false,
- occurrences: isMeeting && scheduledMeeting && isRecurring
- }
- }), participantsList ? REaCt().createElement(AccordionPanel, {
- className: "small-pad",
- title: room.isMeeting ? l.meeting_participants : l.chat_participants,
- chatRoom: room,
- key: "participants"
- }, participantsList) : null, room.type === 'public' && room.observers > 0 && !room.options.w ? REaCt().createElement("div", {
- className: "accordion-text observers"
- }, l[20466], REaCt().createElement("span", {
- className: "observers-count"
- }, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-eye-reveal"
- }), room.observers)) : REaCt().createElement("div", null), isRecurring && isUpcoming && scheduledMeeting.occurrences.some(o => o.isUpcoming) && REaCt().createElement(AccordionPanel, {
- key: "occurrences",
- className: "chat-occurrences-panel",
- accordionClass: "chatroom-occurrences-panel",
- title: l.occurrences_heading,
- chatRoom: room,
- scheduledMeeting,
- occurrences
- }, REaCt().createElement(Occurrences, {
- chatRoom: room,
- scheduledMeeting,
- occurrences,
- occurrencesLoading
- })), REaCt().createElement(AccordionPanel, {
- key: "options",
- className: "have-animation buttons",
- accordionClass: "chatroom-options-panel",
- title: l[7537],
- chatRoom: room,
- sfuClient: window.sfuClient
- }, REaCt().createElement(REaCt().Fragment, null, room.isNote ? null : REaCt().createElement(REaCt().Fragment, null, addParticipantBtn, startAudioCallButton, startVideoCallButton, REaCt().createElement(EndCallButton, {
- call: room.havePendingGroupCall() || room.haveActiveCall(),
- chatRoom: room
- }), scheduledMeeting && REaCt().createElement("div", {
- className: `
- link-button light
- schedule-view-desc
- ${room.isReadOnly() || !scheduledMeeting.description ? 'disabled' : ''}
- `,
- onClick: () => {
- if (!room.isReadOnly() && scheduledMeeting.description) {
- onShowScheduledDescription();
- }
- }
- }, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-description"
- }), REaCt().createElement("span", null, l.schedule_view_desc)), (room.type === 'group' || room.type === 'public') && !scheduledMeeting ? REaCt().createElement("div", {
- className: renameButtonClass,
- onClick: e => {
- if ($(e.target).closest('.disabled').length > 0) {
- return false;
- }
- if (this.props.onRenameClicked) {
- this.props.onRenameClicked();
- }
- }
- }, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-rename"
- }), REaCt().createElement("span", null, room.isMeeting ? l.rename_meeting : l[9080])) : null, scheduledMeeting ? REaCt().createElement("div", {
- className: `
- link-button
- light
- ${room.iAmOperator() ? '' : 'disabled'}
- `,
- onClick: () => room.iAmOperator() ? megaChat.trigger(megaChat.plugins.meetingsManager.EVENTS.EDIT, room) : null
- }, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-rename"
- }), scheduledMeeting.isRecurring ? REaCt().createElement("span", null, l.edit_meeting_series_button) : REaCt().createElement("span", null, l.edit_meeting_button)) : null, room.type === 'public' && !room.isMeeting ? REaCt().createElement("div", {
- className: getChatLinkClass,
- onClick: e => {
- if ($(e.target).closest('.disabled').length > 0) {
- return false;
- }
- this.props.onGetManageChatLinkClicked();
- }
- }, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-link-filled"
- }), REaCt().createElement("span", null, l[20481])) : null, scheduledMeeting ? REaCt().createElement("div", {
- className: `
- link-button
- light
- ${room.iAmOperator() && !scheduledMeeting.canceled ? '' : 'disabled'}
- `,
- onClick: () => {
- if (room.iAmOperator() && !scheduledMeeting.canceled) {
- this.handleCancelMeeting();
- }
- }
- }, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-bin-filled"
- }), scheduledMeeting.isRecurring ? REaCt().createElement("span", null, l.cancel_meeting_series_button) : REaCt().createElement("span", null, l.cancel_meeting_button)) : null, !room.membersSetFromApi.members.hasOwnProperty(u_handle) && room.type === 'public' && !is_chatlink && room.publicChatHandle && room.publicChatKey ? REaCt().createElement("div", {
- className: "link-button light",
- onClick: e => {
- if ($(e.target).closest('.disabled').length > 0) {
- return false;
- }
- this.props.onJoinViaPublicLinkClicked();
- }
- }, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-rename"
- }), REaCt().createElement("span", null, l[20597])) : null, scheduledMeeting ? null : REaCt().createElement(REaCt().Fragment, null, AVseperator, REaCt().createElement(buttons.$, {
- className: "link-button light dropdown-element",
- icon: "sprite-fm-mono icon-upload-filled",
- label: l[23753],
- disabled: room.isReadOnly()
- }, REaCt().createElement(dropdowns.Dropdown, {
- className: "wide-dropdown send-files-selector light",
- noArrow: "true",
- vertOffset: 4,
- onClick: () => false
- }, REaCt().createElement("div", {
- className: "dropdown info-txt"
- }, l[23753] || 'Send...'), REaCt().createElement(dropdowns.DropdownItem, {
- className: "link-button",
- icon: "sprite-fm-mono icon-cloud-drive",
- label: l[19794] || 'My Cloud Drive',
- disabled: mega.paywall,
- onClick: () => {
- this.props.onAttachFromCloudClicked();
- }
- }), REaCt().createElement(dropdowns.DropdownItem, {
- className: "link-button",
- icon: "sprite-fm-mono icon-session-history",
- label: l[19795] || 'My computer',
- disabled: mega.paywall,
- onClick: () => {
- this.props.onAttachFromComputerClicked();
- }
- })))), this.renderPushSettingsButton()), room.type === 'private' ? null : REaCt().createElement(REaCt().Fragment, null, room.scheduledMeeting && this.OptionsButton(waitingRoomButton), this.OptionsButton(openInviteButton), this.renderOptionsBanner(), AVseperator), REaCt().createElement(buttons.$, {
- className: "link-button light export-chat-button",
- disabled: ((_room$messagesBuff4 = room.messagesBuff) == null ? void 0 : _room$messagesBuff4.messages.length) === 0 || room.exportIo,
- onClick: () => {
- room.exportToFile();
- }
- }, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-export-chat-filled"
- }), REaCt().createElement("span", null, room.isMeeting ? l.export_meeting_rhp : l.export_chat_rhp)), REaCt().createElement(buttons.$, {
- className: "link-button light clear-history-button",
- disabled: dontShowTruncateButton || !room.members.hasOwnProperty(u_handle),
- onClick: () => {
- if (this.props.onTruncateClicked) {
- this.props.onTruncateClicked();
- }
- }
- }, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-remove"
- }), REaCt().createElement("span", {
- className: "accordion-clear-history-text"
- }, room.isMeeting ? l.meeting_clear_hist : l[8871])), retentionHistoryBtn, room.iAmOperator() && room.type === 'public' && !scheduledMeeting ? REaCt().createElement("div", {
- className: "chat-enable-key-rotation-paragraph"
- }, AVseperator, REaCt().createElement("div", {
- className: `
- link-button
- light
- ${MEMBERS_LIMITED ? 'disabled' : ''}
- `,
- onClick: e => {
- if (MEMBERS_LIMITED || $(e.target).closest('.disabled').length > 0) {
- return false;
- }
- this.props.onMakePrivateClicked();
- }
- }, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-key"
- }), REaCt().createElement("span", null, l[20623])), REaCt().createElement("p", null, REaCt().createElement("span", null, l[20454]))) : null, AVseperator, REaCt().createElement("div", {
- className: `
- link-button
- light
- ${(room.members.hasOwnProperty(u_handle) || room.state === ChatRoom.STATE.LEFT) && !is_chatlink ? '' : 'disabled'}
- `,
- onClick: e => {
- if ($(e.target).closest('.disabled').length > 0) {
- return false;
- }
- if (room.isArchived()) {
- if (this.props.onUnarchiveClicked) {
- this.props.onUnarchiveClicked();
- }
- } else if (this.props.onArchiveClicked) {
- this.props.onArchiveClicked();
- }
- }
- }, REaCt().createElement("i", {
- className: `
- sprite-fm-mono
- ${room.isArchived() ? 'icon-unarchive' : 'icon-archive'}
- `
- }), REaCt().createElement("span", null, archiveText)), room.type === 'private' ? null : REaCt().createElement(this.LeaveButton, {
- chatRoom: room,
- participants: room.getParticipantsExceptMe(),
- onLeave: () => room.leave(true)
- }))), REaCt().createElement(SharedFilesAccordionPanel, {
- key: "sharedFiles",
- title: l[19796] || 'Shared Files',
- chatRoom: room,
- sharedFiles: (_room$messagesBuff5 = room.messagesBuff) == null ? void 0 : _room$messagesBuff5.sharedFiles
- }), room.type === 'private' && !room.isNote ? REaCt().createElement(IncSharesAccordionPanel, {
- key: "incomingShares",
- title: l[5542],
- chatRoom: room
- }) : null))), this.state.contactPickerDialog && REaCt().createElement(ui_contacts.ContactPickerDialog, {
- exclude: exParticipants,
- megaChat: room.megaChat,
- multiple: true,
- className: "popup add-participant-selector",
- singleSelectedButtonLabel: room.isMeeting ? l.meeting_add_participant : l[8869],
- multipleSelectedButtonLabel: room.isMeeting ? l.meeting_add_participant : l[8869],
- nothingSelectedButtonLabel: l[8870],
- inviteWarningLabel: room.haveActiveCall(),
- chatRoom: room,
- onSelectDone: selected => {
- this.props.onAddParticipantSelected(selected);
- this.setState({
- contactPickerDialog: false
- });
- },
- onClose: () => this.setState({
- contactPickerDialog: false
- }),
- selectFooter: true
- }), this.state.inviteDialog && REaCt().createElement(modalDialogs.A.ModalDialog, {
- onClose: () => {
- this.setState({
- inviteDialog: false
- });
- },
- dialogName: "chat-link-dialog",
- chatRoom: room
- }, REaCt().createElement(inviteParticipantsPanel.Q, {
- chatRoom: room,
- onAddParticipants: () => {
- this.setState({
- inviteDialog: false
- }, () => this.handleAddParticipants());
- }
- })));
- }
-}
-ConversationRightArea.defaultProps = {
- 'requiresUpdateOnResize': true
-};
-const ConversationPanel = (conversationpanel_dec = utils.Ay.SoonFcWrap(360), _dec2 = (0,mixins.N9)(0.7, 9), conversationpanel_class = class ConversationPanel extends mixins.w9 {
- constructor(props) {
- super(props);
- this.domRef = REaCt().createRef();
- this.messagesBlockRef = REaCt().createRef();
- this.$container = undefined;
- this.$messages = undefined;
- this.selectedNodes = [];
- this.state = {
- startCallPopupIsActive: false,
- localVideoIsMinimized: false,
- isFullscreenModeEnabled: false,
- mouseOverDuringCall: false,
- attachCloudDialog: false,
- sendContactDialog: false,
- confirmDeleteDialog: false,
- pasteImageConfirmDialog: false,
- nonLoggedInJoinChatDialog: false,
- pushSettingsDialog: false,
- pushSettingsValue: null,
- messageToBeDeleted: null,
- callMinimized: false,
- editing: false,
- showHistoryRetentionDialog: false,
- setNonLoggedInJoinChatDlgTrue: null,
- hasInvalidKeys: null,
- invalidKeysBanner: null,
- descriptionDialog: false,
- occurrencesLoading: false,
- waitingRoom: false,
- callUserLimit: false,
- historyTimeOutBanner: DISMISS_TRANSITIONS.NOT_SHOWN,
- renameDialog: false,
- renameDialogValue: undefined,
- typingAreaText: ''
- };
- this.RenameDialog = () => {
- const {
- chatRoom
- } = this.props;
- const {
- renameDialogValue
- } = this.state;
- const isDisabled = renameDialogValue === chatRoom.getRoomTitle() || !$.trim(renameDialogValue).length;
- const onSubmit = () => chatRoom.setRoomTopic(renameDialogValue).then(() => this.setState({
- renameDialog: false,
- renameDialogValue: undefined
- })).catch(dump);
- return REaCt().createElement(modalDialogs.A.ModalDialog, {
- chatRoom,
- title: chatRoom.isMeeting ? l.rename_meeting : l[9080],
- name: "rename-group",
- className: "chat-rename-dialog dialog-template-main",
- onClose: () => this.setState({
- renameDialog: false,
- renameDialogValue: undefined
- }),
- buttons: [{
- label: l.msg_dlg_cancel,
- onClick: () => this.setState({
- renameDialog: false,
- renameDialogValue: undefined
- })
- }, {
- label: l[61],
- className: `
- positive
- ${isDisabled ? 'disabled' : ''}
- `,
- onClick: isDisabled ? null : onSubmit
- }]
- }, REaCt().createElement("section", {
- className: "content"
- }, REaCt().createElement("div", {
- className: "content-block"
- }, REaCt().createElement("div", {
- className: "dialog secondary-header"
- }, REaCt().createElement("div", {
- className: "rename-input-bl"
- }, REaCt().createElement("input", {
- type: "text",
- name: "newTopic",
- className: "chat-rename-group-dialog",
- value: renameDialogValue === undefined ? chatRoom.getRoomTitle() : renameDialogValue,
- maxLength: ChatRoom.TOPIC_MAX_LENGTH,
- onChange: ev => this.setState({
- renameDialogValue: ev.target.value.substr(0, 30)
- }),
- onKeyUp: ev => isDisabled ? null : ev.which === 13 && onSubmit()
- }))))));
- };
- this.CloudBrowserDialog = () => {
- const {
- chatRoom
- } = this.props;
- return REaCt().createElement(cloudBrowserModalDialog.CloudBrowserDialog, {
- room: chatRoom,
- allowAttachFolders: true,
- onSelected: nodes => {
- this.selectedNodes = nodes;
- },
- onAttachClicked: () => {
- this.setState({
- attachCloudDialog: false
- }, () => {
- chatRoom.scrolledToBottom = true;
- chatRoom.attachNodes(this.selectedNodes).catch(dump);
- });
- },
- onClose: () => {
- this.setState({
- attachCloudDialog: false
- }, () => {
- this.selectedNodes = [];
- });
- }
- });
- };
- this.SelectContactDialog = () => {
- const {
- chatRoom
- } = this.props;
- const excludedContacts = chatRoom.getParticipantsExceptMe().filter(userHandle => userHandle in M.u);
- return REaCt().createElement(modalDialogs.A.SelectContactDialog, {
- chatRoom,
- exclude: excludedContacts,
- onSelectClicked: selected => this.setState({
- sendContactDialog: false
- }, () => chatRoom.attachContacts(selected)),
- onClose: () => this.setState({
- sendContactDialog: false
- })
- });
- };
- this.DescriptionDialog = () => {
- const {
- chatRoom
- } = this.props;
- const dialogName = 'scheduled-description-dialog';
- return REaCt().createElement(modalDialogs.A.ModalDialog, {
- className: "scheduled-description-dialog",
- meeting: chatRoom.scheduledMeeting,
- popupDidMount: () => M.safeShowDialog(dialogName, () => $(`.${dialogName}`)),
- popupWillUnmount: () => $.dialog === dialogName && closeDialog(),
- onClose: () => this.setState({
- descriptionDialog: false
- })
- }, REaCt().createElement("header", null, REaCt().createElement("h3", null, l.schedule_desc_dlg_title)), REaCt().createElement("section", {
- className: "content"
- }, REaCt().createElement(perfectScrollbar.O, {
- className: "description-scroller"
- }, REaCt().createElement(utils.P9, {
- content: megaChat.html(chatRoom.scheduledMeeting.description).replace(/\n/g, '
') || l.schedule_no_desc
- }))));
- };
- this.PushSettingsDialog = () => {
- const {
- chatRoom
- } = this.props;
- const {
- pushSettingsValue
- } = this.state;
- const state = {
- pushSettingsDialog: false,
- pushSettingsValue: null
- };
- return REaCt().createElement(PushSettingsDialog, {
- room: chatRoom,
- pushSettingsValue,
- onClose: () => this.setState({
- ...state,
- pushSettingsValue
- }, () => $.dialog === 'push-settings-dialog' && closeDialog()),
- onConfirm: pushSettingsValue => this.setState({
- ...state,
- pushSettingsValue
- }, () => pushNotificationSettings.setDnd(chatRoom.chatId, pushSettingsValue === Infinity ? 0 : unixtime() + pushSettingsValue * 60))
- });
- };
- this.updateTypingAreaText = value => {
- this.setState({
- typingAreaText: value
- });
- };
- const {
- chatRoom: _chatRoom
- } = this.props;
- const uniqueId = this.getUniqueId();
- _chatRoom.rebind(`openAttachCloudDialog.${uniqueId}`, () => this.setState({
- attachCloudDialog: true
- }));
- _chatRoom.rebind(`openSendContactDialog.${uniqueId}`, () => this.setState({
- sendContactDialog: true
- }));
- _chatRoom.rebind(`openDescriptionDialog.${uniqueId}`, () => this.setState({
- descriptionDialog: true
- }));
- this.handleKeyDown = SoonFc(120, ev => this._handleKeyDown(ev));
- this.state.waitingRoom = _chatRoom.options.w && (_chatRoom.isAnonymous() || megaChat.initialChatId || is_eplusplus);
- }
- customIsEventuallyVisible() {
- return this.props.chatRoom.isCurrentlyActive;
- }
- onMouseMove() {
- if (this.isComponentEventuallyVisible()) {
- this.props.chatRoom.trigger("onChatIsFocused");
- }
- }
- _handleKeyDown() {
- if (this.__isMounted) {
- const {chatRoom} = this.props;
- if (chatRoom.isActive() && !chatRoom.isReadOnly()) {
- chatRoom.trigger("onChatIsFocused");
- }
- }
- }
- handleDeleteDialog(msg) {
- if (msg) {
- this.setState({
- editing: false,
- confirmDeleteDialog: true,
- messageToBeDeleted: msg
- });
- }
- }
- toggleExpandedFlag() {
- if (this.props.onToggleExpandedFlag) {
- this.props.onToggleExpandedFlag();
- }
- return document.body.classList[call.Ay.isExpanded() ? 'remove' : 'add'](call.Fj);
- }
- startCall(type, scheduled) {
- const {
- chatRoom
- } = this.props;
- if (isStartCallDisabled(chatRoom) || chatRoom.iAmWaitingRoomPeer()) {
- return false;
- }
- return type === call.ZE.AUDIO ? chatRoom.startAudioCall(scheduled) : chatRoom.startVideoCall(scheduled);
- }
- renderUpcomingInfo() {
- const {
- scheduledMeeting
- } = this.props.chatRoom;
- if (scheduledMeeting) {
- const {
- recurring,
- nextOccurrenceStart,
- nextOccurrenceEnd,
- isUpcoming
- } = scheduledMeeting;
- const until = `${(0,helpers.ro)(nextOccurrenceStart, nextOccurrenceEnd) ? '' : time2date(nextOccurrenceEnd / 1000, 4)} ${toLocaleTime(nextOccurrenceEnd)}`;
- return REaCt().createElement(REaCt().Fragment, null, isUpcoming && recurring && REaCt().createElement("span", null, l.next_meeting), REaCt().createElement("span", null, (l.schedule_formatted_date || '%1 from %2 to %3').replace('%1', time2date(nextOccurrenceStart / 1000, 4)).replace('%2', toLocaleTime(nextOccurrenceStart)).replace('%3', until)));
- }
- return null;
- }
- componentDidMount() {
- super.componentDidMount();
- const {
- chatRoom
- } = this.props;
- this.$container = $('.conversation-panel', '#fmholder');
- this.$messages = $('.messages.scroll-area > .perfectScrollbarContainer', this.$container);
- window.addEventListener('keydown', this.handleKeyDown);
- chatRoom.rebind('onSendMessage.scrollToBottom', () => {
- chatRoom.scrolledToBottom = true;
- if (this.messagesListScrollable) {
- this.messagesListScrollable.scrollToBottom();
- }
- });
- chatRoom.rebind('openSendFilesDialog.cpanel', () => this.setState({
- attachCloudDialog: true
- }));
- chatRoom.rebind('showGetChatLinkDialog.ui', () => {
- createTimeoutPromise(() => chatRoom.topic && chatRoom.state === ChatRoom.STATE.READY, 350, 15000).always(() => {
- return chatRoom.isCurrentlyActive ? this.setState({
- chatLinkDialog: true
- }) : chatRoom.updatePublicHandle(false, true);
- });
- });
- if (chatRoom.type === 'private') {
- const otherContactHash = chatRoom.getParticipantsExceptMe()[0];
- if (otherContactHash in M.u) {
- this._privateChangeListener = M.u[otherContactHash].addChangeListener(() => {
- if (!this.isMounted()) {
- return 0xDEAD;
- }
- this.safeForceUpdate();
- });
- }
- }
- if (is_chatlink && !chatRoom.isMeeting) {
- this.state.setNonLoggedInJoinChatDlgTrue = setTimeout(() => {
- M.safeShowDialog('chat-links-preview-desktop', () => {
- if (this.isMounted()) {
- this.setState({
- nonLoggedInJoinChatDialog: true
- });
- }
- });
- }, rand_range(5, 10) * 1000);
- }
- if (is_chatlink && chatRoom.isMeeting && u_type !== false && u_type < 3) {
- eventlog(99747, JSON.stringify([1, u_type | 0]), true);
- }
- chatRoom._uiIsMounted = true;
- chatRoom.$rConversationPanel = this;
- onIdle(() => this.isMounted() && chatRoom.trigger('onComponentDidMount'));
- ChatdIntegration._waitForProtocolHandler(chatRoom, () => {
- if (this.isMounted()) {
- const hasInvalidKeys = chatRoom.hasInvalidKeys();
- this.setState({
- hasInvalidKeys,
- invalidKeysBanner: hasInvalidKeys
- }, () => this.safeForceUpdate());
- }
- });
- megaChat.rebind(`${megaChat.plugins.meetingsManager.EVENTS.OCCURRENCES_UPDATE}.${this.getUniqueId()}`, () => {
- return this.isMounted() && this.setState({
- occurrencesLoading: false
- });
- });
- chatRoom.rebind(`wrOnJoinNotAllowed.${this.getUniqueId()}`, () => {
- return this.isMounted() && this.setState({
- waitingRoom: true
- });
- });
- chatRoom.rebind(`wrOnJoinAllowed.${this.getUniqueId()}`, () => {
- return this.isMounted() && this.setState({
- waitingRoom: false
- });
- });
- chatRoom.rebind(`onCallUserLimitExceeded.${this.getUniqueId()}`, () => {
- if (!this.isMounted()) {
- return;
- }
- if (megaChat.initialChatId || is_eplusplus) {
- this.setState({
- callUserLimit: true
- });
- }
- });
- chatRoom.rebind(`onHistTimeoutChange.${this.getUniqueId()}`, () => {
- if (this.state.historyTimeOutBanner === DISMISS_TRANSITIONS.NOT_SHOWN && chatRoom.historyTimedOut) {
- this.setState({
- historyTimeOutBanner: DISMISS_TRANSITIONS.SHOWN
- });
- } else if (this.state.historyTimeOutBanner && !chatRoom.historyTimedOut) {
- this.setState({
- historyTimeOutBanner: DISMISS_TRANSITIONS.NOT_SHOWN
- });
- }
- });
- if (chatRoom.options.w) {
- chatRoom.rebind(`onMembersUpdated.${this.getUniqueId()}`, (ev, {
- userId,
- priv
- }) => {
- if (userId === u_handle && priv !== ChatRoom.MembersSet.PRIVILEGE_STATE.LEFT) {
- chatRoom.unbind(`onMembersUpdated.${this.getUniqueId()}`);
- if (is_chatlink) {
- return megaChat.routing.reinitAndOpenExistingChat(chatRoom.chatId, chatRoom.publicChatHandle).then(chatRoom => chatRoom.havePendingCall() && priv === ChatRoom.MembersSet.PRIVILEGE_STATE.OPERATOR && chatRoom.joinCall()).catch(dump);
- }
- return this.state.waitingRoom && this.setState({
- waitingRoom: priv !== ChatRoom.MembersSet.PRIVILEGE_STATE.OPERATOR
- });
- }
- });
- }
- this.pageChangeListener = mBroadcaster.addListener('beforepagechange', () => M.chat && this.state.waitingRoom && this.setState({
- waitingRoom: false
- }, () => this.safeForceUpdate()));
- }
- componentWillUnmount() {
- super.componentWillUnmount();
- const self = this;
- const {chatRoom} = self.props;
- chatRoom._uiIsMounted = true;
- if (this._privateChangeListener) {
- const otherContactHash = self.props.chatRoom.getParticipantsExceptMe()[0];
- if (otherContactHash in M.u) {
- M.u[otherContactHash].removeChangeListener(this._privateChangeListener);
- delete this._privateChangeListener;
- }
- }
- mBroadcaster.removeListener(this.pageChangeListener);
- this.props.chatRoom.unbind(`openAttachCloudDialog.${this.getUniqueId()}`);
- this.props.chatRoom.unbind(`openSendContactDialog.${this.getUniqueId()}`);
- this.props.chatRoom.unbind(`openDescriptionDialog.${this.getUniqueId()}`);
- window.removeEventListener('keydown', self.handleKeyDown);
- $(document).off(`fullscreenchange.megaChat_${chatRoom.roomId}`);
- $(document).off(`keydown.keyboardScroll_${chatRoom.roomId}`);
- this.props.chatRoom.unbind(`wrOnJoinNotAllowed.${this.getUniqueId()}`);
- this.props.chatRoom.unbind(`wrOnJoinAllowed.${this.getUniqueId()}`);
- megaChat.unbind(`onIncomingCall.${this.getUniqueId()}`);
- this.props.chatRoom.unbind(`onHistTimeoutChange.${this.getUniqueId()}`);
- }
- componentDidUpdate(prevProps, prevState) {
- const self = this;
- const room = this.props.chatRoom;
- room.megaChat.updateSectionUnreadCount();
- if (prevProps.isActive === false && self.props.isActive === true) {
- const $typeArea = $('.messages-textarea:visible:first', this.$container);
- if ($typeArea.length === 1) {
- $typeArea.trigger("focus");
- moveCursortoToEnd($typeArea[0]);
- }
- }
- if (!prevState.renameDialog && self.state.renameDialog === true) {
- Soon(() => {
- const $input = $('.chat-rename-dialog input');
- if ($input && $input[0] && !$($input[0]).is(":focus")) {
- $input.trigger("focus");
- $input[0].selectionStart = 0;
- $input[0].selectionEnd = $input.val().length;
- }
- });
- }
- if (self.$messages && self.isComponentEventuallyVisible()) {
- $(window).rebind('pastedimage.chatRoom', (e, blob, fileName) => {
- if (self.$messages && self.isComponentEventuallyVisible()) {
- self.setState({
- 'pasteImageConfirmDialog': [blob, fileName, URL.createObjectURL(blob)]
- });
- e.preventDefault();
- }
- });
- self.props.chatRoom.trigger("onComponentDidUpdate");
- }
- }
- isActive() {
- return document.hasFocus() && this.$messages && this.$messages.is(":visible");
- }
- render() {
- const self = this;
- const room = this.props.chatRoom;
- if (!room || !room.roomId) {
- return null;
- }
- const contacts = room.getParticipantsExceptMe();
- let contactHandle;
- let contact;
- let nonLoggedInJoinChatDialog = null;
- if (self.state.nonLoggedInJoinChatDialog === true) {
- const usersCount = Object.keys(room.members).length;
- const closeJoinDialog = () => {
- onIdle(() => {
- if ($.dialog === 'chat-links-preview-desktop') {
- closeDialog();
- }
- });
- self.setState({
- 'nonLoggedInJoinChatDialog': false
- });
- };
- nonLoggedInJoinChatDialog = REaCt().createElement(modalDialogs.A.ModalDialog, {
- title: l[20596],
- className: "mega-dialog chat-links-preview-desktop dialog-template-graphic",
- chatRoom: room,
- onClose: closeJoinDialog
- }, REaCt().createElement("section", {
- className: "content"
- }, REaCt().createElement("div", {
- className: "chatlink-contents"
- }, REaCt().createElement("div", {
- className: "huge-icon group-chat"
- }), REaCt().createElement("h3", null, REaCt().createElement(utils.zT, null, room.getRoomTitle())), REaCt().createElement("h5", null, usersCount ? mega.icu.format(l[20233], usersCount) : ''), REaCt().createElement("p", null, l[20595]))), REaCt().createElement("footer", null, REaCt().createElement("div", {
- className: "bottom-buttons"
- }, REaCt().createElement("button", {
- className: "mega-button positive",
- onClick: () => {
- closeJoinDialog();
- megaChat.loginOrRegisterBeforeJoining(room.publicChatHandle, false, false, false, () => {
- megaChat.routing.reinitAndJoinPublicChat(room.chatId, room.publicChatHandle, room.publicChatKey).then(() => {
- delete megaChat.initialPubChatHandle;
- }, ex => {
- console.error("Failed to join room:", ex);
- });
- });
- }
- }, l[20597]), REaCt().createElement("button", {
- className: "mega-button",
- onClick: closeJoinDialog
- }, l[18682]))));
- }
- let privateChatDialog;
- if (self.state.privateChatDialog === true) {
- const onClose = () => this.setState({
- privateChatDialog: false
- });
- privateChatDialog = REaCt().createElement(modalDialogs.A.ModalDialog, {
- title: l[20594],
- className: "mega-dialog create-private-chat",
- chatRoom: room,
- onClose,
- dialogType: "action",
- dialogName: "create-private-chat-dialog"
- }, REaCt().createElement("section", {
- className: "content"
- }, REaCt().createElement("div", {
- className: "content-block"
- }, REaCt().createElement("i", {
- className: "huge-icon lock"
- }), REaCt().createElement("div", {
- className: "dialog-body-text"
- }, REaCt().createElement("strong", null, l[20590]), REaCt().createElement("br", null), REaCt().createElement("span", null, l[20591])))), REaCt().createElement("footer", null, REaCt().createElement("div", {
- className: "footer-container"
- }, REaCt().createElement("button", {
- className: "mega-button positive large",
- onClick: () => {
- this.props.chatRoom.switchOffPublicMode();
- onClose();
- }
- }, REaCt().createElement("span", null, l[20593])))));
- }
- let confirmDeleteDialog = null;
- if (self.state.confirmDeleteDialog === true) {
- confirmDeleteDialog = REaCt().createElement(modalDialogs.A.ConfirmDialog, {
- chatRoom: room,
- dialogType: "main",
- title: l[8004],
- subtitle: l[8879],
- name: "delete-message",
- pref: "1",
- onClose: () => {
- self.setState({
- 'confirmDeleteDialog': false
- });
- },
- onConfirmClicked: () => {
- const msg = self.state.messageToBeDeleted;
- if (!msg) {
- return;
- }
- const chatdint = room.megaChat.plugins.chatdIntegration;
- if (msg.getState() === Message.STATE.SENT || msg.getState() === Message.STATE.DELIVERED || msg.getState() === Message.STATE.NOT_SENT) {
- const textContents = msg.textContents || '';
- if (textContents[1] === Message.MANAGEMENT_MESSAGE_TYPES.VOICE_CLIP) {
- const attachmentMetadata = msg.getAttachmentMeta() || [];
- Promise.all(attachmentMetadata.map(v => M.moveToRubbish(v.h))).catch(dump);
- }
- chatdint.deleteMessage(room, msg.internalId ? msg.internalId : msg.orderValue);
- msg.deleted = true;
- msg.textContents = "";
- } else if (msg.getState() === Message.STATE.NOT_SENT_EXPIRED) {
- chatdint.discardMessage(room, msg.internalId ? msg.internalId : msg.orderValue);
- }
- self.setState({
- 'confirmDeleteDialog': false,
- 'messageToBeDeleted': false
- });
- if (msg.getState && msg.getState() === Message.STATE.NOT_SENT && !msg.requiresManualRetry) {
- msg.message = "";
- msg.textContents = "";
- msg.messageHtml = "";
- msg.deleted = true;
- msg.trigger('onChange', [msg, "deleted", false, true]);
- }
- }
- }, REaCt().createElement("section", {
- className: "content"
- }, REaCt().createElement("div", {
- className: "content-block"
- }, REaCt().createElement(generic.A, {
- className: " dialog-wrapper",
- message: self.state.messageToBeDeleted,
- hideActionButtons: true,
- initTextScrolling: true,
- dialog: true,
- chatRoom: self.props.chatRoom
- }))));
- }
- if (self.state.pasteImageConfirmDialog) {
- confirmDeleteDialog = REaCt().createElement(modalDialogs.A.ConfirmDialog, {
- chatRoom: room,
- title: l[20905],
- subtitle: l[20906],
- icon: "sprite-fm-uni icon-question",
- name: "paste-image-chat",
- pref: "2",
- onClose: () => {
- self.setState({
- 'pasteImageConfirmDialog': false
- });
- },
- onConfirmClicked: () => {
- const meta = self.state.pasteImageConfirmDialog;
- if (!meta) {
- return;
- }
- try {
- Object.defineProperty(meta[0], 'name', {
- configurable: true,
- writeable: true,
- value: `${Date.now() }.${ M.getSafeName(meta[1] || meta[0].name)}`
- });
- } catch (e) {}
- self.props.chatRoom.scrolledToBottom = true;
- M.addUpload([meta[0]]);
- self.setState({
- 'pasteImageConfirmDialog': false
- });
- URL.revokeObjectURL(meta[2]);
- }
- }, REaCt().createElement("img", {
- src: self.state.pasteImageConfirmDialog[2],
- style: {
- maxWidth: "90%",
- height: "auto",
- maxHeight: $(document).outerHeight() * 0.3,
- margin: '10px auto',
- display: 'block',
- border: '1px solid #ccc',
- borderRadius: '4px'
- },
- onLoad (e) {
- $(e.target).parents('.paste-image-chat').position({
- of: $(document.body)
- });
- }
- }));
- }
- if (self.state.truncateDialog === true) {
- confirmDeleteDialog = REaCt().createElement(modalDialogs.A.ConfirmDialog, {
- chatRoom: room,
- title: room.isMeeting ? l.meeting_clear_hist : l[8871],
- subtitle: room.isMeeting ? l.meeting_trunc_txt : l[8881],
- icon: "sprite-fm-uni icon-question",
- name: "truncate-conversation",
- pref: "3",
- dontShowAgainCheckbox: false,
- onClose: () => {
- self.setState({
- 'truncateDialog': false
- });
- },
- onConfirmClicked: () => {
- self.props.chatRoom.scrolledToBottom = true;
- room.truncate();
- self.setState({
- 'truncateDialog': false
- });
- }
- });
- }
- if (self.state.archiveDialog === true) {
- confirmDeleteDialog = REaCt().createElement(modalDialogs.A.ConfirmDialog, {
- chatRoom: room,
- title: room.isMeeting ? l.meeting_archive_dlg : l[19068],
- subtitle: room.isMeeting ? l.meeting_archive_dlg_text : l[19069],
- icon: "sprite-fm-uni icon-question",
- name: "archive-conversation-dialog",
- pref: "4",
- onClose: () => {
- self.setState({
- 'archiveDialog': false
- });
- },
- onConfirmClicked: () => {
- self.props.chatRoom.scrolledToBottom = true;
- room.archive();
- self.setState({
- 'archiveDialog': false
- });
- }
- });
- }
- if (self.state.unarchiveDialog === true) {
- confirmDeleteDialog = REaCt().createElement(modalDialogs.A.ConfirmDialog, {
- chatRoom: room,
- title: room.isMeeting ? l.meeting_unarchive_dlg : l[19063],
- subtitle: room.isMeeting ? l.meeting_unarchive_dlg_text : l[19064],
- icon: "sprite-fm-uni icon-question",
- name: "unarchive-conversation-dialog",
- pref: "5",
- onClose: () => {
- self.setState({
- 'unarchiveDialog': false
- });
- },
- onConfirmClicked: () => {
- self.props.chatRoom.scrolledToBottom = true;
- room.unarchive();
- self.setState({
- 'unarchiveDialog': false
- });
- }
- });
- }
- let topicInfo = null;
- const isUpcoming = room.scheduledMeeting && room.scheduledMeeting.isUpcoming;
- const isRecurring = room.scheduledMeeting && room.scheduledMeeting.isRecurring;
- if (room.type === 'group' || room.type === 'public') {
- topicInfo = REaCt().createElement("div", {
- className: "chat-topic-info"
- }, REaCt().createElement("div", {
- className: `
- chat-topic-icon
- ${room.isMeeting ? 'meeting-icon' : ''}
- `
- }, REaCt().createElement("i", {
- className: room.isMeeting ? 'sprite-fm-mono icon-video-call-filled' : 'sprite-fm-uni icon-chat-group'
- })), REaCt().createElement("div", {
- className: "chat-topic-text"
- }, REaCt().createElement("span", {
- className: "txt"
- }, REaCt().createElement(utils.zT, null, room.getRoomTitle()), isUpcoming && isRecurring && REaCt().createElement("i", {
- className: "sprite-fm-mono recurring-meeting icon-repeat-thin-solid"
- })), REaCt().createElement("span", {
- className: "txt small"
- }, is_chatlink && isUpcoming && !isRecurring ? this.renderUpcomingInfo() : REaCt().createElement(ui_contacts.MembersAmount, {
- chatRoom: room
- }))));
- } else {
- contactHandle = contacts[0];
- contact = M.u[contactHandle || u_handle];
- topicInfo = megaChat.WITH_SELF_NOTE && room.isNote ? REaCt().createElement("div", {
- className: "note-chat-topic"
- }, REaCt().createElement("div", {
- className: "note-chat-signifier"
- }, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-file-text-thin-outline note-chat-icon"
- })), REaCt().createElement("span", {
- className: "note-chat-label"
- }, l.note_label)) : REaCt().createElement(ui_contacts.ContactCard, {
- key: contact.u,
- className: "short",
- chatRoom: room,
- contact,
- noContextButton: true,
- showLastGreen: true
- });
- }
- let historyRetentionDialog = null;
- if (self.state.showHistoryRetentionDialog === true) {
- historyRetentionDialog = REaCt().createElement(HistoryRetentionDialog, {
- chatRoom: room,
- title: '',
- name: "rename-group",
- className: "",
- onClose: () => {
- self.setState({
- showHistoryRetentionDialog: false
- });
- }
- });
- }
- if (this.state.waitingRoom) {
- return REaCt().createElement(WaitingRoom, {
- chatRoom: room,
- havePendingCall: room.havePendingCall(),
- onWaitingRoomLeave: () => {
- let _room$call;
- (_room$call = room.call) == null || _room$call.destroy();
- if (is_eplusplus) {
- room.leave(true);
- return onIdle(M.logout);
- }
- return this.setState({
- waitingRoom: false
- }, () => {
- onIdle(() => {
- if (megaChat.initialChatId) {
- megaChat.initialChatId = undefined;
- loadSubPage(getLandingPage());
- }
- });
- });
- }
- });
- }
- if (this.state.callUserLimit) {
- return REaCt().createElement(ChatOverlay, {
- overlayType: ChatOverlays.PARTICIPANT_LIMIT,
- onClose: () => {
- if (is_eplusplus) {
- location.replace('https://mega.io');
- } else {
- this.setState({
- callUserLimit: false
- });
- }
- }
- });
- }
- const startCallDisabled = isStartCallDisabled(room) || room.iAmWaitingRoomPeer();
- return REaCt().createElement("div", {
- ref: this.domRef,
- className: `
- conversation-panel
- ${room.type === 'public' ? 'group-chat ' : ''}
- ${room.type}-chat
- ${!room.isCurrentlyActive || megaChat._joinDialogIsShown ? 'hidden' : ''}
- `,
- onMouseMove: () => self.onMouseMove(),
- "data-room-id": self.props.chatRoom.chatId
- }, room.meetingsLoading && REaCt().createElement(Loading, {
- chatRoom: room,
- title: room.meetingsLoading.title
- }), room.call && REaCt().createElement(call.Ay, {
- chatRoom: room,
- peers: room.call.peers,
- call: room.call,
- minimized: this.state.callMinimized,
- typingAreaText: this.state.typingAreaText,
- onCallMinimize: () => {
- return this.state.callMinimized ? null : this.setState({
- callMinimized: true
- }, () => {
- this.toggleExpandedFlag();
- this.safeForceUpdate();
- });
- },
- onCallExpand: () => {
- return this.state.callMinimized && this.setState({
- callMinimized: false
- }, () => {
- $.hideTopMenu();
- if ($.dialog) {
- closeDialog();
- }
- loadSubPage('fm/chat');
- room.show();
- this.toggleExpandedFlag();
- });
- },
- didMount: () => {
- this.toggleExpandedFlag();
- if (room.isMeeting) {
- room.updatePublicHandle().catch(dump);
- }
- },
- willUnmount: minimised => this.setState({
- callMinimized: false
- }, () => minimised ? null : this.toggleExpandedFlag()),
- onCallEnd: () => this.safeForceUpdate(),
- onDeleteMessage: msg => this.handleDeleteDialog(msg),
- onTypingAreaChanged: this.updateTypingAreaText,
- parent: this
- }), megaChat.initialPubChatHandle && room.publicChatHandle === megaChat.initialPubChatHandle && !room.call && room.isMeeting && !room.call && room.activeCallIds.length > 0 && REaCt().createElement(Join, {
- initialView: u_type || is_eplusplus ? Join.VIEW.ACCOUNT : Join.VIEW.INITIAL,
- chatRoom: room,
- onJoinGuestClick: (firstName, lastName, audioFlag, videoFlag) => {
- room.meetingsLoading = l.joining;
- u_eplusplus(firstName, lastName).then(() => {
- return megaChat.routing.reinitAndJoinPublicChat(room.chatId, room.publicChatHandle, room.publicChatKey);
- }).then(() => {
- delete megaChat.initialPubChatHandle;
- return megaChat.getChatById(room.chatId).joinCall(audioFlag, videoFlag);
- }).catch(ex => {
- if (d) {
- console.error('E++ account failure!', ex);
- }
- setTimeout(() => {
- msgDialog('warninga', l[135], l.eplusplus_create_failed, escapeHTML(api_strerror(ex) || ex));
- }, 1234);
- eventlog(99745, JSON.stringify([1, String(ex).split('\n')[0]]));
- });
- },
- onJoinClick: (audioFlag, videoFlag) => {
- const {chatId} = room;
- if (room.members[u_handle]) {
- delete megaChat.initialPubChatHandle;
- megaChat.routing.reinitAndOpenExistingChat(chatId, room.publicChatHandle).then(() => {
- return megaChat.getChatById(chatId).joinCall(audioFlag, videoFlag);
- }).catch(ex => {
- console.error("Failed to open existing room and join call:", ex);
- });
- } else {
- megaChat.routing.reinitAndJoinPublicChat(chatId, room.publicChatHandle, room.publicChatKey).then(() => {
- delete megaChat.initialPubChatHandle;
- return megaChat.getChatById(chatId).joinCall(audioFlag, videoFlag);
- }).catch(ex => {
- console.error("Failed to join room:", ex);
- });
- }
- }
- }), REaCt().createElement("div", {
- className: `
- chat-content-block
- ${room.megaChat.chatUIFlags.convPanelCollapse ? 'no-pane' : 'with-pane'}
- `
- }, room.megaChat.chatUIFlags.convPanelCollapse ? null : REaCt().createElement(ConversationRightArea, {
- isVisible: this.props.chatRoom.isCurrentlyActive,
- chatRoom: this.props.chatRoom,
- roomFlags: this.props.chatRoom.flags,
- members: this.props.chatRoom.membersSetFromApi,
- messagesBuff: room.messagesBuff,
- pushSettingsValue: pushNotificationSettings.getDnd(this.props.chatRoom.chatId),
- occurrencesLoading: this.state.occurrencesLoading,
- onStartCall: mode => (0,call.dQ)(room.haveActiveCall(), room).then(() => this.startCall(mode)).catch(() => d && console.warn('Already in a call.')),
- onAttachFromComputerClicked: () => this.props.chatRoom.uploadFromComputer(),
- onTruncateClicked: () => this.setState({
- truncateDialog: true
- }),
- onArchiveClicked: () => this.setState({
- archiveDialog: true
- }),
- onUnarchiveClicked: () => this.setState({
- unarchiveDialog: true
- }),
- onRenameClicked: () => {
- this.setState({
- renameDialog: true,
- renameDialogValue: this.props.chatRoom.getRoomTitle()
- });
- },
- onGetManageChatLinkClicked: () => this.setState({
- chatLinkDialog: true
- }),
- onMakePrivateClicked: () => this.setState({
- privateChatDialog: true
- }),
- onCloseClicked: () => room.destroy(),
- onJoinViaPublicLinkClicked: () => room.joinViaPublicHandle(),
- onSwitchOffPublicMode: topic => room.switchOffPublicMode(topic),
- onAttachFromCloudClicked: () => this.setState({
- attachCloudDialog: true
- }),
- onPushSettingsClicked: () => M.safeShowDialog('push-settings-dialog', () => this.setState({
- pushSettingsDialog: true
- })),
- onPushSettingsToggled: () => {
- return room.dnd || room.dnd === 0 ? this.setState({
- pushSettingsValue: null
- }, () => pushNotificationSettings.disableDnd(room.chatId)) : pushNotificationSettings.setDnd(room.chatId, 0);
- },
- onHistoryRetentionConfig: () => this.setState({
- showHistoryRetentionDialog: true
- }),
- onAddParticipantSelected: contactHashes => {
- room.scrolledToBottom = true;
- if (room.type === 'group' || room.type === 'public') {
- if (room.options.w && room.call) {
- let _room$call$sfuClient;
- (_room$call$sfuClient = room.call.sfuClient) == null || _room$call$sfuClient.wrAllowJoin(contactHashes);
- }
- return room.trigger('onAddUserRequest', [contactHashes]);
- }
- loadingDialog.show();
- megaChat.trigger('onNewGroupChatRequest', [[...room.getParticipantsExceptMe(), ...contactHashes], {
- keyRotation: false,
- topic: ''
- }]);
- },
- onShowScheduledDescription: room.scheduledMeeting ? () => this.setState({
- descriptionDialog: true
- }) : null
- }), this.state.attachCloudDialog && REaCt().createElement(this.CloudBrowserDialog, null), this.state.sendContactDialog && REaCt().createElement(this.SelectContactDialog, null), this.state.descriptionDialog && REaCt().createElement(this.DescriptionDialog, null), this.state.pushSettingsDialog && REaCt().createElement(this.PushSettingsDialog, null), privateChatDialog, nonLoggedInJoinChatDialog, confirmDeleteDialog, historyRetentionDialog, null, this.state.renameDialog && REaCt().createElement(this.RenameDialog, null), this.state.chatLinkDialog && REaCt().createElement(ChatlinkDialog, {
- chatRoom: this.props.chatRoom,
- onClose: () => this.setState({
- chatLinkDialog: false
- })
- }), REaCt().createElement("div", {
- className: `
- chat-topic-block
- ${room.isNote ? 'is-note' : ''}
- `
- }, REaCt().createElement("div", {
- className: "chat-topic-buttons"
- }, room.type === 'public' && room.isMeeting && REaCt().createElement(buttons.$, {
- className: "mega-button small share-meeting-button",
- label: l.share_meeting_button,
- onClick: () => this.setState({
- chatLinkDialog: true
- }, () => eventlog(500230))
- }), REaCt().createElement(buttons.$, {
- className: "right",
- disableCheckingVisibility: true,
- icon: "sprite-fm-mono icon-info-filled",
- onClick: () => room.megaChat.toggleUIFlag('convPanelCollapse')
- }), room.isNote ? null : REaCt().createElement(REaCt().Fragment, null, REaCt().createElement("div", {
- "data-simpletip": l.unsupported_browser_video,
- "data-simpletipposition": "top",
- "data-simpletipoffset": "5",
- className: `
- ${!megaChat.hasSupportForCalls ? 'simpletip' : ''}
- right
- ${startCallDisabled ? 'disabled' : ''}
- `
- }, REaCt().createElement(buttons.$, {
- icon: "sprite-fm-mono icon-video-call-filled",
- onClick: () => startCallDisabled ? false : (0,call.dQ)(room.haveActiveCall(), room).then(() => this.startCall(call.ZE.VIDEO)).catch(() => d && console.warn('Already in a call.')).then(() => room.isMeeting ? eventlog(500289) : eventlog(500290))
- })), REaCt().createElement("div", {
- "data-simpletip": l.unsupported_browser_audio,
- "data-simpletipposition": "top",
- "data-simpletipoffset": "5",
- className: `
- ${!megaChat.hasSupportForCalls ? 'simpletip' : ''}
- right
- ${startCallDisabled ? 'disabled' : ''}
- `
- }, REaCt().createElement(buttons.$, {
- icon: "sprite-fm-mono icon-phone",
- onClick: () => startCallDisabled ? false : (0,call.dQ)(room.haveActiveCall(), room).then(() => this.startCall(call.ZE.AUDIO)).catch(() => d && console.warn('Already in a call.')).then(() => room.isMeeting ? eventlog(500291) : eventlog(500292))
- })))), topicInfo), REaCt().createElement("div", {
- ref: this.messagesBlockRef,
- className: `
- messages-block
- ${""}
- `
- }, this.state.hasInvalidKeys && this.state.invalidKeysBanner && REaCt().createElement(Alert, {
- type: Alert.TYPE.HIGH,
- className: `
- ${megaChat.chatUIFlags.convPanelCollapse ? 'full-span' : ''}
- ${this.props.offset === ALERTS_BASE_OFFSET ? 'single-alert' : ''}
- `,
- offset: this.props.offset === ALERTS_BASE_OFFSET ? 0 : this.props.offset,
- content: REaCt().createElement(REaCt().Fragment, null, l.chat_key_failed_banner.split('[A]')[0], REaCt().createElement("a", {
- onClick: () => M.reload()
- }, l.chat_key_failed_banner.substring(l.chat_key_failed_banner.indexOf('[A]') + 3, l.chat_key_failed_banner.indexOf('[/A]'))), l.chat_key_failed_banner.split('[/A]')[1]),
- onClose: () => this.setState({
- invalidKeysBanner: false
- })
- }), this.state.historyTimeOutBanner === DISMISS_TRANSITIONS.SHOWN && REaCt().createElement(Alert, {
- type: Alert.TYPE.ERROR,
- className: `
- ${megaChat.chatUIFlags.convPanelCollapse ? 'full-span' : ''}
- ${this.props.offset === ALERTS_BASE_OFFSET ? 'single_alert' : ''}
- history-timeout-banner
- `,
- offset: this.props.offset === ALERTS_BASE_OFFSET ? 0 : this.props.offset,
- content: REaCt().createElement(REaCt().Fragment, null, l.chat_timeout_banner, REaCt().createElement("a", {
- onClick: () => location.reload()
- }, l[85])),
- onClose: () => this.setState({
- historyTimeOutBanner: DISMISS_TRANSITIONS.DISMISSED
- })
- }), REaCt().createElement(historyPanel.A, (0,esm_extends.A)({}, this.props, {
- onMessagesListScrollableMount: mls => {
- this.messagesListScrollable = mls;
- },
- ref: historyPanel => {
- this.historyPanel = historyPanel;
- },
- onDeleteClicked: msg => this.handleDeleteDialog(msg)
- })), !is_chatlink && room.state !== ChatRoom.STATE.LEFT && navigator.onLine && room.scheduledMeeting && !room.isArchived() && !this.state.hasInvalidKeys && !isStartCallDisabled(room) ? REaCt().createElement(StartMeetingNotification, {
- chatRoom: room,
- offset: this.props.offset,
- onWaitingRoomJoin: () => this.setState({
- waitingRoom: true
- }),
- onStartCall: mode => {
- return isStartCallDisabled(room) ? null : (0,call.dQ)(true, room).then(() => this.startCall(mode, true)).catch(ex => d && console.warn(`Already in a call. ${ex}`));
- }
- }) : null, !is_chatlink && room.state !== ChatRoom.STATE.LEFT && (room.havePendingGroupCall() || room.havePendingCall()) && !this.state.hasInvalidKeys && navigator.onLine ? REaCt().createElement(JoinCallNotification, {
- rhpCollapsed: megaChat.chatUIFlags.convPanelCollapse,
- chatRoom: room,
- offset: this.props.offset
- }) : null, room.isAnonymous() ? REaCt().createElement("div", {
- className: "join-chat-block"
- }, REaCt().createElement("div", {
- className: "mega-button large positive",
- onClick: () => {
- const join = () => {
- megaChat.routing.reinitAndJoinPublicChat(room.chatId, room.publicChatHandle, room.publicChatKey).then(() => delete megaChat.initialPubChatHandle, ex => console.error("Failed to join room:", ex));
- };
- if (u_type === 0) {
- return loadSubPage('register');
- }
- if (u_type === false) {
- clearTimeout(self.state.setNonLoggedInJoinChatDlgTrue);
- megaChat.loginOrRegisterBeforeJoining(room.publicChatHandle, false, false, false, join);
- return;
- }
- clearTimeout(self.state.setNonLoggedInJoinChatDlgTrue);
- join();
- }
- }, l[20597])) : REaCt().createElement(composedTextArea.A, {
- chatRoom: room,
- parent: this,
- containerRef: this.messagesBlockRef,
- typingAreaText: this.state.typingAreaText,
- onTypingAreaChanged: this.updateTypingAreaText
- }))));
- }
-}, (0,applyDecoratedDescriptor.A)(conversationpanel_class.prototype, "onMouseMove", [conversationpanel_dec], Object.getOwnPropertyDescriptor(conversationpanel_class.prototype, "onMouseMove"), conversationpanel_class.prototype), (0,applyDecoratedDescriptor.A)(conversationpanel_class.prototype, "render", [_dec2], Object.getOwnPropertyDescriptor(conversationpanel_class.prototype, "render"), conversationpanel_class.prototype), conversationpanel_class);
-class ConversationPanels extends mixins.w9 {
- constructor(props) {
- super(props);
- this.domRef = REaCt().createRef();
- this.notificationListener = 'meetings:notificationPermissions';
- this.notificationGranted = undefined;
- this.notificationHelpURL = `${l.mega_help_host}/chats-meetings/meetings/enable-notification-browser-system-permission`;
- this.state = {
- supportAlert: undefined,
- notificationsPermissions: undefined,
- alertsOffset: ALERTS_BASE_OFFSET
- };
- this.closeSupportAlert = () => this.setState({
- supportAlert: false
- }, () => mega.config.set('nocallsup', 1));
- this.onNotificationsGranted = () => {
- msgDialog('info', '', l.notifications_permissions_granted_title, l.notifications_permissions_granted_info.replace('[A]', ``).replace('[/A]', ''));
- this.notificationGranted = new Notification(l.notification_granted_title, {
- body: l.notification_granted_body
- });
- };
- this.state.supportAlert = !megaChat.hasSupportForCalls;
- this.state.notificationsPermissions = window.Notification ? Notification.permission : 'granted';
- }
- renderNotificationsPending() {
- return REaCt().createElement(Alert, {
- type: Alert.TYPE.LIGHT,
- className: `
- ${megaChat.chatUIFlags.convPanelCollapse ? 'full-span' : ''}
- ${this.props.isEmpty ? 'empty-state' : ''}
- `,
- ref: ref => {
- this.notifPendingRef = ref;
- },
- onTransition: ref => this.setState({
- alertsOffset: ref ? ref.current.offsetHeight : ALERTS_BASE_OFFSET
- }),
- onClose: () => {
- this.setState({
- notificationsPermissions: undefined
- }, () => {
- showToast('success', l.notifications_permissions_toast_title, l.notifications_permissions_toast_control, '', () => loadSubPage('fm/account/notifications'));
- });
- }
- }, l.notifications_permissions_pending, REaCt().createElement("div", {
- className: "meetings-alert-control"
- }, REaCt().createElement("a", {
- href: "#",
- onClick: ev => {
- ev.preventDefault();
- Notification.requestPermission().then(status => {
- this.setState({
- notificationsPermissions: status
- }, () => onIdle(() => this.state.notificationsPermissions === 'granted' && this.onNotificationsGranted()));
- }).catch(ex => d && console.warn(`Failed to retrieve permissions: ${ex}`));
- }
- }, l.notifications_permissions_enable)));
- }
- renderNotificationsBlocked() {
- return REaCt().createElement(Alert, {
- type: Alert.TYPE.MEDIUM,
- className: `
- ${megaChat.chatUIFlags.convPanelCollapse ? 'full-span' : ''}
- ${this.props.isEmpty ? 'empty-state' : ''}
- `,
- ref: ref => {
- this.notifBlockedRef = ref;
- },
- onTransition: ref => this.setState({
- alertsOffset: ref ? ref.current.offsetHeight : ALERTS_BASE_OFFSET
- }),
- onClose: () => this.setState({
- notificationsPermissions: undefined
- })
- }, REaCt().createElement(utils.P9, {
- content: l.notifications_permissions_denied_info.replace('[A]', ``).replace('[/A]', '')
- }));
- }
- componentWillUnmount() {
- super.componentWillUnmount();
- mBroadcaster.removeListener(this.notificationListener);
- }
- componentDidMount() {
- let _this$props$onMount, _this$props;
- super.componentDidMount();
- (_this$props$onMount = (_this$props = this.props).onMount) == null || _this$props$onMount.call(_this$props);
- megaChat.chats.forEach(chatRoom => {
- const {
- scheduledMeeting
- } = chatRoom;
- if (scheduledMeeting && !scheduledMeeting.isPast && scheduledMeeting.isRecurring) {
- scheduledMeeting.getOccurrences().catch(nop);
- }
- });
- mBroadcaster.addListener(this.notificationListener, notificationsPermissions => this.isMounted() && this.setState({
- notificationsPermissions
- }));
- window.addEventListener('resize', () => {
- delay('conv-panels-resize', () => {
- if (!M.chat || !this.isMounted()) {
- return;
- }
- const {
- alertsOffset
- } = this.state;
- if (alertsOffset !== ALERTS_BASE_OFFSET) {
- let _this$notifBlockedRef, _this$notifPendingRef, _this$noSupportRef;
- const state = {};
- if ((_this$notifBlockedRef = this.notifBlockedRef) != null && _this$notifBlockedRef.current) {
- state.alertsOffset = this.notifBlockedRef.current.offsetHeight;
- } else if ((_this$notifPendingRef = this.notifPendingRef) != null && _this$notifPendingRef.current) {
- state.alertsOffset = this.notifPendingRef.current.offsetHeight;
- } else if ((_this$noSupportRef = this.noSupportRef) != null && _this$noSupportRef.current) {
- state.alertsOffset = this.noSupportRef.current.offsetHeight;
- }
- if (state.alertsOffset !== alertsOffset) {
- this.setState(state);
- }
- }
- });
- });
- }
- render() {
- const {
- routingSection,
- chatUIFlags,
- isEmpty,
- onToggleExpandedFlag
- } = this.props;
- const {
- notificationsPermissions,
- supportAlert,
- alertsOffset
- } = this.state;
- const now = Date.now();
- return REaCt().createElement("div", {
- ref: this.domRef,
- className: "conversation-panels"
- }, routingSection === 'contacts' || is_chatlink ? null : window.Notification && notificationsPermissions !== 'granted' && REaCt().createElement(REaCt().Fragment, null, notificationsPermissions === 'default' && this.renderNotificationsPending(), notificationsPermissions === 'denied' && this.renderNotificationsBlocked()), routingSection === 'contacts' ? null : supportAlert && !mega.config.get('nocallsup') && REaCt().createElement(Alert, {
- type: Alert.TYPE.MEDIUM,
- className: `
- ${megaChat.chatUIFlags.convPanelCollapse ? 'full-span' : ''}
- ${isEmpty ? 'empty-state' : ''}
- unsupported-call-alert
- `,
- content: call.Ay.getUnsupportedBrowserMessage(),
- ref: ref => {
- this.noSupportRef = ref;
- },
- onTransition: ref => this.setState({
- alertsOffset: ref ? ref.current.offsetHeight : ALERTS_BASE_OFFSET
- }),
- onClose: this.closeSupportAlert
- }), megaChat.chats.map(chatRoom => {
- if (chatRoom.isCurrentlyActive || now - chatRoom.lastShownInUI < 900000) {
- return REaCt().createElement(ConversationPanel, {
- key: `${chatRoom.roomId}_${chatRoom.instanceIndex}`,
- chatRoom,
- roomType: chatRoom.type,
- isExpanded: chatRoom.megaChat.chatUIFlags.convPanelCollapse,
- isActive: chatRoom.isCurrentlyActive,
- messagesBuff: chatRoom.messagesBuff,
- chatUIFlags,
- offset: alertsOffset,
- onToggleExpandedFlag
- });
- }
- return null;
- }));
- }
-}
-class EmptyConvPanel extends REaCt().Component {
- constructor(...args) {
- super(...args);
- this.domRef = REaCt().createRef();
- this.state = {
- linkData: ''
- };
- this.Tile = ({
- title,
- desc,
- imgClass,
- buttonPrimary,
- buttonSecondary,
- onClickPrimary,
- onClickSecondary
- }) => REaCt().createElement("div", {
- className: "conversations-empty-tile"
- }, REaCt().createElement("span", {
- className: `chat-tile-img ${imgClass}`
- }), REaCt().createElement("div", {
- className: "tile-content"
- }, REaCt().createElement("h2", null, title), REaCt().createElement("div", null, desc), REaCt().createElement(buttons.$, {
- className: "mega-button positive",
- label: buttonPrimary,
- onClick: onClickPrimary
- }), buttonSecondary && REaCt().createElement(buttons.$, {
- className: "mega-button action positive",
- icon: "sprite-fm-mono icon-link",
- label: buttonSecondary,
- onClick: onClickSecondary
- })));
- }
- componentDidMount() {
- (M.account && M.account.contactLink ? Promise.resolve(M.account.contactLink) : api.send('clc')).then(res => {
- let _this$domRef;
- if ((_this$domRef = this.domRef) != null && _this$domRef.current && typeof res === 'string') {
- const prefix = res.startsWith('C!') ? '' : 'C!';
- this.setState({
- linkData: `${getBaseUrl()}/${prefix}${res}`
- });
- }
- }).catch(dump);
- }
- render() {
- const {
- isMeeting,
- onNewChat,
- onStartMeeting,
- onScheduleMeeting
- } = this.props;
- const {
- linkData
- } = this.state;
- return REaCt().createElement("div", {
- ref: this.domRef,
- className: "conversations-empty"
- }, REaCt().createElement("div", {
- className: "conversations-empty-header"
- }, REaCt().createElement("h1", null, isMeeting ? l.meetings_empty_header : l.chat_empty_header), REaCt().createElement("h3", null, (0,utils.lI)(isMeeting ? l.meetings_empty_subheader : l.chat_empty_subheader, '[A]', ui_link.A, {
- onClick: () => {
- window.open('https://mega.io/chatandmeetings', '_blank', 'noopener,noreferrer');
- eventlog(this.props.isMeeting ? 500281 : 500280);
- }
- }))), REaCt().createElement("div", {
- className: "conversations-empty-content"
- }, REaCt().createElement(this.Tile, {
- title: isMeeting ? l.meetings_empty_calls_head : l.invite_friend_btn,
- desc: isMeeting ? l.meetings_empty_calls_desc : l.chat_empty_contact_desc,
- imgClass: isMeeting ? 'empty-meetings-call' : 'empty-chat-contacts',
- buttonPrimary: isMeeting ? l.new_meeting_start : l[71],
- buttonSecondary: !isMeeting && linkData && l.copy_contact_link_btn,
- onClickPrimary: () => {
- if (isMeeting) {
- onStartMeeting();
- eventlog(500275);
- } else {
- contactAddDialog();
- eventlog(500276);
- }
- },
- onClickSecondary: () => {
- copyToClipboard(linkData, `${l[371]}${linkData}`);
- delay('chat-event-copy-contact-link', () => eventlog(500277));
- }
- }), REaCt().createElement(this.Tile, {
- title: isMeeting ? l.meetings_empty_schedule_head : l.chat_empty_add_chat_header,
- desc: isMeeting ? l.meetings_empty_schedule_desc : l.chat_empty_add_chat_desc,
- imgClass: isMeeting ? 'empty-meetings-schedule' : 'empty-chat-new',
- buttonPrimary: isMeeting ? l.schedule_meeting_start : l.add_chat,
- onClickPrimary: () => {
- if (isMeeting) {
- onScheduleMeeting();
- eventlog(500278);
- } else {
- onNewChat();
- eventlog(500279);
- }
- }
- })));
- }
-}
-function isStartCallDisabled(room) {
- if ((0,call.P)()) {
- return true;
- }
- if (!megaChat.hasSupportForCalls) {
- return true;
- }
- return !room.isOnlineForCalls() || room.isReadOnly() || !room.chatId || room.call || (room.type === "group" || room.type === "public") && false || room.getCallParticipants().length > 0;
-}
-
-},
-
-732
-(_, EXP_, REQ_) {
-
-"use strict";
-
-// EXPORTS
-REQ_.d(EXP_, {
- qY: () => conversations_EVENTS,
- Vw: () => VIEWS,
- Ay: () => conversations
-});
-
-// EXTERNAL MODULE: ./node_modules/@babel/runtime/helpers/esm/extends.js
-const esm_extends = REQ_(168);
-// EXTERNAL MODULE: external "React"
-const React_ = REQ_(594);
-const REaCt = REQ_.n(React_);
-// EXTERNAL MODULE: ./js/chat/mixins.js
-const mixins = REQ_(137);
-// EXTERNAL MODULE: ./js/chat/ui/conversationpanel.jsx + 15 modules
-const conversationpanel = REQ_(438);
-// EXTERNAL MODULE: ./js/chat/ui/contactsPanel/contactsPanel.jsx + 20 modules
-const contactsPanel = REQ_(173);
-// EXTERNAL MODULE: ./js/ui/modalDialogs.jsx + 1 modules
-const modalDialogs = REQ_(318);
-// EXTERNAL MODULE: ./js/chat/ui/meetings/button.jsx
-const meetings_button = REQ_(959);
-// EXTERNAL MODULE: ./js/chat/ui/meetings/workflow/preview.jsx
-const preview = REQ_(485);
-// EXTERNAL MODULE: ./js/chat/ui/link.jsx
-const ui_link = REQ_(280);
-// EXTERNAL MODULE: ./js/ui/utils.jsx
-const utils = REQ_(314);
-;// ./js/chat/ui/meetings/workflow/start.jsx
-
-let _Start;
-
-
-
-
-
-
-class Start extends REaCt().Component {
- constructor(props) {
- super(props);
- this.inputRef = REaCt().createRef();
- this.defaultTopic = l.default_meeting_topic.replace('%NAME', M.getNameByHandle(u_handle));
- this.state = {
- audio: false,
- video: false,
- editing: false,
- previousTopic: undefined,
- topic: undefined
- };
- this.handleChange = ev => this.setState({
- topic: ev.target.value
- });
- this.toggleEdit = () => {
- this.setState(state => {
- const topic = state.topic.trim() || this.defaultTopic;
- return {
- editing: !state.editing,
- topic,
- previousTopic: topic
- };
- }, () => onIdle(this.doFocus));
- };
- this.doFocus = () => {
- if (this.state.editing) {
- const input = this.inputRef.current;
- input.focus();
- input.setSelectionRange(0, input.value.length);
- }
- };
- this.doReset = () => this.setState(state => ({
- editing: false,
- topic: state.previousTopic,
- previousTopic: undefined
- }));
- this.bindEvents = () => $(document).rebind(`mousedown.${Start.NAMESPACE}`, ev => {
- if (this.state.editing && !ev.target.classList.contains(Start.CLASS_NAMES.EDIT) && !ev.target.classList.contains(Start.CLASS_NAMES.INPUT)) {
- this.toggleEdit();
- }
- }).rebind(`keyup.${Start.NAMESPACE}`, ({
- keyCode
- }) => {
- if (this.state.editing) {
- const [ENTER, ESCAPE] = [13, 27];
- return keyCode === ENTER ? this.toggleEdit() : keyCode === ESCAPE ? this.doReset() : null;
- }
- });
- this.Input = () => REaCt().createElement("input", {
- type: "text",
- ref: this.inputRef,
- className: Start.CLASS_NAMES.INPUT,
- value: this.state.topic,
- maxLength: ChatRoom.TOPIC_MAX_LENGTH,
- onChange: this.handleChange
- });
- this.onStreamToggle = (audio, video) => this.setState({
- audio,
- video
- });
- this.startMeeting = () => {
- const {
- onStart
- } = this.props;
- const {
- topic,
- audio,
- video
- } = this.state;
- if (onStart) {
- onStart(topic.trim() || this.defaultTopic, audio, video);
- }
- };
- this.state.topic = this.defaultTopic;
- }
- componentDidMount() {
- this.bindEvents();
- if ($.dialog === 'onboardingDialog') {
- closeDialog();
- }
- M.safeShowDialog(Start.dialogName, () => $(`#${Start.NAMESPACE}`));
- }
- componentWillUnmount() {
- $(document).unbind(`.${Start.NAMESPACE}`);
- if ($.dialog === Start.dialogName) {
- closeDialog();
- }
- }
- render() {
- const {
- NAMESPACE,
- CLASS_NAMES
- } = Start;
- const {
- editing,
- topic
- } = this.state;
- return REaCt().createElement(modalDialogs.A.ModalDialog, (0,esm_extends.A)({}, this.state, {
- id: NAMESPACE,
- dialogName: NAMESPACE,
- className: NAMESPACE,
- stopKeyPropagation: editing,
- onClose: () => this.props.onClose()
- }), REaCt().createElement("div", {
- className: `${NAMESPACE}-preview`
- }, REaCt().createElement(preview.A, {
- context: NAMESPACE,
- onToggle: this.onStreamToggle
- })), REaCt().createElement("div", {
- className: "fm-dialog-body"
- }, REaCt().createElement("div", {
- className: `${NAMESPACE}-title`
- }, editing ? REaCt().createElement(this.Input, null) : REaCt().createElement("h2", {
- onClick: this.toggleEdit
- }, REaCt().createElement(utils.zT, null, topic)), REaCt().createElement(meetings_button.A, {
- className: `
- mega-button
- action
- small
- ${CLASS_NAMES.EDIT}
- ${editing ? 'editing' : ''}
- `,
- icon: "icon-rename",
- simpletip: {
- label: l[1342],
- position: 'top'
- },
- onClick: this.toggleEdit
- }, REaCt().createElement("span", null, l[1342]))), REaCt().createElement(meetings_button.A, {
- className: "mega-button positive large start-meeting-button",
- onClick: () => {
- this.startMeeting();
- eventlog(500235);
- }
- }, REaCt().createElement("span", null, l[7315])), REaCt().createElement(ui_link.A, {
- to: "https://mega.io/chatandmeetings",
- target: "_blank"
- }, l.how_meetings_work)));
- }
-}
-_Start = Start;
-Start.NAMESPACE = 'start-meeting';
-Start.dialogName = `${_Start.NAMESPACE}-dialog`;
-Start.CLASS_NAMES = {
- EDIT: 'call-title-edit',
- INPUT: 'call-title-input'
-};
-Start.STREAMS = {
- AUDIO: 1,
- VIDEO: 2
-};
-window.StartMeetingDialogUI = {
- Start
-};
-// EXTERNAL MODULE: ./js/ui/perfectScrollbar.jsx
-const perfectScrollbar = REQ_(486);
-// EXTERNAL MODULE: ./js/chat/ui/contacts.jsx
-const ui_contacts = REQ_(251);
-;// ./js/chat/ui/meetings/schedule/invite.jsx
-
-
-
-
-class Invite extends mixins.w9 {
- constructor(props) {
- super(props);
- this.domRef = REaCt().createRef();
- this.wrapperRef = REaCt().createRef();
- this.inputRef = REaCt().createRef();
- this.state = {
- value: '',
- expanded: false,
- loading: true,
- frequents: [],
- frequentsInitial: [],
- contacts: [],
- contactsInitial: [],
- selected: []
- };
- this.handleMousedown = ({
- target
- }) => this.domRef && this.domRef.current && this.domRef.current.contains(target) ? null : this.setState({
- expanded: false
- });
- this.getSortedContactsList = frequents => {
- const filteredContacts = [];
- M.u.forEach(contact => {
- if (contact.c === 1 && !frequents.includes(contact.u) && !this.state.selected.includes(contact.u)) {
- filteredContacts.push(contact);
- }
- });
- const sortFn = M.getSortByNameFn2(1);
- filteredContacts.sort((a, b) => sortFn(a, b));
- return filteredContacts;
- };
- this.doMatch = (value, collection) => {
- value = value.toLowerCase();
- return collection.filter(contact => {
- contact = typeof contact === 'string' ? M.getUserByHandle(contact) : contact;
- const name = M.getNameByHandle(contact.u).toLowerCase();
- const email = contact.m && contact.m.toLowerCase();
- return name.includes(value) || email.includes(value);
- });
- };
- this.handleSearch = this.handleSearch.bind(this);
- this.state.selected = this.props.participants || [];
- }
- reinitializeWrapper() {
- const wrapperRef = this.wrapperRef && this.wrapperRef.current;
- if (wrapperRef) {
- wrapperRef.reinitialise();
- wrapperRef.scrollToY(0);
- }
- }
- buildContactsList() {
- megaChat.getFrequentContacts().then(frequentContacts => {
- if (this.isMounted()) {
- const frequents = frequentContacts.slice(-ui_contacts.MAX_FREQUENTS).map(c => c.userId);
- const contacts = this.getSortedContactsList(frequents);
- this.setState({
- frequents,
- frequentsInitial: frequents,
- contacts,
- contactsInitial: contacts,
- loading: false
- });
- }
- });
- }
- handleSearch(ev) {
- const {
- value
- } = ev.target;
- const searching = value.length >= 2;
- const frequents = searching ? this.doMatch(value, this.state.frequentsInitial) : this.state.frequentsInitial;
- const contacts = searching ? this.doMatch(value, this.state.contactsInitial) : this.state.contactsInitial;
- this.setState({
- value,
- contacts,
- frequents
- }, () => this.reinitializeWrapper());
- }
- handleSelect({
- userHandle,
- expanded = false
- }) {
- this.setState(state => ({
- value: '',
- expanded,
- selected: state.selected.includes(userHandle) ? state.selected.filter(c => c !== userHandle) : [...state.selected, userHandle]
- }), () => {
- let _this$inputRef$curren;
- this.props.onSelect(this.state.selected);
- this.buildContactsList();
- this.reinitializeWrapper();
- (_this$inputRef$curren = this.inputRef.current) == null || _this$inputRef$curren.focus();
- });
- }
- getFilteredContacts(contacts) {
- if (contacts && contacts.length) {
- return contacts.map(contact => {
- contact = contact instanceof MegaDataMap ? contact : M.u[contact];
- return this.state.selected.includes(contact.u) ? null : REaCt().createElement("div", {
- key: contact.u,
- className: "invite-section-item",
- onClick: () => {
- this.handleSelect({
- userHandle: contact.u,
- expanded: true
- });
- }
- }, REaCt().createElement(ui_contacts.Avatar, {
- contact
- }), REaCt().createElement("div", {
- className: "invite-item-data"
- }, REaCt().createElement("div", {
- className: "invite-item-name"
- }, REaCt().createElement(ui_contacts.ContactAwareName, {
- overflow: true,
- simpletip: {
- offset: 10
- },
- contact
- })), REaCt().createElement("div", {
- className: "invite-item-mail"
- }, contact.m)));
- });
- }
- return null;
- }
- renderContent() {
- const {
- frequents,
- contacts,
- selected
- } = this.state;
- const hasMoreFrequents = frequents.length && frequents.some(h => !selected.includes(h));
- const $$SECTION = (title, children) => REaCt().createElement("div", {
- className: "invite-section"
- }, REaCt().createElement("div", {
- className: "invite-section-title"
- }, title), children && REaCt().createElement("div", {
- className: "invite-section-list"
- }, children));
- if (hasMoreFrequents || contacts.length) {
- return REaCt().createElement(perfectScrollbar.O, {
- ref: this.wrapperRef,
- className: "invite-scroll-wrapper",
- options: {
- 'suppressScrollX': true
- }
- }, hasMoreFrequents ? $$SECTION(l.recent_contact_label, this.getFilteredContacts(frequents)) : '', contacts.length ? $$SECTION(l.all_contact_label, this.getFilteredContacts(contacts)) : '', frequents.length === 0 && contacts.length === 0 && $$SECTION(l.invite_no_results_found, null));
- }
- return $$SECTION(l.invite_no_contacts_to_add, null);
- }
- componentWillUnmount() {
- super.componentWillUnmount();
- document.removeEventListener('mousedown', this.handleMousedown);
- }
- componentDidMount() {
- super.componentDidMount();
- document.addEventListener('mousedown', this.handleMousedown);
- this.buildContactsList();
- }
- render() {
- const {
- className,
- isLoading
- } = this.props;
- const {
- value,
- expanded,
- loading,
- selected
- } = this.state;
- return REaCt().createElement("div", {
- ref: this.domRef,
- className: `
- ${Invite.NAMESPACE}
- ${className || ''}
- `
- }, REaCt().createElement("div", {
- className: "multiple-input"
- }, REaCt().createElement("ul", {
- className: "token-input-list-mega",
- onClick: ({
- target
- }) => isLoading ? null : target.classList.contains('token-input-list-mega') && this.setState({
- expanded: true
- })
- }, selected.map(handle => {
- return REaCt().createElement("li", {
- key: handle,
- className: "token-input-token-mega"
- }, REaCt().createElement("div", {
- className: "contact-tag-item"
- }, REaCt().createElement(ui_contacts.Avatar, {
- contact: M.u[handle],
- className: "avatar-wrapper box-avatar"
- }), REaCt().createElement(ui_contacts.ContactAwareName, {
- contact: M.u[handle],
- overflow: true
- }), REaCt().createElement("i", {
- className: "sprite-fm-mono icon-close-component",
- onClick: () => isLoading ? null : this.handleSelect({
- userHandle: handle
- })
- })));
- }), REaCt().createElement("li", {
- className: "token-input-input-token-mega"
- }, REaCt().createElement("input", {
- ref: this.inputRef,
- type: "text",
- name: "participants",
- className: `${Invite.NAMESPACE}-input`,
- disabled: isLoading,
- autoComplete: "off",
- placeholder: selected.length ? '' : l.schedule_participant_input,
- value,
- onClick: () => this.setState({
- expanded: true
- }),
- onChange: this.handleSearch,
- onKeyDown: ({
- target,
- keyCode
- }) => {
- const {
- selected
- } = this.state;
- return keyCode === 8 && target.value === '' && selected.length && this.handleSelect({
- userHandle: selected[selected.length - 1]
- });
- }
- })))), loading ? null : REaCt().createElement("div", {
- className: `mega-input-dropdown ${expanded ? '' : 'hidden'}`
- }, this.renderContent()));
- }
-}
-Invite.NAMESPACE = 'meetings-invite';
-// EXTERNAL MODULE: ./js/chat/ui/meetings/schedule/helpers.jsx
-const helpers = REQ_(110);
-;// ./js/chat/ui/meetings/schedule/dateObserver.jsx
-
-
-const withDateObserver = Component => class extends REaCt().Component {
- constructor(...args) {
- super(...args);
- this.listener = undefined;
- this.state = {
- timestamp: undefined
- };
- }
- componentWillUnmount() {
- mBroadcaster.removeListener(this.listener);
- }
- componentDidMount() {
- this.listener = mBroadcaster.addListener(withDateObserver.NAMESPACE, timestamp => this.setState({
- timestamp
- }));
- }
- render() {
- return REaCt().createElement(Component, (0,esm_extends.A)({}, this.props, {
- timestamp: this.state.timestamp
- }));
- }
-};
-withDateObserver.NAMESPACE = 'meetings:onSelectDate';
-;// ./js/chat/ui/meetings/schedule/datepicker.jsx
-
-
-
-class Datepicker extends REaCt().Component {
- constructor(props) {
- super(props);
- this.OPTIONS = {
- classes: 'meetings-datepicker-calendar',
- dateFormat: '@',
- minDate: null,
- startDate: null,
- selectedDates: [],
- prevHtml: '',
- nextHtml: '',
- altField: null,
- firstDay: 0,
- autoClose: true,
- toggleSelected: false,
- position: 'bottom left',
- language: {
- daysMin: [l[8763], l[8764], l[8765], l[8766], l[8767], l[8768], l[8769]],
- months: [l[408], l[409], l[410], l[411], l[412], l[413], l[414], l[415], l[416], l[417], l[418], l[419]],
- monthsShort: [l[24035], l[24037], l[24036], l[24038], l[24047], l[24039], l[24040], l[24041], l[24042], l[24043], l[24044], l[24045]]
- },
- onSelect: dateText => {
- const prevDate = new Date(+this.props.value);
- const nextDate = new Date(+dateText);
- nextDate.setHours(prevDate.getHours(), prevDate.getMinutes());
- this.props.onSelect(nextDate.getTime());
- mBroadcaster.sendMessage(withDateObserver.NAMESPACE, nextDate.getTime());
- }
- };
- this.domRef = REaCt().createRef();
- this.inputRef = REaCt().createRef();
- this.datepicker = null;
- this.formatValue = value => {
- if (typeof value === 'number') {
- return time2date(value / 1000, 18);
- }
- return value;
- };
- this.OPTIONS.startDate = new Date(this.props.startDate);
- this.OPTIONS.selectedDates = this.props.selectedDates || [this.OPTIONS.startDate];
- this.OPTIONS.minDate = this.props.minDate ? new Date(this.props.minDate) : new Date();
- this.OPTIONS.position = this.props.position || this.OPTIONS.position;
- this.OPTIONS.altField = `input.${this.props.altField}`;
- }
- initialize() {
- const inputRef = this.inputRef && this.inputRef.current;
- if (inputRef) {
- let _this$props$onMount, _this$props;
- $(inputRef).datepicker(this.OPTIONS);
- this.datepicker = $(inputRef).data('datepicker');
- (_this$props$onMount = (_this$props = this.props).onMount) == null || _this$props$onMount.call(_this$props, this.datepicker);
- }
- }
- componentWillUnmount() {
- if (this.domRef && this.domRef.current) {
- $(this.domRef.current).unbind(`keyup.${Datepicker.NAMESPACE}`);
- }
- }
- componentDidMount() {
- M.require('datepicker_js').done(() => this.initialize());
- if (this.domRef && this.domRef.current) {
- $(this.domRef.current).rebind(`keyup.${Datepicker.NAMESPACE}`, ({
- keyCode
- }) => {
- if (keyCode === 13) {
- this.datepicker.hide();
- return false;
- }
- });
- }
- }
- render() {
- const {
- NAMESPACE
- } = Datepicker;
- const {
- value,
- name,
- className,
- placeholder,
- isLoading,
- onFocus,
- onChange,
- onBlur
- } = this.props;
- const formattedValue = this.formatValue(value);
- return REaCt().createElement("div", {
- ref: this.domRef,
- className: NAMESPACE
- }, REaCt().createElement("div", {
- className: "mega-input datepicker-input"
- }, REaCt().createElement("input", {
- ref: this.inputRef,
- type: "text",
- name,
- className: `
- dialog-input
- ${className || ''}
- `,
- autoComplete: "off",
- disabled: isLoading,
- placeholder: placeholder || '',
- value: formattedValue,
- onFocus: ev => onFocus == null ? void 0 : onFocus(ev),
- onChange: ev => onChange == null ? void 0 : onChange(ev),
- onBlur: ev => onBlur == null ? void 0 : onBlur(ev)
- }), REaCt().createElement("i", {
- className: "sprite-fm-mono icon-calendar1",
- onClick: isLoading ? null : () => {
- if (this.datepicker) {
- let _this$inputRef$curren;
- this.datepicker.show();
- (_this$inputRef$curren = this.inputRef.current) == null || _this$inputRef$curren.focus();
- }
- }
- })));
- }
-}
-Datepicker.NAMESPACE = 'meetings-datepicker';
-const datepicker = (0,mixins.Zz)(withDateObserver)(Datepicker);
-;// ./js/chat/ui/meetings/schedule/select.jsx
-
-
-
-
-
-class Select extends REaCt().Component {
- constructor(...args) {
- super(...args);
- this.domRef = REaCt().createRef();
- this.inputRef = REaCt().createRef();
- this.menuRef = REaCt().createRef();
- this.optionRefs = {};
- this.state = {
- expanded: false,
- manualTimeInput: '',
- timestamp: ''
- };
- this.handleMousedown = ({
- target
- }) => {
- let _this$domRef;
- return (_this$domRef = this.domRef) != null && _this$domRef.current.contains(target) ? null : this.setState({
- expanded: false
- });
- };
- this.handleToggle = ({
- target
- } = {}) => {
- let _this$menuRef, _menuRef$domRef;
- const menuRef = (_this$menuRef = this.menuRef) == null ? void 0 : _this$menuRef.current;
- const menuElement = (_menuRef$domRef = menuRef.domRef) == null ? void 0 : _menuRef$domRef.current;
- if (target !== menuElement) {
- const {
- value
- } = this.props;
- this.setState(state => ({
- expanded: !state.expanded
- }), () => {
- if (value && this.optionRefs[value]) {
- menuRef.scrollToElement(this.optionRefs[value]);
- }
- });
- }
- };
- }
- getFormattedDuration(duration) {
- duration = moment.duration(duration);
- const days = duration.get('days');
- const hours = duration.get('hours');
- const minutes = duration.get('minutes');
- if (!hours && !minutes && !days) {
- return '';
- }
- const totalHours = days ? ~~duration.asHours() : hours;
- if (!hours && minutes) {
- return days ? `(${totalHours}\u00a0h ${minutes}\u00a0m)` : `(${minutes}\u00a0m)`;
- }
- return minutes ? `(${totalHours}\u00a0h ${minutes}\u00a0m)` : `(${totalHours}\u00a0h)`;
- }
- componentWillUnmount() {
- document.removeEventListener('mousedown', this.handleMousedown);
- if (this.inputRef && this.inputRef.current) {
- $(this.inputRef.current).unbind(`keyup.${Select.NAMESPACE}`);
- }
- }
- componentDidMount() {
- let _this$inputRef;
- document.addEventListener('mousedown', this.handleMousedown);
- const inputRef = (_this$inputRef = this.inputRef) == null ? void 0 : _this$inputRef.current;
- if (inputRef) {
- $(inputRef).rebind(`keyup.${Select.NAMESPACE}`, ({
- keyCode
- }) => {
- if (keyCode === 13) {
- this.handleToggle();
- inputRef.blur();
- return false;
- }
- });
- }
- }
- render() {
- const {
- NAMESPACE
- } = Select;
- const {
- name,
- className,
- icon,
- typeable,
- options,
- value,
- format,
- isLoading,
- onChange,
- onBlur,
- onSelect
- } = this.props;
- return REaCt().createElement("div", {
- ref: this.domRef,
- className: `
- ${NAMESPACE}
- ${className || ''}
- `
- }, REaCt().createElement("div", {
- className: `
- mega-input
- dropdown-input
- ${typeable ? 'typeable' : ''}
- `,
- onClick: isLoading ? null : this.handleToggle
- }, typeable ? null : value && REaCt().createElement("span", null, format ? format(value) : value), REaCt().createElement("input", {
- ref: this.inputRef,
- type: "text",
- className: `
- ${NAMESPACE}-input
- ${name}
- `,
- value: (() => {
- if (this.state.manualTimeInput) {
- return this.state.manualTimeInput;
- }
- return format ? format(value) : value;
- })(),
- onFocus: ({
- target
- }) => {
- this.setState({
- manualTimeInput: '',
- timestamp: ''
- }, () => target.select());
- },
- onChange: ({
- target
- }) => {
- const {
- value: manualTimeInput
- } = target;
- const {
- value
- } = this.props;
- const prevDate = moment(value);
- const inputTime = (0,helpers.We)(manualTimeInput);
- prevDate.set({
- hours: inputTime.get('hours'),
- minutes: inputTime.get('minutes')
- });
- const timestamp = prevDate.valueOf();
- onChange == null || onChange(timestamp);
- if (this.optionRefs[value]) {
- this.menuRef.current.scrollToElement(this.optionRefs[value]);
- }
- this.setState({
- manualTimeInput,
- timestamp
- });
- },
- onBlur: () => {
- onBlur(this.state.timestamp);
- this.setState({
- manualTimeInput: '',
- timestamp: ''
- });
- }
- }), icon && REaCt().createElement("i", {
- className: "sprite-fm-mono icon-dropdown"
- }), options && REaCt().createElement("div", {
- className: `
- mega-input-dropdown
- ${this.state.expanded ? '' : 'hidden'}
- `
- }, REaCt().createElement(perfectScrollbar.O, {
- ref: this.menuRef,
- options: {
- suppressScrollX: true
- }
- }, options.map(option => {
- return REaCt().createElement("div", {
- ref: ref => {
- this.optionRefs[option.value] = ref;
- },
- key: option.value,
- className: `
- option
- ${option.value === value || option.label === value ? 'active' : ''}
- `,
- onClick: () => onSelect(option)
- }, option.label, "\xA0", option.duration && this.getFormattedDuration(option.duration));
- })))));
- }
-}
-Select.NAMESPACE = 'meetings-select';
-const schedule_select = (0,mixins.Zz)(withDateObserver)(Select);
-;// ./js/chat/ui/meetings/schedule/datetime.jsx
-
-
-
-
-class DateTime extends REaCt().Component {
- constructor(...args) {
- super(...args);
- this.state = {
- datepickerRef: undefined,
- manualDateInput: '',
- manualTimeInput: '',
- initialDate: ''
- };
- this.handleChange = ev => {
- const {
- onChange
- } = this.props;
- const {
- datepickerRef,
- initialDate
- } = this.state;
- if (!datepickerRef) {
- return;
- }
- const {
- value
- } = ev.target;
- const date = (0,helpers.XH)(value);
- const timestamp = date.valueOf();
- const dateObj = new Date(timestamp);
- dateObj.setHours(initialDate.getHours(), initialDate.getMinutes());
- datepickerRef.selectedDates = [dateObj];
- datepickerRef.currentDate = dateObj;
- datepickerRef.nav._render();
- datepickerRef.views.days._render();
- onChange == null || onChange(value);
- this.setState({
- manualDateInput: dateObj.getTime()
- });
- };
- }
- render() {
- const {
- name,
- startDate,
- altField,
- value,
- minDate,
- filteredTimeIntervals,
- label,
- isLoading,
- onMount,
- onSelectDate,
- onSelectTime,
- onBlur
- } = this.props;
- return REaCt().createElement(REaCt().Fragment, null, label && REaCt().createElement("span", null, label), REaCt().createElement(datepicker, {
- name: `${datepicker.NAMESPACE}-${name}`,
- className: isLoading ? 'disabled' : '',
- isLoading,
- startDate,
- altField: `${schedule_select.NAMESPACE}-${altField}`,
- value,
- minDate,
- onMount: datepickerRef => this.setState({
- datepickerRef
- }, () => onMount(datepickerRef)),
- onSelect: onSelectDate,
- onFocus: ({
- target
- }) => {
- this.setState({
- manualDateInput: undefined,
- manualTimeInput: undefined,
- initialDate: new Date(value)
- }, () => target.select());
- },
- onChange: this.handleChange,
- onBlur: () => onBlur(this.state.manualDateInput)
- }), REaCt().createElement(schedule_select, {
- name: `${schedule_select.NAMESPACE}-${altField}`,
- className: isLoading ? 'disabled' : '',
- isLoading,
- typeable: true,
- options: filteredTimeIntervals,
- value: (() => typeof value === 'number' ? value : this.state.datepickerRef.currentDate.getTime())(),
- format: toLocaleTime,
- onSelect: onSelectTime,
- onChange: () => false,
- onBlur: timestamp => {
- if (timestamp) {
- onSelectTime({
- value: timestamp
- });
- }
- }
- }));
- }
-}
-;// ./js/chat/ui/meetings/schedule/recurring.jsx
-
-
-
-
-
-
-
-
-
-
-
-
-class Recurring extends mixins.w9 {
- constructor(props) {
- let _Object$values$find;
- super(props);
- this.domRef = REaCt().createRef();
- this.VIEWS = {
- DAILY: 0x00,
- WEEKLY: 0x01,
- MONTHLY: 0x02
- };
- this.FREQUENCIES = {
- DAILY: 'd',
- WEEKLY: 'w',
- MONTHLY: 'm'
- };
- this.WEEK_DAYS = {
- MONDAY: {
- value: 1,
- label: l.schedule_day_control_mon
- },
- TUESDAY: {
- value: 2,
- label: l.schedule_day_control_tue
- },
- WEDNESDAY: {
- value: 3,
- label: l.schedule_day_control_wed
- },
- THURSDAY: {
- value: 4,
- label: l.schedule_day_control_thu
- },
- FRIDAY: {
- value: 5,
- label: l.schedule_day_control_fri
- },
- SATURDAY: {
- value: 6,
- label: l.schedule_day_control_sat
- },
- SUNDAY: {
- value: 7,
- label: l.schedule_day_control_sun
- }
- };
- this.OFFSETS = [[l.recur_freq_offset_first_mon || '[A]first[/A][B]Monday[/B]', l.recur_freq_offset_first_tue || '[A]first[/A][B]Tuesday[/B]', l.recur_freq_offset_first_wed || '[A]first[/A][B]Wednesday[/B]', l.recur_freq_offset_first_thu || '[A]first[/A][B]Thursday[/B]', l.recur_freq_offset_first_fri || '[A]first[/A][B]Friday[/B]', l.recur_freq_offset_first_sat || '[A]first[/A][B]Saturday[/B]', l.recur_freq_offset_first_sun || '[A]first[/A][B]Sunday[/B]'], [l.recur_freq_offset_second_mon || '[A]second[/A][B]Monday[/B]', l.recur_freq_offset_second_tue || '[A]second[/A][B]Tuesday[/B]', l.recur_freq_offset_second_wed || '[A]second[/A][B]Wednesday[/B]', l.recur_freq_offset_second_thu || '[A]second[/A][B]Thursday[/B]', l.recur_freq_offset_second_fri || '[A]second[/A][B]Friday[/B]', l.recur_freq_offset_second_sat || '[A]second[/A][B]Saturday[/B]', l.recur_freq_offset_second_sun || '[A]second[/A][B]Sunday[/B]'], [l.recur_freq_offset_third_mon || '[A]third[/A][B]Monday[/B]', l.recur_freq_offset_third_tue || '[A]third[/A][B]Tuesday[/B]', l.recur_freq_offset_third_wed || '[A]third[/A][B]Wednesday[/B]', l.recur_freq_offset_third_thu || '[A]third[/A][B]Thursday[/B]', l.recur_freq_offset_third_fri || '[A]third[/A][B]Friday[/B]', l.recur_freq_offset_third_sat || '[A]third[/A][B]Saturday[/B]', l.recur_freq_offset_third_sun || '[A]third[/A][B]Sunday[/B]'], [l.recur_freq_offset_fourth_mon || '[A]fourth[/A][B]Monday[/B]', l.recur_freq_offset_fourth_tue || '[A]fourth[/A][B]Tuesday[/B]', l.recur_freq_offset_fourth_wed || '[A]fourth[/A][B]Wednesday[/B]', l.recur_freq_offset_fourth_thu || '[A]fourth[/A][B]Thursday[/B]', l.recur_freq_offset_fourth_fri || '[A]fourth[/A][B]Friday[/B]', l.recur_freq_offset_fourth_sat || '[A]fourth[/A][B]Saturday[/B]', l.recur_freq_offset_fourth_sun || '[A]fourth[/A][B]Sunday[/B]'], [l.recur_freq_offset_fifth_mon || '[A]fifth[/A][B]Monday[/B]', l.recur_freq_offset_fifth_tue || '[A]fifth[/A][B]Tuesday[/B]', l.recur_freq_offset_fifth_wed || '[A]fifth[/A][B]Wednesday[/B]', l.recur_freq_offset_fifth_thu || '[A]fifth[/A][B]Thursday[/B]', l.recur_freq_offset_fifth_fri || '[A]fifth[/A][B]Friday[/B]', l.recur_freq_offset_fifth_sat || '[A]fifth[/A][B]Saturday[/B]', l.recur_freq_offset_fifth_sun || '[A]fifth[/A][B]Sunday[/B]']];
- this.OFFSET_POS_REGEX = /\[A]([^[]+)\[\/A]/;
- this.OFFSET_DAY_REGEX = /\[B]([^[]+)\[\/B]/;
- this.MONTH_RULES = {
- DAY: 'day',
- OFFSET: 'offset'
- };
- this.initialEnd = (0,helpers.PS)(this.props.startDateTime, 6);
- this.initialWeekDays = Object.values(this.WEEK_DAYS).map(d => d.value);
- this.initialMonthDay = this.props.startDateTime ? new Date(this.props.startDateTime).getDate() : undefined;
- this.state = {
- view: this.VIEWS.DAILY,
- frequency: this.FREQUENCIES.DAILY,
- end: this.initialEnd,
- prevEnd: undefined,
- interval: 0,
- weekDays: this.initialWeekDays,
- monthRule: this.MONTH_RULES.DAY,
- monthDays: [this.initialMonthDay],
- offset: {
- value: 1,
- weekDay: 1
- },
- monthDaysWarning: this.initialMonthDay > 28
- };
- this.toggleView = (view, frequency, state) => this.props.isLoading ? null : this.setState({
- view,
- frequency,
- ...state
- });
- this.MonthDaySelect = ({
- offset
- }) => {
- const dayIdx = (offset && offset.weekDay || 1) - 1;
- const posIdx = (offset && offset.value || 1) - 1;
- const dayValues = this.OFFSETS[posIdx].map((part, idx) => ({
- value: idx + 1,
- label: this.OFFSET_DAY_REGEX.exec(part)[1]
- }));
- const posValues = [];
- for (let i = 0; i < this.OFFSETS.length; i++) {
- posValues.push({
- value: i + 1,
- label: this.OFFSET_POS_REGEX.exec(this.OFFSETS[i][dayIdx])[1]
- });
- }
- const posFirst = this.OFFSETS[posIdx][dayIdx].indexOf('[A]') < this.OFFSETS[posIdx][dayIdx].indexOf('[B]');
- const pos = REaCt().createElement(schedule_select, {
- name: "recurring-offset-value",
- className: "inline",
- icon: true,
- value: posValues[posIdx].label,
- isLoading: this.props.isLoading,
- options: posValues,
- onSelect: option => {
- this.setState(state => ({
- monthRule: this.MONTH_RULES.OFFSET,
- offset: {
- value: option.value,
- weekDay: state.offset.weekDay || this.WEEK_DAYS.MONDAY.value
- }
- }));
- }
- });
- return REaCt().createElement(REaCt().Fragment, null, posFirst && pos, REaCt().createElement(schedule_select, {
- name: "recurring-offset-day",
- className: "inline",
- icon: true,
- value: dayValues[dayIdx].label,
- isLoading: this.props.isLoading,
- options: dayValues,
- onSelect: option => {
- this.setState(state => ({
- monthRule: this.MONTH_RULES.OFFSET,
- offset: {
- value: state.offset.value || 1,
- weekDay: option.value
- }
- }));
- }
- }), !posFirst && pos);
- };
- this.IntervalSelect = () => {
- const {
- interval,
- view
- } = this.state;
- return REaCt().createElement("div", {
- className: "mega-input inline recurring-interval"
- }, REaCt().createElement(schedule_select, {
- name: `${Recurring.NAMESPACE}-interval`,
- value: interval > 0 ? interval : 1,
- icon: true,
- isLoading: this.props.isLoading,
- options: [...Array(view === this.VIEWS.WEEKLY ? 52 : 12).keys()].map(value => {
- value += 1;
- return {
- value,
- label: value
- };
- }),
- onSelect: ({
- value
- }) => {
- this.setState({
- interval: value === 1 ? 0 : value
- });
- }
- }));
- };
- const {
- chatRoom,
- startDateTime
- } = this.props;
- const weekDay = new Date(startDateTime).getDay();
- this.state.offset.weekDay = ((_Object$values$find = Object.values(this.WEEK_DAYS).find(d => d.value === weekDay)) == null ? void 0 : _Object$values$find.value) || this.WEEK_DAYS.SUNDAY.value;
- if (chatRoom && chatRoom.scheduledMeeting && chatRoom.scheduledMeeting.isRecurring) {
- const {
- frequency,
- interval,
- end,
- weekDays,
- monthDays,
- offset
- } = chatRoom.scheduledMeeting.recurring;
- this.state.view = frequency === 'd' ? this.VIEWS.DAILY : frequency === 'w' ? this.VIEWS.WEEKLY : this.VIEWS.MONTHLY;
- this.state.frequency = frequency;
- this.state.end = end;
- this.state.interval = interval;
- this.state.weekDays = weekDays && weekDays.length ? weekDays : this.initialWeekDays;
- this.state.monthRule = monthDays && monthDays.length ? this.MONTH_RULES.DAY : this.MONTH_RULES.OFFSET;
- this.state.monthDays = monthDays && monthDays.length ? [monthDays[0]] : [this.initialMonthDay];
- this.state.offset = offset && Object.keys(offset).length ? offset : this.state.offset;
- }
- }
- getFormattedState(state) {
- const {
- frequency,
- end,
- interval,
- weekDays,
- monthRule,
- monthDays,
- offset
- } = state;
- switch (true) {
- case frequency === this.FREQUENCIES.DAILY:
- return {
- frequency,
- end,
- weekDays
- };
- case frequency === this.FREQUENCIES.WEEKLY:
- return {
- frequency,
- end,
- ...interval && {
- interval
- },
- weekDays
- };
- case frequency === this.FREQUENCIES.MONTHLY:
- return {
- frequency,
- end,
- ...interval && {
- interval
- },
- ...monthRule === this.MONTH_RULES.DAY ? {
- monthDays
- } : {
- offset: [[offset.value, offset.weekDay]]
- }
- };
- }
- }
- renderDayControls() {
- const {
- weekDays,
- view
- } = this.state;
- const handleWeeklySelection = (weekDay, remove) => {
- this.setState(state => {
- if (remove) {
- return {
- weekDays: state.weekDays.length === 1 ? state.weekDays : state.weekDays.filter(d => d !== weekDay)
- };
- }
- return {
- weekDays: [...state.weekDays, weekDay]
- };
- }, () => {
- const {
- weekDays
- } = this.state;
- if (weekDays.length === Object.keys(this.WEEK_DAYS).length) {
- this.toggleView(this.VIEWS.DAILY, this.FREQUENCIES.DAILY);
- }
- });
- };
- const handleDailySelection = weekDay => {
- this.toggleView(this.VIEWS.WEEKLY, this.FREQUENCIES.WEEKLY, {
- weekDays: weekDays.filter(d => d !== weekDay)
- });
- };
- return REaCt().createElement("div", {
- className: "recurring-field-row"
- }, Object.values(this.WEEK_DAYS).map(({
- value,
- label
- }) => {
- const isCurrentlySelected = weekDays.includes(value);
- return REaCt().createElement(meetings_button.A, {
- key: value,
- className: `
- mega-button
- action
- recurring-toggle-button
- ${isCurrentlySelected ? 'active' : ''}
- ${weekDays.length === 1 && isCurrentlySelected ? 'disabled' : ''}
- `,
- onClick: this.props.isLoading ? null : () => {
- if (view === this.VIEWS.WEEKLY) {
- return handleWeeklySelection(value, isCurrentlySelected);
- }
- return handleDailySelection(value);
- }
- }, label);
- }));
- }
- renderIntervalControls() {
- const {
- view,
- interval
- } = this.state;
- return REaCt().createElement("div", {
- className: "recurring-field-row"
- }, (0,utils.lI)(mega.icu.format(view === this.VIEWS.MONTHLY ? l.recur_rate_monthly : l.recur_rate_weekly, interval > 0 ? interval : 1), "[S]", this.IntervalSelect));
- }
- renderEndControls() {
- const {
- isLoading,
- onMount
- } = this.props;
- const {
- end,
- prevEnd
- } = this.state;
- return REaCt().createElement("div", {
- className: "recurring-field-row"
- }, REaCt().createElement("div", {
- className: "recurring-title-heading"
- }, l.recurring_ends), REaCt().createElement("div", {
- className: "recurring-radio-buttons"
- }, REaCt().createElement("div", {
- className: "recurring-label-wrap"
- }, REaCt().createElement("div", {
- className: `
- uiTheme
- ${end ? 'radioOff' : 'radioOn'}
- `
- }, REaCt().createElement("input", {
- type: "radio",
- name: `${Recurring.NAMESPACE}-radio-end`,
- disabled: isLoading,
- className: `
- uiTheme
- ${end ? 'radioOff' : 'radioOn'}
- `,
- onChange: () => {
- this.setState(state => ({
- end: undefined,
- prevEnd: state.end || state.prevEnd
- }));
- }
- })), REaCt().createElement("div", {
- className: "radio-txt"
- }, REaCt().createElement("span", {
- className: "recurring-radio-label",
- onClick: () => isLoading ? null : this.setState(state => ({
- end: undefined,
- prevEnd: state.end || state.prevEnd
- }))
- }, l.recurring_never))), REaCt().createElement("div", {
- className: "recurring-label-wrap"
- }, REaCt().createElement("div", {
- className: `
- uiTheme
- ${end ? 'radioOn' : 'radioOff'}
- `
- }, REaCt().createElement("input", {
- type: "radio",
- name: `${Recurring.NAMESPACE}-radio-end`,
- disabled: isLoading,
- className: `
- uiTheme
- ${end ? 'radioOn' : 'radioOff'}
- `,
- onChange: () => isLoading ? null : this.setState({
- end: prevEnd || this.initialEnd
- })
- })), REaCt().createElement("div", {
- className: "radio-txt"
- }, REaCt().createElement("span", {
- className: "recurring-radio-label",
- onClick: () => isLoading || end ? null : this.setState({
- end: prevEnd || this.initialEnd
- })
- }, l.recurring_on), REaCt().createElement(datepicker, {
- name: `${Recurring.NAMESPACE}-endDateTime`,
- position: "top left",
- startDate: end || this.initialEnd,
- selectedDates: [new Date(end)],
- isLoading,
- value: end || prevEnd || '',
- placeholder: time2date(end || prevEnd || this.initialEnd / 1000, 18),
- onMount,
- onSelect: timestamp => this.setState({
- end: timestamp
- }, () => this.safeForceUpdate())
- })))));
- }
- renderDaily() {
- return REaCt().createElement("div", {
- className: `${Recurring.NAMESPACE}-daily`
- }, this.renderDayControls(), this.renderEndControls());
- }
- renderWeekly() {
- return REaCt().createElement("div", {
- className: `${Recurring.NAMESPACE}-weekly`
- }, this.renderIntervalControls(), this.renderDayControls(), this.renderEndControls());
- }
- renderMonthly() {
- const {
- isLoading
- } = this.props;
- const {
- monthRule,
- monthDays,
- monthDaysWarning,
- offset
- } = this.state;
- return REaCt().createElement("div", {
- className: `${Recurring.NAMESPACE}-monthly`
- }, this.renderIntervalControls(), REaCt().createElement("div", {
- className: "recurring-field-row"
- }, REaCt().createElement("div", {
- className: "recurring-radio-buttons",
- onClick: isLoading ? null : ev => {
- const {
- name,
- value
- } = ev.target;
- if (name === `${Recurring.NAMESPACE}-radio-monthRule`) {
- this.setState({
- monthRule: value
- });
- }
- }
- }, REaCt().createElement("div", {
- className: "recurring-label-wrap"
- }, REaCt().createElement("div", {
- className: `
- uiTheme
- ${monthRule === 'day' ? 'radioOn' : 'radioOff'}
- `
- }, REaCt().createElement("input", {
- type: "radio",
- name: `${Recurring.NAMESPACE}-radio-monthRule`,
- value: "day",
- disabled: isLoading,
- className: `
- uiTheme
- ${monthRule === 'day' ? 'radioOn' : 'radioOff'}
- `
- })), REaCt().createElement("div", {
- className: "radio-txt"
- }, REaCt().createElement("span", {
- className: "recurring-radio-label",
- onClick: () => isLoading ? null : this.setState({
- monthRule: this.MONTH_RULES.DAY
- })
- }, l.recurring_frequency_day), REaCt().createElement("div", {
- className: "mega-input inline recurring-day"
- }, REaCt().createElement(schedule_select, {
- name: `${Recurring.NAMESPACE}-monthDay`,
- icon: true,
- value: monthDays[0],
- isLoading,
- options: [...Array(31).keys()].map(value => {
- value += 1;
- return {
- value,
- label: value
- };
- }),
- onSelect: ({
- value
- }) => {
- this.setState({
- monthRule: this.MONTH_RULES.DAY,
- monthDays: [value],
- monthDaysWarning: value > 28
- });
- }
- })))), monthDaysWarning && REaCt().createElement("div", {
- className: "recurring-label-wrap"
- }, REaCt().createElement("div", {
- className: "mega-banner body with-btn"
- }, REaCt().createElement("div", {
- className: "green-notification cell text-cell"
- }, REaCt().createElement("div", {
- className: "versioning-body-text"
- }, mega.icu.format(l.recurring_monthdays_warning, monthDays[0]))))), REaCt().createElement("div", {
- className: "recurring-label-wrap"
- }, REaCt().createElement("div", {
- className: `
- uiTheme
- ${monthRule === this.MONTH_RULES.OFFSET ? 'radioOn' : 'radioOff'}
- `
- }, REaCt().createElement("input", {
- type: "radio",
- name: `${Recurring.NAMESPACE}-radio-monthRule`,
- value: "offset",
- disabled: isLoading,
- className: `
- uiTheme
- ${monthRule === this.MONTH_RULES.OFFSET ? 'radioOn' : 'radioOff'}
- `
- })), REaCt().createElement("div", {
- className: "radio-txt"
- }, REaCt().createElement(this.MonthDaySelect, {
- offset
- }))))), this.renderEndControls());
- }
- renderNavigation(view) {
- return REaCt().createElement(REaCt().Fragment, null, REaCt().createElement(meetings_button.A, {
- className: `
- mega-button
- action
- recurring-nav-button
- ${view === this.VIEWS.DAILY ? 'active' : ''}
- `,
- onClick: () => this.toggleView(this.VIEWS.DAILY, this.FREQUENCIES.DAILY)
- }, l.recurring_daily), REaCt().createElement(meetings_button.A, {
- className: `
- mega-button
- action
- recurring-nav-button
- ${view === this.VIEWS.WEEKLY ? 'active' : ''}
- `,
- onClick: () => this.toggleView(this.VIEWS.WEEKLY, this.FREQUENCIES.WEEKLY)
- }, l.recurring_weekly), REaCt().createElement(meetings_button.A, {
- className: `
- mega-button
- action
- recurring-nav-button
- ${view === this.VIEWS.MONTHLY ? 'active' : ''}
- `,
- onClick: () => this.toggleView(this.VIEWS.MONTHLY, this.FREQUENCIES.MONTHLY)
- }, l.recurring_monthly));
- }
- renderContent(view) {
- switch (view) {
- case this.VIEWS.DAILY:
- return this.renderDaily();
- case this.VIEWS.WEEKLY:
- return this.renderWeekly();
- case this.VIEWS.MONTHLY:
- return this.renderMonthly();
- }
- }
- UNSAFE_componentWillUpdate(nextProps, nextState) {
- if (this.state.view !== this.VIEWS.DAILY && nextState.view === this.VIEWS.DAILY) {
- nextState.weekDays = this.initialWeekDays;
- }
- if (nextState.weekDays.length === Object.keys(this.WEEK_DAYS).length && this.state.view !== this.VIEWS.WEEKLY && nextState.view === this.VIEWS.WEEKLY || !(0,helpers.ro)(nextProps.startDateTime, this.props.startDateTime) && this.state.view === this.VIEWS.WEEKLY) {
- const weekday = new Date(nextProps.startDateTime).getDay();
- nextState.weekDays = [weekday === 0 ? 7 : weekday];
- }
- if (!(0,helpers.ro)(nextProps.startDateTime, this.props.startDateTime) && this.state.view === this.VIEWS.MONTHLY) {
- let _Object$values$find2;
- const nextDate = new Date(nextProps.startDateTime);
- nextState.monthDays = [nextDate.getDate()];
- nextState.offset.weekDay = ((_Object$values$find2 = Object.values(this.WEEK_DAYS).find(d => d.value === nextDate.getDay())) == null ? void 0 : _Object$values$find2.value) || this.WEEK_DAYS.SUNDAY.value;
- nextState.monthDaysWarning = nextState.monthDays > 28;
- }
- if (nextState.view === this.VIEWS.MONTHLY && this.state.interval > 12) {
- nextState.interval = 12;
- }
- this.props.onUpdate(this.getFormattedState(nextState));
- }
- componentDidMount() {
- super.componentDidMount();
- this.props.onUpdate(this.getFormattedState(this.state));
- }
- render() {
- const {
- NAMESPACE
- } = Recurring;
- const {
- view
- } = this.state;
- return REaCt().createElement(Row, null, REaCt().createElement(Column, null), REaCt().createElement(Column, null, REaCt().createElement("div", {
- ref: this.domRef,
- className: `
- ${NAMESPACE}
- ${this.props.isLoading ? 'disabled' : ''}
- `
- }, REaCt().createElement("div", {
- className: `${NAMESPACE}-container`
- }, REaCt().createElement("div", {
- className: `${NAMESPACE}-navigation`
- }, this.renderNavigation(view)), REaCt().createElement("div", {
- className: `${NAMESPACE}-content`
- }, this.renderContent(view))))));
- }
-}
-Recurring.NAMESPACE = 'meetings-recurring';
-class Edit extends mixins.w9 {
- constructor(props) {
- super(props);
- this.occurrenceRef = null;
- this.datepickerRefs = [];
- this.interval = ChatRoom.SCHEDULED_MEETINGS_INTERVAL;
- this.incomingCallListener = 'onPrepareIncomingCallDialog.recurringEdit';
- this.state = {
- startDateTime: undefined,
- endDateTime: undefined,
- isDirty: false,
- closeDialog: false,
- overlayed: false
- };
- this.onStartDateSelect = startDateTime => {
- this.setState({
- startDateTime,
- isDirty: true
- }, () => {
- this.datepickerRefs.endDateTime.selectDate(new Date(startDateTime + this.interval));
- });
- };
- this.onEndDateSelect = endDateTime => {
- this.setState({
- endDateTime,
- isDirty: true
- }, () => {
- const {
- startDateTime,
- endDateTime
- } = this.state;
- if (endDateTime < startDateTime) {
- if (endDateTime < Date.now()) {
- return this.setState({
- endDateTime: startDateTime + this.interval
- });
- }
- this.handleTimeSelect({
- startDateTime: endDateTime - this.interval
- });
- }
- });
- };
- this.handleTimeSelect = ({
- startDateTime,
- endDateTime
- }) => {
- startDateTime = startDateTime || this.state.startDateTime;
- endDateTime = endDateTime || this.state.endDateTime;
- this.setState(state => {
- return {
- startDateTime: endDateTime <= state.startDateTime ? endDateTime - this.interval : startDateTime,
- endDateTime: startDateTime >= state.endDateTime ? startDateTime + this.interval : endDateTime,
- isDirty: true
- };
- });
- };
- const {
- scheduledMeeting,
- occurrenceId
- } = this.props;
- this.occurrenceRef = scheduledMeeting.occurrences[occurrenceId];
- if (this.occurrenceRef) {
- this.state.startDateTime = this.occurrenceRef.start;
- this.state.endDateTime = this.occurrenceRef.end;
- }
- }
- componentWillUnmount() {
- super.componentWillUnmount();
- if (this.incomingCallListener) {
- megaChat.off(this.incomingCallListener);
- }
- if ($.dialog === Schedule.dialogName) {
- closeDialog();
- }
- }
- componentDidMount() {
- super.componentDidMount();
- M.safeShowDialog(Schedule.dialogName, () => {
- if (!this.isMounted()) {
- throw Error(`Edit dialog: component not mounted.`);
- }
- megaChat.rebind(this.incomingCallListener, () => {
- if (this.isMounted()) {
- this.setState({
- overlayed: true,
- closeDialog: false
- });
- megaChat.plugins.callManager2.rebind('onRingingStopped.recurringEdit', () => {
- megaChat.plugins.callManager2.off('onRingingStopped.recurringEdit');
- this.setState({
- overlayed: false
- });
- fm_showoverlay();
- });
- }
- });
- return $(`#${Schedule.NAMESPACE}`);
- });
- }
- componentDidUpdate(prevProps) {
- if (prevProps.callExpanded && !this.props.callExpanded) {
- if (!$.dialog) {
- M.safeShowDialog(Schedule.dialogName, `#${Schedule.NAMESPACE}`);
- }
- fm_showoverlay();
- this.setState({
- closeDialog: false
- });
- }
- if (!prevProps.callExpanded && this.props.callExpanded) {
- this.setState({
- closeDialog: false
- });
- }
- }
- render() {
- const {
- chatRoom,
- callExpanded,
- onClose
- } = this.props;
- const {
- startDateTime,
- endDateTime,
- isDirty,
- closeDialog,
- overlayed
- } = this.state;
- const dialogClasses = ['fluid'];
- if (closeDialog) {
- dialogClasses.push('with-confirmation-dialog');
- }
- if (callExpanded || overlayed) {
- dialogClasses.push('hidden');
- }
- const withUpgrade = !u_attr.p && endDateTime - startDateTime > 36e5;
- if (withUpgrade) {
- dialogClasses.push('upgrade');
- }
- return REaCt().createElement(modalDialogs.A.ModalDialog, (0,esm_extends.A)({}, this.state, {
- id: Schedule.NAMESPACE,
- className: dialogClasses.join(' '),
- dialogName: Schedule.dialogName,
- dialogType: "main",
- onClose: () => {
- return isDirty ? this.setState({
- closeDialog: true
- }) : onClose();
- }
- }), REaCt().createElement("header", null, REaCt().createElement("h2", null, l.edit_meeting_title)), REaCt().createElement("div", {
- className: "fm-dialog-body"
- }, REaCt().createElement(Row, null, REaCt().createElement("div", {
- className: "mega-banner body recurring-edit-banner"
- }, REaCt().createElement("div", {
- className: "cell"
- }, (0,utils.lI)(l.scheduled_edit_occurrence_note, '[A]', ui_link.A, {
- onClick: () => {
- onClose();
- megaChat.trigger(megaChat.plugins.meetingsManager.EVENTS.EDIT, chatRoom);
- }
- })))), REaCt().createElement(Row, {
- className: "start-aligned"
- }, REaCt().createElement(Column, null, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-recents-filled"
- })), REaCt().createElement("div", {
- className: "schedule-date-container"
- }, REaCt().createElement(DateTime, {
- name: "startDateTime",
- altField: "startTime",
- datepickerRef: this.datepickerRefs.startDateTime,
- startDate: startDateTime,
- value: startDateTime,
- filteredTimeIntervals: (0,helpers.a4)(startDateTime),
- label: l.schedule_start_date,
- onMount: datepicker => {
- this.datepickerRefs.startDateTime = datepicker;
- },
- onSelectDate: startDateTime => this.onStartDateSelect(startDateTime),
- onSelectTime: ({
- value: startDateTime
- }) => this.handleTimeSelect({
- startDateTime
- }),
- onChange: value => this.setState({
- startDateTime: value
- }),
- onBlur: timestamp => {
- if (timestamp) {
- timestamp = timestamp < Date.now() ? this.occurrenceRef.start : timestamp;
- this.onStartDateSelect(timestamp);
- }
- }
- }), REaCt().createElement(DateTime, {
- name: "endDateTime",
- altField: "endTime",
- datepickerRef: this.datepickerRefs.endDateTime,
- startDate: endDateTime,
- value: endDateTime,
- filteredTimeIntervals: (0,helpers.a4)(endDateTime, startDateTime),
- label: l.schedule_end_date,
- onMount: datepicker => {
- this.datepickerRefs.endDateTime = datepicker;
- },
- onSelectDate: endDateTime => this.onEndDateSelect(endDateTime),
- onSelectTime: ({
- value: endDateTime
- }) => this.handleTimeSelect({
- endDateTime
- }),
- onChange: timestamp => this.setState({
- endDateTime: timestamp
- }),
- onBlur: timestamp => timestamp && this.onEndDateSelect(timestamp)
- }))), withUpgrade && REaCt().createElement(UpgradeNotice, {
- onUpgradeClicked: () => {
- onClose();
- loadSubPage('pro');
- eventlog(500257);
- }
- })), REaCt().createElement("footer", null, REaCt().createElement("div", {
- className: "footer-container"
- }, REaCt().createElement(meetings_button.A, {
- className: "mega-button positive",
- onClick: () => {
- const {
- startDateTime,
- endDateTime
- } = this.state;
- if (startDateTime !== this.occurrenceRef.start || endDateTime !== this.occurrenceRef.end) {
- delay('chat-event-sm-edit-meeting', () => eventlog(99923));
- this.occurrenceRef.update(startDateTime, endDateTime);
- }
- onClose();
- }
- }, REaCt().createElement("span", null, l.update_meeting_button)))), !(overlayed || callExpanded) && closeDialog && REaCt().createElement(CloseDialog, {
- onToggle: () => this.setState({
- closeDialog: false
- }),
- onClose
- }));
- }
-}
-// EXTERNAL MODULE: ./js/chat/chatRoom.jsx + 1 modules
-const chat_chatRoom = REQ_(553);
-;// ./js/chat/ui/meetings/schedule/schedule.jsx
-
-let _Schedule;
-
-
-
-
-
-
-
-
-
-
-
-
-class Schedule extends mixins.w9 {
- constructor(...args) {
- super(...args);
- this.domRef = REaCt().createRef();
- this.scheduledMeetingRef = null;
- this.localStreamRef = '.float-video';
- this.datepickerRefs = [];
- this.incomingCallListener = 'onPrepareIncomingCallDialog.scheduleDialog';
- this.ringingStoppedListener = 'onRingingStopped.scheduleDialog';
- this.interval = ChatRoom.SCHEDULED_MEETINGS_INTERVAL;
- this.nearestHalfHour = (0,helpers.i_)();
- this.state = {
- topic: '',
- startDateTime: this.nearestHalfHour,
- endDateTime: this.nearestHalfHour + this.interval,
- timezone: (0,helpers.dB)(),
- recurring: false,
- participants: [],
- link: false,
- sendInvite: false,
- waitingRoom: false,
- openInvite: false,
- description: '',
- closeDialog: false,
- isEdit: false,
- isDirty: false,
- isLoading: false,
- topicInvalid: false,
- invalidTopicMsg: '',
- descriptionInvalid: false,
- overlayed: false
- };
- this.onTopicChange = value => {
- if (value.length > ChatRoom.TOPIC_MAX_LENGTH) {
- this.setState({
- invalidTopicMsg: l.err_schedule_title_long,
- topicInvalid: true
- });
- value = value.substring(0, ChatRoom.TOPIC_MAX_LENGTH);
- } else if (value.length === 0) {
- this.setState({
- invalidTopicMsg: l.schedule_title_missing,
- topicInvalid: true
- });
- } else if (this.state.invalidTopicMsg) {
- this.setState({
- invalidTopicMsg: '',
- topicInvalid: false
- });
- }
- this.handleChange('topic', value);
- };
- this.onTextareaChange = value => {
- if (value.length > 3000) {
- this.setState({
- descriptionInvalid: true
- });
- value = value.substring(0, 3000);
- } else if (this.state.descriptionInvalid) {
- this.setState({
- descriptionInvalid: false
- });
- }
- this.handleChange('description', value);
- };
- this.onStartDateSelect = () => {
- this.datepickerRefs.endDateTime.selectDate(new Date(this.state.startDateTime + this.interval));
- };
- this.onEndDateSelect = () => {
- const {
- startDateTime,
- endDateTime
- } = this.state;
- if (endDateTime < startDateTime) {
- if (endDateTime < Date.now()) {
- return this.setState({
- endDateTime: startDateTime + this.interval
- });
- }
- this.handleDateSelect({
- startDateTime: endDateTime - this.interval
- });
- }
- };
- this.handleToggle = prop => {
- return Object.keys(this.state).includes(prop) && this.setState(state => ({
- [prop]: !state[prop],
- isDirty: true
- }));
- };
- this.handleChange = (prop, value) => {
- return Object.keys(this.state).includes(prop) && this.setState({
- [prop]: value,
- isDirty: true
- });
- };
- this.handleDateSelect = ({
- startDateTime,
- endDateTime
- }, callback) => {
- this.setState(state => ({
- startDateTime: startDateTime || state.startDateTime,
- endDateTime: endDateTime || state.endDateTime,
- isDirty: true
- }), () => {
- const {
- recurring
- } = this.state;
- if (recurring && recurring.end) {
- const recurringEnd = (0,helpers.PS)(this.state.startDateTime, 6);
- this.datepickerRefs.recurringEnd.selectDate(new Date(recurringEnd));
- }
- if (callback) {
- callback();
- }
- });
- };
- this.handleTimeSelect = ({
- startDateTime,
- endDateTime
- }) => {
- startDateTime = startDateTime || this.state.startDateTime;
- endDateTime = endDateTime || this.state.endDateTime;
- this.setState(state => {
- return {
- startDateTime: endDateTime <= state.startDateTime ? endDateTime - this.interval : startDateTime,
- endDateTime: startDateTime >= state.endDateTime ? startDateTime + this.interval : endDateTime,
- isDirty: true
- };
- });
- };
- this.handleParticipantSelect = participants => {
- return participants && Array.isArray(participants) && this.setState({
- participants,
- isDirty: true
- }, () => {
- const domRef = this.domRef && this.domRef.current;
- if (domRef) {
- domRef.reinitialise();
- }
- });
- };
- this.handleSubmit = () => {
- if (this.state.topic) {
- return this.setState({
- isLoading: true
- }, async () => {
- const {
- chatRoom,
- onClose
- } = this.props;
- const params = [this.state, chatRoom];
- if (chatRoom) {
- delay('chat-event-sm-edit-meeting', () => eventlog(99923));
- } else {
- delay('chat-event-sm-button-create', () => eventlog(99922));
- }
- delay('chat-events-sm-settings', () => this.submitStateEvents({
- ...this.state
- }));
- await megaChat.plugins.meetingsManager[chatRoom ? 'updateMeeting' : 'createMeeting'](...params);
- this.setState({
- isLoading: false
- }, () => {
- onClose();
- megaChat.trigger(conversations_EVENTS.NAV_RENDER_VIEW, VIEWS.MEETINGS);
- });
- });
- }
- return this.setState({
- topicInvalid: true,
- invalidTopicMsg: l.schedule_title_missing
- });
- };
- }
- syncPublicLink() {
- if (this.state.isEdit) {
- const {
- chatRoom
- } = this.props;
- chatRoom.updatePublicHandle().then(() => this.isMounted() && this.setState({
- link: !!chatRoom.publicLink
- })).catch(dump);
- }
- }
- getFilteredTimeIntervals(timestamp, offsetFrom) {
- const timeIntervals = (0,helpers.a4)(timestamp, offsetFrom);
- const {
- end
- } = this.scheduledMeetingRef || {};
- if (this.state.isEdit && end < Date.now()) {
- return timeIntervals;
- }
- return timeIntervals.filter(o => {
- return offsetFrom ? o.value > this.nearestHalfHour : o.value > Date.now();
- });
- }
- submitStateEvents(state) {
- if (state.link) {
- eventlog(500162);
- }
- if (state.sendInvite) {
- eventlog(500163);
- }
- if (state.waitingRoom) {
- eventlog(500164);
- }
- if (state.openInvite) {
- eventlog(500165);
- }
- if (state.description) {
- eventlog(500166);
- }
- if (state.recurring) {
- eventlog(500167);
- } else {
- eventlog(500168);
- }
- eventlog(500169, state.topic.length);
- }
- componentWillUnmount() {
- super.componentWillUnmount();
- if ($.dialog === Schedule.dialogName) {
- closeDialog();
- }
- [document, this.localStreamRef].map(el => $(el).unbind(`.${Schedule.NAMESPACE}`));
- megaChat.off(this.incomingCallListener);
- }
- UNSAFE_componentWillMount() {
- const {
- chatRoom
- } = this.props;
- if (chatRoom) {
- const {
- scheduledMeeting,
- publicLink,
- options
- } = chatRoom;
- this.state.topic = scheduledMeeting.title;
- this.state.startDateTime = scheduledMeeting.start;
- this.state.endDateTime = scheduledMeeting.end;
- this.state.timezone = scheduledMeeting.timezone || (0,helpers.dB)();
- this.state.recurring = scheduledMeeting.recurring;
- this.state.participants = chatRoom.getParticipantsExceptMe();
- this.state.link = !!publicLink;
- this.state.description = scheduledMeeting.description || '';
- this.state.sendInvite = scheduledMeeting.flags;
- this.state.waitingRoom = options[chat_chatRoom.MCO_FLAGS.WAITING_ROOM];
- this.state.openInvite = options[chat_chatRoom.MCO_FLAGS.OPEN_INVITE];
- this.state.isEdit = true;
- this.scheduledMeetingRef = scheduledMeeting;
- }
- }
- componentDidMount() {
- super.componentDidMount();
- this.syncPublicLink();
- if ($.dialog === 'onboardingDialog') {
- closeDialog();
- }
- M.safeShowDialog(Schedule.dialogName, () => {
- if (!this.isMounted()) {
- throw new Error(`${Schedule.dialogName} dialog: component ${Schedule.NAMESPACE} not mounted.`);
- }
- $(document).rebind(`keyup.${Schedule.NAMESPACE}`, ({
- keyCode,
- target
- }) => {
- return this.state.closeDialog || target instanceof HTMLTextAreaElement ? null : keyCode === 13 && this.handleSubmit();
- });
- $(this.localStreamRef).rebind(`click.${Schedule.NAMESPACE}`, () => {
- if (this.state.isDirty) {
- this.handleToggle('closeDialog');
- return false;
- }
- });
- megaChat.rebind(this.incomingCallListener, () => {
- if (this.isMounted()) {
- this.setState({
- overlayed: true,
- closeDialog: false
- });
- megaChat.plugins.callManager2.rebind(this.ringingStoppedListener, () => {
- megaChat.plugins.callManager2.off(this.ringingStoppedListener);
- this.setState({
- overlayed: false
- });
- fm_showoverlay();
- });
- }
- });
- return $(`#${Schedule.NAMESPACE}`);
- });
- }
- componentDidUpdate(prevProps) {
- if (prevProps.callExpanded && !this.props.callExpanded) {
- if (!$.dialog) {
- M.safeShowDialog(Schedule.dialogName, `#${Schedule.NAMESPACE}`);
- }
- fm_showoverlay();
- this.setState({
- closeDialog: false
- });
- }
- if (!prevProps.callExpanded && this.props.callExpanded) {
- this.setState({
- closeDialog: false
- });
- }
- }
- render() {
- let _this$props$chatRoom;
- const {
- topic,
- startDateTime,
- endDateTime,
- recurring,
- participants,
- link,
- sendInvite,
- waitingRoom,
- openInvite,
- description,
- closeDialog,
- isEdit,
- isDirty,
- isLoading,
- topicInvalid,
- invalidTopicMsg,
- descriptionInvalid,
- overlayed
- } = this.state;
- return REaCt().createElement(modalDialogs.A.ModalDialog, (0,esm_extends.A)({}, this.state, {
- id: Schedule.NAMESPACE,
- className: `
- ${closeDialog ? 'with-confirmation-dialog' : ''}
- ${this.props.callExpanded || overlayed ? 'hidden' : ''}
- `,
- dialogName: Schedule.dialogName,
- dialogType: "main",
- onClose: () => isDirty ? this.handleToggle('closeDialog') : this.props.onClose()
- }), REaCt().createElement(Header, {
- chatRoom: isEdit && this.props.chatRoom
- }), REaCt().createElement(perfectScrollbar.O, {
- ref: this.domRef,
- className: "fm-dialog-body",
- options: {
- suppressScrollX: true
- }
- }, REaCt().createElement(Input, {
- name: "topic",
- placeholder: l.schedule_title_input,
- value: topic,
- invalid: topicInvalid,
- invalidMessage: invalidTopicMsg,
- autoFocus: true,
- isLoading,
- onFocus: () => topicInvalid && this.setState({
- topicInvalid: false
- }),
- onChange: this.onTopicChange
- }), REaCt().createElement(Row, {
- className: `unencrypted-warning-row ${topicInvalid ? 'with-topic-err' : ''}`
- }, REaCt().createElement(Column, null), REaCt().createElement(Column, null, REaCt().createElement("div", {
- className: "unencrypted-warning"
- }, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-info"
- }), REaCt().createElement("span", null, l.schedule_encryption_note)))), REaCt().createElement(Row, {
- className: "start-aligned"
- }, REaCt().createElement(Column, null, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-recents-filled"
- })), REaCt().createElement("div", {
- className: "schedule-date-container"
- }, REaCt().createElement(DateTime, {
- name: "startDateTime",
- altField: "startTime",
- datepickerRef: this.datepickerRefs.startDateTime,
- startDate: startDateTime,
- value: startDateTime,
- filteredTimeIntervals: this.getFilteredTimeIntervals(startDateTime),
- label: l.schedule_start_date,
- isLoading,
- onMount: datepicker => {
- this.datepickerRefs.startDateTime = datepicker;
- },
- onSelectDate: startDateTime => {
- this.handleDateSelect({
- startDateTime
- }, this.onStartDateSelect);
- },
- onSelectTime: ({
- value: startDateTime
- }) => this.handleTimeSelect({
- startDateTime
- }),
- onChange: value => this.handleChange('startDateTime', value),
- onBlur: timestamp => {
- if (timestamp) {
- const startDateTime = timestamp < Date.now() ? this.nearestHalfHour : timestamp;
- this.handleDateSelect({
- startDateTime
- }, this.onStartDateSelect);
- }
- }
- }), REaCt().createElement(DateTime, {
- name: "endDateTime",
- altField: "endTime",
- datepickerRef: this.datepickerRefs.endDateTime,
- isLoading,
- startDate: endDateTime,
- value: endDateTime,
- filteredTimeIntervals: this.getFilteredTimeIntervals(endDateTime, startDateTime),
- label: l.schedule_end_date,
- onMount: datepicker => {
- this.datepickerRefs.endDateTime = datepicker;
- },
- onSelectDate: endDateTime => {
- this.handleDateSelect({
- endDateTime
- }, this.onEndDateSelect);
- },
- onSelectTime: ({
- value: endDateTime
- }) => this.handleTimeSelect({
- endDateTime
- }),
- onChange: value => this.handleChange('endDateTime', value),
- onBlur: timestamp => {
- this.handleDateSelect({
- endDateTime: timestamp
- }, this.onEndDateSelect);
- }
- }))), !u_attr.p && endDateTime - startDateTime > 36e5 && REaCt().createElement(UpgradeNotice, {
- onUpgradeClicked: () => {
- this.props.onClose();
- loadSubPage('pro');
- eventlog(500258);
- }
- }), REaCt().createElement(Checkbox, {
- name: "recurring",
- checked: recurring,
- label: l.schedule_recurring_label,
- isLoading,
- onToggle: prop => {
- this.handleToggle(prop);
- delay('chat-event-sm-recurring', () => eventlog(99919));
- }
- }), recurring && REaCt().createElement(Recurring, {
- chatRoom: this.props.chatRoom,
- startDateTime,
- endDateTime,
- isLoading,
- onMount: datepicker => {
- this.datepickerRefs.recurringEnd = datepicker;
- },
- onUpdate: state => {
- this.setState({
- recurring: state
- });
- }
- }), REaCt().createElement(Row, null, REaCt().createElement(Column, null, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-contacts"
- })), REaCt().createElement(Column, null, REaCt().createElement(Invite, {
- className: isLoading ? 'disabled' : '',
- isLoading,
- participants,
- onSelect: this.handleParticipantSelect
- }))), REaCt().createElement(Switch, {
- name: "link",
- toggled: link,
- label: l.schedule_link_label,
- isLoading,
- subLabel: l.schedule_link_info,
- onToggle: prop => {
- this.handleToggle(prop);
- delay('chat-event-sm-meeting-link', () => eventlog(99920));
- }
- }), REaCt().createElement(Checkbox, {
- name: "sendInvite",
- checked: sendInvite,
- label: l.schedule_invite_label,
- isLoading,
- onToggle: prop => {
- this.handleToggle(prop);
- delay('chat-event-sm-calendar-invite', () => eventlog(99921));
- }
- }), REaCt().createElement(Checkbox, {
- name: "waitingRoom",
- className: (_this$props$chatRoom = this.props.chatRoom) != null && _this$props$chatRoom.havePendingCall() ? 'disabled' : '',
- checked: waitingRoom,
- label: l.waiting_room,
- subLabel: l.waiting_room_info,
- isLoading,
- onToggle: waitingRoom => {
- let _this$props$chatRoom2;
- if ((_this$props$chatRoom2 = this.props.chatRoom) != null && _this$props$chatRoom2.havePendingCall()) {
- return;
- }
- this.handleToggle(waitingRoom);
- delay('chat-event-sm-waiting-room', () => eventlog(500297));
- }
- }), REaCt().createElement(Checkbox, {
- name: "openInvite",
- checked: openInvite,
- label: l.open_invite_desc,
- isLoading,
- onToggle: ev => {
- this.handleToggle(ev);
- delay('chat-event-sm-open-invite', () => eventlog(500298));
- }
- }), waitingRoom && openInvite ? REaCt().createElement(Row, null, REaCt().createElement("div", {
- className: "schedule-dialog-banner warn"
- }, REaCt().createElement(utils.P9, null, l.waiting_room_invite.replace('[A]', `
- `).replace('[/A]', '')))) : null, REaCt().createElement(Textarea, {
- name: "description",
- isLoading,
- invalid: descriptionInvalid,
- placeholder: l.schedule_description_input,
- value: description,
- onFocus: () => descriptionInvalid && this.setState({
- descriptionInvalid: false
- }),
- onChange: this.onTextareaChange
- })), REaCt().createElement(Footer, {
- isLoading,
- isEdit,
- topic,
- onSubmit: this.handleSubmit
- }), !(overlayed || this.props.callExpanded) && closeDialog && REaCt().createElement(CloseDialog, {
- onToggle: this.handleToggle,
- onClose: this.props.onClose
- }));
- }
-}
-_Schedule = Schedule;
-Schedule.NAMESPACE = 'schedule-dialog';
-Schedule.dialogName = `meetings-${_Schedule.NAMESPACE}`;
-window.ScheduleMeetingDialogUI = {
- Schedule
-};
-const CloseDialog = ({
- onToggle,
- onClose
-}) => {
- return REaCt().createElement(REaCt().Fragment, null, REaCt().createElement(modalDialogs.A.ModalDialog, {
- name: `${Schedule.NAMESPACE}-confirmation`,
- dialogType: "message",
- className: `
- with-close-btn
- ${Schedule.NAMESPACE}-confirmation
- `,
- title: l.schedule_discard_dlg_title,
- icon: "sprite-fm-uni icon-question",
- buttons: [{
- key: 'n',
- label: l.schedule_discard_cancel,
- onClick: () => onToggle('closeDialog')
- }, {
- key: 'y',
- label: l.schedule_discard_confirm,
- className: 'positive',
- onClick: onClose
- }],
- noCloseOnClickOutside: true,
- stopKeyPropagation: true,
- hideOverlay: true,
- onClose: () => onToggle('closeDialog')
- }), REaCt().createElement("div", {
- className: `${Schedule.NAMESPACE}-confirmation-overlay`,
- onClick: () => onToggle('closeDialog')
- }));
-};
-const Row = ({
- children,
- className
-}) => REaCt().createElement("div", {
- className: `
- ${Schedule.NAMESPACE}-row
- ${className || ''}
- `
-}, children);
-const Column = ({
- children,
- className
-}) => REaCt().createElement("div", {
- className: `
- ${Schedule.NAMESPACE}-column
- ${className || ''}
- `
-}, children);
-const Header = ({
- chatRoom
-}) => {
- const $$container = title => REaCt().createElement("header", null, REaCt().createElement("h2", null, title));
- if (chatRoom) {
- const {
- scheduledMeeting
- } = chatRoom;
- return $$container(scheduledMeeting.isRecurring ? l.edit_meeting_series_title : l.edit_meeting_title);
- }
- return $$container(l.schedule_meeting_title);
-};
-const Input = ({
- name,
- placeholder,
- value,
- invalid,
- invalidMessage,
- autoFocus,
- isLoading,
- onFocus,
- onChange
-}) => {
- return REaCt().createElement(Row, {
- className: invalid ? 'invalid-aligned' : ''
- }, REaCt().createElement(Column, null, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-rename"
- })), REaCt().createElement(Column, null, REaCt().createElement("div", {
- className: `
- mega-input
- ${invalid ? 'error msg' : ''}
- `
- }, REaCt().createElement("input", {
- type: "text",
- name: `${Schedule.NAMESPACE}-${name}`,
- className: isLoading ? 'disabled' : '',
- disabled: isLoading,
- autoFocus,
- autoComplete: "off",
- placeholder,
- value,
- onFocus,
- onChange: ({
- target
- }) => onChange(target.value)
- }), invalid && REaCt().createElement("div", {
- className: "message-container mega-banner"
- }, invalidMessage))));
-};
-const Checkbox = ({
- name,
- className,
- checked,
- label,
- subLabel,
- isLoading,
- onToggle
-}) => {
- return REaCt().createElement(Row, {
- className: `
- ${subLabel ? 'start-aligned' : ''}
- ${className || ''}
- `
- }, REaCt().createElement(Column, null, REaCt().createElement("div", {
- className: `
- checkdiv
- ${checked ? 'checkboxOn' : 'checkboxOff'}
- ${isLoading ? 'disabled' : ''}
- `
- }, REaCt().createElement("input", {
- name: `${Schedule.NAMESPACE}-${name}`,
- disabled: isLoading,
- type: "checkbox",
- onChange: () => onToggle(name)
- }))), REaCt().createElement(Column, {
- className: subLabel ? 'with-sub-label' : ''
- }, REaCt().createElement("label", {
- htmlFor: `${Schedule.NAMESPACE}-${name}`,
- className: isLoading ? 'disabled' : '',
- onClick: () => isLoading ? null : onToggle(name)
- }, label), subLabel && REaCt().createElement("div", {
- className: "sub-label"
- }, subLabel)));
-};
-const Switch = ({
- name,
- toggled,
- label,
- isLoading,
- subLabel,
- onToggle
-}) => {
- const className = `${Schedule.NAMESPACE}-switch`;
- return REaCt().createElement(Row, null, REaCt().createElement(Column, null, REaCt().createElement("i", {
- className: "sprite-fm-uni icon-mega-logo"
- })), REaCt().createElement(Column, {
- className: subLabel ? `with-sub-label ${className}` : className
- }, REaCt().createElement("span", {
- className: `
- schedule-label
- ${isLoading ? 'disabled' : ''}
- `,
- onClick: () => isLoading ? null : onToggle(name)
- }, label), REaCt().createElement("div", {
- className: `
- mega-switch
- ${toggled ? 'toggle-on' : ''}
- ${isLoading ? 'disabled' : ''}
- `,
- onClick: () => isLoading ? null : onToggle(name)
- }, REaCt().createElement("div", {
- className: `
- mega-feature-switch
- sprite-fm-mono-after
- ${toggled ? 'icon-check-after' : 'icon-minimise-after'}
- `
- })), subLabel && REaCt().createElement("div", {
- className: "sub-label"
- }, subLabel)));
-};
-const Textarea = ({
- name,
- placeholder,
- isLoading,
- value,
- invalid,
- onChange,
- onFocus
-}) => {
- return REaCt().createElement(Row, {
- className: "start-aligned"
- }, REaCt().createElement(Column, null, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-description"
- })), REaCt().createElement(Column, null, REaCt().createElement("div", {
- className: `mega-input box-style textarea ${invalid ? 'error' : ''}`
- }, REaCt().createElement("textarea", {
- name: `${Schedule.NAMESPACE}-${name}`,
- className: isLoading ? 'disabled' : '',
- placeholder,
- value,
- readOnly: isLoading,
- onChange: ({
- target
- }) => onChange(target.value),
- onFocus
- })), invalid && REaCt().createElement("div", {
- className: "mega-input error msg textarea-error"
- }, REaCt().createElement("div", {
- className: "message-container mega-banner"
- }, l.err_schedule_desc_long))));
-};
-const Footer = ({
- isLoading,
- isEdit,
- topic,
- onSubmit
-}) => {
- return REaCt().createElement("footer", null, REaCt().createElement("div", {
- className: "footer-container"
- }, REaCt().createElement(meetings_button.A, {
- className: `
- mega-button
- positive
- ${isLoading ? 'disabled' : ''}
- `,
- onClick: () => isLoading ? null : onSubmit(),
- topic
- }, REaCt().createElement("span", null, isEdit ? l.update_meeting_button : l.schedule_meeting_button))));
-};
-const UpgradeNotice = ({
- onUpgradeClicked
-}) => {
- return !!mega.flags.ff_chmon && REaCt().createElement(Row, {
- className: "schedule-upgrade-notice"
- }, REaCt().createElement("h3", null, l.schedule_limit_title), REaCt().createElement("div", null, l.schedule_limit_upgrade_features), REaCt().createElement(meetings_button.A, {
- className: "mega-button positive",
- onClick: onUpgradeClicked
- }, REaCt().createElement("span", null, l.upgrade_now)));
-};
-// EXTERNAL MODULE: ./js/ui/miniui.jsx
-const miniui = REQ_(818);
-;// ./js/chat/ui/startGroupChatWizard.jsx
-const React = REQ_(594);
-
-
-
-
-class StartGroupChatWizard extends mixins.w9 {
- constructor(props) {
- super(props);
- this.dialogName = 'start-group-chat';
- this.domRef = React.createRef();
- this.inputContainerRef = React.createRef();
- this.inputRef = React.createRef();
- let haveContacts = false;
- const keys = M.u.keys();
- for (let i = 0; i < keys.length; i++) {
- if (M.u[keys[i]].c === 1) {
- haveContacts = true;
- break;
- }
- }
- this.state = {
- 'selected': this.props.selected ? this.props.selected : [],
- haveContacts,
- 'step': this.props.flowType === 2 || !haveContacts ? 1 : 0,
- 'keyRotation': false,
- 'createChatLink': this.props.flowType === 2,
- 'groupName': '',
- openInvite: 1
- };
- this.onFinalizeClick = this.onFinalizeClick.bind(this);
- this.onSelectClicked = this.onSelectClicked.bind(this);
- this.onSelected = this.onSelected.bind(this);
- }
- onSelected(nodes) {
- this.setState({
- 'selected': nodes
- });
- if (this.props.onSelected) {
- this.props.onSelected(nodes);
- }
- }
- onSelectClicked() {
- if (this.props.onSelectClicked) {
- this.props.onSelectClicked();
- }
- }
- onFinalizeClick(e) {
- if (e) {
- e.preventDefault();
- e.stopPropagation();
- }
- const {
- groupName,
- selected,
- keyRotation,
- createChatLink,
- openInvite
- } = this.state;
- megaChat.createAndShowGroupRoomFor(selected, groupName.trim(), {
- keyRotation,
- createChatLink: keyRotation ? false : createChatLink,
- openInvite
- });
- this.props.onClose(this);
- eventlog(500236);
- }
- componentDidMount() {
- super.componentDidMount();
- if (!this.props.subDialog) {
- M.safeShowDialog(this.dialogName, nop);
- }
- }
- componentWillUnmount() {
- super.componentWillUnmount();
- if ($.dialog === this.dialogName) {
- closeDialog();
- }
- }
- render() {
- const self = this;
- const classes = `new-group-chat contrast small-footer contact-picker-widget ${ self.props.className}`;
- let contacts = M.u;
- const {haveContacts} = self.state;
- const buttons = [];
- let allowNext = false;
- let failedToEnableChatlink = self.state.failedToEnableChatlink && self.state.createChatLink === true && !self.state.groupName;
- if (self.state.keyRotation) {
- failedToEnableChatlink = false;
- }
- let extraContent;
- if (this.props.extraContent) {
- self.state.step = 0;
- extraContent = React.createElement("div", {
- className: "content-block imported"
- });
- } else if (self.state.step === 0 && haveContacts) {
- allowNext = true;
- buttons.push({
- "label": self.props.cancelLabel,
- "key": "cancel",
- "onClick" (e) {
- self.props.onClose(self);
- e.preventDefault();
- e.stopPropagation();
- }
- });
- buttons.push({
- "label": l[556],
- "key": "next",
- "className": !allowNext ? "disabled positive" : "positive",
- "onClick" (e) {
- e.preventDefault();
- e.stopPropagation();
- self.setState({
- 'step': 1
- });
- }
- });
- } else if (self.state.step === 1) {
- allowNext = self.state.createChatLink ? !failedToEnableChatlink : true;
- contacts = [];
- self.state.selected.forEach((h) => {
- if (h in M.u) {
- contacts.push(M.u[h]);
- }
- });
- if (!haveContacts || this.props.flowType === 2) {
- buttons.push({
- "label": self.props.cancelLabel,
- "key": "cancel",
- "onClick" (e) {
- self.props.onClose(self);
- e.preventDefault();
- e.stopPropagation();
- }
- });
- } else {
- buttons.push({
- "label": l[822],
- "key": "back",
- "onClick" (e) {
- e.preventDefault();
- e.stopPropagation();
- self.setState({
- 'step': 0
- });
- }
- });
- }
- buttons.push({
- "label": l[726],
- "key": "done",
- "className": !allowNext ? "positive disabled" : "positive",
- "onClick" (e) {
- if (self.state.createChatLink === true && !self.state.groupName) {
- self.setState({
- 'failedToEnableChatlink': true
- });
- } else {
- self.onFinalizeClick(e);
- }
- }
- });
- }
- let chatInfoElements;
- if (self.state.step === 1) {
- let _this$state$groupName;
- let checkboxClassName = self.state.createChatLink ? "checkboxOn" : "checkboxOff";
- if (failedToEnableChatlink && self.state.createChatLink) {
- checkboxClassName += " intermediate-state";
- }
- if (self.state.keyRotation) {
- checkboxClassName = "checkboxOff";
- }
- chatInfoElements = React.createElement(React.Fragment, null, React.createElement("div", {
- className: `
- contacts-search-header left-aligned top-pad
- ${failedToEnableChatlink ? 'failed' : ''}
- `
- }, React.createElement("div", {
- className: `
- mega-input
- with-icon
- box-style
- ${((_this$state$groupName = this.state.groupName) == null ? void 0 : _this$state$groupName.length) > 0 ? 'valued' : ''}
- ${failedToEnableChatlink ? 'error msg' : ''}
- `,
- ref: this.inputContainerRef
- }, React.createElement("i", {
- className: "sprite-fm-mono icon-channel-new"
- }), React.createElement("input", {
- autoFocus: true,
- className: "megaInputs",
- type: "text",
- ref: this.inputRef,
- placeholder: l[18509],
- value: this.state.groupName,
- maxLength: ChatRoom.TOPIC_MAX_LENGTH,
- onKeyDown: e => {
- const code = e.which || e.keyCode;
- if (allowNext && code === 13 && self.state.step === 1) {
- this.onFinalizeClick();
- }
- },
- onChange: e => {
- const containerRef = this.inputContainerRef.current;
- const {
- value
- } = e.target;
- containerRef.classList[value.length > 0 ? 'add' : 'remove']('valued');
- this.setState({
- groupName: value,
- failedToEnableChatlink: false
- });
- }
- }))), this.props.flowType === 2 ? null : React.createElement("div", {
- className: "group-chat-dialog content"
- }, React.createElement(miniui.A.ToggleCheckbox, {
- className: "rotation-toggle",
- checked: this.state.keyRotation,
- onToggle: keyRotation => this.setState({
- keyRotation
- }, () => this.inputRef.current.focus())
- }), React.createElement("div", {
- className: "group-chat-dialog header"
- }, l[20576]), React.createElement("div", {
- className: "group-chat-dialog description"
- }, l[20484]), React.createElement(miniui.A.ToggleCheckbox, {
- className: "open-invite-toggle",
- checked: this.state.openInvite,
- value: this.state.openInvite,
- onToggle: openInvite => this.setState({
- openInvite
- }, () => this.inputRef.current.focus())
- }), React.createElement("div", {
- className: "group-chat-dialog header"
- }, l.open_invite_label), React.createElement("div", {
- className: "group-chat-dialog description"
- }, l.open_invite_desc), React.createElement("div", {
- className: `
- group-chat-dialog checkbox
- ${this.state.keyRotation ? 'disabled' : ''}
- ${failedToEnableChatlink ? 'failed' : ''}
- `,
- onClick: () => {
- delay('chatWizard-createChatLink', () => {
- this.setState(state => ({
- createChatLink: !state.createChatLink
- }));
- this.inputRef.current.focus();
- }, 100);
- }
- }, React.createElement("div", {
- className: `checkdiv ${checkboxClassName}`
- }, React.createElement("input", {
- type: "checkbox",
- name: "group-encryption",
- id: "group-encryption",
- className: "checkboxOn hidden"
- })), React.createElement("label", {
- htmlFor: "group-encryption",
- className: "radio-txt lato mid"
- }, l[20575]), React.createElement("div", {
- className: "clear"
- }))), failedToEnableChatlink ? React.createElement("div", {
- className: "group-chat-dialog description chatlinks-intermediate-msg"
- }, l[20573]) : null);
- }
- return React.createElement(modalDialogs.A.ModalDialog, {
- step: self.state.step,
- title: this.props.flowType === 2 && self.state.createChatLink ? l[20638] : this.props.customDialogTitle || l[19483],
- className: classes,
- dialogType: "tool",
- dialogName: "group-chat-dialog",
- showSelectedNum: self.props.showSelectedNum,
- selectedNum: self.state.selected.length,
- closeDlgOnClickOverlay: self.props.closeDlgOnClickOverlay,
- onClose: () => {
- self.props.onClose(self);
- },
- popupDidMount: elem => {
- if (this.props.extraContent) {
- let _elem$querySelector;
- (_elem$querySelector = elem.querySelector('.content-block.imported')) == null || _elem$querySelector.appendChild(this.props.extraContent);
- }
- if (this.props.onExtraContentDidMount) {
- this.props.onExtraContentDidMount(elem);
- }
- },
- triggerResizeOnUpdate: true,
- buttons
- }, React.createElement("div", {
- ref: this.domRef,
- className: "content-block"
- }, chatInfoElements, React.createElement(ui_contacts.ContactPickerWidget, {
- step: self.state.step,
- exclude: self.props.exclude,
- contacts,
- selectableContacts: "true",
- onSelectDone: self.onSelectClicked,
- onSelected: self.onSelected,
- selected: self.state.selected,
- headerClasses: "left-aligned",
- multiple: true,
- readOnly: self.state.step !== 0,
- allowEmpty: true,
- showMeAsSelected: self.state.step === 1,
- className: self.props.pickerClassName,
- disableFrequents: self.props.disableFrequents,
- skipMailSearch: self.props.skipMailSearch,
- autoFocusSearchField: self.props.autoFocusSearchField,
- selectCleanSearchRes: self.props.selectCleanSearchRes,
- disableDoubleClick: self.props.disableDoubleClick,
- selectedWidthSize: self.props.selectedWidthSize,
- emptySelectionMsg: self.props.emptySelectionMsg,
- newEmptySearchResult: self.props.newEmptySearchResult,
- newNoContact: self.props.newNoContact,
- highlightSearchValue: self.props.highlightSearchValue,
- emailTooltips: self.props.emailTooltips
- })), extraContent);
- }
-}
-StartGroupChatWizard.clickTime = 0;
-StartGroupChatWizard.defaultProps = {
- 'selectLabel': l[1940],
- 'cancelLabel': l.msg_dlg_cancel,
- 'hideable': true,
- 'flowType': 1,
- 'pickerClassName': '',
- 'showSelectedNum': false,
- 'disableFrequents': false,
- 'skipMailSearch': false,
- 'autoFocusSearchField': true,
- 'selectCleanSearchRes': true,
- 'disableDoubleClick': false,
- 'newEmptySearchResult': false,
- 'newNoContact': false,
- 'closeDlgOnClickOverlay': true,
- 'emailTooltips': false
-};
-window.StartGroupChatDialogUI = {
- StartGroupChatWizard
-};
-const startGroupChatWizard = {
- StartGroupChatWizard
-};
-// EXTERNAL MODULE: ./js/chat/ui/meetings/call.jsx + 11 modules
-const call = REQ_(3);
-// EXTERNAL MODULE: ./js/chat/ui/chatToaster.jsx
-const chatToaster = REQ_(424);
-;// ./js/chat/ui/searchPanel/resultTable.jsx
-
-const ResultTable = ({
- heading,
- children
-}) => {
- return REaCt().createElement("div", {
- className: `result-table ${heading ? '' : 'nil'}`
- }, heading ? REaCt().createElement("div", {
- className: "result-table-heading"
- }, heading) : null, children);
-};
-const resultTable = ResultTable;
-;// ./js/chat/ui/searchPanel/resultRow.jsx
-
-
-
-
-
-
-
-
-const RESULT_ROW_CLASS = 'result-table-row';
-const USER_CARD_CLASS = 'user-card';
-const roomIsGroup = room => room && room.type === 'group' || room.type === 'public';
-const openResult = ({
- room,
- messageId,
- index
-}, callback) => {
- document.dispatchEvent(new Event(EVENTS.RESULT_OPEN));
- if (isString(room)) {
- loadSubPage(`fm/chat/p/${room}`);
- } else if (room && room.chatId && !messageId) {
- const chatRoom = megaChat.getChatById(room.chatId);
- if (chatRoom) {
- loadSubPage(chatRoom.getRoomUrl());
- } else {
- loadSubPage(`/fm/chat/contacts/${room.chatId}`);
- }
- } else {
- loadSubPage(room.getRoomUrl());
- if (messageId) {
- room.scrollToMessageId(messageId, index);
- }
- }
- return callback && typeof callback === 'function' && callback();
-};
-const lastActivity = room => {
- if (!room.lastActivity || !room.ctime) {
- room = megaChat.getChatById(room.chatId);
- }
- if (room && room.lastActivity || room.ctime) {
- return room.lastActivity ? todayOrYesterday(room.lastActivity * 1000) ? getTimeMarker(room.lastActivity) : time2date(room.lastActivity, 17) : todayOrYesterday(room.ctime * 1000) ? getTimeMarker(room.ctime) : time2date(room.ctime, 17);
- }
- return l[8000];
-};
-class MessageRow extends mixins.w9 {
- render() {
- const {
- data,
- matches,
- room,
- index,
- onResultOpen
- } = this.props;
- const isGroup = roomIsGroup(room);
- const contact = room.getParticipantsExceptMe();
- const summary = room.messagesBuff.getRenderableSummary(data);
- const date = todayOrYesterday(data.delay * 1000) ? getTimeMarker(data.delay) : time2date(data.delay, 17);
- return REaCt().createElement("div", {
- ref: node => {
- this.domRef = node;
- },
- className: `
- ${RESULT_ROW_CLASS}
- message
- `,
- onClick: () => openResult({
- room,
- messageId: data.messageId,
- index
- }, () => onResultOpen(this.domRef))
- }, REaCt().createElement("div", {
- className: "message-result-avatar"
- }, isGroup && REaCt().createElement("div", {
- className: "chat-topic-icon"
- }, REaCt().createElement("i", {
- className: "sprite-fm-uni icon-chat-group"
- })), room.isNote && REaCt().createElement("div", {
- className: "note-chat-signifier"
- }, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-file-text-thin-outline note-chat-icon"
- })), room.type === 'private' && REaCt().createElement(ui_contacts.Avatar, {
- contact: M.u[contact]
- })), REaCt().createElement("div", {
- className: "user-card"
- }, REaCt().createElement("span", {
- className: "title"
- }, isGroup && REaCt().createElement(utils.sp, null, room.getRoomTitle()), room.isNote && REaCt().createElement("span", null, l.note_label), room.type === 'private' && REaCt().createElement(ui_contacts.ContactAwareName, {
- contact: M.u[contact],
- overflow: true
- })), isGroup ? null : REaCt().createElement(ui_contacts.ContactPresence, {
- contact: M.u[contact]
- }), REaCt().createElement("div", {
- className: "clear"
- }), REaCt().createElement("div", {
- className: "message-result-info"
- }, REaCt().createElement("div", {
- className: "summary"
- }, REaCt().createElement(utils.oM, {
- content: megaChat.highlight(summary, matches, true)
- })), REaCt().createElement("div", {
- className: "result-separator"
- }, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-dot"
- })), REaCt().createElement("span", {
- className: "date"
- }, date))));
- }
-}
-class ChatRow extends mixins.w9 {
- render() {
- const {
- room,
- matches,
- onResultOpen
- } = this.props;
- const result = megaChat.highlight(megaChat.html(room.getRoomTitle()), matches, true);
- return REaCt().createElement("div", {
- ref: node => {
- this.domRef = node;
- },
- className: RESULT_ROW_CLASS,
- onClick: () => openResult({
- room
- }, () => onResultOpen(this.domRef))
- }, REaCt().createElement("div", {
- className: "chat-topic-icon"
- }, REaCt().createElement("i", {
- className: "sprite-fm-uni icon-chat-group"
- })), REaCt().createElement("div", {
- className: USER_CARD_CLASS
- }, REaCt().createElement("div", {
- className: "graphic"
- }, REaCt().createElement(utils.oM, null, result)), REaCt().createElement("div", {
- className: "result-last-activity"
- }, lastActivity(room))), REaCt().createElement("div", {
- className: "clear"
- }));
- }
-}
-class MemberRow extends mixins.w9 {
- render() {
- const {
- data,
- matches,
- room,
- contact,
- onResultOpen
- } = this.props;
- const isGroup = room && roomIsGroup(room);
- return REaCt().createElement("div", {
- ref: node => {
- this.domRef = node;
- },
- className: RESULT_ROW_CLASS,
- onClick: () => openResult({
- room: room || contact.h
- }, () => onResultOpen(this.domRef))
- }, isGroup ? REaCt().createElement("div", {
- className: "chat-topic-icon"
- }, REaCt().createElement("i", {
- className: "sprite-fm-uni icon-chat-group"
- })) : REaCt().createElement(ui_contacts.Avatar, {
- contact
- }), REaCt().createElement("div", {
- className: USER_CARD_CLASS
- }, REaCt().createElement("div", {
- className: "graphic"
- }, isGroup ? REaCt().createElement(utils.oM, null, megaChat.highlight(megaChat.html(room.getRoomTitle()), matches, true)) : REaCt().createElement(REaCt().Fragment, null, REaCt().createElement(utils.oM, null, megaChat.highlight(megaChat.html(nicknames.getNickname(data)), matches, true)), REaCt().createElement(ui_contacts.ContactPresence, {
- contact
- }))), lastActivity(room)), REaCt().createElement("div", {
- className: "clear"
- }));
- }
-}
-const NilRow = ({
- onSearchMessages,
- isFirstQuery
-}) => {
- const label = LABEL.SEARCH_MESSAGES_INLINE.replace('[A]', '').replace('[/A]', '');
- return REaCt().createElement("div", {
- className: `
- ${RESULT_ROW_CLASS}
- nil
- `
- }, REaCt().createElement("div", {
- className: "nil-container"
- }, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-preview-reveal"
- }), REaCt().createElement("span", null, LABEL.NO_RESULTS), isFirstQuery && REaCt().createElement("div", {
- className: "search-messages",
- onClick: onSearchMessages
- }, REaCt().createElement(utils.oM, {
- tag: "div",
- content: label
- }))));
-};
-class ResultRow extends mixins.w9 {
- constructor(...args) {
- super(...args);
- this.setActive = nodeRef => {
- if (nodeRef) {
- const elements = document.querySelectorAll(`.${RESULT_ROW_CLASS}.${"active"}`);
- for (let i = elements.length; i--;) {
- elements[i].classList.remove('active');
- }
- nodeRef.classList.add("active");
- }
- };
- }
- render() {
- const {
- type,
- result,
- children,
- onSearchMessages,
- isFirstQuery
- } = this.props;
- if (result) {
- const {
- data,
- index,
- matches,
- room
- } = result;
- const PROPS = {
- data,
- index,
- matches,
- room,
- onResultOpen: this.setActive
- };
- switch (type) {
- case TYPE.MESSAGE:
- return REaCt().createElement(MessageRow, PROPS);
- case TYPE.CHAT:
- return REaCt().createElement(ChatRow, PROPS);
- case TYPE.MEMBER:
- return REaCt().createElement(MemberRow, (0,esm_extends.A)({}, PROPS, {
- contact: M.u[data]
- }));
- default:
- return REaCt().createElement("div", {
- className: RESULT_ROW_CLASS
- }, children);
- }
- }
- return REaCt().createElement(NilRow, {
- onSearchMessages,
- isFirstQuery
- });
- }
-}
-;// ./js/chat/ui/searchPanel/resultContainer.jsx
-
-
-
-
-const TYPE = {
- MESSAGE: 1,
- CHAT: 2,
- MEMBER: 3,
- NIL: 4
-};
-const LABEL = {
- MESSAGES: l[6868],
- CONTACTS_AND_CHATS: l[20174],
- NO_RESULTS: l[8674],
- SEARCH_MESSAGES_CTA: l[23547],
- SEARCH_MESSAGES_INLINE: l[23548],
- DECRYPTING_RESULTS: l[23543],
- PAUSE_SEARCH: l[23544],
- SEARCH_PAUSED: l[23549],
- SEARCH_COMPLETE: l[23546]
-};
-class ResultContainer extends REaCt().Component {
- constructor(...args) {
- super(...args);
- this.renderResults = (results, status, isFirstQuery, onSearchMessages) => {
- if (status === STATUS.COMPLETED && results.length < 1) {
- return REaCt().createElement(resultTable, null, REaCt().createElement(ResultRow, {
- type: TYPE.NIL,
- isFirstQuery,
- onSearchMessages
- }));
- }
- const RESULT_TABLE = {
- CONTACTS_AND_CHATS: [],
- MESSAGES: []
- };
- for (const resultTypeGroup in results) {
- if (results.hasOwnProperty(resultTypeGroup)) {
- const len = results[resultTypeGroup].length;
- for (let i = 0; i < len; i++) {
- const result = results[resultTypeGroup].getItem(i);
- const {
- MESSAGE,
- MEMBER,
- CHAT
- } = TYPE;
- const {
- resultId,
- type
- } = result;
- const table = type === MESSAGE ? 'MESSAGES' : 'CONTACTS_AND_CHATS';
- RESULT_TABLE[table] = [...RESULT_TABLE[table], REaCt().createElement(ResultRow, {
- key: resultId,
- type: type === MESSAGE ? MESSAGE : type === MEMBER ? MEMBER : CHAT,
- result
- })];
- }
- }
- }
- return Object.keys(RESULT_TABLE).map((key, index) => {
- const table = {
- ref: RESULT_TABLE[key],
- hasRows: RESULT_TABLE[key] && RESULT_TABLE[key].length,
- isEmpty: RESULT_TABLE[key] && RESULT_TABLE[key].length < 1,
- props: {
- key: index,
- heading: key === 'MESSAGES' ? LABEL.MESSAGES : LABEL.CONTACTS_AND_CHATS
- }
- };
- if (table.hasRows) {
- return REaCt().createElement(resultTable, table.props, table.ref.map(row => row));
- }
- if (status === STATUS.COMPLETED && key === 'MESSAGES') {
- const SEARCH_MESSAGES = REaCt().createElement("button", {
- className: "search-messages mega-button",
- onClick: onSearchMessages
- }, REaCt().createElement("span", null, LABEL.SEARCH_MESSAGES_CTA));
- const NO_RESULTS = REaCt().createElement(ResultRow, {
- type: TYPE.NIL,
- isFirstQuery,
- onSearchMessages
- });
- return REaCt().createElement(resultTable, table.props, isFirstQuery ? SEARCH_MESSAGES : NO_RESULTS);
- }
- return null;
- });
- };
- }
- render() {
- const {
- results,
- status,
- isFirstQuery,
- onSearchMessages
- } = this.props;
- return this.renderResults(results, status, isFirstQuery, onSearchMessages);
- }
-}
-;// ./js/chat/ui/searchPanel/searchField.jsx
-let _SearchField;
-
-
-
-
-const SEARCH_STATUS_CLASS = 'search-field-status';
-const BASE_ICON_CLASS = 'sprite-fm-mono';
-class SearchField extends mixins.w9 {
- constructor(...args) {
- super(...args);
- this.domRef = REaCt().createRef();
- this.state = {
- hovered: false
- };
- this.renderStatusBanner = () => {
- switch (this.props.status) {
- case STATUS.IN_PROGRESS:
- return REaCt().createElement("div", {
- className: `${SEARCH_STATUS_CLASS} searching info`
- }, LABEL.DECRYPTING_RESULTS);
- case STATUS.PAUSED:
- return REaCt().createElement("div", {
- className: `${SEARCH_STATUS_CLASS} paused info`
- }, LABEL.SEARCH_PAUSED);
- case STATUS.COMPLETED:
- return REaCt().createElement("div", {
- className: `${SEARCH_STATUS_CLASS} complete success`
- }, LABEL.SEARCH_COMPLETE);
- default:
- return null;
- }
- };
- this.renderStatusControls = () => {
- const {
- status,
- onToggle
- } = this.props;
- const handleHover = () => this.setState(state => ({
- hovered: !state.hovered
- }));
- switch (status) {
- case STATUS.IN_PROGRESS:
- return REaCt().createElement("div", {
- className: "progress-controls",
- onClick: onToggle
- }, REaCt().createElement("i", {
- className: `${BASE_ICON_CLASS} icon-pause`
- }));
- case STATUS.PAUSED:
- return REaCt().createElement("i", {
- className: `${BASE_ICON_CLASS} icon-resume`,
- onClick: onToggle,
- onMouseOver: handleHover,
- onMouseOut: handleHover
- });
- case STATUS.COMPLETED:
- return null;
- default:
- return null;
- }
- };
- }
- componentDidMount() {
- super.componentDidMount();
- SearchField.focus();
- }
- render() {
- const {
- value,
- searching,
- status,
- onChange,
- onReset
- } = this.props;
- return REaCt().createElement("div", {
- ref: this.domRef,
- className: "search-field"
- }, REaCt().createElement("i", {
- className: `${BASE_ICON_CLASS} icon-preview-reveal search-icon-find`
- }), REaCt().createElement("input", {
- type: "search",
- autoComplete: "off",
- placeholder: l[102],
- ref: SearchField.inputRef,
- value,
- onChange: ev => {
- if (this.state.hovered) {
- this.setState({
- hovered: false
- });
- }
- onChange(ev);
- }
- }), searching && REaCt().createElement("i", {
- className: `
- ${BASE_ICON_CLASS}
- icon-close-component
- search-icon-reset
- `,
- onClick: onReset
- }), searching && status && REaCt().createElement(REaCt().Fragment, null, this.renderStatusControls(), this.renderStatusBanner()));
- }
-}
-_SearchField = SearchField;
-SearchField.inputRef = REaCt().createRef();
-SearchField.select = () => {
- const inputElement = _SearchField.inputRef && _SearchField.inputRef.current;
- const value = inputElement && inputElement.value;
- if (inputElement && value) {
- inputElement.selectionStart = 0;
- inputElement.selectionEnd = value.length;
- }
-};
-SearchField.focus = () => _SearchField.inputRef && _SearchField.inputRef.current && _SearchField.inputRef.current.focus();
-SearchField.hasValue = () => _SearchField.inputRef && _SearchField.inputRef.current && !!_SearchField.inputRef.current.value.length;
-SearchField.isVisible = () => _SearchField.inputRef && _SearchField.inputRef.current && elementIsVisible(_SearchField.inputRef.current);
-;// ./js/chat/ui/searchPanel/searchPanel.jsx
-
-
-
-
-
-const STATUS = {
- IN_PROGRESS: 1,
- PAUSED: 2,
- COMPLETED: 3
-};
-const EVENTS = {
- RESULT_OPEN: 'chatSearchResultOpen',
- KEYDOWN: 'keydown'
-};
-const ACTIONS = {
- PAUSE: 'pause',
- RESUME: 'resume'
-};
-const SEARCH_PANEL_CLASS = `search-panel`;
-class SearchPanel extends mixins.w9 {
- constructor(...args) {
- super(...args);
- this.domRef = REaCt().createRef();
- this.wrapperRef = null;
- this.state = {
- value: '',
- searching: false,
- status: undefined,
- isFirstQuery: true,
- results: []
- };
- this.unbindEvents = () => {
- if (this.pageChangeListener) {
- mBroadcaster.removeListener(this.pageChangeListener);
- }
- document.removeEventListener(EVENTS.RESULT_OPEN, this.doPause);
- document.removeEventListener(EVENTS.KEYDOWN, this.handleKeyDown);
- megaChat.plugins.chatdIntegration.chatd.off('onClose.search');
- megaChat.plugins.chatdIntegration.chatd.off('onOpen.search');
- };
- this.bindEvents = () => {
- this.pageChangeListener = mBroadcaster.addListener('pagechange', this.doPause);
- document.addEventListener(EVENTS.RESULT_OPEN, this.doPause);
- document.addEventListener(EVENTS.KEYDOWN, this.handleKeyDown);
- megaChat.plugins.chatdIntegration.chatd.rebind('onClose.search', () => this.state.searching && this.doToggle(ACTIONS.PAUSE));
- megaChat.plugins.chatdIntegration.chatd.rebind('onOpen.search', () => this.state.searching && this.doToggle(ACTIONS.RESUME));
- };
- this.doPause = () => {
- if (this.state.status === STATUS.IN_PROGRESS) {
- this.doToggle(ACTIONS.PAUSE);
- }
- };
- this.doSearch = (s, searchMessages) => {
- return ChatSearch.doSearch(s, (room, result, results) => this.setState({
- results
- }), searchMessages).catch(ex => d && console.error('Search failed (or was reset)', ex)).always(() => this.setState({
- status: STATUS.COMPLETED
- }));
- };
- this.doToggle = (action) => {
- const {
- IN_PROGRESS,
- PAUSED,
- COMPLETED
- } = STATUS;
- const searching = this.state.status === IN_PROGRESS || this.state.status === PAUSED;
- if (action && searching) {
- const chatSearch = ChatSearch.doSearch.cs;
- if (!chatSearch) {
- return delay('chat-toggle', () => this.doToggle(action), 600);
- }
- this.setState({
- status: action === ACTIONS.PAUSE ? PAUSED : action === ACTIONS.RESUME ? IN_PROGRESS : COMPLETED
- }, () => chatSearch[action]());
- }
- };
- this.doDestroy = () => ChatSearch && ChatSearch.doSearch && ChatSearch.doSearch.cs && ChatSearch.doSearch.cs.destroy();
- this.handleKeyDown = ev => {
- const {
- keyCode
- } = ev;
- if (keyCode && keyCode === 27) {
- return SearchField.hasValue() ? this.handleReset() : this.doPause();
- }
- };
- this.handleChange = ev => {
- if (SearchField.isVisible()) {
- const {
- value
- } = ev.target;
- const searching = value.length > 0;
- this.doDestroy();
- this.setState({
- value,
- searching,
- status: undefined,
- isFirstQuery: true,
- results: []
- }, () => {
- if (searching) {
- delay('chat-search', () => this.doSearch(value, false), 1600);
- if ($.dialog === 'onboardingDialog') {
- closeDialog();
- }
- } else {
- megaChat.plugins.chatOnboarding.checkAndShowStep();
- }
- });
- this.wrapperRef.scrollToY(0);
- }
- };
- this.handleToggle = () => {
- const inProgress = this.state.status === STATUS.IN_PROGRESS;
- this.setState({
- status: inProgress ? STATUS.PAUSED : STATUS.IN_PROGRESS
- }, () => {
- delay('chat-toggled', () => SearchField.focus());
- return this.doToggle(inProgress ? ACTIONS.PAUSE : ACTIONS.RESUME);
- });
- };
- this.handleReset = () => this.setState({
- value: '',
- searching: false,
- status: undefined,
- results: []
- }, () => {
- this.wrapperRef.scrollToY(0);
- onIdle(() => SearchField.focus());
- this.doDestroy();
- });
- this.handleSearchMessages = () => SearchField.hasValue() && this.setState({
- status: STATUS.IN_PROGRESS,
- isFirstQuery: false
- }, () => {
- this.doSearch(this.state.value, true);
- SearchField.focus();
- SearchField.select();
- });
- }
- componentDidMount() {
- super.componentDidMount();
- this.bindEvents();
- }
- componentWillUnmount() {
- super.componentWillUnmount();
- this.unbindEvents();
- }
- render() {
- const {
- value,
- searching,
- status,
- isFirstQuery,
- results
- } = this.state;
- return REaCt().createElement("div", {
- ref: this.domRef,
- className: `
- ${SEARCH_PANEL_CLASS}
- ${searching ? 'expanded' : ''}
- `
- }, REaCt().createElement(SearchField, {
- value,
- searching,
- status,
- onChange: this.handleChange,
- onToggle: this.handleToggle,
- onReset: this.handleReset
- }), REaCt().createElement(perfectScrollbar.O, {
- className: "search-results-wrapper",
- ref: wrapper => {
- this.wrapperRef = wrapper;
- },
- options: {
- 'suppressScrollX': true
- }
- }, searching && REaCt().createElement(ResultContainer, {
- status,
- results,
- isFirstQuery,
- onSearchMessages: this.handleSearchMessages
- })));
- }
-}
-;// ./js/chat/ui/leftPanel/navigation.jsx
-
-
-
-const Navigation = ({
- view,
- views: {
- CHATS,
- MEETINGS
- },
- routingSection,
- unreadChats,
- unreadMeetings,
- contactRequests,
- renderView
-}) => REaCt().createElement("div", {
- className: `${NAMESPACE}-nav`
-}, REaCt().createElement("div", {
- className: `
- ${NAMESPACE}-nav-container
- ${NAMESPACE}-chats-tab
- ${view === CHATS && routingSection === 'chat' ? 'active' : ''}
- `,
- onClick: () => {
- renderView(CHATS);
- eventlog(500233);
- }
-}, REaCt().createElement(meetings_button.A, {
- unreadChats,
- className: `${NAMESPACE}-nav-button`,
- icon: "icon-chat-filled"
-}, !!unreadChats && REaCt().createElement("div", {
- className: "notifications-count"
-})), REaCt().createElement("span", null, l.chats)), REaCt().createElement("div", {
- className: `
- ${NAMESPACE}-nav-container
- ${NAMESPACE}-meetings-tab
- ${view === MEETINGS && routingSection === 'chat' ? 'active' : ''}
- `,
- onClick: () => {
- renderView(MEETINGS);
- eventlog(500234);
- }
-}, REaCt().createElement(meetings_button.A, {
- unreadMeetings,
- className: `${NAMESPACE}-nav-button`,
- icon: "icon-video-call-filled"
-}, !!unreadMeetings && REaCt().createElement("div", {
- className: "notifications-count"
-})), REaCt().createElement("span", null, l.meetings)), is_eplusplus || is_chatlink ? null : REaCt().createElement("div", {
- className: `
- ${NAMESPACE}-nav-container
- ${NAMESPACE}-contacts-tab
- ${routingSection === 'contacts' ? 'active' : ''}
- `,
- onClick: () => {
- loadSubPage('fm/chat/contacts');
- eventlog(500296);
- }
-}, REaCt().createElement(meetings_button.A, {
- className: `${NAMESPACE}-nav-button`,
- contactRequests,
- icon: "icon-contacts"
-}, !!contactRequests && REaCt().createElement("div", {
- className: "notifications-count"
-})), REaCt().createElement("span", null, l[165])));
-// EXTERNAL MODULE: ./js/ui/buttons.jsx
-const buttons = REQ_(994);
-// EXTERNAL MODULE: ./js/ui/dropdowns.jsx
-const dropdowns = REQ_(911);
-;// ./js/chat/ui/leftPanel/actions.jsx
-
-
-
-
-const Actions = ({
- view,
- views,
- filter,
- routingSection,
- startMeeting,
- scheduleMeeting,
- createNewChat,
- onFilter
-}) => {
- const {
- CHATS,
- MEETINGS,
- LOADING
- } = views;
- if (is_eplusplus || is_chatlink) {
- return null;
- }
- return REaCt().createElement("div", {
- className: `${NAMESPACE}-action-buttons`
- }, view === LOADING && REaCt().createElement(buttons.$, {
- className: "mega-button action loading-sketch"
- }, REaCt().createElement("i", null), REaCt().createElement("span", null)), view === CHATS && routingSection !== 'contacts' && REaCt().createElement(REaCt().Fragment, null, REaCt().createElement(buttons.$, {
- className: "mega-button small positive new-chat-action",
- label: l.add_chat,
- onClick: () => {
- createNewChat();
- eventlog(500284);
- }
- }), REaCt().createElement("div", {
- className: "lhp-filter"
- }, REaCt().createElement("div", {
- className: "lhp-filter-control"
- }, REaCt().createElement(buttons.$, {
- icon: "sprite-fm-mono icon-sort-thin-solid"
- }, REaCt().createElement(dropdowns.Dropdown, {
- className: "light",
- noArrow: "true"
- }, REaCt().createElement(dropdowns.DropdownItem, {
- className: "link-button",
- icon: "sprite-fm-mono icon-eye-reveal",
- label: l.filter_unread,
- onClick: () => onFilter(FILTER.UNREAD)
- }), REaCt().createElement(dropdowns.DropdownItem, {
- className: "link-button",
- icon: "sprite-fm-mono icon-notification-off",
- label: view === MEETINGS ? l.filter_muted__meetings : l.filter_muted__chats,
- onClick: () => onFilter(FILTER.MUTED)
- })))), filter && REaCt().createElement(REaCt().Fragment, null, filter === FILTER.MUTED && REaCt().createElement("div", {
- className: "lhp-filter-tag",
- onClick: () => onFilter(FILTER.MUTED)
- }, REaCt().createElement("span", null, view === MEETINGS ? l.filter_muted__meetings : l.filter_muted__chats), REaCt().createElement("i", {
- className: "sprite-fm-mono icon-close-component"
- })), filter === FILTER.UNREAD && REaCt().createElement("div", {
- className: "lhp-filter-tag",
- onClick: () => onFilter(FILTER.UNREAD)
- }, REaCt().createElement("span", null, l.filter_unread), REaCt().createElement("i", {
- className: "sprite-fm-mono icon-close-component"
- }))))), view === MEETINGS && routingSection !== 'contacts' && REaCt().createElement(buttons.$, {
- className: "mega-button small positive new-meeting-action",
- label: l.new_meeting
- }, REaCt().createElement("i", {
- className: "dropdown-indicator sprite-fm-mono icon-arrow-down"
- }), REaCt().createElement(dropdowns.Dropdown, {
- className: "light",
- noArrow: "true",
- vertOffset: 4,
- positionMy: "left top",
- positionAt: "left bottom"
- }, REaCt().createElement(dropdowns.DropdownItem, {
- className: "link-button",
- icon: "sprite-fm-mono icon-video-plus",
- label: l.new_meeting_start,
- onClick: startMeeting
- }), REaCt().createElement("hr", null), REaCt().createElement(dropdowns.DropdownItem, {
- className: "link-button",
- icon: "sprite-fm-mono icon-calendar2",
- label: l.schedule_meeting_start,
- onClick: scheduleMeeting
- }))), routingSection === 'contacts' && REaCt().createElement(buttons.$, {
- className: "mega-button small positive",
- label: l[71],
- onClick: () => {
- contactAddDialog();
- eventlog(500285);
- }
- }));
-};
-const actions = Actions;
-// EXTERNAL MODULE: ./node_modules/@babel/runtime/helpers/esm/applyDecoratedDescriptor.js
-const applyDecoratedDescriptor = REQ_(793);
-;// ./js/chat/ui/leftPanel/conversationsListItem.jsx
-
-let _dec, _dec2, _class;
-
-
-
-
-const ConversationsListItem = (_dec = utils.Ay.SoonFcWrap(40, true), _dec2 = (0,mixins.N9)(0.7, 8), _class = class ConversationsListItem extends mixins.w9 {
- constructor(...args) {
- super(...args);
- this.domRef = REaCt().createRef();
- this.state = {
- isLoading: true
- };
- }
- isLoading() {
- const mb = this.props.chatRoom.messagesBuff;
- if (mb.haveMessages) {
- return false;
- }
- return mb.messagesHistoryIsLoading() || mb.joined === false && mb.isDecrypting;
- }
- specShouldComponentUpdate() {
- return !this.state.isLoading;
- }
- componentWillUnmount() {
- super.componentWillUnmount();
- this.props.chatRoom.unbind('onUnreadCountUpdate.conversationsListItem');
- }
- componentDidMount() {
- super.componentDidMount();
- this.eventuallyScrollTo();
- const promise = this.isLoading();
- if (promise && promise.always) {
- promise.always(() => {
- if (this.isMounted()) {
- this.setState({
- isLoading: false
- });
- }
- });
- } else if (promise === false) {
- this.setState({
- isLoading: false
- });
- }
- this.props.chatRoom.rebind('onUnreadCountUpdate.conversationsListItem', () => {
- this.safeForceUpdate();
- });
- }
- componentDidUpdate() {
- super.componentDidUpdate();
- this.eventuallyScrollTo();
- }
- eventuallyScrollTo() {
- const chatRoom = this.props.chatRoom || false;
- if (chatRoom._scrollToOnUpdate) {
- if (chatRoom.isCurrentlyActive) {
- chatRoom.scrollToChat();
- } else {
- chatRoom._scrollToOnUpdate = false;
- }
- }
- }
- getConversationTimestamp() {
- const {
- chatRoom
- } = this.props;
- if (chatRoom) {
- const lastMessage = chatRoom.messagesBuff.getLatestTextMessage();
- const timestamp = lastMessage && lastMessage.delay || chatRoom.ctime;
- return todayOrYesterday(timestamp * 1000) ? getTimeMarker(timestamp) : time2date(timestamp, 17);
- }
- return null;
- }
- getScheduledDateTime() {
- const {
- scheduledMeeting
- } = this.props.chatRoom;
- if (scheduledMeeting) {
- const {
- nextOccurrenceStart,
- nextOccurrenceEnd
- } = scheduledMeeting;
- return {
- date: time2date(nextOccurrenceStart / 1000, 19),
- startTime: toLocaleTime(nextOccurrenceStart),
- endTime: toLocaleTime(nextOccurrenceEnd)
- };
- }
- }
- render() {
- let classString = "";
- const {chatRoom} = this.props;
- if (!chatRoom || !chatRoom.chatId) {
- return null;
- }
- const roomId = chatRoom.chatId;
- if (chatRoom.isCurrentlyActive) {
- classString += " active";
- }
- let nameClassString = "user-card-name conversation-name selectable-txt";
- let contactId;
- let id;
- let contact;
- if (chatRoom.type === 'private') {
- const handle = chatRoom.getParticipantsExceptMe()[0];
- contact = handle ? M.u[handle] : M.u[u_handle];
- if (!contact) {
- return `Unknown conversation id for ${chatRoom.roomId}`;
- }
- id = `conversation_${htmlentities(contact.u)}`;
- } else if (chatRoom.type === 'group') {
- contactId = roomId;
- id = `conversation_${contactId}`;
- classString += ' groupchat';
- } else if (chatRoom.type === 'public') {
- contactId = roomId;
- id = `conversation_${contactId}`;
- classString += ' groupchat public';
- } else {
- return `Unknown room type for ${chatRoom.roomId}`;
- }
- const unreadCount = chatRoom.messagesBuff.getUnreadCount();
- let isUnread = false;
- const notificationItems = [];
- if (chatRoom.havePendingCall() && chatRoom.state !== ChatRoom.STATE.LEFT) {
- notificationItems.push(REaCt().createElement("i", {
- className: "tiny-icon white-handset",
- key: "callIcon"
- }));
- }
- if (unreadCount > 0) {
- notificationItems.push(REaCt().createElement("span", {
- key: "unreadCounter"
- }, unreadCount > 9 ? "9+" : unreadCount));
- isUnread = true;
- }
- let lastMessageDiv = null;
- const showHideMsg = mega.config.get('showHideChat');
- const lastMessage = showHideMsg ? '' : chatRoom.messagesBuff.getLatestTextMessage();
- let lastMsgDivClasses;
- if (lastMessage) {
- lastMsgDivClasses = `conversation-message${ isUnread ? " unread" : ""}`;
- const renderableSummary = chatRoom.messagesBuff.getRenderableSummary(lastMessage);
- if (chatRoom.havePendingCall() || chatRoom.haveActiveCall()) {
- lastMsgDivClasses += " call";
- classString += " call-exists";
- }
- lastMessageDiv = REaCt().createElement("div", {
- className: lastMsgDivClasses
- }, REaCt().createElement(utils.P9, null, renderableSummary));
- if (lastMessage.textContents && lastMessage.textContents[1] === Message.MANAGEMENT_MESSAGE_TYPES.VOICE_CLIP && lastMessage.getAttachmentMeta()[0]) {
- const playTime = secondsToTimeShort(lastMessage.getAttachmentMeta()[0].playtime);
- lastMessageDiv = REaCt().createElement("div", {
- className: lastMsgDivClasses
- }, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-audio-filled voice-message-icon"
- }), playTime);
- }
- if (lastMessage.metaType && lastMessage.metaType === Message.MESSAGE_META_TYPE.GEOLOCATION) {
- lastMessageDiv = REaCt().createElement("div", {
- className: lastMsgDivClasses
- }, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-location geolocation-icon"
- }), l[20789]);
- }
- } else {
- lastMsgDivClasses = "conversation-message";
- lastMessageDiv = showHideMsg ? '' : REaCt().createElement("div", {
- className: lastMsgDivClasses
- }, this.state.isLoading ? l[7006] : l[8000]);
- }
- if (chatRoom.type !== 'public') {
- nameClassString += ' privateChat';
- }
- let roomTitle = REaCt().createElement(utils.oM, null, megaChat.html(chatRoom.getRoomTitle()));
- if (chatRoom.type === 'private') {
- roomTitle = megaChat.WITH_SELF_NOTE && chatRoom.isNote ? REaCt().createElement("span", {
- className: "note-chat-label"
- }, l.note_label) : REaCt().createElement("span", null, REaCt().createElement("div", {
- className: "user-card-wrapper"
- }, REaCt().createElement(utils.oM, null, megaChat.html(chatRoom.getRoomTitle()))));
- }
- nameClassString += chatRoom.type === "private" || chatRoom.type === "group" ? ' badge-pad' : '';
- const {
- scheduledMeeting,
- isMeeting
- } = chatRoom;
- const isUpcoming = scheduledMeeting && scheduledMeeting.isUpcoming;
- const {
- startTime,
- endTime
- } = this.getScheduledDateTime() || {};
- const isEmptyNote = chatRoom.isNote && !chatRoom.hasMessages();
- return REaCt().createElement("li", {
- ref: this.domRef,
- id,
- className: `
- ${classString}
- ${isUpcoming ? 'upcoming-conversation' : ''}
- ${this.props.className || ''}
- `,
- "data-room-id": roomId,
- "data-jid": contactId,
- onClick: ev => {
- let _this$props$onConvers, _this$props;
- return ((_this$props$onConvers = (_this$props = this.props).onConversationClick) == null ? void 0 : _this$props$onConvers.call(_this$props, ev)) || loadSubPage(chatRoom.getRoomUrl(false));
- }
- }, REaCt().createElement("div", {
- className: "conversation-avatar"
- }, (chatRoom.type === 'group' || chatRoom.type === 'public') && REaCt().createElement("div", {
- className: `
- chat-topic-icon
- ${isMeeting ? 'meeting-icon' : ''}
- `
- }, REaCt().createElement("i", {
- className: isMeeting ? 'sprite-fm-mono icon-video-call-filled' : 'sprite-fm-uni icon-chat-group'
- })), chatRoom.type === 'private' && contact && chatRoom.isNote ? REaCt().createElement("div", {
- className: `
- note-chat-signifier
- ${isEmptyNote ? 'note-chat-empty' : ''}
- `
- }, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-file-text-thin-outline note-chat-icon"
- })) : REaCt().createElement(ui_contacts.Avatar, {
- contact
- })), REaCt().createElement("div", {
- className: "conversation-data"
- }, REaCt().createElement("div", {
- className: "conversation-data-top"
- }, REaCt().createElement("div", {
- className: `conversation-data-name ${nameClassString}`
- }, roomTitle, chatRoom.isMuted() ? REaCt().createElement("i", {
- className: "sprite-fm-mono icon-notification-off-filled muted-conversation-icon"
- }) : null), chatRoom.isNote ? null : REaCt().createElement("div", {
- className: "conversation-data-badges"
- }, chatRoom.type === 'private' ? REaCt().createElement(ui_contacts.ContactPresence, {
- contact
- }) : null, chatRoom.type === 'group' || chatRoom.type === 'private' ? REaCt().createElement("i", {
- className: "sprite-fm-uni icon-ekr-key simpletip",
- "data-simpletip": l[20935]
- }) : null, scheduledMeeting && scheduledMeeting.isUpcoming && scheduledMeeting.isRecurring && REaCt().createElement("i", {
- className: "sprite-fm-mono icon-repeat-thin-solid"
- }))), REaCt().createElement("div", {
- className: "clear"
- }), isUpcoming ? REaCt().createElement("div", {
- className: "conversation-message-info"
- }, REaCt().createElement("div", {
- className: "conversation-scheduled-data"
- }, REaCt().createElement("span", null, startTime), REaCt().createElement("span", null, "\xA0 - \xA0"), REaCt().createElement("span", null, endTime)), REaCt().createElement("div", {
- className: "conversation-scheduled-data"
- }, notificationItems.length > 0 ? REaCt().createElement("div", {
- className: `
- unread-messages
- items-${notificationItems.length}
- unread-upcoming
- ${unreadCount > 9 && notificationItems.length > 1 ? 'unread-spaced' : ''}
- `
- }, notificationItems) : null)) : REaCt().createElement("div", {
- className: "conversation-message-info"
- }, isEmptyNote ? null : lastMessageDiv)), isUpcoming || isEmptyNote ? null : REaCt().createElement("div", {
- className: "date-time-wrapper"
- }, REaCt().createElement("div", {
- className: "date-time"
- }, this.getConversationTimestamp()), notificationItems.length > 0 ? REaCt().createElement("div", {
- className: `
- unread-messages-container
- ${unreadCount > 9 && notificationItems.length > 1 ? 'unread-spaced' : ''}
- `
- }, REaCt().createElement("div", {
- className: `unread-messages items-${notificationItems.length}`
- }, notificationItems)) : null));
- }
-}, (0,applyDecoratedDescriptor.A)(_class.prototype, "eventuallyScrollTo", [_dec], Object.getOwnPropertyDescriptor(_class.prototype, "eventuallyScrollTo"), _class.prototype), (0,applyDecoratedDescriptor.A)(_class.prototype, "render", [_dec2], Object.getOwnPropertyDescriptor(_class.prototype, "render"), _class.prototype), _class);
-
-;// ./js/chat/ui/leftPanel/conversationsList.jsx
-
-
-
-
-
-
-
-const ConversationsList = ({
- conversations,
- className,
- children
-}) => {
- return REaCt().createElement(perfectScrollbar.O, {
- className: "chat-lp-scroll-area",
- didMount: (id, ref) => {
- megaChat.$chatTreePanePs = [...megaChat.$chatTreePanePs, {
- id,
- ref
- }];
- },
- willUnmount: id => {
- megaChat.$chatTreePanePs = megaChat.$chatTreePanePs.filter(ref => ref.id !== id);
- },
- conversations
- }, REaCt().createElement("ul", {
- className: `
- conversations-pane
- ${className || ''}
- `
- }, children || conversations.map(c => c.roomId && REaCt().createElement(ConversationsListItem, (0,esm_extends.A)({
- key: c.roomId,
- chatRoom: c
- }, c.type === 'private' && {
- contact: M.u[c.getParticipantsExceptMe()[0]]
- })))));
-};
-const Chats = ({
- conversations,
- onArchivedClicked,
- filter
-}) => {
- conversations = Object.values(conversations || {}).filter(c => !c.isMeeting && c.isDisplayable() && (!filter || filter === FILTER.UNREAD && c.messagesBuff.getUnreadCount() > 0 || filter === FILTER.MUTED && c.isMuted())).sort(M.sortObjFn(c => c.lastActivity || c.ctime, -1));
- const noteChat = megaChat.getNoteChat();
- return REaCt().createElement(REaCt().Fragment, null, REaCt().createElement("div", {
- className: "conversations-holder"
- }, filter ? null : REaCt().createElement("div", {
- className: "conversations-category"
- }, REaCt().createElement("span", null, l.filter_heading__recent)), conversations && conversations.length >= 1 ? REaCt().createElement(ConversationsList, {
- conversations
- }, megaChat.WITH_SELF_NOTE && noteChat && noteChat.isDisplayable() ? filter ? null : REaCt().createElement(ConversationsListItem, {
- chatRoom: noteChat
- }) : null, conversations.map(c => c.roomId && !c.isNote && REaCt().createElement(ConversationsListItem, (0,esm_extends.A)({
- key: c.roomId,
- chatRoom: c
- }, c.type === 'private' && {
- contact: M.u[c.getParticipantsExceptMe()[0]]
- })))) : REaCt().createElement("div", {
- className: `
- ${NAMESPACE}-nil
- ${filter ? `${NAMESPACE}-nil--chats` : ''}
- `
- }, filter ? REaCt().createElement(REaCt().Fragment, null, filter === FILTER.MUTED && REaCt().createElement(REaCt().Fragment, null, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-notification-off-filled"
- }), REaCt().createElement("h3", null, l.filter_nil__muted_chats)), filter === FILTER.UNREAD && REaCt().createElement(REaCt().Fragment, null, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-eye-thin-solid"
- }), REaCt().createElement("h3", null, l.filter_nil__unread_messages))) : REaCt().createElement("span", null, l.no_chats_lhp)), megaChat.WITH_SELF_NOTE && conversations && conversations.length === 1 && noteChat && REaCt().createElement(ConversationsList, {
- conversations
- }, REaCt().createElement(ConversationsListItem, {
- chatRoom: noteChat
- }))), REaCt().createElement("div", {
- className: `${NAMESPACE}-bottom`
- }, REaCt().createElement("div", {
- className: `${NAMESPACE}-bottom-control`
- }, REaCt().createElement("div", {
- className: "conversations-category",
- onClick: onArchivedClicked
- }, REaCt().createElement("span", null, l.filter_archived__chats), REaCt().createElement("i", {
- className: "sprite-fm-mono icon-arrow-right"
- })))));
-};
-const Archived = ({
- conversations,
- archivedUnmounting,
- onClose
-}) => {
- const archivedChats = Object.values(conversations || {}).filter(c => !c.isMeeting && c.isArchived()).sort(M.sortObjFn(c => c.lastActivity || c.ctime, -1));
- return REaCt().createElement("div", {
- className: `
- ${NAMESPACE}-archived
- ${archivedUnmounting ? 'with-unmount-animation' : ''}
- `
- }, REaCt().createElement("div", {
- className: `${NAMESPACE}-archived-head`
- }, REaCt().createElement(meetings_button.A, {
- className: "mega-button round",
- icon: "sprite-fm-mono icon-arrow-left-regular-outline",
- onClick: onClose
- }), REaCt().createElement("h2", null, l.filter_archived__chats)), REaCt().createElement("div", {
- className: `${NAMESPACE}-archived-content`
- }, archivedChats && archivedChats.length ? REaCt().createElement(ConversationsList, {
- conversations: archivedChats
- }) : REaCt().createElement("div", {
- className: `${NAMESPACE}-archived-empty`
- }, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-archive"
- }), REaCt().createElement("h3", null, l.filter_archived__nil_chats))));
-};
-class Meetings extends mixins.w9 {
- constructor(props) {
- let _megaChat$getCurrentM;
- super(props);
- this.TABS = {
- UPCOMING: 0x00,
- PAST: 0x01
- };
- this.domRef = REaCt().createRef();
- this.ongoingRef = REaCt().createRef();
- this.navigationRef = REaCt().createRef();
- this.state = {
- tab: this.TABS.UPCOMING
- };
- this.Navigation = ({
- conversations
- }) => {
- const {
- UPCOMING,
- PAST
- } = this.TABS;
- const {
- tab
- } = this.state;
- const unreadMeetings = Object.values(conversations || {}).reduce((acc, curr) => {
- if (curr.isDisplayable() && curr.isMeeting && curr.messagesBuff.getUnreadCount()) {
- let _curr$scheduledMeetin;
- acc[(_curr$scheduledMeetin = curr.scheduledMeeting) != null && _curr$scheduledMeetin.isUpcoming ? UPCOMING : PAST]++;
- }
- return acc;
- }, {
- [UPCOMING]: 0,
- [PAST]: 0
- });
- return REaCt().createElement("div", {
- ref: this.navigationRef,
- className: `
- ${NAMESPACE}-meetings--navigation
- ${this.props.leftPaneWidth < 230 ? 'narrow-width' : ''}
- `
- }, REaCt().createElement(meetings_button.A, {
- converstaions: conversations,
- className: `
- mega-button
- action
- ${tab === UPCOMING ? 'is-active' : ''}
- `,
- onClick: () => this.setState({
- tab: UPCOMING
- })
- }, REaCt().createElement("span", null, l.meetings_tab_upcoming, !!unreadMeetings[UPCOMING] && REaCt().createElement("div", {
- className: "notification-indication"
- }))), REaCt().createElement(meetings_button.A, {
- converstaions: conversations,
- className: `
- mega-button
- action
- ${tab === PAST ? 'is-active' : ''}
- `,
- onClick: () => this.setState({
- tab: PAST
- }, () => eventlog(500254))
- }, REaCt().createElement("span", null, l.meetings_tab_past, !!unreadMeetings[PAST] && REaCt().createElement("div", {
- className: "notification-indication"
- }))));
- };
- this.Holder = ({
- heading,
- className,
- children
- }) => REaCt().createElement("div", {
- className: `
- conversations-holder
- ${className || ''}
- `
- }, REaCt().createElement("div", {
- className: `
- conversations-category
- `
- }, heading && REaCt().createElement("span", null, heading)), children);
- this.Ongoing = ({
- ongoingMeetings
- }) => ongoingMeetings != null && ongoingMeetings.length ? REaCt().createElement("div", {
- ref: this.ongoingRef,
- className: `${NAMESPACE}-meetings--ongoing`
- }, REaCt().createElement("strong", null, l.happening_now), REaCt().createElement(ConversationsList, {
- conversations: ongoingMeetings
- })) : null;
- this.Upcoming = () => {
- const {
- upcomingMeetings,
- nextOccurrences
- } = megaChat.plugins.meetingsManager.filterUpcomingMeetings(this.props.conversations);
- const upcomingItem = chatRoom => REaCt().createElement(ConversationsListItem, {
- key: chatRoom.roomId,
- chatRoom
- });
- return REaCt().createElement(this.Holder, null, upcomingMeetings && upcomingMeetings.length ? REaCt().createElement(ConversationsList, {
- conversations: upcomingMeetings
- }, nextOccurrences.today && nextOccurrences.today.length ? REaCt().createElement("div", {
- className: "conversations-group"
- }, REaCt().createElement("div", {
- className: "conversations-category category--label"
- }, REaCt().createElement("span", null, l.upcoming__today)), nextOccurrences.today.map(upcomingItem)) : null, nextOccurrences.tomorrow && nextOccurrences.tomorrow.length ? REaCt().createElement("div", {
- className: "conversations-group"
- }, REaCt().createElement("div", {
- className: "conversations-category category--label"
- }, REaCt().createElement("span", null, l.upcoming__tomorrow)), nextOccurrences.tomorrow.map(upcomingItem)) : null, Object.keys(nextOccurrences.rest).length ? Object.keys(nextOccurrences.rest).map(date => REaCt().createElement("div", {
- key: date,
- className: "conversations-group"
- }, REaCt().createElement("div", {
- className: "conversations-category category--label"
- }, REaCt().createElement("span", null, date)), nextOccurrences.rest[date].map(upcomingItem))) : null) : REaCt().createElement("div", {
- className: `${NAMESPACE}-nil`
- }, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-calendar-plus-thin-solid"
- }), REaCt().createElement("span", null, l.meetings_upcoming_nil)));
- };
- this.Past = () => {
- const conversations = Object.values(this.props.conversations || {});
- const pastMeetings = conversations.filter(c => {
- const {
- isCanceled,
- isPast,
- isCompleted
- } = c.scheduledMeeting || {};
- return c.isMeeting && c.isDisplayable() && (!c.scheduledMeeting || isCanceled || isPast || isCompleted) && !c.havePendingCall();
- }).sort(M.sortObjFn(c => c.lastActivity || c.ctime, -1));
- const archivedMeetings = conversations.filter(c => c.isMeeting && c.isArchived()).sort(M.sortObjFn(c => c.lastActivity || c.ctime, -1));
- return REaCt().createElement(this.Holder, null, REaCt().createElement(ConversationsList, {
- conversations: pastMeetings
- }, pastMeetings.length ? pastMeetings.map(chatRoom => chatRoom.roomId && REaCt().createElement(ConversationsListItem, {
- key: chatRoom.roomId,
- chatRoom
- })) : REaCt().createElement("div", {
- className: `
- ${NAMESPACE}-nil
- ${archivedMeetings.length ? 'half-sized' : ''}
- `
- }, archivedMeetings.length ? REaCt().createElement("strong", null, l.meetings_past_nil_heading) : null, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-video-thin-solid"
- }), REaCt().createElement("span", null, l.meetings_past_nil)), archivedMeetings.length ? REaCt().createElement(REaCt().Fragment, null, REaCt().createElement("div", {
- className: "archived-separator"
- }), REaCt().createElement("div", {
- className: "conversations-category category--label"
- }, REaCt().createElement("span", null, l.meetings_label_archived)), archivedMeetings.map(chatRoom => chatRoom.roomId && REaCt().createElement(ConversationsListItem, {
- key: chatRoom.roomId,
- chatRoom
- }))) : null));
- };
- this.getContainerStyles = ongoingMeetings => {
- if (ongoingMeetings != null && ongoingMeetings.length) {
- let _this$ongoingRef, _this$navigationRef;
- const ongoingHeight = (_this$ongoingRef = this.ongoingRef) == null || (_this$ongoingRef = _this$ongoingRef.current) == null ? void 0 : _this$ongoingRef.clientHeight;
- const navigationHeight = (_this$navigationRef = this.navigationRef) == null || (_this$navigationRef = _this$navigationRef.current) == null ? void 0 : _this$navigationRef.clientHeight;
- return {
- style: {
- maxHeight: `calc(100% - ${ongoingHeight + navigationHeight + 30}px)`
- }
- };
- }
- return null;
- };
- this.state.tab = this.TABS[(_megaChat$getCurrentM = megaChat.getCurrentMeeting()) != null && _megaChat$getCurrentM.isPast ? 'PAST' : 'UPCOMING'];
- }
- componentWillUnmount() {
- super.componentWillUnmount();
- megaChat.off(`${megaChat.plugins.meetingsManager.EVENTS.OCCURRENCES_UPDATE}.${this.getUniqueId()}`);
- }
- componentDidMount() {
- super.componentDidMount();
- megaChat.rebind(`${megaChat.plugins.meetingsManager.EVENTS.OCCURRENCES_UPDATE}.${this.getUniqueId()}`, () => this.safeForceUpdate());
- megaChat.rebind(megaChat.plugins.meetingsManager.EVENTS.INITIALIZE, (ev, scheduledMeeting) => this.isMounted() && this.setState({
- tab: this.TABS[scheduledMeeting != null && scheduledMeeting.isPast ? 'PAST' : 'UPCOMING']
- }));
- }
- render() {
- const {
- UPCOMING,
- PAST
- } = this.TABS;
- const {
- tab
- } = this.state;
- const ongoingMeetings = Object.values(this.props.conversations || {}).filter(c => c.isDisplayable() && c.isMeeting && c.havePendingCall());
- return REaCt().createElement("div", {
- ref: this.domRef,
- className: `${NAMESPACE}-meetings`
- }, REaCt().createElement(this.Ongoing, {
- ongoingMeetings
- }), REaCt().createElement(this.Navigation, {
- conversations: this.props.conversations
- }), REaCt().createElement("div", (0,esm_extends.A)({
- className: `
- ${NAMESPACE}-meetings--content
- ${tab === UPCOMING ? 'is-upcoming' : ''}
- ${tab === PAST ? 'is-past' : ''}
- `
- }, this.getContainerStyles(ongoingMeetings)), tab === UPCOMING && REaCt().createElement(this.Upcoming, null), tab === PAST && REaCt().createElement(this.Past, null)));
- }
-}
-// EXTERNAL MODULE: ./js/chat/ui/updateObserver.jsx
-const updateObserver = REQ_(501);
-;// ./js/chat/ui/leftPanel/leftPanel.jsx
-
-
-
-
-
-
-
-
-const NAMESPACE = 'lhp';
-const FILTER = {
- MUTED: 'muted',
- UNREAD: 'unread'
-};
-class LeftPanel extends mixins.w9 {
- constructor(props) {
- super(props);
- this.domRef = REaCt().createRef();
- this.contactRequestsListener = undefined;
- this.fmConfigLeftPaneListener = undefined;
- this.state = {
- leftPaneWidth: Math.min(mega.config.get('leftPaneWidth') | 0, 400) || 384,
- archived: false,
- archivedUnmounting: false,
- filter: '',
- unreadChats: 0,
- unreadMeetings: 0,
- contactRequests: 0
- };
- this.toggleFilter = filter => {
- this.setState(state => ({
- filter: state.filter === filter ? '' : filter
- }), () => {
- Object.values(megaChat.$chatTreePanePs).map(({
- ref
- }) => ref.reinitialise == null ? void 0 : ref.reinitialise());
- });
- };
- this.state.contactRequests = Object.keys(M.ipc).length;
- }
- customIsEventuallyVisible() {
- return M.chat;
- }
- renderLoading() {
- return REaCt().createElement(REaCt().Fragment, null, REaCt().createElement("span", {
- className: "heading loading-sketch"
- }), REaCt().createElement("ul", {
- className: "conversations-pane loading-sketch"
- }, Array.from({
- length: this.props.conversations.length
- }, (el, i) => {
- return REaCt().createElement("li", {
- key: i
- }, REaCt().createElement("div", {
- className: "conversation-avatar"
- }, REaCt().createElement("div", {
- className: "chat-topic-icon"
- })), REaCt().createElement("div", {
- className: "conversation-data"
- }, REaCt().createElement("div", {
- className: "conversation-data-top"
- }), REaCt().createElement("div", {
- className: "conversation-message-info"
- }, REaCt().createElement("div", {
- className: "conversation-message"
- }))));
- })));
- }
- componentWillUnmount() {
- super.componentWillUnmount();
- megaChat.unbind(`onUnreadCountUpdate.${NAMESPACE}`);
- mBroadcaster.removeListener(this.contactRequestsListener);
- mBroadcaster.removeListener(this.fmConfigLeftPaneListener);
- }
- componentDidMount() {
- let _$$leftPaneResizable;
- super.componentDidMount();
- megaChat.rebind(`onUnreadCountUpdate.${NAMESPACE}`, (ev, {
- unreadChats,
- unreadMeetings
- }) => {
- this.setState({
- unreadChats,
- unreadMeetings
- }, () => this.safeForceUpdate());
- });
- this.contactRequestsListener = mBroadcaster.addListener('fmViewUpdate:ipc', () => this.setState({
- contactRequests: Object.keys(M.ipc).length
- }));
- $.leftPaneResizableChat = new FMResizablePane(this.domRef.current, {
- ...(_$$leftPaneResizable = $.leftPaneResizable) == null ? void 0 : _$$leftPaneResizable.options,
- minWidth: mega.flags.ab_ads ? 260 : 200
- });
- this.fmConfigLeftPaneListener = mBroadcaster.addListener('fmconfig:leftPaneWidth', value => this.setState(state => ({
- leftPaneWidth: value || state.leftPaneWidth
- })));
- }
- render() {
- const {
- view,
- views,
- conversations,
- routingSection,
- renderView,
- startMeeting,
- scheduleMeeting,
- createNewChat
- } = this.props;
- const {
- CHATS,
- MEETINGS,
- LOADING
- } = views;
- return REaCt().createElement("div", (0,esm_extends.A)({
- ref: this.domRef,
- className: `
- fm-left-panel
- chat-lp-body
- ${NAMESPACE}-container
- ${is_chatlink && 'hidden' || ''}
- ${megaChat._joinDialogIsShown && 'hidden' || ''}
- `
- }, this.state.leftPaneWidth && {
- width: this.state.leftPaneWidth
- }), REaCt().createElement("div", {
- className: "left-pane-drag-handle"
- }), REaCt().createElement(SearchPanel, null), REaCt().createElement(Navigation, {
- view,
- views,
- routingSection,
- unreadChats: this.state.unreadChats,
- unreadMeetings: this.state.unreadMeetings,
- contactRequests: this.state.contactRequests,
- renderView: view => this.setState({
- filter: false
- }, () => renderView(view))
- }), REaCt().createElement(actions, {
- view,
- views,
- filter: this.state.filter,
- routingSection,
- startMeeting,
- scheduleMeeting,
- createNewChat,
- onFilter: this.toggleFilter
- }), this.state.archived && REaCt().createElement(Archived, {
- conversations,
- archivedUnmounting: this.state.archivedUnmounting,
- onClose: () => this.setState({
- archivedUnmounting: true
- }, () => tSleep(0.3).then(() => this.setState({
- archivedUnmounting: false,
- archived: false
- })))
- }), REaCt().createElement("div", {
- className: `
- ${NAMESPACE}-conversations
- ${view === MEETINGS ? 'meetings-view' : ''}
- ${view === CHATS ? 'chats-view' : ''}
- conversations
- content-panel
- active
- `
- }, view === LOADING ? this.renderLoading() : REaCt().createElement(REaCt().Fragment, null, view === MEETINGS && REaCt().createElement(Meetings, {
- conversations,
- leftPaneWidth: this.state.leftPaneWidth
- }), view === CHATS && REaCt().createElement(Chats, {
- conversations,
- filter: this.state.filter,
- onArchivedClicked: () => this.setState({
- archived: true,
- filter: false
- })
- }))));
- }
-}
-const leftPanel = (0,mixins.Zz)(updateObserver.Y)(LeftPanel);
-;// ./js/chat/ui/meetings/workflow/freeCallEnded.jsx
-
-
-const freeCallEnded_NAMESPACE = 'free-call-ended-dlg';
-class FreeCallEnded extends REaCt().Component {
- constructor(...args) {
- super(...args);
- this.domRef = REaCt().createRef();
- }
- componentWillUnmount() {
- if ($.dialog === freeCallEnded_NAMESPACE) {
- closeDialog();
- }
- }
- componentDidMount() {
- M.safeShowDialog(freeCallEnded_NAMESPACE, () => {
- if (!this.domRef.current) {
- throw new Error(`${freeCallEnded_NAMESPACE} dialog: component ${freeCallEnded_NAMESPACE} not mounted.`);
- }
- eventlog(500295);
- return $(`#${freeCallEnded_NAMESPACE}`);
- });
- }
- render() {
- const {
- onClose
- } = this.props;
- return REaCt().createElement(modalDialogs.A.ModalDialog, {
- id: freeCallEnded_NAMESPACE,
- ref: this.domRef,
- className: "mega-dialog",
- dialogType: "action",
- dialogName: freeCallEnded_NAMESPACE,
- onClose
- }, REaCt().createElement("header", null, REaCt().createElement("div", {
- className: "free-call-ended graphic"
- }, REaCt().createElement("img", {
- src: `${staticpath}images/mega/chat-upgrade-rocket.png`
- }))), REaCt().createElement("section", {
- className: "content"
- }, REaCt().createElement("div", {
- className: "content-block"
- }, REaCt().createElement("div", {
- className: "dialog-body-text"
- }, REaCt().createElement("h3", null, l.free_call_ended_dlg_text), REaCt().createElement("span", null, l.free_call_ended_dlg_subtext)))), REaCt().createElement("footer", null, REaCt().createElement("div", {
- className: "footer-container"
- }, REaCt().createElement("button", {
- className: "mega-button positive large",
- onClick: () => {
- loadSubPage('pro');
- eventlog(500261);
- onClose();
- }
- }, REaCt().createElement("span", null, l.upgrade_now)))));
- }
-}
-;// ./js/chat/ui/contactSelectorDialog.jsx
-
-
-
-
-class ContactSelectorDialog extends mixins.w9 {
- constructor(...args) {
- super(...args);
- this.dialogName = 'contact-selector-dialog';
- }
- componentDidMount() {
- super.componentDidMount();
- M.safeShowDialog(this.dialogName, () => $(`.${this.dialogName}`));
- }
- componentWillUnmount() {
- super.componentWillUnmount();
- if ($.dialog === this.dialogName) {
- closeDialog();
- }
- }
- render() {
- const {
- active,
- selectFooter,
- exclude,
- allowEmpty,
- multiple,
- topButtons,
- showAddContact,
- className,
- multipleSelectedButtonLabel,
- singleSelectedButtonLabel,
- nothingSelectedButtonLabel,
- onClose,
- onSelectDone
- } = this.props;
- return REaCt().createElement(modalDialogs.A.ModalDialog, {
- className: `
- popup
- contacts-search
- ${className}
- ${this.dialogName}
- `,
- onClose
- }, REaCt().createElement(ui_contacts.ContactPickerWidget, {
- active,
- className: "popup contacts-search small-footer",
- contacts: M.u,
- selectFooter,
- megaChat,
- withSelfNote: megaChat.WITH_SELF_NOTE,
- exclude,
- allowEmpty,
- multiple,
- topButtons,
- showAddContact,
- multipleSelectedButtonLabel,
- singleSelectedButtonLabel,
- nothingSelectedButtonLabel,
- onClose,
- onAddContact: () => {
- eventlog(500237);
- onClose();
- },
- onSelected: () => {
- eventlog(500238);
- onClose();
- },
- onSelectDone
- }));
- }
-}
-window.ContactSelectorDialogUI = {
- ContactSelectorDialog
-};
-const ui_contactSelectorDialog = ContactSelectorDialog;
-;// ./js/chat/ui/conversations.jsx
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-const VIEWS = {
- CHATS: 0x00,
- MEETINGS: 0x01,
- LOADING: 0x02
-};
-const conversations_EVENTS = {
- NAV_RENDER_VIEW: 'navRenderView'
-};
-window.convAppConstants = {
- VIEWS,
- EVENTS: conversations_EVENTS
-};
-class ConversationsApp extends mixins.w9 {
- constructor(props) {
- super(props);
- this.domRef = REaCt().createRef();
- this.chatRoomRef = null;
- this.occurrenceRef = null;
- this.state = {
- startGroupChatDialog: false,
- startMeetingDialog: false,
- scheduleMeetingDialog: false,
- scheduleOccurrenceDialog: false,
- freeCallEndedDialog: false,
- contactSelectorDialog: false,
- view: VIEWS.LOADING,
- callExpanded: false,
- ipcData: null
- };
- this._cacheRouting();
- megaChat.rebind('onStartNewMeeting.convApp', () => this.startMeeting());
- }
- startMeeting() {
- if (megaChat.hasSupportForCalls) {
- return (0,call.dQ)().then(() => this.setState({
- startMeetingDialog: true
- })).catch(() => d && console.warn('Already in a call.'));
- }
- return showToast('warning', l[7211]);
- }
- _cacheRouting() {
- this.routingSection = this.props.megaChat.routingSection;
- this.routingSubSection = this.props.megaChat.routingSubSection;
- this.routingParams = this.props.megaChat.routingParams;
- }
- hasOpenDialog() {
- return [...document.querySelectorAll('.mega-dialog')].some(dialog => !!(dialog.offsetParent || dialog.offsetWidth || dialog.offsetHeight));
- }
- specShouldComponentUpdate() {
- if (this.routingSection !== this.props.megaChat.routingSection || this.routingSubSection !== this.props.megaChat.routingSubSection || this.routingParams !== this.props.megaChat.routingParams) {
- this._cacheRouting();
- return true;
- }
- }
- componentDidMount() {
- super.componentDidMount();
- $(document).rebind('keydown.megaChatTextAreaFocus', e => {
- if (!M.chat || e.megaChatHandled) {
- return;
- }
- const {
- currentlyOpenedChat
- } = megaChat;
- const currentRoom = megaChat.getCurrentRoom();
- if (currentlyOpenedChat) {
- if (currentRoom && currentRoom.isReadOnly() || $(e.target).is(".messages-textarea, input, textarea") || (e.ctrlKey || e.metaKey || e.which === 19) && e.keyCode === 67 || e.keyCode === 91 || e.keyCode === 17 || e.keyCode === 27 || e.altKey || e.metaKey || e.ctrlKey || e.shiftKey || this.hasOpenDialog() || document.querySelector('textarea:focus,select:focus,input:focus')) {
- return;
- }
- const $typeArea = $('.messages-textarea:visible:first');
- moveCursortoToEnd($typeArea);
- e.megaChatHandled = true;
- $typeArea.triggerHandler(e);
- e.preventDefault();
- e.stopPropagation();
- return false;
- }
- });
- $(document).rebind('mouseup.megaChatTextAreaFocus', e => {
- if (!M.chat || e.megaChatHandled || slideshowid) {
- return;
- }
- const $target = $(e.target);
- if (megaChat.currentlyOpenedChat) {
- if ($target.is(".messages-textarea,a,input,textarea,select,button") || $target.is('i') && $target.parent().is('a,input,select,button') || $target.closest('.messages.scroll-area').length > 0 || $target.closest('.mega-dialog').length > 0 || this.hasOpenDialog() || document.querySelector('textarea:focus,select:focus,input:focus') || window.getSelection().toString()) {
- return;
- }
- const $typeArea = $('.messages-textarea:visible:first');
- if ($typeArea.length === 1 && !$typeArea.is(":focus")) {
- $typeArea.trigger("focus");
- e.megaChatHandled = true;
- }
- }
- });
- megaChat.rebind(megaChat.plugins.meetingsManager.EVENTS.EDIT, (ev, chatOrOccurrence) => {
- if (chatOrOccurrence instanceof ChatRoom || !chatOrOccurrence) {
- this.chatRoomRef = chatOrOccurrence;
- this.setState({
- scheduleMeetingDialog: true
- });
- } else {
- this.occurrenceRef = chatOrOccurrence;
- this.setState({
- scheduleOccurrenceDialog: true
- });
- }
- });
- megaChat.rebind(conversations_EVENTS.NAV_RENDER_VIEW, ({
- data
- }) => {
- if (Object.values(VIEWS).includes(data)) {
- this.renderView(data);
- }
- });
- megaChat.rebind('onCallTimeLimitExceeded', () => {
- this.setState({
- freeCallEndedDialog: true
- });
- });
- if (megaChat.WITH_SELF_NOTE && !megaChat.getNoteChat() && !is_chatlink) {
- api.req({
- a: 'mcc',
- u: [],
- m: 0,
- g: 0,
- v: Chatd.VERSION
- }).catch(dump);
- }
- this.requestReceivedListener = mBroadcaster.addListener('fmViewUpdate:ipc', () => {
- this.setState({
- ipcData: this.makeIpcData()
- });
- });
- this.setState({
- ipcData: this.makeIpcData()
- });
- }
- componentWillUnmount() {
- super.componentWillUnmount();
- $(document).off('keydown.megaChatTextAreaFocus');
- mBroadcaster.removeListener('fmViewUpdate:ipc', this.requestReceivedListener);
- }
- componentDidUpdate(prevProps, prevState) {
- this.handleOnboardingStep();
- const {
- names: prevNames
- } = prevState.ipcData;
- const newIpcData = this.makeIpcData();
- const {
- names: newNames
- } = newIpcData;
- if (newNames.size !== prevNames.size) {
- this.setState({
- ipcData: newIpcData
- });
- return;
- }
- let different = false;
- for (const [email, name] of newNames) {
- if (!prevNames.has(email) || prevNames.get(email) !== name) {
- different = true;
- break;
- }
- }
- if (different) {
- this.setState({
- ipcData: newIpcData
- });
- }
- }
- handleOnboardingStep() {
- if (this.state.view === VIEWS.LOADING) {
- return;
- }
- megaChat.plugins.chatOnboarding.checkAndShowStep();
- }
- renderView(view) {
- this.setState({
- view
- }, () => {
- const {
- $chatTreePanePs,
- routingSection,
- currentlyOpenedChat
- } = megaChat;
- Object.values($chatTreePanePs).forEach(ref => ref.reinitialise == null ? void 0 : ref.reinitialise());
- if (routingSection !== 'chat') {
- loadSubPage('fm/chat');
- }
- megaChat.currentlyOpenedView = view;
- if (!currentlyOpenedChat) {
- megaChat.renderListing(null, false).catch(dump);
- }
- });
- }
- makeIpcData() {
- let mixed = false;
- const names = new Map();
- const data = Object.values(M.ipc).reduce((acc, curr) => {
- const name = M.getNameByEmail(curr.m);
- if (name !== curr.m) {
- names.set(curr.m, name);
- mixed = true;
- }
- return {
- ...acc,
- [curr.p]: {
- ...curr,
- name
- }
- };
- }, Object.create(null));
- return {
- mixed,
- data,
- names
- };
- }
- render() {
- const {
- CHATS,
- MEETINGS
- } = VIEWS;
- const {
- routingSection,
- chatUIFlags,
- currentlyOpenedChat,
- chats
- } = megaChat;
- const {
- view,
- startGroupChatDialog,
- startMeetingDialog,
- scheduleMeetingDialog,
- scheduleOccurrenceDialog,
- callExpanded,
- freeCallEndedDialog,
- contactSelectorDialog
- } = this.state;
- const isEmpty = chats && routingSection === 'chat' && !currentlyOpenedChat && !is_chatlink;
- const isLoading = !currentlyOpenedChat && megaChat.allChatsHadInitialLoadedHistory() === false && routingSection !== 'contacts';
- const rightPane = REaCt().createElement("div", {
- className: `
- fm-right-files-block
- in-chat
- ${is_chatlink ? 'chatlink' : ''}
- `
- }, !isLoading && REaCt().createElement(chatToaster.A, {
- isRootToaster: true
- }), !isLoading && routingSection === 'contacts' && REaCt().createElement(contactsPanel.A, {
- megaChat,
- contacts: M.u,
- received: this.state.ipcData,
- sent: M.opc
- }), !isLoading && routingSection === 'notFound' && REaCt().createElement("span", null, REaCt().createElement("center", null, "Section not found")), !isLoading && isEmpty && REaCt().createElement(conversationpanel.Yk, {
- isMeeting: view === MEETINGS,
- onNewChat: () => this.setState({
- contactSelectorDialog: true
- }),
- onStartMeeting: () => this.startMeeting(),
- onScheduleMeeting: () => this.setState({
- scheduleMeetingDialog: true
- })
- }), !isLoading && REaCt().createElement(conversationpanel.$h, (0,esm_extends.A)({}, this.props, {
- className: routingSection === 'chat' ? '' : 'hidden',
- routingSection,
- currentlyOpenedChat,
- isEmpty,
- chatUIFlags,
- onToggleExpandedFlag: () => this.setState(() => ({
- callExpanded: call.Ay.isExpanded()
- })),
- onMount: () => {
- const chatRoom = megaChat.getCurrentRoom();
- const view = chatRoom && chatRoom.isMeeting ? MEETINGS : CHATS;
- this.setState({
- view
- }, () => {
- megaChat.currentlyOpenedView = view;
- });
- }
- })));
- const noteChat = megaChat.getNoteChat();
- return REaCt().createElement("div", {
- ref: this.domRef,
- className: "conversationsApp"
- }, contactSelectorDialog && REaCt().createElement(ui_contactSelectorDialog, {
- className: `main-start-chat-dropdown ${leftPanel.NAMESPACE}-contact-selector`,
- multiple: false,
- topButtons: [{
- key: 'newGroupChat',
- title: l[19483],
- className: 'positive',
- onClick: () => this.setState({
- startGroupChatDialog: true,
- contactSelectorDialog: false
- })
- }, ...megaChat.WITH_SELF_NOTE ? contactsPanel.A.hasContacts() || noteChat && noteChat.hasMessages() ? [] : [{
- key: 'noteChat',
- title: l.note_label,
- icon: 'sprite-fm-mono icon-file-text-thin-outline note-chat-icon',
- onClick: () => {
- closeDialog();
- loadSubPage(`fm/chat/p/${u_handle}`);
- }
- }] : []],
- showAddContact: contactsPanel.A.hasContacts(),
- onClose: () => this.setState({
- contactSelectorDialog: false
- }),
- onSelectDone: selected => {
- if (selected.length === 1) {
- return megaChat.createAndShowPrivateRoom(selected[0]).then(room => room.setActive());
- }
- megaChat.createAndShowGroupRoomFor(selected);
- }
- }), startGroupChatDialog && REaCt().createElement(StartGroupChatWizard, {
- name: "start-group-chat",
- flowType: 1,
- onClose: () => this.setState({
- startGroupChatDialog: false
- }),
- onConfirmClicked: () => this.setState({
- startGroupChatDialog: false
- })
- }), startMeetingDialog && REaCt().createElement(Start, {
- onStart: (topic, audio, video) => {
- megaChat.createAndStartMeeting(topic, audio, video);
- this.setState({
- startMeetingDialog: false
- });
- },
- onClose: () => this.setState({
- startMeetingDialog: false
- })
- }), scheduleMeetingDialog && REaCt().createElement(Schedule, {
- chatRoom: this.chatRoomRef,
- callExpanded,
- onClose: () => {
- this.setState({
- scheduleMeetingDialog: false
- }, () => {
- this.chatRoomRef = null;
- });
- }
- }), scheduleOccurrenceDialog && REaCt().createElement(Edit, {
- chatRoom: this.occurrenceRef.scheduledMeeting.chatRoom,
- scheduledMeeting: this.occurrenceRef.scheduledMeeting,
- occurrenceId: this.occurrenceRef.uid,
- callExpanded,
- onClose: () => {
- this.setState({
- scheduleOccurrenceDialog: false
- }, () => {
- this.occurrenceRef = null;
- });
- }
- }), freeCallEndedDialog && REaCt().createElement(FreeCallEnded, {
- onClose: () => {
- this.setState({
- freeCallEndedDialog: false
- });
- }
- }), REaCt().createElement(leftPanel, {
- view,
- views: VIEWS,
- routingSection,
- conversations: chats,
- renderView: view => this.renderView(view),
- startMeeting: () => {
- this.startMeeting();
- eventlog(500293);
- },
- scheduleMeeting: () => {
- this.setState({
- scheduleMeetingDialog: true
- });
- delay('chat-event-sm-button-main', () => eventlog(99918));
- },
- createNewChat: () => this.setState({
- contactSelectorDialog: true
- })
- }), rightPane);
- }
-}
-if (false) // removed by dead control flow
-{}
-const conversations = {
- ConversationsApp
-};
-
-},
-
-691
-(_, EXP_, REQ_) {
-
-"use strict";
-
-// EXPORTS
-REQ_.d(EXP_, {
- nC: () => API,
- kg: () => LABELS,
- Ay: () => GifPanel
-});
-
-// EXTERNAL MODULE: external "React"
-const React_ = REQ_(594);
-const REaCt = REQ_.n(React_);
-// EXTERNAL MODULE: ./js/ui/perfectScrollbar.jsx
-const perfectScrollbar = REQ_(486);
-;// ./js/chat/ui/gifPanel/searchField.jsx
-let _SearchField;
-
-
-class SearchField extends REaCt().Component {
- render() {
- const {
- value,
- searching,
- onChange,
- onReset,
- onBack
- } = this.props;
- return REaCt().createElement("div", {
- className: "gif-panel-search"
- }, REaCt().createElement("div", {
- className: "gif-search-field"
- }, searching ? REaCt().createElement("i", {
- className: "sprite-fm-mono icon-left",
- onClick: onBack
- }) : REaCt().createElement("i", {
- className: "sprite-fm-mono icon-preview-reveal"
- }), REaCt().createElement("input", {
- ref: SearchField.inputRef,
- type: "text",
- placeholder: LABELS.SEARCH,
- autoFocus: true,
- value,
- onChange
- }), searching && REaCt().createElement("i", {
- className: "sprite-fm-mono icon-close-component",
- onClick: onReset
- })), REaCt().createElement("div", {
- className: "giphy-logo"
- }, REaCt().createElement("img", {
- src: `${staticpath }images/mega/giphy.gif`,
- alt: "PWRD BY GIPHY"
- })));
- }
-}
-_SearchField = SearchField;
-SearchField.inputRef = REaCt().createRef();
-SearchField.focus = () => _SearchField.inputRef && _SearchField.inputRef.current && _SearchField.inputRef.current.focus();
-SearchField.hasValue = () => _SearchField.inputRef && _SearchField.inputRef.current && !!_SearchField.inputRef.current.value.length;
-;// ./js/chat/ui/gifPanel/result.jsx
-
-
-class Result extends REaCt().Component {
- constructor(...args) {
- super(...args);
- this.resultRef = REaCt().createRef();
- }
- componentDidMount() {
- let _this$props$onMount, _this$props;
- (_this$props$onMount = (_this$props = this.props).onMount) == null || _this$props$onMount.call(_this$props, this.resultRef.current);
- }
- componentWillUnmount() {
- let _this$props$onUnmount, _this$props2;
- (_this$props$onUnmount = (_this$props2 = this.props).onUnmount) == null || _this$props$onUnmount.call(_this$props2, this.resultRef.current, 'unobserve');
- }
- render() {
- const {
- image,
- title,
- onClick
- } = this.props;
- return REaCt().createElement("div", {
- className: `
- ${NODE_CONTAINER_CLASS}
- ${onClick ? 'clickable' : ''}
- `,
- style: {
- height: parseInt(image.height)
- }
- }, REaCt().createElement("div", {
- ref: this.resultRef,
- className: NODE_CLASS,
- style: {
- backgroundImage: HAS_INTERSECTION_OBSERVER ? '' : `url(${image.url})`
- },
- "data-url": image.url,
- onClick
- }, REaCt().createElement("span", null, title)));
- }
-}
-;// ./js/chat/ui/gifPanel/resultContainer.jsx
-
-
-
-const HAS_INTERSECTION_OBSERVER = typeof IntersectionObserver !== 'undefined';
-const NODE_CONTAINER_CLASS = 'node-container';
-const NODE_CLASS = 'node';
-const RESULT_CONTAINER_CLASS = 'gif-panel-results';
-const RESULTS_END_CLASS = 'results-end';
-const Nil = ({
- children
-}) => REaCt().createElement("div", {
- className: "no-results-container"
-}, REaCt().createElement("div", {
- className: "no-results-content"
-}, REaCt().createElement("i", {
- className: "huge-icon sad-smile"
-}), REaCt().createElement("span", null, children)));
-class ResultContainer extends REaCt().Component {
- constructor(...args) {
- super(...args);
- this.intersectionObserver = null;
- this.initializeIntersectionObserver = () => {
- if (HAS_INTERSECTION_OBSERVER) {
- this.intersectionObserver = new IntersectionObserver(entries => {
- for (let i = 0; i < entries.length; i++) {
- var _target$classList, _target$classList2;
- const entry = entries[i];
- const {target} = entry;
- if ((_target$classList = target.classList) != null && _target$classList.contains(NODE_CLASS)) {
- target.style.backgroundImage = entry.isIntersecting ? `url(${target.dataset.url})` : null;
- }
- if (entry.isIntersecting && (_target$classList2 = target.classList) != null && _target$classList2.contains(RESULTS_END_CLASS)) {
- this.props.onPaginate();
- }
- }
- });
- }
- };
- this.toggleIntersectionObserver = (node, action = 'observe') => {
- if (node && this.intersectionObserver) {
- this.intersectionObserver[action](node);
- }
- };
- }
- componentDidMount() {
- this.initializeIntersectionObserver();
- }
- componentWillUnmount() {
- if (this.intersectionObserver) {
- this.intersectionObserver.disconnect();
- this.intersectionObserver = null;
- }
- }
- render() {
- const {
- loading,
- results,
- bottom,
- unavailable,
- onClick
- } = this.props;
- if (unavailable) {
- return REaCt().createElement(Nil, null, LABELS.NOT_AVAILABLE);
- }
- if (loading && results.length < 1) {
- return REaCt().createElement("div", {
- className: RESULT_CONTAINER_CLASS
- }, Array.from({
- length: API.LIMIT
- }, (element, index) => REaCt().createElement("div", {
- key: index,
- className: NODE_CONTAINER_CLASS
- }, REaCt().createElement("div", {
- className: NODE_CLASS,
- style: {
- height: Math.floor(Math.random() * 150) + 100
- }
- }))));
- }
- if (!loading && results.length < 1) {
- return REaCt().createElement(Nil, null, LABELS.NO_RESULTS);
- }
- if (results.length) {
- return REaCt().createElement(REaCt().Fragment, null, REaCt().createElement("div", {
- className: RESULT_CONTAINER_CLASS
- }, results.map(({
- slug,
- images: {
- fixed_width_downsampled
- },
- title
- }, index) => {
- return REaCt().createElement(Result, {
- key: `${slug}--${index}`,
- image: fixed_width_downsampled,
- title,
- onClick: () => onClick(results[index]),
- onMount: this.toggleIntersectionObserver,
- onUnmount: this.toggleIntersectionObserver
- });
- })), REaCt().createElement("div", {
- className: RESULTS_END_CLASS,
- ref: node => this.toggleIntersectionObserver(node),
- style: {
- visibility: bottom ? 'visible' : 'hidden'
- }
- }, REaCt().createElement("img", {
- className: "emoji",
- alt: "\\ud83d\\ude10",
- src: `${staticpath}/images/mega/twemojis/2_v2/72x72/1f610.png`
- }), REaCt().createElement("strong", null, LABELS.END_OF_RESULTS)));
- }
- return null;
- }
-}
-;// ./js/chat/ui/gifPanel/gifPanel.jsx
-
-
-
-
-const GIF_PANEL_CLASS = 'gif-panel-wrapper';
-const MAX_HEIGHT = 550;
-const API = {
- HOSTNAME: 'https://giphy.mega.nz/',
- ENDPOINT: 'v1/gifs',
- SCHEME: 'giphy://',
- convert: path => {
- if (path && typeof path === 'string') {
- const FORMAT = [API.SCHEME, API.HOSTNAME];
- if (path.indexOf(API.SCHEME) === 0 || path.indexOf(API.HOSTNAME) === 0) {
- return String.prototype.replace.apply(path, path.indexOf(API.SCHEME) === 0 ? FORMAT : FORMAT.reverse());
- }
- }
- },
- LIMIT: 50,
- OFFSET: 50
-};
-const LABELS = freeze({
- get SEARCH() {
- return l[24025];
- },
- get NO_RESULTS() {
- return l[24050];
- },
- get NOT_AVAILABLE() {
- return l[24512];
- },
- get END_OF_RESULTS() {
- return l[24156];
- }
-});
-class GifPanel extends REaCt().Component {
- constructor(...args) {
- super(...args);
- this.domRef = REaCt().createRef();
- this.pathRef = '';
- this.controllerRef = null;
- this.fetchRef = null;
- this.delayProcID = null;
- this.defaultState = {
- value: '',
- searching: false,
- results: [],
- loading: true,
- offset: 0,
- bottom: false,
- unavailable: false
- };
- this.state = {
- ...this.defaultState
- };
- this.getContainerHeight = () => window.innerHeight * 0.6 > MAX_HEIGHT ? MAX_HEIGHT : window.innerHeight * 0.6;
- this.getFormattedPath = path => {
- const PATH = path + (path.indexOf('?') === -1 ? '?' : '&');
- const LIMIT = `limit=${API.LIMIT}`;
- return `${API.HOSTNAME + API.ENDPOINT}/${PATH + LIMIT}`;
- };
- this.clickedOutsideComponent = ev => {
- const $target = ev && $(ev.target);
- return $target.parents(`.${GIF_PANEL_CLASS}`).length === 0 && ['.small-icon.tiny-reset', '.small-icon.gif'].every(outsideElement => !$target.is(outsideElement));
- };
- this.bindEvents = () => {
- $(document).rebind('mousedown.gifPanel', ev => {
- if (this.clickedOutsideComponent(ev)) {
- this.props.onToggle();
- }
- }).rebind('keydown.gifPanel', ({
- keyCode
- }) => {
- if (keyCode && keyCode === 27) {
- return SearchField.hasValue() ? this.doReset() : this.props.onToggle();
- }
- });
- };
- this.unbindEvents = () => {
- if (this.delayProcID) {
- delay.cancel(this.delayProcID);
- }
- $(document).unbind('.gifPanel');
- };
- this.doFetch = path => {
- this.setState({
- loading: true,
- unavailable: false
- }, () => {
- this.pathRef = path;
- this.controllerRef = typeof AbortController === 'function' && new AbortController();
- this.fetchRef = fetch(this.getFormattedPath(path), {
- signal: this.controllerRef.signal
- }).then(response => response.json()).then(({
- data
- }) => {
- this.fetchRef = this.pathRef = null;
- if (this.domRef.current) {
- if (data && data.length) {
- return this.setState(state => ({
- results: [...state.results, ...data],
- loading: false
- }));
- }
- return this.setState({
- bottom: true,
- loading: false
- }, () => this.resultContainerRef && this.resultContainerRef.reinitialise());
- }
- }).catch(ex => {
- return ex.name === 'AbortError' ? null : this.setState({
- unavailable: true
- });
- });
- });
- };
- this.doPaginate = () => {
- const {
- value,
- loading,
- searching
- } = this.state;
- if (!loading) {
- this.setState(state => ({
- offset: state.offset + API.OFFSET
- }), () => {
- this.doFetch(searching ? `search?q=${escape(value)}&offset=${this.state.offset}` : `trending?offset=${this.state.offset}`);
- });
- }
- };
- this.doReset = () => {
- this.setState({
- ...this.defaultState
- }, () => {
- this.doFetch('trending');
- onIdle(() => SearchField.focus());
- this.resultContainerRef.scrollToY(0);
- });
- };
- this.handleChange = ev => {
- const {
- value
- } = ev.target;
- const searching = value.length >= 2;
- if (value.length === 0) {
- return this.doReset();
- }
- if (this.fetchRef !== null && this.pathRef === 'trending' && this.controllerRef) {
- this.controllerRef.abort();
- this.fetchRef = this.pathRef = null;
- }
- this.setState(state => ({
- ...this.defaultState,
- value,
- searching,
- results: searching ? [] : state.results
- }), () => {
- this.resultContainerRef.scrollToY(0);
- this.delayProcID = searching ? delay('gif-search', () => this.doFetch(`search?q=${escape(value)}`), 1600) : null;
- });
- };
- this.handleBack = () => this.doReset();
- this.doSend = result => {
- const {
- mp4,
- webp,
- mp4_size,
- webp_size,
- width,
- height
- } = result.images.fixed_height;
- const message = Message.MANAGEMENT_MESSAGE_TYPES.MANAGEMENT + Message.MANAGEMENT_MESSAGE_TYPES.CONTAINS_META + Message.MESSAGE_META_TYPE.GIPHY + JSON.stringify({
- textMessage: result.title,
- src: API.convert(mp4),
- src_webp: API.convert(webp),
- s: mp4_size,
- s_webp: webp_size,
- w: width,
- h: height
- });
- this.props.chatRoom.sendMessage(message);
- this.props.onToggle();
- };
- }
- componentDidMount() {
- if (this.state.results && this.state.results.length === 0) {
- this.doFetch('trending');
- }
- this.bindEvents();
- }
- componentWillUnmount() {
- this.unbindEvents();
- }
- render() {
- const {
- value,
- searching,
- results,
- loading,
- bottom,
- unavailable
- } = this.state;
- return REaCt().createElement("div", {
- ref: this.domRef,
- className: "gif-panel-wrapper"
- }, REaCt().createElement("div", {
- className: "gif-panel",
- style: {
- height: this.getContainerHeight()
- }
- }, REaCt().createElement("div", {
- className: "gif-panel-header"
- }, REaCt().createElement(SearchField, {
- value,
- searching,
- onChange: this.handleChange,
- onReset: this.doReset,
- onBack: this.handleBack
- })), REaCt().createElement("div", {
- className: "gif-panel-content"
- }, REaCt().createElement(perfectScrollbar.O, {
- ref: container => {
- this.resultContainerRef = container;
- },
- options: {
- 'suppressScrollX': true
- }
- }, REaCt().createElement(ResultContainer, {
- results,
- loading,
- bottom,
- unavailable,
- onPaginate: this.doPaginate,
- onClick: this.doSend
- })))));
- }
-}
-
-},
-
-814
-(_, EXP_, REQ_) {
-
-"use strict";
-
-// EXPORTS
-REQ_.d(EXP_, {
- A: () => HistoryPanel
-});
-
-// EXTERNAL MODULE: ./node_modules/@babel/runtime/helpers/esm/applyDecoratedDescriptor.js
-const applyDecoratedDescriptor = REQ_(793);
-// EXTERNAL MODULE: external "React"
-const React_ = REQ_(594);
-const REaCt = REQ_.n(React_);
-// EXTERNAL MODULE: ./js/chat/mixins.js
-const mixins = REQ_(137);
-// EXTERNAL MODULE: ./js/ui/utils.jsx
-const utils = REQ_(314);
-;// ./js/chat/ui/messages/alterParticipants.jsx
-const React = REQ_(594);
-const ContactsUI = REQ_(251);
-const ConversationMessageMixin = REQ_(446).M;
-
-class AltPartsConvMessage extends ConversationMessageMixin {
- haveMoreContactListeners() {
- if (!this.props.message || !this.props.message.meta) {
- return false;
- }
- const {
- included,
- excluded
- } = this.props.message.meta;
- return array.unique([...included || [], ...excluded || []]);
- }
- render() {
- const self = this;
- const {message} = this.props;
- const contact = self.getContact();
- const timestampInt = self.getTimestamp();
- const timestamp = self.getTimestampAsString();
- const datetime = React.createElement("div", {
- className: "message date-time simpletip",
- "data-simpletip": time2date(timestampInt, 17)
- }, timestamp);
- let displayName;
- if (contact) {
- displayName = M.getNameByHandle(contact.u);
- } else {
- displayName = contact;
- }
- const messages = [];
- message.meta.included.forEach((h) => {
- const otherContact = M.u[h] ? M.u[h] : {
- 'u': h,
- h,
- 'c': 0
- };
- const avatar = React.createElement(ContactsUI.Avatar, {
- contact: otherContact,
- chatRoom: self.props.chatRoom,
- className: "message avatar-wrapper small-rounded-avatar"
- });
- const otherDisplayName = M.getNameByHandle(otherContact.u);
- const isSelfJoin = h === contact.u;
- let text = isSelfJoin ? l[23756] : l[8907];
- if (self.props.chatRoom.isMeeting) {
- text = isSelfJoin ? l.meeting_mgmt_user_joined : l.meeting_mgmt_user_added;
- }
- text = text.replace('%1', megaChat.html(otherDisplayName));
- if (!isSelfJoin) {
- text = text.replace('%2', `${megaChat.html(displayName)}`);
- }
- messages.push(React.createElement("div", {
- className: "message body",
- "data-id": `id${ message.messageId}`,
- key: `${message.messageId }_${ h}`
- }, avatar, React.createElement("div", {
- className: "message content-area small-info-txt selectable-txt"
- }, React.createElement(ContactsUI.ContactButton, {
- className: "message",
- contact: otherContact,
- chatRoom: self.props.chatRoom,
- label: React.createElement(utils.zT, null, otherDisplayName)
- }), datetime, React.createElement("div", {
- className: "message text-block"
- }, React.createElement(utils.P9, null, text)))));
- });
- message.meta.excluded.forEach((h) => {
- const otherContact = M.u[h] ? M.u[h] : {
- 'u': h,
- h,
- 'c': 0
- };
- const avatar = React.createElement(ContactsUI.Avatar, {
- contact: otherContact,
- chatRoom: self.props.chatRoom,
- className: "message avatar-wrapper small-rounded-avatar"
- });
- const otherDisplayName = M.getNameByHandle(otherContact.u);
- let text;
- if (otherContact.u === contact.u) {
- text = self.props.chatRoom.isMeeting ? l.meeting_mgmt_left : l[8908];
- } else {
- text = (self.props.chatRoom.isMeeting ? l.meeting_mgmt_kicked : l[8906]).replace("%s", `${megaChat.html(displayName)}`);
- }
- messages.push(React.createElement("div", {
- className: "message body",
- "data-id": `id${ message.messageId}`,
- key: `${message.messageId }_${ h}`
- }, avatar, React.createElement("div", {
- className: "message content-area small-info-txt selectable-txt"
- }, React.createElement(ContactsUI.ContactButton, {
- className: "message",
- chatRoom: self.props.chatRoom,
- contact: otherContact,
- label: React.createElement(utils.zT, null, otherDisplayName)
- }), datetime, React.createElement("div", {
- className: "message text-block"
- }, React.createElement(utils.P9, null, text)))));
- });
- return React.createElement("div", null, messages);
- }
-}
-
-;// ./js/chat/ui/messages/truncated.jsx
-const truncated_React = REQ_(594);
-const truncated_ContactsUI = REQ_(251);
-const truncated_ConversationMessageMixin = REQ_(446).M;
-
-class TruncatedMessage extends truncated_ConversationMessageMixin {
- render() {
- const self = this;
- let cssClasses = "message body";
- const {message} = this.props;
- const {chatRoom} = this.props.message;
- const contact = self.getContact();
- const timestampInt = self.getTimestamp();
- const timestamp = self.getTimestampAsString();
- let datetime = truncated_React.createElement("div", {
- className: "message date-time simpletip",
- "data-simpletip": time2date(timestampInt, 17)
- }, timestamp);
- let displayName;
- if (contact) {
- displayName = M.getNameByHandle(contact.u);
- } else {
- displayName = contact;
- }
- let avatar = null;
- if (this.props.grouped) {
- cssClasses += " grouped";
- } else {
- avatar = truncated_React.createElement(truncated_ContactsUI.Avatar, {
- contact,
- className: "message avatar-wrapper small-rounded-avatar",
- chatRoom
- });
- datetime = truncated_React.createElement("div", {
- className: "message date-time simpletip",
- "data-simpletip": time2date(timestampInt, 17)
- }, timestamp);
- }
- return truncated_React.createElement("div", {
- className: cssClasses,
- "data-id": `id${ message.messageId}`,
- key: message.messageId
- }, avatar, truncated_React.createElement("div", {
- className: "message content-area small-info-txt selectable-txt"
- }, truncated_React.createElement(truncated_ContactsUI.ContactButton, {
- contact,
- className: "message",
- label: truncated_React.createElement(utils.zT, null, displayName),
- chatRoom
- }), datetime, truncated_React.createElement("div", {
- className: "message text-block"
- }, l[8905])));
- }
-}
-
-;// ./js/chat/ui/messages/privilegeChange.jsx
-const privilegeChange_React = REQ_(594);
-const privilegeChange_ContactsUI = REQ_(251);
-const privilegeChange_ConversationMessageMixin = REQ_(446).M;
-
-class PrivilegeChange extends privilegeChange_ConversationMessageMixin {
- haveMoreContactListeners() {
- if (!this.props.message.meta || !this.props.message.meta.targetUserId) {
- return false;
- }
- const uid = this.props.message.meta.targetUserId;
- if (uid && M.u[uid]) {
- return uid;
- }
- return false;
- }
- render() {
- const self = this;
- const {message} = this.props;
- const {chatRoom} = this.props.message;
- const contact = self.getContact();
- const timestampInt = self.getTimestamp();
- const timestamp = self.getTimestampAsString();
- const datetime = privilegeChange_React.createElement("div", {
- className: "message date-time simpletip",
- "data-simpletip": time2date(timestampInt, 17)
- }, timestamp);
- let displayName;
- if (contact) {
- displayName = M.getNameByHandle(contact.u);
- } else {
- displayName = contact;
- }
- const messages = [];
- const otherContact = M.u[message.meta.targetUserId] ? M.u[message.meta.targetUserId] : {
- 'u': message.meta.targetUserId,
- 'h': message.meta.targetUserId,
- 'c': 0
- };
- const avatar = privilegeChange_React.createElement(privilegeChange_ContactsUI.Avatar, {
- contact: otherContact,
- className: "message avatar-wrapper small-rounded-avatar",
- chatRoom
- });
- const otherDisplayName = M.getNameByHandle(otherContact.u);
- let newPrivilegeText = "";
- if (message.meta.privilege === 3) {
- newPrivilegeText = l.priv_change_to_op;
- } else if (message.meta.privilege === 2) {
- newPrivilegeText = l.priv_change_to_std;
- } else if (message.meta.privilege === 0) {
- newPrivilegeText = l.priv_change_to_ro;
- }
- const text = newPrivilegeText.replace('[S]', '').replace('[/S]', '').replace('%s', `${megaChat.html(displayName)}`);
- messages.push(privilegeChange_React.createElement("div", {
- className: "message body",
- "data-id": `id${ message.messageId}`,
- key: message.messageId
- }, avatar, privilegeChange_React.createElement("div", {
- className: "message content-area small-info-txt selectable-txt"
- }, privilegeChange_React.createElement(privilegeChange_ContactsUI.ContactButton, {
- className: "message",
- chatRoom: self.props.chatRoom,
- contact: otherContact,
- label: privilegeChange_React.createElement(utils.zT, null, otherDisplayName)
- }), datetime, privilegeChange_React.createElement("div", {
- className: "message text-block"
- }, privilegeChange_React.createElement(utils.P9, null, text)))));
- return privilegeChange_React.createElement("div", null, messages);
- }
-}
-
-;// ./js/chat/ui/messages/topicChange.jsx
-const topicChange_React = REQ_(594);
-const topicChange_ContactsUI = REQ_(251);
-const topicChange_ConversationMessageMixin = REQ_(446).M;
-
-class TopicChange extends topicChange_ConversationMessageMixin {
- render() {
- const self = this;
- const {message} = this.props;
- const {megaChat} = this.props.message.chatRoom;
- const {chatRoom} = this.props.message;
- if (message.meta.isScheduled) {
- return null;
- }
- const contact = self.getContact();
- const timestampInt = self.getTimestamp();
- const timestamp = self.getTimestampAsString();
- const datetime = topicChange_React.createElement("div", {
- className: "message date-time simpletip",
- "data-simpletip": time2date(timestampInt, 17)
- }, timestamp);
- let displayName;
- if (contact) {
- displayName = M.getNameByHandle(contact.u);
- } else {
- displayName = contact;
- }
- const messages = [];
- const avatar = topicChange_React.createElement(topicChange_ContactsUI.Avatar, {
- contact,
- chatRoom,
- className: "message avatar-wrapper small-rounded-avatar"
- });
- const topic = megaChat.html(message.meta.topic);
- const oldTopic = megaChat.html(message.meta.oldTopic) || '';
- messages.push(topicChange_React.createElement("div", {
- className: "message body",
- "data-id": `id${ message.messageId}`,
- key: message.messageId
- }, avatar, topicChange_React.createElement("div", {
- className: "message content-area small-info-txt selectable-txt"
- }, topicChange_React.createElement(topicChange_ContactsUI.ContactButton, {
- className: "message",
- chatRoom,
- contact,
- label: topicChange_React.createElement(utils.zT, null, displayName)
- }), datetime, topicChange_React.createElement("div", {
- className: "message text-block"
- }, topicChange_React.createElement(utils.P9, null, (chatRoom.scheduledMeeting ? l.schedule_mgmt_title.replace('%1', `${oldTopic}`) : l[9081]).replace('%s', `${topic}`))))));
- return topicChange_React.createElement("div", null, messages);
- }
-}
-
-;// ./js/chat/ui/messages/closeOpenMode.jsx
-const closeOpenMode_React = REQ_(594);
-const closeOpenMode_ContactsUI = REQ_(251);
-const closeOpenMode_ConversationMessageMixin = REQ_(446).M;
-
-class CloseOpenModeMessage extends closeOpenMode_ConversationMessageMixin {
- render() {
- const self = this;
- let cssClasses = "message body";
- const {message} = this.props;
- const contact = self.getContact();
- const timestampInt = self.getTimestamp();
- const timestamp = self.getTimestampAsString();
- let datetime = closeOpenMode_React.createElement("div", {
- className: "message date-time",
- title: time2date(timestampInt)
- }, timestamp);
- let displayName;
- if (contact) {
- displayName = M.getNameByHandle(contact.u);
- } else {
- displayName = contact;
- }
- let avatar = null;
- if (this.props.grouped) {
- cssClasses += " grouped";
- } else {
- avatar = closeOpenMode_React.createElement(closeOpenMode_ContactsUI.Avatar, {
- contact,
- className: "message avatar-wrapper small-rounded-avatar",
- chatRoom: this.props.chatRoom
- });
- datetime = closeOpenMode_React.createElement("div", {
- className: "message date-time",
- title: time2date(timestampInt)
- }, timestamp);
- }
- return closeOpenMode_React.createElement("div", {
- className: cssClasses,
- "data-id": `id${ message.messageId}`,
- key: message.messageId
- }, avatar, closeOpenMode_React.createElement("div", {
- className: "message content-area small-info-txt selectable-txt"
- }, closeOpenMode_React.createElement("div", {
- className: "message user-card-name"
- }, closeOpenMode_React.createElement(utils.zT, null, displayName)), datetime, closeOpenMode_React.createElement("div", {
- className: "message text-block"
- }, l[20569])));
- }
-}
-
-;// ./js/chat/ui/messages/chatHandle.jsx
-const chatHandle_React = REQ_(594);
-const chatHandle_ContactsUI = REQ_(251);
-const chatHandle_ConversationMessageMixin = REQ_(446).M;
-
-class ChatHandleMessage extends chatHandle_ConversationMessageMixin {
- render() {
- const self = this;
- let cssClasses = "message body";
- const {message} = this.props;
- const contact = self.getContact();
- const timestampInt = self.getTimestamp();
- const timestamp = self.getTimestampAsString();
- let datetime = chatHandle_React.createElement("div", {
- className: "message date-time",
- title: time2date(timestampInt)
- }, timestamp);
- let displayName;
- if (contact) {
- displayName = M.getNameByHandle(contact.u);
- } else {
- displayName = contact;
- }
- let avatar = null;
- if (this.props.grouped) {
- cssClasses += " grouped";
- } else {
- avatar = chatHandle_React.createElement(chatHandle_ContactsUI.Avatar, {
- contact,
- className: "message avatar-wrapper small-rounded-avatar",
- chatRoom: this.props.chatRoom
- });
- datetime = chatHandle_React.createElement("div", {
- className: "message date-time",
- title: time2date(timestampInt)
- }, timestamp);
- }
- return chatHandle_React.createElement("div", {
- className: cssClasses,
- "data-id": `id${ message.messageId}`,
- key: message.messageId
- }, avatar, chatHandle_React.createElement("div", {
- className: "message content-area small-info-txt selectable-txt"
- }, chatHandle_React.createElement("div", {
- className: "message user-card-name"
- }, chatHandle_React.createElement(utils.zT, null, displayName)), datetime, chatHandle_React.createElement("div", {
- className: "message text-block"
- }, message.meta.handleUpdate === 1 ? l[20570] : l[20571])));
- }
-}
-
-// EXTERNAL MODULE: ./js/chat/ui/messages/generic.jsx + 14 modules
-const generic = REQ_(890);
-// EXTERNAL MODULE: ./js/ui/perfectScrollbar.jsx
-const perfectScrollbar = REQ_(486);
-// EXTERNAL MODULE: ./js/chat/ui/messages/mixin.jsx
-const mixin = REQ_(446);
-// EXTERNAL MODULE: ./js/chat/ui/contacts.jsx
-const contacts = REQ_(251);
-;// ./js/chat/ui/messages/retentionChange.jsx
-
-
-
-
-class RetentionChange extends mixin.M {
- render() {
- const {
- message
- } = this.props;
- const contact = this.getContact();
- return REaCt().createElement("div", {
- className: "message body",
- "data-id": `id${ message.messageId}`,
- key: message.messageId
- }, REaCt().createElement(contacts.Avatar, {
- contact,
- className: "message avatar-wrapper small-rounded-avatar"
- }), REaCt().createElement("div", {
- className: "message content-area small-info-txt selectable-txt"
- }, REaCt().createElement(contacts.ContactButton, {
- contact,
- className: "message",
- label: REaCt().createElement(utils.zT, null, M.getNameByHandle(contact.u))
- }), REaCt().createElement("div", {
- className: "message date-time simpletip",
- "data-simpletip": time2date(this.getTimestamp(), 17)
- }, this.getTimestampAsString()), REaCt().createElement("div", {
- className: "message text-block"
- }, message.getMessageRetentionSummary())));
- }
-}
-// EXTERNAL MODULE: ./js/chat/ui/meetings/call.jsx + 11 modules
-const call = REQ_(3);
-// EXTERNAL MODULE: ./js/chat/ui/messages/scheduleMetaChange.jsx
-const scheduleMetaChange = REQ_(757);
-;// ./js/chat/ui/historyPanel.jsx
-
-let _dec, _class;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-const HistoryPanel = (_dec = (0,mixins.hG)(450, true), _class = class HistoryPanel extends mixins.w9 {
- constructor(props) {
- super(props);
- this.$container = null;
- this.$messages = null;
- this.domRef = REaCt().createRef();
- this.state = {
- editing: false,
- toast: false
- };
- this.renderNotice = label => REaCt().createElement("div", {
- className: "dropdown body dropdown-arrow down-arrow tooltip not-sent-notification-cancel hidden"
- }, REaCt().createElement("i", {
- className: "dropdown-white-arrow"
- }), REaCt().createElement("div", {
- className: "dropdown notification-text"
- }, REaCt().createElement("i", {
- className: "small-icon conversations"
- }), label));
- this.renderLoadingSpinner = () => REaCt().createElement("div", {
- style: {
- top: '50%'
- },
- className: `
- loading-spinner
- js-messages-loading
- light
- manual-management
- ${this.loadingShown ? '' : 'hidden'}
- `
- }, REaCt().createElement("div", {
- className: "main-loader",
- style: {
- position: 'fixed',
- top: '50%',
- left: '50%'
- }
- }));
- this.renderNavigationToast = () => {
- const {
- chatRoom
- } = this.props;
- const unreadCount = chatRoom.messagesBuff.getUnreadCount();
- return REaCt().createElement("div", {
- className: `
- theme-dark-forced
- messages-toast
- ${this.state.toast ? 'active' : ''}
- `,
- onClick: () => {
- this.setState({
- toast: false
- }, () => {
- this.messagesListScrollable.scrollToBottom();
- chatRoom.scrolledToBottom = true;
- });
- }
- }, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-down"
- }), unreadCount > 0 && REaCt().createElement("span", null, unreadCount > 9 ? '9+' : unreadCount));
- };
- this.onKeyboardScroll = ({
- keyCode
- }) => {
- let _scrollbar$domRef;
- const scrollbar = this.messagesListScrollable;
- const domNode = scrollbar == null || (_scrollbar$domRef = scrollbar.domRef) == null ? void 0 : _scrollbar$domRef.current;
- if (domNode && this.isComponentEventuallyVisible() && !this.state.attachCloudDialog) {
- const scrollPositionY = scrollbar.getScrollPositionY();
- const offset = parseInt(domNode.style.height);
- const PAGE = {
- UP: 33,
- DOWN: 34
- };
- switch (keyCode) {
- case PAGE.UP:
- scrollbar.scrollToY(scrollPositionY - offset, true);
- this.onMessagesScrollUserScroll(scrollbar, 100);
- break;
- case PAGE.DOWN:
- if (!scrollbar.isAtBottom()) {
- scrollbar.scrollToY(scrollPositionY + offset, true);
- }
- break;
- }
- }
- };
- this.onMessagesScrollUserScroll = (ps, offset = 5) => {
- const {
- chatRoom
- } = this.props;
- const {
- messagesBuff
- } = chatRoom;
- const scrollPositionY = ps.getScrollPositionY();
- if (messagesBuff.messages.length === 0) {
- chatRoom.scrolledToBottom = true;
- return;
- }
- if (ps.isCloseToBottom(30) === true) {
- if (!chatRoom.scrolledToBottom) {
- messagesBuff.detachMessages();
- }
- chatRoom.scrolledToBottom = true;
- } else {
- chatRoom.scrolledToBottom = false;
- }
- if (!this.scrollPullHistoryRetrieval && !messagesBuff.isRetrievingHistory && (ps.isAtTop() || scrollPositionY < offset && ps.getScrollHeight() > 500) && messagesBuff.haveMoreHistory()) {
- ps.disable();
- this.scrollPullHistoryRetrieval = true;
- this.lastScrollPosition = scrollPositionY;
- let msgAppended = 0;
- const scrYOffset = ps.getScrollHeight();
- chatRoom.one('onMessagesBuffAppend.pull', () => {
- msgAppended++;
- });
- chatRoom.off('onHistoryDecrypted.pull');
- chatRoom.one('onHistoryDecrypted.pull', () => {
- chatRoom.off('onMessagesBuffAppend.pull');
- if (msgAppended > 0) {
- this._reposOnUpdate = scrYOffset;
- }
- this.scrollPullHistoryRetrieval = -1;
- });
- messagesBuff.retrieveChatHistory();
- }
- if (this.lastScrollPosition !== scrollPositionY) {
- this.lastScrollPosition = scrollPositionY;
- }
- delay('chat-toast', this.initToast, 200);
- };
- this.initToast = () => {
- let _this$messagesListScr;
- const {
- chatRoom
- } = this.props;
- return this.isMounted() && this.setState({
- toast: !chatRoom.scrolledToBottom && !((_this$messagesListScr = this.messagesListScrollable) != null && _this$messagesListScr.isCloseToBottom != null && _this$messagesListScr.isCloseToBottom(30))
- }, () => this.state.toast ? null : chatRoom.trigger('onChatIsFocused'));
- };
- this.handleWindowResize = this._handleWindowResize.bind(this);
- }
- customIsEventuallyVisible() {
- return this.props.chatRoom.isCurrentlyActive;
- }
- UNSAFE_componentWillMount() {
- let _chatRoom$messagesBuf;
- const {
- chatRoom
- } = this.props;
- chatRoom.rebind('onHistoryDecrypted.cp', () => this.eventuallyUpdate());
- this._messagesBuffChangeHandler = (_chatRoom$messagesBuf = chatRoom.messagesBuff) == null ? void 0 : _chatRoom$messagesBuf.addChangeListener(SoonFc(() => {
- if (this.isComponentEventuallyVisible()) {
- let _this$domRef;
- $('.js-messages-scroll-area', (_this$domRef = this.domRef) == null ? void 0 : _this$domRef.current).trigger('forceResize', [true]);
- }
- this.refreshUI();
- }));
- }
- componentDidMount() {
- super.componentDidMount();
- const {
- chatRoom,
- onMount
- } = this.props;
- window.addEventListener('resize', this.handleWindowResize);
- window.addEventListener('keydown', this.handleKeyDown);
- this.$container = $(`.conversation-panel[data-room-id="${chatRoom.chatId}"]`);
- this.eventuallyInit();
- chatRoom.trigger('onHistoryPanelComponentDidMount');
- if (onMount) {
- onMount(this);
- }
- }
- componentWillUnmount() {
- super.componentWillUnmount();
- const {
- chatRoom
- } = this.props;
- if (this._messagesBuffChangeHandler) {
- let _chatRoom$messagesBuf2;
- (_chatRoom$messagesBuf2 = chatRoom.messagesBuff) == null || _chatRoom$messagesBuf2.removeChangeListener(this._messagesBuffChangeHandler);
- delete this._messagesBuffChangeHandler;
- }
- window.removeEventListener('resize', this.handleWindowResize);
- window.removeEventListener('keydown', this.handleKeyDown);
- $(document).off(`fullscreenchange.megaChat_${chatRoom.roomId}`);
- $(document).off(`keydown.keyboardScroll_${chatRoom.roomId}`);
- }
- componentDidUpdate(prevProps, prevState) {
- let _self$domRef;
- const self = this;
- self.eventuallyInit(false);
- const domNode = (_self$domRef = self.domRef) == null ? void 0 : _self$domRef.current;
- const jml = domNode && domNode.querySelector('.js-messages-loading');
- if (jml) {
- if (self.loadingShown) {
- jml.classList.remove('hidden');
- } else {
- jml.classList.add('hidden');
- }
- }
- self.handleWindowResize();
- if (prevState.editing === false && self.state.editing !== false && self.messagesListScrollable) {
- self.messagesListScrollable.reinitialise(false);
- Soon(() => {
- if (self.editDomElement && self.editDomElement.length === 1) {
- self.messagesListScrollable.scrollToElement(self.editDomElement[0], false);
- }
- });
- }
- if (self._reposOnUpdate !== undefined) {
- const ps = self.messagesListScrollable;
- ps.__prevPosY = ps.getScrollHeight() - self._reposOnUpdate + self.lastScrollPosition;
- ps.scrollToY(ps.__prevPosY, true);
- }
- }
- eventuallyInit(doResize) {
- let _this$domRef2;
- if (this.initialised) {
- return;
- }
- const domNode = (_this$domRef2 = this.domRef) == null ? void 0 : _this$domRef2.current;
- if (domNode) {
- this.initialised = true;
- } else {
- return;
- }
- this.$messages = $('.messages.scroll-area > .perfectScrollbarContainer', this.$container);
- this.$messages.droppable({
- tolerance: 'pointer',
- drop(e, ui) {
- $.doDD(e, ui, 'drop', 1);
- },
- over(e, ui) {
- $.doDD(e, ui, 'over', 1);
- },
- out(e, ui) {
- $.doDD(e, ui, 'out', 1);
- }
- });
- this.lastScrollPosition = null;
- this.props.chatRoom.scrolledToBottom = true;
- if (doResize !== false) {
- this.handleWindowResize();
- }
- }
- _handleWindowResize(e, scrollToBottom) {
- if (!M.chat) {
- return;
- }
- if (!this.isMounted()) {
- this.componentWillUnmount();
- return;
- }
- if (!this.isComponentEventuallyVisible()) {
- return;
- }
- const self = this;
- self.eventuallyInit(false);
- if (!self.$messages) {
- return;
- }
- if (call.Ay.isExpanded()) {
- const $container = $('.meetings-call');
- const $messages = $('.js-messages-scroll-area', $container);
- const $textarea = $('.chat-textarea-block', $container);
- const $sidebar = $('.sidebar', $container);
- const scrollBlockHeight = parseInt($sidebar.outerHeight(), 10) - parseInt($textarea.outerHeight(), 10) - 72;
- if ($sidebar.hasClass('chat-opened') && scrollBlockHeight !== $messages.outerHeight()) {
- $messages.css('height', scrollBlockHeight);
- self.refreshUI(true);
- }
- return;
- }
- const scrollBlockHeight = $('.chat-content-block', self.$container).outerHeight() - ($('.chat-topic-block', self.$container).outerHeight() || 0) - (is_chatlink ? $('.join-chat-block', self.$container).outerHeight() : $('.messages-block .chat-textarea-block', self.$container).outerHeight());
- if (scrollBlockHeight !== self.$messages.outerHeight()) {
- self.$messages.css('height', scrollBlockHeight);
- $('.messages.main-pad', self.$messages).css('min-height', scrollBlockHeight);
- self.refreshUI(true);
- } else {
- self.refreshUI(scrollToBottom);
- }
- }
- refreshUI() {
- if (this.isComponentEventuallyVisible()) {
- const room = this.props.chatRoom;
- room.renderContactTree();
- room.megaChat.refreshConversations();
- room.trigger('RefreshUI');
- if (room.scrolledToBottom) {
- delay(`hp:reinit-scroll:${this.getUniqueId()}`, () => {
- if (this.messagesListScrollable) {
- this.messagesListScrollable.reinitialise(true, true);
- }
- }, 30);
- }
- }
- }
- isLoading() {
- const {chatRoom} = this.props;
- if (chatRoom.historyTimedOut) {
- return false;
- }
- const mb = chatRoom.messagesBuff;
- return this.scrollPullHistoryRetrieval === true || chatRoom.activeSearches || mb.messagesHistoryIsLoading() || mb.joined === false || mb.isDecrypting;
- }
- specShouldComponentUpdate() {
- return !this.loadingShown && this.isComponentEventuallyVisible();
- }
- enableScrollbar() {
- const ps = this.messagesListScrollable;
- ps.enable();
- this._reposOnUpdate = undefined;
- this.lastScrollPosition = ps.__prevPosY | 0;
- }
- editMessage(messageId) {
- const self = this;
- self.setState({
- 'editing': messageId
- });
- self.props.chatRoom.scrolledToBottom = false;
- }
- onMessageEditDone(v, messageContents) {
- const self = this;
- const room = this.props.chatRoom;
- room.scrolledToBottom = true;
- self.editDomElement = null;
- const currentContents = v.textContents;
- v.edited = false;
- if (messageContents === false || messageContents === currentContents) {
- let _self$messagesListScr;
- (_self$messagesListScr = self.messagesListScrollable) == null || _self$messagesListScr.scrollToBottom(true);
- } else if (messageContents) {
- let _self$messagesListScr2;
- room.trigger('onMessageUpdating', v);
- room.megaChat.plugins.chatdIntegration.updateMessage(room, v.internalId ? v.internalId : v.orderValue, messageContents);
- if (v.getState && (v.getState() === Message.STATE.NOT_SENT || v.getState() === Message.STATE.SENT) && !v.requiresManualRetry) {
- if (v.textContents) {
- v.textContents = messageContents;
- }
- if (v.emoticonShortcutsProcessed) {
- v.emoticonShortcutsProcessed = false;
- }
- if (v.emoticonsProcessed) {
- v.emoticonsProcessed = false;
- }
- if (v.messageHtml) {
- delete v.messageHtml;
- }
- v.trigger('onChange', [v, "textContents", "", messageContents]);
- megaChat.plugins.richpreviewsFilter.processMessage({}, v, false, true);
- }
- (_self$messagesListScr2 = self.messagesListScrollable) == null || _self$messagesListScr2.scrollToBottom(true);
- } else if (messageContents.length === 0) {
- this.props.onDeleteClicked(v);
- }
- self.setState({
- 'editing': false
- });
- self.refreshUI();
- Soon(() => {
- $('.chat-textarea-block:visible textarea').focus();
- }, 300);
- }
- render() {
- const self = this;
- const room = this.props.chatRoom;
- if (!room || !room.roomId) {
- return null;
- }
- const contacts = room.getParticipantsExceptMe();
- let contactHandle;
- let contact;
- let avatarMeta;
- let contactName = "";
- if (contacts && contacts.length === 1) {
- contactHandle = contacts[0];
- contact = M.u[contactHandle];
- avatarMeta = contact ? generateAvatarMeta(contact.u) : {};
- contactName = avatarMeta.fullName;
- } else if (contacts && contacts.length > 1) {
- contactName = room.getRoomTitle();
- }
- let messagesList = [];
- if (this.isLoading()) {
- self.loadingShown = true;
- } else {
- const mb = room.messagesBuff;
- if (this.scrollPullHistoryRetrieval < 0) {
- this.scrollPullHistoryRetrieval = false;
- self.enableScrollbar();
- }
- delete self.loadingShown;
- if (room.historyTimedOut || mb.joined === true && !self.scrollPullHistoryRetrieval && mb.haveMoreHistory() === false) {
- const $$WELCOME_MESSAGE = ({
- heading,
- title,
- info,
- className
- }) => REaCt().createElement("div", {
- className: `
- messages
- welcome-message
- ${className || ''}
- `
- }, REaCt().createElement(utils.P9, {
- tag: "h1",
- content: heading
- }), title && REaCt().createElement("span", null, title), info);
- messagesList = [...messagesList, room.isNote ? $$WELCOME_MESSAGE({
- heading: l.note_heading,
- info: REaCt().createElement("p", null, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-file-text-thin-outline note-chat-icon"
- }), l.note_description),
- className: 'note-chat-info'
- }) : $$WELCOME_MESSAGE({
- heading: room.scheduledMeeting || !contactName ? megaChat.html(room.getRoomTitle()) : l[8002].replace('%s', `${megaChat.html(contactName)}`),
- title: l[8080],
- info: REaCt().createElement(REaCt().Fragment, null, REaCt().createElement("p", null, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-lock"
- }), REaCt().createElement(utils.P9, {
- content: l[8540].replace("[S]", "").replace("[/S]", "")
- })), REaCt().createElement("p", null, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-accept"
- }), REaCt().createElement(utils.P9, {
- content: l[8539].replace("[S]", "").replace("[/S]", "")
- })))
- })];
- }
- }
- let lastTimeMarker;
- let lastMessageFrom = null;
- let lastGroupedMessageTimeStamp = null;
- let grouped = false;
- for (let i = 0; i < room.messagesBuff.messages.length; i++) {
- let v = room.messagesBuff.messages.getItem(i);
- if (!v.protocol && v.revoked !== true) {
- let shouldRender = true;
- if (v.isManagement && v.isManagement() === true && v.isRenderableManagement() === false || v.deleted === true) {
- shouldRender = false;
- }
- const timestamp = v.delay;
- const curTimeMarker = getTimeMarker(timestamp);
- if (shouldRender === true && curTimeMarker && lastTimeMarker !== curTimeMarker) {
- lastTimeMarker = curTimeMarker;
- messagesList.push(REaCt().createElement("div", {
- className: "message date-divider selectable-txt",
- key: `${v.messageId }_marker`,
- title: time2date(timestamp)
- }, curTimeMarker));
- grouped = false;
- lastMessageFrom = null;
- lastGroupedMessageTimeStamp = null;
- }
- if (shouldRender === true) {
- let {userId} = v;
- if (!userId && contact && contact.u) {
- userId = contact.u;
- }
- if (v instanceof Message && v.dialogType !== "truncated") {
- if (!lastMessageFrom || userId && lastMessageFrom === userId) {
- if (timestamp - lastGroupedMessageTimeStamp < 300) {
- grouped = true;
- } else {
- grouped = false;
- lastMessageFrom = userId;
- lastGroupedMessageTimeStamp = timestamp;
- }
- } else {
- grouped = false;
- lastMessageFrom = userId;
- if (lastMessageFrom === userId) {
- lastGroupedMessageTimeStamp = timestamp;
- } else {
- lastGroupedMessageTimeStamp = null;
- }
- }
- } else {
- grouped = false;
- lastMessageFrom = null;
- lastGroupedMessageTimeStamp = null;
- }
- }
- if ((v.dialogType === "remoteCallEnded" || v.dialogType === "remoteCallStarted") && v && v.wrappedChatDialogMessage) {
- v = v.wrappedChatDialogMessage;
- }
- if (v.dialogType) {
- let messageInstance = null;
- if (v.dialogType === 'alterParticipants') {
- messageInstance = REaCt().createElement(AltPartsConvMessage, {
- message: v,
- key: v.messageId,
- contact: Message.getContactForMessage(v),
- grouped,
- chatRoom: room
- });
- } else if (v.dialogType === 'truncated') {
- messageInstance = REaCt().createElement(TruncatedMessage, {
- message: v,
- key: v.messageId,
- contact: Message.getContactForMessage(v),
- grouped,
- chatRoom: room
- });
- } else if (v.dialogType === 'privilegeChange') {
- messageInstance = REaCt().createElement(PrivilegeChange, {
- message: v,
- key: v.messageId,
- contact: Message.getContactForMessage(v),
- grouped,
- chatRoom: room
- });
- } else if (v.dialogType === 'topicChange') {
- messageInstance = REaCt().createElement(TopicChange, {
- message: v,
- key: v.messageId,
- contact: Message.getContactForMessage(v),
- grouped,
- chatRoom: room
- });
- } else if (v.dialogType === 'openModeClosed') {
- messageInstance = REaCt().createElement(CloseOpenModeMessage, {
- message: v,
- key: v.messageId,
- contact: Message.getContactForMessage(v),
- grouped,
- chatRoom: room
- });
- } else if (v.dialogType === 'chatHandleUpdate') {
- messageInstance = REaCt().createElement(ChatHandleMessage, {
- message: v,
- key: v.messageId,
- contact: Message.getContactForMessage(v),
- grouped,
- chatRoom: room
- });
- } else if (v.dialogType === 'messageRetention') {
- messageInstance = REaCt().createElement(RetentionChange, {
- message: v,
- key: v.messageId,
- contact: Message.getContactForMessage(v)
- });
- } else if (v.dialogType === 'scheduleMeta') {
- if (v.meta.onlyTitle) {
- messageInstance = REaCt().createElement(TopicChange, {
- message: v,
- key: v.messageId,
- contact: Message.getContactForMessage(v),
- grouped,
- chatRoom: v.chatRoom
- });
- } else {
- if (v.meta.topicChange) {
- messagesList.push(REaCt().createElement(TopicChange, {
- message: v,
- key: `${v.messageId}-topic`,
- contact: Message.getContactForMessage(v),
- grouped,
- chatRoom: v.chatRoom
- }));
- }
- messageInstance = REaCt().createElement(scheduleMetaChange.A, {
- message: v,
- key: v.messageId,
- mode: v.meta.mode,
- chatRoom: room,
- grouped,
- link: v.chatRoom.publicLink,
- contact: Message.getContactForMessage(v)
- });
- }
- }
- messagesList.push(messageInstance);
- } else {
- if (!v.chatRoom) {
- v.chatRoom = room;
- }
- messagesList.push(REaCt().createElement(generic.A, {
- message: v,
- state: v.state,
- key: v.messageId,
- contact: Message.getContactForMessage(v),
- grouped,
- onUpdate: () => {
- self.onResizeDoUpdate();
- },
- editing: self.state.editing === v.messageId || self.state.editing === v.pendingMessageId,
- onEditStarted: ((v, $domElement) => {
- self.editDomElement = $domElement;
- self.setState({
- 'editing': v.messageId
- });
- self.forceUpdate();
- }).bind(this, v),
- chatRoom: room,
- onEditDone: this.onMessageEditDone.bind(this, v),
- onDeleteClicked: msg => {
- if (this.props.onDeleteClicked) {
- this.props.onDeleteClicked(msg);
- }
- },
- onResized: () => {
- this.handleWindowResize();
- },
- onEmojiBarChange: () => {
- this.handleWindowResize();
- }
- }));
- }
- }
- }
- return REaCt().createElement("div", {
- ref: this.domRef,
- className: `
- messages
- scroll-area
- ${this.props.className || ''}
- `
- }, REaCt().createElement(perfectScrollbar.O, {
- className: "js-messages-scroll-area perfectScrollbarContainer",
- ref: ref => {
- let _this$props$onMessage, _this$props;
- this.messagesListScrollable = ref;
- $(document).rebind(`keydown.keyboardScroll_${room.roomId}`, this.onKeyboardScroll);
- (_this$props$onMessage = (_this$props = this.props).onMessagesListScrollableMount) == null || _this$props$onMessage.call(_this$props, ref);
- },
- chatRoom: room,
- messagesBuff: room.messagesBuff,
- editDomElement: this.state.editDomElement,
- editingMessageId: this.state.editing,
- confirmDeleteDialog: this.state.confirmDeleteDialog,
- renderedMessagesCount: messagesList.length,
- options: {
- suppressScrollX: true
- },
- isLoading: room.messagesBuff.messagesHistoryIsLoading() || room.activeSearches > 0 || this.loadingShown,
- onFirstInit: ps => {
- ps.scrollToBottom(true);
- room.scrolledToBottom = 1;
- },
- onUserScroll: this.onMessagesScrollUserScroll
- }, REaCt().createElement("div", {
- className: "messages main-pad"
- }, REaCt().createElement("div", {
- className: "messages content-area"
- }, this.renderLoadingSpinner(), messagesList))), this.renderNavigationToast());
- }
-}, (0,applyDecoratedDescriptor.A)(_class.prototype, "enableScrollbar", [_dec], Object.getOwnPropertyDescriptor(_class.prototype, "enableScrollbar"), _class.prototype), _class);
-
-
-},
-
-815
-(_, EXP_, REQ_) {
-
-"use strict";
-REQ_.d(EXP_, {
-Q: () => InviteParticipantsPanel
-});
-const react0__ = REQ_(594);
-const react0 = REQ_.n(react0__);
-const _meetings_call_jsx1__ = REQ_(3);
-const _ui_miniui_jsx2__ = REQ_(818);
-const _ui_buttons_jsx3__ = REQ_(994);
-const _ui_dropdowns_jsx4__ = REQ_(911);
-
-
-
-
-
-const NAMESPACE = 'invite-panel';
-class InviteParticipantsPanel extends react0().Component {
- constructor(props) {
- super(props);
- this.domRef = react0().createRef();
- this.state = {
- link: '',
- copied: false
- };
- this.retrieveChatLink();
- }
- retrieveChatLink(cim) {
- const {
- chatRoom
- } = this.props;
- if (!chatRoom.topic) {
- return;
- }
- this.loading = chatRoom.updatePublicHandle(false, cim).always(() => {
- delete this.loading;
- if (this.domRef.current) {
- if (chatRoom.publicLink) {
- this.setState({
- link: `${getBaseUrl()}/${chatRoom.publicLink}`
- });
- } else {
- this.setState({
- link: false
- });
- }
- }
- });
- }
- getInviteBody(encode) {
- const {
- chatRoom
- } = this.props;
- const {
- link
- } = this.state;
- const {
- scheduledMeeting
- } = chatRoom;
- let body = l.invite_body_text;
- if (scheduledMeeting) {
- const {
- nextOccurrenceStart
- } = chatRoom.scheduledMeeting;
- body = l.invite_body_text_scheduled.replace('%4', time2date(nextOccurrenceStart / 1000, 20)).replace('%5', toLocaleTime(nextOccurrenceStart));
- }
- body = body.replace(/\[BR]/g, '\n').replace('%1', u_attr.name).replace('%2', chatRoom.getRoomTitle()).replace('%3', link);
- if (encode) {
- return typeof body.toWellFormatted === 'function' ? body.toWellFormatted() : body.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g, '').replace(/[\uD800-\uDBFF]/g, '\uFFFD').replace(/[\uDC00-\uDFFF]/g, '\uFFFD');
- }
- return body;
- }
- render() {
- const {
- chatRoom,
- disableLinkToggle,
- onAddParticipants
- } = this.props;
- const {
- link,
- copied
- } = this.state;
- const inCall = _meetings_call_jsx1__.Ay.isExpanded();
- if (this.loading) {
- return react0().createElement("div", {
- ref: this.domRef,
- className: `
- ${NAMESPACE}
- ${inCall ? 'theme-dark-forced' : ''}
- `
- }, react0().createElement("header", null), react0().createElement("section", {
- className: "content"
- }, react0().createElement("div", {
- className: "content-block"
- })));
- }
- const canInvite = !!(chatRoom.iAmOperator() || chatRoom.options[MCO_FLAGS.OPEN_INVITE]) && onAddParticipants;
- const canToggleLink = !disableLinkToggle && chatRoom.iAmOperator() && (chatRoom.isMeeting || chatRoom.topic);
- const mailto = `mailto:?to=&subject=${l.invite_subject_text}&body=${this.getInviteBody(true)}`;
- const copyText = chatRoom.isMeeting ? l.copy_meeting_link : l[1394];
- return react0().createElement("div", {
- ref: this.domRef,
- className: `
- ${NAMESPACE}
- ${inCall ? 'theme-dark-forced' : ''}
- `
- }, react0().createElement("header", null, react0().createElement("h3", null, l.invite_participants)), react0().createElement("section", {
- className: "content"
- }, canToggleLink && chatRoom.type !== 'group' && react0().createElement("div", {
- className: "content-block link-block"
- }, react0().createElement("div", {
- className: "text-wrapper"
- }, react0().createElement("span", {
- className: "link-label"
- }, l.invite_toggle_link_label), react0().createElement("div", {
- className: `link-description ${inCall ? '' : 'hidden'}`
- }, l.invite_toggle_link_desc)), react0().createElement(_ui_miniui_jsx2__.A.ToggleCheckbox, {
- className: "meeting-link-toggle",
- checked: !!link,
- value: !!link,
- onToggle: () => {
- if (this.loading) {
- return;
- }
- if (link) {
- this.loading = chatRoom.updatePublicHandle(true).always(() => {
- delete this.loading;
- if (this.domRef.current) {
- this.setState({
- link: false
- });
- }
- });
- } else {
- this.retrieveChatLink(true);
- }
- }
- })), link && react0().createElement("div", {
- className: "content-block"
- }, react0().createElement(_ui_buttons_jsx3__.$, {
- className: "flat-button",
- icon: `sprite-fm-mono icon-${copied ? 'check' : 'link-thin-outline'}`,
- label: copied ? l.copied : copyText,
- onClick: () => {
- if (copied) {
- return;
- }
- delay('chat-event-inv-copylink', () => eventlog(99964));
- copyToClipboard(link);
- this.setState({
- copied: true
- }, () => {
- tSleep(3).then(() => {
- if (this.domRef.current) {
- this.setState({
- copied: false
- });
- }
- });
- });
- }
- })), link && react0().createElement("div", {
- className: "content-block"
- }, react0().createElement(_ui_buttons_jsx3__.$, {
- className: "flat-button",
- label: l.share_chat_link,
- icon: "sprite-fm-mono icon-share-02-thin-outline"
- }, react0().createElement(_ui_dropdowns_jsx4__.Dropdown, {
- className: `
- button-group-menu
- invite-dropdown
- ${inCall ? 'theme-dark-forced' : ''}
- `,
- noArrow: true,
- positionAt: "left bottom",
- collision: "none",
- horizOffset: 79,
- vertOffset: 6,
- ref: r => {
- this.dropdownRef = r;
- },
- onBeforeActiveChange: e => {
- if (e) {
- delay('chat-event-inv-dropdown', () => eventlog(99965));
- $(document.body).trigger('closeAllDropdownsExcept', this.dropdownRef);
- }
- }
- }, react0().createElement(_ui_dropdowns_jsx4__.DropdownItem, {
- key: "send-invite",
- className: `
- ${inCall ? 'theme-dark-forced' : ''}
- `,
- icon: "sprite-fm-mono icon-mail-thin-outline",
- label: l.share_chat_link_invite,
- onClick: () => {
- delay('chat-event-inv-email', () => eventlog(99966));
- window.open(mailto, '_self', 'noopener,noreferrer');
- }
- }), react0().createElement(_ui_dropdowns_jsx4__.DropdownItem, {
- key: "copy-invite",
- className: `
- ${inCall ? 'theme-dark-forced' : ''}
- `,
- label: l.copy_chat_link_invite,
- icon: "sprite-fm-mono icon-square-copy",
- onClick: () => {
- delay('chat-event-inv-copy', () => eventlog(99967));
- copyToClipboard(this.getInviteBody(), l.invite_copied);
- }
- })))), canInvite && (link || canToggleLink) && chatRoom.type !== 'group' && react0().createElement("div", {
- className: "content-block invite-panel-divider"
- }, l.invite_dlg_divider), canInvite && react0().createElement("div", {
- className: "content-block add-participant-block"
- }, react0().createElement(_ui_buttons_jsx3__.$, {
- className: "flat-button",
- icon: "sprite-fm-mono icon-user-square-thin-outline",
- label: l.add_participants,
- onClick: () => {
- delay('chat-event-inv-add-participant', () => eventlog(99968));
- onAddParticipants();
- }
- }))));
- }
-}
-
-},
-
-280
-(_, EXP_, REQ_) {
-
-"use strict";
-REQ_.d(EXP_, {
-A: () => Link
-});
-const react0__ = REQ_(594);
-const react0 = REQ_.n(react0__);
-
-class Link extends react0().Component {
- constructor(props) {
- super(props);
- this.IS_CLICK_URL = undefined;
- this.IS_CLICK_URL = this.props.to && (this.props.to.startsWith('/') || this.props.to.includes('mega.io'));
- }
- componentDidMount() {
- if (this.IS_CLICK_URL) {
- clickURLs();
- }
- }
- render() {
- const {
- className,
- to,
- target,
- children,
- onClick
- } = this.props;
- if (this.IS_CLICK_URL) {
- return react0().createElement("a", {
- className: `
- clickurl
- ${className || ''}
- `,
- href: to,
- target
- }, children);
- }
- return react0().createElement("a", {
- className,
- href: "#",
- onClick: ev => {
- if (onClick) {
- ev.preventDefault();
- return onClick(ev);
- }
- return null;
- }
- }, children);
- }
-}
-
-},
-
-959
-(_, EXP_, REQ_) {
-
-"use strict";
-REQ_.d(EXP_, {
-A: () => __WEBPACK_DEFAULT_EXPORT__
-});
-const react0__ = REQ_(594);
-const react0 = REQ_.n(react0__);
-
-class Group extends react0().Component {
- constructor(props) {
- super(props);
- this.containerRef = react0().createRef();
- this.state = {
- expanded: false
- };
- this.doToggle = this.doToggle.bind(this);
- }
- toggleEvents() {
- return this.state.expanded ? $(document).rebind(`mousedown.${Group.NAMESPACE}`, ev => !this.containerRef.current.contains(ev.target) && this.doToggle()).rebind(`keydown.${Group.NAMESPACE}`, ({
- keyCode
- }) => keyCode && keyCode === 27 && this.doToggle()) : $(document).unbind(`.${Group.NAMESPACE}`);
- }
- doToggle() {
- this.setState(state => ({
- expanded: !state.expanded
- }), () => this.toggleEvents());
- }
- render() {
- const {
- active,
- warn,
- onHold,
- screenSharing,
- children
- } = this.props;
- if (children && children.length) {
- return react0().createElement("div", {
- ref: this.containerRef,
- className: Group.BASE_CLASS
- }, react0().createElement("div", {
- className: `
- ${Group.BASE_CLASS}-menu
- ${this.state.expanded ? 'expanded' : ''}
- `,
- onClick: this.doToggle
- }, children.map(item => {
- return item && react0().createElement("div", {
- key: item.key,
- className: `${Group.BASE_CLASS}-item`
- }, item);
- })), react0().createElement("button", {
- className: "mega-button theme-light-forced round large",
- onClick: this.doToggle
- }, active && react0().createElement("div", {
- className: "info-indicator active"
- }), warn && react0().createElement("div", {
- className: "info-indicator warn simpletip",
- "data-simpletip": l.screen_share_crop_tip,
- "data-simpletipposition": "top",
- "data-simpletipoffset": "5",
- "data-simpletip-class": "theme-dark-forced"
- }, react0().createElement("i", {
- className: "sprite-fm-mono icon-exclamation-filled"
- })), react0().createElement("i", {
- className: `
- sprite-fm-mono
- ${screenSharing ? 'icon-end-screenshare' : ''}
- ${!onHold && !screenSharing && 'icon-options'}
- `
- })));
- }
- return null;
- }
-}
-Group.NAMESPACE = 'buttonGroup';
-Group.BASE_CLASS = 'button-group';
-class Button extends react0().Component {
- constructor(...args) {
- super(...args);
- this.buttonRef = react0().createRef();
- }
- componentDidUpdate() {
- if (this.props.simpletip) {
- $(this.buttonRef.current).trigger('simpletipUpdated');
- }
- }
- componentDidMount() {
- if (this.props.didMount) {
- this.props.didMount(this);
- }
- }
- render() {
- const {
- children,
- className,
- style,
- simpletip,
- icon,
- onClick
- } = this.props;
- return react0().createElement("button", {
- ref: this.buttonRef,
- className: `
- ${className ? className : ''}
- ${simpletip ? 'simpletip' : ''}
- `,
- style,
- "data-simpletip": simpletip == null ? void 0 : simpletip.label,
- "data-simpletipposition": simpletip == null ? void 0 : simpletip.position,
- "data-simpletipoffset": simpletip == null ? void 0 : simpletip.offset,
- "data-simpletip-class": simpletip == null ? void 0 : simpletip.className,
- onClick
- }, icon && react0().createElement("i", {
- className: `sprite-fm-mono ${icon}`
- }), children);
- }
-}
-Button.Group = Group;
-const __WEBPACK_DEFAULT_EXPORT__ = Button;
-
-},
-
-3
-(_, EXP_, REQ_) {
-
-"use strict";
-
-// EXPORTS
-REQ_.d(EXP_, {
- Fj: () => EXPANDED_FLAG,
- g: () => MODE,
- ZE: () => TYPE,
- gR: () => VIEW,
- Ay: () => Call,
- dQ: () => inProgressAlert,
- P: () => isGuest
-});
-
-// EXTERNAL MODULE: ./node_modules/@babel/runtime/helpers/esm/extends.js
-const esm_extends = REQ_(168);
-// EXTERNAL MODULE: external "React"
-const React_ = REQ_(594);
-const REaCt = REQ_.n(React_);
-// EXTERNAL MODULE: ./js/chat/mixins.js
-const mixins = REQ_(137);
-// EXTERNAL MODULE: ./js/chat/ui/meetings/stream.jsx + 7 modules
-const stream = REQ_(415);
-// EXTERNAL MODULE: ./js/chat/ui/composedTextArea.jsx + 1 modules
-const composedTextArea = REQ_(77);
-// EXTERNAL MODULE: ./js/chat/ui/historyPanel.jsx + 7 modules
-const historyPanel = REQ_(814);
-// EXTERNAL MODULE: ./js/chat/ui/contacts.jsx
-const ui_contacts = REQ_(251);
-// EXTERNAL MODULE: ./js/ui/perfectScrollbar.jsx
-const perfectScrollbar = REQ_(486);
-;// ./js/chat/ui/meetings/collapse.jsx
-
-class Collapse extends REaCt().Component {
- constructor(...args) {
- super(...args);
- this.state = {
- expanded: true
- };
- }
- render() {
- const {
- expanded
- } = this.state;
- const {
- heading,
- badge,
- children
- } = this.props;
- return REaCt().createElement("div", {
- className: "collapse"
- }, heading && REaCt().createElement("div", {
- className: "collapse-head",
- onClick: () => this.setState(state => ({
- expanded: !state.expanded
- }))
- }, REaCt().createElement("i", {
- className: `
- sprite-fm-mono
- ${expanded ? 'icon-arrow-down' : 'icon-arrow-up'}
- `
- }), REaCt().createElement("h5", null, heading), badge !== undefined && badge > 0 && REaCt().createElement("span", {
- className: "participants-count"
- }, badge)), expanded && children);
- }
-}
-// EXTERNAL MODULE: ./js/ui/utils.jsx
-const utils = REQ_(314);
-// EXTERNAL MODULE: ./js/chat/ui/meetings/button.jsx
-const meetings_button = REQ_(959);
-// EXTERNAL MODULE: ./js/chat/ui/contactsPanel/contactsPanel.jsx + 20 modules
-const contactsPanel = REQ_(173);
-// EXTERNAL MODULE: ./js/chat/ui/meetings/videoNodeMenu.jsx
-const videoNodeMenu = REQ_(539);
-// EXTERNAL MODULE: ./js/chat/ui/meetings/videoNode.jsx
-const videoNode = REQ_(414);
-;// ./js/chat/ui/meetings/participants.jsx
-
-
-
-
-
-
-
-
-
-
-
-
-class Participant extends mixins.w9 {
- constructor(props) {
- super(props);
- this.domRef = REaCt().createRef();
- this.raisedHandListener = undefined;
- this.baseIconClass = 'sprite-fm-mono';
- this.state = {
- raisedHandPeers: []
- };
- this.state.raisedHandPeers = this.props.raisedHandPeers || [];
- }
- componentDidMount() {
- super.componentDidMount();
- this.props.source.registerConsumer(this);
- this.raisedHandListener = mBroadcaster.addListener('meetings:raisedHand', raisedHandPeers => this.setState({
- raisedHandPeers
- }, () => this.safeForceUpdate()));
- }
- componentWillUnmount() {
- super.componentWillUnmount();
- this.props.source.deregisterConsumer(this);
- mBroadcaster.removeListener(this.raisedHandListener);
- }
- onAvChange() {
- this.safeForceUpdate();
- }
- render() {
- const {
- call,
- mode,
- chatRoom,
- source,
- contact,
- handle,
- name,
- recorderCid,
- onCallMinimize,
- onSpeakerChange,
- onModeChange
- } = this.props;
- const {
- isOnHold,
- videoMuted,
- audioMuted,
- clientId
- } = source;
- const hasRelationship = contactsPanel.A.hasRelationship(contact);
- return REaCt().createElement("div", {
- ref: this.domRef,
- className: "participant-wrapper"
- }, this.state.raisedHandPeers.includes(handle) && !isOnHold ? REaCt().createElement("div", {
- className: "participant-signifier"
- }, REaCt().createElement("i", {
- className: "sprite-fm-uni icon-raise-hand"
- })) : REaCt().createElement(ui_contacts.Avatar, {
- contact: M.u[handle]
- }), REaCt().createElement("div", {
- className: "name"
- }, handle === u_handle ? REaCt().createElement(utils.zT, null, `${name} ${l.me}`) : REaCt().createElement(ui_contacts.ContactAwareName, {
- contact: M.u[handle],
- emoji: true
- }), Call.isModerator(chatRoom, handle) && REaCt().createElement("span", null, REaCt().createElement("i", {
- className: `${this.baseIconClass} icon-admin-outline`
- }))), REaCt().createElement("div", {
- className: "status"
- }, recorderCid === clientId || recorderCid === call.sfuClient.cid && handle === u_handle ? REaCt().createElement("div", {
- className: "recording-status"
- }, REaCt().createElement("span", null)) : null, REaCt().createElement("i", {
- className: `
- ${this.baseIconClass}
- ${videoMuted ? 'icon-video-off-thin-outline inactive' : 'icon-video-thin-outline'}
- `
- }), REaCt().createElement(videoNode.Gz, {
- source
- }), REaCt().createElement("div", {
- className: "participants-menu theme-dark-forced"
- }, REaCt().createElement("div", {
- className: "participants-menu-toggle"
- }, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-side-menu"
- })), REaCt().createElement("div", {
- className: "participants-menu-content"
- }, REaCt().createElement("ul", null, hasRelationship ? REaCt().createElement("li", null, REaCt().createElement(meetings_button.A, {
- icon: "sprite-fm-mono icon-info",
- onClick: () => {
- onCallMinimize();
- loadSubPage(`fm/chat/contacts/${handle}`);
- }
- }, REaCt().createElement("span", null, l[6859]))) : null, chatRoom.iAmOperator() && u_handle !== handle && !audioMuted && REaCt().createElement("li", null, REaCt().createElement(meetings_button.A, {
- icon: "sprite-fm-mono icon-mic-off-thin-outline",
- onClick: () => {
- call.sfuClient.mutePeer(clientId);
- megaChat.plugins.userHelper.getUserNickname(handle).catch(dump).always(name => {
- ChatToast.quick(l.you_muted_peer.replace('%NAME', name || ''));
- });
- }
- }, REaCt().createElement("span", null, l[16214]))), hasRelationship ? REaCt().createElement("li", null, REaCt().createElement(meetings_button.A, {
- icon: "sprite-fm-mono icon-chat",
- onClick: () => {
- onCallMinimize();
- loadSubPage(`fm/chat/p/${handle}`);
- }
- }, REaCt().createElement("span", null, l.send_message))) : null, chatRoom.iAmOperator() && u_handle !== handle && REaCt().createElement("li", null, REaCt().createElement(videoNodeMenu.EH, {
- stream: source,
- chatRoom
- })), REaCt().createElement("li", null, REaCt().createElement(videoNodeMenu.yU, {
- mode,
- stream: source,
- onSpeakerChange,
- onModeChange
- })), call.isPublic && chatRoom.iAmOperator() && u_handle !== handle && REaCt().createElement("li", null, REaCt().createElement(meetings_button.A, {
- icon: "sprite-fm-mono icon-disabled-filled",
- onClick: () => chatRoom.trigger('onRemoveUserRequest', handle)
- }, REaCt().createElement("span", null, l[8867]))))))));
- }
-}
-class Participants extends mixins.w9 {
- get allPeersMuted() {
- return Object.values(this.props.peers).filter(p => p instanceof CallManager2.Peer).every(p => p.audioMuted);
- }
- constructor(props) {
- super(props);
- this.domRef = REaCt().createRef();
- this.muteRef = REaCt().createRef();
- this.NAMESPACE = 'participants';
- this.FILTER = {
- IN_CALL: 0,
- CHAT_PARTICIPANTS: 1
- };
- this.state = {
- filter: this.FILTER.IN_CALL,
- noResponsePeers: [],
- ringingPeers: [],
- allPeersMuted: undefined
- };
- this.doHangUp = handle => {
- if (handle) {
- const {
- call,
- chatRoom
- } = this.props;
- return this.isMounted() && this.setState(state => ({
- ringingPeers: state.ringingPeers.filter(p => p !== handle)
- }), () => chatRoom.ringUser(handle, call.callId, 0));
- }
- };
- this.doCall = handle => {
- if (handle) {
- const {
- call,
- chatRoom
- } = this.props;
- this.setState(state => ({
- ringingPeers: [...state.ringingPeers, handle]
- }), () => {
- chatRoom.ringUser(handle, call.callId, 1);
- if (chatRoom.options.w) {
- let _call$sfuClient;
- call == null || (_call$sfuClient = call.sfuClient) == null || _call$sfuClient.wrAllowJoin([handle]);
- }
- tSleep(40).then(() => {
- this.doHangUp(handle);
- return Object.keys(chatRoom.uniqueCallParts).includes(handle) ? null : this.setState(state => ({
- noResponsePeers: [...state.noResponsePeers, handle]
- }));
- });
- });
- }
- };
- this.getCallState = handle => {
- const {
- noResponsePeers,
- ringingPeers
- } = this.state;
- if (this.props.initialCallRinging || ringingPeers.includes(handle)) {
- return l.call_state_calling;
- }
- if (noResponsePeers.includes(handle)) {
- return l.call_state_no_response;
- }
- return l.call_state_not_in_call;
- };
- this.getCallParticipants = () => {
- const {
- call,
- mode,
- chatRoom,
- recorderCid,
- raisedHandPeers,
- onCallMinimize,
- onSpeakerChange,
- onModeChange
- } = this.props;
- const peers = Object.values(this.props.peers);
- const $$PEER = peer => peer && REaCt().createElement("li", {
- key: `${peer.clientId || ''}-${peer.userHandle}`
- }, REaCt().createElement(Participant, {
- call,
- mode,
- chatRoom,
- source: peer.userHandle ? peer : call.getLocalStream(),
- contact: M.u[peer.userHandle] || undefined,
- handle: peer.userHandle || u_handle,
- name: peer.name || M.getNameByHandle(u_handle),
- recorderCid,
- raisedHandPeers,
- onCallMinimize,
- onSpeakerChange,
- onModeChange
- }));
- let $$RAISED = [];
- for (const userHandle of call.sfuClient.raisedHands) {
- const peer = peers.find(p => (p.userHandle || p.localPeerStream.userHandle) === userHandle);
- $$RAISED = [...$$RAISED, $$PEER(peer)];
- }
- const $$REST = peers.filter(p => ![...call.sfuClient.raisedHands].includes(p.userHandle || p.localPeerStream.userHandle)).sort((a, b) => !!a.userHandle - !!b.userHandle).map(peer => $$PEER(peer));
- return REaCt().createElement("ul", null, $$RAISED, $$REST);
- };
- this.getChatParticipants = () => {
- const {
- chatRoom,
- initialCallRinging
- } = this.props;
- const {
- ringingPeers
- } = this.state;
- const callParticipants = Object.keys(chatRoom.uniqueCallParts);
- const chatParticipants = chatRoom.getParticipantsExceptMe().filter(h => !callParticipants.includes(h));
- if (chatParticipants != null && chatParticipants.length) {
- return REaCt().createElement(REaCt().Fragment, null, chatParticipants.length > 1 ? (() => {
- const isRingingAll = initialCallRinging || JSON.stringify(ringingPeers) === JSON.stringify(chatParticipants);
- return REaCt().createElement(meetings_button.A, {
- className: `
- mega-button
- action
- neutral
- call-control-all
- ${isRingingAll ? 'disabled' : ''}
- `,
- icon: "sprite-fm-mono phone-call-01",
- onClick: () => isRingingAll ? null : chatParticipants.map(handle => this.doCall(handle))
- }, l.call_all_button);
- })() : null, REaCt().createElement("ul", null, chatParticipants.map(handle => {
- const contact = M.u[handle];
- const isRinging = initialCallRinging || ringingPeers.includes(handle);
- return REaCt().createElement("li", {
- key: handle
- }, REaCt().createElement(ui_contacts.Avatar, {
- contact
- }), REaCt().createElement("div", {
- className: "name"
- }, REaCt().createElement(ui_contacts.ContactAwareName, {
- contact: M.u[handle],
- emoji: true
- }), REaCt().createElement("span", {
- className: `
- user-card-presence
- ${megaChat.userPresenceToCssClass(contact.presence)}
- `
- }), Call.isModerator(chatRoom, handle) && REaCt().createElement("span", null, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-admin-outline"
- })), REaCt().createElement("div", {
- className: "call-state"
- }, this.getCallState(handle))), isRinging ? null : REaCt().createElement("div", {
- className: "call-control"
- }, REaCt().createElement(meetings_button.A, {
- className: "mega-button action neutral",
- onClick: () => this.doCall(handle)
- }, l.call_button)));
- })));
- }
- return REaCt().createElement("div", {
- className: "participants-empty"
- }, REaCt().createElement("span", {
- className: "empty-check-icon"
- }), REaCt().createElement("h3", null, l.all_participants_in_call));
- };
- this.renderParticipantsList = () => {
- const {
- filter,
- raisedHandPeers
- } = this.state;
- return REaCt().createElement("div", {
- className: `
- participants-list
- ${filter === this.FILTER.IN_CALL ? '' : 'with-chat-participants'}
- ${this.props.guest ? 'guest' : ''}
- `
- }, REaCt().createElement(perfectScrollbar.O, {
- filter,
- raisedHandPeers,
- options: {
- 'suppressScrollX': true
- }
- }, filter === this.FILTER.IN_CALL ? this.getCallParticipants() : this.getChatParticipants()));
- };
- this.renderMuteAllControl = () => {
- const {
- allPeersMuted
- } = this.state;
- const simpletip = {
- label: l.mute_all_tooltip,
- position: 'top',
- className: 'theme-dark-forced'
- };
- return REaCt().createElement(meetings_button.A, {
- ref: this.muteRef,
- simpletip: allPeersMuted ? null : simpletip,
- className: `
- mega-button
- action
- ${this.NAMESPACE}-mute
- ${allPeersMuted ? 'disabled' : ''}
- `,
- icon: "sprite-fm-mono icon-mic-off-thin-outline",
- onClick: () => {
- let _this$muteRef, _muteRef$buttonRef;
- const muteRef = (_this$muteRef = this.muteRef) == null ? void 0 : _this$muteRef.current;
- const buttonRef = (_muteRef$buttonRef = muteRef.buttonRef) == null ? void 0 : _muteRef$buttonRef.current;
- return allPeersMuted ? null : this.setState({
- allPeersMuted: true
- }, () => {
- this.props.call.sfuClient.mutePeer();
- ChatToast.quick(l.you_muted_all_peers);
- if (buttonRef) {
- $(buttonRef).trigger('simpletipClose');
- }
- });
- }
- }, allPeersMuted ? l.all_muted : l.mute_all);
- };
- this.state.allPeersMuted = this.allPeersMuted;
- }
- componentWillUnmount() {
- super.componentWillUnmount();
- ['onCallPeerJoined', 'onPeerAvChange'].map(event => this.props.chatRoom.off(`${event}.${this.NAMESPACE}`));
- }
- componentDidMount() {
- super.componentDidMount();
- this.props.chatRoom.rebind(`onCallPeerJoined.${this.NAMESPACE}`, (ev, userHandle) => {
- const {
- noResponsePeers,
- ringingPeers
- } = this.state;
- this.setState({
- noResponsePeers: noResponsePeers.includes(userHandle) ? noResponsePeers.filter(h => h !== userHandle) : noResponsePeers,
- ringingPeers: ringingPeers.includes(userHandle) ? ringingPeers.filter(h => h !== userHandle) : ringingPeers
- });
- }).rebind(`onPeerAvChange.${this.NAMESPACE}`, () => this.isMounted() && this.setState({
- allPeersMuted: this.allPeersMuted
- }));
- }
- render() {
- const {
- IN_CALL,
- CHAT_PARTICIPANTS
- } = this.FILTER;
- const {
- withInvite,
- chatRoom,
- peers,
- onInviteToggle
- } = this.props;
- const {
- filter
- } = this.state;
- return REaCt().createElement("div", {
- ref: this.domRef,
- className: this.NAMESPACE
- }, chatRoom.type === 'private' ? null : REaCt().createElement("div", {
- className: `${this.NAMESPACE}-nav`
- }, REaCt().createElement(meetings_button.A, {
- className: filter === IN_CALL ? 'active' : '',
- onClick: () => this.setState({
- filter: IN_CALL
- })
- }, l.call_heading_in_call), REaCt().createElement(meetings_button.A, {
- className: filter === CHAT_PARTICIPANTS ? 'active' : '',
- onClick: () => this.setState({
- filter: CHAT_PARTICIPANTS
- })
- }, l.call_heading_not_in_call)), filter === IN_CALL ? REaCt().createElement(REaCt().Fragment, null, REaCt().createElement("div", {
- className: `${this.NAMESPACE}-actions`
- }, withInvite && REaCt().createElement(meetings_button.A, {
- className: `
- mega-button
- action
- ${this.NAMESPACE}-invite
- `,
- icon: "sprite-fm-mono icon-user-plus-thin-outline",
- onClick: onInviteToggle
- }, l[8726]), chatRoom.iAmOperator() && this.renderMuteAllControl()), REaCt().createElement(Collapse, (0,esm_extends.A)({}, this.props, {
- filter,
- heading: l[16217],
- badge: (peers == null ? void 0 : peers.length) + 1
- }), this.renderParticipantsList())) : this.renderParticipantsList());
- }
-}
-;// ./js/chat/ui/meetings/guest.jsx
-
-
-class Guest extends REaCt().Component {
- constructor(...args) {
- super(...args);
- this.state = {
- copy: ''
- };
- }
- componentDidMount() {
- this.setState({
- copy: `${l.free_storage_info__call.replace('%s', bytesToSize(mega.bstrg, 0))}`
- });
- }
- render() {
- const {
- copy
- } = this.state;
- return REaCt().createElement("div", {
- className: "guest-register"
- }, REaCt().createElement("div", {
- className: "guest-register-content"
- }, REaCt().createElement(meetings_button.A, {
- className: "close-guest-register",
- icon: "icon-close-component",
- onClick: this.props.onGuestClose
- }, REaCt().createElement("span", null, l[148])), REaCt().createElement("div", null, REaCt().createElement("i", {
- className: "sprite-fm-illustration-wide registration"
- }), REaCt().createElement("span", null, copy)), REaCt().createElement(meetings_button.A, {
- className: "mega-button positive register-button",
- onClick: () => loadSubPage('register')
- }, l.sign_up_btn)));
- }
-}
-;// ./js/chat/ui/meetings/sidebar.jsx
-
-
-
-
-
-
-
-
-const inviteAllowed = chatRoom => {
- if (chatRoom) {
- return chatRoom.type !== 'private' && !!(chatRoom.options[MCO_FLAGS.OPEN_INVITE] || Call.isModerator(chatRoom, u_handle) || chatRoom.publicLink);
- }
- return false;
-};
-class Sidebar extends mixins.w9 {
- constructor(...args) {
- super(...args);
- this.domRef = REaCt().createRef();
- this.historyPanel = null;
- this.renderHead = ({
- title,
- children
- }) => {
- return REaCt().createElement("div", {
- className: "sidebar-head"
- }, REaCt().createElement(meetings_button.A, {
- simpletip: {
- label: l.close_sidebar,
- className: 'theme-dark-forced'
- },
- className: "mega-button action small left",
- icon: "icon-collapse-right",
- onClick: this.props.onSidebarClose
- }, REaCt().createElement("span", null, l.close_sidebar)), REaCt().createElement("h2", null, title), children || null);
- };
- this.renderParticipantsView = () => {
- const {
- call,
- mode,
- peers,
- initialCallRinging,
- chatRoom,
- guest,
- recorderCid,
- raisedHandPeers,
- onInviteToggle,
- onCallMinimize,
- onSpeakerChange,
- onModeChange
- } = this.props;
- const withInvite = inviteAllowed(chatRoom);
- return REaCt().createElement(REaCt().Fragment, null, this.renderHead({
- title: l[16217]
- }), REaCt().createElement(Participants, {
- withInvite,
- call,
- mode,
- peers,
- initialCallRinging,
- chatRoom,
- guest,
- recorderCid,
- raisedHandPeers,
- onInviteToggle,
- onCallMinimize,
- onSpeakerChange,
- onModeChange
- }));
- };
- this.renderChatView = () => {
- const {
- chatRoom,
- typingAreaText,
- onDeleteMessage,
- onTypingAreaChanged
- } = this.props;
- return REaCt().createElement(REaCt().Fragment, null, this.renderHead({
- title: l.chats
- }), REaCt().createElement(historyPanel.A, {
- ref: ref => {
- this.historyPanel = ref;
- },
- chatRoom,
- className: "in-call",
- onDeleteClicked: onDeleteMessage
- }), REaCt().createElement(composedTextArea.A, {
- chatRoom,
- parent: this,
- containerRef: this.domRef,
- typingAreaText,
- onTypingAreaChanged
- }));
- };
- }
- render() {
- const {
- view,
- guest,
- onGuestClose
- } = this.props;
- return REaCt().createElement("div", {
- className: "sidebar-wrapper theme-dark-forced"
- }, REaCt().createElement("div", {
- ref: this.domRef,
- className: `
- sidebar
- ${view === VIEW.CHAT ? 'chat-opened' : 'theme-dark-forced'}
- `
- }, view === VIEW.PARTICIPANTS && this.renderParticipantsView(), view === VIEW.CHAT && this.renderChatView(), guest && view !== VIEW.CHAT && REaCt().createElement(Guest, {
- onGuestClose
- })));
- }
-}
-// EXTERNAL MODULE: ./js/ui/modalDialogs.jsx + 1 modules
-const modalDialogs = REQ_(318);
-;// ./js/chat/ui/meetings/workflow/invite/search.jsx
-let _Search;
-
-
-class Search extends REaCt().Component {
- render() {
- const {
- value,
- placeholder,
- onChange
- } = this.props;
- return REaCt().createElement("div", {
- className: `${Invite.NAMESPACE}-field`
- }, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-preview-reveal"
- }), REaCt().createElement("input", {
- type: "text",
- autoFocus: true,
- placeholder: l[23750].replace('[X]', placeholder),
- ref: Search.inputRef,
- value,
- onChange
- }));
- }
-}
-_Search = Search;
-Search.inputRef = REaCt().createRef();
-Search.focus = () => {
- return _Search.inputRef && _Search.inputRef.current && _Search.inputRef.current.focus();
-};
-;// ./js/chat/ui/meetings/workflow/invite/footer.jsx
-
-
-const Footer = ({
- selected,
- onClose,
- onAdd
-}) => {
- return REaCt().createElement("footer", null, REaCt().createElement("div", {
- className: "footer-container"
- }, REaCt().createElement(meetings_button.A, {
- className: "mega-button",
- onClick: onClose
- }, l.msg_dlg_cancel), REaCt().createElement(meetings_button.A, {
- className: `
- mega-button
- positive
- ${selected.length > 0 ? '' : 'disabled'}
- `,
- onClick: onAdd
- }, l.add)));
-};
-const footer = Footer;
-;// ./js/chat/ui/meetings/workflow/invite/nil.jsx
-
-
-const Nil = () => {
- return REaCt().createElement("div", {
- className: `${Invite.NAMESPACE}-nil`
- }, REaCt().createElement("div", {
- className: "fm-empty-contacts-bg"
- }), REaCt().createElement("h2", null, HAS_CONTACTS() ? l[8674] : l[784]));
-};
-const nil = Nil;
-// EXTERNAL MODULE: ./js/chat/ui/link.jsx
-const ui_link = REQ_(280);
-;// ./js/chat/ui/meetings/workflow/invite/invite.jsx
-
-
-
-
-
-
-
-
-
-
-
-const HAS_CONTACTS = () => {
- const keys = M.u.keys();
- for (let i = 0; i < keys.length; i++) {
- if (M.u[keys[i]].c === 1) {
- return true;
- }
- }
-};
-class Invite extends REaCt().Component {
- constructor(props) {
- super(props);
- this.domRef = REaCt().createRef();
- this.wrapperRef = REaCt().createRef();
- this.state = {
- loading: true,
- value: '',
- searching: false,
- contacts: [],
- contactsInitial: [],
- frequents: [],
- frequentsInitial: [],
- selected: [],
- excluded: [],
- input: false
- };
- this.getSortedContactsList = (frequents, excluded) => {
- frequents = frequents || this.state.frequents;
- excluded = excluded || this.state.excluded;
- const filteredContacts = [];
- (this.props.contacts || M.u).forEach(contact => {
- if (contact.c === 1 && !frequents.includes(contact.u) && !excluded.includes(contact.u)) {
- filteredContacts.push(contact);
- }
- });
- const sortFn = M.getSortByNameFn2(1);
- filteredContacts.sort((a, b) => sortFn(a, b));
- return filteredContacts;
- };
- this.doMatch = (value, collection) => {
- value = value.toLowerCase();
- return collection.filter(contact => {
- contact = typeof contact === 'string' ? M.getUserByHandle(contact) : contact;
- const name = M.getNameByHandle(contact.u || contact).toLowerCase();
- const email = contact.m && contact.m.toLowerCase();
- return name.includes(value) || email.includes(value);
- });
- };
- this.handleSearch = ev => {
- const {
- value
- } = ev.target;
- const searching = value.length >= 2;
- const frequents = searching ? this.doMatch(value, this.state.frequentsInitial) : this.state.frequentsInitial;
- const contacts = searching ? this.doMatch(value, this.state.contactsInitial) : this.state.contactsInitial;
- this.setState({
- value,
- searching,
- frequents,
- contacts
- }, () => {
- const wrapperRef = this.wrapperRef && this.wrapperRef.current;
- if (wrapperRef && searching) {
- wrapperRef.reinitialise();
- wrapperRef.scrollToY(0);
- }
- });
- };
- this.handleSelect = userHandle => {
- this.setState(state => ({
- selected: state.selected.includes(userHandle) ? state.selected.filter(c => c !== userHandle) : [...state.selected, userHandle]
- }), () => Search.focus());
- };
- this.handleAdd = () => {
- const {
- selected
- } = this.state;
- const {
- call,
- chatRoom,
- onClose
- } = this.props;
- if (selected.length > 0) {
- if (chatRoom.options.w) {
- let _call$sfuClient;
- call == null || (_call$sfuClient = call.sfuClient) == null || _call$sfuClient.wrAllowJoin(selected);
- }
- chatRoom == null || chatRoom.trigger('onAddUserRequest', [selected]);
- onClose == null || onClose();
- }
- };
- this.getFrequentContacts = () => megaChat.getFrequentContacts().then(response => {
- if (!this.domRef.current) {
- return;
- }
- const frequents = [];
- const maxFreq = Math.max(response.length - ui_contacts.MAX_FREQUENTS, 0);
- for (let i = response.length - 1; i >= maxFreq; i--) {
- const contact = response[i];
- if (!this.state.excluded.includes(contact.userId)) {
- frequents.push(contact.userId);
- }
- }
- this.setState({
- frequents,
- frequentsInitial: frequents,
- contacts: this.getSortedContactsList(frequents),
- loading: false
- });
- });
- this.getFilteredFrequents = () => {
- const {
- frequents,
- selected
- } = this.state;
- if (frequents.length === 0) {
- return false;
- }
- return frequents.map(userHandle => {
- return REaCt().createElement(ui_contacts.ContactCard, {
- key: userHandle,
- contact: M.u[userHandle],
- chatRoom: false,
- className: `
- contacts-search
- short
- ${selected.includes(userHandle) ? 'selected' : ''}
- `,
- noContextButton: true,
- noContextMenu: true,
- selectable: true,
- onClick: () => this.handleSelect(userHandle)
- });
- });
- };
- this.getFilteredContacts = () => {
- const {
- contacts,
- frequents,
- excluded,
- selected
- } = this.state;
- const $$CONTACTS = [];
- for (let i = 0; i < contacts.length; i++) {
- const contact = contacts[i];
- const {
- u: userHandle
- } = contact;
- if (!frequents.includes(userHandle) && !excluded.includes(userHandle)) {
- $$CONTACTS.push(REaCt().createElement(ui_contacts.ContactCard, {
- key: userHandle,
- contact,
- chatRoom: false,
- className: `
- contacts-search
- short
- ${selected.includes(userHandle) ? 'selected' : ''}
- `,
- noContextButton: true,
- noContextMenu: true,
- selectable: true,
- onClick: () => this.handleSelect(userHandle)
- }));
- }
- }
- return $$CONTACTS.length === 0 ? false : $$CONTACTS;
- };
- this.renderContent = () => {
- const frequentContacts = this.getFilteredFrequents();
- const contactsFiltered = this.getFilteredContacts();
- if (HAS_CONTACTS()) {
- const {
- contacts,
- frequents
- } = this.state;
- const $$RESULT_TABLE = (header, children) => REaCt().createElement("div", {
- className: "contacts-search-subsection"
- }, REaCt().createElement("div", {
- className: "contacts-list-header"
- }, header), REaCt().createElement("div", {
- className: "contacts-search-list"
- }, children));
- if (frequents.length === 0 && contacts.length === 0) {
- return REaCt().createElement(nil, null);
- }
- return REaCt().createElement(perfectScrollbar.O, {
- ref: this.wrapperRef,
- options: {
- 'suppressScrollX': true
- }
- }, frequentContacts ? $$RESULT_TABLE(l[20141], frequentContacts) : '', contactsFiltered ? $$RESULT_TABLE(l[165], contactsFiltered) : '');
- }
- return REaCt().createElement(nil, null);
- };
- this.renderLoading = () => {
- return REaCt().createElement("div", {
- className: `${Invite.NAMESPACE}-loading`
- }, REaCt().createElement("h2", null, l[1456]));
- };
- this.state.excluded = this.props.chatRoom ? this.props.chatRoom.getParticipantsExceptMe() : [];
- this.state.contacts = this.state.contactsInitial = this.getSortedContactsList();
- }
- componentDidMount() {
- this.getFrequentContacts();
- }
- render() {
- const {
- NAMESPACE
- } = Invite;
- const {
- value,
- loading,
- selected,
- contactsInitial
- } = this.state;
- const {
- chatRoom,
- call,
- onClose
- } = this.props;
- const {
- isMeeting,
- publicLink
- } = chatRoom || {};
- const callPartsLength = chatRoom.getCallParticipants().length;
- return REaCt().createElement(modalDialogs.A.ModalDialog, (0,esm_extends.A)({}, this.state, {
- ref: this.domRef,
- name: NAMESPACE,
- className: `
- ${NAMESPACE}
- dialog-template-tool
- `,
- callPartsLength,
- hideOverlay: true,
- onClose
- }), REaCt().createElement("div", {
- className: `${NAMESPACE}-head`
- }, REaCt().createElement("h2", null, isMeeting ? l.invite_participants : l[8726]), isMeeting && publicLink && REaCt().createElement(REaCt().Fragment, null, REaCt().createElement("p", null, l.copy_and_share), REaCt().createElement("div", {
- className: "link-input-container"
- }, REaCt().createElement(meetings_button.A, {
- className: `mega-button large positive ${publicLink ? '' : 'disabled'}`,
- onClick: () => publicLink && copyToClipboard(`${getBaseUrl()}/${publicLink}`, l[371])
- }, !publicLink ? l[7006] : l[1394]))), HAS_CONTACTS() && REaCt().createElement(Search, {
- value,
- placeholder: contactsInitial.length,
- onChange: this.handleSearch
- }), call.sfuClient.callLimits && call.sfuClient.callLimits.usr && callPartsLength >= call.sfuClient.callLimits.usr && REaCt().createElement("div", {
- className: `${NAMESPACE}-user-limit-banner`
- }, call.organiser === u_handle ? (0,utils.lI)(l.invite_limit_banner_organiser, '[A]', ui_link.A, {
- className: 'invite-limit-link',
- onClick() {
- window.open(`${getBaseUrl()}/pro`, '_blank', 'noopener,noreferrer');
- eventlog(500260);
- }
- }) : l.invite_limit_banner_host)), REaCt().createElement("div", {
- className: "fm-dialog-body"
- }, REaCt().createElement("div", {
- className: `${NAMESPACE}-contacts`
- }, loading ? this.renderLoading() : this.renderContent())), REaCt().createElement(footer, {
- selected,
- onAdd: this.handleAdd,
- onClose
- }));
- }
-}
-Invite.NAMESPACE = 'invite-meeting';
-;// ./js/chat/ui/meetings/workflow/ephemeral.jsx
-
-
-
-const Ephemeral = ({
- ephemeralAccounts,
- onClose
-}) => {
- const ephemeralAccount = ephemeralAccounts && ephemeralAccounts[ephemeralAccounts.length - 1];
- return REaCt().createElement(modalDialogs.A.ModalDialog, {
- name: "ephemeral-dialog",
- dialogType: "message",
- icon: "sprite-fm-uni icon-info",
- title: REaCt().createElement(ui_contacts.ContactAwareName, {
- emoji: true,
- contact: M.u[ephemeralAccount]
- }),
- noCloseOnClickOutside: true,
- buttons: [{
- key: 'ok',
- label: l[81],
- onClick: onClose
- }],
- onClose
- }, REaCt().createElement("p", null, l.ephemeral_info));
-};
-const workflow_ephemeral = Ephemeral;
-;// ./js/chat/ui/meetings/offline.jsx
-
-
-const Offline = ({
- onCallEnd,
- onClose
-}) => {
- return REaCt().createElement(modalDialogs.A.ModalDialog, {
- name: "reconnect-dialog",
- dialogType: "message",
- icon: "sprite-fm-uni icon-warning",
- title: l.no_internet,
- noCloseOnClickOutside: true,
- buttons: [{
- key: 'ok',
- label: l.msg_dlg_cancel,
- onClick: onClose
- }, {
- key: 'leave',
- label: l[5883],
- className: 'negative',
- onClick: onCallEnd
- }],
- onClose
- }, REaCt().createElement("p", null, l.no_connection));
-};
-const meetings_offline = Offline;
-// EXTERNAL MODULE: ./js/chat/ui/conversationpanel.jsx + 15 modules
-const conversationpanel = REQ_(438);
-// EXTERNAL MODULE: ./js/chat/ui/meetings/streamControls.jsx
-const streamControls = REQ_(489);
-;// ./js/chat/ui/meetings/sidebarControls.jsx
-
-
-
-const SidebarControls = ({
- npeers,
- view,
- sidebar,
- call,
- chatRoom,
- onChatToggle,
- onParticipantsToggle,
- onInviteToggle
-}) => {
- const notifications = chatRoom.getUnreadCount();
- const isOnHold = !!((call == null ? void 0 : call.av) & Av.onHold);
- const canInvite = chatRoom.type !== 'private' && !!(chatRoom.iAmOperator() || chatRoom.options[MCO_FLAGS.OPEN_INVITE] || chatRoom.publicLink);
- return REaCt().createElement("div", {
- className: "sidebar-controls"
- }, REaCt().createElement("ul", {
- className: isOnHold ? 'disabled' : ''
- }, canInvite && REaCt().createElement("li", {
- onClick: isOnHold ? null : onInviteToggle
- }, REaCt().createElement(meetings_button.A, {
- className: `
- mega-button
- theme-dark-forced
- call-action
- round
- `,
- icon: "icon-user-plus-thin-outline"
- }), REaCt().createElement("span", {
- className: "control-label"
- }, l[8726])), REaCt().createElement("li", {
- onClick: isOnHold ? null : onChatToggle
- }, REaCt().createElement(meetings_button.A, {
- className: `
- mega-button
- theme-dark-forced
- call-action
- round
- ${sidebar && view === VIEW.CHAT ? 'selected' : ''}
- ${isOnHold ? 'disabled' : ''}
- `,
- icon: sidebar && view === VIEW.CHAT ? 'icon-chat-filled' : 'icon-message-chat-circle-thin'
- }), REaCt().createElement("span", {
- className: "control-label"
- }, l.chat_call_button), notifications > 0 && REaCt().createElement("span", {
- className: "notification-badge notifications-count"
- }, notifications > 9 ? '9+' : notifications)), REaCt().createElement("li", {
- onClick: isOnHold ? null : onParticipantsToggle
- }, REaCt().createElement(meetings_button.A, {
- className: `
- mega-button
- theme-dark-forced
- call-action
- round
- ${sidebar && view === VIEW.PARTICIPANTS ? 'selected' : ''}
- ${isOnHold ? 'disabled' : ''}
- `,
- icon: sidebar && view === VIEW.PARTICIPANTS ? 'icon-users-thin-solid' : 'icon-users-thin-outline'
- }), REaCt().createElement("span", {
- className: "control-label"
- }, l.participants_call_button), REaCt().createElement("span", {
- className: `
- notification-badge
- participants-count
- theme-dark-forced
- ${npeers + 1 > 99 ? 'large' : ''}
- `
- }, npeers + 1))));
-};
-const sidebarControls = SidebarControls;
-// EXTERNAL MODULE: ./js/chat/ui/inviteParticipantsPanel.jsx
-const inviteParticipantsPanel = REQ_(815);
-// EXTERNAL MODULE: ./js/ui/dropdowns.jsx
-const dropdowns = REQ_(911);
-;// ./js/chat/ui/meetings/call.jsx
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-const NAMESPACE = 'meetings-call';
-const EXPANDED_FLAG = 'in-call';
-const MOUSE_OUT_DELAY = 2500;
-const MODE = {
- THUMBNAIL: 1,
- MAIN: 2,
- MINI: 3
-};
-const VIEW = {
- DEFAULT: 0,
- CHAT: 1,
- PARTICIPANTS: 2
-};
-const TYPE = {
- AUDIO: 1,
- VIDEO: 2
-};
-const isGuest = () => !u_type;
-const inProgressAlert = (isJoin, chatRoom) => {
- return new Promise((resolve, reject) => {
- if (megaChat.haveAnyActiveCall()) {
- if (window.sfuClient) {
- const {
- chatRoom: activeCallRoom
- } = megaChat.activeCall;
- const peers = activeCallRoom ? activeCallRoom.getParticipantsExceptMe(activeCallRoom.getCallParticipants()).map(h => M.getNameByHandle(h)) : [];
- let body = isJoin ? l.cancel_to_join : l.cancel_to_start;
- if (peers.length) {
- body = mega.utils.trans.listToString(peers, isJoin ? l.cancel_with_to_join : l.cancel_with_to_start);
- }
- msgDialog('warningb', null, l.call_in_progress, body, null, 1);
- return reject();
- }
- if (chatRoom.getCallParticipants().includes(u_handle)) {
- return resolve();
- }
- return msgDialog(`warningb:!^${l[2005]}!${isJoin ? l.join_call_anyway : l.start_call_anyway}`, null, isJoin ? l.join_multiple_calls_title : l.start_multiple_calls_title, isJoin ? l.join_multiple_calls_text : l.start_multiple_calls_text, join => {
- if (join) {
- return resolve();
- }
- return reject();
- }, 1);
- }
- resolve();
- });
-};
-window.inProgressAlert = inProgressAlert;
-class RecordingConsentDialog extends REaCt().Component {
- componentWillUnmount() {
- if ($.dialog && $.dialog === RecordingConsentDialog.dialogName) {
- closeDialog();
- }
- }
- render() {
- const {
- peers,
- recorderCid,
- onCallEnd,
- onClose
- } = this.props;
- const recordingPeer = peers[recorderCid];
- const recorderName = nicknames.getNickname(recordingPeer).substr(0, ChatToastIntegration.MAX_NAME_CHARS);
- return REaCt().createElement(modalDialogs.A.ModalDialog, {
- dialogName: RecordingConsentDialog.dialogName,
- className: `
- mega-dialog
- dialog-template-message
- info
- `,
- stopKeyPropagation: true,
- noCloseOnClickOutside: true
- }, REaCt().createElement("header", null, REaCt().createElement("div", {
- className: "graphic"
- }, REaCt().createElement("i", {
- className: "info sprite-fm-uni icon-info"
- })), REaCt().createElement("div", {
- className: "info-container"
- }, REaCt().createElement("h3", {
- id: "msgDialog-title"
- }, l.call_recorded_heading), REaCt().createElement("p", {
- className: "text"
- }, REaCt().createElement(utils.P9, null, l.call_recorded_body.replace('[A]', ``).replace('[/A]', ''))))), REaCt().createElement("footer", null, REaCt().createElement("div", {
- className: "footer-container"
- }, REaCt().createElement("div", {
- className: "space-between"
- }, REaCt().createElement(meetings_button.A, {
- className: "mega-button",
- onClick: onCallEnd
- }, REaCt().createElement("span", null, l[5883])), REaCt().createElement(meetings_button.A, {
- className: "mega-button positive",
- onClick: () => {
- onClose();
- ChatToast.quick(l.user_recording_toast.replace('%NAME', recorderName));
- }
- }, REaCt().createElement("span", null, l.ok_button))))));
- }
-}
-RecordingConsentDialog.dialogName = `${"meetings-call"}-consent`;
-class Call extends mixins.w9 {
- constructor(props) {
- super(props);
- this.domRef = REaCt().createRef();
- this.recordingConsentDialog = `${NAMESPACE}-consent`;
- this.ephemeralAddListener = undefined;
- this.delayProcID = null;
- this.pCallTimer = null;
- this.offlineDelayed = undefined;
- this.callStartTimeout = undefined;
- this.flagMap = attribCache.bitMapsManager.exists('obv4') ? attribCache.bitMapsManager.get('obv4') : undefined;
- this.timeoutBannerRef = REaCt().createRef();
- this.state = {
- mode: undefined,
- view: VIEW.PARTICIPANTS,
- sidebar: false,
- forcedLocal: false,
- hovered: false,
- invite: false,
- ephemeral: false,
- offline: false,
- ephemeralAccounts: [],
- everHadPeers: false,
- guest: isGuest(),
- waitingRoomPeers: [],
- raisedHandPeers: [],
- raisedHandToast: false,
- initialCallRinging: false,
- onboardingUI: false,
- onboardingRecording: false,
- onboardingRaise: false,
- recorderCid: undefined,
- recordingConsentDialog: false,
- recordingConsented: false,
- recordingActivePeer: undefined,
- recordingTooltip: false,
- invitePanel: false,
- presenterThumbSelected: false,
- timeoutBanner: false,
- showTimeoutUpgrade: false,
- activeElement: false
- };
- this.handleRetryTimeout = () => {
- const {
- call,
- chatRoom
- } = this.props;
- if ((call == null ? void 0 : call.sfuClient.connState) === SfuClient.ConnState.kDisconnectedRetrying) {
- this.handleCallEnd();
- chatRoom.trigger('onRetryTimeout');
- megaChat.playSound(megaChat.SOUNDS.CALL_END);
- }
- };
- this.handleCallOnline = () => {
- if (this.pCallTimer) {
- this.pCallTimer.abort();
- this.pCallTimer = null;
- }
- this.setState({
- offline: false,
- raisedHandPeers: [...this.props.call.sfuClient.raisedHands]
- });
- };
- this.customIsEventuallyVisible = () => true;
- this.renderRaisedHandToast = () => {
- const {
- raisedHandPeers
- } = this.state;
- window.toaster.main.hideAll();
- toaster.main.show({
- buttons: [{
- text: l[16797],
- onClick: () => this.setState({
- sidebar: true,
- view: VIEW.PARTICIPANTS,
- raisedHandToast: false
- }, () => window.toaster.main.hideAll())
- }],
- onClose: () => this.setState({
- raisedHandToast: false
- }, () => window.toaster.main.hideAll()),
- classes: ['theme-dark-forced', 'call-toast'],
- icons: ['sprite-fm-uni icon-raise-hand'],
- timeout: 0,
- content: (() => {
- const peerName = M.getNameByHandle(raisedHandPeers[0]);
- const peersCount = raisedHandPeers.length;
- const withCurrentPeer = raisedHandPeers.includes(u_handle);
- const CONTENT = {
- 1: () => l.raise_peer_raised.replace('%s', peerName),
- 2: () => {
- const message = withCurrentPeer ? l.raise_self_peers_raised : l.raise_two_raised;
- return mega.icu.format(message, peersCount - 1).replace('%s', peerName);
- },
- rest: () => {
- const message = withCurrentPeer ? l.raise_self_peers_raised : l.raise_peers_raised;
- return mega.icu.format(message, withCurrentPeer ? peersCount - 1 : peersCount);
- }
- };
- return (CONTENT[peersCount] || CONTENT.rest)();
- })()
- });
- };
- this.bindCallEvents = () => {
- const {
- chatRoom
- } = this.props;
- chatRoom.rebind(`onCallPeerLeft.${NAMESPACE}`, (ev, {
- userHandle,
- clientId
- }) => {
- const {
- minimized,
- peers,
- call,
- chatRoom
- } = this.props;
- if (clientId === this.state.recorderCid) {
- chatRoom.trigger('onRecordingStopped', {
- userHandle,
- clientId
- });
- }
- if (minimized) {
- this.setState({
- mode: peers.length === 0 ? MODE.THUMBNAIL : MODE.MINI
- }, () => {
- call.setViewMode(this.state.mode);
- });
- }
- });
- chatRoom.rebind(`onCallPeerJoined.${NAMESPACE}`, () => {
- const {
- minimized,
- peers,
- call
- } = this.props;
- if (minimized) {
- this.setState({
- mode: peers.length === 0 ? MODE.THUMBNAIL : MODE.MINI
- }, () => {
- call.setViewMode(this.state.mode);
- });
- }
- if (call.hasOtherParticipant()) {
- if (!this.state.everHadPeers) {
- this.setState({
- everHadPeers: true
- });
- }
- clearTimeout(this.callStartTimeout);
- }
- });
- chatRoom.rebind(`onCallLeft.${NAMESPACE}`, () => this.props.minimized && this.props.onCallEnd());
- chatRoom.rebind(`wrOnUsersEntered.${NAMESPACE}`, (ev, users) => Object.entries(users).forEach(([handle, host]) => {
- return host || this.state.waitingRoomPeers.includes(handle) ? null : this.isMounted() && this.setState({
- waitingRoomPeers: [...this.state.waitingRoomPeers, handle]
- }, () => {
- const {
- waitingRoomPeers
- } = this.state;
- if (waitingRoomPeers && waitingRoomPeers.length === 1) {
- megaChat.playSound(megaChat.SOUNDS.CALL_JOIN_WAITING);
- }
- mBroadcaster.sendMessage('meetings:peersWaiting', waitingRoomPeers);
- });
- }));
- const usrwr = (e, users) => {
- users = typeof users === 'string' ? [users] : users;
- return this.isMounted() && this.setState({
- waitingRoomPeers: this.state.waitingRoomPeers.filter(h => !users.includes(h))
- }, () => mBroadcaster.sendMessage('meetings:peersWaiting', this.state.waitingRoomPeers));
- };
- chatRoom.rebind(`wrOnUserLeft.${NAMESPACE}`, usrwr);
- chatRoom.rebind(`wrOnUsersAllow.${NAMESPACE}`, usrwr);
- chatRoom.rebind(`wrOnUserDump.${NAMESPACE}`, (ev, users) => Object.entries(users).forEach(([handle, host]) => {
- return host || this.state.waitingRoomPeers.includes(handle) ? null : this.isMounted() && this.setState({
- waitingRoomPeers: [...this.state.waitingRoomPeers, handle]
- });
- }));
- chatRoom.rebind(`onRecordingStarted.${NAMESPACE}`, (ev, {
- userHandle,
- clientId
- }) => {
- if (!this.state.recorderCid) {
- return this.state.recordingConsented ? this.setState({
- recorderCid: clientId
- }, () => {
- ChatToast.quick(l.user_recording_toast.replace('%NAME', nicknames.getNickname(userHandle).substr(0, ChatToastIntegration.MAX_NAME_CHARS)));
- }) : (() => {
- closeDialog();
- M.safeShowDialog(RecordingConsentDialog.dialogName, () => this.setState({
- recorderCid: clientId,
- recordingConsentDialog: true
- }));
- })();
- }
- });
- chatRoom.rebind(`onRecordingStopped.${NAMESPACE}`, (ev, {
- userHandle,
- clientId
- }) => {
- const {
- recorderCid
- } = this.state;
- this.setState({
- recordingConsentDialog: false,
- recorderCid: clientId === recorderCid ? false : recorderCid
- }, () => window.sfuClient && clientId === recorderCid && ChatToast.quick(l.user_recording_nop_toast.replace('%NAME', nicknames.getNickname(userHandle).substr(0, ChatToastIntegration.MAX_NAME_CHARS))));
- });
- chatRoom.rebind(`onMutedBy.${NAMESPACE}`, (ev, {
- cid
- }) => {
- megaChat.plugins.userHelper.getUserNickname(this.props.peers[cid]).catch(dump).always(name => {
- ChatToast.quick(l.muted_by.replace('%NAME', name || ''));
- });
- });
- chatRoom.rebind(`onCallEndTimeUpdated.${NAMESPACE}`, ({
- data
- }) => {
- this.setState({
- timeoutBanner: !!data,
- showTimeoutUpgrade: this.props.call.organiser === u_handle && data - Date.now() >= 120e3
- }, () => {
- if (this.state.timeoutBanner) {
- this.timeoutBannerInterval = this.timeoutBannerInterval || setInterval(() => this.updateTimeoutDuration(), 1000);
- } else {
- clearInterval(this.timeoutBannerInterval);
- delete this.timeoutBannerInterval;
- }
- });
- });
- chatRoom.rebind(`onRaisedHandAdd.${NAMESPACE}`, (ev, {
- userHandle
- }) => this.isMounted() && this.setState(state => ({
- raisedHandPeers: [...state.raisedHandPeers, userHandle]
- }), () => {
- const {
- raisedHandPeers
- } = this.state;
- if (userHandle !== u_handle && !this.props.minimized) {
- this.setState({
- raisedHandToast: true
- }, () => this.renderRaisedHandToast());
- }
- mBroadcaster.sendMessage('meetings:raisedHand', raisedHandPeers);
- }));
- chatRoom.rebind(`onRaisedHandDel.${NAMESPACE}`, (ev, {
- userHandle
- }) => this.isMounted() && this.setState(state => ({
- raisedHandPeers: state.raisedHandPeers.filter(h => h !== userHandle)
- }), () => {
- const {
- raisedHandPeers,
- raisedHandToast
- } = this.state;
- mBroadcaster.sendMessage('meetings:raisedHand', raisedHandPeers);
- if (raisedHandPeers && raisedHandPeers.length) {
- return raisedHandToast ? this.renderRaisedHandToast() : null;
- }
- return this.setState({
- raisedHandToast: false
- }, () => window.toaster.main.hideAll());
- }));
- chatRoom.rebind(`onRecordingActivePeer.${NAMESPACE}`, (ev, {
- userHandle
- }) => this.setState({
- recordingActivePeer: userHandle
- }));
- };
- this.unbindCallEvents = () => ['onCallPeerLeft', 'onCallPeerJoined', 'onCallLeft', 'wrOnUsersAllow', 'wrOnUsersEntered', 'wrOnUserLeft', 'alterUserPrivilege', 'onCallState', 'onRecordingStarted', 'onRecordingStopped', 'onRecordingActivePeer', 'onCallEndTimeUpdated', 'onRaisedHandAdd', 'onRaisedHandDel'].map(event => this.props.chatRoom.off(`${event}.${NAMESPACE}`));
- this.handleCallMinimize = () => {
- const {
- call,
- peers,
- onCallMinimize
- } = this.props;
- const {
- mode,
- sidebar,
- view
- } = this.state;
- const {
- callToutId,
- stayOnEnd,
- presenterStreams
- } = call;
- Call.STATE.PREVIOUS = mode !== MODE.MINI ? {
- mode,
- sidebar,
- view
- } : Call.STATE.PREVIOUS;
- const doMinimize = () => {
- onCallMinimize();
- window.toaster.main.hideAll();
- };
- mega.ui.mInfoPanel.hide();
- return peers.length > 0 || presenterStreams.has(u_handle) ? this.setState({
- mode: MODE.MINI,
- sidebar: false
- }, () => {
- doMinimize();
- call.setViewMode(MODE.MINI);
- }) : (() => {
- doMinimize();
- if (typeof callToutId !== 'undefined' && !stayOnEnd) {
- onIdle(() => call.showTimeoutDialog());
- }
- })();
- };
- this.handleCallExpand = async () => {
- mega.ui.mInfoPanel.hide();
- return new Promise(resolve => {
- this.setState({
- ...Call.STATE.PREVIOUS
- }, () => {
- this.props.onCallExpand();
- resolve();
- });
- });
- };
- this.handleStreamToggle = action => {
- const {
- peers
- } = this.props;
- if (action === stream.hK.ADD && peers.length === stream.$A) {
- return;
- }
- return action === stream.hK.ADD ? peers.addFakeDupStream() : peers.removeFakeDupStream();
- };
- this.handleSpeakerChange = (source, presenterThumbSelected) => {
- if (source) {
- this.handleModeChange(MODE.MAIN);
- const sourceId = source.isLocal ? 0 : source.clientId;
- if (sourceId !== this.props.call.pinnedCid) {
- this.props.call.setPinnedCid(sourceId);
- } else {
- this.props.call.setPinnedCid(sourceId, !source.hasScreen || presenterThumbSelected === this.state.presenterThumbSelected);
- }
- const {
- pinnedCid
- } = this.props.call;
- this.setState({
- forcedLocal: !!(source.isLocal && pinnedCid !== null),
- presenterThumbSelected: pinnedCid === null ? false : !!presenterThumbSelected && source.hasScreen
- });
- } else if (source === null) {
- this.setState({
- presenterThumbSelected: !!presenterThumbSelected
- });
- }
- };
- this.handleModeChange = mode => {
- this.props.call.setViewMode(mode);
- this.setState({
- mode,
- forcedLocal: false
- });
- };
- this.handleChatToggle = () => {
- if (this.state.sidebar && this.state.view === VIEW.CHAT) {
- return this.setState({
- ...Call.STATE.DEFAULT
- });
- }
- return this.setState({
- sidebar: true,
- view: VIEW.CHAT
- });
- };
- this.handleParticipantsToggle = forceOpen => {
- if (forceOpen !== true) {
- forceOpen = false;
- }
- if (this.state.sidebar && this.state.view === VIEW.CHAT) {
- return this.setState({
- sidebar: true,
- view: VIEW.PARTICIPANTS
- });
- }
- return this.setState({
- sidebar: forceOpen ? true : !this.state.sidebar,
- view: VIEW.PARTICIPANTS
- });
- };
- this.handleInviteToggle = () => {
- if (Object.values(M.u.toJS()).some(u => u.c === 1)) {
- const participants = (0,conversationpanel.zV)(this.props.chatRoom);
- if ((0,conversationpanel.e4)(participants)) {
- msgDialog(`confirmationa:!^${l[8726]}!${l.msg_dlg_cancel}`, null, `${l.all_contacts_added}`, `${l.all_contacts_added_to_chat}`, res => {
- if (res) {
- contactAddDialog(null, false);
- }
- });
- } else {
- this.setState({
- invite: !this.state.invite
- });
- }
- } else {
- msgDialog(`confirmationa:!^${l[8726]}!${l.msg_dlg_cancel}`, null, `${l.no_contacts}`, `${l.no_contacts_text}`, resp => {
- if (resp) {
- contactAddDialog(null, false);
- }
- });
- }
- };
- this.handleHoldToggle = async () => {
- await this.props.call.toggleHold();
- mBroadcaster.sendMessage('meetings:toggleHold');
- };
- this.handleScreenSharingToggle = () => {
- const {
- call
- } = this.props;
- const userAgent = navigator.userAgent.match(/Chrom(e|ium)\/(\d+)\./);
- const version = parseInt(userAgent[2], 10);
- if (version === 92) {
- return msgDialog('info', undefined, l[47], l.chrome_screensharing);
- }
- return call.toggleScreenSharing();
- };
- this.handleCallEnd = () => {
- let _this$props$call;
- mega.ui.mInfoPanel.hide();
- (_this$props$call = this.props.call) == null || _this$props$call.destroy(SfuClient.TermCode.kUserHangup);
- };
- this.handleEphemeralAdd = handle => handle && this.setState(state => ({
- ephemeral: true,
- ephemeralAccounts: [...state.ephemeralAccounts, handle]
- }));
- this.handleStayConfirm = () => {
- const {
- call
- } = this.props;
- call.handleStayConfirm();
- onIdle(() => this.safeForceUpdate());
- };
- this.handleRecordingToggle = () => {
- const {
- call,
- chatRoom
- } = this.props;
- if (chatRoom.isMeeting) {
- eventlog(500286);
- } else {
- eventlog(500287);
- }
- if (this.state.recorderCid) {
- return msgDialog(`confirmation:!^${l.stop_recording_dialog_cta}!${l.stop_recording_nop_dialog_cta}`, undefined, l.stop_recording_dialog_heading, l.stop_recording_dialog_body, cb => cb && sfuClient.recordingStop(), 1);
- }
- msgDialog(`warningb:!^${l.start_recording_dialog_cta}!${l.msg_dlg_cancel}`, null, l.notify_participants_dialog_heading, l.notify_participants_dialog_body, cb => {
- if (cb || cb === null) {
- return;
- }
- call.sfuClient.recordingStart(this.onWeStoppedRecording).then(() => {
- call.recorderCid = this.state.recorderCid;
- this.setState({
- recorderCid: call.sfuClient.cid
- });
- this.handleModeChange(MODE.MAIN);
- call.recordActiveStream();
- ChatToast.quick(l.started_recording_toast);
- }).catch(dump);
- }, 1);
- };
- this.onWeStoppedRecording = err => this.isMounted() && this.setState({
- recorderCid: undefined,
- recordingActivePeer: undefined
- }, () => err ? ChatToast.quick(`${l.stopped_recording_toast} Error: ${err.message || err}`) : ChatToast.quick(l.stopped_recording_toast));
- this.renderRecordingControl = () => {
- const {
- chatRoom,
- call,
- peers
- } = this.props;
- const {
- recorderCid,
- recordingTooltip,
- recordingActivePeer
- } = this.state;
- const isModerator = Call.isModerator(chatRoom, u_handle);
- const $$CONTAINER = ({
- className,
- onClick,
- children
- }) => REaCt().createElement("div", {
- className: `
- recording-control
- ${localStorage.callDebug ? 'with-offset' : ''}
- ${className || ''}
- `,
- onClick
- }, children);
- if (recorderCid) {
- const isRecorder = isModerator && recorderCid === call.sfuClient.cid;
- const recordingPeer = peers[recorderCid];
- return REaCt().createElement($$CONTAINER, {
- recordingTooltip,
- className: "recording-fixed"
- }, REaCt().createElement("div", (0,esm_extends.A)({
- className: `
- recording-ongoing
- simpletip
- ${isRecorder ? '' : 'plain-background'}
- `
- }, recorderCid !== call.sfuClient.cid && {
- 'data-simpletip': l.host_recording.replace('%NAME', nicknames.getNickname(recordingPeer) || megaChat.plugins.userHelper.SIMPLETIP_USER_LOADER),
- 'data-simpletipposition': 'top',
- 'data-simpletipoffset': 5,
- 'data-simpletip-class': 'theme-dark-forced'
- }), REaCt().createElement("span", {
- className: `
- recording-icon
- button
- ${recordingTooltip ? 'active-dropdown' : ''}
- ${isRecorder ? 'clickable' : ''}
- `,
- onMouseEnter: () => isRecorder && this.setState({
- recordingTooltip: true
- }),
- onMouseOut: () => isRecorder && delay('meetings-rec-hover', () => this.setState({
- recordingTooltip: false
- }), 1250)
- }, "REC ", REaCt().createElement("i", null), REaCt().createElement(dropdowns.Dropdown, {
- className: "recording-info theme-dark-forced",
- active: recordingTooltip,
- noArrow: false,
- positionMy: "center top",
- positionAt: "center bottom",
- vertOffset: 40,
- horizOffset: 30
- }, REaCt().createElement("div", null, "Currently recording: ", nicknames.getNickname(recordingActivePeer)))), isRecorder && REaCt().createElement("span", {
- className: "recording-toggle",
- onClick: this.handleRecordingToggle
- }, l.record_stop_button)));
- }
- const isOnHold = !!((call == null ? void 0 : call.av) & Av.onHold);
- return isModerator && REaCt().createElement($$CONTAINER, {
- className: isOnHold ? 'disabled' : '',
- onClick: () => {
- this.setState({
- onboardingRecording: false,
- hovered: false
- }, () => {
- this.flagMap.setSync(OBV4_FLAGS.CHAT_CALL_RECORDING, 1);
- this.flagMap.safeCommit();
- });
- return isOnHold || recorderCid && recorderCid !== call.sfuClient.cid ? null : this.handleRecordingToggle();
- }
- }, REaCt().createElement(meetings_button.A, {
- className: `
- mega-button
- theme-dark-forced
- call-action
- round
- recording-start
- ${isOnHold ? 'disabled' : ''}
- `
- }, REaCt().createElement("div", null, REaCt().createElement("i", null))), REaCt().createElement("span", {
- className: "record-label"
- }, l.record_start_button));
- };
- this.setActiveElement = activeElement => this.setState({
- activeElement
- });
- const {
- SOUNDS
- } = megaChat;
- [SOUNDS.RECONNECT, SOUNDS.CALL_END, SOUNDS.CALL_JOIN_WAITING].map(sound => ion.sound.preload(sound));
- this.state.mode = props.call.viewMode;
- this.setOnboarding();
- this.handleMouseMove = this.handleMouseMove.bind(this);
- this.handleMouseOut = this.handleMouseOut.bind(this);
- }
- handleMouseMove() {
- this.setState({
- hovered: true
- });
- if (this.delayProcID) {
- delay.cancel(this.delayProcID);
- this.delayProcID = null;
- }
- }
- handleMouseOut() {
- if (this.state.hovered) {
- this.delayProcID = delay('meetings-call-hover', () => {
- if (this.isMounted()) {
- this.setState({
- hovered: false
- });
- }
- }, MOUSE_OUT_DELAY);
- }
- }
- handleCallOffline() {
- if (!this.pCallTimer) {
- (this.pCallTimer = tSleep(30)).then(() => {
- this.setState({
- offline: true
- });
- });
- }
- }
- setOnboarding() {
- this.state.onboardingUI = this.state.hovered = this.flagMap && !this.flagMap.getSync(OBV4_FLAGS.CHAT_CALL_UI);
- if (!this.state.onboardingUI) {
- this.state.onboardingRecording = this.state.hovered = this.flagMap && !this.flagMap.getSync(OBV4_FLAGS.CHAT_CALL_RECORDING);
- }
- if (!this.state.onboardingUI && !this.state.onboardingRecording) {
- this.state.onboardingRaise = this.state.hovered = this.flagMap && !this.flagMap.getSync(OBV4_FLAGS.CHAT_CALL_RAISE);
- }
- }
- handleInvitePanelToggle() {
- delay('chat-event-inv-call', () => eventlog(99962));
- this.setState({
- invitePanel: !this.state.invitePanel
- });
- }
- handleInviteOrAdd() {
- const {
- chatRoom
- } = this.props;
- if (chatRoom.type === 'group') {
- return this.handleInviteToggle();
- }
- loadingDialog.show('fetchchatlink');
- chatRoom.updatePublicHandle(false, false, true).catch(dump).always(() => {
- loadingDialog.hide('fetchchatlink');
- if (!this.isMounted()) {
- return;
- }
- if (!chatRoom.iAmOperator() && chatRoom.options[MCO_FLAGS.OPEN_INVITE] && !chatRoom.publicLink) {
- this.handleInviteToggle();
- } else if (chatRoom.type === 'public' && !chatRoom.topic) {
- this.handleInviteToggle();
- } else {
- this.handleInvitePanelToggle();
- }
- });
- }
- renderTimeLimitBanner() {
- return REaCt().createElement("div", {
- className: "call-time-limit-banner theme-dark-forced"
- }, REaCt().createElement("span", {
- ref: this.timeoutBannerRef
- }, this.timeoutString), REaCt().createElement("span", {
- className: "call-limit-banner-action",
- onClick: () => {
- clearInterval(this.timeoutBannerInterval);
- delete this.timeoutBannerInterval;
- this.setState({
- timeoutBanner: false
- });
- }
- }, l[2005]), this.state.showTimeoutUpgrade && REaCt().createElement(ui_link.A, {
- className: "call-limit-banner-action",
- onClick: () => {
- window.open(`${getBaseUrl()}/pro`, '_blank', 'noopener,noreferrer');
- eventlog(500262);
- }
- }, l.upgrade_now));
- }
- get timeoutString() {
- const {
- call
- } = this.props;
- if (call.callEndTime === 0) {
- return '';
- }
- const remainSeconds = Math.max(0, Math.ceil((call.callEndTime - Date.now()) / 1000));
- if (call.organiser === u_handle) {
- if (remainSeconds < 60) {
- return mega.icu.format(l.free_call_banner_organiser_ending_sec, remainSeconds);
- }
- if (remainSeconds <= 120) {
- return mega.icu.format(l.free_call_banner_organiser_ending, Math.ceil(remainSeconds / 60));
- }
- return mega.icu.format(l.free_call_banner_organiser_warning, Math.ceil(remainSeconds / 60));
- }
- if (remainSeconds < 60) {
- return mega.icu.format(l.free_call_banner_ending_sec, remainSeconds);
- }
- if (remainSeconds <= 120) {
- return mega.icu.format(l.free_call_banner_ending, Math.ceil(remainSeconds / 60));
- }
- return mega.icu.format(l.free_call_banner_warning, Math.ceil(remainSeconds / 60));
- }
- updateTimeoutDuration() {
- if (this.timeoutBannerRef) {
- const {
- current
- } = this.timeoutBannerRef;
- const newStr = this.timeoutString;
- if (newStr && current && current.innerText !== newStr) {
- current.innerText = newStr;
- }
- if (this.state.showTimeoutUpgrade && this.props.call.callEndTime - Date.now() <= 12e4) {
- this.setState({
- showTimeoutUpgrade: false
- });
- }
- }
- }
- componentWillUnmount() {
- super.componentWillUnmount();
- const {
- minimized,
- willUnmount,
- chatRoom
- } = this.props;
- chatRoom.megaChat.off(`sfuConnClose.${NAMESPACE}`);
- chatRoom.megaChat.off(`sfuConnOpen.${NAMESPACE}`);
- chatRoom.megaChat.off(`onSpeakerChange.${NAMESPACE}`);
- chatRoom.megaChat.off(`onPeerAvChange.${NAMESPACE}`);
- mBroadcaster.removeListener(this.ephemeralAddListener);
- mBroadcaster.removeListener(this.pageChangeListener);
- clearTimeout(this.callStartTimeout);
- delay.cancel('callOffline');
- if ($.dialog) {
- closeDialog();
- }
- if (this.timeoutBannerInterval) {
- clearInterval(this.timeoutBannerInterval);
- }
- window.toaster.main.hideAll();
- this.unbindCallEvents();
- willUnmount == null || willUnmount(minimized);
- }
- componentDidMount() {
- super.componentDidMount();
- const {
- call,
- didMount,
- chatRoom
- } = this.props;
- this.ephemeralAddListener = mBroadcaster.addListener('meetings:ephemeralAdd', handle => this.handleEphemeralAdd(handle));
- this.pageChangeListener = mBroadcaster.addListener('pagechange', () => {
- const currentRoom = megaChat.getCurrentRoom();
- if (Call.isExpanded() && (!M.chat || currentRoom && currentRoom.chatId !== chatRoom.chatId)) {
- this.handleCallMinimize();
- }
- });
- chatRoom.megaChat.rebind(`sfuConnOpen.${NAMESPACE}`, () => this.handleCallOnline());
- chatRoom.megaChat.rebind(`sfuConnClose.${NAMESPACE}`, () => this.handleCallOffline());
- chatRoom.rebind(`onCallState.${NAMESPACE}`, (ev, {
- arg
- }) => this.setState({
- initialCallRinging: arg
- }));
- const {
- tresizer
- } = $;
- chatRoom.rebind(`onPeerAvChange.${NAMESPACE}`, tresizer);
- chatRoom.rebind(`onSpeakerChange.${NAMESPACE}`, tresizer);
- this.callStartTimeout = setTimeout(() => {
- if (!mega.config.get('callemptytout') && !call.hasOtherParticipant()) {
- call.left = true;
- call.initCallTimeout();
- }
- }, 300000);
- setTimeout(() => {
- let _call$peers;
- return ((_call$peers = call.peers) == null ? void 0 : _call$peers.length) && !call.hasOtherParticipant() && this.setState({
- everHadPeers: true
- });
- }, 2e3);
- if (sessionStorage.previewMedia) {
- const {
- audio,
- video
- } = JSON.parse(sessionStorage.previewMedia);
- sessionStorage.removeItem('previewMedia');
- tSleep(2).then(() => audio && call.sfuClient.muteAudio()).then(() => video && call.sfuClient.muteCamera()).catch(dump);
- }
- this.bindCallEvents();
- didMount == null || didMount();
- }
- componentDidUpdate() {
- if (typeof psa !== 'undefined') {
- psa.repositionMeetingsCall();
- }
- }
- render() {
- let _ref;
- const {
- minimized,
- peers,
- call,
- chatRoom,
- parent,
- typingAreaText,
- onDeleteMessage,
- onTypingAreaChanged
- } = this.props;
- const {
- mode,
- view,
- sidebar,
- hovered,
- forcedLocal,
- invite,
- ephemeral,
- ephemeralAccounts,
- guest,
- offline,
- onboardingUI,
- onboardingRecording,
- onboardingRaise,
- everHadPeers,
- initialCallRinging,
- waitingRoomPeers,
- recorderCid,
- raisedHandPeers,
- recordingConsentDialog,
- invitePanel,
- presenterThumbSelected,
- timeoutBanner,
- activeElement
- } = this.state;
- const {
- stayOnEnd
- } = call;
- const hasOnboarding = onboardingUI || onboardingRecording || onboardingRaise;
- const STREAM_PROPS = {
- mode,
- peers,
- sidebar,
- hovered: hasOnboarding || hovered,
- forcedLocal,
- call,
- view,
- chatRoom,
- parent,
- stayOnEnd,
- everHadPeers,
- waitingRoomPeers,
- recorderCid,
- presenterThumbSelected,
- raisedHandPeers,
- activeElement,
- hasOtherParticipants: call.hasOtherParticipant(),
- isOnHold: call.sfuClient.isOnHold,
- isFloatingPresenter: (_ref = mode === MODE.MINI && !forcedLocal ? call.getActiveStream() : call.getLocalStream()) == null ? void 0 : _ref.hasScreen,
- onSpeakerChange: this.handleSpeakerChange,
- onModeChange: this.handleModeChange,
- onInviteToggle: this.handleInviteToggle,
- onStayConfirm: this.handleStayConfirm
- };
- return REaCt().createElement("div", {
- ref: this.domRef,
- className: `
- meetings-call
- ${minimized ? 'minimized' : ''}
- ${timeoutBanner ? 'with-timeout-banner' : ''}
- ${activeElement ? 'with-active-element' : ''}
- `,
- onMouseMove: hasOnboarding ? null : this.handleMouseMove,
- onMouseOut: hasOnboarding ? null : this.handleMouseOut
- }, timeoutBanner && this.renderTimeLimitBanner(), REaCt().createElement(stream.Ay, (0,esm_extends.A)({}, STREAM_PROPS, {
- minimized,
- ephemeralAccounts,
- onCallMinimize: this.handleCallMinimize,
- onCallExpand: this.handleCallExpand,
- onCallEnd: this.handleCallEnd,
- onStreamToggle: this.handleStreamToggle,
- onRecordingToggle: () => call.sfuClient.recordingStop(),
- onChatToggle: this.handleChatToggle,
- onParticipantsToggle: this.handleParticipantsToggle,
- onAudioClick: () => call.toggleAudio(),
- onVideoClick: () => call.toggleVideo(),
- onScreenSharingClick: this.handleScreenSharingToggle,
- onHoldClick: this.handleHoldToggle,
- onVideoDoubleClick: this.handleSpeakerChange,
- setActiveElement: this.setActiveElement
- })), sidebar && REaCt().createElement(Sidebar, (0,esm_extends.A)({}, STREAM_PROPS, {
- guest,
- initialCallRinging,
- typingAreaText,
- onGuestClose: () => this.setState({
- guest: false
- }),
- onSidebarClose: () => this.setState({
- ...Call.STATE.DEFAULT
- }),
- onDeleteMessage,
- onCallMinimize: this.handleCallMinimize,
- onInviteToggle: () => this.handleInviteOrAdd(),
- onTypingAreaChanged
- })), minimized ? null : REaCt().createElement(REaCt().Fragment, null, this.renderRecordingControl(), REaCt().createElement(streamControls.Ay, {
- call,
- minimized,
- peers,
- chatRoom,
- recorderCid,
- hovered,
- raisedHandPeers,
- onboardingRaise,
- onOnboardingRaiseDismiss: () => {
- this.setState({
- onboardingRaise: false,
- hovered: false
- }, () => {
- this.flagMap.setSync(OBV4_FLAGS.CHAT_CALL_RAISE, 1);
- this.flagMap.safeCommit();
- });
- },
- onRecordingToggle: () => this.setState({
- recorderCid: undefined
- }, () => call.sfuClient.recordingStop()),
- onAudioClick: () => call.toggleAudio(),
- onVideoClick: () => call.toggleVideo(),
- onScreenSharingClick: this.handleScreenSharingToggle,
- onCallEnd: this.handleCallEnd,
- onStreamToggle: this.handleStreamToggle,
- onHoldClick: this.handleHoldToggle,
- setActiveElement: this.setActiveElement
- }), REaCt().createElement(sidebarControls, {
- call,
- chatRoom,
- npeers: peers.length,
- mode,
- view,
- sidebar,
- onChatToggle: this.handleChatToggle,
- onParticipantsToggle: this.handleParticipantsToggle,
- onInviteToggle: () => this.handleInviteOrAdd()
- })), invite && REaCt().createElement(Invite, {
- contacts: M.u,
- call,
- chatRoom,
- onClose: () => this.setState({
- invite: false
- })
- }), ephemeral && REaCt().createElement(workflow_ephemeral, {
- ephemeralAccounts,
- onClose: () => this.setState({
- ephemeral: false
- })
- }), offline && REaCt().createElement(meetings_offline, {
- onClose: () => {
- if (offline) {
- this.setState({
- offline: false
- }, () => delay('call:timeout', this.handleRetryTimeout, 3e4));
- }
- },
- onCallEnd: () => {
- this.setState({
- offline: false
- }, () => this.handleRetryTimeout());
- }
- }), onboardingUI && REaCt().createElement("div", {
- className: `${NAMESPACE}-onboarding`
- }, REaCt().createElement("div", {
- className: "mega-dialog mega-onboarding-dialog dialog-template-message onboarding-UI",
- id: "ob-dialog",
- role: "dialog",
- "aria-labelledby": "ob-dialog-title",
- "aria-modal": "true"
- }, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-tooltip-arrow tooltip-arrow top",
- id: "ob-dialog-arrow"
- }), REaCt().createElement("header", null, REaCt().createElement("div", null, REaCt().createElement("h2", {
- id: "ob-dialog-title"
- }, l.onboarding_call_title), REaCt().createElement("p", {
- id: "ob-dialog-text"
- }, l.onboarding_call_body))), REaCt().createElement("footer", null, REaCt().createElement("div", {
- className: "footer-container"
- }, REaCt().createElement("button", {
- className: "mega-button js-next small theme-light-forced",
- onClick: () => {
- this.setState({
- onboardingUI: false,
- onboardingRecording: chatRoom.iAmOperator() && !this.flagMap.getSync(OBV4_FLAGS.CHAT_CALL_RECORDING)
- }, () => {
- this.flagMap.setSync(OBV4_FLAGS.CHAT_CALL_UI, 1);
- this.flagMap.safeCommit();
- this.setState({
- onboardingRaise: !this.state.onboardingRecording && !this.flagMap.getSync(OBV4_FLAGS.CHAT_CALL_RAISE)
- });
- });
- }
- }, REaCt().createElement("span", null, l.ok_button)))))), onboardingRecording && Call.isModerator(chatRoom, u_handle) && REaCt().createElement("div", {
- className: `${NAMESPACE}-onboarding`
- }, REaCt().createElement("div", {
- className: "mega-dialog mega-onboarding-dialog dialog-template-message onboarding-recording",
- id: "ob-dialog",
- role: "dialog",
- "aria-labelledby": "ob-dialog-title",
- "aria-modal": "true"
- }, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-tooltip-arrow tooltip-arrow bottom",
- id: "ob-dialog-arrow"
- }), REaCt().createElement("header", null, REaCt().createElement("div", null, REaCt().createElement("h2", {
- id: "ob-dialog-title"
- }, l.recording_onboarding_title), REaCt().createElement("p", {
- id: "ob-dialog-text"
- }, l.recording_onboarding_body_intro), REaCt().createElement("p", {
- id: "ob-dialog-text"
- }, l.recording_onboarding_body_details))), REaCt().createElement("footer", null, REaCt().createElement("div", {
- className: "footer-container"
- }, REaCt().createElement(ui_link.A, {
- className: "link-button",
- to: "https://help.mega.io/chats-meetings/chats/call-recording",
- target: "_blank"
- }, l[8742]), REaCt().createElement("button", {
- className: "mega-button js-next small theme-light-forced",
- onClick: () => {
- this.setState({
- onboardingRecording: false,
- onboardingRaise: true
- }, () => {
- this.flagMap.setSync(OBV4_FLAGS.CHAT_CALL_RECORDING, 1);
- this.flagMap.safeCommit();
- });
- }
- }, REaCt().createElement("span", null, l.ok_button)))))), recordingConsentDialog && REaCt().createElement(RecordingConsentDialog, {
- peers,
- recorderCid,
- onClose: () => this.setState({
- recordingConsentDialog: false,
- recordingConsented: true
- }),
- onCallEnd: this.handleCallEnd
- }), invitePanel && REaCt().createElement(modalDialogs.A.ModalDialog, {
- className: "theme-dark-forced",
- onClose: () => {
- this.setState({
- invitePanel: false
- });
- },
- dialogName: "chat-link-dialog",
- chatRoom
- }, REaCt().createElement(inviteParticipantsPanel.Q, {
- chatRoom,
- onAddParticipants: () => {
- this.setState({
- invitePanel: false
- }, () => this.handleInviteToggle());
- }
- })));
- }
-}
-Call.STATE = {
- DEFAULT: {
- sidebar: false
- },
- PREVIOUS: {
- mode: null,
- sidebar: null,
- view: null
- }
-};
-Call.isModerator = (chatRoom, handle) => {
- if (chatRoom && handle) {
- return chatRoom.members[handle] === ChatRoom.MembersSet.PRIVILEGE_STATE.OPERATOR;
- }
- return false;
-};
-Call.isExpanded = () => document.body.classList.contains(EXPANDED_FLAG);
-Call.getUnsupportedBrowserMessage = () => navigator.userAgent.match(/Chrom(e|ium)\/(\d+)\./) ? l.alert_unsupported_browser_version : l.alert_unsupported_browser;
-
-},
-
-972
-(_, EXP_, REQ_) {
-
-"use strict";
-REQ_.d(EXP_, {
-C: () => withHostsObserver
-});
-const _extends0__ = REQ_(168);
-const react1__ = REQ_(594);
-const react1 = REQ_.n(react1__);
-const _mixins_js2__ = REQ_(137);
-const _ui_modalDialogs_jsx3__ = REQ_(318);
-const _contacts_jsx4__ = REQ_(251);
-const _ui_buttons_jsx5__ = REQ_(994);
-
-
-
-
-
-
-const withHostsObserver = Component => {
- return class extends _mixins_js2__.w9 {
- constructor(...args) {
- super(...args);
- this.state = {
- dialog: false,
- selected: []
- };
- this.hasHost = participants => participants.some(handle => this.props.chatRoom.members[handle] === ChatRoom.MembersSet.PRIVILEGE_STATE.OPERATOR);
- this.toggleDialog = () => {
- this.setState(state => ({
- dialog: !state.dialog,
- selected: []
- }), () => this.safeForceUpdate());
- };
- this.renderDialog = () => {
- let _this$props$participa;
- const {
- selected
- } = this.state;
- return react1().createElement(_ui_modalDialogs_jsx3__.A.ModalDialog, (0,_extends0__.A)({}, this.state, {
- className: "assign-host contact-picker-widget",
- dialogName: "assign-host-dialog",
- dialogType: "tool",
- onClose: () => this.setState({
- dialog: false
- }, () => this.safeForceUpdate())
- }), react1().createElement("header", null, react1().createElement("h2", null, l.assign_host_title)), react1().createElement("div", {
- className: "content-block"
- }, react1().createElement(_contacts_jsx4__.ContactPickerWidget, {
- className: "popup contacts-search small-footer",
- contacts: (_this$props$participa = this.props.participants) == null ? void 0 : _this$props$participa.filter(h => h !== u_handle),
- multiple: true,
- hideSearch: true,
- disableFrequents: true,
- participantsList: true,
- disableDoubleClick: true,
- emailTooltips: true,
- nothingSelectedButtonLabel: l.add_hosts_placeholder,
- onClose: () => this.setState({
- dialog: false
- }),
- onSelected: selected => this.setState({
- selected
- }, () => this.safeForceUpdate())
- })), react1().createElement("footer", null, react1().createElement("div", {
- className: "footer-container"
- }, react1().createElement(_ui_buttons_jsx5__.$, {
- label: l.msg_dlg_cancel,
- className: "mega-button",
- onClick: this.toggleDialog
- }), react1().createElement(_ui_buttons_jsx5__.$, {
- label: l.assign_and_leave,
- className: `
- mega-button
- positive
- ${selected.length ? '' : 'disabled'}
- `,
- onClick: () => selected.length && this.assignAndLeave()
- }))));
- };
- this.assignAndLeave = () => {
- const {
- chatRoom,
- onLeave
- } = this.props;
- const {
- selected
- } = this.state;
- for (let i = selected.length; i--;) {
- chatRoom.trigger('alterUserPrivilege', [selected[i], ChatRoom.MembersSet.PRIVILEGE_STATE.OPERATOR]);
- }
- this.toggleDialog();
- onLeave == null || onLeave();
- $(document).trigger('closeDropdowns');
- };
- this.confirmLeave = ({
- title,
- body,
- cta,
- altCta
- }) => {
- msgDialog(`confirmationa:!^${cta}!${altCta || l.msg_dlg_cancel}`, null, title, body, cb => {
- if (cb) {
- this.toggleDialog();
- } else if (cb === false) {
- let _this$props$onConfirm, _this$props;
- (_this$props$onConfirm = (_this$props = this.props).onConfirmDenied) == null || _this$props$onConfirm.call(_this$props);
- }
- }, 1);
- };
- }
- render() {
- return react1().createElement(react1().Fragment, null, react1().createElement(Component, (0,_extends0__.A)({}, this.props, {
- confirmLeave: this.confirmLeave,
- hasHost: this.hasHost
- })), this.state.dialog && this.renderDialog());
- }
- };
-};
-
-},
-
-772
-(_, EXP_, REQ_) {
-
-"use strict";
-REQ_.d(EXP_, {
-Q: () => withMicObserver
-});
-const _extends0__ = REQ_(168);
-const react1__ = REQ_(594);
-const react1 = REQ_.n(react1__);
-const _mixins2__ = REQ_(137);
-const _button_jsx3__ = REQ_(959);
-
-
-
-
-const withMicObserver = Component => class extends _mixins2__.w9 {
- constructor(props) {
- super(props);
- this.namespace = `SO-${Component.NAMESPACE}`;
- this.inputObserver = `onNoMicInput.${this.namespace}`;
- this.sendObserver = `onAudioSendDenied.${this.namespace}`;
- this.state = {
- signal: true,
- blocked: false
- };
- this.renderSignalWarning = this.renderSignalWarning.bind(this);
- this.renderBlockedWarning = this.renderBlockedWarning.bind(this);
- }
- bindObservers() {
- this.props.chatRoom.rebind(this.inputObserver, () => this.setState({
- signal: false
- })).rebind(this.sendObserver, () => {
- this.setState({
- blocked: true
- }, () => {
- if (this.props.minimized) {
- const toast = new ChatToast(l.max_speakers_toast, {
- icon: 'sprite-fm-uni icon-hazard',
- close: true
- });
- toast.dispatch();
- }
- });
- });
- }
- renderSignalDialog() {
- return msgDialog('warningb', null, l.no_mic_title, l.chat_mic_off_tooltip, null, 1);
- }
- renderSignalWarning() {
- return react1().createElement("div", {
- className: `
- ${this.namespace}
- meetings-signal-issue
- simpletip
- `,
- "data-simpletip": l.show_info,
- "data-simpletipposition": "top",
- "data-simpletipoffset": "5",
- "data-simpletip-class": "theme-dark-forced",
- onClick: () => this.renderSignalDialog()
- }, react1().createElement("i", {
- className: "sprite-fm-mono icon-exclamation-filled"
- }));
- }
- renderBlockedWarning() {
- return react1().createElement("div", {
- className: "stream-toast theme-dark-forced"
- }, react1().createElement("div", {
- className: "stream-toast-content"
- }, react1().createElement("i", {
- className: "stream-toast-icon sprite-fm-uni icon-warning"
- }), react1().createElement("div", {
- className: "stream-toast-message"
- }, l.max_speakers_toast), react1().createElement(_button_jsx3__.A, {
- className: "mega-button action stream-toast-close",
- icon: "sprite-fm-mono icon-close-component",
- onClick: () => this.setState({
- blocked: false
- })
- })));
- }
- componentWillUnmount() {
- super.componentWillUnmount();
- this.props.chatRoom.unbind(this.inputObserver);
- }
- componentDidMount() {
- super.componentDidMount();
- this.bindObservers();
- }
- render() {
- return react1().createElement(Component, (0,_extends0__.A)({}, this.props, {
- signal: this.state.signal,
- renderSignalWarning: this.renderSignalWarning,
- blocked: this.state.blocked,
- renderBlockedWarning: this.renderBlockedWarning
- }));
- }
-};
-
-},
-
-542
-(_, EXP_, REQ_) {
-
-"use strict";
-REQ_.d(EXP_, {
-$: () => withPermissionsObserver
-});
-const _extends0__ = REQ_(168);
-const react1__ = REQ_(594);
-const react1 = REQ_.n(react1__);
-const _mixins_js2__ = REQ_(137);
-const _ui_modalDialogs_jsx3__ = REQ_(318);
-const _ui_utils_jsx4__ = REQ_(314);
-
-
-
-
-
-const errors = {
- browser: 'NotAllowedError: Permission denied',
- system: 'NotAllowedError: Permission denied by system',
- dismissed: 'NotAllowedError: Permission dismissed',
- nil: 'NotFoundError: Requested device not found',
- sharedCam: 'NotReadableError: Could not start video source',
- sharedMic: 'NotReadableError: Could not start audio source',
- sharedGeneric: 'NotReadableError: Device in use'
-};
-const isUserActionError = error => {
- return error && error === errors.browser;
-};
-const withPermissionsObserver = Component => {
- return class extends _mixins_js2__.w9 {
- constructor(props) {
- super(props);
- this.namespace = `PO-${Component.NAMESPACE}`;
- this.observer = `onLocalMediaError.${this.namespace}`;
- this.childRef = undefined;
- this.platform = ua.details.os;
- this.helpURL = `${l.mega_help_host}/chats-meetings/meetings/enable-audio-video-call-permissions`;
- this.macURI = 'x-apple.systempreferences:com.apple.preference.security';
- this.winURI = 'ms-settings';
- this.CONTENT = {
- [Av.Audio]: {
- system: {
- title: l.no_mic_title,
- info: this.platform === 'Windows' ? l.no_mic_system_windows.replace('[A]', ``).replace('[/A]', '') : l.no_mic_system_mac.replace('[A]', ``).replace('[/A]', ''),
- buttons: [this.platform === 'Apple' || this.platform === 'Windows' ? {
- key: 'open-settings',
- label: l.open_system_settings,
- className: 'positive',
- onClick: () => {
- window.open(this.platform === 'Apple' ? `${this.macURI}?Privacy_Microphone` : `${this.winURI}:privacy-microphone`, '_blank', 'noopener,noreferrer');
- this.closePermissionsDialog(Av.Audio);
- }
- } : {
- key: 'ok',
- label: l.ok_button,
- className: 'positive',
- onClick: () => this.closePermissionsDialog(Av.Audio)
- }]
- },
- browser: {
- title: l.no_mic_title,
- cover: 'permissions-mic',
- info: l.allow_mic_access.replace('[X]', ''),
- buttons: [{
- key: 'ok',
- label: l.ok_button,
- className: 'positive',
- onClick: () => this.closePermissionsDialog(Av.Audio)
- }]
- },
- nil: {
- title: l.no_mic_detected_title,
- info: l.no_mic_detected_info,
- buttons: [{
- key: 'ok',
- label: l.ok_button,
- className: 'positive',
- onClick: () => this.closePermissionsDialog(Av.Audio)
- }]
- },
- shared: {
- title: l.no_mic_title,
- info: l.shared_mic_err_info.replace('[A]', ``).replace('[/A]', ''),
- buttons: [{
- key: 'ok',
- label: l.ok_button,
- className: 'positive',
- onClick: () => this.closePermissionsDialog(Av.Audio)
- }]
- }
- },
- [Av.Camera]: {
- system: {
- title: l.no_camera_title,
- info: this.platform === 'Windows' ? l.no_camera_system_windows.replace('[A]', ``).replace('[/A]', '') : l.no_camera_system_mac.replace('[A]', ``).replace('[/A]', ''),
- buttons: [this.platform === 'Apple' || this.platform === 'Windows' ? {
- key: 'open-settings',
- label: l.open_system_settings,
- className: 'positive',
- onClick: () => {
- window.open(this.platform === 'Apple' ? `${this.macURI}?Privacy_Camera` : `${this.winURI}:privacy-webcam`, '_blank', 'noopener,noreferrer');
- this.closePermissionsDialog(Av.Camera);
- }
- } : {
- key: 'ok',
- label: l.ok_button,
- className: 'positive',
- onClick: () => this.closePermissionsDialog(Av.Camera)
- }]
- },
- browser: {
- title: l.no_camera_title,
- cover: 'permissions-camera',
- info: l.allow_camera_access.replace('[X]', ''),
- buttons: [{
- key: 'ok',
- label: l.ok_button,
- className: 'positive',
- onClick: () => this.closePermissionsDialog(Av.Camera)
- }]
- },
- nil: {
- title: l.no_camera_detected_title,
- info: l.no_camera_detected_info,
- buttons: [{
- key: 'ok',
- label: l.ok_button,
- className: 'positive',
- onClick: () => this.closePermissionsDialog(Av.Camera)
- }]
- },
- shared: {
- title: l.no_camera_title,
- info: l.shared_cam_err_info.replace('[A]', ``).replace('[/A]', ''),
- buttons: [{
- key: 'ok',
- label: l.ok_button,
- className: 'positive',
- onClick: () => this.closePermissionsDialog(Av.Camera)
- }]
+ contacts.push(JSX_(ContactCard, {
+ withSelfNote,
+ disabled: isDisabled,
+ contact: v,
+ chatRoom: withSelfNote && megaChat.getNoteChat(),
+ className: `contacts-search short ${ selectedClass }${isDisabled ? " disabled" : ""}`,
+ noContextButton: "true",
+ selectable: selectableContacts,
+ onClick: self.props.readOnly ? () => {} : contact => {
+ if (isDisabled) {
+ return false;
+ }
+ const contactHash = contact.u;
+ if (contactHash === self.lastClicked && new Date() - self.clickTime < 500 && !self.props.disableDoubleClick || !self.props.multiple) {
+ if (self.props.onSelected) {
+ self.props.onSelected([contactHash]);
}
- },
- [Av.Screen]: {
- title: l.no_screen_title,
- info: l.no_screen_system.replace('[A]', ``).replace('[/A]', ''),
- buttons: [{
- key: 'open-settings',
- label: l.open_system_settings,
- className: 'positive',
- onClick: () => {
- window.open(`${this.macURI}?Privacy_ScreenCapture`, '_blank', 'noopener,noreferrer');
- this.closePermissionsDialog(Av.Screen);
+ self.props.onSelectDone([contactHash]);
+ closeDropdowns();
+ return;
+ } else {
+ const selected = clone(self.state.selected || []);
+ if (selected.indexOf(contactHash) === -1) {
+ selected.push(contactHash);
+ self.scrollToLastSelected = true;
+ if (self.props.onSelected) {
+ self.props.onSelected(selected);
+ }
+ } else {
+ if (selected.indexOf(contactHash) >= 0) {
+ array.remove(selected, contactHash);
+ }
+ if (self.props.onSelected) {
+ self.props.onSelected(selected);
}
- }]
- }
- };
- this.state = {
- errMic: '',
- errCamera: '',
- errScreen: '',
- [`dialog-${Av.Audio}`]: null,
- [`dialog-${Av.Camera}`]: null,
- [`dialog-${Av.Screen}`]: null
- };
- this.getPermissionsDialogContent = () => {
- const {
- CONTENT,
- state
- } = this;
- const {
- errMic,
- errCamera
- } = state;
- const {
- browser,
- system,
- nil,
- sharedCam,
- sharedMic,
- sharedGeneric
- } = errors;
- return {
- [Av.Audio]: {
- ...errMic === browser && CONTENT[Av.Audio].browser,
- ...errMic === system && CONTENT[Av.Audio].system,
- ...errMic === nil && CONTENT[Av.Audio].nil,
- ...errMic === sharedMic && CONTENT[Av.Audio].shared,
- ...errMic === sharedGeneric && CONTENT[Av.Audio].shared
- },
- [Av.Camera]: {
- ...errCamera === browser && CONTENT[Av.Camera].browser,
- ...errCamera === system && CONTENT[Av.Camera].system,
- ...errCamera === nil && CONTENT[Av.Camera].nil,
- ...errCamera === sharedCam && CONTENT[Av.Camera].shared,
- ...errCamera === sharedGeneric && CONTENT[Av.Camera].shared
- },
- [Av.Screen]: CONTENT[Av.Screen]
- };
- };
- this.resetError = av => {
- this.setState({
- errMic: av === Av.Audio ? '' : this.state.errMic,
- errCamera: av === Av.Camera ? '' : this.state.errCamera,
- errScreen: av === Av.Screen ? '' : this.state.errScreen
- });
- };
- this.hasToRenderPermissionsWarning = this.hasToRenderPermissionsWarning.bind(this);
- this.renderPermissionsWarning = this.renderPermissionsWarning.bind(this);
- }
- hasToRenderPermissionsWarning(av) {
- const CONFIG = {
- [Av.Audio]: {
- showOnUserActionError: true,
- err: this.state.errMic
- },
- [Av.Camera]: {
- showOnUserActionError: true,
- err: this.state.errCamera
- },
- [Av.Screen]: {
- showOnUserActionError: false,
- err: this.state.errScreen
- }
- };
- const current = CONFIG[av];
- if (current) {
- return isUserActionError(current.err) ? current.showOnUserActionError : current.err;
- }
- return false;
- }
- closePermissionsDialog(av) {
- this.setState({
- [`dialog-${av}`]: false
- }, () => {
- let _this$childRef;
- return (_this$childRef = this.childRef) == null ? void 0 : _this$childRef.safeForceUpdate();
- });
- }
- renderPermissionsDialog(av, child) {
- const content = this.getPermissionsDialogContent();
- const {
- title,
- info,
- buttons,
- cover
- } = content[av] || {};
- return react1().createElement(_ui_modalDialogs_jsx3__.A.ModalDialog, {
- dialogName: `${this.namespace}-permissions-${av}`,
- className: `
- meetings-permissions-dialog
- dialog-template-message
- with-close-btn
- warning
- `,
- buttons,
- hideOverlay: Component.NAMESPACE === 'preview-meeting' && !document.body.classList.contains('not-logged'),
- onClose: () => {
- this.setState({
- [`dialog-${av}`]: false
- }, () => child && child.safeForceUpdate());
- }
- }, react1().createElement("header", null, cover ? null : react1().createElement("div", {
- className: "graphic"
- }, react1().createElement("i", {
- className: "warning sprite-fm-uni icon-warning"
- })), react1().createElement("div", {
- className: "info-container"
- }, react1().createElement("h3", {
- id: "msgDialog-title"
- }, title || l[47]), cover && react1().createElement("div", {
- className: "permissions-warning-cover"
- }, react1().createElement("span", {
- className: cover
- })), react1().createElement(_ui_utils_jsx4__.P9, {
- tag: "p",
- className: "permissions-warning-info",
- content: info
- }))));
- }
- renderPermissionsWarning(av, child) {
- const {
- errMic,
- errCamera
- } = this.state;
- const dismissed = errMic === errors.dismissed || errCamera === errors.dismissed;
- return react1().createElement("div", {
- className: `
- ${this.namespace}
- meetings-signal-issue
- simpletip
- ${dismissed ? 'with-small-area' : ''}
- `,
- "data-simpletip": l.show_info,
- "data-simpletipposition": "top",
- "data-simpletipoffset": "5",
- "data-simpletip-class": "theme-dark-forced",
- onClick: () => dismissed ? null : this.setState({
- [`dialog-${av}`]: true
- }, () => {
- if (child) {
- this.childRef = child;
}
- })
- }, react1().createElement("span", {
- className: "signal-issue-background"
- }), react1().createElement("i", {
- className: "sprite-fm-mono icon-exclamation-filled"
- }), this.state[`dialog-${av}`] && this.renderPermissionsDialog(av, child));
- }
- componentWillUnmount() {
- super.componentWillUnmount();
- megaChat.unbind(this.observer);
- }
- componentDidMount() {
- super.componentDidMount();
- megaChat.rebind(this.observer, (ev, errAv) => {
- this.setState({
- errMic: errAv && errAv.mic ? String(errAv.mic) : this.state.errMic,
- errCamera: errAv && errAv.camera ? String(errAv.camera) : this.state.errCamera,
- errScreen: errAv && errAv.screen ? String(errAv.screen) : this.state.errScreen
- });
- });
- megaChat.rebind(`onLocalMediaQueryError.${this.namespace}`, (ev, {
- type,
- err
- }) => {
- if (type === 'screen' && String(err) === errors.system) {
- this.setState({
- [`dialog-${Av.Screen}`]: true
- }, () => this.safeForceUpdate());
- }
- });
- }
- render() {
- return react1().createElement(Component, (0,_extends0__.A)({}, this.props, this.state, {
- errMic: this.state.errMic,
- errCamera: this.state.errCamera,
- errScreen: this.state.errScreen,
- hasToRenderPermissionsWarning: this.hasToRenderPermissionsWarning,
- resetError: this.resetError,
- renderPermissionsWarning: this.renderPermissionsWarning
- }));
- }
- };
-};
-
-},
-
-110
-(_, EXP_, REQ_) {
-
-"use strict";
-REQ_.d(EXP_, {
-PS: () => addMonths,
-We: () => stringToTime,
-XH: () => stringToDate,
-a4: () => getTimeIntervals,
-cK: () => isToday,
-dB: () => getUserTimezone,
-ef: () => isTomorrow,
-i_: () => getNearestHalfHour,
-ro: () => isSameDay
-});
-
-const stringToDate = string => {
- return moment(string, ['DD MMM YYYY', 'DD-MM-YYYY', 'DD.MM.YYYY', 'MMM DD YYYY', 'YYYY MMM DD', 'YYYY DD MMM']);
-};
-const stringToTime = string => moment(string, ['HH:mm', 'hh:mm A']);
-const isSameDay = (a, b) => {
- return new Date(a).toDateString() === new Date(b).toDateString();
-};
-const isToday = timestamp => {
- return new Date(timestamp).toDateString() === new Date().toDateString();
-};
-const isTomorrow = timestamp => {
- const tomorrow = new Date();
- tomorrow.setDate(tomorrow.getDate() + 1);
- return tomorrow.toDateString() === new Date(timestamp).toDateString();
-};
-const getDaysInMonth = (year, month) => {
- return new Date(year, month, 0).getDate();
-};
-const addMonths = (timestamp, months) => {
- const date = new Date(timestamp);
- return new Date(date.setMonth(date.getMonth() + months)).getTime();
-};
-const getNearestHalfHour = (timestamp = Date.now()) => {
- const {
- SCHEDULED_MEETINGS_INTERVAL
- } = ChatRoom;
- return new Date(Math.ceil(timestamp / SCHEDULED_MEETINGS_INTERVAL) * SCHEDULED_MEETINGS_INTERVAL).getTime();
-};
-const getUserTimezone = () => {
- return Intl.DateTimeFormat().resolvedOptions().timeZone;
-};
-const getTimeIntervals = (timestamp, offsetFrom, interval = 30) => {
- const increments = [];
- if (timestamp) {
- const [targetDate, initialDate] = [new Date(timestamp), new Date(timestamp)].map(date => {
- date.setHours(0);
- date.setMinutes(0);
- return date;
- });
- while (targetDate.getDate() === initialDate.getDate()) {
- const timestamp = targetDate.getTime();
- const diff = offsetFrom && timestamp - offsetFrom;
- increments.push({
- value: timestamp,
- label: toLocaleTime(timestamp),
- duration: diff && diff > 0 ? diff : undefined
- });
- targetDate.setMinutes(targetDate.getMinutes() + interval);
- }
- }
- return increments;
-};
-
-},
-
-415
-(_, EXP_, REQ_) {
-
-"use strict";
-
-// EXPORTS
-REQ_.d(EXP_, {
- $A: () => MAX_STREAMS,
- Bq: () => PAGINATION,
- gh: () => STREAMS_PER_PAGE,
- hK: () => STREAM_ACTIONS,
- ro: () => chunkNodes,
- Ay: () => stream_Stream,
- iv: () => filterAndSplitSources
-});
-
-// EXTERNAL MODULE: ./node_modules/@babel/runtime/helpers/esm/extends.js
-const esm_extends = REQ_(168);
-// EXTERNAL MODULE: external "React"
-const React_ = REQ_(594);
-const REaCt = REQ_.n(React_);
-// EXTERNAL MODULE: ./js/chat/mixins.js
-const mixins = REQ_(137);
-// EXTERNAL MODULE: ./js/chat/ui/meetings/call.jsx + 11 modules
-const meetings_call = REQ_(3);
-// EXTERNAL MODULE: ./js/chat/ui/meetings/videoNode.jsx
-const videoNode = REQ_(414);
-// EXTERNAL MODULE: ./js/ui/utils.jsx
-const utils = REQ_(314);
-// EXTERNAL MODULE: ./js/chat/ui/meetings/button.jsx
-const meetings_button = REQ_(959);
-// EXTERNAL MODULE: ./js/ui/dropdowns.jsx
-const dropdowns = REQ_(911);
-// EXTERNAL MODULE: ./js/ui/buttons.jsx
-const buttons = REQ_(994);
-;// ./js/chat/ui/meetings/floatExtendedControls.jsx
-
-
-
-class FloatExtendedControls extends REaCt().Component {
- constructor(...args) {
- super(...args);
- this.isActive = type => {
- return !!(this.props.call.av & type);
- };
- }
- render() {
- const {
- hasToRenderPermissionsWarning,
- renderPermissionsWarning,
- resetError,
- showScreenDialog,
- onScreenSharingClick,
- onHoldClick
- } = this.props;
- const {
- onHold,
- Screen
- } = SfuClient.Av;
- const isOnHold = this.isActive(onHold);
- const callHoldLabel = isOnHold ? l[23459] : l[23460];
- const screenSharingLabel = this.isActive(Screen) ? l[22890] : l[22889];
- return REaCt().createElement(buttons.$, {
- className: "mega-button theme-light-forced round large button-group",
- icon: "sprite-fm-mono icon-options",
- showScreenDialog
- }, this.isActive(Screen) && REaCt().createElement("div", {
- className: "info-indicator active"
- }), REaCt().createElement(dropdowns.Dropdown, {
- className: "button-group-menu theme-dark-forced",
- noArrow: true,
- positionAt: "center top",
- collision: "none",
- vertOffset: -90,
- ref: r => {
- this.dropdownRef = r;
- },
- onBeforeActiveChange: e => {
- if (e) {
- $(document.body).trigger('closeAllDropdownsExcept', this.dropdownRef);
+ self.setState({
+ selected
+ });
+ if (self.props.selectCleanSearchRes) {
+ self.setState({
+ 'searchValue': ''
+ });
+ }
+ if (self.props.autoFocusSearchField) {
+ let _self$contactSearchFi;
+ (_self$contactSearchFi = self.contactSearchField) == null || _self$contactSearchFi.focus();
+ }
}
+ self.clickTime = new Date();
+ self.lastClicked = contactHash;
},
- showScreenDialog
- }, REaCt().createElement(dropdowns.DropdownItem, {
- key: "call-hold",
- className: `
- theme-dark-forced
- ${isOnHold ? 'active' : ''}
- `,
- label: callHoldLabel,
- icon: `
- sprite-fm-mono
- ${isOnHold ? 'icon-play-small-regular-outline' : 'icon-pause-small-regular-outline'}
- `,
- onClick: onHoldClick
- }), REaCt().createElement(dropdowns.DropdownItem, {
- key: "screen-sharing",
- className: `
- theme-dark-forced
- ${isOnHold ? 'disabled' : ''}
- ${this.isActive(Screen) ? 'active' : ''}
- `,
- label: screenSharingLabel,
- icon: `
- sprite-fm-mono
- ${this.isActive(Screen) ? 'icon-monitor-off' : 'icon-monitor'}
- `,
- onClick: () => {
- resetError(Av.Screen);
- onScreenSharingClick();
- }
- }), hasToRenderPermissionsWarning(Screen) ? renderPermissionsWarning(Screen, this) : null));
- }
-}
-FloatExtendedControls.NAMESPACE = 'stream-extended-controls';
-// EXTERNAL MODULE: ./js/chat/ui/meetings/micObserver.jsx
-const micObserver = REQ_(772);
-// EXTERNAL MODULE: ./js/chat/ui/meetings/permissionsObserver.jsx
-const permissionsObserver = REQ_(542);
-// EXTERNAL MODULE: ./js/chat/ui/meetings/hostsObserver.jsx
-const hostsObserver = REQ_(972);
-// EXTERNAL MODULE: ./js/chat/ui/meetings/streamControls.jsx
-const streamControls = REQ_(489);
-;// ./js/chat/ui/meetings/float.jsx
-
-
-
-
-
-
-
-
-
-
-
-
-class FloatingVideo extends REaCt().Component {
- constructor(...args) {
- super(...args);
- this.collapseListener = null;
- this.state = {
- collapsed: false
- };
- this.toggleCollapsedMode = () => {
- return this.setState(state => ({
- collapsed: !state.collapsed
- }));
- };
- }
- componentWillUnmount() {
- mBroadcaster.removeListener(this.collapseListener);
- }
- componentDidMount() {
- this.collapseListener = mBroadcaster.addListener('meetings:collapse', () => this.setState({
- collapsed: true
+ noContextMenu: true,
+ searchValue: self.state.searchValue,
+ highlightSearchValue: self.props.highlightSearchValue,
+ emailTooltips: self.props.emailTooltips,
+ key: v.u
}));
- }
- componentDidUpdate() {
- if (typeof psa !== 'undefined') {
- psa.repositionMeetingsCall();
+ if (typeof this.props.onEventuallyUpdated === 'function') {
+ this.props.onEventuallyUpdated();
}
+ return true;
}
render() {
- const {
- peers,
- minimized,
- call,
- floatDetached
- } = this.props;
- if (peers.length === 0 && !minimized && !call.isSharingScreen()) {
- return null;
- }
- const STREAM_PROPS = {
- ...this.props,
- collapsed: this.state.collapsed,
- toggleCollapsedMode: this.toggleCollapsedMode,
- onLoadedData: this.onLoadedData
- };
- if (minimized) {
- return REaCt().createElement(utils.Ay.RenderTo, {
- element: document.body
- }, REaCt().createElement(Stream, STREAM_PROPS));
- }
- return floatDetached ? REaCt().createElement(Stream, STREAM_PROPS) : null;
- }
-}
-FloatingVideo.NAMESPACE = 'float-video';
-FloatingVideo.POSITION_MODIFIER = 'with-sidebar';
-class Stream extends mixins.w9 {
- constructor(...args) {
- super(...args);
- this.domRef = REaCt().createRef();
- this.DRAGGABLE = {
- POSITION: {
- top: undefined,
- left: undefined
- },
- OPTIONS: {
- scroll: 'false',
- cursor: 'move',
- opacity: 1,
- start: () => {
- if (this.state.options) {
- this.handleOptionsToggle();
+ const self = this;
+ let contacts = [];
+ const frequentContacts = [];
+ let extraClasses = "";
+ const contactsSelected = [];
+ let multipleContacts = null;
+ let selectableContacts = false;
+ let selectFooter = null;
+ let selectedContacts = false;
+ const isSearching = !!self.state.searchValue;
+ megaChat.getNoteChat();
+ const onAddContact = e => {
+ e.preventDefault();
+ e.stopPropagation();
+ contactAddDialog();
+ if (this.props.onClose) {
+ this.props.onClose();
+ }
+ };
+ if (self.props.readOnly) {
+ const sel = self.state.selected || [];
+ for (let i = 0; i < sel.length; i++) {
+ const v = sel[i];
+ contactsSelected.push(JSX_(ContactItem, {
+ contact: M.u[v],
+ key: v,
+ chatRoom: self.props.chatRoom
+ }));
+ }
+ } else if (self.props.multiple) {
+ selectableContacts = true;
+ const onSelectDoneCb = e => {
+ e.preventDefault();
+ e.stopPropagation();
+ closeDropdowns();
+ if (self.props.onSelectDone) {
+ self.props.onSelectDone(self.state.selected);
+ }
+ };
+ let onContactSelectDoneCb = contact => {
+ const contactHash = contact.u;
+ if (contactHash === self.lastClicked && new Date() - self.clickTime < 500) {
+ if (self.props.onSelected) {
+ self.props.onSelected([contactHash]);
}
- $(document.body).trigger('closeAllDropdownsExcept');
- },
- stop: (event, ui) => {
- this.DRAGGABLE.POSITION = ui.position;
- const {
- clientWidth,
- clientHeight
- } = document.body;
- const {
- helper
- } = ui;
- const {
- left,
- top
- } = this.DRAGGABLE.POSITION;
- if (left < clientWidth / 2) {
- helper.css('left', `${left / clientWidth * 100}%`).css('right', 'unset');
+ self.props.onSelectDone([contactHash]);
+ return;
+ } else {
+ const selected = clone(self.state.selected || []);
+ if (selected.indexOf(contactHash) === -1) {
+ selected.push(contactHash);
+ self.scrollToLastSelected = true;
+ if (self.props.onSelected) {
+ self.props.onSelected(selected);
+ }
} else {
- helper.css('left', 'unset').css('right', `${clientWidth - left - helper.width()}px`);
+ if (selected.indexOf(contactHash) >= 0) {
+ array.remove(selected, contactHash);
+ }
+ if (self.props.onSelected) {
+ self.props.onSelected(selected);
+ }
}
- if (top < clientHeight / 2) {
- helper.css('top', `${top / clientHeight * 100}%`).css('bottom', 'unset');
- } else {
- helper.css('top', 'unset').css('bottom', `${clientHeight - top - helper.height()}px`);
+ self.setState({
+ selected
+ });
+ if (self.props.selectCleanSearchRes) {
+ self.setState({
+ 'searchValue': ''
+ });
+ }
+ if (self.props.autoFocusSearchField) {
+ let _self$contactSearchFi2;
+ (_self$contactSearchFi2 = self.contactSearchField) == null || _self$contactSearchFi2.focus();
}
}
- }
- };
- this.EVENTS = {
- MINIMIZE: ['slideshow:open', 'contact:open', 'textEditor:open', 'chat:open'],
- EXPAND: ['slideshow:close', 'textEditor:close']
- };
- this.LISTENERS = [];
- this.PREV_STATE = {};
- this.state = {
- options: false
- };
- this.getStreamSource = () => {
- const {
- call,
- mode,
- forcedLocal
- } = this.props;
- return mode === meetings_call.g.MINI && !forcedLocal ? call.getActiveStream() : call.getLocalStream();
- };
- this.unbindEvents = () => {
- const events = [...this.EVENTS.MINIMIZE, ...this.EVENTS.EXPAND];
- for (let i = events.length; i--;) {
- const event = events[i];
- mBroadcaster.removeListener(this.LISTENERS[event]);
- }
- document.removeEventListener('click', this.handleOptionsClose);
- };
- this.bindEvents = () => {
- for (let i = this.EVENTS.MINIMIZE.length; i--;) {
- const event = this.EVENTS.MINIMIZE[i];
- this.LISTENERS[event] = mBroadcaster.addListener(event, () => {
- this.PREV_STATE.minimised = this.props.minimized;
- return this.props.onCallMinimize();
- });
- }
- for (let i = this.EVENTS.EXPAND.length; i--;) {
- const event = this.EVENTS.EXPAND[i];
- this.LISTENERS[event] = mBroadcaster.addListener(event, () => {
- if (this.PREV_STATE.minimised) {
- delete this.PREV_STATE.minimised;
- return;
+ self.clickTime = new Date();
+ self.lastClicked = contactHash;
+ };
+ const selectedWidthSize = self.props.selectedWidthSize || 54;
+ const selectedWidth = self.state.selected.length * selectedWidthSize;
+ if (!self.state.selected || self.state.selected.length === 0) {
+ selectedContacts = false;
+ const emptySelectionMsg = self.props.emptySelectionMsg || l[8889];
+ multipleContacts = JSX_("div", {
+ className: "horizontal-contacts-list"
+ }, JSX_("div", {
+ className: "contacts-list-empty-txt"
+ }, self.props.nothingSelectedButtonLabel ? self.props.nothingSelectedButtonLabel : emptySelectionMsg));
+ } else {
+ selectedContacts = true;
+ onContactSelectDoneCb = onContactSelectDoneCb.bind(self);
+ const sel2 = self.state.selected || [];
+ for (let i2 = 0; i2 < sel2.length; i2++) {
+ const v2 = sel2[i2];
+ contactsSelected.push(JSX_(ContactItem, {
+ key: v2,
+ chatRoom: self.props.chatRoom || false,
+ contact: M.u[v2],
+ noContextMenu: true,
+ onClick: onContactSelectDoneCb
+ }));
+ }
+ multipleContacts = JSX_("div", {
+ className: "horizontal-contacts-list"
+ }, JSX_(_ui_perfectScrollbar_jsx4__ .O, {
+ className: "perfectScrollbarContainer selected-contact-block horizontal-only",
+ selected: this.state.selected,
+ ref (psSelected) {
+ self.psSelected = psSelected;
}
- delete this.PREV_STATE.minimised;
- return this.props.view === meetings_call.gR.CHAT && this.props.onCallExpand();
- });
- }
- document.addEventListener('click', this.handleOptionsClose);
- };
- this.initDraggable = () => {
- let _this$domRef;
- const {
- minimized,
- wrapperRef
- } = this.props;
- const containerEl = (_this$domRef = this.domRef) == null ? void 0 : _this$domRef.current;
- if (containerEl) {
- $(containerEl).draggable({
- ...this.DRAGGABLE.OPTIONS,
- containment: minimized ? 'body' : wrapperRef == null ? void 0 : wrapperRef.current
- });
+ }, JSX_("div", {
+ className: "select-contact-centre",
+ style: {
+ width: selectedWidth
+ }
+ }, contactsSelected)));
}
- };
- this.repositionDraggable = () => {
- let _this$props$wrapperRe, _this$domRef2;
- const wrapperEl = (_this$props$wrapperRe = this.props.wrapperRef) == null ? void 0 : _this$props$wrapperRe.current;
- const localEl = (_this$domRef2 = this.domRef) == null ? void 0 : _this$domRef2.current;
- if (localEl.offsetLeft + localEl.offsetWidth > wrapperEl.offsetWidth) {
- localEl.style.left = 'unset';
- localEl.style.removeProperty("right");
+ if (self.props.selectFooter) {
+ selectFooter = JSX_("footer", null, JSX_("button", {
+ className: "mega-button",
+ onClick: onAddContact.bind(self)
+ }, JSX_("span", null, l[71])), JSX_("div", {
+ className: "footer-spacing"
+ }), JSX_("button", {
+ className: `mega-button ${selectedContacts ? '' : 'disabled'}`,
+ onClick (e) {
+ if (self.state.selected.length > 0) {
+ onSelectDoneCb(e);
+ }
+ }
+ }, JSX_("span", null, this.props.multipleSelectedButtonLabel ? this.props.multipleSelectedButtonLabel : l[8890])));
}
- };
- this.handleOptionsClose = ({
- target
- }) => {
- if (this.state.options && !target.classList.contains('icon-options')) {
- this.setState({
- options: false
- });
+ }
+ const alreadyAdded = {};
+ let hideFrequents = !self.props.readOnly && !self.state.searchValue && frequentContacts.length > 0;
+ let frequentsLoading = false;
+ if (this.props.readOnly || this.props.disableFrequents) {
+ hideFrequents = true;
+ this._foundFrequents = [];
+ } else if (!self._foundFrequents) {
+ frequentsLoading = true;
+ this._foundFrequents = [];
+ megaChat.getFrequentContacts().then(res => {
+ this._foundFrequents = res.slice(Math.max(res.length - 30, 0), res.length).reverse();
+ }).catch(dump).finally(() => {
+ if (this.isMounted()) {
+ this.safeForceUpdate();
+ }
+ });
+ }
+ for (let i = this._foundFrequents.length, total = 0; total < MAX_FREQUENTS && i--;) {
+ const v = this._foundFrequents[i];
+ if (v.userId in M.u && this._eventuallyAddContact(M.u[v.userId], frequentContacts, selectableContacts)) {
+ alreadyAdded[v.userId] = 1;
+ total++;
}
- };
- this.handleOptionsToggle = () => this.setState({
- options: !this.state.options
+ }
+ self.props.contacts.forEach((v) => {
+ alreadyAdded[v.h] || self._eventuallyAddContact(v, contacts, selectableContacts);
});
- this.renderOnHoldVideoNode = () => REaCt().createElement(videoNode.Cn, {
- chatRoom: this.props.chatRoom
+ const sortFn = M.getSortByNameFn2(1);
+ contacts.sort((a, b) => {
+ return b.props.withSelfNote - a.props.withSelfNote || sortFn(a.props.contact, b.props.contact);
});
- this.renderOptionsDialog = () => {
- const {
- call,
- mode,
- forcedLocal,
- onScreenSharingClick,
- onSpeakerChange,
- onModeChange,
- toggleCollapsedMode,
- onMoveIntoGrid
- } = this.props;
- const IS_SPEAKER_VIEW = mode === meetings_call.g.MAIN && forcedLocal;
+ if (Object.keys(alreadyAdded).length === 0) {
+ hideFrequents = true;
+ }
+ const innerDivStyles = {};
+ if (this.props.showMeAsSelected) {
+ self._eventuallyAddContact(M.u[u_handle], contacts, selectableContacts, true);
+ }
+ let noOtherContacts = false;
+ if (contacts.length === 0 || !(0,_contactsPanel_utils_jsx10__ .SN)() && this.props.step !== 1) {
+ noOtherContacts = true;
+ let noContactsMsg = "";
+ if (M.u.length < 2) {
+ noContactsMsg = l[8877];
+ } else {
+ noContactsMsg = l[8878];
+ }
+ if (hideFrequents) {
+ contacts = JSX_("em", null, noContactsMsg);
+ }
+ }
+ const haveContacts = isSearching || frequentContacts.length !== 0 || !noOtherContacts;
+ let contactsList;
+ if (haveContacts) {
+ if (frequentContacts.length === 0 && noOtherContacts) {
+ if (self.props.newEmptySearchResult) {
+ contactsList = JSX_("div", {
+ className: "chat-contactspicker-no-contacts flex flex-column flex-center searching mt-2"
+ }, JSX_("div", {
+ className: "section-icon sprite-fm-mono icon-contacts"
+ }), JSX_("div", {
+ className: "fm-empty-cloud-txt small"
+ }, l[8674]));
+ } else {
+ contactsList = JSX_("div", {
+ className: "chat-contactspicker-no-contacts flex flex-column mt-2"
+ }, JSX_("div", {
+ className: "contacts-list-header"
+ }, l[165]), JSX_("div", {
+ className: "flex flex-1 flex-column flex-center"
+ }, JSX_("div", {
+ className: "section-icon sprite-fm-mono icon-contacts"
+ }), JSX_("div", {
+ className: "fm-empty-cloud-txt small"
+ }, l[784]), JSX_("div", {
+ className: "fm-empty-description small"
+ }, l[19115])));
+ }
+ } else {
+ contactsList = JSX_(_ui_perfectScrollbar_jsx4__ .O, {
+ ref: ref => {
+ self.searchContactsScroll = ref;
+ },
+ className: "contacts-search-scroll",
+ selected: this.state.selected,
+ changedHashProp: this.props.changedHashProp,
+ contacts,
+ frequentContacts,
+ searchValue: this.state.searchValue
+ }, JSX_(react1___default().Fragment, null, JSX_("div", {
+ className: "contacts-search-subsection",
+ style: {
+ display: hideFrequents ? 'none' : ''
+ }
+ }, JSX_("div", {
+ className: "contacts-list-header"
+ }, l[20141]), frequentsLoading ? JSX_("div", {
+ className: "loading-spinner"
+ }, "...") : JSX_("div", {
+ className: "contacts-search-list",
+ style: innerDivStyles
+ }, frequentContacts)), contacts.length > 0 ? JSX_("div", {
+ className: "contacts-search-subsection"
+ }, JSX_("div", {
+ className: "contacts-list-header"
+ }, frequentContacts && frequentContacts.length === 0 ? this.props.readOnly ? l[16217] : l[165] : l[165]), JSX_("div", {
+ className: "contacts-search-list",
+ style: innerDivStyles
+ }, contacts)) : null));
+ }
+ } else if (self.props.newNoContact) {
+ multipleContacts = "";
+ contactsList = JSX_("div", {
+ className: "chat-contactspicker-no-contacts flex flex-column flex-center mt-2"
+ }, JSX_("div", {
+ className: "section-icon sprite-fm-mono icon-contacts"
+ }), JSX_("div", {
+ className: "fm-empty-cloud-txt small"
+ }, l[784]), JSX_("div", {
+ className: "fm-empty-description small"
+ }, l[19115]));
+ extraClasses += " no-contacts";
+ } else {
+ contactsList = JSX_("div", {
+ className: "chat-contactspicker-no-contacts flex flex-column flex-center mt-16"
+ }, JSX_("div", {
+ className: "section-icon sprite-fm-mono icon-contacts"
+ }), JSX_("div", {
+ className: "fm-empty-cloud-txt small"
+ }, l[784]), JSX_("div", {
+ className: "fm-empty-description small"
+ }, l[19115]), JSX_("button", {
+ className: "mega-button positive large fm-empty-button",
+ onClick: () => {
+ contactAddDialog();
+ self.props.onClose == null || self.props.onClose();
+ }
+ }, JSX_("span", null, l[101])), JSX_("div", {
+ className: `
+ ${this.state.publicLink ? '' : 'loading'}
+ empty-share-public
+ `
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-link-circle"
+ }), JSX_(_ui_utils_jsx3__ .P9, null, l[19111])));
+ extraClasses += " no-contacts";
+ }
+ const totalContactsNum = contacts.length + frequentContacts.length;
+ const searchPlaceholderMsg = mega.icu.format(l.search_contact_placeholder, totalContactsNum);
+ return JSX_("div", {
+ ref: this.domRef,
+ className: `
+ ${this.props.className || ''}
+ ${extraClasses}
+ `
+ }, this.props.topButtons && JSX_("div", {
+ className: "contacts-search-buttons"
+ }, this.props.topButtons.map(button => {
const {
- POSITION
- } = this.DRAGGABLE;
- return REaCt().createElement("div", {
+ key,
+ icon,
+ className,
+ title,
+ onClick
+ } = button || {};
+ return JSX_("div", {
+ key,
+ className: "button-wrapper",
+ onClick: e => {
+ closeDropdowns();
+ onClick(e);
+ }
+ }, JSX_(_ui_buttons_jsx5__ .$, {
className: `
- ${FloatingVideo.NAMESPACE}-options
- ${POSITION.left < 200 ? 'options-top' : ''}
- ${POSITION.left < 200 && POSITION.top < 100 ? 'options-bottom' : ''}
- theme-dark-forced
- `
- }, REaCt().createElement("ul", null, REaCt().createElement("li", null, REaCt().createElement(meetings_button.A, {
- icon: `
- sprite-fm-mono
- ${IS_SPEAKER_VIEW ? 'grid-9' : 'grid-main'}
- `,
- onClick: () => this.setState({
- options: false
+ ${className || ''}
+ ${key === 'newChatLink' ? 'branded-blue' : ''}
+ mega-button
+ `,
+ icon,
+ label: title
+ }));
+ })), multipleContacts, !this.props.readOnly && haveContacts && !this.props.hideSearch && JSX_(react1___default().Fragment, null, JSX_("div", {
+ className: `
+ contacts-search-header
+ ${this.props.headerClasses}
+ `
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-preview-reveal"
+ }), JSX_("input", {
+ autoFocus: true,
+ type: "search",
+ placeholder: searchPlaceholderMsg,
+ ref: nodeRef => {
+ this.contactSearchField = nodeRef;
+ },
+ onChange: this.onSearchChange,
+ value: this.state.searchValue
+ }), JSX_("div", {
+ className: `
+ search-result-clear
+ ${this.state.searchValue && this.state.searchValue.length > 0 ? '' : 'hidden'}
+ `,
+ onClick: () => {
+ this.setState({
+ searchValue: ''
}, () => {
- if (IS_SPEAKER_VIEW) {
- return onModeChange(meetings_call.g.THUMBNAIL);
- }
- onSpeakerChange(call.getLocalStream());
- })
- }, REaCt().createElement("div", null, IS_SPEAKER_VIEW ? l.switch_to_thumb_view : l.display_in_main_view))), REaCt().createElement("li", null, REaCt().createElement(meetings_button.A, {
- icon: "sprite-fm-mono icon-collapse-up",
- onClick: onMoveIntoGrid
- }, REaCt().createElement("div", null, l.move_into_grid_button))), REaCt().createElement("li", null, REaCt().createElement(meetings_button.A, {
- icon: "sprite-fm-mono icon-download-standard",
- onClick: () => this.setState({
- options: false
- }, () => toggleCollapsedMode())
- }, REaCt().createElement("div", null, l.collapse_self_video)))), !!(call.av & SfuClient.Av.Screen) && REaCt().createElement("ul", {
- className: "has-separator"
- }, REaCt().createElement("li", null, REaCt().createElement(meetings_button.A, {
- className: "end-screen-share",
- icon: "icon-end-screenshare",
- onClick: () => {
- this.setState({
- options: false
- });
- onScreenSharingClick();
- }
- }, REaCt().createElement("div", null, l[22890])))));
- };
- this.renderMiniMode = source => {
- const {
- call,
- chatRoom,
- mode,
- minimized,
- isPresenterNode,
- onLoadedData
- } = this.props;
- if (call.isOnHold) {
- return this.renderOnHoldVideoNode();
+ let _this$contactSearchFi;
+ return (_this$contactSearchFi = this.contactSearchField) == null ? void 0 : _this$contactSearchFi.focus();
+ });
}
- const VideoClass = source.isLocal ? isPresenterNode ? videoNode.Cn : videoNode.bJ : videoNode.zu;
- return REaCt().createElement(VideoClass, {
- key: source,
- source,
- chatRoom,
- mode,
- minimized,
- isPresenterNode,
- onLoadedData
- });
- };
- this.renderSelfView = () => {
- const {
- isOnHold,
- raisedHandPeers,
- minimized,
- chatRoom,
- isPresenterNode,
- call,
- onLoadedData
- } = this.props;
- const {
- options
- } = this.state;
- if (isOnHold) {
- return this.renderOnHoldVideoNode();
- }
- const VideoNode = call.isSharingScreen() ? videoNode.Vm : videoNode.bJ;
- return REaCt().createElement(REaCt().Fragment, null, REaCt().createElement(VideoNode, {
- isSelfOverlay: true,
- raisedHandPeers,
- minimized,
- chatRoom,
- isPresenterNode,
- onLoadedData
- }), REaCt().createElement("div", {
- className: `${FloatingVideo.NAMESPACE}-self-overlay`
- }, minimized ? null : REaCt().createElement(meetings_button.A, {
- className: `
- mega-button
- theme-light-forced
- action
- small
- float-video-options-control
- ${options ? 'active' : ''}
- `,
- icon: "sprite-fm-mono icon-options",
- onClick: () => this.handleOptionsToggle()
- }), options && this.renderOptionsDialog()));
- };
- }
- componentWillUnmount() {
- super.componentWillUnmount();
- this.unbindEvents();
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-close-component"
+ })))), this.props.inviteWarningLabel && this.props.chatRoom && this.renderInviteWarning(), !this.props.readOnly && haveContacts && !this.props.hideSearch && JSX_("div", {
+ className: "contacts-search-header-separator"
+ }), this.props.participantsList ? this.renderParticipantsList() : contactsList, selectFooter, this.props.showAddContact && (0,_contactsPanel_utils_jsx10__ .SN)() ? JSX_("div", {
+ className: "contacts-search-bottom"
+ }, JSX_(_ui_buttons_jsx5__ .$, {
+ className: "mega-button action positive",
+ icon: "sprite-fm-mono icon-add-circle",
+ label: l[71],
+ onClick: () => {
+ let _this$props$onAddCont, _this$props3;
+ contactAddDialog();
+ closeDropdowns();
+ (_this$props$onAddCont = (_this$props3 = this.props).onAddContact) == null || _this$props$onAddCont.call(_this$props3);
+ }
+ })) : null);
}
- componentDidUpdate(prevProps) {
- super.componentDidUpdate();
- if (this.props.mode !== prevProps.mode) {
- this.initDraggable();
- }
- if (this.props.sidebar !== prevProps.sidebar && this.props.sidebar) {
- this.repositionDraggable();
- }
+}
+ContactPickerWidget.defaultProps = {
+ multipleSelectedButtonLabel: false,
+ singleSelectedButtonLabel: false,
+ nothingSelectedButtonLabel: false,
+ allowEmpty: false,
+ disableFrequents: false,
+ skipMailSearch: false,
+ autoFocusSearchField: true,
+ selectCleanSearchRes: true,
+ disableDoubleClick: false,
+ newEmptySearchResult: false,
+ newNoContact: false,
+ emailTooltips: false
+};
+class ContactPickerDialog extends _mixins2__ .w9 {
+ constructor(...args) {
+ super(...args);
+ this.dialogName = 'contact-picker-dialog';
}
componentDidMount() {
super.componentDidMount();
- this.bindEvents();
- this.initDraggable();
+ M.safeShowDialog(this.dialogName, () => $(`.${this.dialogName}`));
+ }
+ componentWillUnmount() {
+ super.componentWillUnmount();
+ if ($.dialog === this.dialogName) {
+ closeDialog();
+ }
}
render() {
const {
- NAMESPACE,
- POSITION_MODIFIER
- } = FloatingVideo;
- const {
- call,
- mode,
- minimized,
- sidebar,
- collapsed,
- toggleCollapsedMode,
- onCallExpand
+ active,
+ allowEmpty,
+ className,
+ exclude,
+ megaChat,
+ multiple,
+ multipleSelectedButtonLabel,
+ name,
+ nothingSelectedButtonLabel,
+ selectFooter,
+ singleSelectedButtonLabel,
+ inviteWarningLabel,
+ chatRoom,
+ onClose,
+ onSelectDone
} = this.props;
- const IS_MINI_MODE = mode === meetings_call.g.MINI;
- if (collapsed) {
- return REaCt().createElement("div", {
- ref: this.domRef,
- className: `
- ${NAMESPACE}
- collapsed
- theme-dark-forced
- ${sidebar && !minimized ? POSITION_MODIFIER : ''}
- `,
- onClick: toggleCollapsedMode
- }, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-arrow-up icon-collapse"
- }), REaCt().createElement("div", {
- className: "collapsed-audio-indicator"
- }, REaCt().createElement(videoNode.Gz, {
- source: call.getLocalStream()
- })));
- }
- const source = this.getStreamSource() || call.getLocalStream();
- return REaCt().createElement("div", {
- ref: this.domRef,
+ return JSX_(_ui_modalDialogs7__ .A.ModalDialog, {
+ name,
className: `
- ${NAMESPACE}
- ${IS_MINI_MODE ? 'mini' : ''}
- ${minimized ? 'minimized' : ''}
- ${this.state.options ? 'active' : ''}
- ${sidebar && !minimized ? POSITION_MODIFIER : ''}
+ ${className}
+ ${this.dialogName}
+ contacts-search
`,
- onClick: ({
- target
- }) => minimized && target.classList.contains(`${NAMESPACE}-overlay`) && onCallExpand()
- }, IS_MINI_MODE && this.renderMiniMode(source), !IS_MINI_MODE && this.renderSelfView(), minimized && REaCt().createElement(__Minimized, (0,esm_extends.A)({}, this.props, {
- onOptionsToggle: this.handleOptionsToggle
- })));
+ onClose
+ }, JSX_(ContactPickerWidget, {
+ active,
+ allowEmpty,
+ className: "popup contacts-search small-footer",
+ contacts: M.u,
+ exclude,
+ megaChat,
+ multiple,
+ multipleSelectedButtonLabel,
+ nothingSelectedButtonLabel,
+ selectFooter,
+ singleSelectedButtonLabel,
+ inviteWarningLabel,
+ chatRoom,
+ onClose,
+ onSelectDone
+ }));
}
}
-class Minimized extends mixins.w9 {
- constructor(props) {
- super(props);
- this.domRef = REaCt().createRef();
- this.SIMPLETIP_PROPS = {
- position: 'top',
- offset: 5,
- className: 'theme-dark-forced'
- };
- this.waitingPeersListener = undefined;
- this.raisedHandListener = undefined;
- this.state = {
- unread: 0,
- waitingRoomPeers: [],
- raisedHandPeers: [],
- hideWrList: false,
- hideHandsList: false
- };
- this.isActive = type => {
- return this.props.call.av & type;
- };
- this.getUnread = () => {
- const {
- chatRoom
- } = this.props;
- chatRoom.rebind(Minimized.UNREAD_EVENT, () => this.setState({
- unread: chatRoom.getUnreadCount()
- }, () => this.safeForceUpdate()));
- };
- this.renderSignalWarning = () => this.props.signal ? null : this.props.renderSignalWarning();
- this.renderPermissionsWarning = type => {
- const {
- hasToRenderPermissionsWarning,
- renderPermissionsWarning
- } = this.props;
- if (hasToRenderPermissionsWarning(type)) {
- return renderPermissionsWarning(type, this);
- }
- return null;
- };
- this.renderStreamControls = () => {
- const {
- call,
- chatRoom,
- recorderCid,
- hasToRenderPermissionsWarning,
- renderPermissionsWarning,
- resetError,
- onRecordingToggle,
- onAudioClick,
- onVideoClick,
- onScreenSharingClick,
- onHoldClick,
- onCallEnd
- } = this.props;
- const audioLabel = this.isActive(SfuClient.Av.Audio) ? l[16214] : l[16708];
- const videoLabel = this.isActive(SfuClient.Av.Camera) ? l[22894] : l[22893];
- const LeaveButton = (0,hostsObserver.C)(({
- hasHost,
- chatRoom,
- confirmLeave,
- onLeave
- }) => {
- return REaCt().createElement(meetings_button.A, {
- simpletip: {
- ...this.SIMPLETIP_PROPS,
- label: l[5884]
- },
- className: "mega-button theme-dark-forced round large end-call",
- icon: "icon-phone-02",
- onClick: ev => {
- ev.stopPropagation();
- const callParticipants = chatRoom.getCallParticipants();
- const doLeave = () => !chatRoom.iAmOperator() || hasHost(chatRoom.call ? chatRoom.call.peers.map(a => a.userHandle) : []) || callParticipants.length === 1 ? onLeave() : confirmLeave({
- title: l.assign_host_leave_call,
- body: l.assign_host_leave_call_details,
- cta: l.assign_host_button,
- altCta: l.leave_anyway
- });
- return recorderCid && recorderCid === call.sfuClient.cid ? (0,streamControls.sX)(doLeave, onRecordingToggle) : doLeave();
- }
- }, REaCt().createElement("span", null, l[5884]));
- });
- return REaCt().createElement(REaCt().Fragment, null, REaCt().createElement("div", {
- className: `${FloatingVideo.NAMESPACE}-controls`
- }, REaCt().createElement("div", {
- className: "meetings-signal-container"
- }, REaCt().createElement(meetings_button.A, {
- simpletip: {
- ...this.SIMPLETIP_PROPS,
- label: audioLabel
- },
- className: `
- mega-button
- theme-light-forced
- round
- ${this.isActive(SfuClient.Av.onHold) ? 'disabled' : ''}
- ${this.isActive(SfuClient.Av.Audio) ? '' : 'with-fill'}
- `,
- icon: this.isActive(SfuClient.Av.Audio) ? 'icon-mic-thin-outline' : 'icon-mic-off-thin-outline',
- onClick: ev => {
- ev.stopPropagation();
- resetError(Av.Audio);
- onAudioClick();
- }
- }, REaCt().createElement("span", null, audioLabel)), this.renderSignalWarning(), this.renderPermissionsWarning(Av.Audio)), REaCt().createElement("div", {
- className: "meetings-signal-container"
- }, REaCt().createElement(meetings_button.A, {
- simpletip: {
- ...this.SIMPLETIP_PROPS,
- label: videoLabel
- },
- className: `
- mega-button
- theme-light-forced
- round
- ${this.isActive(SfuClient.Av.onHold) ? 'disabled' : ''}
- ${this.isActive(SfuClient.Av.Camera) ? '' : 'with-fill'}
- `,
- icon: this.isActive(SfuClient.Av.Camera) ? 'icon-video-thin-outline' : 'icon-video-off-thin-outline',
- onClick: ev => {
- ev.stopPropagation();
- resetError(Av.Camera);
- onVideoClick();
- }
- }, REaCt().createElement("span", null, videoLabel)), this.renderPermissionsWarning(Av.Camera)), REaCt().createElement("div", {
- className: "meetings-signal-container"
- }, REaCt().createElement(FloatExtendedControls, {
- call,
- chatRoom,
- onScreenSharingClick,
- onHoldClick,
- hasToRenderPermissionsWarning,
- renderPermissionsWarning,
- resetError,
- showScreenDialog: !!this.props[`dialog-${Av.Screen}`]
- }), this.renderPermissionsWarning(Av.Screen)), REaCt().createElement(LeaveButton, {
- chatRoom,
- participants: chatRoom.getCallParticipants(),
- onLeave: onCallEnd,
- onConfirmDenied: onCallEnd
- })), REaCt().createElement("span", {
- className: `${FloatingVideo.NAMESPACE}-fade`
- }));
- };
- this.renderPeersList = () => {
- const {
- onCallExpand,
- onParticipantsToggle,
- onWrListToggle
- } = this.props;
- const {
- waitingRoomPeers,
- raisedHandPeers,
- hideHandsList,
- hideWrList
- } = this.state;
- if (hideHandsList && hideWrList) {
- return null;
- }
- const showRaised = hideHandsList || !hideWrList && waitingRoomPeers.length ? false : !!raisedHandPeers.length;
- if (!showRaised && hideWrList) {
- return null;
- }
- const showButton = !showRaised || showRaised && raisedHandPeers.length > 1;
- return REaCt().createElement("div", {
- className: `
- ${FloatingVideo.NAMESPACE}-alert
- alert--waiting-peers
- theme-dark-forced
- `,
- onClick: onCallExpand
- }, REaCt().createElement(meetings_button.A, {
- className: "close js-close",
- icon: "sprite-fm-mono icon-dialog-close",
- hideWrList,
- hideHandsList,
- onClick: ev => {
- ev.stopPropagation();
- this.setState({
- hideHandsList: hideWrList || showRaised,
- hideWrList: true
- });
- }
- }), REaCt().createElement("div", {
- className: `alert-label ${showButton ? '' : 'label-only'}`
- }, showRaised && REaCt().createElement("i", {
- className: "sprite-fm-uni icon-raise-hand"
- }), !hideWrList && !!waitingRoomPeers.length && mega.icu.format(l.wr_peers_waiting, waitingRoomPeers.length), showRaised && (raisedHandPeers.length > 1 ? raisedHandPeers.includes(u_handle) ? mega.icu.format(l.raise_self_peers_raised, raisedHandPeers.length - 1) : mega.icu.format(l.raise_peers_raised, raisedHandPeers.length) : REaCt().createElement(utils.P9, {
- tag: "span",
- content: raisedHandPeers[0] === u_handle ? l.raise_self_raised : l.raise_peer_raised.replace('%s', megaChat.html(M.getNameByHandle(raisedHandPeers[0])))
- }))), showButton && REaCt().createElement(meetings_button.A, {
- className: "show-people",
- label: showRaised ? l[16797] : l.wr_see_waiting,
- onClick: ev => {
- ev.stopPropagation();
- const promise = onCallExpand().catch(dump);
- if (showRaised) {
- promise.then(() => onParticipantsToggle(true));
- } else if (waitingRoomPeers.length > 1) {
- promise.then(() => onWrListToggle(true));
- }
- }
- }, showRaised ? l[16797] : l.wr_see_waiting));
- };
- this.state.waitingRoomPeers = this.props.waitingRoomPeers || [];
- this.state.raisedHandPeers = this.props.raisedHandPeers || [];
+
+ },
+
+ 836
+(_, EXP_, REQ_) {
+
+"use strict";
+ REQ_.d(EXP_, {
+ SN: () => hasContacts,
+ U_: () => resetCredentials,
+ X7: () => hasRelationship,
+ d_: () => LABEL,
+ gR: () => VIEW,
+ p4: () => isVerified,
+ qH: () => verifyCredentials,
+ qY: () => EVENTS,
+ ym: () => getUserFingerprint
+ });
+ const react0__ = REQ_(1594);
+ const react0___default = REQ_.n(react0__);
+
+const EVENTS = {
+ KEYDOWN: 'keydown'
+};
+const VIEW = {
+ CONTACTS: 0x00,
+ RECEIVED_REQUESTS: 0x01,
+ SENT_REQUESTS: 0x02,
+ PROFILE: 0x03
+};
+const LABEL = {
+ CONTACTS: l[165],
+ RECEIVED_REQUESTS: l[5863],
+ SENT_REQUESTS: l[5862]
+};
+const hasContacts = () => M.u.some(contact => contact.c === 1);
+const hasRelationship = contact => contact && contact.c === 1;
+const isVerified = contact => {
+ if (contact && contact.u) {
+ const {
+ u: handle
+ } = contact;
+ const verificationState = u_authring.Ed25519[handle] || {};
+ return verificationState.method >= authring.AUTHENTICATION_METHOD.FINGERPRINT_COMPARISON;
+ }
+ return null;
+};
+const verifyCredentials = contact => {
+ if (contact.c === 1 && u_authring && u_authring.Ed25519) {
+ const verifyState = u_authring.Ed25519[contact.u] || {};
+ if (typeof verifyState.method === "undefined" || verifyState.method < authring.AUTHENTICATION_METHOD.FINGERPRINT_COMPARISON) {
+ fingerprintDialog(contact.u);
+ }
+ }
+};
+const resetCredentials = contact => {
+ if (M.isInvalidUserStatus()) {
+ return;
}
- componentDidMount() {
- super.componentDidMount();
- this.getUnread();
- this.waitingPeersListener = mBroadcaster.addListener('meetings:peersWaiting', waitingRoomPeers => this.setState({
- waitingRoomPeers,
- hideWrList: false,
- hideHandsList: false
- }, () => this.safeForceUpdate()));
- this.raisedHandListener = mBroadcaster.addListener('meetings:raisedHand', raisedHandPeers => this.setState({
- raisedHandPeers,
- hideWrList: false,
- hideHandsList: false
- }, () => this.safeForceUpdate()));
- ['onCallPeerJoined', 'onCallPeerLeft'].map(event => this.props.chatRoom.rebind(`${event}.${Minimized.NAMESPACE}`, (ev, {
- userHandle
- }) => this.isMounted() && this.setState(state => ({
- raisedHandPeers: state.raisedHandPeers.includes(userHandle) ? state.raisedHandPeers.filter(h => h !== userHandle) : [...this.props.call.sfuClient.raisedHands]
- }), this.safeForceUpdate)));
+ authring.resetFingerprintsForUser(contact.u).then(() => contact.trackDataChange()).catch(dump);
+};
+const getUserFingerprint = handle => {
+ const $$FINGERPRINT = [];
+ userFingerprint(handle, fingerprints => {
+ for (let i = 0; i < fingerprints.length; i++) {
+ $$FINGERPRINT.push(JSX_("span", {
+ key: i
+ }, fingerprints[i]));
+ }
+ });
+ return $$FINGERPRINT;
+};
+
+ },
+
+ 4904
+(_, EXP_, REQ_) {
+
+"use strict";
+
+// EXPORTS
+REQ_.d(EXP_, {
+ qY: () => EVENTS,
+ Vw: () => VIEWS,
+ Ay: () => conversations
+});
+
+// EXTERNAL MODULE: ./node_modules/@babel/runtime/helpers/esm/extends.js
+const esm_extends = REQ_(8168);
+// EXTERNAL MODULE: external "React"
+const external_React_ = REQ_(1594);
+const REaCt = REQ_.n(external_React_);
+// EXTERNAL MODULE: ./js/chat/mixins.js
+const mixins = REQ_(8264);
+// EXTERNAL MODULE: ./js/chat/ui/meetings/utils.jsx
+const utils = REQ_(3901);
+// EXTERNAL MODULE: ./js/ui/modalDialogs.jsx + 1 modules
+const modalDialogs = REQ_(8120);
+;// ./js/chat/ui/meetings/workflow/freeCallEnded.jsx
+
+
+const NAMESPACE = 'free-call-ended-dlg';
+class FreeCallEnded extends REaCt().Component {
+ constructor(...args) {
+ super(...args);
+ this.domRef = REaCt().createRef();
}
componentWillUnmount() {
- super.componentWillUnmount();
- this.props.chatRoom.unbind(Minimized.UNREAD_EVENT);
- [this.waitingPeersListener, this.raisedHandListener].map(listener => mBroadcaster.removeListener(listener));
- ['onCallPeerJoined', 'onCallPeerLeft'].map(event => this.props.chatRoom.off(`${event}.${Minimized.NAMESPACE}`));
+ if ($.dialog === NAMESPACE) {
+ closeDialog();
+ }
+ }
+ componentDidMount() {
+ M.safeShowDialog(NAMESPACE, () => {
+ if (!this.domRef.current) {
+ throw new Error(`${NAMESPACE} dialog: component ${NAMESPACE} not mounted.`);
+ }
+ eventlog(500295);
+ return $(`#${NAMESPACE}`);
+ });
}
render() {
const {
- onCallExpand
+ onClose
} = this.props;
- const {
- unread,
- raisedHandPeers,
- waitingRoomPeers
- } = this.state;
- return REaCt().createElement("div", {
+ return JSX_(modalDialogs.A.ModalDialog, {
+ id: NAMESPACE,
ref: this.domRef,
- className: `${FloatingVideo.NAMESPACE}-wrapper`
- }, REaCt().createElement("div", {
- className: `${FloatingVideo.NAMESPACE}-overlay`
- }, REaCt().createElement(meetings_button.A, {
- simpletip: {
- ...this.SIMPLETIP_PROPS,
- label: l.expand_mini_call
- },
- className: "mega-button theme-light-forced action small expand",
- icon: "sprite-fm-mono icon-fullscreen-enter",
- onClick: ev => {
- ev.stopPropagation();
- onCallExpand();
+ className: "mega-dialog",
+ dialogType: "action",
+ dialogName: NAMESPACE,
+ onClose
+ }, JSX_("header", null, JSX_("div", {
+ className: "free-call-ended graphic"
+ }, JSX_("img", {
+ src: `${staticpath}images/mega/chat-upgrade-rocket.png`
+ }))), JSX_("section", {
+ className: "content"
+ }, JSX_("div", {
+ className: "content-block"
+ }, JSX_("div", {
+ className: "dialog-body-text"
+ }, JSX_("h3", null, l.free_call_ended_dlg_text), JSX_("span", null, l.free_call_ended_dlg_subtext)))), JSX_("footer", null, JSX_("div", {
+ className: "footer-container"
+ }, JSX_("button", {
+ className: "mega-button positive large",
+ onClick: () => {
+ loadSubPage('pro');
+ eventlog(500261);
+ onClose();
}
- }), this.renderStreamControls()), waitingRoomPeers && waitingRoomPeers.length || raisedHandPeers && raisedHandPeers.length ? this.renderPeersList() : null, unread ? REaCt().createElement("div", {
- className: `${FloatingVideo.NAMESPACE}-notifications`
- }, REaCt().createElement(meetings_button.A, {
- className: "mega-button round large chat-control",
- icon: "icon-chat-filled"
- }, REaCt().createElement("span", null, l.chats)), REaCt().createElement("span", null, unread > 9 ? '9+' : unread)) : null);
+ }, JSX_("span", null, l.upgrade_now)))));
}
}
-Minimized.NAMESPACE = 'float-video-minimized';
-Minimized.UNREAD_EVENT = 'onUnreadCountUpdate.localStreamNotifications';
-const __Minimized = (0,mixins.Zz)(micObserver.Q, permissionsObserver.$)(Minimized);
-// EXTERNAL MODULE: ./js/chat/ui/inviteParticipantsPanel.jsx
-const inviteParticipantsPanel = REQ_(815);
-;// ./js/chat/ui/meetings/participantsNotice.jsx
-
-
-
-
+// EXTERNAL MODULE: ./js/chat/ui/contactsPanel/utils.jsx
+const contactsPanel_utils = REQ_(836);
+// EXTERNAL MODULE: ./js/chat/ui/leftPanel/utils.jsx
+const leftPanel_utils = REQ_(4664);
+// EXTERNAL MODULE: ./js/chat/ui/link.jsx
+const ui_link = REQ_(4649);
+;// ./js/chat/ui/errorBoundary.jsx
-class ParticipantsNotice extends mixins.w9 {
- constructor(props) {
- super(props);
- this.domRef = REaCt().createRef();
- this.renderUserAlone = () => REaCt().createElement("div", {
- className: `
- ${ParticipantsNotice.NAMESPACE}
- theme-dark-forced
- user-alone
- `
- }, this.props.stayOnEnd ? REaCt().createElement("div", {
- className: `${ParticipantsNotice.NAMESPACE}-heading`
- }, REaCt().createElement("h1", null, this.props.everHadPeers ? l.only_one_here : l.waiting_for_others)) : REaCt().createElement("div", {
- className: `${ParticipantsNotice.NAMESPACE}-content user-alone`
- }, REaCt().createElement("h3", null, l.only_one_here), REaCt().createElement("p", {
- className: "theme-dark-forced"
- }, REaCt().createElement(utils.P9, null, l.empty_call_dlg_text.replace('%s', '2'))), REaCt().createElement("div", {
- className: "notice-footer"
- }, REaCt().createElement(meetings_button.A, {
- className: "mega-button large stay-on-call",
- onClick: this.props.onStayConfirm
- }, REaCt().createElement("span", null, l.empty_call_stay_button)), REaCt().createElement(meetings_button.A, {
- className: "mega-button positive large stay-on-call",
- onClick: this.props.onCallEnd
- }, REaCt().createElement("span", null, l.empty_call_dlg_end)))));
- this.renderUserWaiting = () => {
- const {
- chatRoom,
- onInviteToggle
- } = this.props;
- return REaCt().createElement("div", {
- className: `
- ${ParticipantsNotice.NAMESPACE}
- ${chatRoom.isMeeting ? '' : 'user-alone'}
- theme-dark-forced
- `
- }, REaCt().createElement("div", {
- className: `${ParticipantsNotice.NAMESPACE}-heading`
- }, chatRoom.type === 'private' ? REaCt().createElement("h1", null, REaCt().createElement(utils.zT, null, l.waiting_for_peer.replace('%NAME', chatRoom.getRoomTitle()))) : REaCt().createElement("h1", null, l.waiting_for_others)), chatRoom.isMeeting && chatRoom.publicLink && REaCt().createElement("div", {
- className: `${ParticipantsNotice.NAMESPACE}-content-invite`
- }, REaCt().createElement(inviteParticipantsPanel.Q, {
- chatRoom,
- disableLinkToggle: true,
- onAddParticipants: () => {
- this.setState({
- inviteDialog: false
- }, () => onInviteToggle());
- }
- })));
+class ErrorBoundary extends REaCt().Component {
+ constructor(...args) {
+ super(...args);
+ this.state = {
+ hasError: false,
+ error: null
};
- this.av = this.props.call.sfuClient.availAv;
+ this.handleRetry = () => this.setState({
+ hasError: false,
+ error: null
+ });
}
- specShouldComponentUpdate(newProps) {
- const {
- stayOnEnd,
- hasLeft,
- isOnHold,
- call
- } = this.props;
- const currAv = this.av;
- this.av = call.sfuClient.availAv;
- return newProps.stayOnEnd !== stayOnEnd || newProps.hasLeft !== hasLeft || newProps.isOnHold !== isOnHold || this.av !== currAv;
+ static getDerivedStateFromError(error) {
+ return {
+ hasError: true,
+ error
+ };
+ }
+ componentDidCatch(error, errorInfo) {
+ console.error(error, errorInfo);
}
render() {
const {
- call,
- hasLeft,
- streamContainer,
- chatRoom
- } = this.props;
- if (call.isDestroyed) {
- return null;
+ hasError,
+ error
+ } = this.state;
+ if (hasError) {
+ return JSX_("div", {
+ className: "meetings-error"
+ }, JSX_("div", {
+ className: "meetings-error--content"
+ }, JSX_("i", {
+ className: `
+ sprite-fm-illustration-wide
+ ${mega.ui.isDarkTheme() ? 'mega-logo-dark' : 'img-mega-logo-light'}
+ `
+ }), JSX_("h1", null, l[200]), JSX_("span", null, "Please ", JSX_(ui_link.A, {
+ onClick: this.handleRetry
+ }, "try again"), " or\xA0", JSX_(ui_link.A, {
+ onClick: () => location.reload()
+ }, "reload the page"), "."), d && JSX_("div", {
+ className: "meetings-error--details"
+ }, error.toString())));
}
- return REaCt().createElement("div", {
- ref: this.domRef,
- className: `${ParticipantsNotice.NAMESPACE}-container`
- }, call.isSharingScreen() ? null : REaCt().createElement(videoNode.Cn, {
- className: "local-stream-mirrored",
- chatRoom,
- source: call.getLocalStream()
- }), streamContainer(hasLeft ? this.renderUserAlone() : this.renderUserWaiting()));
+ return this.props.children;
}
}
-ParticipantsNotice.NAMESPACE = 'participants-notice';
-// EXTERNAL MODULE: ./js/chat/ui/chatToaster.jsx
-const chatToaster = REQ_(424);
-;// ./js/chat/ui/meetings/participantsBlock.jsx
+// EXTERNAL MODULE: ./js/chat/ui/fallback.jsx
+const fallback = REQ_(3439);
+;// ./js/chat/ui/conversations.jsx
+
+
-const MAX_STREAMS_PER_PAGE = 10;
-const SIMPLE_TIP = {
- position: 'top',
- offset: 5,
- className: 'theme-dark-forced'
+
+const LeftPanel = (0,external_React_.lazy)(() => REQ_.e( 493).then(REQ_.bind(REQ_, 4907)));
+const EmptyConversationsPanel = (0,external_React_.lazy)(() => REQ_.e( 493).then(REQ_.bind(REQ_, 8596)));
+const ChatToaster = (0,external_React_.lazy)(() => REQ_.e( 493).then(REQ_.bind(REQ_, 8491)));
+const ConversationPanels = (0,external_React_.lazy)(() => REQ_.e( 493).then(REQ_.bind(REQ_, 5677)).then(m => ({
+ default: m.ConversationPanels
+})));
+const ContactsPanel = (0,external_React_.lazy)(() => REQ_.e( 253).then(REQ_.bind(REQ_, 5392)));
+const ScheduleMeetingDialog = (0,external_React_.lazy)(() => REQ_.e( 716).then(REQ_.bind(REQ_, 8389)));
+const ScheduleOccurrenceDialog = (0,external_React_.lazy)(() => REQ_.e( 716).then(REQ_.bind(REQ_, 4156)));
+const ContactSelectorDialog = (0,external_React_.lazy)(() => REQ_.e( 543).then(REQ_.bind(REQ_, 2678)));
+const StartGroupChatWizard = (0,external_React_.lazy)(() => REQ_.e( 543).then(REQ_.bind(REQ_, 5199)));
+const StartMeetingDialog = (0,external_React_.lazy)(() => REQ_.e( 543).then(REQ_.bind(REQ_, 7190)));
+const VIEWS = {
+ CHATS: 0x00,
+ MEETINGS: 0x01,
+ LOADING: 0x02
};
-class ParticipantsBlock extends mixins.w9 {
- constructor(...args) {
- super(...args);
+const EVENTS = {
+ NAV_RENDER_VIEW: 'navRenderView'
+};
+window.convAppConstants = {
+ VIEWS,
+ EVENTS
+};
+class ConversationsApp extends mixins.w9 {
+ constructor(props) {
+ super(props);
this.domRef = REaCt().createRef();
- this.nodeMenuRef = REaCt().createRef();
- this.dupNodeMenuRef = REaCt().createRef();
+ this.chatRoomRef = null;
+ this.occurrenceRef = null;
this.state = {
- page: 0
+ startGroupChatDialog: false,
+ startMeetingDialog: false,
+ scheduleMeetingDialog: false,
+ scheduleOccurrenceDialog: false,
+ freeCallEndedDialog: false,
+ contactSelectorDialog: false,
+ view: VIEWS.LOADING,
+ callExpanded: false,
+ ipcData: null
};
- this.movePage = direction => this.setState(state => ({
- page: direction === PAGINATION.NEXT ? state.page + 1 : state.page - 1
- }));
- this.renderLocalNode = isPresenterNode => {
+ this._cacheRouting();
+ megaChat.rebind('onStartNewMeeting.convApp', () => this.startMeeting());
+ }
+ startMeeting() {
+ if (megaChat.hasSupportForCalls) {
+ return (0,utils.dQ)().then(() => this.setState({
+ startMeetingDialog: true
+ })).catch(() => d && console.warn('Already in a call.'));
+ }
+ return showToast('warning', l[7211]);
+ }
+ _cacheRouting() {
+ this.routingSection = this.props.megaChat.routingSection;
+ this.routingSubSection = this.props.megaChat.routingSubSection;
+ this.routingParams = this.props.megaChat.routingParams;
+ }
+ hasOpenDialog() {
+ return [...document.querySelectorAll('.mega-dialog')].some(dialog => !!(dialog.offsetParent || dialog.offsetWidth || dialog.offsetHeight));
+ }
+ specShouldComponentUpdate() {
+ if (this.routingSection !== this.props.megaChat.routingSection || this.routingSubSection !== this.props.megaChat.routingSubSection || this.routingParams !== this.props.megaChat.routingParams) {
+ this._cacheRouting();
+ return true;
+ }
+ }
+ componentDidMount() {
+ super.componentDidMount();
+ $(document).rebind('keydown.megaChatTextAreaFocus', e => {
+ if (!M.chat || e.megaChatHandled) {
+ return;
+ }
const {
- call,
- peers,
- mode,
- raisedHandPeers,
- chatRoom,
- forcedLocal,
- presenterThumbSelected,
- onSeparate,
- onSpeakerChange,
- onModeChange
- } = this.props;
- const localStream = call.getLocalStream();
- if (localStream) {
- const IS_SPEAKER_VIEW = mode === meetings_call.g.MAIN && forcedLocal;
- const VideoClass = isPresenterNode ? videoNode.Vm : videoNode.bJ;
- let isActive = false;
- if (isPresenterNode) {
- isActive = forcedLocal && !presenterThumbSelected;
- } else if (call.pinnedCid === 0 || forcedLocal) {
- if (presenterThumbSelected) {
- isActive = !isPresenterNode;
- } else if (localStream.hasScreen) {
- isActive = isPresenterNode;
- } else {
- isActive = true;
- }
+ currentlyOpenedChat
+ } = megaChat;
+ const currentRoom = megaChat.getCurrentRoom();
+ if (currentlyOpenedChat) {
+ if (currentRoom && currentRoom.isReadOnly() || $(e.target).is(".messages-textarea, input, textarea") || (e.ctrlKey || e.metaKey || e.which === 19) && e.keyCode === 67 || e.keyCode === 91 || e.keyCode === 17 || e.keyCode === 27 || e.altKey || e.metaKey || e.ctrlKey || e.shiftKey || this.hasOpenDialog() || document.querySelector('textarea:focus,select:focus,input:focus')) {
+ return;
}
- return REaCt().createElement(VideoClass, {
- key: `${u_handle}${isPresenterNode ? '_block' : ''}`,
- className: `
- local-stream-node
- ${call.isSharingScreen() ? '' : 'local-stream-mirrored'}
- ${isActive ? 'active' : ''}
- ${call.speakerCid === 0 ? 'active-speaker' : ''}
- `,
- simpletip: {
- ...SIMPLE_TIP,
- label: l[8885]
- },
- mode,
- raisedHandPeers,
- chatRoom,
- source: localStream,
- localAudioMuted: !(call.av & SfuClient.Av.Audio),
- isPresenterNode,
- onClick: (source, ev) => {
- const nodeMenuRef = isPresenterNode ? this.nodeMenuRef && this.nodeMenuRef.current : this.dupNodeMenuRef && this.dupNodeMenuRef.current;
- if (nodeMenuRef && nodeMenuRef.contains(ev.target)) {
- ev.preventDefault();
- ev.stopPropagation();
- return;
- }
- return onSpeakerChange(localStream, !isPresenterNode);
- }
- }, (peers == null ? void 0 : peers.length) && REaCt().createElement("div", {
- ref: isPresenterNode ? this.nodeMenuRef : this.dupNodeMenuRef,
- className: "node-menu theme-dark-forced"
- }, REaCt().createElement("div", {
- className: "node-menu-toggle"
- }, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-more-horizontal-thin-outline"
- })), REaCt().createElement("div", {
- className: "node-menu-content"
- }, REaCt().createElement("ul", null, REaCt().createElement("li", null, REaCt().createElement(meetings_button.A, {
- icon: `
- sprite-fm-mono
- ${IS_SPEAKER_VIEW ? 'grid-9' : 'grid-main'}
- `,
- onClick: () => {
- if (IS_SPEAKER_VIEW) {
- return onModeChange(meetings_call.g.THUMBNAIL);
- }
- return onSpeakerChange(localStream);
- }
- }, REaCt().createElement("span", null, IS_SPEAKER_VIEW ? l.switch_to_thumb_view : l.display_in_main_view))), REaCt().createElement("li", null, REaCt().createElement(meetings_button.A, {
- icon: "sprite-fm-mono grid-separate",
- onClick: onSeparate
- }, REaCt().createElement("span", null, l.separate_from_grid_button)))))));
+ const $typeArea = $('.messages-textarea:visible:first');
+ moveCursortoToEnd($typeArea);
+ e.megaChatHandled = true;
+ $typeArea.triggerHandler(e);
+ e.preventDefault();
+ e.stopPropagation();
+ return false;
}
- return null;
- };
- this.onScroll = (chunks, evt) => {
- const {
- page
- } = this.state;
- if (evt.deltaY < 0) {
- if (page > 0) {
- this.movePage(PAGINATION.PREV);
+ });
+ $(document).rebind('mouseup.megaChatTextAreaFocus', e => {
+ if (!M.chat || e.megaChatHandled || slideshowid) {
+ return;
+ }
+ const $target = $(e.target);
+ if (megaChat.currentlyOpenedChat) {
+ if ($target.is(".messages-textarea,a,input,textarea,select,button") || $target.is('i') && $target.parent().is('a,input,select,button') || $target.closest('.messages.scroll-area').length > 0 || $target.closest('.mega-dialog').length > 0 || this.hasOpenDialog() || document.querySelector('textarea:focus,select:focus,input:focus') || window.getSelection().toString()) {
+ return;
}
- } else if (evt.deltaY > 0) {
- if (page < Object.values(chunks).length - 1) {
- this.movePage(PAGINATION.NEXT);
+ const $typeArea = $('.messages-textarea:visible:first');
+ if ($typeArea.length === 1 && !$typeArea.is(":focus")) {
+ $typeArea.trigger("focus");
+ e.megaChatHandled = true;
}
}
- };
+ });
+ megaChat.rebind(megaChat.plugins.meetingsManager.EVENTS.EDIT, (ev, chatOrOccurrence) => {
+ if (chatOrOccurrence instanceof ChatRoom || !chatOrOccurrence) {
+ this.chatRoomRef = chatOrOccurrence;
+ this.setState({
+ scheduleMeetingDialog: true
+ });
+ } else {
+ this.occurrenceRef = chatOrOccurrence;
+ this.setState({
+ scheduleOccurrenceDialog: true
+ });
+ }
+ });
+ megaChat.rebind(EVENTS.NAV_RENDER_VIEW, ({
+ data
+ }) => {
+ if (Object.values(VIEWS).includes(data)) {
+ this.renderView(data);
+ }
+ });
+ megaChat.rebind('onCallTimeLimitExceeded', () => {
+ this.setState({
+ freeCallEndedDialog: true
+ });
+ });
+ if (megaChat.WITH_SELF_NOTE && !megaChat.getNoteChat() && !is_chatlink) {
+ api.req({
+ a: 'mcc',
+ u: [],
+ m: 0,
+ g: 0,
+ v: Chatd.VERSION
+ }).catch(dump);
+ }
+ this.requestReceivedListener = mBroadcaster.addListener('fmViewUpdate:ipc', () => {
+ this.setState({
+ ipcData: this.makeIpcData()
+ });
+ });
+ this.setState({
+ ipcData: this.makeIpcData()
+ });
+ }
+ componentWillUnmount() {
+ super.componentWillUnmount();
+ $(document).off('keydown.megaChatTextAreaFocus');
+ mBroadcaster.removeListener('fmViewUpdate:ipc', this.requestReceivedListener);
}
- shouldComponentUpdate() {
+ componentDidUpdate(prevProps, prevState) {
+ this.handleOnboardingStep();
const {
- peers
- } = this.props;
- return peers && peers.length;
- }
- render() {
+ names: prevNames
+ } = prevState.ipcData;
+ const newIpcData = this.makeIpcData();
const {
- call,
- mode,
- peers,
- floatDetached,
- chatRoom,
- raisedHandPeers,
- presenterThumbSelected,
- onSpeakerChange
- } = this.props;
- if (peers && peers.length) {
- const {
- screen,
- video,
- rest
- } = filterAndSplitSources(peers, call);
- const sources = [...screen, ...video, ...rest];
- const $$PEER = (peer, i) => {
- const {
- clientId,
- userHandle,
- hasScreenAndCam,
- hasScreen,
- isLocal
- } = peer;
- if (screen.length && (screen[0].clientId === clientId || screen[0].isLocal && isLocal)) {
- screen.shift();
- }
- if (!(peer instanceof CallManager2.Peer)) {
- const isPresenterNode = screen.length && screen[0].isLocal;
- if (floatDetached && !isPresenterNode) {
- return;
- }
- return this.renderLocalNode(!floatDetached && isPresenterNode);
- }
- const presenterCid = screen.length && screen[0].clientId === clientId;
- let PeerClass;
- if (hasScreenAndCam) {
- PeerClass = presenterCid ? videoNode.ob : videoNode.Qs;
- } else {
- PeerClass = videoNode.au;
- }
- assert(!presenterCid || hasScreen);
- const isActiveSpeaker = !peer.audioMuted && call.speakerCid === peer.clientId;
- let isActive = false;
- if (call.pinnedCid === clientId) {
- if (presenterThumbSelected) {
- isActive = !presenterCid;
- } else if (hasScreen) {
- isActive = presenterCid;
- } else {
- isActive = true;
- }
- }
- const name = M.getNameByHandle(userHandle);
- let label = name;
- if (presenterCid) {
- label = name ? l.presenter_nail.replace('%s', name) : megaChat.plugins.userHelper.SIMPLETIP_USER_LOADER;
- } else {
- label = name || megaChat.plugins.userHelper.SIMPLETIP_USER_LOADER;
- }
- return REaCt().createElement(PeerClass, {
- key: `${userHandle}-${i}-${clientId}`,
- className: `
- video-crop
- ${isActive ? 'active' : ''}
- ${isActiveSpeaker ? 'active-speaker' : ''}
- `,
- simpletip: {
- ...SIMPLE_TIP,
- label
- },
- raisedHandPeers,
- mode,
- chatRoom,
- source: peer,
- isPresenterNode: !!presenterCid,
- onSpeakerChange: node => onSpeakerChange(node, !presenterCid),
- onClick: node => onSpeakerChange(node, !presenterCid)
- });
- };
- if (sources.length <= (floatDetached ? MAX_STREAMS_PER_PAGE : 9)) {
- return REaCt().createElement("div", {
- ref: this.domRef,
- className: "stream-participants-block theme-dark-forced"
- }, REaCt().createElement("div", {
- className: "participants-container"
- }, REaCt().createElement("div", {
- className: `
- participants-grid
- ${floatDetached && sources.length === 1 || sources.length === 0 ? 'single-column' : ''}
- `
- }, sources.map((p, i) => $$PEER(p, i)))));
+ names: newNames
+ } = newIpcData;
+ if (newNames.size !== prevNames.size) {
+ this.setState({
+ ipcData: newIpcData
+ });
+ return;
+ }
+ let different = false;
+ for (const [email, name] of newNames) {
+ if (!prevNames.has(email) || prevNames.get(email) !== name) {
+ different = true;
+ break;
}
- const {
- page
- } = this.state;
- const chunks = chunkNodes(sources, MAX_STREAMS_PER_PAGE);
- return REaCt().createElement("div", {
- ref: this.domRef,
- className: "carousel"
- }, REaCt().createElement("div", {
- className: "carousel-container",
- onWheel: evt => this.onScroll(chunks, evt)
- }, REaCt().createElement("div", {
- className: "stream-participants-block theme-dark-forced"
- }, REaCt().createElement("div", {
- className: "participants-container"
- }, Object.values(chunks).map((chunk, i) => {
- const {
- id,
- nodes
- } = chunk;
- return REaCt().createElement("div", {
- key: id,
- className: `
- carousel-page
- ${i === page ? 'active' : ''}
- `
- }, page === 0 ? null : REaCt().createElement("button", {
- className: "carousel-control carousel-button-prev theme-dark-forced",
- onClick: () => this.movePage(PAGINATION.PREV)
- }, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-arrow-up"
- })), REaCt().createElement("div", {
- className: `
- participants-grid
- ${nodes.length === 1 ? 'single-column' : ''}
- `
- }, nodes.map((peer, j) => $$PEER(peer, j + i * MAX_STREAMS_PER_PAGE))), page >= Object.values(chunks).length - 1 ? null : REaCt().createElement("button", {
- className: "carousel-control carousel-button-next theme-dark-forced",
- onClick: () => this.movePage(PAGINATION.NEXT)
- }, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-arrow-down"
- })));
- })))));
}
- return null;
+ if (different) {
+ this.setState({
+ ipcData: newIpcData
+ });
+ }
}
-}
-// EXTERNAL MODULE: ./js/chat/ui/meetings/videoNodeMenu.jsx
-const videoNodeMenu = REQ_(539);
-// EXTERNAL MODULE: ./js/ui/modalDialogs.jsx + 1 modules
-const modalDialogs = REQ_(318);
-;// ./js/chat/ui/meetings/modeSwitch.jsx
-
-
-
-
-
-class ModeSwitch extends mixins.w9 {
- constructor(...args) {
- super(...args);
- this.domRef = REaCt().createRef();
- this.state = {
- expanded: false,
- settings: false
- };
- this.handleMousedown = ({
- target
- }) => {
- if (this.state.expanded || this.state.settings) {
- let _this$domRef;
- return (_this$domRef = this.domRef) != null && (_this$domRef = _this$domRef.current) != null && _this$domRef.contains(target) ? null : this.doClose();
+ handleOnboardingStep() {
+ if (this.state.view === VIEWS.LOADING) {
+ return;
+ }
+ megaChat.plugins.chatOnboarding.checkAndShowStep();
+ }
+ renderView(view) {
+ this.setState({
+ view
+ }, () => {
+ const {
+ $chatTreePanePs,
+ routingSection,
+ currentlyOpenedChat
+ } = megaChat;
+ Object.values($chatTreePanePs).forEach(ref => ref.reinitialise == null ? void 0 : ref.reinitialise());
+ if (routingSection !== 'chat') {
+ loadSubPage('fm/chat');
}
- };
- this.handleKeydown = ({
- keyCode
- }) => keyCode && keyCode === 27 && this.doClose();
- this.doClose = () => this.isMounted() && this.setState({
- expanded: false,
- settings: false
- }, () => this.props.setActiveElement(this.state.expanded));
- this.doToggle = () => this.isMounted() && this.setState(state => ({
- expanded: !state.expanded
- }), () => this.props.setActiveElement(this.state.expanded || this.state.settings));
- this.setStreamsPerPage = streamsPerPage => {
- if (streamsPerPage) {
- let _this$props$onStreams, _this$props;
- (_this$props$onStreams = (_this$props = this.props).onStreamsPerPageChange) == null || _this$props$onStreams.call(_this$props, streamsPerPage);
- this.doClose();
+ megaChat.currentlyOpenedView = view;
+ if (!currentlyOpenedChat) {
+ megaChat.renderListing(null, false).catch(dump);
}
- };
- this.getModeIcon = mode => {
- switch (mode) {
- case meetings_call.g.THUMBNAIL:
- return 'grid-9';
- case meetings_call.g.MAIN:
- return 'grid-main';
- default:
- return null;
+ });
+ }
+ makeIpcData() {
+ let mixed = false;
+ const names = new Map();
+ const data = Object.values(M.ipc).reduce((acc, curr) => {
+ const name = M.getNameByEmail(curr.m);
+ if (name !== curr.m) {
+ names.set(curr.m, name);
+ mixed = true;
}
- };
- this.Toggle = () => {
- const {
- mode
- } = this.props;
- return REaCt().createElement("div", {
- className: `${ModeSwitch.BASE_CLASS}-toggle`,
- onClick: this.doToggle
- }, REaCt().createElement(meetings_button.A, null, REaCt().createElement("i", {
- className: `sprite-fm-mono ${this.getModeIcon(mode)}`
- }), mode === meetings_call.g.THUMBNAIL && REaCt().createElement("div", null, l.thumbnail_view), mode === meetings_call.g.MAIN && REaCt().createElement("div", null, l.main_view)), REaCt().createElement("i", {
- className: "sprite-fm-mono icon-arrow-down"
- }));
- };
- this.Option = ({
- label,
- mode
- }) => {
- return REaCt().createElement("div", {
- className: `
- ${ModeSwitch.BASE_CLASS}-option
- ${mode === this.props.mode ? 'active' : ''}
- `,
- onClick: () => {
- this.doToggle();
- this.props.onModeChange(mode);
- }
- }, REaCt().createElement(meetings_button.A, null, REaCt().createElement("i", {
- className: `sprite-fm-mono ${this.getModeIcon(mode)}`
- }), REaCt().createElement("div", null, label)));
- };
- this.Settings = () => {
- const {
- streamsPerPage
- } = this.props;
- return REaCt().createElement("div", {
- className: `${ModeSwitch.BASE_CLASS}-settings`
- }, REaCt().createElement("div", {
- className: "settings-wrapper"
- }, REaCt().createElement("strong", null, l.layout_settings_heading), REaCt().createElement("span", null, l.layout_settings_info), REaCt().createElement("div", {
- className: "recurring-radio-buttons"
- }, REaCt().createElement("div", {
- className: "recurring-label-wrap"
- }, REaCt().createElement("div", {
- className: `
- uiTheme
- ${streamsPerPage === STREAMS_PER_PAGE.MIN ? 'radioOn' : 'radioOff'}
- `
- }, REaCt().createElement("input", {
- type: "radio",
- name: "9",
- onClick: () => this.setStreamsPerPage(STREAMS_PER_PAGE.MIN)
- })), REaCt().createElement("div", {
- className: "radio-txt"
- }, REaCt().createElement("span", {
- className: "recurring-radio-label",
- onClick: () => this.setStreamsPerPage(STREAMS_PER_PAGE.MIN)
- }, "9"))), REaCt().createElement("div", {
- className: "recurring-label-wrap"
- }, REaCt().createElement("div", {
- className: `
- uiTheme
- ${streamsPerPage === STREAMS_PER_PAGE.MED ? 'radioOn' : 'radioOff'}
- `
- }, REaCt().createElement("input", {
- type: "radio",
- name: "21",
- onClick: () => {
- this.setStreamsPerPage(STREAMS_PER_PAGE.MED);
- }
- })), REaCt().createElement("div", {
- className: "radio-txt"
- }, REaCt().createElement("span", {
- className: "recurring-radio-label",
- onClick: () => this.setStreamsPerPage(STREAMS_PER_PAGE.MED)
- }, "21"))), REaCt().createElement("div", {
- className: "recurring-label-wrap"
- }, REaCt().createElement("div", {
- className: `
- uiTheme
- ${streamsPerPage === STREAMS_PER_PAGE.MAX ? 'radioOn' : 'radioOff'}
- `
- }, REaCt().createElement("input", {
- type: "radio",
- name: "49",
- onClick: () => {
- this.setStreamsPerPage(STREAMS_PER_PAGE.MAX);
+ return {
+ ...acc,
+ [curr.p]: {
+ ...curr,
+ name
}
- })), REaCt().createElement("div", {
- className: "radio-txt"
- }, REaCt().createElement("span", {
- className: "recurring-radio-label",
- onClick: () => this.setStreamsPerPage(STREAMS_PER_PAGE.MAX)
- }, "49")))), REaCt().createElement("small", null, l.layout_settings_warning)), REaCt().createElement("div", {
- className: "settings-close"
- }, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-dialog-close",
- onClick: this.doClose
- })));
+ };
+ }, Object.create(null));
+ return {
+ mixed,
+ data,
+ names
};
}
- componentWillUnmount() {
- super.componentWillUnmount();
- document.removeEventListener('mousedown', this.handleMousedown);
- document.removeEventListener('keydown', this.handleKeydown);
- }
- componentDidMount() {
- super.componentDidMount();
- document.addEventListener('mousedown', this.handleMousedown);
- document.addEventListener('keydown', this.handleKeydown);
- }
render() {
const {
- Toggle,
- Option,
- Settings,
- domRef,
- state,
- doToggle
- } = this;
- return REaCt().createElement("div", {
- ref: domRef,
- className: ModeSwitch.BASE_CLASS
- }, REaCt().createElement(Toggle, null), REaCt().createElement("div", {
+ CHATS,
+ MEETINGS
+ } = VIEWS;
+ const {
+ routingSection,
+ chatUIFlags,
+ currentlyOpenedChat,
+ chats
+ } = megaChat;
+ const {
+ view,
+ startGroupChatDialog,
+ startMeetingDialog,
+ scheduleMeetingDialog,
+ scheduleOccurrenceDialog,
+ callExpanded,
+ freeCallEndedDialog,
+ contactSelectorDialog
+ } = this.state;
+ const isEmpty = chats && routingSection === 'chat' && !currentlyOpenedChat && !is_chatlink;
+ const isLoading = !currentlyOpenedChat && megaChat.allChatsHadInitialLoadedHistory() === false && routingSection !== 'contacts';
+ const rightPane = JSX_("div", {
className: `
- ${ModeSwitch.BASE_CLASS}-menu
- ${state.expanded ? 'expanded' : ''}
- `
- }, REaCt().createElement(Option, {
- label: l.main_view,
- mode: meetings_call.g.MAIN
- }), REaCt().createElement(Option, {
- label: l.thumbnail_view,
- mode: meetings_call.g.THUMBNAIL
- }), REaCt().createElement("div", {
- className: `${ModeSwitch.BASE_CLASS}-option`,
- onClick: () => this.setState({
- settings: true
- }, doToggle)
- }, REaCt().createElement(meetings_button.A, null, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-settings"
- }), REaCt().createElement("div", null, l.layout_settings_button)))), state.settings && REaCt().createElement(Settings, null));
+ fm-right-files-block
+ in-chat
+ ${is_chatlink ? 'chatlink' : ''}
+ `
+ }, JSX_(external_React_.Suspense, {
+ fallback: JSX_(fallback.A, null)
+ }, !isLoading && JSX_(ChatToaster, {
+ isRootToaster: true
+ }), !isLoading && routingSection === 'contacts' && JSX_(ContactsPanel, {
+ megaChat,
+ contacts: M.u,
+ received: this.state.ipcData,
+ sent: M.opc
+ }), !isLoading && JSX_(ConversationPanels, (0,esm_extends.A)({}, this.props, {
+ className: routingSection === 'chat' ? '' : 'hidden',
+ routingSection,
+ currentlyOpenedChat,
+ isEmpty,
+ chatUIFlags,
+ onToggleExpandedFlag: () => this.setState(() => ({
+ callExpanded: (0,utils.Av)()
+ })),
+ onMount: () => {
+ const chatRoom = megaChat.getCurrentRoom();
+ const view = chatRoom && chatRoom.isMeeting ? MEETINGS : CHATS;
+ this.setState({
+ view
+ }, () => {
+ megaChat.currentlyOpenedView = view;
+ });
+ }
+ })), !isLoading && isEmpty && JSX_(EmptyConversationsPanel, {
+ isMeeting: view === MEETINGS,
+ onNewChat: () => this.setState({
+ contactSelectorDialog: true
+ }),
+ onStartMeeting: () => this.startMeeting(),
+ onScheduleMeeting: () => this.setState({
+ scheduleMeetingDialog: true
+ })
+ })), !isLoading && routingSection === 'notFound' && JSX_("span", null, JSX_("center", null, "Section not found")));
+ const noteChat = megaChat.getNoteChat();
+ return JSX_(ErrorBoundary, null, JSX_("div", {
+ ref: this.domRef,
+ className: "conversationsApp"
+ }, JSX_(external_React_.Suspense, {
+ fallback: JSX_(fallback.A, null)
+ }, startMeetingDialog && JSX_(StartMeetingDialog, {
+ onStart: (topic, audio, video) => {
+ megaChat.createAndStartMeeting(topic, audio, video);
+ this.setState({
+ startMeetingDialog: false
+ });
+ },
+ onClose: () => this.setState({
+ startMeetingDialog: false
+ })
+ }), startGroupChatDialog && JSX_(StartGroupChatWizard, {
+ name: "start-group-chat",
+ flowType: 1,
+ onClose: () => this.setState({
+ startGroupChatDialog: false
+ }),
+ onConfirmClicked: () => this.setState({
+ startGroupChatDialog: false
+ })
+ }), scheduleMeetingDialog && JSX_(ScheduleMeetingDialog, {
+ chatRoom: this.chatRoomRef,
+ callExpanded,
+ onClose: () => {
+ this.setState({
+ scheduleMeetingDialog: false
+ }, () => {
+ this.chatRoomRef = null;
+ });
+ }
+ }), scheduleOccurrenceDialog && JSX_(ScheduleOccurrenceDialog, {
+ chatRoom: this.occurrenceRef.scheduledMeeting.chatRoom,
+ scheduledMeeting: this.occurrenceRef.scheduledMeeting,
+ occurrenceId: this.occurrenceRef.uid,
+ callExpanded,
+ onClose: () => {
+ this.setState({
+ scheduleOccurrenceDialog: false
+ }, () => {
+ this.occurrenceRef = null;
+ });
+ }
+ }), contactSelectorDialog && JSX_(ContactSelectorDialog, {
+ className: `main-start-chat-dropdown ${leftPanel_utils.C}-contact-selector`,
+ multiple: false,
+ topButtons: [{
+ key: 'newGroupChat',
+ title: l[19483],
+ className: 'positive',
+ onClick: () => this.setState({
+ startGroupChatDialog: true,
+ contactSelectorDialog: false
+ })
+ }, ...megaChat.WITH_SELF_NOTE ? (0,contactsPanel_utils.SN)() || noteChat && noteChat.hasMessages() ? [] : [{
+ key: 'noteChat',
+ title: l.note_label,
+ icon: 'sprite-fm-mono icon-file-text-thin-outline note-chat-icon',
+ onClick: () => {
+ closeDialog();
+ loadSubPage(`fm/chat/p/${u_handle}`);
+ }
+ }] : []],
+ showAddContact: (0,contactsPanel_utils.SN)(),
+ onClose: () => this.setState({
+ contactSelectorDialog: false
+ }),
+ onSelectDone: selected => {
+ if (selected.length === 1) {
+ return megaChat.createAndShowPrivateRoom(selected[0]).then(room => room.setActive());
+ }
+ megaChat.createAndShowGroupRoomFor(selected);
+ }
+ })), JSX_(external_React_.Suspense, {
+ fallback: JSX_(fallback.A, null)
+ }, routingSection && JSX_(LeftPanel, {
+ view,
+ views: VIEWS,
+ routingSection,
+ conversations: chats,
+ renderView: view => this.renderView(view),
+ startMeeting: () => {
+ this.startMeeting();
+ eventlog(500293);
+ },
+ scheduleMeeting: () => {
+ this.setState({
+ scheduleMeetingDialog: true
+ });
+ delay('chat-event-sm-button-main', () => eventlog(99918));
+ },
+ createNewChat: () => this.setState({
+ contactSelectorDialog: true
+ })
+ })), freeCallEndedDialog && JSX_(FreeCallEnded, {
+ onClose: () => {
+ this.setState({
+ freeCallEndedDialog: false
+ });
+ }
+ }), rightPane));
}
}
-ModeSwitch.NAMESPACE = 'modeSwitch';
-ModeSwitch.BASE_CLASS = 'mode';
-;// ./js/chat/ui/meetings/streamHead.jsx
+ const conversations = ConversationsApp;
+ },
+ 3439
+(_, EXP_, REQ_) {
+"use strict";
+ REQ_.d(EXP_, {
+ A: () => Fallback
+ });
+ const react0__ = REQ_(1594);
+ const react0___default = REQ_.n(react0__);
+class Fallback extends react0___default().Component {
+ render() {
+ return JSX_("div", {
+ className: "loading-spinner light"
+ }, JSX_("div", {
+ className: "main-loader"
+ }));
+ }
+}
+ },
+ 4664
+(_, EXP_, REQ_) {
+"use strict";
+ REQ_.d(EXP_, {
+ C: () => NAMESPACE,
+ x: () => FILTER
+ });
+const NAMESPACE = 'lhp';
+const FILTER = {
+ MUTED: 'muted',
+ UNREAD: 'unread'
+};
+ },
-class StreamHead extends mixins.w9 {
- constructor(...args) {
- super(...args);
- this.delayProcID = null;
- this.domRef = REaCt().createRef();
- this.durationRef = REaCt().createRef();
- this.dialogRef = REaCt().createRef();
- this.topicRef = REaCt().createRef();
- this.interval = undefined;
- this.state = {
- dialog: false,
- duration: undefined,
- banner: false,
- modeSwitch: false
- };
- this.updateDurationDOM = () => {
- if (this.durationRef) {
- this.durationRef.current.innerText = this.durationString;
- }
- };
- this.closeTooltips = () => {
- for (const node of this.domRef.current.querySelectorAll('.simpletip')) {
- node.dispatchEvent(StreamHead.EVENTS.SIMPLETIP);
- }
- };
- this.toggleFullscreen = () => this.fullscreen ? document.exitFullscreen() : document.documentElement.requestFullscreen();
- this.toggleBanner = callback => this.setState(state => ({
- banner: !state.banner
- }), () => callback && callback());
- this.handleDialogClose = ({
- target
- }) => {
- if (this.state.dialog) {
- let _targetDialog$domRef;
- const {
- topicRef,
- dialogRef,
- delayProcID
- } = this;
- const topicElement = topicRef && topicRef.current;
- const targetDialog = dialogRef && dialogRef.current && dialogRef.current;
- const dialogElement = (_targetDialog$domRef = targetDialog.domRef) == null ? void 0 : _targetDialog$domRef.current;
- if (topicElement.contains(target)) {
- return;
- }
- return (target.classList.contains('icon-dialog-close') || !dialogElement.contains(target)) && this.setState({
- dialog: false
- }, () => delayProcID && delay.cancel(delayProcID));
- }
- };
- this.getModerators = () => {
- let _this$props$chatRoom;
- const members = (_this$props$chatRoom = this.props.chatRoom) == null ? void 0 : _this$props$chatRoom.members;
- if (members) {
- const moderators = [];
- for (const [handle, role] of Object.entries(members)) {
- if (role === ChatRoom.MembersSet.PRIVILEGE_STATE.OPERATOR) {
- moderators.push(M.getNameByHandle(handle));
- }
- }
- return mega.utils.trans.listToString(moderators, mega.icu.format(l.meeting_moderators, moderators.length));
- }
- };
- this.Dialog = () => {
- const link = `${getBaseUrl()}/${this.props.chatRoom.publicLink}`;
- const mods = this.getModerators();
- return REaCt().createElement(modalDialogs.A.ModalDialog, (0,esm_extends.A)({
- ref: this.dialogRef
- }, this.state, {
- mods,
- name: "meeting-info-dialog",
- title: l[18132],
- className: "group-chat-link dialog-template-main theme-dark-forced in-call-info",
- hideOverlay: true
- }), REaCt().createElement("section", {
- className: "content"
- }, REaCt().createElement("div", {
- className: "content-block"
- }, REaCt().createElement(utils.zT, {
- className: "info"
- }, mods), REaCt().createElement("div", {
- className: "info"
- }, l.copy_and_share), REaCt().createElement("div", {
- className: "link-input-container"
- }, REaCt().createElement("div", {
- className: "mega-input with-icon box-style"
- }, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-link"
- }), REaCt().createElement("input", {
- type: "text",
- className: "megaInputs",
- readOnly: true,
- value: link
- })), REaCt().createElement(meetings_button.A, {
- className: "mega-button positive copy-to-clipboard",
- onClick: () => {
- if (copyToClipboard(link)) {
- this.toggleBanner(() => {
- this.delayProcID = delay(`${StreamHead.NAMESPACE}-banner`, this.toggleBanner, 10000);
- });
- }
- }
- }, REaCt().createElement("span", null, l[63]))), this.state.banner && REaCt().createElement("div", {
- className: "banner-copy-success"
- }, l[7654]))), REaCt().createElement("footer", null, REaCt().createElement("div", {
- className: "footer-container"
- })));
- };
- this.Pagination = () => {
- const {
- mode,
- peers,
- page,
- streamsPerPage,
- floatDetached,
- chunksLength,
- call,
- onMovePage
- } = this.props;
- if (mode !== meetings_call.g.THUMBNAIL || !peers) {
- return null;
- }
- const {
- screen,
- video,
- rest
- } = filterAndSplitSources(peers, call);
- if (screen.length + video.length + rest.length > (floatDetached ? streamsPerPage + 1 : streamsPerPage)) {
- return REaCt().createElement("div", {
- className: `${StreamHead.NAMESPACE}-pagination`
- }, REaCt().createElement(meetings_button.A, {
- className: `
- carousel-button-prev
- theme-dark-forced
- ${page !== 0 ? '' : 'disabled'}
- `,
- icon: "sprite-fm-mono icon-arrow-left",
- onClick: () => page !== 0 && onMovePage(PAGINATION.PREV)
- }), REaCt().createElement("div", null, page + 1, "/", chunksLength), REaCt().createElement(meetings_button.A, {
- className: `
- carousel-button-next
- theme-dark-forced
- ${page < chunksLength - 1 ? '' : 'disabled'}
- `,
- icon: "sprite-fm-mono icon-arrow-right",
- onClick: () => page < chunksLength - 1 && onMovePage(PAGINATION.NEXT)
- }));
- }
- return null;
- };
- }
- get fullscreen() {
- return document.fullscreenElement;
- }
- get duration() {
- return (Date.now() - this.props.call.ts) / 1000;
- }
- get durationString() {
- return this.duration ? secondsToTimeShort(this.duration) : '--:--:--';
- }
- componentWillUnmount() {
- super.componentWillUnmount();
- clearInterval(this.durationInterval);
- document.removeEventListener(StreamHead.EVENTS.FULLSCREEN, this.closeTooltips);
- document.removeEventListener(StreamHead.EVENTS.CLICK_DIALOG, this.handleDialogClose);
+ 4649
+(_, EXP_, REQ_) {
+
+"use strict";
+ REQ_.d(EXP_, {
+ A: () => Link
+ });
+ const react0__ = REQ_(1594);
+ const react0___default = REQ_.n(react0__);
+
+class Link extends react0___default().Component {
+ constructor(props) {
+ super(props);
+ this.IS_CLICK_URL = undefined;
+ this.IS_CLICK_URL = this.props.to && (this.props.to.startsWith('/') || this.props.to.includes('mega.io'));
}
componentDidMount() {
- super.componentDidMount();
- this.durationInterval = setInterval(this.updateDurationDOM, 1000);
- document.addEventListener(StreamHead.EVENTS.FULLSCREEN, this.closeTooltips);
- document.addEventListener(StreamHead.EVENTS.CLICK_DIALOG, this.handleDialogClose);
+ if (this.IS_CLICK_URL) {
+ clickURLs();
+ }
}
render() {
const {
- NAMESPACE
- } = StreamHead;
- const {
- mode,
- streamsPerPage,
- chatRoom,
- onStreamsPerPageChange,
- onCallMinimize,
- onModeChange,
- setActiveElement
+ className,
+ to,
+ target,
+ children,
+ onClick
} = this.props;
- const {
- dialog
- } = this.state;
- const SIMPLETIP = {
- position: 'bottom',
- offset: 5,
- className: 'theme-dark-forced'
- };
- return REaCt().createElement("div", {
- ref: this.domRef,
- className: `${NAMESPACE}`
- }, dialog && REaCt().createElement(this.Dialog, null), REaCt().createElement("div", {
- className: `${NAMESPACE}-content theme-dark-forced`
- }, REaCt().createElement("div", {
- className: `${NAMESPACE}-info`
- }, REaCt().createElement("div", {
- ref: this.durationRef,
- className: "stream-duration"
- }, this.durationString), REaCt().createElement("div", {
- ref: this.topicRef,
- className: `
- stream-topic
- ${chatRoom.isMeeting && chatRoom.publicLink ? 'has-meeting-link' : ''}
- `,
- onClick: () => chatRoom.isMeeting && chatRoom.publicLink && this.setState({
- dialog: !dialog,
- banner: false
- }, () => setActiveElement(this.state.dialog))
- }, REaCt().createElement(utils.zT, null, chatRoom.getRoomTitle()), chatRoom.isMeeting && chatRoom.publicLink && REaCt().createElement("i", {
- className: `
- sprite-fm-mono
- ${dialog ? 'icon-arrow-up' : 'icon-arrow-down'}
- `
- }))), REaCt().createElement(this.Pagination, null), REaCt().createElement("div", {
- className: `${NAMESPACE}-controls`
- }, REaCt().createElement(ModeSwitch, {
- mode,
- streamsPerPage,
- onStreamsPerPageChange,
- onModeChange,
- setActiveElement
- }), REaCt().createElement(meetings_button.A, {
- className: "head-control",
- simpletip: {
- ...SIMPLETIP,
- label: this.fullscreen ? l.exit_fullscreen : l[17803]
- },
- icon: this.fullscreen ? 'icon-fullscreen-leave' : 'icon-fullscreen-enter',
- onClick: this.toggleFullscreen
- }, REaCt().createElement("span", null, this.fullscreen ? l.exit_fullscreen : l[17803])), REaCt().createElement(meetings_button.A, {
- className: "head-control",
- simpletip: {
- ...SIMPLETIP,
- label: l.minimize
- },
- icon: "icon-call-min-mode",
- onClick: () => {
- onCallMinimize();
- eventlog(500305);
+ if (this.IS_CLICK_URL) {
+ return JSX_("a", {
+ className: `
+ clickurl
+ ${className || ''}
+ `,
+ href: to,
+ target
+ }, children);
+ }
+ return JSX_("a", {
+ className,
+ href: "#",
+ onClick: ev => {
+ if (onClick) {
+ ev.preventDefault();
+ return onClick(ev);
+ }
+ return null;
}
- }, REaCt().createElement("div", null, l.minimize)))));
+ }, children);
}
}
-StreamHead.NAMESPACE = 'stream-head';
-StreamHead.EVENTS = {
- FULLSCREEN: 'fullscreenchange',
- SIMPLETIP: new Event('simpletipClose'),
- CLICK_DIALOG: 'click'
-};
-// EXTERNAL MODULE: ./js/chat/ui/contacts.jsx
-const contacts = REQ_(251);
-// EXTERNAL MODULE: ./js/ui/perfectScrollbar.jsx
-const perfectScrollbar = REQ_(486);
-// EXTERNAL MODULE: ./js/chat/ui/link.jsx
-const ui_link = REQ_(280);
-;// ./js/chat/ui/meetings/waitingRoom/admit.jsx
-
-
-
+ },
+ 6740
+(_, EXP_, REQ_) {
+"use strict";
+ REQ_.d(EXP_, {
+ A: () => __WEBPACK_DEFAULT_EXPORT__
+ });
+ const react0__ = REQ_(1594);
+ const react0___default = REQ_.n(react0__);
-const NAMESPACE = 'admit';
-class Admit extends mixins.w9 {
- constructor(...args) {
- super(...args);
- this.domRef = REaCt().createRef();
- this.peersWaitingRef = REaCt().createRef();
+class Group extends react0___default().Component {
+ constructor(props) {
+ super(props);
+ this.containerRef = react0___default().createRef();
this.state = {
expanded: false
};
- this.doAdmit = peers => {
- let _this$props$call;
- return (_this$props$call = this.props.call) == null || (_this$props$call = _this$props$call.sfuClient) == null ? void 0 : _this$props$call.wrAllowJoin([peers]);
- };
- this.doDeny = peers => {
- let _this$props$call2;
- return (_this$props$call2 = this.props.call) == null || (_this$props$call2 = _this$props$call2.sfuClient) == null ? void 0 : _this$props$call2.wrKickOut([peers]);
- };
- this.Icon = ({
- icon,
- label,
- onClick
- }) => REaCt().createElement("i", {
- className: `
- sprite-fm-mono
- simpletip
- ${icon}
- `,
- "data-simpletip": label,
- "data-simpletipposition": "top",
- "data-simpletipoffset": "5",
- "data-simpletip-class": "theme-dark-forced",
- onClick
- });
- this.CallLimitBanner = ({
- call
- }) => REaCt().createElement("div", {
- className: `${NAMESPACE}-user-limit-banner`
- }, call.organiser === u_handle ? (0,utils.lI)(l.admit_limit_banner_organiser, '[A]', ui_link.A, {
- onClick() {
- window.open(`${getBaseUrl()}/pro`, '_blank', 'noopener,noreferrer');
- eventlog(500259);
- }
- }) : l.admit_limit_banner_host);
- this.renderPeersList = () => {
- const {
- peers,
- call,
- chatRoom
- } = this.props;
- const disableAdding = call.sfuClient.callLimits && call.sfuClient.callLimits.usr && chatRoom.getCallParticipants().length >= call.sfuClient.callLimits.usr;
- return REaCt().createElement(perfectScrollbar.O, {
- ref: this.peersWaitingRef,
- options: {
- 'suppressScrollX': true
- }
- }, REaCt().createElement("div", {
- className: "peers-waiting"
- }, this.isUserLimited && REaCt().createElement(this.CallLimitBanner, {
- call
- }), peers.map(handle => {
- return REaCt().createElement("div", {
- key: handle,
- className: "peers-waiting-card"
- }, REaCt().createElement("div", {
- className: "peer-avatar"
- }, REaCt().createElement(contacts.Avatar, {
- contact: M.u[handle]
- })), REaCt().createElement("div", {
- className: "peer-name"
- }, REaCt().createElement(contacts.ContactAwareName, {
- contact: M.u[handle],
- emoji: true
- })), REaCt().createElement("div", {
- className: "peer-controls"
- }, REaCt().createElement(this.Icon, {
- icon: "icon-close-component",
- label: l.wr_deny,
- onClick: () => this.doDeny(handle)
- }), REaCt().createElement(this.Icon, {
- icon: `icon-check ${disableAdding ? 'disabled' : ''}`,
- label: l.wr_admit,
- onClick: () => !disableAdding && this.doAdmit(handle)
- })));
- })));
- };
- this.renderMultiplePeersWaiting = () => {
- const {
- call,
- peers,
- expanded,
- onWrListToggle
- } = this.props;
- if (peers && peers.length) {
- const disableAddAll = this.isUserLimited;
- return REaCt().createElement(REaCt().Fragment, null, REaCt().createElement("div", {
- className: `${NAMESPACE}-head`
- }, REaCt().createElement("h3", null, mega.icu.format(l.wr_peers_waiting, peers.length)), expanded ? REaCt().createElement(this.Icon, {
- icon: "icon-arrow-up",
- onClick: () => onWrListToggle(false)
- }) : null), !expanded && disableAddAll && REaCt().createElement(this.CallLimitBanner, {
- call
- }), expanded && REaCt().createElement("div", {
- className: `${NAMESPACE}-content`
- }, this.renderPeersList()), REaCt().createElement("div", {
- className: `${NAMESPACE}-controls`
- }, expanded ? null : REaCt().createElement(meetings_button.A, {
- className: "mega-button theme-dark-forced",
- onClick: () => onWrListToggle(true)
- }, REaCt().createElement("span", null, l.wr_see_waiting)), REaCt().createElement(meetings_button.A, {
- peers,
- className: `mega-button positive theme-dark-forced ${disableAddAll ? 'disabled' : ''}`,
- onClick: () => !disableAddAll && call.sfuClient.wrAllowJoin(peers)
- }, REaCt().createElement("span", null, l.wr_admit_all))));
- }
- return null;
- };
- this.renderSinglePeerWaiting = () => {
- const {
- peers,
- call
- } = this.props;
- const peer = peers[0];
- const disableAdding = this.isUserLimited;
- if (peer) {
- return REaCt().createElement(REaCt().Fragment, null, REaCt().createElement(utils.P9, {
- tag: "h3",
- content: l.wr_peer_waiting.replace('%s', megaChat.html(M.getNameByHandle(peer)))
- }), disableAdding && REaCt().createElement(this.CallLimitBanner, {
- call
- }), REaCt().createElement("div", {
- className: `${NAMESPACE}-controls`
- }, REaCt().createElement(meetings_button.A, {
- className: "mega-button theme-dark-forced",
- onClick: () => this.doDeny(peer)
- }, REaCt().createElement("span", null, l.wr_deny)), REaCt().createElement(meetings_button.A, {
- className: `mega-button positive theme-dark-forced ${disableAdding ? 'disabled' : ''}`,
- onClick: () => !disableAdding && this.doAdmit(peer)
- }, REaCt().createElement("span", null, l.wr_admit))));
- }
- return null;
- };
+ this.doToggle = this.doToggle.bind(this);
}
- get isUserLimited() {
- const {
- call,
- chatRoom,
- peers
- } = this.props;
- return call.sfuClient.callLimits && call.sfuClient.callLimits.usr && chatRoom.getCallParticipants().length + (peers ? peers.length : 0) > call.sfuClient.callLimits.usr;
+ toggleEvents() {
+ return this.state.expanded ? $(document).rebind(`mousedown.${Group.NAMESPACE}`, ev => !this.containerRef.current.contains(ev.target) && this.doToggle()).rebind(`keydown.${Group.NAMESPACE}`, ({
+ keyCode
+ }) => keyCode && keyCode === 27 && this.doToggle()) : $(document).unbind(`.${Group.NAMESPACE}`);
+ }
+ doToggle() {
+ this.setState(state => ({
+ expanded: !state.expanded
+ }), () => this.toggleEvents());
}
render() {
const {
- chatRoom,
- peers
+ active,
+ warn,
+ onHold,
+ screenSharing,
+ children
} = this.props;
- if (chatRoom.iAmOperator()) {
- return REaCt().createElement("div", {
- ref: this.domRef,
+ if (children && children.length) {
+ return JSX_("div", {
+ ref: this.containerRef,
+ className: Group.BASE_CLASS
+ }, JSX_("div", {
className: `
- ${NAMESPACE}
- theme-dark-forced
- `
- }, REaCt().createElement("div", {
- className: `${NAMESPACE}-wrapper`
- }, peers && peers.length > 1 ? this.renderMultiplePeersWaiting() : this.renderSinglePeerWaiting()));
+ ${Group.BASE_CLASS}-menu
+ ${this.state.expanded ? 'expanded' : ''}
+ `,
+ onClick: this.doToggle
+ }, children.map(item => {
+ return item && JSX_("div", {
+ key: item.key,
+ className: `${Group.BASE_CLASS}-item`
+ }, item);
+ })), JSX_("button", {
+ className: "mega-button theme-light-forced round large",
+ onClick: this.doToggle
+ }, active && JSX_("div", {
+ className: "info-indicator active"
+ }), warn && JSX_("div", {
+ className: "info-indicator warn simpletip",
+ "data-simpletip": l.screen_share_crop_tip,
+ "data-simpletipposition": "top",
+ "data-simpletipoffset": "5",
+ "data-simpletip-class": "theme-dark-forced"
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-exclamation-filled"
+ })), JSX_("i", {
+ className: `
+ sprite-fm-mono
+ ${screenSharing ? 'icon-end-screenshare' : ''}
+ ${!onHold && !screenSharing && 'icon-options'}
+ `
+ })));
}
return null;
}
}
-;// ./js/chat/ui/meetings/stream.jsx
-
-
-
-
-
-
+Group.NAMESPACE = 'buttonGroup';
+Group.BASE_CLASS = 'button-group';
+class Button extends react0___default().Component {
+ constructor(...args) {
+ super(...args);
+ this.buttonRef = react0___default().createRef();
+ }
+ componentDidUpdate() {
+ if (this.props.simpletip) {
+ $(this.buttonRef.current).trigger('simpletipUpdated');
+ }
+ }
+ componentDidMount() {
+ if (this.props.didMount) {
+ this.props.didMount(this);
+ }
+ }
+ render() {
+ const {
+ children,
+ className,
+ style,
+ simpletip,
+ icon,
+ onClick
+ } = this.props;
+ return JSX_("button", {
+ ref: this.buttonRef,
+ className: `
+ ${className ? className : ''}
+ ${simpletip ? 'simpletip' : ''}
+ `,
+ style,
+ "data-simpletip": simpletip == null ? void 0 : simpletip.label,
+ "data-simpletipposition": simpletip == null ? void 0 : simpletip.position,
+ "data-simpletipoffset": simpletip == null ? void 0 : simpletip.offset,
+ "data-simpletip-class": simpletip == null ? void 0 : simpletip.className,
+ onClick
+ }, icon && JSX_("i", {
+ className: `sprite-fm-mono ${icon}`
+ }), children);
+ }
+}
+Button.Group = Group;
+ const __WEBPACK_DEFAULT_EXPORT__ = Button;
+ },
+ 6521
+(_, EXP_, REQ_) {
+"use strict";
+ REQ_.d(EXP_, {
+ PS: () => addMonths,
+ We: () => stringToTime,
+ XH: () => stringToDate,
+ a4: () => getTimeIntervals,
+ cK: () => isToday,
+ dB: () => getUserTimezone,
+ ef: () => isTomorrow,
+ i_: () => getNearestHalfHour,
+ ro: () => isSameDay
+ });
+const stringToDate = string => {
+ return moment(string, ['DD MMM YYYY', 'DD-MM-YYYY', 'DD.MM.YYYY', 'MMM DD YYYY', 'YYYY MMM DD', 'YYYY DD MMM']);
+};
+const stringToTime = string => moment(string, ['HH:mm', 'hh:mm A']);
+const isSameDay = (a, b) => {
+ return new Date(a).toDateString() === new Date(b).toDateString();
+};
+const isToday = timestamp => {
+ return new Date(timestamp).toDateString() === new Date().toDateString();
+};
+const isTomorrow = timestamp => {
+ const tomorrow = new Date();
+ tomorrow.setDate(tomorrow.getDate() + 1);
+ return tomorrow.toDateString() === new Date(timestamp).toDateString();
+};
+const getDaysInMonth = (year, month) => {
+ return new Date(year, month, 0).getDate();
+};
+const addMonths = (timestamp, months) => {
+ const date = new Date(timestamp);
+ return new Date(date.setMonth(date.getMonth() + months)).getTime();
+};
+const getNearestHalfHour = (timestamp = Date.now()) => {
+ const {
+ SCHEDULED_MEETINGS_INTERVAL
+ } = ChatRoom;
+ return new Date(Math.ceil(timestamp / SCHEDULED_MEETINGS_INTERVAL) * SCHEDULED_MEETINGS_INTERVAL).getTime();
+};
+const getUserTimezone = () => {
+ return Intl.DateTimeFormat().resolvedOptions().timeZone;
+};
+const getTimeIntervals = (timestamp, offsetFrom, interval = 30) => {
+ const increments = [];
+ if (timestamp) {
+ const [targetDate, initialDate] = [new Date(timestamp), new Date(timestamp)].map(date => {
+ date.setHours(0);
+ date.setMinutes(0);
+ return date;
+ });
+ while (targetDate.getDate() === initialDate.getDate()) {
+ const timestamp = targetDate.getTime();
+ const diff = offsetFrom && timestamp - offsetFrom;
+ increments.push({
+ value: timestamp,
+ label: toLocaleTime(timestamp),
+ duration: diff && diff > 0 ? diff : undefined
+ });
+ targetDate.setMinutes(targetDate.getMinutes() + interval);
+ }
+ }
+ return increments;
+};
+ },
+ 3901
+(_, EXP_, REQ_) {
-const stream_NAMESPACE = 'stream';
+"use strict";
+ REQ_.d(EXP_, {
+ $A: () => MAX_STREAMS,
+ Av: () => isExpanded,
+ Bq: () => PAGINATION,
+ Cy: () => isModerator,
+ Fj: () => EXPANDED_FLAG,
+ HV: () => getUnsupportedBrowserMessage,
+ P: () => isGuest,
+ ZE: () => TYPE,
+ _F: () => renderEndConfirm,
+ dQ: () => inProgressAlert,
+ g: () => MODE,
+ gR: () => VIEW,
+ gh: () => STREAMS_PER_PAGE,
+ hK: () => STREAM_ACTIONS,
+ sX: () => renderLeaveConfirm
+ });
+const EXPANDED_FLAG = 'in-call';
+const MODE = {
+ THUMBNAIL: 1,
+ MAIN: 2,
+ MINI: 3
+};
+const VIEW = {
+ DEFAULT: 0,
+ CHAT: 1,
+ PARTICIPANTS: 2
+};
+const TYPE = {
+ AUDIO: 1,
+ VIDEO: 2
+};
const STREAM_ACTIONS = {
ADD: 1,
REMOVE: 2
@@ -26881,757 +5217,44 @@ const STREAMS_PER_PAGE = {
MED: 21,
MAX: 49
};
-const chunkNodes = (nodes, size) => {
- if (nodes && nodes.length && size) {
- const chunked = [];
- let index = 0;
- while (index < nodes.length) {
- chunked.push({
- id: index,
- nodes: nodes.slice(index, index + size)
- });
- index += size;
- }
- return chunked;
- }
- return null;
-};
-const filterAndSplitSources = (sources, call) => {
- const screen = [];
- const video = [];
- const rest = [];
- for (const peer of Object.values(sources.toJS())) {
- if (peer instanceof CallManager2.Peer) {
- if (peer.hasScreen) {
- screen.push(peer, peer);
- } else if (peer.videoMuted) {
- rest.push(peer);
- } else {
- video.push(peer);
- }
- }
- }
- const local = call.getLocalStream();
- if (local.hasScreen) {
- const presenters = [...call.presenterStreams];
- if (presenters.pop() === u_handle) {
- screen.unshift(local, local);
- } else {
- screen.push(local, local);
- }
- } else if (local.av & Av.Camera) {
- video.unshift(local);
- } else {
- rest.push(local);
- }
- return {
- screen,
- video,
- rest
- };
-};
-class stream_Stream extends mixins.w9 {
- constructor(...args) {
- super(...args);
- this.domRef = REaCt().createRef();
- this.containerRef = REaCt().createRef();
- this.nodeRefs = [];
- this.chunks = [];
- this.chunksLength = 0;
- this.lastRescaledCache = undefined;
- this.state = {
- page: 0,
- overlayed: false,
- streamsPerPage: STREAMS_PER_PAGE.MED,
- floatDetached: false,
- wrToggled: false
- };
- this.toggleFloatDetachment = () => {
- this.setState(state => ({
- floatDetached: !state.floatDetached
- }));
- };
- this.toggleWaitingRoomList = state => {
- this.setState({
- wrToggled: state
- });
- };
- }
- movePage(direction) {
- return this.setState(state => ({
- page: direction === PAGINATION.NEXT ? state.page + 1 : state.page - 1
- }));
- }
- getColumns(streamsCount) {
- switch (true) {
- case streamsCount >= 43:
- return 7;
- case streamsCount >= 26:
- return 6;
- case streamsCount >= 17:
- return 5;
- case streamsCount >= 13:
- return 4;
- case streamsCount === 1:
- return 1;
- case streamsCount >= 7:
- return 3;
- default:
- return 2;
- }
- }
- scaleNodes(columns, forced = false) {
- let _Object$values$page;
- const {
- peers,
- minimized,
- mode,
- call
- } = this.props;
- const {
- screen,
- video,
- rest
- } = filterAndSplitSources(peers, call);
- let presenter = false;
- const sources = [...screen, ...video, ...rest].filter(source => {
- if (!source.isLocal) {
- return true;
- }
- if (source.hasScreen && !presenter) {
- presenter = true;
- return true;
- }
- return false;
- });
- presenter = false;
- const container = this.containerRef.current;
- this.lastRescaledCache = forced ? null : this.lastRescaledCache;
- if (minimized || !container) {
- return;
- }
- const {
- floatDetached,
- streamsPerPage,
- page
- } = this.state;
- const parentRef = container.parentNode;
- const parentStyle = getComputedStyle(parentRef);
- const extraVerticalMargin = parseInt(parentStyle.paddingTop) + parseInt(parentStyle.paddingBottom);
- let containerWidth = parentRef.offsetWidth;
- let containerHeight = parentRef.offsetHeight - extraVerticalMargin;
- const nodesPerPage = floatDetached ? streamsPerPage : streamsPerPage - 1;
- const streamsInUI = sources.length > nodesPerPage ? (_Object$values$page = Object.values(this.chunks)[page]) == null ? void 0 : _Object$values$page.nodes : sources;
- if (streamsInUI) {
- const streamCountInUI = sources.length > nodesPerPage || floatDetached ? streamsInUI.length : streamsInUI.length + 1;
- let rows;
- if (mode === meetings_call.g.THUMBNAIL) {
- columns = typeof columns === 'number' ? columns : this.getColumns(streamCountInUI);
- rows = Math.ceil(streamCountInUI / columns);
- } else {
- rows = 1;
- columns = 1;
- }
- containerWidth -= columns * 6 * 2;
- containerHeight -= rows * 6 * 2;
- let targetWidth = Math.floor(containerWidth / columns);
- let targetHeight = targetWidth / 16 * 9;
- if (targetHeight * rows > containerHeight) {
- targetHeight = Math.floor(containerHeight / rows);
- targetWidth = targetHeight / 9 * 16;
- }
- const nodeRefs = this.nodeRefs.flat();
- const nodeRefsLength = nodeRefs.length;
- const viewMode = mode || meetings_call.g.MAIN;
- let cache = `${viewMode}:${targetWidth}:${targetHeight}:${nodeRefsLength}:${rows}:${streamCountInUI}:${columns}`;
- for (let i = 0; i < nodeRefsLength; i++) {
- cache += `${nodeRefs[i].cacheKey}:`;
- }
- if (this.lastRescaledCache === cache) {
- return;
- }
- this.lastRescaledCache = cache;
- for (let i = 0; i < nodeRefsLength; i++) {
- const node = nodeRefs[i];
- if (node && node.ref) {
- node.ref.style.width = `${targetWidth}px`;
- node.ref.style.height = `${targetHeight}px`;
- }
- }
- container.style.width = `${(targetWidth + 12) * columns}px`;
- }
- }
- renderNodes() {
- const {
- mode,
- peers,
- call,
- raisedHandPeers,
- chatRoom,
- onVideoDoubleClick,
- onModeChange
- } = this.props;
- const {
- page,
- streamsPerPage,
- floatDetached
- } = this.state;
- const {
- screen,
- video,
- rest
- } = filterAndSplitSources(peers, call);
- const sources = [...screen, ...video, ...rest];
- if (mode === meetings_call.g.THUMBNAIL) {
- const nodesPerPage = floatDetached ? streamsPerPage : streamsPerPage - 1;
- if (sources.length <= nodesPerPage) {
- const $$PEER = (peer, i) => {
- const {
- clientId,
- hasScreenAndCam,
- hasScreen,
- isLocal
- } = peer;
- if (screen.length && (screen[0].clientId === clientId || screen[0].isLocal && isLocal)) {
- screen.shift();
- }
- if (!(peer instanceof CallManager2.Peer)) {
- const isPresenterNode = screen.length && screen[0].isLocal;
- if (floatDetached && !isPresenterNode) {
- return;
- }
- if (floatDetached || !isPresenterNode) {
- return REaCt().createElement(videoNode.bJ, {
- key: `${mode}_thumb_${u_handle}`,
- chatRoom,
- isPresenterNode: false,
- raisedHandPeers,
- source: peer,
- didMount: ref => {
- this.nodeRefs.push({
- clientId: u_handle,
- cacheKey: `${mode}_${u_handle}_thumb`,
- ref
- });
- this.scaleNodes(undefined, true);
- },
- willUnmount: () => {
- this.nodeRefs = this.nodeRefs.filter(nodeRef => nodeRef.cacheKey !== `${mode}_${u_handle}_thumb`);
- }
- }, this.renderSelfViewMenu());
- }
- return REaCt().createElement(videoNode.Cn, {
- key: `${mode}_${u_handle}`,
- chatRoom,
- isPresenterNode,
- source: isPresenterNode && peer,
- raisedHandPeers,
- didMount: ref => {
- this.nodeRefs.push({
- clientId: u_handle,
- cacheKey: `${mode}_${u_handle}`,
- ref
- });
- this.scaleNodes(undefined, true);
- },
- willUnmount: () => {
- this.nodeRefs = this.nodeRefs.filter(nodeRef => nodeRef.cacheKey !== `${mode}_${u_handle}`);
- }
- }, hasScreen ? this.renderNodeMenu(peer, {
- isPresenterNode
- }) : this.renderSelfViewMenu());
- }
- const presenterCid = screen.length && screen[0].clientId === clientId;
- let PeerClass = videoNode.au;
- if (hasScreenAndCam) {
- PeerClass = presenterCid ? videoNode.zu : videoNode.Qs;
- }
- const cacheKey = `${mode}_${clientId}_${i}_${hasScreenAndCam ? 1 : 0}`;
- return REaCt().createElement(PeerClass, {
- key: cacheKey,
- mode,
- chatRoom,
- menu: true,
- source: peer,
- raisedHandPeers,
- isPresenterNode: !!presenterCid,
- onDoubleClick: (peer, e) => {
- e.preventDefault();
- e.stopPropagation();
- onVideoDoubleClick(peer, !presenterCid);
- },
- didMount: ref => {
- this.nodeRefs.push({
- clientId: presenterCid || clientId,
- cacheKey,
- ref
- });
- },
- willUnmount: () => {
- this.nodeRefs = this.nodeRefs.filter(nodeRef => nodeRef.cacheKey !== cacheKey);
- }
- }, this.renderNodeMenu(peer, {
- isPresenterNode: !!presenterCid
- }));
- };
- return sources.map((p, i) => $$PEER(p, i));
- }
- if (floatDetached) {
- for (let i = 0; i < sources.length; i++) {
- if (sources[i].isLocal) {
- sources.splice(i, 1);
- break;
- }
- }
- }
- this.chunks = chunkNodes(sources, streamsPerPage);
- this.chunksLength = Object.values(this.chunks).length;
- return REaCt().createElement("div", {
- className: "carousel"
- }, REaCt().createElement("div", {
- className: "carousel-container"
- }, Object.values(this.chunks).map((chunk, i) => {
+const isGuest = () => !u_type;
+const inProgressAlert = (isJoin, chatRoom) => {
+ return new Promise((resolve, reject) => {
+ if (megaChat.haveAnyActiveCall()) {
+ if (window.sfuClient) {
const {
- id,
- nodes
- } = chunk;
- return REaCt().createElement("div", {
- key: id,
- className: `
- carousel-page
- ${i === page ? 'active' : ''}
- `
- }, nodes.map((peer, j) => {
- const {
- clientId,
- hasScreenAndCam,
- hasScreen,
- isLocal
- } = peer;
- if (screen.length && (screen[0].clientId === clientId || screen[0].isLocal && isLocal)) {
- screen.shift();
- }
- if (peer instanceof CallManager2.Peer) {
- const presenterCid = screen.length && screen[0].clientId === clientId;
- const cacheKey = `${mode}_${clientId}_${j + i * streamsPerPage}_${hasScreenAndCam ? 1 : 0}`;
- let PeerClass = videoNode.au;
- if (hasScreenAndCam) {
- PeerClass = presenterCid ? videoNode.zu : videoNode.Qs;
- }
- return REaCt().createElement(PeerClass, {
- key: cacheKey,
- mode,
- source: peer,
- chatRoom,
- isPresenterNode: !!presenterCid,
- raisedHandPeers,
- onDoubleClick: (peer, e) => {
- e.preventDefault();
- e.stopPropagation();
- onVideoDoubleClick(peer);
- },
- didMount: ref => {
- if (!this.nodeRefs[id]) {
- this.nodeRefs[id] = [];
- }
- this.nodeRefs[id].push({
- clientId: presenterCid || clientId,
- ref,
- cacheKey
- });
- this.scaleNodes(undefined, true);
- },
- willUnmount: () => {
- this.nodeRefs = this.nodeRefs.map(chunk => chunk.filter(nodeRef => nodeRef.cacheKey !== cacheKey));
- }
- }, this.renderNodeMenu(peer, {
- isPresenterNode: !!presenterCid
- }));
- }
- const isPresenterNode = screen.length && screen[0].isLocal;
- if (floatDetached && !isPresenterNode) {
- return null;
- }
- if (floatDetached || !isPresenterNode) {
- return REaCt().createElement(videoNode.bJ, {
- key: `${mode}_thumb_${u_handle}`,
- chatRoom,
- source: peer,
- isPresenterNode: false,
- didMount: ref => {
- if (!this.nodeRefs[id]) {
- this.nodeRefs[id] = [];
- }
- this.nodeRefs[id].push({
- clientId: u_handle,
- cacheKey: `${mode}_${u_handle}_thumb`,
- ref
- });
- this.scaleNodes(undefined, true);
- },
- willUnmount: () => {
- this.nodeRefs = this.nodeRefs.map(chunk => chunk.filter(nodeRef => nodeRef.cacheKey !== `${mode}_${u_handle}_thumb`));
- }
- }, this.renderSelfViewMenu());
- }
- return REaCt().createElement(videoNode.Cn, {
- key: `${mode}_${u_handle}`,
- chatRoom,
- raisedHandPeers,
- isPresenterNode,
- source: isPresenterNode && peer,
- didMount: ref => {
- if (!this.nodeRefs[id]) {
- this.nodeRefs[id] = [];
- }
- this.nodeRefs[id].push({
- clientId: u_handle,
- ref,
- cacheKey: `${mode}_${u_handle}`
- });
- this.scaleNodes(undefined, true);
- },
- willUnmount: () => {
- this.nodeRefs = this.nodeRefs.map(chunk => chunk.filter(nodeRef => nodeRef.cacheKey !== `${mode}_${u_handle}`));
- }
- }, hasScreen ? this.renderNodeMenu(peer, {
- isPresenterNode
- }) : this.renderSelfViewMenu());
- }));
- })));
- }
- const source = call.getActiveStream();
- if (!source) {
- return null;
- }
- const VideoType = source.isLocal ? videoNode.Cn : videoNode.zu;
- const videoNodeRef = REaCt().createRef();
- return REaCt().createElement(VideoType, {
- key: source.clientId,
- chatRoom,
- raisedHandPeers,
- source,
- isPresenterNode: source.hasScreen,
- toggleFullScreen: () => {
- call.setPinnedCid(source.clientId);
- },
- onSpeakerChange: () => {
- onModeChange(meetings_call.g.THUMBNAIL);
- },
- ref: node => {
- videoNodeRef.current = node;
- }
- }, this.renderNodeMenu(source, {
- key: `${source.clientId}-main`,
- isMain: true,
- videoNodeRef,
- isPresenterNode: source.hasScreen
- }));
- }
- renderNodeMenu(peer, props) {
- const {
- mode,
- chatRoom,
- ephemeralAccounts,
- onCallMinimize,
- onSpeakerChange,
- onModeChange
- } = this.props;
- return REaCt().createElement(videoNodeMenu.Ay, (0,esm_extends.A)({
- mode,
- privilege: chatRoom.members[peer.userHandle],
- chatRoom,
- stream: peer,
- ephemeralAccounts,
- onCallMinimize,
- onSpeakerChange,
- onModeChange
- }, props));
- }
- renderSelfViewMenu() {
- const {
- call,
- onSpeakerChange
- } = this.props;
- return REaCt().createElement("div", {
- className: "node-menu theme-dark-forced"
- }, REaCt().createElement("div", {
- className: "node-menu-toggle"
- }, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-more-horizontal-thin-outline"
- })), REaCt().createElement("div", {
- className: "node-menu-content"
- }, REaCt().createElement("ul", null, REaCt().createElement("li", null, REaCt().createElement(meetings_button.A, {
- icon: "sprite-fm-mono grid-main",
- onClick: () => onSpeakerChange(call.getLocalStream())
- }, REaCt().createElement("span", null, l.display_in_main_view))), REaCt().createElement("li", null, REaCt().createElement(meetings_button.A, {
- icon: "sprite-fm-mono grid-separate",
- onClick: this.toggleFloatDetachment
- }, REaCt().createElement("span", null, l.separate_from_grid_button))))));
- }
- renderOnHold() {
- return REaCt().createElement("div", {
- className: "on-hold-overlay"
- }, REaCt().createElement("div", {
- className: "stream-on-hold theme-light-forced",
- onClick: this.props.onHoldClick
- }, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-play"
- }), REaCt().createElement("span", null, l[23459])));
- }
- renderStreamContainer() {
- const {
- call,
- chatRoom,
- peers,
- stayOnEnd,
- everHadPeers,
- isOnHold,
- mode,
- hasOtherParticipants,
- onInviteToggle,
- onStayConfirm,
- onCallEnd
- } = this.props;
- const {
- screen,
- video,
- rest
- } = filterAndSplitSources(peers, call);
- const sources = [...screen, ...video, ...rest];
- const showNotice = sources.length === 0 || !hasOtherParticipants && !call.presenterStreams.has(u_handle);
- const streamContainer = content => REaCt().createElement("div", {
- ref: this.containerRef,
- className: `
- ${stream_NAMESPACE}-container
- ${showNotice ? 'with-notice' : ''}
- ${sources.length === 1 && mode === meetings_call.g.THUMBNAIL ? `${this.state.floatDetached ? 'single' : 'dual'}-stream` : ''}
- `
- }, content);
- if (showNotice) {
- return REaCt().createElement(ParticipantsNotice, {
- call,
- hasLeft: call.left,
- chatRoom,
- everHadPeers,
- streamContainer,
- stayOnEnd,
- isOnHold,
- onInviteToggle,
- onStayConfirm,
- onCallEnd: () => onCallEnd(1)
- });
- }
- return streamContainer(this.renderNodes());
- }
- renderToaster() {
- return REaCt().createElement(chatToaster.A, {
- showDualNotifications: true,
- hidden: this.props.minimized,
- onShownToast: toast => {
- if (toast.options && toast.options.persistent) {
- this.setState({
- overlayed: true
- });
- }
- },
- onHideToast: toast => {
- if (this.state.overlayed && toast.options && toast.options.persistent) {
- this.setState({
- overlayed: false
- });
+ chatRoom: activeCallRoom
+ } = megaChat.activeCall;
+ const peers = activeCallRoom ? activeCallRoom.getParticipantsExceptMe(activeCallRoom.getCallParticipants()).map(h => M.getNameByHandle(h)) : [];
+ let body = isJoin ? l.cancel_to_join : l.cancel_to_start;
+ if (peers.length) {
+ body = mega.utils.trans.listToString(peers, isJoin ? l.cancel_with_to_join : l.cancel_with_to_start);
}
+ msgDialog('warningb', null, l.call_in_progress, body, null, 1);
+ return reject();
}
- });
- }
- specShouldComponentUpdate(nextProps) {
- if (nextProps.minimized !== this.props.minimized || nextProps.mode !== this.props.mode || nextProps.isFloatingPresenter !== this.props.isFloatingPresenter) {
- return true;
- }
- return null;
- }
- componentWillUnmount() {
- super.componentWillUnmount();
- chatGlobalEventManager.removeEventListener('resize', this.getUniqueId());
- mBroadcaster.removeListener(this.callHoldListener);
- }
- componentDidMount() {
- super.componentDidMount();
- this.scaleNodes();
- chatGlobalEventManager.addEventListener('resize', this.getUniqueId(), () => this.scaleNodes());
- this.callHoldListener = mBroadcaster.addListener('meetings:toggleHold', () => this.scaleNodes(undefined, true));
- }
- componentDidUpdate() {
- super.componentDidMount();
- const {
- call,
- mode,
- forcedLocal,
- onSpeakerChange,
- onModeChange
- } = this.props;
- this.scaleNodes();
- if (this.chunksLength > 0 && this.state.page + 1 > this.chunksLength) {
- this.movePage(PAGINATION.PREV);
- }
- if (mode === meetings_call.g.THUMBNAIL && call.pinnedCid !== null) {
- this.hasPresenter = true;
- onSpeakerChange(call.getActiveStream());
- } else if (mode === meetings_call.g.MAIN && call.pinnedCid === null && !call.presenterStreams.size && this.hasPresenter) {
- this.hasPresenter = false;
- onModeChange(meetings_call.g.THUMBNAIL);
- } else if (mode === meetings_call.g.MAIN && forcedLocal && call.pinnedCid !== 0) {
- onSpeakerChange(call.getActiveStream());
- } else if (!call.presenterStreams.size) {
- this.hasPresenter = false;
+ if (chatRoom.getCallParticipants().includes(u_handle)) {
+ return resolve();
+ }
+ return msgDialog(`warningb:!^${l[2005]}!${isJoin ? l.join_call_anyway : l.start_call_anyway}`, null, isJoin ? l.join_multiple_calls_title : l.start_multiple_calls_title, isJoin ? l.join_multiple_calls_text : l.start_multiple_calls_text, join => {
+ if (join) {
+ return resolve();
+ }
+ return reject();
+ }, 1);
}
+ resolve();
+ });
+};
+window.inProgressAlert = inProgressAlert;
+const isModerator = (chatRoom, handle) => {
+ if (chatRoom && handle) {
+ return chatRoom.members[handle] === ChatRoom.MembersSet.PRIVILEGE_STATE.OPERATOR;
}
- render() {
- const {
- overlayed,
- page,
- streamsPerPage,
- floatDetached,
- wrToggled
- } = this.state;
- const {
- mode,
- call,
- chatRoom,
- minimized,
- peers,
- sidebar,
- hovered,
- forcedLocal,
- view,
- isOnHold,
- waitingRoomPeers,
- recorderCid,
- raisedHandPeers,
- isFloatingPresenter,
- onRecordingToggle,
- onCallMinimize,
- onCallExpand,
- onModeChange,
- onAudioClick,
- onVideoClick,
- onCallEnd,
- onScreenSharingClick,
- onHoldClick,
- onSpeakerChange,
- onParticipantsToggle,
- setActiveElement
- } = this.props;
- return REaCt().createElement("div", {
- ref: this.domRef,
- className: `
- ${stream_NAMESPACE}
- ${sidebar ? '' : 'full'}
- ${hovered ? 'hovered' : ''}
- `
- }, waitingRoomPeers && waitingRoomPeers.length ? REaCt().createElement(Admit, {
- chatRoom,
- call,
- peers: waitingRoomPeers,
- expanded: wrToggled,
- onWrListToggle: this.toggleWaitingRoomList
- }) : null, this.renderToaster(), minimized ? null : REaCt().createElement(REaCt().Fragment, null, REaCt().createElement("div", {
- className: `
- ${stream_NAMESPACE}-wrapper
- ${mode === meetings_call.g.MAIN ? 'with-participants-block' : ''}
- `
- }, isOnHold ? this.renderOnHold() : overlayed && REaCt().createElement("div", {
- className: "call-overlay"
- }), this.renderStreamContainer()), mode === meetings_call.g.MAIN && REaCt().createElement(ParticipantsBlock, (0,esm_extends.A)({}, this.props, {
- floatDetached,
- onSeparate: this.toggleFloatDetachment
- })), REaCt().createElement(StreamHead, {
- disableCheckingVisibility: true,
- mode,
- peers,
- page,
- streamsPerPage,
- floatDetached,
- chunksLength: this.chunksLength,
- call,
- chatRoom,
- onCallMinimize,
- onModeChange,
- onStreamsPerPageChange: streamsPerPage => this.setState({
- streamsPerPage
- }),
- onMovePage: direction => this.movePage(direction),
- setActiveElement
- })), REaCt().createElement(FloatingVideo, {
- call,
- peers,
- mode,
- view,
- floatDetached,
- isOnHold,
- chatRoom,
- minimized,
- sidebar,
- forcedLocal,
- isPresenterNode: isFloatingPresenter,
- wrapperRef: this.domRef,
- waitingRoomPeers,
- recorderCid,
- raisedHandPeers,
- onRecordingToggle,
- onAudioClick,
- onVideoClick,
- onCallEnd,
- onScreenSharingClick,
- onCallMinimize,
- onMoveIntoGrid: this.toggleFloatDetachment,
- onCallExpand: async () => {
- await onCallExpand();
- this.scaleNodes(undefined, true);
- },
- onSpeakerChange,
- onModeChange,
- onHoldClick,
- onParticipantsToggle,
- onWrListToggle: this.toggleWaitingRoomList
- }));
- }
-}
-
-},
-
-489
-(_, EXP_, REQ_) {
-
-"use strict";
-REQ_.d(EXP_, {
-Ay: () => __WEBPACK_DEFAULT_EXPORT__,
-_F: () => renderEndConfirm,
-sX: () => renderLeaveConfirm
-});
-const _extends0__ = REQ_(168);
-const react1__ = REQ_(594);
-const react1 = REQ_.n(react1__);
-const _mixins2__ = REQ_(137);
-const _button_jsx3__ = REQ_(959);
-const _stream_jsx4__ = REQ_(415);
-const _micObserver_jsx5__ = REQ_(772);
-const _permissionsObserver_jsx6__ = REQ_(542);
-const _call_jsx7__ = REQ_(3);
-const _hostsObserver_jsx8__ = REQ_(972);
-const _ui_dropdowns_jsx9__ = REQ_(911);
-const _ui_utils_jsx10__ = REQ_(314);
-
-
-
-
-
-
-
-
-
-
-
+ return false;
+};
+const isExpanded = () => document.body.classList.contains(EXPANDED_FLAG);
+const getUnsupportedBrowserMessage = () => navigator.userAgent.match(/Chrom(e|ium)\/(\d+)\./) ? l.alert_unsupported_browser_version : l.alert_unsupported_browser;
const renderLeaveConfirm = (onConfirm, onRecordingToggle) => msgDialog(`confirmation:!^${l.leave_call_recording_dialog_cta}!${l.leave_call_recording_dialog_nop_cta}`, undefined, l.leave_call_recording_dialog_heading, l.leave_call_recording_dialog_body, cb => {
if (cb) {
onRecordingToggle();
@@ -27644,9898 +5267,7046 @@ const renderEndConfirm = (onConfirm, onRecordingToggle) => msgDialog(`confirmati
onConfirm();
}
}, 1);
-class StreamControls extends _mixins2__.w9 {
- constructor(...args) {
- super(...args);
- this.domRef = react1().createRef();
- this.endContainerRef = react1().createRef();
- this.endButtonRef = react1().createRef();
- this.SIMPLETIP = {
- position: 'top',
- offset: 8,
- className: 'theme-dark-forced'
- };
- this.state = {
- endCallOptions: false,
- endCallPending: false,
- devices: {},
- audioSelectDropdown: false,
- videoSelectDropdown: false,
- loading: false,
- muteSpeak: false
- };
- this.LeaveButton = (0,_hostsObserver_jsx8__.C)(({
- hasHost,
- chatRoom,
- confirmLeave,
- onLeave
- }) => {
- const doLeave = () => hasHost(chatRoom.call ? chatRoom.call.peers.map(a => a.userHandle) : []) ? onLeave() : confirmLeave({
- title: l.assign_host_leave_call,
- body: l.assign_host_leave_call_details,
- cta: l.assign_host_button,
- altCta: l.leave_anyway
- });
- return react1().createElement(_button_jsx3__.A, {
- className: "mega-button",
- onClick: () => {
- const {
- recorderCid,
- call,
- onRecordingToggle
- } = this.props;
- return recorderCid && recorderCid === call.sfuClient.cid ? renderLeaveConfirm(doLeave, onRecordingToggle) : doLeave();
- }
- }, react1().createElement("span", null, l.leave));
+
+ },
+
+ 855
+(_, EXP_, REQ_) {
+
+"use strict";
+ REQ_.d(EXP_, {
+ M: () => ConversationMessageMixin
+ });
+ const react0__ = REQ_(1594);
+ const react0___default = REQ_.n(react0__);
+ const _mixins_js1__ = REQ_(8264);
+ const _ui_buttons_jsx2__ = REQ_(5155);
+ const _ui_emojiDropdown_jsx3__ = REQ_(1165);
+
+
+
+
+class ConversationMessageMixin extends _mixins_js1__ .u9 {
+ constructor(props) {
+ super(props);
+ this.attachRerenderCallbacks = false;
+ this._reactionContactHandles = [];
+ this.__cmmUpdateTickCount = 0;
+ this._contactChangeListeners = false;
+ this.onAfterRenderWasTriggered = false;
+ lazy(this, '__cmmId', () => {
+ return `${this.getUniqueId() }--${ String(Math.random()).slice(-7)}`;
});
- this.setActiveElement = forced => this.props.setActiveElement(forced || this.state.audioSelectDropdown || this.state.videoSelectDropdown || this.state.endCallOptions);
- this.handleMousedown = ({
- target
- }) => {
- if (this.isMounted()) {
- const {
- audioSelectDropdown,
- videoSelectDropdown,
- endCallOptions
- } = this.state;
- return (audioSelectDropdown || videoSelectDropdown || endCallOptions) && ['audio-sources', 'video-sources', 'meetings-end-options'].some(selector => {
- let _document$querySelect;
- return (_document$querySelect = document.querySelector(`.${selector}`)) == null ? void 0 : _document$querySelect.contains(target);
- }) ? 0x4B1D : this.setState({
- audioSelectDropdown: false,
- videoSelectDropdown: false,
- endCallOptions: false
- }, this.setActiveElement);
- }
- };
- this.renderDebug = () => {
- return react1().createElement("div", {
- className: "stream-debug",
- style: {
- position: 'absolute',
- left: 25,
- bottom: 36,
- display: 'flex',
- alignItems: 'center',
- color: 'tomato'
- }
- }, react1().createElement(_button_jsx3__.A, {
- className: "mega-button round small theme-dark-forced positive",
- simpletip: {
- ...this.SIMPLETIP,
- label: 'Add Stream'
- },
- onClick: () => this.props.onStreamToggle(_stream_jsx4__.hK.ADD)
- }, react1().createElement("span", null, l.add)), react1().createElement(_button_jsx3__.A, {
- className: "mega-button round small theme-dark-forced negative",
- simpletip: {
- ...this.SIMPLETIP,
- label: 'Remove Stream'
- },
- onClick: () => this.props.peers.length > 1 && this.props.onStreamToggle(_stream_jsx4__.hK.REMOVE)
- }, react1().createElement("span", null, l[83])), react1().createElement("span", null, this.props.peers.length + 1));
- };
- this.renderEndCallOptions = () => {
- let _this$endContainerRef;
- const {
- call,
- chatRoom,
- recorderCid,
- onRecordingToggle,
- onCallEnd
- } = this.props;
- const {
- endCallOptions,
- endCallPending
- } = this.state;
- const doEnd = () => this.setState({
- endCallPending: true
- }, () => chatRoom.endCallForAll());
- const endContainerRef = (_this$endContainerRef = this.endContainerRef) == null ? void 0 : _this$endContainerRef.current;
- return react1().createElement("div", (0,_extends0__.A)({}, endCallOptions && {
- style: (({
- left,
- top
- }) => ({
- left,
- top
- }))(endContainerRef.getBoundingClientRect())
- }, {
- className: `
- meetings-end-options
- theme-dark-forced
- ${endCallOptions ? '' : 'hidden'}
- `
- }), react1().createElement("div", {
- className: "meetings-end-options-content"
- }, react1().createElement(this.LeaveButton, {
- chatRoom,
- recorderCid,
- participants: chatRoom.getCallParticipants(),
- onLeave: onCallEnd,
- onConfirmDenied: onCallEnd
- }), react1().createElement(_button_jsx3__.A, {
- className: `
- mega-button
- positive
- ${endCallPending ? 'disabled' : ''}
- `,
- onClick: () => {
- if (recorderCid && recorderCid === call.sfuClient.cid) {
- return renderEndConfirm(doEnd, onRecordingToggle);
- }
- return doEnd();
- }
- }, react1().createElement("span", null, l.end_for_all))));
- };
- this.renderEndCall = () => {
- const {
- call,
- chatRoom,
- peers,
- recorderCid,
- onRecordingToggle,
- onCallEnd
- } = this.props;
- return react1().createElement("div", {
- ref: this.endContainerRef,
- className: "end-call-container",
- onClick: () => {
- if (chatRoom.type !== 'private' && peers.length && _call_jsx7__.Ay.isModerator(chatRoom, u_handle)) {
- return this.setState(state => ({
- endCallOptions: !state.endCallOptions
- }), () => {
- if (this.endButtonRef) {
- $(this.endButtonRef.current).trigger('simpletipClose');
- }
- this.setActiveElement();
- });
- }
- if (recorderCid && recorderCid === call.sfuClient.cid) {
- return chatRoom.type === 'private' ? renderEndConfirm(onCallEnd, onRecordingToggle) : renderLeaveConfirm(onCallEnd, onRecordingToggle);
- }
- return onCallEnd();
- }
- }, react1().createElement(_ui_utils_jsx10__.Ay.RenderTo, {
- element: document.body
- }, this.renderEndCallOptions()), react1().createElement(_button_jsx3__.A, {
- simpletip: {
- ...this.SIMPLETIP,
- label: l[5884]
- },
- className: "mega-button theme-dark-forced round negative end-call call-action",
- icon: "icon-phone-02",
- didMount: button => {
- this.endButtonRef = button.buttonRef;
- }
- }), react1().createElement("span", null, l.end_button));
- };
- this.renderSourceOpener = ({
- type,
- eventId
- }) => {
- return react1().createElement("div", {
- className: `
- input-source-opener
- button
- ${this.state[type] ? 'active-dropdown' : ''}
- `,
- onClick: async ev => {
- ev.stopPropagation();
- this.setState(() => ({
- loading: true
- }), async () => {
- const devices = await this.updateMediaDevices();
- const updated = JSON.stringify(devices) !== JSON.stringify(this.state.devices);
- this.setState(state => ({
- loading: false,
- audioSelectDropdown: false,
- videoSelectDropdown: false,
- devices: updated ? devices : this.state.devices,
- [type]: !state[type]
- }), () => {
- const {
- audioSelectDropdown,
- videoSelectDropdown
- } = this.state;
- this.props.setActiveElement(audioSelectDropdown || videoSelectDropdown);
- eventlog(eventId);
- });
- });
- }
- }, react1().createElement("i", {
- className: "sprite-fm-mono icon-arrow-up"
- }));
- };
- this.handleDeviceChange = () => {
- this.micDefaultRenamed = false;
- this.updateMediaDevices().always(devices => {
- let _sfuClient$localAudio, _oldDevices$audioIn;
- if (!this.isMounted()) {
- return;
+ this._emojiOnActiveStateChange = this._emojiOnActiveStateChange.bind(this);
+ this.emojiSelected = this.emojiSelected.bind(this);
+ const {
+ message: msg
+ } = this.props;
+ if (msg instanceof Message && msg._reactions && msg.messageId.length === 11 && msg.isSentOrReceived() && !Object.hasOwnProperty.call(msg, 'reacts')) {
+ msg.reacts.forceLoad().then(() => {
+ this.addContactListenerIfMissing(this._reactionContacts());
+ }).catch(dump.bind(null, `reactions.load.${msg.messageId}`));
+ }
+ }
+ UNSAFE_componentWillMount() {
+ if (super.UNSAFE_componentWillMount) {
+ super.UNSAFE_componentWillMount();
+ }
+ const {chatRoom} = this.props;
+ if (chatRoom) {
+ chatRoom.rebind(`onChatShown.${ this.__cmmId}`, () => {
+ if (!this._contactChangeListeners) {
+ this.addContactListeners();
}
- const {
- devices: oldDevices
- } = this.state;
- const {
- sfuClient,
- av
- } = this.props.call;
- if (av & Av.Audio && !SfuClient.micDeviceId && ((_sfuClient$localAudio = sfuClient.localAudioTrack()) == null ? void 0 : _sfuClient$localAudio.getCapabilities().deviceId) === 'default' && oldDevices != null && (_oldDevices$audioIn = oldDevices.audioIn) != null && _oldDevices$audioIn.default && devices.audioIn.default && oldDevices.audioIn.default !== devices.audioIn.default) {
- for (const [key, value] of Object.entries(devices.audioIn)) {
- if (key !== 'default' && devices.audioIn.default.indexOf(value) > -1) {
- sfuClient.setMicDevice(key).then(() => SfuClient.persistMicDevice(null));
- break;
- }
- }
+ }).rebind(`onChatHidden.${ this.__cmmId}`, () => {
+ if (this._contactChangeListeners) {
+ this.removeContactListeners();
}
- this.setState({
- devices,
- audioSelectDropdown: false,
- videoSelectDropdown: false
- }, this.setActiveElement);
});
+ }
+ this.addContactListeners();
+ }
+ haveMeetingsCall() {
+ return document.querySelector('.meetings-call') && document.querySelector('.chat-opened');
+ }
+ removeContactListeners() {
+ const users = this._contactChangeListeners;
+ if (d > 3) {
+ console.warn('%s.removeContactListeners', this.getReactId(), [this], users);
+ }
+ for (let i = users.length; i--;) {
+ users[i].removeEventHandler(this);
+ }
+ this._contactChangeListeners = false;
+ }
+ _reactionContacts() {
+ const {
+ message
+ } = this.props;
+ const {
+ reacts
+ } = message;
+ const handles = [];
+ const reactions = Object.values(reacts.reactions);
+ for (let i = 0; i < reactions.length; i++) {
+ handles.push(...Object.keys(reactions[i]));
+ }
+ this._reactionContactHandles = array.unique(handles);
+ return this._reactionContactHandles;
+ }
+ addContactListeners() {
+ const users = this._contactChangeListeners || [];
+ const addUser = user => {
+ if (user instanceof MegaDataMap && users.indexOf(user) < 0) {
+ users.push(user);
+ }
};
- this.renderOnboardingRaise = () => {
- const {
- chatRoom,
- onOnboardingRaiseDismiss
- } = this.props;
- return react1().createElement("div", {
- className: "meetings-call-onboarding"
- }, react1().createElement("div", {
- className: "mega-dialog mega-onboarding-dialog dialog-template-message onboarding-raise",
- id: "ob-dialog",
- role: "dialog",
- "aria-labelledby": "ob-dialog-title",
- "aria-modal": "true"
- }, react1().createElement("i", {
- className: "sprite-fm-mono icon-tooltip-arrow tooltip-arrow bottom",
- id: "ob-dialog-arrow"
- }), react1().createElement("header", null, react1().createElement("div", null, react1().createElement("h2", {
- id: "ob-dialog-title"
- }, l.raise_onboarding_title), react1().createElement("p", {
- id: "ob-dialog-text"
- }, chatRoom.isMeeting ? l.raise_onboarding_body : l.raise_onboarding_group_body))), react1().createElement("footer", null, react1().createElement("div", {
- className: "footer-container"
- }, react1().createElement("button", {
- className: "mega-button js-next small theme-light-forced",
- onClick: onOnboardingRaiseDismiss
- }, react1().createElement("span", null, l.ok_button))))));
- };
- this.renderRaiseButton = () => {
- const {
- call,
- raisedHandPeers,
- onboardingRaise
- } = this.props;
- const isOnHold = call.av & Av.onHold;
- const hasRaisedHand = raisedHandPeers.includes(u_handle);
- return react1().createElement("li", {
- className: isOnHold ? 'disabled' : ''
- }, onboardingRaise && this.renderOnboardingRaise(), react1().createElement(_button_jsx3__.A, {
- className: `
- mega-button
- theme-light-forced
- call-action
- round
- ${isOnHold ? 'disabled' : ''}
- ${hasRaisedHand ? 'with-fill' : ''}
- `,
- icon: "icon-raise-hand",
- onClick: isOnHold ? null : () => {
- if (hasRaisedHand) {
- call.sfuClient.lowerHand();
- eventlog(500311);
- return;
- }
- call.sfuClient.raiseHand();
- eventlog(500249);
+ addUser(this.getContact());
+ if (this.haveMoreContactListeners) {
+ const moreIds = this.haveMoreContactListeners();
+ if (moreIds) {
+ for (let i = moreIds.length; i--;) {
+ const handle = moreIds[i];
+ addUser(handle in M.u && M.u[handle]);
}
- }), react1().createElement("span", null, l.raise_button));
- };
+ }
+ }
+ for (let i = this._reactionContactHandles.length; i--;) {
+ addUser(this._reactionContactHandles[i] in M.u && M.u[this._reactionContactHandles[i]]);
+ }
+ if (d > 3) {
+ console.warn('%s.addContactListeners', this.getReactId(), [this], users);
+ }
+ for (let i = users.length; i--;) {
+ users[i].addChangeListener(this);
+ }
+ this._contactChangeListeners = users;
+ }
+ addContactListenerIfMissing(contacts) {
+ if (!this._contactChangeListeners) {
+ return false;
+ }
+ if (!Array.isArray(contacts)) {
+ contacts = [contacts];
+ }
+ const added = [];
+ for (let i = 0; i < contacts.length; i++) {
+ const user = M.u[contacts[i]];
+ if (user && !this._contactChangeListeners.includes(user)) {
+ this._contactChangeListeners.push(user);
+ user.addChangeListener(this);
+ added.push(user.h);
+ }
+ }
+ if (d > 1) {
+ console.warn('%s.addContactListenerIfMissing', this.getReactId(), [this], added);
+ }
+ }
+ eventuallyUpdate() {
+ super.eventuallyUpdate();
+ this.__cmmUpdateTickCount = -2;
}
- renderSoundDropdown() {
- const {
- call
- } = this.props;
- const {
- micDeviceId,
- audioOutDeviceId
- } = SfuClient;
- const {
- audioIn = {},
- audioOut = {}
- } = this.state.devices;
- let selectedIn;
- const inTrack = call.sfuClient.localAudioTrack();
- if (inTrack) {
- const {
- deviceId
- } = inTrack.getCapabilities();
- selectedIn = deviceId in audioIn ? deviceId : 'default';
- if (deviceId === 'default' && inTrack.label !== audioIn.default) {
- this.micDefaultRenamed = inTrack.label;
- }
- } else if (micDeviceId) {
- selectedIn = micDeviceId in audioIn ? micDeviceId : 'default';
+ handleChangeEvent(x, z, k) {
+ if (k === 'ts' || k === 'ats') {
+ return;
+ }
+ if (this.isComponentEventuallyVisible()) {
+ if (++this.__cmmUpdateTickCount > 5) {
+ this.eventuallyUpdate();
+ delay.cancel(this.__cmmId);
+ } else {
+ delay(this.__cmmId, () => this.eventuallyUpdate(), 90);
+ }
} else {
- selectedIn = 'default';
+ this._requiresUpdateOnResize = true;
}
- if (this.micDefaultRenamed) {
- audioIn.default = this.micDefaultRenamed;
+ }
+ componentWillUnmount() {
+ super.componentWillUnmount();
+ const {chatRoom} = this.props;
+ if (chatRoom) {
+ chatRoom.off(`onChatShown.${ this.__cmmId}`).off(`onChatHidden.${ this.__cmmId}`);
}
- let selectedOut;
- let peerPlayer;
- if (call.sfuClient.peers.size) {
- peerPlayer = call.sfuClient.peers.values().next().audioPlayer;
+ if (this._contactChangeListeners) {
+ this.removeContactListeners();
}
- if (peerPlayer && peerPlayer.playerElem && peerPlayer.playerElem.sinkId) {
- const {
- sinkId
- } = peerPlayer.playerElem;
- selectedOut = sinkId in audioOut ? sinkId : 'default';
- } else if (audioOutDeviceId) {
- selectedOut = audioOutDeviceId in audioOut ? audioOutDeviceId : 'default';
- } else {
- selectedOut = 'default';
+ }
+ getContact() {
+ if (this.props.contact) {
+ return this.props.contact;
}
- const mics = Object.entries(audioIn).map(([id, name]) => {
- return react1().createElement(_ui_dropdowns_jsx9__.DropdownItem, {
- key: id,
- onClick: () => {
- call.sfuClient.setMicDevice(id === 'default' ? null : id);
- this.setState({
- audioSelectDropdown: false
- }, this.setActiveElement);
- }
- }, react1().createElement(react1().Fragment, null, react1().createElement("div", {
- className: "av-device-name"
- }, name), selectedIn === id && react1().createElement("i", {
- className: "sprite-fm-mono icon-check-small-regular-outline"
- })));
- });
- const speakers = Object.entries(audioOut).map(([id, name]) => {
- return react1().createElement(_ui_dropdowns_jsx9__.DropdownItem, {
- key: id,
- onClick: () => {
- Promise.resolve(call.sfuClient.setAudioOutDevice(id === 'default' ? null : id)).catch(dump);
- this.setState({
- audioSelectDropdown: false
- }, this.setActiveElement);
- }
- }, react1().createElement(react1().Fragment, null, react1().createElement("div", {
- className: "av-device-name"
- }, name), selectedOut === id && react1().createElement("i", {
- className: "sprite-fm-mono icon-check-small-regular-outline"
- })));
- });
- return react1().createElement(_ui_dropdowns_jsx9__.Dropdown, {
- className: "input-sources audio-sources theme-dark-forced",
- active: true,
- noArrow: true,
- positionMy: "center top",
- positionAt: "center bottom",
- horizOffset: -50,
- vertOffset: 16,
- closeDropdown: () => this.setState({
- audioSelectDropdown: false
- }, this.setActiveElement)
- }, react1().createElement("div", {
- className: "source-label"
- }, l.microphone), mics.length ? mics : react1().createElement(_ui_dropdowns_jsx9__.DropdownItem, {
- label: l.no_mics
- }), react1().createElement("hr", null), react1().createElement("div", {
- className: "source-label"
- }, l.speaker), speakers.length ? speakers : react1().createElement(_ui_dropdowns_jsx9__.DropdownItem, {
- label: l.no_speakers
- }), react1().createElement("hr", null), react1().createElement(_ui_dropdowns_jsx9__.DropdownItem, {
- icon: "sprite-fm-mono icon-volume-max-small-regular-outline",
- label: l.test_speaker,
- disabled: speakers.length === 0,
- onClick: () => {
- delay('call-test-speaker', () => {
- this.testAudioOut().catch(ex => {
- console.error('Failed to test audio on the selected device', ex, audioOutDeviceId);
- });
- });
- }
- }));
+ const {message} = this.props;
+ return Message.getContactForMessage(message);
+ }
+ getTimestampAsString() {
+ return toLocaleTime(this.getTimestamp());
}
- renderVideoDropdown() {
+ getTimestamp(forUpdated) {
const {
- call
+ message
} = this.props;
- const {
- videoIn = {}
- } = this.state.devices;
- const {
- camDeviceId
- } = SfuClient;
- let selectedCam;
- if (call.sfuClient.localCameraTrack()) {
- const {
- deviceId
- } = call.sfuClient.localCameraTrack().getCapabilities();
- selectedCam = deviceId in videoIn ? deviceId : 'default';
- } else if (camDeviceId) {
- selectedCam = camDeviceId in videoIn ? camDeviceId : 'default';
- } else {
- selectedCam = 'default';
+ const timestamp = (message.getDelay == null ? void 0 : message.getDelay()) || message.delay || unixtime();
+ return forUpdated && message.updated > 0 ? timestamp + message.updated : timestamp;
+ }
+ componentDidUpdate() {
+ const self = this;
+ const {chatRoom} = self.props.message;
+ if (!self.onAfterRenderWasTriggered) {
+ const msg = self.props.message;
+ let shouldRender = true;
+ if (msg.isManagement && msg.isManagement() === true && msg.isRenderableManagement() === false) {
+ shouldRender = false;
+ }
+ if (shouldRender) {
+ chatRoom.trigger("onAfterRenderMessage", self.props.message);
+ self.onAfterRenderWasTriggered = true;
+ }
}
- const cameras = Object.entries(videoIn).map(([id, name]) => {
- return react1().createElement(_ui_dropdowns_jsx9__.DropdownItem, {
- key: id,
- onClick: () => {
- call.sfuClient.setCameraDevice(id === 'default' ? null : id);
- this.setState({
- videoSelectDropdown: false
- }, this.setActiveElement);
- }
- }, react1().createElement(react1().Fragment, null, react1().createElement("div", {
- className: "av-device-name"
- }, name), selectedCam === id && react1().createElement("i", {
- className: "sprite-fm-mono icon-check-small-regular-outline"
- })));
+ }
+ getCurrentUserReactions() {
+ const {
+ reactions
+ } = this.props.message.reacts;
+ return Object.keys(reactions).filter(utf => {
+ let _reactions$utf;
+ return (_reactions$utf = reactions[utf]) == null ? void 0 : _reactions$utf[u_handle];
});
- return react1().createElement(_ui_dropdowns_jsx9__.Dropdown, {
- className: "input-sources video-sources theme-dark-forced",
- active: true,
- noArrow: true,
- positionMy: "center top",
- positionAt: "center bottom",
- horizOffset: -50,
- vertOffset: 16,
- closeDropdown: () => this.setState({
- videoSelectDropdown: false
- }, this.setActiveElement)
- }, react1().createElement("div", {
- className: "source-label"
- }, l.camera_button), cameras.length ? cameras : react1().createElement(_ui_dropdowns_jsx9__.DropdownItem, {
- label: l.no_cameras
- }));
}
- async updateMediaDevices() {
- let devices = await SfuClient.enumMediaDevices().catch(dump);
- devices = devices || {
- audioIn: {},
- audioOut: {},
- videoIn: {}
+ emojiSelected(e, slug, meta) {
+ const {
+ chatRoom,
+ message,
+ onEmojiBarChange
+ } = this.props;
+ if (chatRoom.isReadOnly()) {
+ return false;
+ }
+ const {
+ reactions
+ } = this.props.message.reacts;
+ const CURRENT_USER_REACTIONS = this.getCurrentUserReactions().length;
+ const REACTIONS_LIMIT = {
+ TOTAL: 50,
+ PER_PERSON: 24
};
- const removeEmptyDevices = devices => {
- for (const key of Object.keys(devices)) {
- if (!key || !devices[key]) {
- delete devices[key];
- }
+ const addReaction = () => chatRoom.messagesBuff.userAddReaction(message.messageId, slug, meta);
+ const emoji = megaChat._emojiData.emojisSlug[slug] || meta;
+ if (emoji && message.reacts.getReaction(u_handle, emoji.u)) {
+ if (onEmojiBarChange && Object.keys(reactions).length === 1 && Object.keys(reactions[emoji.u]).length === 1) {
+ onEmojiBarChange(false);
}
- };
- removeEmptyDevices(devices.audioIn);
- removeEmptyDevices(devices.audioOut);
- removeEmptyDevices(devices.videoIn);
- if (devices.audioIn.communications) {
- delete devices.audioIn.communications;
+ return chatRoom.messagesBuff.userDelReaction(message.messageId, slug, meta);
}
- return devices;
- }
- async testAudioOut() {
- if (!SfuClient.audioOutDeviceId) {
- return megaChat.playSound(megaChat.SOUNDS.SPEAKER_TEST);
+ if (emoji && reactions[emoji.u] && CURRENT_USER_REACTIONS < REACTIONS_LIMIT.PER_PERSON) {
+ return addReaction();
}
- const currentDevices = await this.updateMediaDevices();
- if (currentDevices.audioOut && !(SfuClient.audioOutDeviceId in currentDevices.audioOut)) {
- return megaChat.playSound(megaChat.SOUNDS.SPEAKER_TEST);
+ if (CURRENT_USER_REACTIONS >= REACTIONS_LIMIT.PER_PERSON) {
+ return msgDialog('info', '', l[24205].replace('%1', REACTIONS_LIMIT.PER_PERSON));
}
- const ctx = new AudioContext({
- sinkId: SfuClient.audioOutDeviceId
- });
- if (ctx.state !== 'running') {
- throw new Error('The audio context failed to start');
- }
- const soundBuffer = await megaChat.fetchSoundBuffer(megaChat.SOUNDS.SPEAKER_TEST);
- const buffer = await ctx.decodeAudioData(soundBuffer);
- const gain = ctx.createGain();
- const source = ctx.createBufferSource();
- source.buffer = buffer;
- source.connect(gain);
- gain.connect(ctx.destination);
- gain.gain.value = 0.07;
- source.start();
- }
- componentWillUnmount() {
- super.componentWillUnmount();
- document.removeEventListener('mousedown', this.handleMousedown);
- navigator.mediaDevices.removeEventListener('devicechange', this.handleDeviceChange);
- this.props.chatRoom.off(`onLocalSpeechDetected.${StreamControls.NAMESPACE}`);
+ if (Object.keys(reactions).length >= REACTIONS_LIMIT.TOTAL) {
+ return msgDialog('info', '', l[24206].replace('%1', REACTIONS_LIMIT.TOTAL));
+ } else if (onEmojiBarChange && Object.keys(reactions).length === 0) {
+ onEmojiBarChange(true);
+ }
+ return addReaction();
}
- componentDidMount() {
- super.componentDidMount();
- document.addEventListener('mousedown', this.handleMousedown);
- navigator.mediaDevices.addEventListener('devicechange', this.handleDeviceChange);
- this.props.chatRoom.rebind(`onLocalSpeechDetected.${StreamControls.NAMESPACE}`, () => this.setState({
- muteSpeak: true
- }, () => this.setActiveElement(true)));
+ _emojiOnActiveStateChange(newVal) {
+ this.setState(() => {
+ return {
+ reactionsDropdownActive: newVal
+ };
+ });
}
- render() {
+ getEmojisImages() {
const {
- call,
- signal,
chatRoom,
- renderSignalWarning,
- hasToRenderPermissionsWarning,
- renderPermissionsWarning,
- resetError,
- blocked,
- renderBlockedWarning,
- onAudioClick,
- onVideoClick,
- onScreenSharingClick,
- onHoldClick
+ message
} = this.props;
- const {
- audioSelectDropdown,
- videoSelectDropdown,
- muteSpeak
- } = this.state;
- const avFlags = call.av;
- const isOnHold = avFlags & Av.onHold;
- return react1().createElement(react1().Fragment, null, blocked && renderBlockedWarning(), react1().createElement("div", {
- ref: this.domRef,
- className: StreamControls.NAMESPACE
- }, d && localStorage.callDebug ? this.renderDebug() : '', react1().createElement("ul", null, react1().createElement("li", {
- className: `
- ${isOnHold ? 'disabled' : ''}
- with-input-selector
- `,
- onClick: () => isOnHold ? null : this.setState({
- muteSpeak: false
- }, () => {
- resetError(Av.Audio);
- onAudioClick();
- })
- }, muteSpeak && react1().createElement("div", {
- className: "mic-muted-tip theme-light-forced",
- onClick: ev => ev.stopPropagation()
- }, react1().createElement("span", null, l.mic_still_muted), react1().createElement(_button_jsx3__.A, {
- className: "mic-muted-tip-btn",
- onClick: () => {
- this.setState({
- muteSpeak: false
- }, () => {
- this.setActiveElement();
- eventlog(500509);
- });
+ const isReadOnlyClass = chatRoom.isReadOnly() ? " disabled" : "";
+ let emojisImages = message._reactions && message.reacts.reactions && Object.keys(message.reacts.reactions).map(utf => {
+ const reaction = message.reacts.reactions[utf];
+ const count = Object.keys(reaction).length;
+ if (!count) {
+ return null;
}
- }, l[148]), react1().createElement("i", {
- className: "sprite-fm-mono icon-tooltip-arrow tooltip-arrow bottom"
- })), react1().createElement(_button_jsx3__.A, {
- className: `
- mega-button
- theme-light-forced
- call-action
- round
- ${isOnHold ? 'disabled' : ''}
- ${avFlags & Av.Audio || isOnHold ? '' : 'with-fill'}
- `,
- icon: avFlags & Av.Audio ? 'icon-mic-thin-outline' : 'icon-mic-off-thin-outline'
- }), react1().createElement("span", null, l.mic_button), signal ? null : renderSignalWarning(), hasToRenderPermissionsWarning(Av.Audio) ? renderPermissionsWarning(Av.Audio) : null, this.renderSourceOpener({
- type: 'audioSelectDropdown',
- eventId: chatRoom.isMeeting ? 500299 : 500300
- })), audioSelectDropdown && react1().createElement("div", {
- ref: this.audioDropdownRef
- }, this.renderSoundDropdown()), react1().createElement("li", {
- className: `
- ${isOnHold ? 'disabled' : ''}
- with-input-selector
- `,
- onClick: () => {
- if (isOnHold) {
- return;
+ const filename = twemoji.convert.toCodePoint(utf);
+ const currentUserReacted = !!reaction[u_handle];
+ const names = [];
+ if (reaction) {
+ ChatdIntegration._ensureContactExists(Object.keys(reaction));
+ const rKeys = Object.keys(reaction);
+ for (let i = 0; i < rKeys.length; i++) {
+ const uid = rKeys[i];
+ if (reaction[uid]) {
+ if (uid === u_handle) {
+ names.push(l[24071] || 'You');
+ } else if (uid in M.u) {
+ names.push(M.getNameByHandle(uid) || megaChat.plugins.userHelper.SIMPLETIP_USER_LOADER);
+ }
+ }
}
- resetError(Av.Camera);
- onVideoClick();
}
- }, react1().createElement(_button_jsx3__.A, {
- className: `
- mega-button
- theme-light-forced
- call-action
- round
- ${isOnHold ? 'disabled' : ''}
- ${avFlags & Av.Camera || isOnHold ? '' : 'with-fill'}
- `,
- icon: avFlags & Av.Camera ? 'icon-video-thin-outline' : 'icon-video-off-thin-outline'
- }), react1().createElement("span", null, l.camera_button), hasToRenderPermissionsWarning(Av.Camera) ? renderPermissionsWarning(Av.Camera) : null, this.renderSourceOpener({
- type: 'videoSelectDropdown',
- eventId: chatRoom.isMeeting ? 500301 : 500302
- })), videoSelectDropdown && react1().createElement("div", {
- ref: this.videoDropdownRef
- }, this.renderVideoDropdown()), react1().createElement("li", {
- className: isOnHold ? 'disabled' : '',
- onClick: () => {
- if (isOnHold) {
- return;
+ let emojiData = megaChat._emojiData.emojisUtf[utf];
+ if (!emojiData) {
+ emojiData = Object.create(null);
+ emojiData.u = utf;
+ }
+ let slug = emojiData && emojiData.n || "";
+ let tipText;
+ slug = slug ? `:${slug}:` : utf;
+ if (Object.keys(reaction).length === 1 && reaction[u_handle]) {
+ tipText = (l[24068] || "You (click to remove) [G]reacted with %s[/G]").replace("%s", slug);
+ } else {
+ tipText = mega.utils.trans.listToString(names, (l[24069] || "%s [G]reacted with %s2[/G]").replace("%s2", slug));
+ }
+ const notFoundEmoji = slug && slug[0] !== ":";
+ return JSX_("div", {
+ key: slug,
+ onClick: ((e, slug, meta) => () => this.emojiSelected(e, slug, meta))(null, slug, emojiData),
+ className: `
+ reactions-bar__reaction
+ simpletip
+ ${currentUserReacted ? 'user-reacted' : ''}
+ ${notFoundEmoji ? 'emoji-loading-error' : ''}
+ ${isReadOnlyClass}
+ `,
+ "data-simpletip": tipText,
+ "data-simpletipoffset": "3",
+ "data-simpletipposition": "top"
+ }, JSX_("img", {
+ width: "10",
+ height: "10",
+ className: "emoji emoji-loading",
+ draggable: "false",
+ onError: e => {
+ const textNode = document.createElement("em");
+ textNode.classList.remove('emoji-loading');
+ textNode.append(document.createTextNode(utf));
+ e.target.replaceWith(textNode);
+ textNode.parentNode.classList.add('emoji-loading-error');
+ },
+ onLoad: e => {
+ e.target.classList.remove('emoji-loading');
+ },
+ src: `${staticpath }images/mega/twemojis/2_v2/72x72/${ filename }.png`
+ }), JSX_("span", {
+ className: "message text-block"
+ }, count));
+ });
+ emojisImages = emojisImages && emojisImages.filter((v) => {
+ return !!v;
+ });
+ if (emojisImages && emojisImages.length > 0) {
+ const reactionBtn = !chatRoom.isReadOnly() ? JSX_(_ui_buttons_jsx2__ .$, {
+ className: "popup-button reactions-button hover-colorized simpletip",
+ icon: "sprite-fm-theme icon-emoji-reactions reactions-icon",
+ disabled: false,
+ key: "add-reaction-button",
+ attrs: {
+ 'data-simpletip': l[24070] || "Add reaction...",
+ 'data-simpletipoffset': "3",
+ 'data-simpletipposition': "top"
}
- resetError(Av.Screen);
- onScreenSharingClick();
- if (chatRoom.isMeeting) {
- eventlog(500303);
- } else {
- eventlog(500304);
+ }, JSX_(_ui_emojiDropdown_jsx3__ .A, {
+ horizOffset: this.haveMeetingsCall() ? -150 : 0,
+ onActiveChange: this._emojiOnActiveStateChange,
+ className: "popup emoji reactions-dropdown",
+ onClick: this.emojiSelected
+ })) : null;
+ emojisImages.push(reactionBtn);
+ }
+ return emojisImages ? JSX_("div", {
+ className: "reactions-bar",
+ id: "reactions-bar",
+ onMouseEnter: () => {
+ if (this._loadedReacts) {
+ return false;
}
+ this._loadedReacts = megaChat.plugins.userHelper.fetchAllNames(this._reactionContacts(), chatRoom).catch(dump).finally(() => {
+ this._loadedReacts = true;
+ this.safeForceUpdate();
+ });
}
- }, react1().createElement(_button_jsx3__.A, {
- className: `
- mega-button
- theme-light-forced
- call-action
- round
- ${isOnHold ? 'disabled' : ''}
- ${avFlags & Av.Screen ? 'with-fill' : ''}
- `,
- icon: avFlags & Av.Screen ? 'icon-monitor-off' : 'icon-monitor'
- }), react1().createElement("span", null, avFlags & Av.Screen ? l.screenshare_stop_button : l.screenshare_button), hasToRenderPermissionsWarning(Av.Screen) ? renderPermissionsWarning(Av.Screen, this) : null), chatRoom.type === 'private' ? null : this.renderRaiseButton(), react1().createElement("li", {
- onClick: onHoldClick
- }, react1().createElement(_button_jsx3__.A, {
- className: `
- mega-button
- theme-light-forced
- call-action
- round
- ${isOnHold ? 'with-fill' : ''}
- `,
- icon: isOnHold ? 'icon-play-small-regular-outline' : 'icon-pause-small-regular-outline'
- }), react1().createElement("span", null, isOnHold ? l.resume_call_button : l.hold_button)), react1().createElement("li", null, this.renderEndCall()))));
+ }, emojisImages) : null;
+ }
+ getMessageActionButtons() {
+ const {
+ chatRoom,
+ message
+ } = this.props;
+ return message instanceof Message && message.isSentOrReceived() && !chatRoom.isReadOnly() ? JSX_(_ui_buttons_jsx2__ .$, {
+ className: "popup-button reactions-button tiny-button simpletip",
+ icon: `${"sprite-fm-theme reactions-icon"} icon-emoji-reactions`,
+ iconHovered: `${"sprite-fm-theme reactions-icon"} icon-emoji-reactions-active`,
+ disabled: false,
+ key: "add-reaction-button",
+ attrs: {
+ 'data-simpletip': l[24070] || "Add reaction...",
+ 'data-simpletipoffset': "3",
+ 'data-simpletipposition': "top"
+ }
+ }, JSX_(_ui_emojiDropdown_jsx3__ .A, {
+ horizOffset: this.haveMeetingsCall() ? -110 : 0,
+ noArrow: true,
+ onActiveChange: this._emojiOnActiveStateChange,
+ className: "popup emoji reactions-dropdown",
+ onClick: this.emojiSelected
+ })) : null;
}
}
-StreamControls.NAMESPACE = 'stream-controls';
-const __WEBPACK_DEFAULT_EXPORT__ = (0,_mixins2__.Zz)(_micObserver_jsx5__.Q, _permissionsObserver_jsx6__.$)(StreamControls);
-},
-414
+ },
+
+ 5470
(_, EXP_, REQ_) {
"use strict";
-REQ_.d(EXP_, {
-Cn: () => LocalVideoHiRes,
-Gz: () => AudioLevelIndicator,
-Qs: () => PeerVideoThumbFixed,
-Vm: () => LocalVideoHiResCloned,
-au: () => PeerVideoThumb,
-bJ: () => LocalVideoThumb,
-ob: () => PeerVideoHiResCloned,
-zu: () => PeerVideoHiRes
-});
-const react0__ = REQ_(594);
-const react0 = REQ_.n(react0__);
-const _mixins1__ = REQ_(137);
-const _contacts_jsx2__ = REQ_(251);
-const _call_jsx3__ = REQ_(3);
-const _ui_utils4__ = REQ_(314);
+ REQ_.d(EXP_, {
+ A: () => ScheduleMetaChange
+ });
+ const react0__ = REQ_(1594);
+ const react0___default = REQ_.n(react0__);
+ const _mixin_jsx1__ = REQ_(855);
+ const _contacts_jsx2__ = REQ_(8022);
+ const _ui_utils_jsx3__ = REQ_(6411);
+ const _ui_buttons_jsx4__ = REQ_(5155);
-class VideoNode extends _mixins1__.w9 {
- constructor(props, source) {
- super(props);
- this.domRef = react0().createRef();
- this.contRef = react0().createRef();
- this.audioLevelRef = react0().createRef();
- this.statsHudRef = react0().createRef();
- this.raisedHandListener = undefined;
+class ScheduleMetaChange extends _mixin_jsx1__ .M {
+ constructor(...args) {
+ super(...args);
this.state = {
- raisedHandPeers: []
+ link: ''
};
- this.source = source;
- this.state.raisedHandPeers = this.props.raisedHandPeers || [];
}
componentDidMount() {
- let _this$props$didMount, _this$props, _this$domRef;
super.componentDidMount();
- this.source.registerConsumer(this);
- (_this$props$didMount = (_this$props = this.props).didMount) == null || _this$props$didMount.call(_this$props, (_this$domRef = this.domRef) == null ? void 0 : _this$domRef.current);
- this.requestVideo(true);
- this.raisedHandListener = mBroadcaster.addListener('meetings:raisedHand', raisedHandPeers => this.setState({
- raisedHandPeers
- }, () => this.safeForceUpdate()));
- }
- onVisibilityChange(isVisible) {
- this.requestVideo(isVisible);
- }
- componentDidUpdate() {
- super.componentDidUpdate();
- if (this.props.didUpdate) {
- let _this$domRef2;
- this.props.didUpdate((_this$domRef2 = this.domRef) == null ? void 0 : _this$domRef2.current);
- }
- this.requestVideo();
- }
- onAvChange() {
- this.safeForceUpdate();
- }
- displayVideoElement(video, container) {
- this.attachVideoElemHandlers(video);
- this.video = video;
- container.replaceChildren(video);
- }
- attachVideoElemHandlers(video) {
- if (video._snSetup) {
- return;
+ if (this.props.mode === ScheduleMetaChange.MODE.CREATED) {
+ if (is_chatlink) {
+ this.setState({
+ link: `${getBaseUrl()}/chat/${is_chatlink.ph}#${is_chatlink.key}`
+ });
+ } else {
+ const {
+ chatRoom
+ } = this.props;
+ chatRoom.updatePublicHandle().then(() => {
+ if (this.isMounted() && !this.state.link && chatRoom.publicLink) {
+ this.setState({
+ link: `${getBaseUrl()}/${chatRoom.publicLink}`
+ });
+ }
+ }).catch(dump);
+ }
}
- video.autoplay = true;
- video.controls = false;
- video.muted = true;
- video.ondblclick = e => {
+ if (this.props.message.meta.ap) {
const {
- onDoubleClick,
- toggleFullScreen
- } = this.props;
- onDoubleClick == null || onDoubleClick(this.source, e);
- if (toggleFullScreen && !document.fullscreenElement && this.domRef.current) {
- if (typeof toggleFullScreen === 'function') {
- toggleFullScreen(this);
- }
- this.domRef.current.requestFullscreen({
- navigationUI: 'hide'
+ meetingsManager
+ } = megaChat.plugins;
+ this.redrawListener = `${meetingsManager.EVENTS.OCCURRENCES_UPDATE}.redraw${this.getUniqueId()}`;
+ megaChat.rebind(this.redrawListener, () => {
+ onIdle(() => {
+ const {
+ meta
+ } = this.props.message;
+ if (!meta.ap) {
+ return;
+ }
+ this.props.message.meta = meetingsManager.noCsMeta(meta.handle, meta.ap, megaChat.chats[meta.cid]);
+ this.safeForceUpdate();
});
- }
- };
- video.onloadeddata = ev => {
- if (this.props.onLoadedData) {
- this.props.onLoadedData(ev);
- }
- };
- video._snSetup = true;
+ megaChat.off(this.redrawListener);
+ delete this.redrawListener;
+ });
+ }
}
componentWillUnmount() {
super.componentWillUnmount();
- delete this.video;
- this.detachVideoElemHandlers();
- this.source.deregisterConsumer(this);
- mBroadcaster.removeListener(this.raisedHandListener);
- if (this.props.willUnmount) {
- this.props.willUnmount();
- }
- }
- detachVideoElemHandlers() {
- let _this$contRef$current;
- const video = (_this$contRef$current = this.contRef.current) == null ? void 0 : _this$contRef$current.firstChild;
- if (!video || !video._snSetup) {
- return;
- }
- video.onloadeddata = null;
- video.ondblclick = null;
- delete video._snSetup;
- }
- isVideoCropped() {
- let _this$video;
- return (_this$video = this.video) == null ? void 0 : _this$video.classList.contains("video-crop");
- }
- cropVideo() {
- let _this$video2;
- (_this$video2 = this.video) == null || _this$video2.classList.add("video-crop");
- }
- uncropVideo() {
- let _this$video3;
- (_this$video3 = this.video) == null || _this$video3.classList.remove("video-crop");
- }
- displayStats(stats) {
- const elem = this.statsHudRef.current;
- if (!elem) {
- return;
+ if (this.redrawListener) {
+ megaChat.off(this.redrawListener);
}
- elem.textContent = stats ? `${stats} (${this.ownVideo ? "cloned" : "ref"})` : "";
}
- renderVideoDebugMode() {
- if (this.source.isFake) {
- return null;
- }
- let className = "video-rtc-stats";
- let title;
- if (this.isLocal) {
- if (window.sfuClient) {
- title = new URL(window.sfuClient.url).host;
- }
- if (this.props.isSelfOverlay) {
- className += " video-rtc-stats-ralign";
- }
- }
- if (!title) {
- title = "";
+ specShouldComponentUpdate(nextProps) {
+ if (this.props.mode === ScheduleMetaChange.MODE.CREATED && this.props.link !== nextProps.link) {
+ return true;
}
- return react0().createElement("div", {
- ref: this.statsHudRef,
- className,
- title
- });
+ return null;
}
- renderContent() {
- const {
- source,
- contRef
- } = this;
- if (this.props.isPresenterNode || source.av & Av.Camera) {
- return react0().createElement("div", {
- ref: contRef,
- className: "video-node-holder video-node-loading"
+ componentDidUpdate(prevProps) {
+ if (this.props.mode === ScheduleMetaChange.MODE.CREATED && prevProps.link !== this.props.link) {
+ this.setState({
+ link: this.props.link ? `${getBaseUrl()}/${this.props.link}` : ''
});
}
- delete this._lastResizeHeight;
- return react0().createElement(_contacts_jsx2__.Avatar, {
- contact: M.u[source.userHandle]
- });
- }
- getStatusIcon(icon, label) {
- return react0().createElement("span", {
- className: "simpletip",
- "data-simpletip-class": "theme-dark-forced",
- "data-simpletipposition": "top",
- "data-simpletipoffset": "5",
- "data-simpletip": label
- }, react0().createElement("i", {
- className: icon
- }));
- }
- renderStatus() {
- const {
- chatRoom,
- isPresenterNode,
- minimized
- } = this.props;
- const {
- raisedHandPeers
- } = this.state;
- const {
- source
- } = this;
- const {
- sfuClient
- } = chatRoom.call;
- const {
- userHandle,
- isOnHold
- } = source;
- const $$CONTAINER = ({
- children
- }) => react0().createElement("div", {
- className: "video-node-status theme-dark-forced"
- }, children);
- const name = react0().createElement("div", {
- className: "video-status-name"
- }, isPresenterNode ? react0().createElement(_ui_utils4__.zT, null, l.presenter_nail.replace('%s', M.getNameByHandle(userHandle))) : react0().createElement(_contacts_jsx2__.ContactAwareName, {
- contact: M.u[userHandle],
- emoji: true
- }));
- if (isOnHold) {
- return react0().createElement($$CONTAINER, null, name, this.getStatusIcon('sprite-fm-mono icon-pause', l[23542].replace('%s', M.getNameByHandle(userHandle) || megaChat.plugins.userHelper.SIMPLETIP_USER_LOADER)));
- }
- return react0().createElement(react0().Fragment, null, !minimized && react0().createElement("div", {
- className: "stream-signifiers"
- }, raisedHandPeers && raisedHandPeers.length && raisedHandPeers.includes(userHandle) ? this.getStatusIcon('sprite-fm-uni stream-signifier-icon icon-raise-hand') : null), react0().createElement($$CONTAINER, null, name, react0().createElement(AudioLevelIndicator, {
- source
- }), sfuClient.haveBadNetwork ? this.getStatusIcon('sprite-fm-mono icon-call-offline', l.poor_connection) : null));
}
- render() {
+ onAddToCalendar() {
const {
- mode,
- chatRoom,
- simpletip,
- className,
- children,
- onClick
+ chatRoom
} = this.props;
const {
- domRef,
- source,
- isLocal,
- isLocalScreen
- } = this;
- if (!chatRoom.call) {
- return null;
- }
- const {
- call
- } = chatRoom;
- const isActiveSpeaker = !source.audioMuted && call.speakerCid === source.clientId;
- return react0().createElement("div", {
- ref: domRef,
- className: `
- video-node
- ${onClick ? 'clickable' : ''}
- ${className || ''}
- ${isLocal && !isLocalScreen ? ' local-stream-mirrored' : ''}
- ${simpletip ? 'simpletip' : ''}
- ${isActiveSpeaker && mode === _call_jsx3__.g.THUMBNAIL ? 'active-speaker' : ''}
- `,
- "data-simpletip": simpletip == null ? void 0 : simpletip.label,
- "data-simpletipposition": simpletip == null ? void 0 : simpletip.position,
- "data-simpletipoffset": simpletip == null ? void 0 : simpletip.offset,
- "data-simpletip-class": simpletip == null ? void 0 : simpletip.className,
- onClick: evt => onClick == null ? void 0 : onClick(source, evt)
- }, source && react0().createElement(react0().Fragment, null, children || null, react0().createElement("div", {
- className: "video-node-content"
- }, CallManager2.Call.VIDEO_DEBUG_MODE ? this.renderVideoDebugMode() : null, this.renderContent(), this.renderStatus())));
- }
-}
-class DynVideo extends VideoNode {
- onAvChange() {
- this._lastResizeHeight = null;
- super.onAvChange();
- }
- dynRequestVideo() {
- const {
- source,
- domRef
- } = this;
- if (source.isFake || source.isDestroyed) {
- return;
- }
- if (source.isStreaming() && this.isMounted()) {
- const node = domRef == null ? void 0 : domRef.current;
- this.dynRequestVideoBySize(node.offsetHeight);
- } else {
- this.dynRequestVideoBySize(0);
- this.displayStats(null);
- }
- }
- dynRequestVideoQuality(quality) {
- this.requestedQ = quality && CallManager2.FORCE_LOWQ ? 1 : quality;
- if (!this.source.dynUpdateVideoQuality()) {
- this.dynUpdateVideoElem();
- }
- }
- dynRequestVideoBySize(h) {
- if (h === 0) {
- this._lastResizeHeight = 0;
- this.dynRequestVideoQuality(CallManager2.VIDEO_QUALITY.NO_VIDEO);
- return;
- }
- if (this.contRef.current) {
- if (this._lastResizeHeight === h) {
- return;
- }
- this._lastResizeHeight = h;
- } else {
- this._lastResizeHeight = null;
- }
- let newQ;
- if (h > 360) {
- newQ = CallManager2.VIDEO_QUALITY.HIGH;
- } else if (h > 180) {
- newQ = CallManager2.VIDEO_QUALITY.MEDIUM;
- } else if (h > 90 || this.noThumb) {
- newQ = CallManager2.VIDEO_QUALITY.LOW;
- } else {
- newQ = CallManager2.VIDEO_QUALITY.THUMB;
- }
- this.dynRequestVideoQuality(newQ);
- }
- dynUpdateVideoElem() {
- let _this$source$hiResPla;
- const vidCont = this.contRef.current;
- if (!this.isMounted() || !vidCont) {
- return;
- }
- const player = this.noThumb ? (_this$source$hiResPla = this.source.hiResPlayer) == null || (_this$source$hiResPla = _this$source$hiResPla.gui) == null ? void 0 : _this$source$hiResPla.video : this.source.player;
- if (!player) {
- vidCont.replaceChildren();
- return;
- }
- this.dynSetVideoSource(player, vidCont);
- }
-}
-class DynVideoDirect extends DynVideo {
- constructor(props, source) {
- super(props, source);
- this.isDirect = true;
- this.requestVideo = this.dynRequestVideo;
- }
- dynSetVideoSource(srcPlayer, vidCont) {
- if (vidCont.firstChild !== srcPlayer) {
- this.displayVideoElement(srcPlayer, vidCont);
- }
- if (srcPlayer.paused) {
- srcPlayer.play().catch(nop);
- }
- }
-}
-class PeerVideoHiRes extends DynVideoDirect {
- constructor(props) {
- super(props, props.source);
- }
-}
-class DynVideoCloned extends DynVideo {
- constructor(props, source) {
- super(props, source);
- this.ownVideo = CallManager2.createVideoElement();
- }
- dynSetVideoSource(srcPlayer, vidCont) {
- const cloned = this.ownVideo;
- const currVideo = vidCont.firstChild;
- if (!currVideo) {
- this.displayVideoElement(cloned, vidCont);
- } else {
- assert(currVideo === cloned);
- }
- if (cloned.paused || cloned.srcObject !== srcPlayer.srcObject) {
- cloned.srcObject = srcPlayer.srcObject;
- Promise.resolve(cloned.play()).catch(nop);
- }
- }
-}
-class PeerVideoThumb extends DynVideoCloned {
- constructor(props) {
- super(props, props.source);
- this.requestVideo = this.dynRequestVideo;
- }
-}
-class PeerVideoThumbFixed extends VideoNode {
- constructor(props) {
- super(props, props.source);
- assert(props.source.hasScreenAndCam);
- this.ownVideo = CallManager2.createVideoElement();
- if (CallManager2.Call.VIDEO_DEBUG_MODE) {
- this.onRxStats = this._onRxStats;
- }
- }
- addVideo() {
- assert(this.source.hasScreenAndCam);
- const vidCont = this.contRef.current;
- assert(vidCont);
- if (vidCont.firstChild !== this.ownVideo) {
- this.displayVideoElement(this.ownVideo, vidCont);
- }
- }
- delVideo() {
- SfuClient.playerStop(this.ownVideo);
- const vidCont = this.contRef.current;
- if (!vidCont) {
- return;
- }
- vidCont.replaceChildren();
- }
- requestVideo(forceVisible) {
- if (!this.isComponentVisible() && !forceVisible) {
- return;
- }
- if (this.player) {
- this.playVideo();
- } else {
- this.addVideo();
- this.player = this.source.sfuPeer.getThumbVideo(() => {
- return this;
- });
- }
- }
- playVideo() {
- let _this$player$slot;
- const track = (_this$player$slot = this.player.slot) == null ? void 0 : _this$player$slot.inTrack;
- if (!track) {
- return;
- }
- SfuClient.playerPlay(this.ownVideo, track, true);
- }
- attachToTrack(track) {
- if (!this.source.hasScreenAndCam) {
- return;
- }
- SfuClient.playerPlay(this.ownVideo, track);
- }
- detachFromTrack() {
- this.delVideo();
- }
- onPlayerDestroy() {
- delete this.player;
- }
- componentWillUnmount() {
- if (this.player) {
- this.player.destroy();
- }
- super.componentWillUnmount();
- }
- _onRxStats(track, info, raw) {
- if (this.player) {
- this.displayStats(CallManager2.Call.rxStatsToText(track, info, raw));
- }
- }
-}
-class PeerVideoHiResCloned extends DynVideoCloned {
- constructor(props) {
- super(props, props.source);
- this.noThumb = true;
- this.requestVideo = this.dynRequestVideo;
- }
-}
-class LocalVideoHiResCloned extends VideoNode {
- constructor(props) {
- super(props, props.chatRoom.call.getLocalStream());
- this.isLocal = true;
- this.ownVideo = CallManager2.createVideoElement();
- }
- get isLocalScreen() {
- return this.source.av & Av.Screen;
- }
- requestVideo(forceVisible) {
- if (d > 1 && forceVisible) {
- console.debug('ignoring forceVisible');
- }
- const vidCont = this.contRef.current;
- if (!vidCont) {
- return;
- }
- const track = this.source.sfuClient.localScreenTrack();
- if (!track) {
- vidCont.replaceChildren();
- } else {
- if (vidCont.firstChild !== this.ownVideo) {
- this.displayVideoElement(this.ownVideo, vidCont);
- }
- SfuClient.playerPlay(this.ownVideo, track, true);
+ id,
+ title
+ } = chatRoom && chatRoom.scheduledMeeting || {};
+ if (id) {
+ delay(`fetchical${id}`, () => {
+ eventlog(500038);
+ asyncApiReq({
+ a: 'mcsmfical',
+ id
+ }).then(([, res]) => {
+ delay(`saveical${id}`, () => {
+ M.saveAs(base64urldecode(res), `${title.replace(/\W/g, '')}.ics`).then(nop).catch(() => {
+ msgDialog('error', '', l.calendar_add_failed, '');
+ });
+ }, 1000);
+ }).catch(() => {
+ msgDialog('error', '', l.calendar_add_failed, '');
+ });
+ }, 250);
}
}
-}
-class LocalVideoHiRes extends DynVideoDirect {
- constructor(props) {
- super(props, props.chatRoom.call.getLocalStream());
- this.isLocal = true;
- }
- get isLocalScreen() {
- return this.source.av & Av.Screen;
- }
-}
-class LocalVideoThumb extends VideoNode {
- constructor(props) {
- const source = props.chatRoom.call.getLocalStream();
- super(props, source);
- this.isLocal = true;
- this.isLocalScreen = source.av & Av.Screen && !(source.av & Av.Camera);
- this.sfuClient = props.chatRoom.call.sfuClient;
- this.ownVideo = CallManager2.createVideoElement();
- }
- requestVideo() {
- const vidCont = this.contRef.current;
- if (!vidCont) {
- return;
- }
- const currVideo = vidCont.firstChild;
- const track = this.isLocalScreen ? this.sfuClient.localScreenTrack() : this.sfuClient.localCameraTrack();
- if (!track) {
- if (currVideo) {
- vidCont.replaceChildren();
- }
- } else {
- if (!currVideo) {
- this.displayVideoElement(this.ownVideo, vidCont);
- } else {
- assert(currVideo === this.ownVideo);
- }
- SfuClient.playerPlay(this.ownVideo, track, true);
+ static getTitleText(meta) {
+ const {
+ mode,
+ recurring,
+ occurrence,
+ converted,
+ prevTiming
+ } = meta;
+ const {
+ MODE
+ } = ScheduleMetaChange;
+ switch (mode) {
+ case MODE.CREATED:
+ {
+ return recurring ? l.schedule_mgmt_new_recur : l.schedule_mgmt_new;
+ }
+ case MODE.EDITED:
+ {
+ if (converted) {
+ return recurring ? l.schedule_mgmt_update_convert_recur : l.schedule_mgmt_update_convert;
+ }
+ if (occurrence) {
+ return l.schedule_mgmt_update_occur;
+ }
+ if (prevTiming) {
+ return recurring ? l.schedule_mgmt_update_recur : l.schedule_mgmt_update;
+ }
+ return l.schedule_mgmt_update_desc;
+ }
+ case MODE.CANCELLED:
+ {
+ if (recurring) {
+ return occurrence ? l.schedule_mgmt_cancel_occur : l.schedule_mgmt_cancel_recur;
+ }
+ return l.schedule_mgmt_cancel;
+ }
}
+ return '';
}
- onAvChange() {
- const av = this.sfuClient.availAv;
- this.isLocalScreen = av & Av.Screen && !(av & Av.Camera);
- super.onAvChange();
- }
-}
-class AudioLevelIndicator extends react0().Component {
- constructor(props) {
- super(props);
- this.source = props.source;
- this.indicatorRef = react0().createRef();
- this.updateAudioLevel = this.updateAudioLevel.bind(this);
- }
- componentDidMount() {
- this.source.registerVuLevelConsumer(this);
- }
- componentWillUnmount() {
- this.source.unregisterVuLevelConsumer(this);
- }
- updateAudioLevel(level) {
- const levelInd = this.indicatorRef.current;
- if (!levelInd) {
- return;
+ renderTimingBlock() {
+ const {
+ message,
+ mode
+ } = this.props;
+ const {
+ meta
+ } = message;
+ const {
+ MODE
+ } = ScheduleMetaChange;
+ if (mode === MODE.CANCELLED && !meta.occurrence) {
+ return null;
}
- level = Math.round(level * 400);
- if (level > 90) {
- level = 90;
+ const [now, prev] = megaChat.plugins.meetingsManager.getOccurrenceStrings(meta);
+ return JSX_("div", {
+ className: "schedule-timing-block"
+ }, meta.prevTiming && JSX_("s", null, prev || ''), now);
+ }
+ checkAndFakeOccurrenceMeta(meta) {
+ const {
+ MODE
+ } = ScheduleMetaChange;
+ if (meta.occurrence && meta.mode === MODE.CANCELLED && !meta.calendar) {
+ const meeting = megaChat.plugins.meetingsManager.getMeetingOrOccurrenceParent(meta.handle);
+ if (meeting) {
+ const occurrences = meeting.getOccurrencesById(meta.handle);
+ if (occurrences) {
+ meta.calendar = {
+ date: new Date(occurrences[0].start).getDate(),
+ month: time2date(Math.floor(occurrences[0].start / 1000), 12)
+ };
+ meta.timeRules.startTime = Math.floor(occurrences[0].start / 1000);
+ meta.timeRules.endTime = Math.floor(occurrences[0].end / 1000);
+ }
+ }
}
- levelInd.style.height = `${level + 10}%`;
}
render() {
const {
- audioMuted
- } = this.source;
- return react0().createElement("span", {
- className: "simpletip",
- "data-simpletip-class": "theme-dark-forced",
- "data-simpletipposition": "top",
- "data-simpletipoffset": "5",
- "data-simpletip": audioMuted ? l.muted : ''
- }, react0().createElement("i", {
- className: `
- sprite-fm-mono
- ${audioMuted ? 'icon-mic-off-thin-outline inactive' : 'icon-mic-thin-outline speaker-indicator'}
- `
- }, audioMuted ? null : react0().createElement("div", {
- ref: this.indicatorRef,
- className: "mic-fill"
- })));
+ chatRoom,
+ message,
+ mode,
+ contact
+ } = this.props;
+ const {
+ meta,
+ messageId
+ } = message;
+ const {
+ scheduledMeeting
+ } = chatRoom;
+ const {
+ MODE
+ } = ScheduleMetaChange;
+ const {
+ link
+ } = this.state;
+ if (meta.gone) {
+ return null;
+ }
+ this.checkAndFakeOccurrenceMeta(meta);
+ return JSX_("div", null, JSX_("div", {
+ className: "message body",
+ "data-id": `id${messageId}`,
+ key: messageId
+ }, JSX_(_contacts_jsx2__ .eu, {
+ contact: contact.u,
+ className: "message avatar-wrapper small-rounded-avatar",
+ chatRoom
+ }), JSX_("div", {
+ className: "message schedule-message content-area small-info-txt selectable-txt"
+ }, JSX_(_contacts_jsx2__ .bq, {
+ className: "message",
+ chatRoom,
+ contact,
+ label: JSX_(_ui_utils_jsx3__ .zT, null, M.getNameByHandle(contact.u))
+ }), JSX_("div", {
+ className: "message date-time simpletip",
+ "data-simpletip": time2date(this.getTimestamp())
+ }, this.getTimestampAsString()), JSX_("div", {
+ className: "message text-block"
+ }, ScheduleMetaChange.getTitleText(meta), " ", !!d && meta.handle), JSX_("div", {
+ className: "message body-block"
+ }, (meta.prevTiming || meta.calendar || meta.topic && meta.onlyTitle || meta.recurring) && JSX_("div", {
+ className: "schedule-detail-block"
+ }, meta.calendar && scheduledMeeting && (meta.recurring && !scheduledMeeting.recurring || meta.occurrence && meta.mode === MODE.CANCELLED || !meta.recurring) && JSX_("div", {
+ className: "schedule-calendar-icon"
+ }, JSX_("div", {
+ className: "schedule-date"
+ }, meta.calendar.date), JSX_("div", {
+ className: "schedule-month"
+ }, meta.calendar.month)), JSX_("div", {
+ className: "schedule-detail-main"
+ }, JSX_("div", {
+ className: "schedule-meeting-title"
+ }, mode === MODE.CANCELLED ? JSX_("s", null, meta.topic || chatRoom.topic) : meta.topic || chatRoom.topic), this.renderTimingBlock()), chatRoom.iAmInRoom() && scheduledMeeting && mode !== MODE.CANCELLED && JSX_(_ui_buttons_jsx4__ .$, {
+ className: "mega-button",
+ onClick: () => this.onAddToCalendar()
+ }, JSX_("span", null, mode === MODE.CREATED && !meta.occurrence ? l.schedule_add_calendar : l.schedule_update_calendar))), mode === MODE.CREATED && scheduledMeeting && scheduledMeeting.description && JSX_("div", {
+ className: "schedule-description"
+ }, JSX_(_ui_utils_jsx3__ .P9, null, megaChat.html(scheduledMeeting.description).replace(/\n/g, '
'))), link && JSX_("div", null, JSX_("div", {
+ className: "schedule-link-instruction"
+ }, l.schedule_mgmt_link_instruct), JSX_("div", {
+ className: "schedule-meeting-link"
+ }, JSX_("span", null, link), JSX_(_ui_buttons_jsx4__ .$, {
+ className: "mega-button positive",
+ onClick: () => {
+ copyToClipboard(link, l[7654]);
+ delay('chat-event-sm-copy-link', () => eventlog(500039));
+ }
+ }, JSX_("span", null, l[63]))), JSX_("span", null, l.schedule_link_note))))));
}
}
+ScheduleMetaChange.MODE = {
+ CREATED: 1,
+ EDITED: 2,
+ CANCELLED: 3
+};
+window.ScheduleMetaChange = ScheduleMetaChange;
-},
+ },
-539
+ 187
(_, EXP_, REQ_) {
"use strict";
-REQ_.d(EXP_, {
-Ay: () => VideoNodeMenu,
-EH: () => Privilege,
-yU: () => Pin
-});
-const react0__ = REQ_(594);
-const react0 = REQ_.n(react0__);
-const _mixins1__ = REQ_(137);
-const _button_jsx2__ = REQ_(959);
-const _call_jsx3__ = REQ_(3);
-
-
-
-
-
-const Privilege = ({
- chatRoom,
- stream
-}) => {
- const {
- call,
- userHandle
- } = stream || {};
- if (call && call.isPublic) {
- const {
- OPERATOR,
- FULL
- } = ChatRoom.MembersSet.PRIVILEGE_STATE;
- const currentUserModerator = chatRoom.members[u_handle] === OPERATOR;
- const targetUserModerator = chatRoom.members[userHandle] === OPERATOR;
- return currentUserModerator && react0().createElement(_button_jsx2__.A, {
- targetUserModerator,
- icon: "sprite-fm-mono icon-admin-outline",
- onClick: () => {
- ['alterUserPrivilege', 'onCallPrivilegeChange'].map(event => chatRoom.trigger(event, [userHandle, targetUserModerator ? FULL : OPERATOR]));
- }
- }, react0().createElement("span", null, targetUserModerator ? l.remove_moderator : l.make_moderator));
- }
- return null;
-};
-const Contact = ({
- stream,
- ephemeralAccounts,
- onCallMinimize
-}) => {
- const {
- userHandle
- } = stream;
- const IS_GUEST = (0,_call_jsx3__.P)() || ephemeralAccounts && ephemeralAccounts.includes(userHandle);
- const HAS_RELATIONSHIP = M.u[userHandle].c === 1;
- if (HAS_RELATIONSHIP) {
- return react0().createElement(_button_jsx2__.A, {
- icon: "sprite-fm-mono icon-chat",
- onClick: () => {
- onCallMinimize();
- loadSubPage(`fm/chat/p/${userHandle}`);
- }
- }, react0().createElement("span", null, l[7997]));
- }
- return react0().createElement(_button_jsx2__.A, {
- className: IS_GUEST ? 'disabled' : '',
- icon: "sprite-fm-mono icon-add",
- onClick: () => {
- return IS_GUEST ? false : M.syncContactEmail(userHandle, true).then(email => {
- const OPC = Object.values(M.opc);
- if (OPC && OPC.length && OPC.some(opc => opc.m === email)) {
- return msgDialog('warningb', '', l[17545]);
- }
- msgDialog('info', l[150], l[5898]);
- M.inviteContact(M.u[u_handle].m, email);
- }).catch(() => mBroadcaster.sendMessage('meetings:ephemeralAdd', userHandle));
+ REQ_.d(EXP_, {
+ d: () => getMessageString
+ });
+let getMessageString;
+(function () {
+ let MESSAGE_STRINGS;
+ let MESSAGE_STRINGS_GROUP;
+ let MESSAGE_STRINGS_MEETING;
+ const _sanitizeStrings = function (arg) {
+ if (typeof arg === "undefined") {
+ return arg;
+ } else if (typeof arg === "string") {
+ return escapeHTML(arg);
+ } else if (arg.forEach) {
+ arg.forEach((v, k) => {
+ arg[k] = _sanitizeStrings(v);
+ });
+ } else if (typeof arg === "object") {
+ Object.keys(arg).forEach((k) => {
+ arg[k] = _sanitizeStrings(arg[k]);
+ });
}
- }, react0().createElement("span", null, l[24581]));
-};
-const Pin = ({
- stream,
- mode,
- onSpeakerChange,
- onModeChange
-}) => {
- return react0().createElement(_button_jsx2__.A, {
- icon: "sprite-fm-mono grid-main",
- onClick: () => mode === _call_jsx3__.g.THUMBNAIL ? onSpeakerChange == null ? void 0 : onSpeakerChange(stream) : onModeChange == null ? void 0 : onModeChange(_call_jsx3__.g.THUMBNAIL)
- }, react0().createElement("span", null, mode === _call_jsx3__.g.THUMBNAIL ? l.display_in_main_view : l.switch_to_thumb_view));
-};
-class VideoNodeMenu extends _mixins1__.w9 {
- constructor(...args) {
- super(...args);
- this.domRef = react0().createRef();
- this.ToggleCrop = ({
- videoNodeRef
- }) => {
- const videoNode = videoNodeRef == null ? void 0 : videoNodeRef.current;
- if (!videoNode) {
- return null;
- }
- return videoNode.isVideoCropped() ? react0().createElement(_button_jsx2__.A, {
- icon: "sprite-fm-mono grid-main",
- onClick: () => {
- videoNode.uncropVideo();
- this.forceUpdate();
- }
- }, react0().createElement("span", null, "Uncrop video")) : react0().createElement(_button_jsx2__.A, {
- icon: "sprite-fm-mono grid-main",
- onClick: () => {
- videoNode.cropVideo();
- this.forceUpdate();
- }
- }, react0().createElement("span", null, "Crop video"));
- };
- }
- render() {
- const {
- NAMESPACE
- } = VideoNodeMenu;
- const {
- stream,
- isPresenterNode,
- mode,
- onSpeakerChange,
- onModeChange
- } = this.props;
- const {
- userHandle,
- clientId
- } = stream;
- if (isPresenterNode) {
- return react0().createElement("div", {
- ref: this.domRef,
- className: `
- ${NAMESPACE}
- theme-dark-forced
- ${mode === _call_jsx3__.g.THUMBNAIL ? '' : 'presenter'}
- `
- }, react0().createElement("div", {
- className: `${NAMESPACE}-toggle`
- }, react0().createElement("i", {
- className: `sprite-fm-mono call-node-pin icon-pin${mode === _call_jsx3__.g.MAIN ? '-off' : ''}`,
- onClick: () => mode === _call_jsx3__.g.THUMBNAIL ? onSpeakerChange == null ? void 0 : onSpeakerChange(stream) : onModeChange == null ? void 0 : onModeChange(_call_jsx3__.g.THUMBNAIL)
- })));
+ return arg;
+ };
+ getMessageString = function (type, isGroupCall, isMeeting) {
+ if (!MESSAGE_STRINGS) {
+ MESSAGE_STRINGS = {
+ 'outgoing-call': l[5891].replace("[X]", "[[[X]]]"),
+ 'incoming-call': l[19964] || "[[%s]] is calling...",
+ 'call-timeout': [l[18698].replace("[X]", "[[[X]]]")],
+ 'call-starting': l[7206].replace("[X]", "[[[X]]]"),
+ 'call-feedback': l[7998].replace("[X]", "[[[X]]]"),
+ 'call-initialising': l[7207].replace("[X]", "[[[X]]]"),
+ 'call-ended': [l[19965] || "Call ended.", l[7208]],
+ 'remoteCallEnded': [l[19965] || "Call ended.", l[7208]],
+ 'call-failed-media': l[7204],
+ 'call-failed': [l[19966] || "Call failed.", l[7208]],
+ 'call-handled-elsewhere': l[5895].replace("[X]", "[[[X]]]"),
+ 'call-missed': l[17870],
+ 'call-rejected': l[19040],
+ 'call-canceled': l[19041],
+ 'remoteCallStarted': l[5888],
+ 'call-started': l[5888].replace("[X]", "[[[X]]]"),
+ 'alterParticipants': undefined,
+ 'privilegeChange': undefined,
+ 'truncated': l[8905]
+ };
+ _sanitizeStrings(MESSAGE_STRINGS);
+ }
+ if (isGroupCall && !MESSAGE_STRINGS_GROUP) {
+ MESSAGE_STRINGS_GROUP = {
+ 'call-ended': [l[19967], l[7208]],
+ 'remoteCallEnded': [l[19967], l[7208]],
+ 'call-handled-elsewhere': l[19968],
+ 'call-canceled': l[19969],
+ 'call-started': l[19970]
+ };
+ _sanitizeStrings(MESSAGE_STRINGS_GROUP);
}
- if (userHandle !== u_handle) {
- const $$CONTROLS = {
- Contact,
- Pin,
- Privilege
+ if (isMeeting && !MESSAGE_STRINGS_MEETING) {
+ MESSAGE_STRINGS_MEETING = {
+ 'call-ended': [l.meeting_mgmt_call_ended, l[7208]],
+ 'remoteCallEnded': [l.meeting_mgmt_call_ended, l[7208]],
+ 'call-started': l.meeting_mgmt_call_started
};
- return react0().createElement("div", {
- ref: this.domRef,
- className: `
- ${NAMESPACE}
- theme-dark-forced
- `
- }, react0().createElement("div", {
- className: `${NAMESPACE}-toggle`
- }, react0().createElement("i", {
- className: "sprite-fm-mono icon-more-horizontal-thin-outline"
- })), react0().createElement("div", {
- className: `${NAMESPACE}-content`
- }, react0().createElement("ul", null, Object.values($$CONTROLS).map(($$CONTROL, i) => react0().createElement("li", {
- key: `${Object.keys($$CONTROLS)[i]}-${clientId}-${userHandle}`
- }, react0().createElement($$CONTROL, this.props))))));
}
- return null;
- }
-}
-VideoNodeMenu.NAMESPACE = 'node-menu';
+ if (isMeeting && MESSAGE_STRINGS_MEETING[type]) {
+ return MESSAGE_STRINGS_MEETING[type];
+ }
+ if (isGroupCall && MESSAGE_STRINGS_GROUP[type]) {
+ return MESSAGE_STRINGS_GROUP[type];
+ }
+ return MESSAGE_STRINGS[type];
+ };
+})();
+
-},
+ },
-269
+ 4372
(_, EXP_, REQ_) {
"use strict";
-REQ_.r(EXP_);
-REQ_.d(EXP_, {
-"default": () => Incoming
-});
-const _extends0__ = REQ_(168);
-const react1__ = REQ_(594);
-const react1 = REQ_.n(react1__);
-const _contacts_jsx2__ = REQ_(251);
-const _ui_modalDialogs_jsx3__ = REQ_(318);
-const _button_jsx4__ = REQ_(959);
-const _call_jsx5__ = REQ_(3);
-const _ui_utils_jsx6__ = REQ_(314);
-
-
-
-
+ REQ_.d(EXP_, {
+ Y: () => withUpdateObserver
+ });
+ const _babel_runtime_helpers_extends0__ = REQ_(8168);
+ const react1__ = REQ_(1594);
+ const react1___default = REQ_.n(react1__);
+ const _mixins_js2__ = REQ_(8264);
-class Incoming extends react1().Component {
- constructor(props) {
- super(props);
+const withUpdateObserver = Component => class extends _mixins_js2__ .w9 {
+ constructor(...args) {
+ super(...args);
+ this.updateInterval = 600000;
+ this.instanceRef = react1___default().createRef();
+ this.intervalRef = undefined;
this.state = {
- video: false,
- unsupported: undefined,
- hoveredSwitch: true,
- hideOverlay: false
- };
- this.renderSwitchControls = () => {
- const className = `mega-button large round switch ${this.state.hoveredSwitch ? 'hovered' : ''}`;
- const toggleHover = () => this.setState(state => ({
- hoveredSwitch: !state.hoveredSwitch
- }));
- return react1().createElement("div", {
- className: "switch-button"
- }, react1().createElement("div", {
- className: "switch-button-container simpletip",
- "data-simpletip": l.end_and_answer,
- "data-simpletipposition": "top",
- onMouseEnter: toggleHover,
- onMouseLeave: toggleHover,
- onClick: ev => {
- ev.stopPropagation();
- this.props.onSwitch();
- }
- }, react1().createElement(_button_jsx4__.A, {
- className: `${className} negative`,
- icon: "icon-end-call"
- }), react1().createElement(_button_jsx4__.A, {
- className: `${className} positive`,
- icon: "icon-phone"
- })));
+ updated: 0
};
- this.renderAnswerControls = () => {
- const {
- video,
- unsupported
- } = this.state;
- const {
- onAnswer,
- onToggleVideo
- } = this.props;
- return react1().createElement(react1().Fragment, null, react1().createElement(_button_jsx4__.A, {
- className: `
- mega-button
- positive
- answer
- ${unsupported ? 'disabled' : ''}
- `,
- icon: "icon-phone",
- simpletip: unsupported ? null : {
- position: 'top',
- label: l[7205]
- },
- onClick: unsupported ? null : onAnswer
- }, react1().createElement("span", null, l[7205])), react1().createElement(_button_jsx4__.A, {
- className: `
- mega-button
- large
- round
- video
- ${video ? '' : 'negative'}
- ${unsupported ? 'disabled' : ''}
- `,
- icon: video ? 'icon-video-call-filled' : 'icon-video-off',
- simpletip: unsupported ? null : {
- position: 'top',
- label: video ? l[22894] : l[22893]
- },
- onClick: () => unsupported ? null : this.setState({
- video: !video
- }, () => onToggleVideo(video))
- }, react1().createElement("span", null, video ? l[22894] : l[22893])));
+ this.updateListener = () => {
+ return this.isComponentVisible() && document.visibilityState === 'visible' && this.setState(state => ({
+ updated: ++state.updated
+ }), () => this.safeForceUpdate());
};
- this.state.unsupported = !megaChat.hasSupportForCalls;
- this.state.hideOverlay = document.body.classList.contains('overlayed') && !$.msgDialog;
- }
- componentDidMount() {
- this._old$dialog = $.dialog;
- $.dialog = "chat-incoming-call";
}
componentWillUnmount() {
- $.dialog = this._old$dialog;
+ super.componentWillUnmount();
+ document.removeEventListener('visibilitychange', this.updateListener);
+ clearInterval(this.intervalRef);
+ }
+ componentDidMount() {
+ super.componentDidMount();
+ document.addEventListener('visibilitychange', this.updateListener);
+ this.intervalRef = setInterval(this.instanceRef.current[Component.updateListener] || this.updateListener, Component.updateInterval || this.updateInterval);
}
render() {
- const {
- chatRoom
- } = this.props;
- if (chatRoom) {
- const {
- NAMESPACE
- } = Incoming;
- const {
- callerId,
- onClose,
- onReject
- } = this.props;
- const {
- unsupported
- } = this.state;
- const CALL_IN_PROGRESS = window.sfuClient;
- const isPrivateRoom = chatRoom.type === 'private';
- const rejectLabel = isPrivateRoom ? l[20981] : l.msg_dlg_cancel;
- return react1().createElement(_ui_modalDialogs_jsx3__.A.ModalDialog, (0,_extends0__.A)({}, this.state, {
- name: NAMESPACE,
- className: NAMESPACE,
- roomName: chatRoom.getRoomTitle(),
- onClose: () => onClose()
- }), react1().createElement("div", {
- className: "fm-dialog-body"
- }, react1().createElement("div", {
- className: `${NAMESPACE}-avatar`
- }, react1().createElement(_contacts_jsx2__.Avatar, {
- contact: M.u[callerId]
- })), react1().createElement("div", {
- className: `${NAMESPACE}-info`
- }, react1().createElement("h1", null, react1().createElement(_ui_utils_jsx6__.zT, null, chatRoom.getRoomTitle())), react1().createElement("span", null, isPrivateRoom ? l[17878] : l[19995])), react1().createElement("div", {
- className: `
- ${NAMESPACE}-controls
- ${CALL_IN_PROGRESS ? 'call-in-progress' : ''}
- `
- }, react1().createElement(_button_jsx4__.A, {
- className: `
- mega-button
- large
- round
- negative
- `,
- icon: "icon-end-call",
- simpletip: {
- position: 'top',
- label: rejectLabel
- },
- onClick: onReject
- }, react1().createElement("span", null, rejectLabel)), CALL_IN_PROGRESS ? this.renderSwitchControls() : this.renderAnswerControls()), unsupported && react1().createElement("div", {
- className: `${NAMESPACE}-unsupported`
- }, react1().createElement("div", {
- className: "unsupported-message"
- }, _call_jsx5__.Ay.getUnsupportedBrowserMessage()))));
- }
- console.error('Incoming dialog received missing chatRoom prop.');
- return null;
+ return JSX_(Component, (0,_babel_runtime_helpers_extends0__ .A)({
+ ref: this.instanceRef
+ }, this.state, this.props));
}
-}
-Incoming.NAMESPACE = 'incoming-dialog';
-window.ChatCallIncomingDialog = Incoming;
+};
-},
+ },
-485
+ 5779
(_, EXP_, REQ_) {
"use strict";
-REQ_.d(EXP_, {
-A: () => __WEBPACK_DEFAULT_EXPORT__
-});
-const react0__ = REQ_(594);
-const react0 = REQ_.n(react0__);
-const _mixins_js1__ = REQ_(137);
-const _contacts_jsx2__ = REQ_(251);
-const _call_jsx3__ = REQ_(3);
-const _button_jsx4__ = REQ_(959);
-const _permissionsObserver_jsx5__ = REQ_(542);
+ REQ_.d(EXP_, {
+ O1: () => prepareExportIo,
+ VV: () => prepareExportStreams,
+ li: () => withSuspense
+ });
+ const react0__ = REQ_(1594);
+ const react0___default = REQ_.n(react0__);
+ const _ui_fallback_jsx1__ = REQ_(3439);
+
+
+async function prepareExportIo(dl) {
+ const {
+ zname,
+ size
+ } = dl;
+ if (window.isSecureContext && typeof showSaveFilePicker === 'function' && typeof FileSystemFileHandle !== 'undefined' && 'createWritable' in FileSystemFileHandle.prototype && typeof FileSystemWritableFileStream !== 'undefined' && 'seek' in FileSystemWritableFileStream.prototype) {
+ const file = await window.showSaveFilePicker({
+ suggestedName: zname
+ }).catch(ex => {
+ if (String(ex).includes('aborted')) {
+ throw new Error('Aborted');
+ }
+ dump(ex);
+ });
+ if (file) {
+ const stream = await file.createWritable().catch(dump);
+ if (stream) {
+ return {
+ stream,
+ write (data, position, done) {
+ this.stream.write({
+ type: 'write',
+ position,
+ data
+ }).then(done).catch(dump);
+ },
+ download () {
+ this.abort();
+ },
+ abort () {
+ this.stream.close();
+ },
+ setCredentials () {
+ this.begin();
+ }
+ };
+ }
+ }
+ }
+ if (MemoryIO.usable() && Math.min(MemoryIO.fileSizeLimit, 94371840) > size) {
+ return new MemoryIO('chat_0', dl);
+ } else if (window.requestFileSystem) {
+ return new FileSystemAPI('chat_0', dl);
+ }
+ throw new Error('Download methods are unsupported');
+}
+function prepareExportStreams(attachNodes, onEmpty) {
+ return attachNodes.map(node => {
+ return {
+ name: node.name,
+ lastModified: new Date((node.mtime || node.ts) * 1000),
+ input: M.gfsfetch.getReadableStream(node, {
+ error(ex, n) {
+ if (d) {
+ console.error(`${n.h}: ${ex}`);
+ }
+ onEmpty(n.s);
+ }
+ })
+ };
+ });
+}
+const withSuspense = Component => {
+ const Wrapped = props => JSX_(react0__.Suspense, {
+ fallback: JSX_(_ui_fallback_jsx1__ .A, null)
+ }, JSX_(Component, props));
+ Wrapped.displayName = `withSuspense(${Component.displayName || Component.name || 'Component'})`;
+ return Wrapped;
+};
+ },
+ 5155
+(_, EXP_, REQ_) {
+"use strict";
+ REQ_.d(EXP_, {
+ $: () => Button
+ });
+ const _babel_runtime_helpers_extends0__ = REQ_(8168);
+ const react1__ = REQ_(1594);
+ const react1___default = REQ_.n(react1__);
+ const _chat_mixins_js2__ = REQ_(8264);
-class Preview extends react0().Component {
+const BLURRABLE_CLASSES = '.conversationsApp, .join-meeting, .main-blur-block';
+class Button extends _chat_mixins_js2__ .w9 {
constructor(props) {
super(props);
- this.domRef = react0().createRef();
- this.videoRef = react0().createRef();
- this.stream = null;
+ this.domRef = react1___default().createRef();
+ this.buttonClass = `.button`;
this.state = {
- audio: false,
- video: false,
- avatarMeta: undefined
+ focused: false,
+ hovered: false,
+ iconHovered: ''
};
- this.getTrackType = type => !type ? 'getTracks' : type === Preview.STREAMS.AUDIO ? 'getAudioTracks' : 'getVideoTracks';
- this.startStream = type => {
- this.stopStream();
- const {
- audio,
- video
- } = this.state;
- navigator.mediaDevices.getUserMedia({
- audio,
- video
- }).then(stream => {
- const videoRef = this.videoRef.current;
- if (videoRef) {
- videoRef.srcObject = stream;
- this.stream = stream;
- if (this.props.onToggle) {
- this.props.onToggle(this.state.audio, this.state.video);
- }
- }
- }).catch(ex => {
- const stream = type === Preview.STREAMS.AUDIO ? 'audio' : 'video';
- return this.domRef.current && this.setState(state => ({
- [stream]: !state[stream]
- }), () => {
- megaChat.trigger('onLocalMediaError', {
- [type === Preview.STREAMS.AUDIO ? 'mic' : 'camera']: `${ex.name}: ${ex.message}`
- });
- console.error(`${ex.name}: ${ex.message}`);
+ this.onBlur = e => {
+ let _this$domRef;
+ if (!this.isMounted()) {
+ return;
+ }
+ if (!e || !$(e.target).closest(this.buttonClass).is((_this$domRef = this.domRef) == null ? void 0 : _this$domRef.current)) {
+ this.setState({
+ focused: false
+ }, () => {
+ this.unbindEvents();
+ this.safeForceUpdate();
});
- });
- };
- this.stopStream = type => {
- if (this.stream) {
- const trackType = this.getTrackType(type);
- const tracks = this.stream[trackType]();
- for (const track of tracks) {
- track.stop();
- }
}
};
- this.toggleStream = type => {
- let _this$props$resetErro, _this$props;
- const stream = type === Preview.STREAMS.AUDIO ? 'audio' : 'video';
- this.setState(state => ({
- [stream]: !state[stream]
- }), () => {
- if (this.props.onToggle) {
- this.props.onToggle(this.state.audio, this.state.video);
+ this.onClick = e => {
+ let _this$domRef2;
+ if (this.props.disabled === true) {
+ e.preventDefault();
+ e.stopPropagation();
+ return;
+ }
+ if ($(e.target).closest('.popup').closest(this.buttonClass).is((_this$domRef2 = this.domRef) == null ? void 0 : _this$domRef2.current) && this.state.focused === true) {
+ e.preventDefault();
+ e.stopPropagation();
+ return;
+ }
+ if ($(e.target).is('input, textarea, select')) {
+ return;
+ }
+ if (this.state.focused === false) {
+ if (this.props.onClick) {
+ this.props.onClick(this, e);
+ } else if (react1___default().Children.count(this.props.children) > 0) {
+ this.setState({
+ focused: true
+ }, () => this.safeForceUpdate());
}
- return this.state[stream] ? this.startStream(type) : this.stopStream(type);
- });
- (_this$props$resetErro = (_this$props = this.props).resetError) == null || _this$props$resetErro.call(_this$props, type === Preview.STREAMS.AUDIO ? Av.Audio : Av.Camera);
- };
- this.renderAvatar = () => {
- if ((0,_call_jsx3__.P)()) {
- return react0().createElement("div", {
- className: "avatar-guest"
- }, react0().createElement("i", {
- className: "sprite-fm-uni icon-owner"
- }));
+ } else if (this.state.focused === true) {
+ this.setState({
+ focused: false
+ });
+ this.unbindEvents();
}
- if (is_chatlink) {
- const {
- avatarUrl,
- color,
- shortName
- } = this.state.avatarMeta || {};
- return react0().createElement("div", {
- className: `
- avatar-wrapper
- ${color ? `color${color}` : ''}
- `
- }, avatarUrl && react0().createElement("img", {
- src: avatarUrl,
- alt: ""
- }), color && react0().createElement("span", null, shortName));
+ };
+ this.state.iconHovered = this.props.iconHovered || '';
+ }
+ UNSAFE_componentWillUpdate(nextProps, nextState) {
+ if (nextProps.disabled === true && nextState.focused === true) {
+ nextState.focused = false;
+ }
+ if (this.state.focused !== nextState.focused && nextState.focused === true) {
+ this.bindEvents();
+ if (this._pageChangeListener) {
+ mBroadcaster.removeListener(this._pageChangeListener);
}
- return react0().createElement(_contacts_jsx2__.Avatar, {
- contact: M.u[u_handle]
+ this._pageChangeListener = mBroadcaster.addListener('pagechange', () => {
+ if (this.state.focused === true) {
+ this.onBlur();
+ }
});
- };
- this.state.audio = this.props.audio || this.state.audio;
- if (this.props.video) {
- this.state.video = this.props.video;
- this.startStream(Preview.STREAMS.VIDEO);
- this.props.onToggle(this.state.audio, this.state.video);
}
}
componentWillUnmount() {
- this.stopStream();
+ super.componentWillUnmount();
+ this.unbindEvents();
}
- componentDidMount() {
- if (this.props.onToggle) {
- this.props.onToggle(this.state.audio, this.state.video);
- }
- this.setState({
- avatarMeta: is_chatlink ? generateAvatarMeta(u_handle) : undefined
- });
+ renderChildren() {
+ return this.props.children && react1___default().Children.map(this.props.children, child => child && (typeof child.type === 'string' || child.type === undefined ? child : react1___default().cloneElement(child, {
+ active: this.state.focused,
+ closeDropdown: () => this.setState({
+ focused: false
+ }, () => this.unbindEvents()),
+ onActiveChange: active => {
+ let _this$domRef3;
+ const $element = $(((_this$domRef3 = this.domRef) == null ? void 0 : _this$domRef3.current) || this.domNode);
+ const $scrollables = $element.parents('.ps');
+ if ($scrollables.length > 0) {
+ $scrollables.map((k, element) => Ps[active ? 'disable' : 'enable'](element));
+ }
+ child.props.onActiveChange == null || child.props.onActiveChange(active);
+ return this[active ? 'bindEvents' : 'unbindEvents']();
+ }
+ })));
+ }
+ bindEvents() {
+ $(BLURRABLE_CLASSES).rebind(`mousedown.button--${this.getUniqueId()}`, this.onBlur);
+ $(document).rebind(`keyup.button--${this.getUniqueId()}`, ev => this.state.focused === true && ev.keyCode === 27 && this.onBlur());
+ $(document).rebind(`closeDropdowns.${this.getUniqueId()}`, this.onBlur);
+ }
+ unbindEvents() {
+ $(BLURRABLE_CLASSES).unbind(`mousedown.button--${this.getUniqueId()}`);
+ $(document).off(`keyup.button--${this.getUniqueId()}`);
+ $(document).off(`closeDropdowns.${this.getUniqueId()}`);
+ mBroadcaster.removeListener(this._pageChangeListener);
}
render() {
const {
- NAMESPACE
- } = Preview;
- const {
- hasToRenderPermissionsWarning,
- renderPermissionsWarning
+ className,
+ disabled,
+ style,
+ icon,
+ iconHovered,
+ label,
+ attrs,
+ toggle,
+ secondLabel,
+ secondLabelClass
} = this.props;
- const {
- audio,
- video
- } = this.state;
- const SIMPLETIP_PROPS = {
- label: undefined,
- position: 'top',
- className: 'theme-dark-forced'
- };
- return react0().createElement("div", {
+ const isMegaButton = className && className.indexOf('mega-button') > -1;
+ const TagName = isMegaButton ? 'button' : 'div';
+ return JSX_(TagName, (0,_babel_runtime_helpers_extends0__ .A)({
ref: this.domRef,
className: `
- ${NAMESPACE}
- local-stream-mirrored
- `
- }, video && react0().createElement("div", {
- className: `${NAMESPACE}-video-overlay`
- }), react0().createElement("video", {
- className: video ? 'streaming' : '',
- muted: true,
- autoPlay: true,
- ref: this.videoRef
- }), !video && this.renderAvatar(), react0().createElement("div", {
- className: `${NAMESPACE}-controls`
- }, react0().createElement("div", {
- className: "preview-control-wrapper"
- }, react0().createElement(_button_jsx4__.A, {
- simpletip: {
- ...SIMPLETIP_PROPS,
- label: audio ? l[16214] : l[16708]
- },
- className: `
- mega-button
- round
- theme-light-forced
- ${NAMESPACE}-control
- ${audio ? '' : 'with-fill'}
- `,
- icon: audio ? 'icon-mic-thin-outline' : 'icon-mic-off-thin-outline',
- onClick: () => {
- this.toggleStream(Preview.STREAMS.AUDIO);
- }
- }), react0().createElement("span", null, l.mic_button), hasToRenderPermissionsWarning(Av.Audio) ? renderPermissionsWarning(Av.Audio) : null), react0().createElement("div", {
- className: "preview-control-wrapper"
- }, react0().createElement(_button_jsx4__.A, {
- simpletip: {
- ...SIMPLETIP_PROPS,
- label: video ? l[22894] : l[22893]
- },
+ button
+ ${className || ''}
+ ${disabled ? 'disabled' : ''}
+ ${this.state.focused ? 'active active-dropdown' : ''}
+ `,
+ style,
+ onClick: this.onClick,
+ onMouseEnter: () => iconHovered && this.setState({
+ hovered: true
+ }),
+ onMouseLeave: () => iconHovered && this.setState({
+ hovered: false
+ })
+ }, attrs), icon && !isMegaButton && JSX_("div", null, JSX_("i", {
+ className: this.state.hovered ? this.state.iconHovered : icon
+ })), icon && isMegaButton && JSX_("div", null, JSX_("i", {
+ className: this.state.hovered ? this.state.iconHovered : icon
+ })), label && JSX_("span", null, label), secondLabel && JSX_("span", {
+ className: secondLabelClass ? secondLabelClass : ''
+ }, secondLabel), toggle && JSX_("div", {
className: `
- mega-button
- round
- theme-light-forced
- ${NAMESPACE}-control
- ${video ? '' : 'with-fill'}
- `,
- icon: video ? 'icon-video-thin-outline' : 'icon-video-off-thin-outline',
- onClick: () => this.toggleStream(Preview.STREAMS.VIDEO)
- }), react0().createElement("span", null, l.camera_button), hasToRenderPermissionsWarning(Av.Camera) ? renderPermissionsWarning(Av.Camera) : null)));
+ mega-switch
+ ${toggle.className ? toggle.className : ''}
+ ${toggle.enabled ? 'toggle-on' : ''}
+ `,
+ role: "switch",
+ "aria-checked": !!toggle.enabled,
+ onClick: ev => {
+ ev.stopPropagation();
+ if (this.props.toggle.onClick) {
+ this.props.toggle.onClick();
+ }
+ }
+ }, JSX_("div", {
+ className: `mega-feature-switch sprite-fm-mono-after
+ ${toggle.enabled ? 'icon-check-after' : 'icon-minimise-after'}`
+ })), this.renderChildren());
}
}
-Preview.NAMESPACE = 'preview-meeting';
-Preview.STREAMS = {
- AUDIO: 1,
- VIDEO: 2
-};
-const __WEBPACK_DEFAULT_EXPORT__ = (0,_mixins_js1__.Zz)(_permissionsObserver_jsx5__.$)(Preview);
-},
+ },
-890
+ 1510
(_, EXP_, REQ_) {
"use strict";
+ REQ_.d(EXP_, {
+ ms: () => Dropdown,
+ tJ: () => DropdownItem
+ });
-// EXPORTS
-REQ_.d(EXP_, {
- A: () => GenericConversationMessage
-});
-
-// EXTERNAL MODULE: ./node_modules/@babel/runtime/helpers/esm/extends.js
-const esm_extends = REQ_(168);
-// EXTERNAL MODULE: external "React"
-const React_ = REQ_(594);
-const REaCt = REQ_.n(React_);
-// EXTERNAL MODULE: ./js/chat/ui/messages/mixin.jsx
-const mixin = REQ_(446);
-// EXTERNAL MODULE: ./js/chat/ui/contacts.jsx
-const ui_contacts = REQ_(251);
-// EXTERNAL MODULE: ./js/ui/utils.jsx
-const utils = REQ_(314);
-;// ./js/chat/ui/messages/abstractGenericMessage.jsx
+ const react0__ = REQ_(1594);
+ const react0___default = REQ_.n(react0__);
+ const _utils_jsx1__ = REQ_(6411);
+ const _chat_mixins2__ = REQ_(8264);
+ const _chat_ui_contacts_jsx3__ = REQ_(8022);
-class AbstractGenericMessage extends mixin.M {
- constructor(...args) {
- super(...args);
- this.domRef = REaCt().createRef();
+class Dropdown extends _chat_mixins2__ .w9 {
+ constructor(props) {
+ super(props);
+ this.domRef = react0___default().createRef();
+ this.onActiveChange = this.onActiveChange.bind(this);
+ this.onResized = this.onResized.bind(this);
+ }
+ UNSAFE_componentWillUpdate(nextProps) {
+ if (this.props.active != nextProps.active) {
+ this.onActiveChange(nextProps.active);
+ }
+ }
+ specShouldComponentUpdate(nextProps, nextState) {
+ if (this.props.active != nextProps.active) {
+ if (this.props.onBeforeActiveChange) {
+ this.props.onBeforeActiveChange(nextProps.active);
+ }
+ return true;
+ } else if (this.props.focused != nextProps.focused) {
+ return true;
+ } else if (this.state && this.state.active != nextState.active) {
+ return true;
+ }
+ return undefined;
+ }
+ onActiveChange(newVal) {
+ if (this.props.onActiveChange) {
+ this.props.onActiveChange(newVal);
+ }
+ }
+ reposElementUsing(element, obj, info) {
+ let $element;
+ if (this.popupElement) {
+ $element = $(this.popupElement);
+ } else {
+ return;
+ }
+ const self = this;
+ let vertOffset = 0;
+ let horizOffset = 0;
+ if (!self.props.noArrow) {
+ const $arrow = $('.dropdown-white-arrow', $element);
+ let arrowHeight;
+ if (self.props.arrowHeight) {
+ arrowHeight = self.props.arrowHeight;
+ if (info.vertical === "top") {
+ arrowHeight = 0;
+ } else {
+ arrowHeight *= -1;
+ }
+ } else {
+ arrowHeight = $arrow.outerHeight();
+ }
+ if (info.vertical === "top") {
+ $(element).removeClass("down-arrow").addClass("up-arrow");
+ } else {
+ $(element).removeClass("up-arrow").addClass("down-arrow");
+ }
+ vertOffset += info.vertical === "top" ? arrowHeight : 0;
+ }
+ if (self.props.vertOffset) {
+ vertOffset += self.props.vertOffset * (info.vertical === "top" ? 1 : -1);
+ }
+ if (self.props.horizOffset) {
+ horizOffset += self.props.horizOffset;
+ }
+ $(element).css({
+ left: `${obj.left + 0 + horizOffset }px`,
+ top: `${obj.top + vertOffset }px`
+ });
+ if (this.props.positionLeft) {
+ $(element).css({
+ left: this.props.positionLeft
+ });
+ }
+ }
+ onResized() {
+ const self = this;
+ if (this.props.active === true && this.popupElement) {
+ const $element = $(this.popupElement);
+ const $positionToElement = $('.button.active-dropdown:visible');
+ if ($positionToElement.length === 0) {
+ return;
+ }
+ let $container = $positionToElement.closest('.messages.scroll-area');
+ if ($container.length === 0) {
+ $container = $(document.body);
+ }
+ $element.css('margin-left', '');
+ $element.position({
+ of: $positionToElement,
+ my: self.props.positionMy ? self.props.positionMy : "center top",
+ at: self.props.positionAt ? self.props.positionAt : "center bottom",
+ collision: this.props.collision || 'flipfit',
+ within: self.props.wrapper || $container,
+ using (obj, info) {
+ self.reposElementUsing(this, obj, info);
+ }
+ });
+ }
+ }
+ componentDidMount() {
+ super.componentDidMount();
+ chatGlobalEventManager.addEventListener('resize', `drpdwn${ this.getUniqueId()}`, this.onResized.bind(this));
+ this.onResized();
+ const self = this;
+ $(document.body).rebind(`closeAllDropdownsExcept.drpdwn${ this.getUniqueId()}`, (e, target) => {
+ if (self.props.active && target !== self) {
+ if (self.props && self.props.closeDropdown) {
+ self.props.closeDropdown();
+ }
+ }
+ });
}
- getAvatar() {
- const contact = this.getContact() || Message.getContactForMessage(this.props.message);
- if (this.props.grouped) {
- return null;
+ componentDidUpdate() {
+ this.onResized();
+ }
+ componentWillUnmount() {
+ super.componentWillUnmount();
+ $(document.body).unbind(`closeAllDropdownsExcept.drpdwn${ this.getUniqueId()}`);
+ if (this.props.active) {
+ this.onActiveChange(false);
}
- return contact ? REaCt().createElement(ui_contacts.Avatar, {
- contact: this.getContact(),
- className: "message avatar-wrapper small-rounded-avatar",
- chatRoom: this.props.chatRoom
- }) : null;
+ chatGlobalEventManager.removeEventListener('resize', `drpdwn${ this.getUniqueId()}`);
+ }
+ doRerender() {
+ const self = this;
+ setTimeout(() => {
+ self.safeForceUpdate();
+ }, 100);
+ setTimeout(() => {
+ self.onResized();
+ }, 200);
}
- getName() {
- const contact = this.getContact() || Message.getContactForMessage(this.props.message);
- if (this.props.grouped) {
+ renderChildren() {
+ const self = this;
+ return react0___default().Children.map(this.props.children, (child) => {
+ if (child) {
+ let activeVal = self.props.active || self.state.active;
+ activeVal = String(activeVal);
+ return react0___default().cloneElement(child, {
+ active: activeVal
+ });
+ }
return null;
- }
- return contact ? REaCt().createElement(ui_contacts.ContactButton, {
- contact,
- className: "message",
- label: REaCt().createElement(utils.zT, null, M.getNameByHandle(contact.u)),
- chatRoom: this.props.message.chatRoom,
- dropdownDisabled: !!this.props.dialog
- }) : null;
+ });
}
- renderMessageActionButtons(buttons) {
- if (!buttons) {
+ render() {
+ if (this.props.active !== true) {
return null;
}
- const cnt = buttons.length;
- if (cnt === 0) {
- return null;
+ const self = this;
+ let child = null;
+ if (this.props.children) {
+ child = JSX_("div", {
+ ref: this.domRef
+ }, self.renderChildren());
+ } else if (this.props.dropdownItemGenerator) {
+ child = this.props.dropdownItemGenerator(this);
}
- return REaCt().createElement("div", {
- className: `right-aligned-msg-buttons ${cnt && cnt > 1 ? `total-${cnt}` : ''}`
- }, buttons);
- }
- render() {
- const {
- message,
- grouped,
- additionalClasses,
- hideActionButtons
- } = this.props;
- if (message.deleted) {
+ if (!child && !this.props.forceShowWhenEmpty) {
+ if (this.props.active !== false) {
+ queueMicrotask(() => {
+ self.onActiveChange(false);
+ });
+ }
return null;
}
- return REaCt().createElement("div", {
- ref: this.domRef,
- "data-id": message.messageId,
+ return JSX_(_utils_jsx1__ .Ay.RenderTo, {
+ element: document.body,
className: `
- ${this.getClassNames ? this.getClassNames() : grouped ? 'grouped' : ''}
- ${additionalClasses}
- ${message.messageId}
- message
+ dropdown
body
- `
- }, this.getAvatar && this.getAvatar(), REaCt().createElement("div", {
- className: "message content-area selectable-txt"
- }, this.getName && this.getName(), this.getMessageTimestamp ? this.getMessageTimestamp() : grouped ? null : REaCt().createElement("div", {
- className: "message date-time simpletip",
- "data-simpletip": time2date(this.getTimestamp(), 17),
- "data-simpletipposition": "top",
- "data-simpletipoffset": "4"
- }, this.getTimestampAsString()), !hideActionButtons && this.getMessageActionButtons && this.renderMessageActionButtons(this.getMessageActionButtons()), this.getContents && this.getContents(), hideActionButtons ? null : this.getEmojisImages()));
+ ${this.props.noArrow ? '' : 'dropdown-arrow up-arrow'}
+ ${this.props.className || ''}
+ `,
+ style: this.popupElement && {
+ zIndex: 123,
+ position: 'absolute',
+ width: this.props.styles ? this.props.styles.width : undefined
+ },
+ popupDidMount: popupElement => {
+ this.popupElement = popupElement;
+ this.onResized();
+ },
+ popupWillUnmount: () => {
+ delete this.popupElement;
+ }
+ }, JSX_("div", {
+ ref: this.domRef,
+ onClick: () => {
+ $(document.body).trigger('closeAllDropdownsExcept', this);
+ }
+ }, this.props.noArrow ? null : JSX_("i", {
+ className: "dropdown-white-arrow"
+ }), child));
}
}
-;// ./js/chat/ui/messages/utils.jsx
-let getMessageString;
-(function () {
- let MESSAGE_STRINGS;
- let MESSAGE_STRINGS_GROUP;
- let MESSAGE_STRINGS_MEETING;
- const _sanitizeStrings = function (arg) {
- if (typeof arg === "undefined") {
- return arg;
- } else if (typeof arg === "string") {
- return escapeHTML(arg);
- } else if (arg.forEach) {
- arg.forEach((v, k) => {
- arg[k] = _sanitizeStrings(v);
- });
- } else if (typeof arg === "object") {
- Object.keys(arg).forEach((k) => {
- arg[k] = _sanitizeStrings(arg[k]);
- });
- }
- return arg;
- };
- getMessageString = function (type, isGroupCall, isMeeting) {
- if (!MESSAGE_STRINGS) {
- MESSAGE_STRINGS = {
- 'outgoing-call': l[5891].replace("[X]", "[[[X]]]"),
- 'incoming-call': l[19964] || "[[%s]] is calling...",
- 'call-timeout': [l[18698].replace("[X]", "[[[X]]]")],
- 'call-starting': l[7206].replace("[X]", "[[[X]]]"),
- 'call-feedback': l[7998].replace("[X]", "[[[X]]]"),
- 'call-initialising': l[7207].replace("[X]", "[[[X]]]"),
- 'call-ended': [l[19965] || "Call ended.", l[7208]],
- 'remoteCallEnded': [l[19965] || "Call ended.", l[7208]],
- 'call-failed-media': l[7204],
- 'call-failed': [l[19966] || "Call failed.", l[7208]],
- 'call-handled-elsewhere': l[5895].replace("[X]", "[[[X]]]"),
- 'call-missed': l[17870],
- 'call-rejected': l[19040],
- 'call-canceled': l[19041],
- 'remoteCallStarted': l[5888],
- 'call-started': l[5888].replace("[X]", "[[[X]]]"),
- 'alterParticipants': undefined,
- 'privilegeChange': undefined,
- 'truncated': l[8905]
- };
- _sanitizeStrings(MESSAGE_STRINGS);
- }
- if (isGroupCall && !MESSAGE_STRINGS_GROUP) {
- MESSAGE_STRINGS_GROUP = {
- 'call-ended': [l[19967], l[7208]],
- 'remoteCallEnded': [l[19967], l[7208]],
- 'call-handled-elsewhere': l[19968],
- 'call-canceled': l[19969],
- 'call-started': l[19970]
- };
- _sanitizeStrings(MESSAGE_STRINGS_GROUP);
- }
- if (isMeeting && !MESSAGE_STRINGS_MEETING) {
- MESSAGE_STRINGS_MEETING = {
- 'call-ended': [l.meeting_mgmt_call_ended, l[7208]],
- 'remoteCallEnded': [l.meeting_mgmt_call_ended, l[7208]],
- 'call-started': l.meeting_mgmt_call_started
- };
- }
- if (isMeeting && MESSAGE_STRINGS_MEETING[type]) {
- return MESSAGE_STRINGS_MEETING[type];
- }
- if (isGroupCall && MESSAGE_STRINGS_GROUP[type]) {
- return MESSAGE_STRINGS_GROUP[type];
- }
- return MESSAGE_STRINGS[type];
- };
-})();
-mega.ui = mega.ui || {};
-mega.ui.chat = mega.ui.chat || {};
-mega.ui.chat.getMessageString = getMessageString;
-
-;// ./js/chat/ui/messages/types/local.jsx
-
-
-
-
-
-const MESSAGE_TYPE = {
- OUTGOING: 'outgoing-call',
- INCOMING: 'incoming-call',
- TIMEOUT: 'call-timeout',
- STARTING: 'call-starting',
- FEEDBACK: 'call-feedback',
- INITIALISING: 'call-initialising',
- ENDED: 'call-ended',
- ENDED_REMOTE: 'remoteCallEnded',
- FAILED: 'call-failed',
- FAILED_MEDIA: 'call-failed-media',
- HANDLED_ELSEWHERE: 'call-handled-elsewhere',
- MISSED: 'call-missed',
- REJECTED: 'call-rejected',
- CANCELLED: 'call-canceled',
- STARTED: 'call-started',
- STARTED_REMOTE: 'remoteCallStarted',
- ALTER_PARTICIPANTS: 'alterParticipants',
- PRIVILEGE_CHANGE: 'privilegeChange',
- TRUNCATED: 'truncated'
+Dropdown.defaultProps = {
+ 'requiresUpdateOnResize': true
};
-class Local extends AbstractGenericMessage {
- componentDidMount() {
- super.componentDidMount();
- this._setClassNames();
- }
- _roomIsGroup() {
- return this.props.message.chatRoom.type === 'group' || this.props.message.chatRoom.type === 'public';
- }
- _getParticipantNames(message) {
- return message.meta && message.meta.participants && !!message.meta.participants.length && message.meta.participants.map(handle => `[[${megaChat.html(M.getNameByHandle(handle))}]]`);
+class DropdownContactsSelector extends _chat_mixins2__ .w9 {
+ constructor(props) {
+ super(props);
+ this.state = {
+ 'selected': this.props.selected ? this.props.selected : []
+ };
+ this.onSelectClicked = this.onSelectClicked.bind(this);
+ this.onSelected = this.onSelected.bind(this);
}
- _getExtraInfo(message) {
- const {
- meta,
- type
- } = message;
- const participantNames = this._getParticipantNames(message);
- const HAS_PARTICIPANTS = participantNames && !!participantNames.length && participantNames.length > 1;
- const HAS_DURATION = meta && meta.duration;
- const ENDED = type === MESSAGE_TYPE.ENDED || type === MESSAGE_TYPE.FAILED || type === MESSAGE_TYPE.CANCELLED;
- let messageExtraInfo = [HAS_PARTICIPANTS ? mega.utils.trans.listToString(participantNames, l[20234]) : ''];
- if (ENDED) {
- messageExtraInfo = [...messageExtraInfo, HAS_PARTICIPANTS ? '. ' : '', HAS_DURATION ? l[7208].replace('[X]', `[[${secToDuration(meta.duration)}]]`) : ''];
+ specShouldComponentUpdate(nextProps, nextState) {
+ if (this.props.active != nextProps.active) {
+ return true;
+ } else if (this.props.focused != nextProps.focused) {
+ return true;
+ } else if (this.state && this.state.active != nextState.active) {
+ return true;
+ } else if (this.state && JSON.stringify(this.state.selected) != JSON.stringify(nextState.selected)) {
+ return true;
+ } else {
+ return undefined;
}
- return messageExtraInfo && messageExtraInfo.reduce((acc, cur) => (acc + cur).replace(/\[\[/g, '').replace(/]]/g, ''));
}
- _setClassNames() {
- let cssClass;
- switch (this.props.message.type) {
- case MESSAGE_TYPE.REJECTED:
- cssClass = 'sprite-fm-theme icon-handset-rejected';
- break;
- case MESSAGE_TYPE.MISSED:
- cssClass = 'sprite-fm-theme icon-handset-missed';
- break;
- case MESSAGE_TYPE.OUTGOING:
- case MESSAGE_TYPE.HANDLED_ELSEWHERE:
- cssClass = 'sprite-fm-theme icon-handset-outgoing';
- break;
- case MESSAGE_TYPE.FAILED:
- case MESSAGE_TYPE.FAILED_MEDIA:
- cssClass = 'sprite-fm-theme icon-handset-failed';
- break;
- case MESSAGE_TYPE.ENDED:
- case MESSAGE_TYPE.TIMEOUT:
- cssClass = 'sprite-fm-theme icon-handset-ended';
- break;
- case MESSAGE_TYPE.CANCELLED:
- cssClass = 'sprite-fm-theme icon-handset-cancelled';
- break;
- case MESSAGE_TYPE.FEEDBACK:
- case MESSAGE_TYPE.STARTING:
- case MESSAGE_TYPE.STARTED:
- cssClass = 'sprite-fm-mono icon-phone';
- break;
- case MESSAGE_TYPE.INCOMING:
- cssClass = 'sprite-fm-theme icon-handset-incoming';
- break;
- default:
- cssClass = `sprite-fm-mono ${ this.props.message.type}`;
- break;
+ onSelected(nodes) {
+ this.setState({
+ 'selected': nodes
+ });
+ if (this.props.onSelected) {
+ this.props.onSelected(nodes);
}
- this.props.message.cssClass = cssClass;
+ this.forceUpdate();
+ }
+ onSelectClicked() {
+ this.props.onSelectClicked();
+ }
+ render() {
+ return JSX_(Dropdown, {
+ className: `
+ popup contacts-search
+ ${this.props.className}
+ tooltip-blur
+ `,
+ active: this.props.active,
+ closeDropdown: this.props.closeDropdown,
+ ref: ref => {
+ this.dropdownRef = ref;
+ },
+ positionMy: this.props.positionMy,
+ positionAt: this.props.positionAt,
+ arrowHeight: this.props.arrowHeight,
+ horizOffset: this.props.horizOffset,
+ vertOffset: this.props.vertOffset,
+ noArrow: true
+ }, JSX_(_chat_ui_contacts_jsx3__ .hU, {
+ onClose: this.props.closeDropdown,
+ onEventuallyUpdated: () => {
+ let _this$dropdownRef;
+ return (_this$dropdownRef = this.dropdownRef) == null ? void 0 : _this$dropdownRef.doRerender();
+ },
+ active: this.props.active,
+ className: "popup contacts-search tooltip-blur small-footer",
+ contacts: M.u,
+ selectFooter: this.props.selectFooter,
+ megaChat: this.props.megaChat,
+ exclude: this.props.exclude,
+ allowEmpty: this.props.allowEmpty,
+ multiple: this.props.multiple,
+ topButtons: this.props.topButtons,
+ showAddContact: this.props.showAddContact,
+ onAddContact: () => eventlog(500237),
+ onSelected: () => eventlog(500238),
+ onSelectDone: this.props.onSelectDone,
+ multipleSelectedButtonLabel: this.props.multipleSelectedButtonLabel,
+ singleSelectedButtonLabel: this.props.singleSelectedButtonLabel,
+ nothingSelectedButtonLabel: this.props.nothingSelectedButtonLabel
+ }));
}
- _getIcon(message) {
- const MESSAGE_ICONS = {
- [MESSAGE_TYPE.STARTED]: ` `,
- [MESSAGE_TYPE.ENDED]: ` `,
- DEFAULT: ` `
+}
+DropdownContactsSelector.defaultProps = {
+ requiresUpdateOnResize: true
+};
+class DropdownItem extends _chat_mixins2__ .w9 {
+ constructor(props) {
+ super(props);
+ this.domRef = react0___default().createRef();
+ this.state = {
+ 'isClicked': false
};
- return MESSAGE_ICONS[message.type] || MESSAGE_ICONS.DEFAULT;
+ this.onClick = this.onClick.bind(this);
+ this.onMouseOver = this.onMouseOver.bind(this);
}
- _getText() {
- const {
- message
- } = this.props;
- const IS_GROUP = this._roomIsGroup();
- let messageText = getMessageString(message.type, IS_GROUP, message.chatRoom.isMeeting);
- if (!messageText) {
- return console.error(`Message with type: ${message.type} -- no text string defined. Message: ${message}`);
- }
- messageText = CallManager2._getMltiStrTxtCntsForMsg(message, messageText.splice ? messageText : [messageText], true);
- messageText = megaChat.html(messageText);
- message.textContents = String(messageText).replace("[[", "").replace("]]", "");
- if (IS_GROUP) {
- messageText = `
- ${this._getIcon(message)}
-
- ${messageText}
- ${this._getExtraInfo(message)}
-
- `;
- }
- return messageText;
- }
- _getAvatarsListing() {
- const {
- message
- } = this.props;
- if (this._roomIsGroup() && message.type === MESSAGE_TYPE.STARTED && message.messageId === `${MESSAGE_TYPE.STARTED}-${message.chatRoom.getActiveCallMessageId()}`) {
- const unique = message.chatRoom.uniqueCallParts ? Object.keys(message.chatRoom.uniqueCallParts) : [];
- return unique.map(handle => REaCt().createElement(ui_contacts.Avatar, {
- key: handle,
- contact: M.u[handle],
- simpletip: true,
- className: "message avatar-wrapper small-rounded-avatar"
- }));
- }
- return null;
+ renderChildren() {
+ const self = this;
+ return react0___default().Children.map(this.props.children, (child) => {
+ const props = {
+ active: self.state.isClicked,
+ closeDropdown () {
+ self.setState({
+ 'isClicked': false
+ });
+ }
+ };
+ return react0___default().cloneElement(child, props);
+ });
}
- _getButtons() {
+ onClick(ev) {
const {
- message
+ children,
+ persistent,
+ onClick
} = this.props;
- if (message.buttons && Object.keys(message.buttons).length) {
- return REaCt().createElement("div", {
- className: "buttons-block"
- }, Object.keys(message.buttons).map(key => {
- const button = message.buttons[key];
- return REaCt().createElement("button", {
- key,
- className: button.classes,
- onClick: e => button.callback(e.target)
- }, button.icon && REaCt().createElement("div", null, REaCt().createElement("i", {
- className: `small-icon ${button.icon}`
- })), REaCt().createElement("span", null, button.text));
- }), REaCt().createElement("div", {
- className: "clear"
- }));
+ if (children) {
+ ev.stopPropagation();
+ ev.preventDefault();
+ this.setState({
+ isClicked: !this.state.isClicked
+ });
}
- }
- getAvatar() {
- const {
- message,
- grouped
- } = this.props;
- if (message.type === MESSAGE_TYPE.FEEDBACK) {
- return null;
+ if (!persistent) {
+ $(document).trigger('closeDropdowns');
}
- const $$AVATAR = REaCt().createElement(ui_contacts.Avatar, {
- contact: message.authorContact,
- className: "message avatar-wrapper small-rounded-avatar",
- chatRoom: message.chatRoom
- });
- const $$ICON = REaCt().createElement("div", {
- className: "feedback call-status-block"
- }, REaCt().createElement("i", {
- className: `sprite-fm-mono ${message.cssClass}`
- }));
- return message.showInitiatorAvatar ? grouped ? null : $$AVATAR : $$ICON
- ;
+ return onClick && onClick(ev);
}
- getMessageTimestamp() {
- let _this$props$message;
- const callId = (_this$props$message = this.props.message) == null || (_this$props$message = _this$props$message.meta) == null ? void 0 : _this$props$message.callId;
- let debugMsg = "";
- if (d && callId) {
- debugMsg = `: callId: ${callId}`;
+ onMouseOver(e) {
+ if (this.props.submenu) {
+ const $contextItem = $(e.target).closest(".contains-submenu");
+ const $subMenu = $contextItem.next('.submenu');
+ const contextTopPos = $contextItem.position().top;
+ let contextleftPos = 0;
+ $contextItem.addClass("opened");
+ $subMenu.addClass("active");
+ contextleftPos = $contextItem.offset().left + $contextItem.outerWidth() + $subMenu.outerWidth() + 10;
+ if (contextleftPos > $(document.body).width()) {
+ $subMenu.addClass("left-position");
+ }
+ $subMenu.css({
+ "top": contextTopPos
+ });
+ } else if (!$(e.target).parent('.submenu').length) {
+ const $dropdown = $(e.target).closest(".dropdown.body");
+ $dropdown.find(".contains-submenu").removeClass("opened");
+ $dropdown.find(".submenu").removeClass("active");
}
- return REaCt().createElement("div", {
- className: "message date-time simpletip",
- "data-simpletip": time2date(this.getTimestamp(), 17)
- }, this.getTimestampAsString(), debugMsg);
- }
- getClassNames() {
- const {
- message: {
- showInitiatorAvatar,
- type
- },
- grouped
- } = this.props;
- const classNames = [showInitiatorAvatar && grouped && 'grouped', this._roomIsGroup() && type !== MESSAGE_TYPE.OUTGOING && type !== MESSAGE_TYPE.INCOMING && 'with-border'];
- return classNames.filter(className => className).join(' ');
- }
- getName() {
- const {
- message,
- grouped
- } = this.props;
- const contact = this.getContact();
- return message.showInitiatorAvatar && !grouped ? REaCt().createElement(ui_contacts.ContactButton, {
- contact,
- className: "message",
- label: REaCt().createElement(utils.zT, null, message.authorContact ? M.getNameByHandle(message.authorContact.u) : ''),
- chatRoom: message.chatRoom
- }) : M.getNameByHandle(contact.u);
}
- getContents() {
+ render() {
const {
- message: {
- getState
- }
+ className,
+ disabled,
+ label,
+ icon,
+ submenu
} = this.props;
- return REaCt().createElement(REaCt().Fragment, null, REaCt().createElement("div", {
- className: "message text-block"
- }, REaCt().createElement("div", {
- className: "message call-inner-block"
- }, REaCt().createElement("div", {
- className: "call-info"
- }, REaCt().createElement("div", {
- className: "call-info-container"
- }, REaCt().createElement(utils.P9, {
- className: "info-wrapper"
- }, this._getText())), REaCt().createElement("div", {
- className: "call-info-avatars"
- }, this._getAvatarsListing(), REaCt().createElement("div", {
- className: "clear"
- }))))), getState && getState() === Message.STATE.NOT_SENT ? null : this._getButtons());
+ return JSX_("div", {
+ ref: this.domRef,
+ className: `
+ dropdown-item
+ ${className ? className : ''}
+ ${submenu ? 'contains-submenu' : ''}
+ ${disabled ? 'disabled' : ''}
+ `,
+ onClick: disabled ? undefined : ev => this.onClick(ev),
+ onMouseOver: this.onMouseOver
+ }, icon && JSX_("i", {
+ className: icon
+ }), label && JSX_("span", null, label), submenu ? JSX_("i", {
+ className: "sprite-fm-mono icon-arrow-right submenu-icon"
+ }) : '', JSX_("div", null, this.renderChildren()));
}
}
-// EXTERNAL MODULE: ./js/ui/dropdowns.jsx
-const dropdowns = REQ_(911);
-// EXTERNAL MODULE: ./js/ui/buttons.jsx
-const buttons = REQ_(994);
-;// ./js/chat/ui/messages/types/contact.jsx
+DropdownItem.defaultProps = {
+ requiresUpdateOnResize: true
+};
+ },
+ 1165
+(_, EXP_, REQ_) {
+"use strict";
+ REQ_.d(EXP_, {
+ A: () => DropdownEmojiSelector
+ });
+ const _babel_runtime_helpers_extends0__ = REQ_(8168);
+ const react1__ = REQ_(1594);
+ const react1___default = REQ_.n(react1__);
+ const _chat_mixins_js2__ = REQ_(8264);
+ const _dropdowns_jsx3__ = REQ_(1510);
+ const _perfectScrollbar_jsx4__ = REQ_(1301);
-class Contact extends AbstractGenericMessage {
- constructor(...args) {
- super(...args);
- this.DIALOG = {
- ADDED: addedEmail => msgDialog('info', l[150], l[5898].replace('[X]', addedEmail)),
- DUPLICATE: () => msgDialog('warningb', '', l[17545])
+
+
+class DropdownEmojiSelector extends _chat_mixins_js2__ .w9 {
+ constructor(props) {
+ super(props);
+ this.domRef = react1___default().createRef();
+ this.emojiSearchRef = react1___default().createRef();
+ this.data_categories = null;
+ this.data_emojis = null;
+ this.data_emojiByCategory = null;
+ this.customCategoriesOrder = ["frequently_used", "people", "nature", "food", "activity", "travel", "objects", "symbols", "flags"];
+ this.frequentlyUsedEmojis = ['slight_smile', 'grinning', 'smile', 'rofl', 'wink', 'yum', 'rolling_eyes', 'stuck_out_tongue', 'smiling_face_with_3_hearts', 'heart_eyes', 'kissing_heart', 'sob', 'pleading_face', 'thumbsup', 'pray', 'wave', 'fire', 'sparkles'];
+ this.heightDefs = {
+ 'categoryTitleHeight': 55,
+ 'emojiRowHeight': 35,
+ 'containerHeight': 302,
+ 'totalScrollHeight': 302,
+ 'numberOfEmojisPerRow': 9
};
+ this.categoryLabels = {
+ 'frequently_used': l[17737],
+ 'people': l[8016],
+ 'objects': l[17735],
+ 'activity': l[8020],
+ 'nature': l[8017],
+ 'travel': l[8021],
+ 'symbols': l[17736],
+ 'food': l[8018],
+ 'flags': l[17703]
+ };
+ this.state = this.getInitialState();
+ this.onSearchChange = this.onSearchChange.bind(this);
+ this.onUserScroll = this.onUserScroll.bind(this);
+ this._onScrollChanged = this._onScrollChanged.bind(this);
}
- haveMoreContactListeners() {
- const {
- message
- } = this.props;
- const textContents = message.textContents.substring(2, message.textContents.length);
- const attachmentMeta = JSON.parse(textContents);
- if (!attachmentMeta) {
- return false;
- }
- const contacts = attachmentMeta.map(v => v.u);
- return contacts.length ? contacts : false;
- }
- _doAddContact(contactEmail) {
- return M.inviteContact(M.u[u_handle] ? M.u[u_handle].m : u_attr.email, contactEmail);
- }
- _handleAddContact(contactEmail) {
- let _this$props$chatRoom;
- if ((_this$props$chatRoom = this.props.chatRoom) != null && _this$props$chatRoom.isAnonymous()) {
- return this._doAddContact(contactEmail).then(addedEmail => this.DIALOG.ADDED(addedEmail)).catch(this.DIALOG.DUPLICATE);
- }
- return Object.values(M.opc).some(opc => opc.m === contactEmail) ? this.DIALOG.DUPLICATE() : this._doAddContact(contactEmail).then(addedEmail => this.DIALOG.ADDED(addedEmail))
- ;
- }
- _getContactAvatar(contact, className) {
- return REaCt().createElement(ui_contacts.Avatar, {
- className: `avatar-wrapper ${className}`,
- contact: M.u[contact.u],
- chatRoom: this.props.chatRoom
+ getInitialState() {
+ return clone({
+ 'previewEmoji': null,
+ 'searchValue': '',
+ 'browsingCategory': false,
+ 'isActive': false,
+ 'isLoading': true,
+ 'loadFailed': false,
+ 'visibleCategories': "0"
});
}
- _getContactDeleteButton(message) {
- if (message.isEditable()) {
- return REaCt().createElement(REaCt().Fragment, null, REaCt().createElement("hr", null), REaCt().createElement(dropdowns.DropdownItem, {
- icon: "sprite-fm-mono icon-dialog-close",
- label: l[83],
- onClick: e => this.props.onDelete(e, message)
- }));
- }
- }
- _getContactCard(message, contact, contactEmail) {
- const HAS_RELATIONSHIP = M.u[contact.u].c === 1;
- let name = REaCt().createElement(ui_contacts.ContactAwareName, {
- emoji: true,
- contact: M.u[contact.u]
- });
- const {
- chatRoom
- } = this.props;
- const isAnonView = chatRoom.isAnonymous();
- if (megaChat.FORCE_EMAIL_LOADING) {
- name += `(${ contact.m })`;
- }
- return REaCt().createElement(buttons.$, {
- ref: ref => {
- this.buttonRef = ref;
+ _generateEmoji(meta) {
+ const filename = twemoji.convert.toCodePoint(meta.u);
+ return JSX_("img", {
+ width: "20",
+ height: "20",
+ className: "emoji emoji-loading",
+ draggable: "false",
+ alt: meta.u,
+ title: `:${ meta.n }:`,
+ onLoad: e => {
+ e.target.classList.remove('emoji-loading');
},
- className: "tiny-button",
- icon: "tiny-icon icons-sprite grey-dots"
- }, REaCt().createElement(dropdowns.Dropdown, {
- className: "white-context-menu shared-contact-dropdown",
- noArrow: true,
- positionMy: "left bottom",
- positionAt: "right bottom",
- horizOffset: 4
- }, REaCt().createElement("div", {
- className: "dropdown-avatar rounded"
- }, this._getContactAvatar(contact, 'context-avatar'), isAnonView ? REaCt().createElement("div", {
- className: "dropdown-user-name"
- }) : REaCt().createElement("div", {
- className: "dropdown-user-name"
- }, REaCt().createElement("div", {
- className: "name"
- }, HAS_RELATIONSHIP && (this.isLoadingContactInfo() ? REaCt().createElement("em", {
- className: "contact-name-loading"
- }) : name), !HAS_RELATIONSHIP && name, REaCt().createElement(ui_contacts.ContactPresence, {
- className: "small",
- contact
- })), REaCt().createElement("div", {
- className: "email"
- }, M.u[contact.u].m))), REaCt().createElement(ui_contacts.ContactFingerprint, {
- contact: M.u[contact.u]
- }), HAS_RELATIONSHIP && REaCt().createElement(REaCt().Fragment, null, REaCt().createElement(dropdowns.DropdownItem, {
- icon: "sprite-fm-mono icon-user-filled",
- label: l[5868],
- onClick: () => {
- loadSubPage(`fm/chat/contacts/${ contact.u}`);
- mBroadcaster.sendMessage('contact:open');
- }
- }), REaCt().createElement("hr", null), REaCt().createElement(dropdowns.DropdownItem, {
- icon: "sprite-fm-mono icon-chat-filled",
- label: l[8632],
- onClick: () => {
- loadSubPage(`fm/chat/p/${ contact.u}`);
- mBroadcaster.sendMessage('chat:open');
- }
- })), u_type && u_type > 2 && contact.u !== u_handle && !HAS_RELATIONSHIP && !is_eplusplus && REaCt().createElement(dropdowns.DropdownItem, {
- icon: "sprite-fm-mono icon-add",
- label: l[71],
- onClick: () => this._handleAddContact(contactEmail)
- }), this._getContactDeleteButton(message)));
- }
- getContents() {
- const {
- message,
- chatRoom
- } = this.props;
- const textContents = message.textContents.substr(2, message.textContents.length);
- const attachmentMeta = JSON.parse(textContents);
- const isAnonView = chatRoom.isAnonymous();
- if (!attachmentMeta) {
- return console.error(`Message w/ type: ${message.type} -- no attachment meta defined. Message: ${message}`);
- }
- let contacts = [];
- attachmentMeta.forEach(v => {
- let _this$buttonRef;
- const contact = M.u && v.u in M.u && M.u[v.u].m ? M.u[v.u] : v;
- const contactEmail = contact.email ? contact.email : contact.m;
- if (!M.u[contact.u]) {
- M.u.set(contact.u, new MegaDataObject(MEGA_USER_STRUCT, {
- 'u': contact.u,
- 'name': contact.name,
- 'm': contact.email ? contact.email : contactEmail,
- 'c': undefined
- }));
- } else if (M.u[contact.u] && !M.u[contact.u].m) {
- M.u[contact.u].m = contact.email ? contact.email : contactEmail;
- }
- contacts = [...contacts, REaCt().createElement("div", {
- key: contact.u
- }, isAnonView ? REaCt().createElement("div", {
- className: "message shared-info"
- }) : REaCt().createElement("div", {
- className: "message shared-info"
- }, REaCt().createElement("div", {
- className: "message data-title selectable-txt",
- onClick: (_this$buttonRef = this.buttonRef) == null ? void 0 : _this$buttonRef.onClick
- }, REaCt().createElement(utils.zT, null, M.getNameByHandle(contact.u))), M.u[contact.u] ? REaCt().createElement(ui_contacts.ContactVerified, {
- className: "right-align",
- contact: M.u[contact.u]
- }) : null, REaCt().createElement("div", {
- className: "user-card-email selectable-txt"
- }, contactEmail)), REaCt().createElement("div", {
- className: "message shared-data"
- }, REaCt().createElement("div", {
- className: "data-block-view semi-big"
- }, M.u[contact.u] ? REaCt().createElement(ui_contacts.ContactPresence, {
- className: "small",
- contact: M.u[contact.u]
- }) : null, this._getContactCard(message, contact, contactEmail), this._getContactAvatar(contact, 'medium-avatar')), REaCt().createElement("div", {
- className: "clear"
- })))];
+ onError: e => {
+ e.target.classList.remove('emoji-loading');
+ e.target.classList.add('emoji-loading-error');
+ },
+ src: `${staticpath }images/mega/twemojis/2_v2/72x72/${ filename }.png`
});
- return REaCt().createElement("div", {
- className: "message shared-block"
- }, contacts);
- }
-}
-;// ./js/chat/ui/messages/types/attachment.jsx
-
-
-
-
-class Attachment extends AbstractGenericMessage {
- _isRevoked(node) {
- return !M.chd[node.ch] || node.revoked;
- }
- _isUserRegistered() {
- return typeof u_type !== 'undefined' && u_type > 2;
}
- getContents() {
- const {
- message,
- chatRoom
- } = this.props;
- const contact = this.getContact();
- const NODE_DOESNT_EXISTS_ANYMORE = {};
- const attachmentMeta = message.getAttachmentMeta() || [];
- const files = [];
- for (let i = 0; i < attachmentMeta.length; i++) {
- var _this$buttonRef;
- const v = attachmentMeta[i];
- if (this._isRevoked(v)) {
- continue;
- }
- const {
- icon,
- isImage,
- isVideo,
- isAudio,
- isText,
- showThumbnail,
- isPreviewable
- } = M.getMediaProperties(v);
- let dropdown = null;
- let noThumbPrev = '';
- var previewButton = null;
- if (isPreviewable) {
- if (!showThumbnail) {
- noThumbPrev = 'no-thumb-prev';
- }
- let previewLabel = isAudio ? l[17828] : isVideo ? l[16275] : l[1899];
- let previewIcon = isAudio ? 'icon-play' : isVideo ? 'icon-video-call-filled' : 'icon-preview-reveal';
- if (isText) {
- previewLabel = l[16797];
- previewIcon = "icon-file-edit";
+ _generateEmojiElement(emoji, cat) {
+ const self = this;
+ const categoryName = self.data_categories[cat];
+ return JSX_("div", {
+ "data-emoji": emoji.n,
+ className: "button square-button emoji",
+ key: `${categoryName }_${ emoji.n}`,
+ onMouseEnter: e => {
+ if (self.mouseEnterTimer) {
+ clearTimeout(self.mouseEnterTimer);
}
- previewButton = REaCt().createElement("span", {
- key: "previewButton"
- }, REaCt().createElement(dropdowns.DropdownItem, {
- label: previewLabel,
- icon: `sprite-fm-mono ${previewIcon}`,
- disabled: mega.paywall,
- onClick: e => {
- mega.ui.mInfoPanel.hide();
- this.props.onPreviewStart(v, e);
- }
- }));
- }
- dropdown = contact.u === u_handle ? REaCt().createElement(buttons.$, {
- ref: ref => {
- this.buttonRef = ref;
- },
- className: "tiny-button",
- icon: "tiny-icon icons-sprite grey-dots"
- }, REaCt().createElement(dropdowns.Dropdown, {
- className: "white-context-menu attachments-dropdown",
- noArrow: true,
- positionMy: "left top",
- positionAt: "left bottom",
- horizOffset: -4,
- vertOffset: 3,
- onBeforeActiveChange: newState => {
- if (newState === true) {
- this.forceUpdate();
- }
- },
- dropdownItemGenerator: dd => {
- const linkButtons = [];
- const firstGroupOfButtons = [];
- let revokeButton = null;
- let downloadButton = null;
- let addToAlbumButton = null;
- if (message.isEditable && message.isEditable()) {
- revokeButton = REaCt().createElement(dropdowns.DropdownItem, {
- icon: "sprite-fm-mono icon-dialog-close",
- label: l[83],
- onClick: () => {
- chatRoom.megaChat.plugins.chatdIntegration.updateMessage(chatRoom, message.internalId || message.orderValue, "");
- }
- });
- }
- if (!M.d[v.h] && !NODE_DOESNT_EXISTS_ANYMORE[v.h]) {
- dbfetch.acquire(v.h).always(() => {
- if (!M.d[v.h]) {
- NODE_DOESNT_EXISTS_ANYMORE[v.h] = true;
- dd.doRerender();
- } else {
- dd.doRerender();
- }
- });
- return REaCt().createElement("span", {
- className: "loading"
- }, l[5533]);
- } else if (!NODE_DOESNT_EXISTS_ANYMORE[v.h]) {
- downloadButton = REaCt().createElement(dropdowns.DropdownItem, {
- icon: "sprite-fm-mono icon-download-small",
- label: l[1187],
- disabled: mega.paywall,
- onClick: () => this.props.onDownloadStart(v)
- });
- if (M.getNodeRoot(v.h) !== M.RubbishID) {
- this.props.onAddLinkButtons(v.h, linkButtons);
- }
- firstGroupOfButtons.push(REaCt().createElement(dropdowns.DropdownItem, {
- icon: "sprite-fm-mono icon-info",
- label: l[6859],
- key: "infoDialog",
- onClick: () => {
- mega.ui.mInfoPanel.show([v.ch]);
- }
- }));
- this.props.onAddFavouriteButtons(v.h, firstGroupOfButtons);
- linkButtons.push(REaCt().createElement(dropdowns.DropdownItem, {
- icon: "sprite-fm-mono icon-send-to-chat",
- label: l[17764],
- key: "sendToChat",
- disabled: mega.paywall,
- onClick: () => {
- $.selected = [v.h];
- openSendToChatDialog();
- }
- }));
- if (M.isGalleryNode(v)) {
- addToAlbumButton = REaCt().createElement(dropdowns.DropdownItem, {
- icon: "sprite-fm-mono rectangle-stack-plus-small-regular-outline",
- label: l.add_to_album,
- disabled: mega.paywall,
- onClick: () => mega.gallery.albums.addToAlbum([v.h])
- });
- }
- }
- if (!previewButton && firstGroupOfButtons.length === 0 && !downloadButton && !addToAlbumButton && linkButtons.length === 0 && !revokeButton) {
- return null;
- }
- if (previewButton && (firstGroupOfButtons.length > 0 || downloadButton || addToAlbumButton || linkButtons.length > 0 || revokeButton)) {
- previewButton = [previewButton, REaCt().createElement("hr", {
- key: "preview-sep"
- })];
- }
- return REaCt().createElement("div", null, previewButton, firstGroupOfButtons, firstGroupOfButtons && firstGroupOfButtons.length > 0 ? REaCt().createElement("hr", null) : "", addToAlbumButton, addToAlbumButton ? REaCt().createElement("hr", null) : "", downloadButton, linkButtons, revokeButton && downloadButton ? REaCt().createElement("hr", null) : "", revokeButton);
+ e.stopPropagation();
+ e.preventDefault();
+ self.mouseEnterTimer = setTimeout(() => {
+ self.setState({
+ 'previewEmoji': emoji
+ });
+ }, 250);
+ },
+ onMouseLeave: e => {
+ if (self.mouseEnterTimer) {
+ clearTimeout(self.mouseEnterTimer);
}
- })) : REaCt().createElement(buttons.$, {
- ref: ref => {
- this.buttonRef = ref;
- },
- className: "tiny-button",
- icon: "tiny-icon icons-sprite grey-dots"
- }, REaCt().createElement(dropdowns.Dropdown, {
- className: "white-context-menu attachments-dropdown",
- noArrow: true,
- positionMy: "left top",
- positionAt: "left bottom",
- horizOffset: -4,
- vertOffset: 3
- }, previewButton, previewButton && REaCt().createElement("hr", null), REaCt().createElement(dropdowns.DropdownItem, {
- icon: "sprite-fm-mono icon-download-small",
- label: l[1187],
- disabled: mega.paywall,
- onClick: () => this.props.onDownloadStart(v)
- }), !is_chatlink && this._isUserRegistered() && REaCt().createElement(REaCt().Fragment, null, REaCt().createElement(dropdowns.DropdownItem, {
- icon: "sprite-fm-mono icon-cloud",
- label: l[1988],
- disabled: mega.paywall,
- onClick: () => this.props.onAddToCloudDrive(v, false)
- }), REaCt().createElement(dropdowns.DropdownItem, {
- icon: "sprite-fm-mono icon-send-to-chat",
- label: l[17764],
- disabled: mega.paywall,
- onClick: () => this.props.onAddToCloudDrive(v, true)
- }))));
- if (M.getNodeShare(v.h).down) {
- dropdown = null;
- }
- const attachmentClasses = "message shared-data";
- let preview = REaCt().createElement("div", {
- className: `data-block-view medium ${ noThumbPrev}`,
- onClick: ({
- target
- }) => {
- if (isPreviewable && !target.classList.contains('tiny-button')) {
- mega.ui.mInfoPanel.hide();
- this.props.onPreviewStart(v);
- }
+ e.stopPropagation();
+ e.preventDefault();
+ self.setState({
+ 'previewEmoji': null
+ });
+ },
+ onClick: e => {
+ if (self.props.onClick) {
+ self.props.onClick(e, emoji.n, emoji);
+ $(document).trigger('closeDropdowns');
}
- }, dropdown, REaCt().createElement("div", {
- className: "data-block-bg"
- }, REaCt().createElement("div", {
- className: `item-type-icon-90 icon-${ icon }-90`
- })));
- if (showThumbnail) {
- const src = v.src || window.noThumbURI || '';
- let thumbClass = v.src ? '' : " no-thumb";
- let thumbOverlay = null;
- if (isImage) {
- thumbClass += " image";
- thumbOverlay = REaCt().createElement("div", {
- className: "thumb-overlay",
- onClick: () => {
- mega.ui.mInfoPanel.hide();
- this.props.onPreviewStart(v);
- }
+ }
+ }, self._generateEmoji(emoji));
+ }
+ UNSAFE_componentWillUpdate(nextProps, nextState) {
+ if (nextState.searchValue !== this.state.searchValue || nextState.browsingCategories !== this.state.browsingCategories) {
+ this._cachedNodes = {};
+ if (this.scrollableArea) {
+ this.scrollableArea.scrollToY(0);
+ }
+ this._onScrollChanged(0, nextState);
+ }
+ if (nextState.isActive === true) {
+ const self = this;
+ if (nextState.isLoading === true || !self.loadingPromise && (!self.data_categories || !self.data_emojis)) {
+ const p = [megaChat.getEmojiDataSet('categories'), megaChat.getEmojiDataSet('emojis')];
+ this.loadingPromise = Promise.all(p).then(([categories, emojis]) => {
+ this.data_emojis = emojis;
+ this.data_categories = categories;
+ self.data_categories.push('frequently_used');
+ self.data_categoriesWithCustomOrder = [];
+ self.customCategoriesOrder.forEach((catName) => {
+ self.data_categoriesWithCustomOrder.push(self.data_categories.indexOf(catName));
});
- } else {
- thumbClass = `${thumbClass } video ${ isPreviewable ? " previewable" : "non-previewable"}`;
- thumbOverlay = REaCt().createElement("div", {
- className: "thumb-overlay",
- onClick: () => {
- if (isPreviewable) {
- mega.ui.mInfoPanel.hide();
- this.props.onPreviewStart(v);
- }
+ self.data_emojiByCategory = {};
+ const frequentlyUsedEmojisMeta = {};
+ self.data_emojis.forEach((emoji) => {
+ const cat = emoji.c;
+ if (!self.data_emojiByCategory[cat]) {
+ self.data_emojiByCategory[cat] = [];
}
- }, isPreviewable && REaCt().createElement("div", {
- className: "thumb-overlay-play"
- }, REaCt().createElement("div", {
- className: "thumb-overlay-circle"
- }, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-play"
- }))), REaCt().createElement("div", {
- className: "video-thumb-details"
- }, v.playtime && REaCt().createElement("i", {
- className: "sprite-fm-mono icon-play"
- }), REaCt().createElement("span", null, secondsToTimeShort(v.playtime || -1))));
- }
- preview = src ? REaCt().createElement("div", {
- id: v.ch,
- className: `shared-link thumb ${thumbClass}`
- }, thumbOverlay, dropdown, REaCt().createElement("img", {
- alt: "",
- className: `thumbnail-placeholder ${ v.h}`,
- src,
- key: `thumb-${ v.ch}`,
- onClick: () => isPreviewable && this.props.onPreviewStart(v)
- })) : preview;
- }
- files.push(REaCt().createElement("div", {
- key: `attachment-${v.ch}`,
- className: attachmentClasses
- }, REaCt().createElement("div", {
- className: "message shared-info",
- onClick: (_this$buttonRef = this.buttonRef) == null ? void 0 : _this$buttonRef.onClick
- }, REaCt().createElement("div", {
- className: "message data-title selectable-txt"
- }, l[17669], REaCt().createElement("span", {
- className: "file-name"
- }, v.name)), REaCt().createElement("div", {
- className: "message file-size"
- }, bytesToSize(v.s))), preview, REaCt().createElement("div", {
- className: "clear"
- })));
- }
- return REaCt().createElement("div", {
- className: "message shared-block"
- }, files);
- }
-}
-// EXTERNAL MODULE: ./js/chat/mixins.js
-const mixins = REQ_(137);
-;// ./js/chat/ui/messages/types/partials/audioPlayer.jsx
-
-
-class AudioPlayer extends mixins.w9 {
- constructor(props) {
- super(props);
- this.domRef = REaCt().createRef();
- this.state = {
- currentTime: null,
- progressWidth: 0,
- isBeingPlayed: false,
- isPaused: false
- };
- this.handleOnTimeUpdate = this.handleOnTimeUpdate.bind(this);
- this.handleOnMouseDown = this.handleOnMouseDown.bind(this);
- }
- play() {
- const audio = this.audioEl;
- if (audio.paused) {
- const result = audio.play();
- if (result instanceof Promise) {
- result.catch(ex => {
- if (ex.name !== 'AbortError') {
- console.error(ex);
+ if (self.frequentlyUsedEmojis.indexOf(emoji.n) > -1) {
+ frequentlyUsedEmojisMeta[emoji.n] = emoji.u;
+ }
+ emoji.element = self._generateEmojiElement(emoji, cat);
+ self.data_emojiByCategory[cat].push(emoji);
+ });
+ self.data_emojiByCategory[8] = [];
+ self.frequentlyUsedEmojis.forEach((slug) => {
+ const emoji = {
+ 'n': slug,
+ 'u': frequentlyUsedEmojisMeta[slug]
+ };
+ emoji.element = self._generateEmojiElement(emoji, 99);
+ self.data_emojiByCategory[8].push(emoji);
+ });
+ self._onScrollChanged(0);
+ self.setState({
+ 'isLoading': false
+ });
+ }).catch(ex => {
+ if (d) {
+ console.error("Emoji loading failed.", ex);
}
+ this.setState({
+ 'loadFailed': true,
+ 'isLoading': false
+ });
});
}
- const audios = document.getElementsByClassName('audio-player__player');
- Array.prototype.filter.call(audios, audioElement => audioElement.id !== this.props.audioId).forEach(audioElement => {
- if (!audioElement.paused) {
- audioElement.pause();
+ } else if (nextState.isActive === false) {
+ if (this.data_emojis) {
+ for (let i = this.data_emojis.length; i--;) {
+ delete this.data_emojis[i].element;
}
- });
- this.setState({
- isPaused: false
- });
- } else {
- audio.pause();
- this.setState({
- isPaused: true
- });
+ }
+ this.data_emojis = null;
+ this.data_categories = null;
+ this.data_emojiByCategory = null;
+ this.loadingPromise = null;
}
}
- handleOnTimeUpdate() {
- const {
- currentTime,
- duration
- } = this.audioEl;
- this.setState({
- currentTime: secondsToTimeShort(currentTime),
- progressWidth: currentTime / duration * 100
+ onSearchChange(e) {
+ const self = this;
+ self.setState({
+ searchValue: e.target.value,
+ browsingCategory: false
});
}
- handleOnMouseDown(event) {
- event.preventDefault();
- const {
- sliderPin,
- slider
- } = this;
- const shiftX = event.clientX - sliderPin.getBoundingClientRect().left;
- const onMouseMove = event => {
- let newLeft = event.clientX - shiftX - slider.getBoundingClientRect().left;
- if (newLeft < 0) {
- newLeft = 0;
- }
- const rightEdge = slider.offsetWidth - sliderPin.offsetWidth;
- if (newLeft > rightEdge) {
- newLeft = rightEdge;
- }
- sliderPin.style.left = `${newLeft}px`;
- const pinPosition = newLeft / slider.getBoundingClientRect().width;
- const newTime = Math.ceil(this.props.playtime * pinPosition);
- const newCurrentTime = secondsToTimeShort(newTime);
- this.audioEl.currentTime = newTime;
- this.setState({
- currentTime: newCurrentTime,
- progressWidth: pinPosition > 1 ? 100 : pinPosition * 100
- });
- };
- function onMouseUp() {
- document.removeEventListener('mouseup', onMouseUp);
- document.removeEventListener('mousemove', onMouseMove);
+ onUserScroll($ps) {
+ if (this.state.browsingCategory) {
+ const $cat = $(`.emoji-category-container[data-category-name="${ this.state.browsingCategory }"]`);
+ if (!elementInViewport($cat)) {
+ this.setState({
+ 'browsingCategory': false
+ });
+ }
}
- document.addEventListener('mousemove', onMouseMove);
- document.addEventListener('mouseup', onMouseUp);
- sliderPin.ondragstart = () => false;
+ this._onScrollChanged($ps.getScrollPositionY());
}
- render() {
- const {
- source,
- audioId,
- loading,
- playtime
- } = this.props;
- const {
- progressWidth,
- isBeingPlayed,
- isPaused,
- currentTime
- } = this.state;
- let playtimeStyles = null;
- if (isBeingPlayed) {
- playtimeStyles = {
- color: 'var(--secondary-red)'
- };
+ generateEmojiElementsByCategory(categoryId, posTop, stateObj) {
+ const self = this;
+ if (!self._cachedNodes) {
+ self._cachedNodes = {};
}
- let btnClass = 'icon-pause';
- if (!isBeingPlayed || isPaused) {
- btnClass = 'icon-play';
+ if (!stateObj) {
+ stateObj = self.state;
}
- let controls = REaCt().createElement("span", {
- onClick: () => {
- this.play();
- if (this.props.source === null) {
- this.props.getAudioFile();
- }
- }
- }, REaCt().createElement("i", {
- className: `sprite-fm-mono ${btnClass}`
- }));
- if (loading) {
- controls = REaCt().createElement("div", {
- className: "small-blue-spinner audio-player__spinner"
- });
+ if (typeof self._cachedNodes[categoryId] !== 'undefined') {
+ return self._cachedNodes[categoryId];
}
- return REaCt().createElement("div", {
- ref: this.domRef,
- className: "audio-player"
- }, controls, REaCt().createElement("div", {
- className: "slider",
- ref: slider => {
- this.slider = slider;
- }
- }, REaCt().createElement("div", {
- className: "slider__progress",
- style: {
- width: `${progressWidth}%`
+ const categoryName = self.data_categories[categoryId];
+ const emojis = [];
+ const {searchValue} = stateObj;
+ let totalEmojis = 0;
+ self.data_emojiByCategory[categoryId].forEach((meta) => {
+ const slug = meta.n;
+ if (searchValue.length > 0) {
+ if (`:${ slug }:`.toLowerCase().indexOf(searchValue.toLowerCase()) < 0) {
+ return;
+ }
}
- }), REaCt().createElement("div", {
- className: "slider__progress__pin",
- style: {
- left: `${progressWidth}%`
- },
- ref: sliderPin => {
- this.sliderPin = sliderPin;
- },
- onMouseDown: this.handleOnMouseDown
- })), REaCt().createElement("span", {
- className: "audio-player__time",
- style: playtimeStyles
- }, currentTime || secondsToTimeShort(playtime)), REaCt().createElement("audio", {
- src: source,
- className: "audio-player__player",
- id: audioId,
- ref: audio => {
- this.audioEl = audio;
- },
- onPlaying: () => this.setState({
- isBeingPlayed: true
- }),
- onPause: () => this.setState({
- isPaused: true
- }),
- onEnded: () => this.setState({
- progressWidth: 0,
- isBeingPlayed: false,
- currentTime: 0
- }),
- onTimeUpdate: this.handleOnTimeUpdate
- }));
- }
-}
-;// ./js/chat/ui/messages/types/partials/audioContainer.jsx
-
-
-class AudioContainer extends REaCt().Component {
- constructor(props) {
- super(props);
- this.state = {
- audioBlobUrl: null,
- loading: false
- };
- this.getAudioFile = this.getAudioFile.bind(this);
- }
- getAudioFile() {
- const {
- mime,
- h
- } = this.props;
- this.setState({
- loading: true
+ totalEmojis++;
+ emojis.push(meta.element);
});
- if (mime !== 'audio/mp4') {
- if (d) {
- console.warn('cannot play this file type (%s)', mime, h, [this]);
- }
- return false;
+ if (emojis.length > 0) {
+ const totalHeight = self.heightDefs.categoryTitleHeight + Math.ceil(totalEmojis / self.heightDefs.numberOfEmojisPerRow) * self.heightDefs.emojiRowHeight;
+ return self._cachedNodes[categoryId] = [totalHeight, JSX_("div", {
+ key: categoryName,
+ "data-category-name": categoryName,
+ className: "emoji-category-container",
+ style: {
+ 'position': 'absolute',
+ 'top': posTop
+ }
+ }, emojis.length > 0 ? JSX_("div", {
+ className: "clear"
+ }) : null, JSX_("div", {
+ className: "emoji-type-txt"
+ }, self.categoryLabels[categoryName] ? self.categoryLabels[categoryName] : categoryName), JSX_("div", {
+ className: "clear"
+ }), emojis, JSX_("div", {
+ className: "clear"
+ }))];
+ } else {
+ return self._cachedNodes[categoryId] = undefined;
}
- M.gfsfetch(h, 0, -1).then(({
- buffer
- }) => {
- this.setState(() => {
- return {
- audioBlobUrl: mObjectURL([buffer], 'audio/mp4'),
- loading: false
- };
- });
- }).catch(ex => {
- console.error(ex);
- });
- return true;
- }
- componentWillUnmount() {
- URL.revokeObjectURL(this.state.audioBlobUrl);
}
- render() {
- const {
- audioBlobUrl,
- loading
- } = this.state;
- const {
- playtime,
- mime,
- audioId
- } = this.props;
- return REaCt().createElement("div", {
- className: "audio-container"
- }, REaCt().createElement(AudioPlayer, {
- source: audioBlobUrl,
- audioId,
- loading,
- mime,
- getAudioFile: this.getAudioFile,
- playtime
- }));
+ _isVisible(scrollTop, scrollBottom, elTop, elBottom) {
+ const visibleTop = elTop < scrollTop ? scrollTop : elTop;
+ const visibleBottom = elBottom > scrollBottom ? scrollBottom : elBottom;
+ return visibleBottom - visibleTop > 0;
}
-}
-AudioContainer.defaultProps = {
- h: null,
- mime: null
-};
-;// ./js/chat/ui/messages/types/voiceClip.jsx
-
-
-
-
-
-class VoiceClip extends AbstractGenericMessage {
- _getActionButtons() {
- const {
- isBeingEdited,
- chatRoom,
- message,
- dialog,
- onDelete
- } = this.props;
- if (message.isEditable() && !isBeingEdited() && !chatRoom.isReadOnly() && !dialog) {
- return REaCt().createElement(buttons.$, {
- className: "tiny-button",
- icon: "tiny-icon icons-sprite grey-dots"
- }, REaCt().createElement(dropdowns.Dropdown, {
- className: "white-context-menu attachments-dropdown",
- noArrow: true,
- positionMy: "left bottom",
- positionAt: "right bottom",
- horizOffset: 4
- }, REaCt().createElement(dropdowns.DropdownItem, {
- icon: "sprite-fm-mono icon-dialog-close",
- label: l[1730],
- onClick: ev => onDelete(ev, message)
- })));
+ _onScrollChanged(scrollPositionY, stateObj) {
+ const self = this;
+ if (!self.data_categoriesWithCustomOrder) {
+ return;
}
- return null;
- }
- _getAudioContainer() {
- const {
- message
- } = this.props;
- const attachmentMeta = message.getAttachmentMeta();
- if (attachmentMeta && attachmentMeta.length) {
- return attachmentMeta.map(voiceClip => REaCt().createElement(AudioContainer, {
- key: voiceClip.h,
- h: voiceClip.h,
- mime: voiceClip.mime,
- playtime: voiceClip.playtime,
- audioId: `vm${message.messageId}`
- }));
+ if (scrollPositionY === false) {
+ scrollPositionY = self.scrollableArea.getScrollPositionY();
}
- }
- getContents() {
- return REaCt().createElement(REaCt().Fragment, null, this.props.message.getState() === Message.STATE.NOT_SENT ? null : this._getActionButtons(), this._getAudioContainer());
- }
-}
-;// ./js/chat/ui/messages/types/partials/metaRichpreview.jsx
-const React = REQ_(594);
-const ConversationMessageMixin = REQ_(446).M;
-const MetaRichPreviewLoading = REQ_(707).a;
-class MetaRichpreview extends ConversationMessageMixin {
- getBase64Url(b64incoming) {
- if (!b64incoming || !b64incoming.split) {
- return;
+ if (!stateObj) {
+ stateObj = self.state;
+ }
+ const visibleStart = scrollPositionY;
+ const visibleEnd = visibleStart + self.heightDefs.containerHeight;
+ let currentPos = 0;
+ let visibleCategories = [];
+ self._emojiReactElements = [];
+ self.data_categoryPositions = {};
+ self.data_categoriesWithCustomOrder.forEach((k) => {
+ const categoryDivMeta = self.generateEmojiElementsByCategory(k, currentPos, stateObj);
+ if (categoryDivMeta) {
+ const startPos = currentPos;
+ currentPos += categoryDivMeta[0];
+ const endPos = currentPos;
+ self.data_categoryPositions[k] = startPos;
+ if (self._isVisible(visibleStart, visibleEnd, startPos, endPos)) {
+ visibleCategories.push(k);
+ self._emojiReactElements.push(categoryDivMeta[1]);
+ }
+ }
+ });
+ if (self._emojiReactElements.length === 0) {
+ const emojisNotFound = JSX_("span", {
+ className: "emojis-not-found",
+ key: 'emojis-not-found'
+ }, l[20920]);
+ self._emojiReactElements.push(emojisNotFound);
}
- let exti = b64incoming.split(":");
- const b64i = exti[1];
- exti = exti[0];
- return `data:image/${ exti };base64,${ b64i}`;
+ visibleCategories = visibleCategories.join(',');
+ self.setState({
+ 'totalScrollHeight': currentPos,
+ visibleCategories
+ });
}
- render() {
+ _renderEmojiPickerPopup() {
const self = this;
- const {message} = this.props;
- const output = [];
- const metas = message.meta && message.meta.extra ? message.meta.extra : [];
- const failedToLoad = message.meta.isLoading && unixtime() - message.meta.isLoading > 300;
- const isLoading = !!message.meta.isLoading;
- if (failedToLoad) {
- return null;
+ let preview;
+ if (self.state.previewEmoji) {
+ const meta = self.state.previewEmoji;
+ preview = JSX_("div", {
+ className: "emoji-preview"
+ }, self._generateEmoji(meta), JSX_("div", {
+ className: "emoji title"
+ }, `:${ meta.n }:`));
}
- for (let i = 0; i < metas.length; i++) {
- const meta = metas[i];
- if (!meta.d && !meta.t && !message.meta.isLoading) {
- continue;
- }
- const previewCss = {};
- if (meta.i) {
- previewCss.backgroundImage = `url(${ self.getBase64Url(meta.i) })`;
- previewCss.backgroundRepeat = "no-repeat";
- previewCss.backgroundPosition = "center center";
+ const categoryIcons = {
+ "frequently_used": "icon-emoji-type-frequent",
+ "people": "icon-emoji-type-people",
+ "nature": "icon-emoji-type-nature",
+ "food": "icon-emoji-type-food",
+ "activity": "icon-emoji-type-activity",
+ "travel": "icon-emoji-type-travel",
+ "objects": "icon-emoji-type-objects",
+ "symbols": "icon-emoji-type-symbol",
+ "flags": "icon-emoji-type-flag"
+ };
+ const categoryButtons = [];
+ let activeCategoryName = false;
+ if (!self.state.searchValue) {
+ const firstActive = self.state.visibleCategories.split(",")[0];
+ if (firstActive) {
+ activeCategoryName = self.data_categories[firstActive];
}
- var previewContainer;
- if (isLoading) {
- previewContainer = React.createElement(MetaRichPreviewLoading, {
- message,
- isLoading: message.meta.isLoading
- });
- } else {
- let domainName = meta.url;
- domainName = domainName.replace("https://", "").replace("http://", "").split("/")[0];
- previewContainer = React.createElement("div", {
- className: "message richpreview body"
- }, meta.i ? React.createElement("div", {
- className: "message richpreview img-wrapper"
- }, React.createElement("div", {
- className: "message richpreview preview",
- style: previewCss
- })) : undefined, React.createElement("div", {
- className: "message richpreview inner-wrapper"
- }, React.createElement("div", {
- className: "message richpreview data-title selectable-txt"
- }, React.createElement("span", {
- className: "message richpreview title"
- }, meta.t)), React.createElement("div", {
- className: "message richpreview desc"
- }, ellipsis(meta.d, 'end', 82)), React.createElement("div", {
- className: "message richpreview url-container"
- }, meta.ic ? React.createElement("span", {
- className: "message richpreview url-favicon"
- }, React.createElement("img", {
- src: self.getBase64Url(meta.ic),
- width: 16,
- height: 16,
- onError: e => {
- e.target.parentNode.removeChild(e.target);
- },
- alt: ""
- })) : "", React.createElement("span", {
- className: "message richpreview url"
- }, domainName))));
- }
- output.push(React.createElement("div", {
- key: meta.url,
- className: `message richpreview container ${ meta.i ? "have-preview" : "no-preview" } ${ meta.d ? "have-description" : "no-description" } ${ isLoading ? "is-loading" : "done-loading"}`,
- onClick: function (url) {
- if (!message.meta.isLoading) {
- window.open(url, "_blank", 'noopener,noreferrer');
- }
- }.bind(this, meta.url)
- }, previewContainer, React.createElement("div", {
- className: "clear"
- })));
}
- return React.createElement("div", {
- className: "message richpreview previews-container"
- }, output);
- }
-}
-
-;// ./js/chat/ui/messages/types/partials/metaRichpreviewConfirmation.jsx
-const metaRichpreviewConfirmation_React = REQ_(594);
-const metaRichpreviewConfirmation_ConversationMessageMixin = REQ_(446).M;
-class MetaRichprevConfirmation extends metaRichpreviewConfirmation_ConversationMessageMixin {
- doAllow() {
- const {message} = this.props;
- const {megaChat} = this.props.message.chatRoom;
- delete message.meta.requiresConfirmation;
- RichpreviewsFilter.confirmationDoConfirm();
- megaChat.plugins.richpreviewsFilter.processMessage({}, message);
- message.trackDataChange();
- }
- doNotNow() {
- const {message} = this.props;
- delete message.meta.requiresConfirmation;
- RichpreviewsFilter.confirmationDoNotNow();
- message.trackDataChange();
- }
- doNever() {
- const {message} = this.props;
- msgDialog('confirmation', l[870], l[18687], '', (e) => {
- if (e) {
- delete message.meta.requiresConfirmation;
- RichpreviewsFilter.confirmationDoNever();
- message.trackDataChange();
- }
+ self.customCategoriesOrder.forEach(categoryName => {
+ categoryButtons.push(JSX_("div", {
+ visiblecategories: this.state.visibleCategories,
+ className: `
+ button square-button emoji
+ ${activeCategoryName === categoryName ? 'active' : ''}
+ `,
+ key: categoryIcons[categoryName],
+ onClick: e => {
+ e.stopPropagation();
+ e.preventDefault();
+ this.setState({
+ browsingCategory: categoryName,
+ searchValue: ''
+ });
+ this._cachedNodes = {};
+ const categoryPosition = this.data_categoryPositions[this.data_categories.indexOf(categoryName)] + 10;
+ this.scrollableArea.scrollToY(categoryPosition);
+ this._onScrollChanged(categoryPosition);
+ const {
+ current
+ } = this.emojiSearchRef || !1;
+ current == null || current.focus();
+ }
+ }, JSX_("i", {
+ className: `sprite-fm-mono ${categoryIcons[categoryName]}`
+ })));
});
+ return JSX_(react1___default().Fragment, null, JSX_("div", {
+ className: "popup-header emoji"
+ }, preview || JSX_("div", {
+ className: "search-block emoji"
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-preview-reveal"
+ }), JSX_("input", {
+ ref: this.emojiSearchRef,
+ type: "search",
+ placeholder: l[102],
+ onChange: this.onSearchChange,
+ autoFocus: true,
+ value: this.state.searchValue
+ }))), JSX_(_perfectScrollbar_jsx4__ .O, {
+ className: "popup-scroll-area emoji perfectScrollbarContainer",
+ searchValue: this.state.searchValue,
+ onUserScroll: this.onUserScroll,
+ visibleCategories: this.state.visibleCategories,
+ ref: ref => {
+ this.scrollableArea = ref;
+ }
+ }, JSX_("div", {
+ className: "popup-scroll-content emoji"
+ }, JSX_("div", {
+ style: {
+ height: this.state.totalScrollHeight
+ }
+ }, this._emojiReactElements))), JSX_("div", {
+ className: "popup-footer emoji"
+ }, categoryButtons));
}
render() {
const self = this;
- let notNowButton = null;
- let neverButton = null;
- if (RichpreviewsFilter.confirmationCount >= 2) {
- neverButton = metaRichpreviewConfirmation_React.createElement("button", {
- className: "mega-button right negative",
- onClick () {
- self.doNever();
- }
- }, metaRichpreviewConfirmation_React.createElement("span", null, l[1051]));
- }
- notNowButton = metaRichpreviewConfirmation_React.createElement("button", {
- className: "mega-button right",
- onClick () {
- self.doNotNow();
- }
- }, metaRichpreviewConfirmation_React.createElement("span", null, l[18682]));
- return metaRichpreviewConfirmation_React.createElement("div", {
- className: "message richpreview previews-container"
- }, metaRichpreviewConfirmation_React.createElement("div", {
- className: "message richpreview container confirmation"
- }, metaRichpreviewConfirmation_React.createElement("div", {
- className: "message richpreview body"
- }, metaRichpreviewConfirmation_React.createElement("div", {
- className: "message richpreview img-wrapper"
- }, metaRichpreviewConfirmation_React.createElement("div", {
- className: " message richpreview preview-confirmation sprite-fm-illustration img-chat-url-preview "
- })), metaRichpreviewConfirmation_React.createElement("div", {
- className: "message richpreview inner-wrapper"
- }, metaRichpreviewConfirmation_React.createElement("div", {
- className: "message richpreview data-title selectable-txt"
- }, metaRichpreviewConfirmation_React.createElement("span", {
- className: "message richpreview title"
- }, l[18679])), metaRichpreviewConfirmation_React.createElement("div", {
- className: "message richpreview desc"
- }, l[18680])), metaRichpreviewConfirmation_React.createElement("div", {
- className: "buttons-block"
- }, metaRichpreviewConfirmation_React.createElement("button", {
- className: "mega-button right positive",
- onClick: () => {
- self.doAllow();
+ let popupContents = null;
+ if (self.state.isActive === true) {
+ if (self.state.loadFailed === true) {
+ popupContents = JSX_("div", {
+ className: "loading"
+ }, l[1514]);
+ } else if (this.state.isLoading || !this.data_emojiByCategory || !this.data_categories) {
+ popupContents = JSX_("div", {
+ className: "loading"
+ }, l[5533]);
+ } else {
+ popupContents = self._renderEmojiPickerPopup();
}
- }, metaRichpreviewConfirmation_React.createElement("span", null, l[18681])), notNowButton, neverButton)), metaRichpreviewConfirmation_React.createElement("div", {
- className: "clear"
- })));
- }
-}
-
-;// ./js/chat/ui/messages/types/partials/geoLocation.jsx
-
-function GeoLocation(props) {
- const {
- latitude,
- lng
- } = props;
- const handleOnclick = (lat, lng) => {
- const openGmaps = () => {
- window.open(`https://www.google.com/maps/search/?api=1&query=${lat},${lng}`, '_blank', 'noopener,noreferrer');
- };
- if (GeoLocationLinks.gmapsConfirmation === -1 || GeoLocationLinks.gmapsConfirmation === false) {
- msgDialog('confirmation', 'geolocation-link', l[20788], l.confirm_ext_link, answer => {
- if (answer) {
- GeoLocationLinks.confirmationDoConfirm();
- closeDialog();
- openGmaps();
- } else {
- GeoLocationLinks.confirmationDoNever();
- }
- });
- } else if (GeoLocationLinks.gmapsConfirmation) {
- openGmaps();
+ } else {
+ popupContents = null;
}
- };
- return REaCt().createElement("div", {
- className: "geolocation-container"
- }, REaCt().createElement("div", {
- className: "geolocation",
- onClick: () => handleOnclick(latitude, lng)
- }, REaCt().createElement("div", {
- className: "geolocation__details"
- }, REaCt().createElement("div", {
- className: "geolocation__icon"
- }, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-location"
- })), REaCt().createElement("ul", {
- className: "geolocation__data-list"
- }, REaCt().createElement("li", null, REaCt().createElement("span", {
- className: "geolocation__title"
- }, l[20789])), REaCt().createElement("li", null, REaCt().createElement("p", null, REaCt().createElement("span", {
- className: "geolocation__coordinates-icon"
- }), REaCt().createElement("span", {
- className: "geolocation__coordinates"
- }, "https://maps.google.com")))))));
-}
-const geoLocation = GeoLocation;
-// EXTERNAL MODULE: ./js/chat/ui/messages/types/partials/metaRichPreviewLoading.jsx
-const metaRichPreviewLoading = REQ_(707);
-;// ./js/chat/ui/messages/types/partials/metaRichpreviewMegaLinks.jsx
-
-
-
-
-
-class MetaRichpreviewMegaLinks extends mixin.M {
- render() {
- const {message} = this.props;
- const {chatRoom} = this.props.message;
- let previewContainer;
- const output = [];
- const megaLinks = message.megaLinks ? message.megaLinks : [];
- for (let i = 0; i < megaLinks.length; i++) {
- const megaLinkInfo = megaLinks[i];
- if (megaLinkInfo.failed) {
- continue;
- }
- if (megaLinkInfo.hadLoaded() === false) {
- if (megaLinkInfo.startedLoading() === false) {
- megaLinkInfo.getInfo().then(() => {
- const {
- megaLinks
- } = this.props.message;
- const contactLinkHandles = megaLinks.filter(link => link.is_contactlink).map(link => link.info.h);
- if (contactLinkHandles.length) {
- this.addContactListenerIfMissing(contactLinkHandles);
- }
- }).catch(reportError).finally(() => {
- message.trackDataChange();
- onIdle(() => {
- this.safeForceUpdate();
- });
+ return JSX_(_dropdowns_jsx3__ .ms, (0,_babel_runtime_helpers_extends0__ .A)({
+ className: "popup emoji"
+ }, self.props, {
+ isLoading: self.state.isLoading,
+ loadFailed: self.state.loadFailed,
+ visibleCategories: this.state.visibleCategories,
+ forceShowWhenEmpty: true,
+ onActiveChange: newValue => {
+ if (newValue === false) {
+ self.setState(self.getInitialState());
+ self._cachedNodes = {};
+ self._onScrollChanged(0);
+ } else {
+ self.setState({
+ 'isActive': true
});
}
- previewContainer = REaCt().createElement(metaRichPreviewLoading.a, {
- message,
- isLoading: megaLinkInfo.hadLoaded()
- });
- } else if (megaLinkInfo.is_contactlink) {
- const fakeContact = M.u[megaLinkInfo.info.h] ? M.u[megaLinkInfo.info.h] : {
- 'u': megaLinkInfo.info.h,
- 'm': megaLinkInfo.info.e,
- 'firstName': megaLinkInfo.info.fn,
- 'lastName': megaLinkInfo.info.ln,
- 'name': `${megaLinkInfo.info.fn } ${ megaLinkInfo.info.ln}`
- };
- if (!M.u[fakeContact.u]) {
- M.u.set(fakeContact.u, new MegaDataObject(MEGA_USER_STRUCT, {
- 'u': fakeContact.u,
- 'name': `${fakeContact.firstName } ${ fakeContact.lastName}`,
- 'm': fakeContact.m ? fakeContact.m : "",
- 'c': undefined
- }));
- }
- const contact = M.u[megaLinkInfo.info.h];
- previewContainer = REaCt().createElement("div", {
- key: megaLinkInfo.info.h,
- className: "message shared-block contact-link"
- }, REaCt().createElement("div", {
- className: "message shared-info"
- }, REaCt().createElement("div", {
- className: "message data-title selectable-txt"
- }, contact.name), REaCt().createElement(ui_contacts.ContactVerified, {
- className: "right-align",
- contact
- }), REaCt().createElement("div", {
- className: "user-card-email selectable-txt"
- }, contact.m)), REaCt().createElement("div", {
- className: "message shared-data"
- }, REaCt().createElement("div", {
- className: "data-block-view semi-big"
- }, REaCt().createElement(ui_contacts.ContactPresence, {
- className: "small",
- contact
- }), REaCt().createElement(ui_contacts.Avatar, {
- className: "avatar-wrapper medium-avatar",
- contact,
- chatRoom
- })), REaCt().createElement("div", {
- className: "clear"
- })));
- } else {
- var desc;
- const is_icon = megaLinkInfo.is_dir ? true : !(megaLinkInfo.havePreview() && megaLinkInfo.info.preview_url);
- if (megaLinkInfo.is_chatlink) {
- desc = l[8876].replace('%1', megaLinkInfo.info.ncm);
- } else if (!megaLinkInfo.is_dir) {
- desc = bytesToSize(megaLinkInfo.info.size);
- } else {
- const totalNumberOfFiles = megaLinkInfo.info.s[1];
- const numOfVersionedFiles = megaLinkInfo.info.s[4];
- const folderCount = megaLinkInfo.info.s[2];
- const totalFileSize = megaLinkInfo.info.size;
- const versionsSize = megaLinkInfo.info.s[3];
- desc = REaCt().createElement("span", null, fm_contains(totalNumberOfFiles - numOfVersionedFiles, folderCount - 1), REaCt().createElement("br", null), bytesToSize(totalFileSize - versionsSize));
+ if (self.props.onActiveChange) {
+ self.props.onActiveChange(newValue);
}
- previewContainer = REaCt().createElement("div", {
- className: `message richpreview body ${ is_icon ? "have-icon" : "no-icon" } ${ megaLinkInfo.is_chatlink ? "is-chat" : ""}`
- }, megaLinkInfo.havePreview() && megaLinkInfo.info.preview_url ? REaCt().createElement("div", {
- className: "message richpreview img-wrapper"
- }, REaCt().createElement("div", {
- className: "message richpreview preview",
- style: {
- "backgroundImage": `url(${ megaLinkInfo.info.preview_url })`
- }
- })) : REaCt().createElement("div", {
- className: "message richpreview img-wrapper"
- }, megaLinkInfo.is_chatlink ? REaCt().createElement("i", {
- className: "huge-icon conversations"
- }) : REaCt().createElement("div", {
- className: `message richpreview icon item-type-icon-90 icon-${ megaLinkInfo.is_dir ? "folder" : fileIcon(megaLinkInfo.info) }-90`
- })), REaCt().createElement("div", {
- className: "message richpreview inner-wrapper"
- }, REaCt().createElement("div", {
- className: "message richpreview data-title selectable-txt"
- }, REaCt().createElement("span", {
- className: "message richpreview title"
- }, REaCt().createElement(utils.zT, null, megaLinkInfo.info.name || megaLinkInfo.info.topic || ""))), REaCt().createElement("div", {
- className: "message richpreview desc"
- }, desc), REaCt().createElement("div", {
- className: "message richpreview url-container"
- }, REaCt().createElement("span", {
- className: "message richpreview url-favicon"
- }, REaCt().createElement("img", {
- src: `https://mega.${mega.tld}/favicon.ico?v=3&c=1`,
- width: 16,
- height: 16,
- onError: e => {
- if (e && e.target && e.target.parentNode) {
- e.target.parentNode.removeChild(e.target);
- }
- },
- alt: ""
- })), REaCt().createElement("span", {
- className: "message richpreview url"
- }, ellipsis(megaLinkInfo.getLink(), 'end', 40)))));
- }
- output.push(REaCt().createElement("div", {
- key: `${megaLinkInfo.node_key }_${ output.length}`,
- className: `message richpreview container ${ megaLinkInfo.havePreview() ? "have-preview" : "no-preview" } ${ megaLinkInfo.d ? "have-description" : "no-description" } ${ !megaLinkInfo.hadLoaded() ? "is-loading" : "done-loading"}`,
- onClick: function (url, megaLinkInfo) {
- if (megaLinkInfo.hadLoaded()) {
- if (window.sfuClient && megaLinkInfo.is_chatlink) {
- const {
- chatRoom: callRoom
- } = megaChat.activeCall;
- const peers = callRoom ? callRoom.getParticipantsExceptMe(callRoom.getCallParticipants()).map(h => M.getNameByHandle(h)) : [];
- const body = peers.length ? mega.utils.trans.listToString(peers, l.cancel_with_to_join) : l.cancel_to_join;
- return msgDialog('confirmation', undefined, l.call_in_progress, body, e => e && window.open(url, '_blank', 'noopener,noreferrer'));
- }
- window.open(url, '_blank', 'noopener,noreferrer');
- }
- }.bind(this, megaLinkInfo.getLink(), megaLinkInfo)
- }, previewContainer, REaCt().createElement("div", {
- className: "clear"
- })));
- }
- return REaCt().createElement("div", {
- className: "message richpreview previews-container"
- }, output);
+ },
+ searchValue: self.state.searchValue,
+ browsingCategory: self.state.browsingCategory,
+ previewEmoji: self.state.previewEmoji
+ }), JSX_("div", {
+ ref: this.domRef
+ }, popupContents));
}
}
+DropdownEmojiSelector.defaultProps = {
+ 'requiresUpdateOnResize': true,
+ 'hideable': true
+};
-// EXTERNAL MODULE: ./js/chat/ui/typingArea.jsx + 1 modules
-const typingArea = REQ_(795);
-// EXTERNAL MODULE: ./js/ui/perfectScrollbar.jsx
-const perfectScrollbar = REQ_(486);
-;// ./js/chat/ui/messages/types/text.jsx
-
-
-
-
-
+ },
+ 8120
+(_, EXP_, REQ_) {
+"use strict";
+// EXPORTS
+REQ_.d(EXP_, {
+ A: () => modalDialogs
+});
+// UNUSED EXPORTS: ExtraFooterElement
+// EXTERNAL MODULE: external "React"
+const external_React_ = REQ_(1594);
+const REaCt = REQ_.n(external_React_);
+// EXTERNAL MODULE: ./js/ui/utils.jsx
+const utils = REQ_(6411);
+// EXTERNAL MODULE: ./js/chat/mixins.js
+const mixins = REQ_(8264);
+;// ./js/ui/forms.jsx
-class Text extends AbstractGenericMessage {
+class Checkbox extends mixins.w9 {
constructor(props) {
super(props);
+ this.domRef = REaCt().createRef();
this.state = {
- editText: ''
+ checked: this.props.checked ? this.props.checked : false
};
+ this.onLabelClick = this.onLabelClick.bind(this);
+ this.onChange = this.onChange.bind(this);
}
- isRichPreview(message) {
- return message.metaType === Message.MESSAGE_META_TYPE.RICH_PREVIEW;
+ onLabelClick(e) {
+ const state = !this.state.checked;
+ this.setState({
+ 'checked': state
+ });
+ if (this.props.onLabelClick) {
+ this.props.onLabelClick(e, state);
+ }
+ this.onChange(e);
}
- isGeoLocation(message) {
- return message.metaType === Message.MESSAGE_META_TYPE.GEOLOCATION;
+ onChange(e) {
+ if (this.props.onChange) {
+ this.props.onChange(e, this.state.checked);
+ }
}
- getClassNames() {
+ render() {
const {
- message,
- isBeingEdited,
- grouped
+ name,
+ id,
+ children
} = this.props;
- const REQUIRES_CONFIRMATION = this.isRichPreview(message) && message.meta.requiresConfirmation && !isBeingEdited() && (message.source === Message.SOURCE.SENT || message.confirmed === true);
- return `
- ${REQUIRES_CONFIRMATION ? 'preview-requires-confirmation-container' : ''}
- ${grouped ? 'grouped' : ''}
- `;
+ const className = this.state.checked ? 'checkboxOn' : 'checkboxOff';
+ return JSX_("div", {
+ ref: this.domRef,
+ className: "formsCheckbox"
+ }, JSX_("div", {
+ className: `
+ checkdiv
+ ${className}
+ `,
+ onClick: this.onLabelClick
+ }, JSX_("input", {
+ type: "checkbox",
+ name,
+ id,
+ className,
+ checked: this.state.checked,
+ onChange: this.onChange
+ })), JSX_("label", {
+ htmlFor: id,
+ className: "radio-txt"
+ }, children));
+ }
+}
+ const ui_forms = {
+ Checkbox
+};
+// EXTERNAL MODULE: ./js/chat/ui/contacts.jsx
+const contacts = REQ_(8022);
+;// ./js/ui/modalDialogs.jsx
+
+
+
+
+
+class ExtraFooterElement extends REaCt().Component {
+ render() {
+ return this.props.children;
}
- renderMessageIndicators() {
+}
+class SafeShowDialogController extends mixins.w9 {
+ constructor(props) {
+ super(props);
+ this.dialogName = 'unnamed-dialog';
+ this.dialogBecameVisible = null;
const {
- message,
- spinnerElement,
- isBeingEdited,
- onRetry,
- onCancelRetry
- } = this.props;
- if (!message || spinnerElement || isBeingEdited()) {
- return null;
- }
- const state = message.getState == null ? void 0 : message.getState();
- if (![Message.STATE.NOT_SENT, Message.STATE.NOT_SENT_EXPIRED].includes(state)) {
+ render
+ } = this;
+ this.render = () => {
+ if (this.dialogBecameVisible) {
+ console.assert($.dialog === this.dialogName, `${this.dialogName} state overridden.`);
+ return render.call(this);
+ }
return null;
- }
- const props = {
- 'data-simpletipposition': 'top',
- 'data-simpletipoffset': 8
};
- return message.requiresManualRetry ? REaCt().createElement("div", {
- className: "not-sent-indicator clickable"
- }, REaCt().createElement("span", (0,esm_extends.A)({
- className: "simpletip"
- }, props, {
- "data-simpletip": l[8883],
- onClick: ev => onRetry(ev, message)
- }), REaCt().createElement("i", {
- className: "small-icon refresh-circle"
- })), REaCt().createElement("span", (0,esm_extends.A)({
- className: "simpletip"
- }, props, {
- "data-simpletip": l[8884],
- onClick: ev => onCancelRetry(ev, message)
- }), REaCt().createElement("i", {
- className: "sprite-fm-mono icon-dialog-close"
- }))) : REaCt().createElement("div", (0,esm_extends.A)({
- className: "not-sent-indicator simpletip"
- }, props, {
- "data-simpletip": l[8882]
- }), REaCt().createElement("i", {
- className: "small-icon yellow-triangle"
- }));
}
- getMessageActionButtons() {
- const {
- chatRoom,
- message,
- isBeingEdited
- } = this.props;
- if (isBeingEdited()) {
- return [];
- }
- let extraPreButtons = [];
- let messageActionButtons = null;
- const IS_GEOLOCATION = this.isGeoLocation(message);
- if (!message.deleted && this.isRichPreview(message)) {
- if (!message.meta.requiresConfirmation) {
- if (message.isEditable()) {
- if (message.meta.isLoading) {
- extraPreButtons = [...extraPreButtons, REaCt().createElement(dropdowns.DropdownItem, {
- icon: "sprite-fm-mono icon-eye-hidden",
- key: "stop-link-preview",
- label: l[18684],
- className: "",
- onClick: e => {
- e.stopPropagation();
- e.preventDefault();
- chatRoom.megaChat.plugins.richpreviewsFilter.cancelLoading(chatRoom, message);
- }
- })];
- } else {
- extraPreButtons = [...extraPreButtons, REaCt().createElement(dropdowns.DropdownItem, {
- key: "remove-link-preview",
- icon: "sprite-fm-mono icon-eye-hidden",
- label: l[18684],
- className: "",
- onClick: e => {
- e.stopPropagation();
- e.preventDefault();
- chatRoom.megaChat.plugins.richpreviewsFilter.revertToText(chatRoom, message);
- }
- })];
- }
- }
- } else if (!isBeingEdited() && !(message.source === Message.SOURCE.SENT || message.confirmed === true)) {
- extraPreButtons = [...extraPreButtons, REaCt().createElement(dropdowns.DropdownItem, {
- key: "insert-link-preview",
- icon: "icons-sprite bold-eye",
- label: l[18683],
- className: "",
- onClick: e => {
- e.stopPropagation();
- e.preventDefault();
- chatRoom.megaChat.plugins.richpreviewsFilter.insertPreview(message);
- }
- })];
- }
- }
- if (!message.deleted && message.isEditable() && !isBeingEdited() && !chatRoom.isReadOnly() && !message.requiresManualRetry) {
- const editButton = !IS_GEOLOCATION && REaCt().createElement(dropdowns.DropdownItem, {
- icon: "sprite-fm-mono icon-rename",
- label: l[1342],
- onClick: () => this.props.onEditToggle(true)
- });
- messageActionButtons = REaCt().createElement(buttons.$, {
- key: "delete-msg",
- className: "tiny-button",
- icon: "sprite-fm-mono icon-options"
- }, REaCt().createElement(dropdowns.Dropdown, {
- className: "white-context-menu attachments-dropdown",
- noArrow: true,
- positionMy: "left bottom",
- positionAt: "right bottom",
- horizOffset: 4
- }, extraPreButtons, editButton, editButton ? REaCt().createElement("hr", null) : null, REaCt().createElement(dropdowns.DropdownItem, {
- icon: "sprite-fm-mono icon-dialog-close",
- label: l[1730],
- onClick: e => this.props.onDelete(e, message)
- })));
- }
- let parentButtons;
- if (super.getMessageActionButtons) {
- parentButtons = super.getMessageActionButtons();
- }
- const returnedButtons = [];
- if (messageActionButtons) {
- returnedButtons.push(messageActionButtons);
- }
- if (message.messageHtml && message.messageHtml.includes('') && message.messageHtml.includes('')) {
- returnedButtons.push(REaCt().createElement(buttons.$, {
- key: "copy-msg",
- className: "tiny-button simpletip copy-txt-block",
- icon: "sprite-fm-mono icon-copy",
- attrs: {
- 'data-simpletip': l.copy_txt_block_tip,
- 'data-simpletipoffset': '3',
- 'data-simpletipposition': 'top'
- },
- onClick: () => {
- copyToClipboard(message.textContents.replace(/```/g, ''), l.copy_txt_block_toast);
- }
- }));
- }
- if (parentButtons) {
- returnedButtons.push(parentButtons);
+ shouldComponentUpdate(nextProps, nextState) {
+ if (!this.dialogBecameVisible) {
+ return false;
}
- return returnedButtons;
+ return super.shouldComponentUpdate(nextProps, nextState);
}
- getContents() {
- const {
- message,
- chatRoom,
- onUpdate,
- isBeingEdited,
- spinnerElement
- } = this.props;
- let textMessage = message.messageHtml;
- const IS_GEOLOCATION = this.isGeoLocation(message);
- const {
- lng,
- la: latitude
- } = IS_GEOLOCATION && message.meta.extra[0];
- if (message.textContents === '' && !message.dialogType) {
- message.deleted = true;
- }
- let subMessageComponent = [];
- if (!message.deleted) {
- if (this.isRichPreview(message)) {
- if (!message.meta.requiresConfirmation) {
- subMessageComponent = [...subMessageComponent, REaCt().createElement(MetaRichpreview, {
- key: "richprev",
- message,
- chatRoom
- })];
- } else if (!isBeingEdited()) {
- if (message.source === Message.SOURCE.SENT || message.confirmed === true) {
- subMessageComponent = [...subMessageComponent, REaCt().createElement(MetaRichprevConfirmation, {
- key: "confirm",
- message,
- chatRoom
- })];
- }
- }
+ componentDidMount() {
+ super.componentDidMount();
+ M.safeShowDialog(this.dialogName, () => {
+ if (!this.isMounted()) {
+ throw new Error(`${this.dialogName} component is no longer mounted.`);
}
- if (message.megaLinks) {
- subMessageComponent = [...subMessageComponent, REaCt().createElement(MetaRichpreviewMegaLinks, {
- key: "richprevml",
- message,
- chatRoom
- })];
+ this.dialogBecameVisible = 1;
+ this.forceUpdate();
+ });
+ }
+ componentWillUnmount() {
+ super.componentWillUnmount();
+ if (this.dialogBecameVisible) {
+ this.dialogBecameVisible = false;
+ console.assert($.dialog === this.dialogName);
+ if ($.dialog === this.dialogName) {
+ closeDialog();
}
}
- let messageDisplayBlock;
- if (isBeingEdited() === true) {
- let msgContents = message.textContents;
- msgContents = megaChat.plugins.emoticonsFilter.fromUtfToShort(msgContents);
- messageDisplayBlock = REaCt().createElement(typingArea.T, {
- iconClass: "small-icon writing-pen textarea-icon",
- initialText: msgContents,
- text: this.state.editText || msgContents,
- chatRoom,
- showButtons: true,
- editing: true,
- className: "edit-typing-area",
- onUpdate: () => onUpdate ? onUpdate : null,
- onConfirm: messageContents => {
- this.props.onEditToggle(false);
- if (this.props.onEditDone) {
- Soon(() => {
- const tmpMessageObj = {
- textContents: messageContents
- };
- megaChat.plugins.emoticonsFilter.processOutgoingMessage({}, tmpMessageObj);
- this.props.onEditDone(tmpMessageObj.textContents);
- if (this.isMounted()) {
- this.forceUpdate();
- }
- });
- }
- return true;
- },
- onResized: this.props.onResized ? this.props.onResized : false,
- onValueChanged: val => {
- this.setState({
- editText: val
- });
+ }
+ componentDidUpdate() {
+ assert(this.dialogBecameVisible);
+ super.componentDidUpdate();
+ if (++this.dialogBecameVisible === 2) {
+ requestAnimationFrame(() => {
+ const dialog = document.querySelectorAll(`.${this.dialogName}`);
+ console.assert(dialog.length === 1, `Unexpected ${this.dialogName} state.`);
+ console.assert($.dialog === this.dialogName, `${this.dialogName} state overridden.`);
+ if (dialog.length === 1 && $.dialog === this.dialogName) {
+ dialog[0].classList.remove('hidden', 'arrange-to-back');
}
});
- } else {
- if (message.updated > 0 && !message.metaType) {
- textMessage = `${textMessage} ${l[8887]} `;
- }
- if (this.props.initTextScrolling) {
- messageDisplayBlock = REaCt().createElement(perfectScrollbar.O, {
- className: "message text-block scroll"
- }, REaCt().createElement("div", {
- className: "message text-scroll"
- }, REaCt().createElement(utils.P9, null, textMessage)));
- } else {
- messageDisplayBlock = REaCt().createElement("div", {
- className: "message text-block"
- }, REaCt().createElement(utils.P9, null, textMessage));
- }
}
- return REaCt().createElement(REaCt().Fragment, null, this.renderMessageIndicators(), IS_GEOLOCATION ? null : messageDisplayBlock, subMessageComponent, spinnerElement, IS_GEOLOCATION && REaCt().createElement(geoLocation, {
- latitude,
- lng
- }));
}
}
-// EXTERNAL MODULE: ./js/chat/ui/gifPanel/gifPanel.jsx + 3 modules
-const gifPanel = REQ_(691);
-;// ./js/chat/ui/messages/types/giphy.jsx
-
-
-
-
-
-class Giphy extends AbstractGenericMessage {
- constructor(...args) {
- super(...args);
- this.gifRef = REaCt().createRef();
- this.viewStateListener = `viewstateChange.giphy--${this.getUniqueId()}`;
- this.state = {
- src: undefined
- };
+class ModalDialog extends mixins.w9 {
+ constructor(props) {
+ super(props);
+ this.domRef = REaCt().createRef();
+ this.onBlur = this.onBlur.bind(this);
+ this.onCloseClicked = this.onCloseClicked.bind(this);
+ this.onPopupDidMount = this.onPopupDidMount.bind(this);
}
componentDidMount() {
super.componentDidMount();
- megaChat.rebind(this.viewStateListener, ({
- data
- }) => {
- const gifRef = this.gifRef && this.gifRef.current;
- if (gifRef) {
- const {
- state
- } = data;
- if (state === 'active' && gifRef.paused || state !== 'active' && !gifRef.paused) {
- this.toggle();
+ if (!this.props.hideOverlay) {
+ $(document.body).addClass('overlayed');
+ $('.fm-dialog-overlay').removeClass('hidden');
+ }
+ $('textarea:focus').trigger("blur");
+ if (!this.props.noCloseOnClickOutside) {
+ const convApp = document.querySelector('.conversationsApp');
+ if (convApp) {
+ convApp.removeEventListener('click', this.onBlur);
+ convApp.addEventListener('click', this.onBlur);
+ }
+ $('.fm-modal-dialog').rebind(`click.modalDialogOv${ this.getUniqueId()}`, ({
+ target
+ }) => {
+ if ($(target).is('.fm-modal-dialog')) {
+ this.onBlur();
+ }
+ });
+ $('.fm-dialog-overlay').rebind(`click.modalDialog${ this.getUniqueId()}`, () => {
+ if (this.props.closeDlgOnClickOverlay) {
+ this.onBlur();
}
+ return false;
+ });
+ }
+ $(document).rebind(`keyup.modalDialog${ this.getUniqueId()}`, ({
+ keyCode
+ }) => {
+ if (!this.props.stopKeyPropagation && keyCode === 27) {
+ this.onBlur();
}
});
}
+ onBlur(e) {
+ let _this$domRef;
+ const $element = $((_this$domRef = this.domRef) == null ? void 0 : _this$domRef.current);
+ if (!e || !$(e.target).closest('.mega-dialog').is($element)) {
+ const convApp = document.querySelector('.conversationsApp');
+ if (convApp) {
+ convApp.removeEventListener('click', this.onBlur);
+ }
+ this.onCloseClicked();
+ }
+ }
componentWillUnmount() {
+ let _this$props$popupWill, _this$props;
super.componentWillUnmount();
- megaChat.off(this.viewStateListener);
+ if (!this.props.noCloseOnClickOutside) {
+ const convApp = document.querySelector('.conversationsApp');
+ if (convApp) {
+ convApp.removeEventListener('click', this.onBlur);
+ }
+ $('.fm-dialog-overlay').off(`click.modalDialog${ this.getUniqueId()}`);
+ }
+ if (!this.props.hideOverlay) {
+ $(document.body).removeClass('overlayed');
+ $('.fm-dialog-overlay').addClass('hidden');
+ }
+ $(this.domNode).off(`dialog-closed.modalDialog${ this.getUniqueId()}`);
+ $(document).off(`keyup.modalDialog${ this.getUniqueId()}`);
+ (_this$props$popupWill = (_this$props = this.props).popupWillUnmount) == null || _this$props$popupWill.call(_this$props);
}
- onVisibilityChange(isIntersecting) {
- this.setState({
- src: isIntersecting ? gifPanel.nC.convert(this.props.message.meta.src) : undefined
- }, () => {
- let _this$gifRef;
- (_this$gifRef = this.gifRef) == null || (_this$gifRef = _this$gifRef.current) == null || _this$gifRef[isIntersecting ? 'load' : 'pause']();
- this.safeForceUpdate();
- });
+ onCloseClicked() {
+ const self = this;
+ if (self.props.onClose) {
+ self.props.onClose(self);
+ }
}
- toggle() {
- const video = this.gifRef.current;
- Promise.resolve(video[video.paused ? 'play' : 'pause']()).catch(nop);
+ onPopupDidMount(elem) {
+ this.domNode = elem;
+ $(elem).rebind(`dialog-closed.modalDialog${ this.getUniqueId()}`, () => this.onCloseClicked());
+ if (this.props.popupDidMount) {
+ this.props.popupDidMount(elem);
+ }
}
- getMessageActionButtons() {
- const {
- onDelete,
- message
- } = this.props;
- const $$BUTTONS = [message.isEditable() && REaCt().createElement(buttons.$, {
- key: "delete-GIPHY-button",
- className: "tiny-button",
- icon: "sprite-fm-mono icon-options"
- }, REaCt().createElement(dropdowns.Dropdown, {
- className: "white-context-menu attachments-dropdown",
- noArrow: true,
- positionMy: "left bottom",
- positionAt: "right bottom",
- horizOffset: 4
- }, REaCt().createElement(dropdowns.DropdownItem, {
- icon: "sprite-fm-mono icon-dialog-close",
- label: l[1730],
- onClick: e => onDelete(e, message)
- }))), super.getMessageActionButtons && super.getMessageActionButtons()];
- return $$BUTTONS.filter(button => button);
- }
- getContents() {
- const {
- message,
- hideActionButtons
- } = this.props;
- const {
- s,
- w,
- h,
- src
- } = message.meta;
- const autoPlay = parseInt(s, 10) < 4e6;
- return REaCt().createElement("video", {
- className: "giphy-block",
- ref: this.gifRef,
- title: message.textContents,
- autoPlay,
- loop: true,
- muted: true,
- controls: false,
- width: w,
- height: h,
- style: {
- cursor: autoPlay ? 'default' : 'pointer',
- height: `${h}px`
- },
- onClick: () => !autoPlay && this.toggle(),
- src: hideActionButtons ? gifPanel.nC.convert(src) : this.state.src
+ render() {
+ const self = this;
+ let classes = 'mega-dialog';
+ let selectedNumEle = null;
+ let footer = null;
+ const extraFooterElements = [];
+ const otherElements = [];
+ let x = 0;
+ REaCt().Children.forEach(self.props.children, (child) => {
+ if (!child) {
+ return;
+ }
+ if (child.type.name === 'ExtraFooterElement') {
+ extraFooterElements.push(REaCt().cloneElement(child, {
+ key: x++
+ }));
+ } else {
+ otherElements.push(REaCt().cloneElement(child, {
+ key: x++
+ }));
+ }
});
+ if (self.props.className) {
+ classes += ` ${self.props.className}`;
+ }
+ if (self.props.dialogType) {
+ classes += ` dialog-template-${self.props.dialogType}`;
+ }
+ if (self.props.dialogName) {
+ classes += ` ${self.props.dialogName}`;
+ }
+ if (self.props.showSelectedNum && self.props.selectedNum) {
+ selectedNumEle = JSX_("div", {
+ className: "selected-num"
+ }, JSX_("span", null, self.props.selectedNum));
+ }
+ let buttons;
+ if (self.props.buttons) {
+ buttons = [];
+ self.props.buttons.forEach((v, i) => {
+ if (v) {
+ buttons.push(JSX_("button", {
+ className: (v.defaultClassname ? v.defaultClassname : "mega-button") + (v.className ? ` ${ v.className}` : "") + (self.props.dialogType === "action" ? "large" : ""),
+ onClick: e => {
+ if ($(e.target).is(".disabled")) {
+ return false;
+ }
+ if (v.onClick) {
+ v.onClick(e, self);
+ }
+ },
+ key: v.key + i
+ }, v.iconBefore ? JSX_("div", null, JSX_("i", {
+ className: v.iconBefore
+ })) : null, JSX_("span", null, v.label), v.iconAfter ? JSX_("div", null, JSX_("i", {
+ className: v.iconAfter
+ })) : null));
+ }
+ });
+ if (buttons && buttons.length > 0 || extraFooterElements && extraFooterElements.length > 0) {
+ footer = JSX_("footer", null, buttons && buttons.length > 0 ? JSX_("div", {
+ className: "footer-container"
+ }, buttons) : null, extraFooterElements && extraFooterElements.length > 0 ? JSX_("aside", null, extraFooterElements) : null);
+ }
+ }
+ return JSX_(utils.Ay.RenderTo, {
+ element: document.body,
+ className: "fm-modal-dialog",
+ popupDidMount: this.onPopupDidMount
+ }, JSX_("div", {
+ ref: this.domRef,
+ id: self.props.id,
+ className: classes,
+ "aria-labelledby": self.props.dialogName ? `${self.props.dialogName }-title` : null,
+ role: "dialog",
+ "aria-modal": "true",
+ onClick: self.props.onClick
+ }, JSX_("button", {
+ className: "close",
+ onClick: self.onCloseClicked
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-dialog-close"
+ })), self.props.title ? self.props.dialogType === "message" ? JSX_("header", null, self.props.icon ? JSX_("i", {
+ className: `graphic ${self.props.icon}`
+ }) : self.props.iconElement, JSX_("div", null, JSX_("h3", {
+ id: self.props.dialogName ? `${self.props.dialogName }-title` : null
+ }, self.props.title, selectedNumEle), self.props.subtitle ? JSX_("p", null, self.props.subtitle) : null, otherElements)) : JSX_("header", null, self.props.icon ? JSX_("i", {
+ className: `graphic ${self.props.icon}`
+ }) : self.props.iconElement, JSX_("h2", {
+ id: self.props.dialogName ? `${self.props.dialogName }-title` : null
+ }, self.props.title, selectedNumEle), self.props.subtitle ? JSX_("p", null, self.props.subtitle) : null) : null, self.props.dialogType !== "message" ? otherElements : null, buttons || extraFooterElements ? footer : null));
}
}
-;// ./js/chat/ui/messages/generic.jsx
-
-
-
-
-
-
-
-
-
-
-class GenericConversationMessage extends mixin.M {
+ModalDialog.defaultProps = {
+ 'hideable': true,
+ 'noCloseOnClickOutside': false,
+ 'closeDlgOnClickOverlay': true,
+ 'showSelectedNum': false,
+ 'selectedNum': 0
+};
+class SelectContactDialog extends mixins.w9 {
constructor(props) {
super(props);
- this.containerRef = REaCt().createRef();
+ this.dialogName = 'send-contact-dialog';
this.state = {
- editing: this.props.editing
+ selected: []
};
- this.pid = `__geom_${ String(Math.random()).substr(2)}`;
- }
- isBeingEdited() {
- return this.state.editing === true || this.props.editing === true;
+ this.state.selected = this.props.selected || [];
+ this.onSelected = this.onSelected.bind(this);
}
- componentDidUpdate(oldProps, oldState) {
- const isBeingEdited = this.isBeingEdited();
- const isMounted = this.isMounted();
- if (isBeingEdited && isMounted) {
- let _this$containerRef;
- const $generic = $((_this$containerRef = this.containerRef) == null ? void 0 : _this$containerRef.current);
- const $textarea = $('textarea', $generic);
- if ($textarea.length > 0 && !$textarea.is(":focus")) {
- $textarea.trigger("focus");
- moveCursortoToEnd($textarea[0]);
- }
- if (!oldState.editing && this.props.onEditStarted) {
- this.props.onEditStarted($generic);
- moveCursortoToEnd($textarea);
- }
- }
- if (isMounted && !isBeingEdited && oldState.editing === true && this.props.onUpdate) {
- this.props.onUpdate();
- }
+ onSelected(nodes) {
+ let _this$props$onSelecte, _this$props2;
+ this.setState({
+ selected: nodes
+ });
+ (_this$props$onSelecte = (_this$props2 = this.props).onSelected) == null || _this$props$onSelecte.call(_this$props2, nodes);
}
componentDidMount() {
- let _this$containerRef2;
super.componentDidMount();
- const $node = $((_this$containerRef2 = this.containerRef) == null ? void 0 : _this$containerRef2.current);
- if (this.isBeingEdited() && this.isMounted()) {
- const $textarea = $('textarea', $node);
- if ($textarea.length > 0 && !$textarea.is(':focus')) {
- $textarea.trigger('focus');
- moveCursortoToEnd($textarea[0]);
- }
- }
+ M.safeShowDialog(this.dialogName, () => $(`.${this.dialogName}`));
}
- haveMoreContactListeners() {
- if (!this.props.message || !this.props.message.meta) {
- return false;
- }
- if (this.props.message.meta && this.props.message.meta.participants) {
- return this.props.message.meta.participants;
+ componentWillUnmount() {
+ super.componentWillUnmount();
+ if ($.dialog === this.dialogName) {
+ closeDialog();
}
- return false;
}
- doDelete(e, msg) {
- e.preventDefault(e);
- e.stopPropagation(e);
- if (msg.getState() === Message.STATE.NOT_SENT_EXPIRED) {
- this.doCancelRetry(e, msg);
- } else {
- this.props.onDeleteClicked(this.props.message);
- }
- }
- doCancelRetry(e, msg) {
- e.preventDefault(e);
- e.stopPropagation(e);
- const {chatRoom} = this.props.message;
- const {messageId} = msg;
- chatRoom.messagesBuff.messages.removeByKey(messageId);
- chatRoom.megaChat.plugins.chatdIntegration.discardMessage(chatRoom, messageId);
- }
- doRetry(e, msg) {
- e.preventDefault(e);
- e.stopPropagation(e);
- const {chatRoom} = this.props.message;
- this.doCancelRetry(e, msg);
- chatRoom._sendMessageToTransport(msg).then(internalId => {
- msg.internalId = internalId;
- this.safeForceUpdate();
- });
+ render() {
+ return JSX_(ModalDialog, {
+ title: l.share_contact_title,
+ className: `
+ send-contact
+ contrast
+ small-footer
+ dialog-template-tool
+ ${this.props.className}
+ ${this.dialogName}
+ `,
+ selected: this.state.selected,
+ buttons: [{
+ key: "cancel",
+ label: this.props.cancelLabel,
+ onClick: ev => {
+ this.props.onClose();
+ ev.preventDefault();
+ ev.stopPropagation();
+ }
+ }, {
+ key: "select",
+ label: this.props.selectLabel,
+ className: this.state.selected.length === 0 ? 'positive disabled' : 'positive',
+ onClick: ev => {
+ if (this.state.selected.length > 0) {
+ let _this$props$onSelecte2, _this$props3;
+ (_this$props$onSelecte2 = (_this$props3 = this.props).onSelected) == null || _this$props$onSelecte2.call(_this$props3, this.state.selected);
+ this.props.onSelectClicked(this.state.selected);
+ }
+ ev.preventDefault();
+ ev.stopPropagation();
+ }
+ }],
+ onClose: this.props.onClose
+ }, JSX_("section", {
+ className: "content"
+ }, JSX_("div", {
+ className: "content-block"
+ }, JSX_(contacts.hU, {
+ megaChat: this.props.megaChat,
+ exclude: this.props.exclude,
+ selectableContacts: "true",
+ onSelectDone: this.props.onSelectClicked,
+ onSelected: this.onSelected,
+ onClose: this.props.onClose,
+ selected: this.state.selected,
+ contacts: M.u,
+ headerClasses: "left-aligned",
+ multiple: true
+ }))));
}
- _favourite(h) {
- if (M.isInvalidUserStatus()) {
- return;
- }
- const newFavState = Number(!M.isFavourite(h));
- M.favourite([h], newFavState);
+}
+SelectContactDialog.clickTime = 0;
+SelectContactDialog.defaultProps = {
+ selectLabel: l.share_contact_action,
+ cancelLabel: l.msg_dlg_cancel,
+ hideable: true
+};
+class ConfirmDialog extends mixins.w9 {
+ static saveState(o) {
+ const state = mega.config.get('xcod') >>> 0;
+ mega.config.set('xcod', state | 1 << o.props.pref);
}
- _addFavouriteButtons(h, arr) {
- const self = this;
- if (M.getNodeRights(h) > 1) {
- const isFav = M.isFavourite(h);
- arr.push(REaCt().createElement(dropdowns.DropdownItem, {
- icon: `
- sprite-fm-mono
- context
- ${isFav ? 'icon-favourite-removed' : 'icon-favourite'}
- `,
- label: isFav ? l[5872] : l[5871],
- isFav,
- key: "fav",
- disabled: mega.paywall,
- onClick: e => {
- self._favourite(h);
- e.stopPropagation();
- e.preventDefault();
- return false;
- }
- }));
- return isFav;
- }
- return false;
+ static clearState(o) {
+ const state = mega.config.get('xcod') >>> 0;
+ mega.config.set('xcod', state & ~(1 << o.props.pref));
}
- _isNodeHavingALink(h) {
- return M.getNodeShare(h) !== false;
+ static autoConfirm(o) {
+ console.assert(o.props.pref > 0);
+ const state = mega.config.get('xcod') >>> 0;
+ return !!(state & 1 << o.props.pref);
}
- _addLinkButtons(h, arr) {
- const self = this;
- const haveLink = self._isNodeHavingALink(h) === true;
- const getManageLinkText = haveLink ? l[6909] : l[5622];
- arr.push(REaCt().createElement(dropdowns.DropdownItem, {
- icon: `sprite-fm-mono icon-link${haveLink ? '-gear' : ''}`,
- key: "getLinkButton",
- label: getManageLinkText,
- disabled: mega.paywall,
- onClick: self._getLink.bind(self, h)
- }));
- if (haveLink) {
- arr.push(REaCt().createElement(dropdowns.DropdownItem, {
- icon: "sprite-fm-mono context icon-link-remove",
- key: "removeLinkButton",
- label: l[6821],
- disabled: mega.paywall,
- onClick: self._removeLink.bind(self, h)
- }));
- return true;
- }
- return false;
+ constructor(props) {
+ super(props);
+ this.dialogName = 'confirm-dialog';
+ this._wasAutoConfirmed = undefined;
+ this._keyUpEventName = `keyup.confirmDialog${ this.getUniqueId()}`;
+ this.dialogName = this.props.name || this.dialogName;
+ lazy(this, '_autoConfirm', () => this.props.onConfirmClicked && this.props.dontShowAgainCheckbox && ConfirmDialog.autoConfirm(this));
}
- _startDownload(v) {
- M.addDownload([v]);
+ unbindEvents() {
+ $(document).off(this._keyUpEventName);
}
- _addToCloudDrive(v, openSendToChat) {
- $.selected = [v.h];
- $.chatAttachmentShare = true;
- if ($.dialog === 'onboardingDialog') {
- closeDialog();
- }
- if (openSendToChat) {
- openSendToChatDialog();
- return;
- }
- openSaveToDialog(v, (node, target) => {
- target = target || M.RootID;
- M.injectNodes(node, target, res => {
- if (!Array.isArray(res) || !res.length) {
- if (d) {
- console.warn('Unable to inject nodes... no longer existing?', res);
+ componentDidMount() {
+ super.componentDidMount();
+ M.safeShowDialog(this.dialogName, () => {
+ queueMicrotask(() => {
+ if (!this.isMounted()) {
+ return;
+ }
+ if (this._autoConfirm) {
+ if (!this._wasAutoConfirmed) {
+ this._wasAutoConfirmed = 1;
+ queueMicrotask(() => {
+ this.onConfirmClicked();
+ });
}
- } else {
- mega.ui.toast.show(mega.icu.format(l.toast_import_file, res.length).replace('%s', M.getNameByHandle(target)), 4, l[16797], {
- actionButtonCallback() {
- M.openFolder(target).then(() => {
- if (window.selectionManager) {
- let reset = false;
- for (let i = res.length; i--;) {
- const n = M.getNodeByHandle(res[i]);
- if (n.p === target) {
- if (reset) {
- selectionManager.add_to_selection(n.h);
- } else {
- selectionManager.resetTo(n.h);
- reset = true;
- }
- }
- }
- }
- }).catch(dump);
- }
- });
+ return;
}
+ $(document).rebind(this._keyUpEventName, e => {
+ if (e.which === 13 || e.keyCode === 13) {
+ if (!this.isMounted()) {
+ this.unbindEvents();
+ return;
+ }
+ this.onConfirmClicked();
+ return false;
+ }
+ });
});
- }, false);
+ });
}
- _getLink(h, e) {
- if (u_type === 0) {
- ephemeralDialog(l[1005]);
- } else {
- $.selected = [h];
- mega.Share.initCopyrightsDialog([h]);
- }
- if (e) {
- e.preventDefault();
- e.stopPropagation();
+ componentWillUnmount() {
+ super.componentWillUnmount();
+ this.unbindEvents();
+ if ($.dialog === this.dialogName) {
+ closeDialog();
}
+ delete this._wasAutoConfirmed;
}
- _removeLink(h, e) {
- if (u_type === 0) {
- ephemeralDialog(l[1005]);
- } else {
- const exportLink = new mega.Share.ExportLink({
- 'updateUI': true,
- 'nodesToProcess': [h]
- });
- exportLink.removeExportLink();
- }
- if (e) {
- e.preventDefault();
- e.stopPropagation();
+ onConfirmClicked() {
+ this.unbindEvents();
+ if (this.props.onConfirmClicked) {
+ this.props.onConfirmClicked();
}
}
- _startPreview(v, e) {
- if ($(e && e.target).is('.tiny-button')) {
- return;
+ render() {
+ const self = this;
+ if (this._autoConfirm) {
+ return null;
}
- assert(M.chat, 'Not in chat.');
- if (e) {
- e.preventDefault();
- e.stopPropagation();
+ const classes = `delete-message${ self.props.name ? ` ${self.props.name}` : "" }${self.props.className ? ` ${self.props.className}` : ""}`;
+ let dontShowCheckbox = null;
+ if (self.props.dontShowAgainCheckbox) {
+ dontShowCheckbox = JSX_("div", {
+ className: "footer-checkbox"
+ }, JSX_(ui_forms.Checkbox, {
+ name: "delete-confirm",
+ id: "delete-confirm",
+ onLabelClick: (e, state) => {
+ if (state === true) {
+ ConfirmDialog.saveState(self);
+ } else {
+ ConfirmDialog.clearState(self);
+ }
+ }
+ }, l[7039]));
}
- M.viewMediaFile(v);
- }
- render() {
- const {
- message,
- chatRoom
- } = this.props;
- const {megaChat} = this.props.message.chatRoom;
- const {textContents} = message;
- let additionalClasses = "";
- let spinnerElement = null;
- let messageIsNowBeingSent = false;
- if (this.props.className) {
- additionalClasses += this.props.className;
- }
- if (message instanceof Message) {
- if (!message.wasRendered || !message.messageHtml) {
- message.messageHtml = htmlentities(textContents).replace(/\n/gi, "
").replace(/\t/g, ' ');
- message.processedBy = {};
- const evtObj = {
- message,
- room: chatRoom
- };
- megaChat.trigger('onPreBeforeRenderMessage', evtObj);
- const event = new MegaDataEvent('onBeforeRenderMessage');
- megaChat.trigger(event, evtObj);
- megaChat.trigger('onPostBeforeRenderMessage', evtObj);
- if (event.isPropagationStopped()) {
- this.logger.warn(`Event propagation stopped receiving (rendering) of message: ${message}`);
- return false;
+ return JSX_(ModalDialog, {
+ title: this.props.title,
+ subtitle: this.props.subtitle,
+ className: classes,
+ dialogId: this.props.name,
+ dialogType: this.props.dialogType,
+ icon: this.props.icon,
+ onClose: () => {
+ self.props.onClose(self);
+ },
+ buttons: [{
+ "label": self.props.cancelLabel,
+ "key": "cancel",
+ "onClick" (e) {
+ ConfirmDialog.clearState(self);
+ self.props.onClose(self);
+ e.preventDefault();
+ e.stopPropagation();
}
- message.wasRendered = 1;
- }
- const state = message.getState();
- const stateText = message.getStateText(state);
- if (state === Message.STATE.NOT_SENT) {
- messageIsNowBeingSent = unixtime() - message.delay < 5;
- if (messageIsNowBeingSent) {
- additionalClasses += ' sending';
- spinnerElement = REaCt().createElement("div", {
- className: "small-blue-spinner"
- });
- if (!message.sending) {
- message.sending = true;
- delay(this.pid + message.messageId, () => {
- if (chatRoom.messagesBuff.messages[message.messageId] && message.sending === true) {
- chatRoom.messagesBuff.trackDataChange();
- if (this.isMounted()) {
- this.forceUpdate();
- }
- }
- }, (5 - (unixtime() - message.delay)) * 1000);
- }
- } else {
- additionalClasses += ' not-sent';
- if (message.sending === true) {
- message.sending = false;
- message.trigger('onChange', [message, 'sending', true, false]);
- }
- if (message.requiresManualRetry) {
- additionalClasses += ' retrying requires-manual-retry';
- } else {
- additionalClasses += ' retrying';
- }
+ }, {
+ "label": self.props.confirmLabel,
+ "key": "select",
+ "className": "positive",
+ "onClick" (e) {
+ self.onConfirmClicked();
+ e.preventDefault();
+ e.stopPropagation();
}
- } else {
- additionalClasses += ` ${ stateText}`;
- }
- }
- const MESSAGE = {
- TYPE: {
- ATTACHMENT: textContents[1] === Message.MANAGEMENT_MESSAGE_TYPES.ATTACHMENT,
- CONTACT: textContents[1] === Message.MANAGEMENT_MESSAGE_TYPES.CONTACT,
- REVOKE_ATTACHMENT: textContents[1] === Message.MANAGEMENT_MESSAGE_TYPES.REVOKE_ATTACHMENT,
- VOICE_CLIP: textContents[1] === Message.MANAGEMENT_MESSAGE_TYPES.VOICE_CLIP,
- GIPHY: message.metaType && message.metaType === Message.MESSAGE_META_TYPE.GIPHY,
- TEXT: textContents[0] !== Message.MANAGEMENT_MESSAGE_TYPES.MANAGEMENT,
- INLINE: !(message instanceof Message) && message.type && !!message.type.length,
- REVOKED: message.revoked
- },
- props: {
- ...this.props,
- additionalClasses
- },
- isBeingEdited: () => this.isBeingEdited(),
- onDelete: (e, message) => this.doDelete(e, message)
- };
- const $$CONTAINER = children => REaCt().createElement("div", {
- ref: this.containerRef
- }, children);
- switch (true) {
- case MESSAGE.TYPE.REVOKED || MESSAGE.TYPE.REVOKE_ATTACHMENT:
- return null;
- case MESSAGE.TYPE.ATTACHMENT:
- return $$CONTAINER(REaCt().createElement(Attachment, (0,esm_extends.A)({}, MESSAGE.props, {
- onPreviewStart: (v, e) => this._startPreview(v, e),
- onDownloadStart: v => this._startDownload(v),
- onAddLinkButtons: (h, arr) => this._addLinkButtons(h, arr),
- onAddToCloudDrive: (v, openSendToChat) => this._addToCloudDrive(v, openSendToChat),
- onAddFavouriteButtons: (h, arr) => this._addFavouriteButtons(h, arr)
- })));
- case MESSAGE.TYPE.CONTACT:
- return $$CONTAINER(REaCt().createElement(Contact, (0,esm_extends.A)({}, MESSAGE.props, {
- onDelete: MESSAGE.onDelete
- })));
- case MESSAGE.TYPE.VOICE_CLIP:
- return $$CONTAINER(REaCt().createElement(VoiceClip, (0,esm_extends.A)({}, MESSAGE.props, {
- isBeingEdited: MESSAGE.isBeingEdited,
- onDelete: MESSAGE.onDelete
- })));
- case MESSAGE.TYPE.INLINE:
- return $$CONTAINER(REaCt().createElement(Local, MESSAGE.props));
- case MESSAGE.TYPE.GIPHY:
- return $$CONTAINER(REaCt().createElement(Giphy, (0,esm_extends.A)({}, MESSAGE.props, {
- onDelete: MESSAGE.onDelete
- })));
- case MESSAGE.TYPE.TEXT:
- return $$CONTAINER(REaCt().createElement(Text, (0,esm_extends.A)({}, MESSAGE.props, {
- onEditToggle: editing => this.setState({
- editing
- }),
- onDelete: MESSAGE.onDelete,
- onRetry: (e, message) => this.doRetry(e, message),
- onCancelRetry: (e, message) => this.doCancelRetry(e, message),
- isBeingEdited: MESSAGE.isBeingEdited,
- spinnerElement
- })));
- default:
- return null;
- }
+ }]
+ }, self.props.children, dontShowCheckbox ? JSX_(ExtraFooterElement, null, dontShowCheckbox) : null);
}
}
+lazy(ConfirmDialog, 'defaultProps', () => {
+ return freeze({
+ 'confirmLabel': l[6826],
+ 'cancelLabel': l.msg_dlg_cancel,
+ 'dontShowAgainCheckbox': true,
+ 'hideable': true,
+ 'dialogType': 'message'
+ });
+});
+ const modalDialogs = {
+ ModalDialog,
+ SelectContactDialog,
+ SafeShowDialogController,
+ ConfirmDialog
+};
-},
+ },
-446
+ 1301
(_, EXP_, REQ_) {
"use strict";
-REQ_.d(EXP_, {
-M: () => ConversationMessageMixin
-});
-const react0__ = REQ_(594);
-const react0 = REQ_.n(react0__);
-const _mixins1__ = REQ_(137);
-const _ui_buttons_jsx2__ = REQ_(994);
-const _ui_emojiDropdown_jsx3__ = REQ_(844);
-
+ REQ_.d(EXP_, {
+ O: () => PerfectScrollbar
+ });
+ const _babel_runtime_helpers_applyDecoratedDescriptor0__ = REQ_(793);
+ const react1__ = REQ_(1594);
+ const react1___default = REQ_.n(react1__);
+ const _chat_mixins2__ = REQ_(8264);
+let _dec, _dec2, _class, _PerfectScrollbar;
-class ConversationMessageMixin extends _mixins1__.u9 {
+const PerfectScrollbar = (_dec = (0,_chat_mixins2__ .hG)(30, true), _dec2 = (0,_chat_mixins2__ .hG)(30, true), _class = (_PerfectScrollbar = class PerfectScrollbar extends _chat_mixins2__ .w9 {
constructor(props) {
super(props);
- this.attachRerenderCallbacks = false;
- this._reactionContactHandles = [];
- this.__cmmUpdateTickCount = 0;
- this._contactChangeListeners = false;
- this.onAfterRenderWasTriggered = false;
- lazy(this, '__cmmId', () => {
- return `${this.getUniqueId() }--${ String(Math.random()).slice(-7)}`;
- });
- this._emojiOnActiveStateChange = this._emojiOnActiveStateChange.bind(this);
- this.emojiSelected = this.emojiSelected.bind(this);
- const {
- message: msg
- } = this.props;
- if (msg instanceof Message && msg._reactions && msg.messageId.length === 11 && msg.isSentOrReceived() && !Object.hasOwnProperty.call(msg, 'reacts')) {
- msg.reacts.forceLoad().then(() => {
- this.addContactListenerIfMissing(this._reactionContacts());
- }).catch(dump.bind(null, `reactions.load.${msg.messageId}`));
- }
+ this.domRef = react1___default().createRef();
+ this.isUserScroll = true;
+ this.scrollEventIncId = 0;
}
- UNSAFE_componentWillMount() {
- if (super.UNSAFE_componentWillMount) {
- super.UNSAFE_componentWillMount();
- }
- const {chatRoom} = this.props;
- if (chatRoom) {
- chatRoom.rebind(`onChatShown.${ this.__cmmId}`, () => {
- if (!this._contactChangeListeners) {
- this.addContactListeners();
- }
- }).rebind(`onChatHidden.${ this.__cmmId}`, () => {
- if (this._contactChangeListeners) {
- this.removeContactListeners();
- }
- });
+ get$Node() {
+ if (!this.$Node) {
+ let _this$domRef;
+ this.$Node = $((_this$domRef = this.domRef) == null ? void 0 : _this$domRef.current);
}
- this.addContactListeners();
- }
- haveMeetingsCall() {
- return document.querySelector('.meetings-call') && document.querySelector('.chat-opened');
+ return this.$Node;
}
- removeContactListeners() {
- const users = this._contactChangeListeners;
- if (d > 3) {
- console.warn('%s.removeContactListeners', this.getReactId(), [this], users);
- }
- for (let i = users.length; i--;) {
- users[i].removeEventHandler(this);
+ doProgramaticScroll(newPos, forced, isX, skipReinitialised) {
+ if (!this.isMounted()) {
+ return;
}
- this._contactChangeListeners = false;
+ const self = this;
+ const $elem = self.get$Node();
+ let animFrameInner = false;
+ const prop = !isX ? 'scrollTop' : 'scrollLeft';
+ const event = `scroll.progscroll${ self.scrollEventIncId++}`;
+ $elem.rebind(event, () => {
+ if (animFrameInner) {
+ cancelAnimationFrame(animFrameInner);
+ animFrameInner = false;
+ }
+ $elem.off(event);
+ if (!skipReinitialised) {
+ self.reinitialised(true);
+ } else if (typeof skipReinitialised === 'function') {
+ onIdle(skipReinitialised);
+ }
+ self.isUserScroll = true;
+ });
+ self.isUserScroll = false;
+ $elem[0][prop] = Math.round(newPos);
+ Ps.update($elem[0]);
+ animFrameInner = requestAnimationFrame(() => {
+ animFrameInner = false;
+ self.isUserScroll = true;
+ $elem.off(event);
+ });
+ return true;
}
- _reactionContacts() {
- const {
- message
- } = this.props;
- const {
- reacts
- } = message;
- const handles = [];
- const reactions = Object.values(reacts.reactions);
- for (let i = 0; i < reactions.length; i++) {
- handles.push(...Object.keys(reactions[i]));
+ componentDidMount() {
+ let _this$props$didMount, _this$props;
+ super.componentDidMount();
+ const self = this;
+ const $elem = self.get$Node();
+ $elem.height('100%');
+ const options = Object.assign({}, {
+ 'handlers': ['click-rail', 'drag-thumb', 'keyboard', 'wheel', 'touch'],
+ 'minScrollbarLength': 20
+ }, self.props.options);
+ Ps.initialize($elem[0], options);
+ if (self.props.onFirstInit) {
+ self.props.onFirstInit(self, $elem);
}
- this._reactionContactHandles = array.unique(handles);
- return this._reactionContactHandles;
- }
- addContactListeners() {
- const users = this._contactChangeListeners || [];
- const addUser = user => {
- if (user instanceof MegaDataMap && users.indexOf(user) < 0) {
- users.push(user);
+ $elem.rebind(`ps-scroll-y.ps${ self.getUniqueId()}`, (e) => {
+ if ($elem.attr('data-scroll-disabled') === "true") {
+ e.stopPropagation();
+ e.preventDefault();
+ e.originalEvent.stopPropagation();
+ e.originalEvent.preventDefault();
+ return false;
}
- };
- addUser(this.getContact());
- if (this.haveMoreContactListeners) {
- const moreIds = this.haveMoreContactListeners();
- if (moreIds) {
- for (let i = moreIds.length; i--;) {
- const handle = moreIds[i];
- addUser(handle in M.u && M.u[handle]);
- }
+ if (self.props.onUserScroll && self.isUserScroll === true && $elem.is(e.target)) {
+ self.props.onUserScroll(self, $elem, e);
}
+ });
+ $elem.rebind(`disable-scroll.ps${ self.getUniqueId()}`, () => {
+ Ps.destroy($elem[0]);
+ });
+ $elem.rebind(`enable-scroll.ps${ self.getUniqueId()}`, () => {
+ Ps.initialize($elem[0], options);
+ });
+ $elem.rebind(`forceResize.ps${ self.getUniqueId()}`, (e, forced, scrollPositionYPerc, scrollToElement) => {
+ self.onResize(forced, scrollPositionYPerc, scrollToElement);
+ });
+ self.onResize();
+ this.attachAnimationEvents();
+ (_this$props$didMount = (_this$props = this.props).didMount) == null || _this$props$didMount.call(_this$props, this.getUniqueId(), this);
+ }
+ componentWillUnmount() {
+ let _this$props$willUnmou, _this$props2;
+ super.componentWillUnmount();
+ const $elem = this.get$Node();
+ $elem.off(`ps-scroll-y.ps${ this.getUniqueId()}`);
+ const ns = `.ps${ this.getUniqueId()}`;
+ $elem.parents('.have-animation').unbind(`animationend${ ns } webkitAnimationEnd${ ns } oAnimationEnd${ ns}`);
+ (_this$props$willUnmou = (_this$props2 = this.props).willUnmount) == null || _this$props$willUnmou.call(_this$props2, this.getUniqueId(), this);
+ }
+ attachAnimationEvents() {}
+ eventuallyReinitialise(forced, scrollPositionYPerc, scrollToElement) {
+ const self = this;
+ if (!self.isComponentEventuallyVisible()) {
+ return;
}
- for (let i = this._reactionContactHandles.length; i--;) {
- addUser(this._reactionContactHandles[i] in M.u && M.u[this._reactionContactHandles[i]]);
- }
- if (d > 3) {
- console.warn('%s.addContactListeners', this.getReactId(), [this], users);
- }
- for (let i = users.length; i--;) {
- users[i].addChangeListener(this);
+ const $elem = self.get$Node();
+ const h = self.getContentHeight();
+ if (forced || self._currHeight !== h) {
+ self._currHeight = h;
+ self._doReinit(scrollPositionYPerc, scrollToElement, forced, $elem);
}
- this._contactChangeListeners = users;
}
- addContactListenerIfMissing(contacts) {
- if (!this._contactChangeListeners) {
- return false;
- }
- if (!Array.isArray(contacts)) {
- contacts = [contacts];
+ _doReinit(scrollPositionYPerc, scrollToElement, forced, $elem) {
+ let fired = false;
+ if (this.props.onReinitialise) {
+ fired = this.props.onReinitialise(this, $elem, forced, scrollPositionYPerc, scrollToElement);
}
- const added = [];
- for (let i = 0; i < contacts.length; i++) {
- const user = M.u[contacts[i]];
- if (user && !this._contactChangeListeners.includes(user)) {
- this._contactChangeListeners.push(user);
- user.addChangeListener(this);
- added.push(user.h);
+ if (fired === false) {
+ if (scrollPositionYPerc) {
+ if (scrollPositionYPerc === -1) {
+ this.scrollToBottom(true);
+ } else {
+ this.scrollToPercentY(scrollPositionYPerc, true);
+ }
+ } else if (scrollToElement) {
+ this.scrollToElement(scrollToElement, true);
}
}
- if (d > 1) {
- console.warn('%s.addContactListenerIfMissing', this.getReactId(), [this], added);
- }
}
- eventuallyUpdate() {
- super.eventuallyUpdate();
- this.__cmmUpdateTickCount = -2;
+ scrollToBottom(skipReinitialised) {
+ this.reinitialise(skipReinitialised, true);
}
- handleChangeEvent(x, z, k) {
- if (k === 'ts' || k === 'ats') {
+ reinitialise(skipReinitialised, bottom) {
+ let _this$domRef2;
+ const $elem = (_this$domRef2 = this.domRef) == null ? void 0 : _this$domRef2.current;
+ if (!$elem) {
return;
}
- if (this.isComponentEventuallyVisible()) {
- if (++this.__cmmUpdateTickCount > 5) {
- this.eventuallyUpdate();
- delay.cancel(this.__cmmId);
- } else {
- delay(this.__cmmId, () => this.eventuallyUpdate(), 90);
- }
- } else {
- this._requiresUpdateOnResize = true;
+ this.isUserScroll = false;
+ if (bottom) {
+ $elem.scrollTop = this.getScrollHeight();
+ }
+ Ps.update($elem);
+ this.isUserScroll = true;
+ if (!skipReinitialised) {
+ this.reinitialised(true);
}
}
- componentWillUnmount() {
- super.componentWillUnmount();
- const {chatRoom} = this.props;
- if (chatRoom) {
- chatRoom.off(`onChatShown.${ this.__cmmId}`).off(`onChatHidden.${ this.__cmmId}`);
+ getDOMRect(node) {
+ let _this$domRef3;
+ node = node || ((_this$domRef3 = this.domRef) == null ? void 0 : _this$domRef3.current);
+ return node && node.getBoundingClientRect();
+ }
+ getScrollOffset(value) {
+ let _this$domRef4;
+ const $elem = (_this$domRef4 = this.domRef) == null ? void 0 : _this$domRef4.current;
+ if ($elem) {
+ return this.getDOMRect($elem.children[0])[value] - this.getDOMRect($elem)[value];
}
- if (this._contactChangeListeners) {
- this.removeContactListeners();
+ return 0;
+ }
+ getScrollHeight() {
+ const res = this.getScrollOffset('height');
+ if (res < 1) {
+ return this._lastKnownScrollHeight || 0;
}
+ this._lastKnownScrollHeight = res;
+ return res;
}
- getContact() {
- if (this.props.contact) {
- return this.props.contact;
+ getScrollWidth() {
+ const res = this.getScrollOffset('width');
+ if (res < 1) {
+ return this._lastKnownScrollWidth || 0;
}
- const {message} = this.props;
- return Message.getContactForMessage(message);
+ this._lastKnownScrollWidth = res;
+ return res;
}
- getTimestampAsString() {
- return toLocaleTime(this.getTimestamp());
+ getContentHeight() {
+ const $elem = this.get$Node();
+ return $elem[0].scrollHeight;
}
- getTimestamp(forUpdated) {
- const {
- message
- } = this.props;
- const timestamp = (message.getDelay == null ? void 0 : message.getDelay()) || message.delay || unixtime();
- return forUpdated && message.updated > 0 ? timestamp + message.updated : timestamp;
+ getContentWidth() {
+ const $elem = this.get$Node();
+ return $elem[0].scrollWidth;
}
- componentDidUpdate() {
- const self = this;
- const {chatRoom} = self.props.message;
- if (!self.onAfterRenderWasTriggered) {
- const msg = self.props.message;
- let shouldRender = true;
- if (msg.isManagement && msg.isManagement() === true && msg.isRenderableManagement() === false) {
- shouldRender = false;
- }
- if (shouldRender) {
- chatRoom.trigger("onAfterRenderMessage", self.props.message);
- self.onAfterRenderWasTriggered = true;
- }
- }
+ setCssContentHeight(h) {
+ const $elem = this.get$Node();
+ return $elem.css('height', h);
}
- getCurrentUserReactions() {
- const {
- reactions
- } = this.props.message.reacts;
- return Object.keys(reactions).filter(utf => {
- let _reactions$utf;
- return (_reactions$utf = reactions[utf]) == null ? void 0 : _reactions$utf[u_handle];
- });
+ isAtTop() {
+ let _this$domRef5;
+ return ((_this$domRef5 = this.domRef) == null ? void 0 : _this$domRef5.current.scrollTop) === 0;
}
- emojiSelected(e, slug, meta) {
- const {
- chatRoom,
- message,
- onEmojiBarChange
- } = this.props;
- if (chatRoom.isReadOnly()) {
- return false;
- }
- const {
- reactions
- } = this.props.message.reacts;
- const CURRENT_USER_REACTIONS = this.getCurrentUserReactions().length;
- const REACTIONS_LIMIT = {
- TOTAL: 50,
- PER_PERSON: 24
- };
- const addReaction = () => chatRoom.messagesBuff.userAddReaction(message.messageId, slug, meta);
- const emoji = megaChat._emojiData.emojisSlug[slug] || meta;
- if (emoji && message.reacts.getReaction(u_handle, emoji.u)) {
- if (onEmojiBarChange && Object.keys(reactions).length === 1 && Object.keys(reactions[emoji.u]).length === 1) {
- onEmojiBarChange(false);
- }
- return chatRoom.messagesBuff.userDelReaction(message.messageId, slug, meta);
- }
- if (emoji && reactions[emoji.u] && CURRENT_USER_REACTIONS < REACTIONS_LIMIT.PER_PERSON) {
- return addReaction();
- }
- if (CURRENT_USER_REACTIONS >= REACTIONS_LIMIT.PER_PERSON) {
- return msgDialog('info', '', l[24205].replace('%1', REACTIONS_LIMIT.PER_PERSON));
- }
- if (Object.keys(reactions).length >= REACTIONS_LIMIT.TOTAL) {
- return msgDialog('info', '', l[24206].replace('%1', REACTIONS_LIMIT.TOTAL));
- } else if (onEmojiBarChange && Object.keys(reactions).length === 0) {
- onEmojiBarChange(true);
- }
- return addReaction();
+ isAtBottom() {
+ return Math.round(this.getScrollPositionY()) === Math.round(this.getScrollHeight());
}
- _emojiOnActiveStateChange(newVal) {
- this.setState(() => {
- return {
- reactionsDropdownActive: newVal
- };
- });
+ isCloseToBottom(minPixelsOff) {
+ return this.getScrollHeight() - this.getScrollPositionY() <= minPixelsOff;
}
- getEmojisImages() {
- const {
- chatRoom,
- message
- } = this.props;
- const isReadOnlyClass = chatRoom.isReadOnly() ? " disabled" : "";
- let emojisImages = message._reactions && message.reacts.reactions && Object.keys(message.reacts.reactions).map(utf => {
- const reaction = message.reacts.reactions[utf];
- const count = Object.keys(reaction).length;
- if (!count) {
- return null;
- }
- const filename = twemoji.convert.toCodePoint(utf);
- const currentUserReacted = !!reaction[u_handle];
- const names = [];
- if (reaction) {
- ChatdIntegration._ensureContactExists(Object.keys(reaction));
- const rKeys = Object.keys(reaction);
- for (let i = 0; i < rKeys.length; i++) {
- const uid = rKeys[i];
- if (reaction[uid]) {
- if (uid === u_handle) {
- names.push(l[24071] || 'You');
- } else if (uid in M.u) {
- names.push(M.getNameByHandle(uid) || megaChat.plugins.userHelper.SIMPLETIP_USER_LOADER);
- }
- }
- }
- }
- let emojiData = megaChat._emojiData.emojisUtf[utf];
- if (!emojiData) {
- emojiData = Object.create(null);
- emojiData.u = utf;
- }
- let slug = emojiData && emojiData.n || "";
- let tipText;
- slug = slug ? `:${slug}:` : utf;
- if (Object.keys(reaction).length === 1 && reaction[u_handle]) {
- tipText = (l[24068] || "You (click to remove) [G]reacted with %s[/G]").replace("%s", slug);
- } else {
- tipText = mega.utils.trans.listToString(names, (l[24069] || "%s [G]reacted with %s2[/G]").replace("%s2", slug));
- }
- const notFoundEmoji = slug && slug[0] !== ":";
- return react0().createElement("div", {
- key: slug,
- onClick: ((e, slug, meta) => () => this.emojiSelected(e, slug, meta))(null, slug, emojiData),
- className: `
- reactions-bar__reaction
- simpletip
- ${currentUserReacted ? 'user-reacted' : ''}
- ${notFoundEmoji ? 'emoji-loading-error' : ''}
- ${isReadOnlyClass}
- `,
- "data-simpletip": tipText,
- "data-simpletipoffset": "3",
- "data-simpletipposition": "top"
- }, react0().createElement("img", {
- width: "10",
- height: "10",
- className: "emoji emoji-loading",
- draggable: "false",
- onError: e => {
- const textNode = document.createElement("em");
- textNode.classList.remove('emoji-loading');
- textNode.append(document.createTextNode(utf));
- e.target.replaceWith(textNode);
- textNode.parentNode.classList.add('emoji-loading-error');
- },
- onLoad: e => {
- e.target.classList.remove('emoji-loading');
- },
- src: `${staticpath }images/mega/twemojis/2_v2/72x72/${ filename }.png`
- }), react0().createElement("span", {
- className: "message text-block"
- }, count));
- });
- emojisImages = emojisImages && emojisImages.filter((v) => {
- return !!v;
- });
- if (emojisImages && emojisImages.length > 0) {
- const reactionBtn = !chatRoom.isReadOnly() ? react0().createElement(_ui_buttons_jsx2__.$, {
- className: "popup-button reactions-button hover-colorized simpletip",
- icon: "sprite-fm-theme icon-emoji-reactions reactions-icon",
- disabled: false,
- key: "add-reaction-button",
- attrs: {
- 'data-simpletip': l[24070] || "Add reaction...",
- 'data-simpletipoffset': "3",
- 'data-simpletipposition': "top"
- }
- }, react0().createElement(_ui_emojiDropdown_jsx3__.L, {
- horizOffset: this.haveMeetingsCall() ? -150 : 0,
- onActiveChange: this._emojiOnActiveStateChange,
- className: "popup emoji reactions-dropdown",
- onClick: this.emojiSelected
- })) : null;
- emojisImages.push(reactionBtn);
+ getScrolledPercentY() {
+ return 100 / this.getScrollHeight() * this.getScrollPositionY();
+ }
+ getScrollPositionY() {
+ let _this$domRef6;
+ return (_this$domRef6 = this.domRef) == null ? void 0 : _this$domRef6.current.scrollTop;
+ }
+ getScrollPositionX() {
+ let _this$domRef7;
+ return (_this$domRef7 = this.domRef) == null ? void 0 : _this$domRef7.current.scrollLeft;
+ }
+ getClientWidth() {
+ let _this$domRef8;
+ return (_this$domRef8 = this.domRef) == null ? void 0 : _this$domRef8.current.clientWidth;
+ }
+ getClientHeight() {
+ let _this$domRef9;
+ return (_this$domRef9 = this.domRef) == null ? void 0 : _this$domRef9.current.clientHeight;
+ }
+ scrollToPercentY(posPerc, skipReinitialised) {
+ const $elem = this.get$Node();
+ const targetPx = this.getScrollHeight() / 100 * posPerc;
+ if ($elem[0].scrollTop !== targetPx) {
+ this.doProgramaticScroll(targetPx, 0, 0, skipReinitialised);
}
- return emojisImages ? react0().createElement("div", {
- className: "reactions-bar",
- id: "reactions-bar",
- onMouseEnter: () => {
- if (this._loadedReacts) {
- return false;
- }
- this._loadedReacts = megaChat.plugins.userHelper.fetchAllNames(this._reactionContacts(), chatRoom).catch(dump).finally(() => {
- this._loadedReacts = true;
- this.safeForceUpdate();
- });
- }
- }, emojisImages) : null;
}
- getMessageActionButtons() {
+ scrollToPercentX(posPerc, skipReinitialised) {
+ const $elem = this.get$Node();
+ const targetPx = this.getScrollWidth() / 100 * posPerc;
+ if ($elem[0].scrollLeft !== targetPx) {
+ this.doProgramaticScroll(targetPx, false, true, skipReinitialised);
+ }
+ }
+ scrollToY(posY, skipReinitialised) {
+ const $elem = this.get$Node();
+ if ($elem[0].scrollTop !== posY) {
+ this.doProgramaticScroll(posY, 0, 0, skipReinitialised);
+ }
+ }
+ scrollToElement(element, skipReinitialised) {
+ if (element && element.offsetParent) {
+ this.doProgramaticScroll(element.offsetTop, 0, 0, skipReinitialised);
+ }
+ }
+ disable() {
+ if (this.isMounted()) {
+ const $elem = this.get$Node();
+ $elem.attr('data-scroll-disabled', true);
+ $elem.addClass('ps-disabled');
+ Ps.disable($elem[0]);
+ }
+ }
+ enable() {
+ if (this.isMounted()) {
+ const $elem = this.get$Node();
+ $elem.removeAttr('data-scroll-disabled');
+ $elem.removeClass('ps-disabled');
+ Ps.enable($elem[0]);
+ }
+ }
+ reinitialised(forced) {
+ if (this.props.onReinitialise) {
+ this.props.onReinitialise(this, this.get$Node(), forced ? forced : false);
+ }
+ }
+ onResize(forced, scrollPositionYPerc, scrollToElement) {
+ if (forced && forced.originalEvent) {
+ forced = true;
+ scrollPositionYPerc = undefined;
+ }
+ this.eventuallyReinitialise(forced, scrollPositionYPerc, scrollToElement);
+ }
+ inViewport(domNode) {
+ return verge.inViewport(domNode);
+ }
+ componentDidUpdate() {
+ if (this.props.requiresUpdateOnResize || this.requiresUpdateOnResize) {
+ this.onResize(true);
+ }
+ this.attachAnimationEvents();
+ }
+ customIsEventuallyVisible() {
+ const {chatRoom} = this.props;
+ return !chatRoom || chatRoom.isCurrentlyActive;
+ }
+ render() {
const {
- chatRoom,
- message
+ style,
+ className,
+ children
} = this.props;
- return message instanceof Message && message.isSentOrReceived() && !chatRoom.isReadOnly() ? react0().createElement(_ui_buttons_jsx2__.$, {
- className: "popup-button reactions-button tiny-button simpletip",
- icon: `${"sprite-fm-theme reactions-icon"} icon-emoji-reactions`,
- iconHovered: `${"sprite-fm-theme reactions-icon"} icon-emoji-reactions-active`,
- disabled: false,
- key: "add-reaction-button",
- attrs: {
- 'data-simpletip': l[24070] || "Add reaction...",
- 'data-simpletipoffset': "3",
- 'data-simpletipposition': "top"
- }
- }, react0().createElement(_ui_emojiDropdown_jsx3__.L, {
- horizOffset: this.haveMeetingsCall() ? -110 : 0,
- noArrow: true,
- onActiveChange: this._emojiOnActiveStateChange,
- className: "popup emoji reactions-dropdown",
- onClick: this.emojiSelected
- })) : null;
+ return JSX_("div", {
+ ref: this.domRef,
+ style,
+ className
+ }, children);
}
-}
-
+}, _PerfectScrollbar.defaultProps = {
+ className: "perfectScrollbarContainer",
+ requiresUpdateOnResize: true
+}, _PerfectScrollbar), (0,_babel_runtime_helpers_applyDecoratedDescriptor0__ .A)(_class.prototype, "eventuallyReinitialise", [_dec], Object.getOwnPropertyDescriptor(_class.prototype, "eventuallyReinitialise"), _class.prototype), (0,_babel_runtime_helpers_applyDecoratedDescriptor0__ .A)(_class.prototype, "onResize", [_dec2], Object.getOwnPropertyDescriptor(_class.prototype, "onResize"), _class.prototype), _class);
-},
+ },
-757
+ 6411
(_, EXP_, REQ_) {
"use strict";
-REQ_.d(EXP_, {
-A: () => ScheduleMetaChange
-});
-const react0__ = REQ_(594);
-const react0 = REQ_.n(react0__);
-const _mixin_jsx1__ = REQ_(446);
-const _contacts_jsx2__ = REQ_(251);
-const _ui_utils_jsx3__ = REQ_(314);
-const _ui_buttons_jsx4__ = REQ_(994);
-
-
-
-
-
-class ScheduleMetaChange extends _mixin_jsx1__.M {
+ REQ_.d(EXP_, {
+ Ay: () => __WEBPACK_DEFAULT_EXPORT__,
+ P9: () => ParsedHTML,
+ T9: () => withOverflowObserver,
+ lI: () => reactStringWrap,
+ oM: () => OFlowParsedHTML,
+ sp: () => OFlowEmoji,
+ zT: () => Emoji
+ });
+ const react0__ = REQ_(1594);
+ const react0___default = REQ_.n(react0__);
+ const react_dom1__ = REQ_(5206);
+ const react_dom1___default = REQ_.n(react_dom1__);
+ const _chat_mixins_js2__ = REQ_(8264);
+
+
+
+class RenderTo extends react0___default().Component {
constructor(...args) {
super(...args);
- this.state = {
- link: ''
- };
- }
- componentDidMount() {
- super.componentDidMount();
- if (this.props.mode === ScheduleMetaChange.MODE.CREATED) {
- if (is_chatlink) {
- this.setState({
- link: `${getBaseUrl()}/chat/${is_chatlink.ph}#${is_chatlink.key}`
- });
- } else {
- const {
- chatRoom
- } = this.props;
- chatRoom.updatePublicHandle().then(() => {
- if (this.isMounted() && !this.state.link && chatRoom.publicLink) {
- this.setState({
- link: `${getBaseUrl()}/${chatRoom.publicLink}`
- });
- }
- }).catch(dump);
- }
- }
- if (this.props.message.meta.ap) {
- const {
- meetingsManager
- } = megaChat.plugins;
- this.redrawListener = `${meetingsManager.EVENTS.OCCURRENCES_UPDATE}.redraw${this.getUniqueId()}`;
- megaChat.rebind(this.redrawListener, () => {
- onIdle(() => {
- const {
- meta
- } = this.props.message;
- if (!meta.ap) {
- return;
- }
- this.props.message.meta = meetingsManager.noCsMeta(meta.handle, meta.ap, megaChat.chats[meta.cid]);
- this.safeForceUpdate();
- });
- megaChat.off(this.redrawListener);
- delete this.redrawListener;
- });
- }
+ this.$$rootRef = undefined;
+ this.popupElement = undefined;
}
- componentWillUnmount() {
- super.componentWillUnmount();
- if (this.redrawListener) {
- megaChat.off(this.redrawListener);
- }
+ _setClassNames() {
+ this.popupElement.className = this.props.className || '';
}
- specShouldComponentUpdate(nextProps) {
- if (this.props.mode === ScheduleMetaChange.MODE.CREATED && this.props.link !== nextProps.link) {
- return true;
- }
- return null;
+ _renderLayer() {
+ this.$$rootRef.render(this.props.children);
+ queueMicrotask(() => {
+ let _this$props$popupDidM, _this$props;
+ return (_this$props$popupDidM = (_this$props = this.props).popupDidMount) == null ? void 0 : _this$props$popupDidM.call(_this$props, this.popupElement);
+ });
}
- componentDidUpdate(prevProps) {
- if (this.props.mode === ScheduleMetaChange.MODE.CREATED && prevProps.link !== this.props.link) {
- this.setState({
- link: this.props.link ? `${getBaseUrl()}/${this.props.link}` : ''
- });
- }
+ componentDidUpdate() {
+ this._setClassNames();
+ this._renderLayer();
}
- onAddToCalendar() {
- const {
- chatRoom
- } = this.props;
- const {
- id,
- title
- } = chatRoom && chatRoom.scheduledMeeting || {};
- if (id) {
- delay(`fetchical${id}`, () => {
- eventlog(500038);
- asyncApiReq({
- a: 'mcsmfical',
- id
- }).then(([, res]) => {
- delay(`saveical${id}`, () => {
- M.saveAs(base64urldecode(res), `${title.replace(/\W/g, '')}.ics`).then(nop).catch(() => {
- msgDialog('error', '', l.calendar_add_failed, '');
- });
- }, 1000);
- }).catch(() => {
- msgDialog('error', '', l.calendar_add_failed, '');
- });
- }, 250);
- }
+ componentWillUnmount() {
+ let _this$props$popupWill, _this$props2;
+ onIdle(() => this.$$rootRef.unmount());
+ (_this$props$popupWill = (_this$props2 = this.props).popupWillUnmount) == null || _this$props$popupWill.call(_this$props2, this.popupElement);
+ this.props.element.removeChild(this.popupElement);
}
- static getTitleText(meta) {
- const {
- mode,
- recurring,
- occurrence,
- converted,
- prevTiming
- } = meta;
- const {
- MODE
- } = ScheduleMetaChange;
- switch (mode) {
- case MODE.CREATED:
- {
- return recurring ? l.schedule_mgmt_new_recur : l.schedule_mgmt_new;
- }
- case MODE.EDITED:
- {
- if (converted) {
- return recurring ? l.schedule_mgmt_update_convert_recur : l.schedule_mgmt_update_convert;
- }
- if (occurrence) {
- return l.schedule_mgmt_update_occur;
- }
- if (prevTiming) {
- return recurring ? l.schedule_mgmt_update_recur : l.schedule_mgmt_update;
- }
- return l.schedule_mgmt_update_desc;
- }
- case MODE.CANCELLED:
- {
- if (recurring) {
- return occurrence ? l.schedule_mgmt_cancel_occur : l.schedule_mgmt_cancel_recur;
- }
- return l.schedule_mgmt_cancel;
- }
+ componentDidMount() {
+ this.popupElement = document.createElement('div');
+ this.$$rootRef = (0,react_dom1__.createRoot)(this.popupElement);
+ this._setClassNames();
+ if (this.props.style) {
+ $(this.popupElement).css(this.props.style);
}
- return '';
+ this.props.element.appendChild(this.popupElement);
+ this._renderLayer();
}
- renderTimingBlock() {
+ render() {
+ return null;
+ }
+}
+const withOverflowObserver = Component => class extends _chat_mixins_js2__ .u9 {
+ constructor(props) {
+ super(props);
+ this.displayName = 'OverflowObserver';
+ this.ref = react0___default().createRef();
+ this.state = {
+ overflowed: false
+ };
+ this.handleMouseEnter = this.handleMouseEnter.bind(this);
+ }
+ handleMouseEnter() {
+ const element = this.ref && this.ref.current;
+ if (element) {
+ this.setState({
+ overflowed: element.scrollWidth > element.offsetWidth
+ });
+ }
+ }
+ shouldComponentUpdate(nextProps, nextState) {
+ return nextState.overflowed !== this.state.overflowed || nextProps.children !== this.props.children || nextProps.content !== this.props.content;
+ }
+ render() {
const {
- message,
- mode
+ simpletip
} = this.props;
- const {
- meta
- } = message;
- const {
- MODE
- } = ScheduleMetaChange;
- if (mode === MODE.CANCELLED && !meta.occurrence) {
- return null;
- }
- const [now, prev] = megaChat.plugins.meetingsManager.getOccurrenceStrings(meta);
- return react0().createElement("div", {
- className: "schedule-timing-block"
- }, meta.prevTiming && react0().createElement("s", null, prev || ''), now);
+ return JSX_("div", {
+ ref: this.ref,
+ className: `
+ overflow-observer
+ ${this.state.overflowed ? 'simpletip simpletip-tc' : ''}
+ `,
+ "data-simpletipposition": (simpletip == null ? void 0 : simpletip.position) || 'top',
+ "data-simpletipoffset": simpletip == null ? void 0 : simpletip.offset,
+ "data-simpletip-class": (simpletip == null ? void 0 : simpletip.className) || 'medium-width center-align',
+ onMouseEnter: this.handleMouseEnter
+ }, JSX_(Component, this.props));
}
- checkAndFakeOccurrenceMeta(meta) {
+};
+const Emoji = ({
+ children
+}) => {
+ return JSX_(ParsedHTML, {
+ content: megaChat.html(children)
+ });
+};
+class ParsedHTML extends react0___default().Component {
+ constructor(...args) {
+ super(...args);
+ this.ref = react0___default().createRef();
+ }
+ updateInternalState() {
const {
- MODE
- } = ScheduleMetaChange;
- if (meta.occurrence && meta.mode === MODE.CANCELLED && !meta.calendar) {
- const meeting = megaChat.plugins.meetingsManager.getMeetingOrOccurrenceParent(meta.handle);
- if (meeting) {
- const occurrences = meeting.getOccurrencesById(meta.handle);
- if (occurrences) {
- meta.calendar = {
- date: new Date(occurrences[0].start).getDate(),
- month: time2date(Math.floor(occurrences[0].start / 1000), 12)
- };
- meta.timeRules.startTime = Math.floor(occurrences[0].start / 1000);
- meta.timeRules.endTime = Math.floor(occurrences[0].end / 1000);
+ children,
+ content
+ } = this.props;
+ const ref = this.ref && this.ref.current;
+ if (!children && !content) {
+ return d > 1 && console.warn('Emoji: No content passed.');
+ }
+ if (ref) {
+ if (ref.childNodes.length) {
+ while (ref.firstChild) {
+ ref.removeChild(ref.firstChild);
}
}
+ ref.appendChild(parseHTML(children || content));
}
}
+ shouldComponentUpdate(nextProps) {
+ return nextProps && (nextProps.children !== this.props.children || nextProps.content !== this.props.content);
+ }
+ componentDidUpdate() {
+ this.updateInternalState();
+ }
+ componentDidMount() {
+ this.updateInternalState();
+ }
render() {
const {
- chatRoom,
- message,
- mode,
- contact
+ className,
+ onClick,
+ tag
} = this.props;
- const {
- meta,
- messageId
- } = message;
- const {
- scheduledMeeting
- } = chatRoom;
- const {
- MODE
- } = ScheduleMetaChange;
- const {
- link
- } = this.state;
- if (meta.gone) {
- return null;
- }
- this.checkAndFakeOccurrenceMeta(meta);
- return react0().createElement("div", null, react0().createElement("div", {
- className: "message body",
- "data-id": `id${messageId}`,
- key: messageId
- }, react0().createElement(_contacts_jsx2__.Avatar, {
- contact: contact.u,
- className: "message avatar-wrapper small-rounded-avatar",
- chatRoom
- }), react0().createElement("div", {
- className: "message schedule-message content-area small-info-txt selectable-txt"
- }, react0().createElement(_contacts_jsx2__.ContactButton, {
- className: "message",
- chatRoom,
- contact,
- label: react0().createElement(_ui_utils_jsx3__.zT, null, M.getNameByHandle(contact.u))
- }), react0().createElement("div", {
- className: "message date-time simpletip",
- "data-simpletip": time2date(this.getTimestamp())
- }, this.getTimestampAsString()), react0().createElement("div", {
- className: "message text-block"
- }, ScheduleMetaChange.getTitleText(meta), " ", !!d && meta.handle), react0().createElement("div", {
- className: "message body-block"
- }, (meta.prevTiming || meta.calendar || meta.topic && meta.onlyTitle || meta.recurring) && react0().createElement("div", {
- className: "schedule-detail-block"
- }, meta.calendar && scheduledMeeting && (meta.recurring && !scheduledMeeting.recurring || meta.occurrence && meta.mode === MODE.CANCELLED || !meta.recurring) && react0().createElement("div", {
- className: "schedule-calendar-icon"
- }, react0().createElement("div", {
- className: "schedule-date"
- }, meta.calendar.date), react0().createElement("div", {
- className: "schedule-month"
- }, meta.calendar.month)), react0().createElement("div", {
- className: "schedule-detail-main"
- }, react0().createElement("div", {
- className: "schedule-meeting-title"
- }, mode === MODE.CANCELLED ? react0().createElement("s", null, meta.topic || chatRoom.topic) : meta.topic || chatRoom.topic), this.renderTimingBlock()), chatRoom.iAmInRoom() && scheduledMeeting && mode !== MODE.CANCELLED && react0().createElement(_ui_buttons_jsx4__.$, {
- className: "mega-button",
- onClick: () => this.onAddToCalendar()
- }, react0().createElement("span", null, mode === MODE.CREATED && !meta.occurrence ? l.schedule_add_calendar : l.schedule_update_calendar))), mode === MODE.CREATED && scheduledMeeting && scheduledMeeting.description && react0().createElement("div", {
- className: "schedule-description"
- }, react0().createElement(_ui_utils_jsx3__.P9, null, megaChat.html(scheduledMeeting.description).replace(/\n/g, '
'))), link && react0().createElement("div", null, react0().createElement("div", {
- className: "schedule-link-instruction"
- }, l.schedule_mgmt_link_instruct), react0().createElement("div", {
- className: "schedule-meeting-link"
- }, react0().createElement("span", null, link), react0().createElement(_ui_buttons_jsx4__.$, {
- className: "mega-button positive",
- onClick: () => {
- copyToClipboard(link, l[7654]);
- delay('chat-event-sm-copy-link', () => eventlog(500039));
- }
- }, react0().createElement("span", null, l[63]))), react0().createElement("span", null, l.schedule_link_note))))));
+ return JSX_(tag || 'span', {
+ ref: this.ref,
+ className,
+ onClick
+ });
}
}
-ScheduleMetaChange.MODE = {
- CREATED: 1,
- EDITED: 2,
- CANCELLED: 3
+const reactStringWrap = (src, find, WrapClass, wrapProps) => {
+ const endTag = find.replace('[', '[/');
+ return JSX_(react0___default().Fragment, null, src.split(find)[0], JSX_(WrapClass, wrapProps, src.substring(src.indexOf(find) + find.length, src.indexOf(endTag))), src.split(endTag)[1]);
+};
+const OFlowEmoji = withOverflowObserver(Emoji);
+const OFlowParsedHTML = withOverflowObserver(ParsedHTML);
+ const __WEBPACK_DEFAULT_EXPORT__ = {
+ RenderTo,
+ SoonFcWrap: _chat_mixins_js2__ .hG,
+ OFlowEmoji,
+ OFlowParsedHTML
};
-window.ScheduleMetaChange = ScheduleMetaChange;
-},
+ },
-707
-(_, EXP_, REQ_) {
+ 1594
+(module) {
"use strict";
-REQ_.d(EXP_, {
-a: () => MetaRichpreviewLoading
-});
-const React = REQ_(594);
-const ConversationMessageMixin = REQ_(446).M;
-class MetaRichpreviewLoading extends ConversationMessageMixin {
- render() {
- return React.createElement("div", {
- className: "loading-spinner light small"
- }, React.createElement("div", {
- className: "main-loader"
- }));
- }
+module.exports = React;
+
+ },
+
+ 5206
+(module) {
+
+"use strict";
+module.exports = ReactDOM;
+
+ },
+
+ 793
+(__webpack_module__, EXP_, REQ_) {
+
+"use strict";
+ REQ_.d(EXP_, {
+ A: () => _applyDecoratedDescriptor
+ });
+function _applyDecoratedDescriptor(i, e, r, n, l) {
+ let a = {};
+ return Object.keys(n).forEach((i) => {
+ a[i] = n[i];
+ }), a.enumerable = !!a.enumerable, a.configurable = !!a.configurable, ("value" in a || a.initializer) && (a.writable = !0), a = r.slice().reverse().reduce((r, n) => {
+ return n(i, e, r) || r;
+ }, a), l && void 0 !== a.initializer && (a.value = a.initializer ? a.initializer.call(l) : void 0, a.initializer = void 0), void 0 === a.initializer ? (Object.defineProperty(i, e, a), null) : a;
}
-},
+ },
-795
-(_, EXP_, REQ_) {
+ 8168
+(__webpack_module__, EXP_, REQ_) {
"use strict";
+ REQ_.d(EXP_, {
+ A: () => _extends
+ });
+function _extends() {
+ return _extends = Object.assign ? Object.assign.bind() : function (n) {
+ for (let e = 1; e < arguments.length; e++) {
+ const t = arguments[e];
+ for (const r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]);
+ }
+ return n;
+ }, _extends.apply(null, arguments);
+}
-// EXPORTS
-REQ_.d(EXP_, {
- T: () => TypingArea
-});
-// EXTERNAL MODULE: ./node_modules/@babel/runtime/helpers/esm/applyDecoratedDescriptor.js
-const applyDecoratedDescriptor = REQ_(793);
-// EXTERNAL MODULE: external "React"
-const React_ = REQ_(594);
-const REaCt = REQ_.n(React_);
-// EXTERNAL MODULE: ./js/ui/utils.jsx
-const utils = REQ_(314);
-// EXTERNAL MODULE: ./js/chat/mixins.js
-const mixins = REQ_(137);
-// EXTERNAL MODULE: ./js/ui/emojiDropdown.jsx
-const emojiDropdown = REQ_(844);
-// EXTERNAL MODULE: ./js/ui/buttons.jsx
-const ui_buttons = REQ_(994);
-;// ./js/chat/ui/emojiAutocomplete.jsx
+ }
+
+ };
+
+ // The module cache
+ const __webpack_module_cache__ = {};
+
+ // The require function
+ function REQ_(moduleId) {
+ // Check if module is in cache
+ const cachedModule = __webpack_module_cache__[moduleId];
+ if (cachedModule !== undefined) {
+ return cachedModule.exports;
+ }
+ // Create a new module (and put it into the cache)
+ const module = __webpack_module_cache__[moduleId] = {
+ // no module.id needed
+ // no module.loaded needed
+ exports: {}
+ };
+
+ // Execute the module function
+ __webpack_modules__[moduleId](module, module.exports, REQ_);
+
+ // Return the exports of the module
+ return module.exports;
+ }
+
+ // expose the modules object (__webpack_modules__)
+ REQ_.m = __webpack_modules__;
+
+
+
+ (() => {
+ // getDefaultExport function for compatibility with non-harmony modules
+ REQ_.n = (module) => {
+ const getter = module && module.__esModule ?
+ () => module.default :
+ () => module;
+ REQ_.d(getter, { a: getter });
+ return getter;
+ };
+ })();
+
+
+ (() => {
+ // define getter functions for harmony exports
+ REQ_.d = (exports, definition) => {
+ for(const key in definition) {
+ if(REQ_.o(definition, key) && !REQ_.o(exports, key)) {
+ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
+ }
+ }
+ };
+ })();
+
+
+ (() => {
+ REQ_.f = {};
+ // This file contains only the entry chunk.
+ // The chunk loading function for additional chunks
+ REQ_.e = (chunkId) => {
+ return Promise.all(Object.keys(REQ_.f).reduce((promises, key) => {
+ REQ_.f[key](chunkId, promises);
+ return promises;
+ }, []));
+ };
+ })();
+
+
+ (() => {
+ // This function allow to reference async chunks
+ REQ_.u = (chunkId) => {
+ // return url for filenames based on template
+ return `js/chat/bundle.${ {"253":"contacts-panel","313":"cloud-browser","493":"core-ui","543":"start-conversation","716":"schedule-meeting","752":"waiting-room","987":"call"}[chunkId] }.js`;
+ };
+ })();
+
+
+ (() => {
+ REQ_.o = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop)
+ })();
+
+
+ (() => {
+ const inProgress = {};
+ const dataWebpackPrefix = "@meganz/webclient:";
+ // loadScript function to load a script via script tag
+ REQ_.l = (url, done, key, chunkId) => {
+ if(inProgress[url]) { inProgress[url].push(done); return; }
+ let script, needAttach;
+ if(key !== undefined) {
+ const scripts = document.getElementsByTagName("script");
+ for(let i = 0; i < scripts.length; i++) {
+ const s = scripts[i];
+ if(s.getAttribute("src") == url || s.getAttribute("data-webpack") == dataWebpackPrefix + key) { script = s; break; }
+ }
+ }
+ if(!script) {
+ needAttach = true;
+ script = document.createElement('script');
+
+ script.charset = 'utf-8';
+ if (REQ_.nc) {
+ script.setAttribute("nonce", REQ_.nc);
+ }
+ script.setAttribute("data-webpack", dataWebpackPrefix + key);
+
+ script.src = url;
+ }
+ inProgress[url] = [done];
+ const onScriptComplete = (prev, event) => {
+ // avoid mem leaks in IE.
+ script.onerror = script.onload = null;
+ clearTimeout(timeout);
+ const doneFns = inProgress[url];
+ delete inProgress[url];
+ script.parentNode && script.parentNode.removeChild(script);
+ doneFns && doneFns.forEach((fn) => fn(event));
+ if(prev) return prev(event);
+ }
+ var timeout = setTimeout(onScriptComplete.bind(null, undefined, { type: 'timeout', target: script }), 120000);
+ script.onerror = onScriptComplete.bind(null, script.onerror);
+ script.onload = onScriptComplete.bind(null, script.onload);
+ needAttach && document.head.appendChild(script);
+ };
+ })();
+
+
+ (() => {
+ // define __esModule on exports
+ REQ_.r = (exports) => {
+ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
+ }
+ Object.defineProperty(exports, '__esModule', { value: true });
+ };
+ })();
+
+
+ (() => {
+ REQ_.p = "/";
+ })();
+
+
+ (() => {
+ // no baseURI
+
+ // object to store loaded and loading chunks
+ // undefined = chunk not loaded, null = chunk preloaded/prefetched
+ // [resolve, reject, Promise] = chunk loading, 0 = chunk loaded
+ const installedChunks = {
+ 524: 0
+ };
+
+ REQ_.f.j = (chunkId, promises) => {
+ // JSONP chunk loading for javascript
+ let installedChunkData = REQ_.o(installedChunks, chunkId) ? installedChunks[chunkId] : undefined;
+ if(installedChunkData !== 0) { // 0 means "already installed".
+
+ // a Promise means "currently loading".
+ if(installedChunkData) {
+ promises.push(installedChunkData[2]);
+ } else {
+ if(true) { // all chunks have JS
+ // setup Promise in chunk cache
+ const promise = new Promise((resolve, reject) => installedChunkData = installedChunks[chunkId] = [resolve, reject]);
+ promises.push(installedChunkData[2] = promise);
+
+ // start chunk loading
+ const url = REQ_.p + REQ_.u(chunkId);
+ // create error before stack unwound to get useful stacktrace later
+ const error = new Error();
+ const loadingEnded = (event) => {
+ if(REQ_.o(installedChunks, chunkId)) {
+ installedChunkData = installedChunks[chunkId];
+ if(installedChunkData !== 0) installedChunks[chunkId] = undefined;
+ if(installedChunkData) {
+ const errorType = event && (event.type === 'load' ? 'missing' : event.type);
+ const realSrc = event && event.target && event.target.src;
+ error.message = `Loading chunk ${ chunkId } failed.\n(${ errorType }: ${ realSrc })`;
+ error.name = 'ChunkLoadError';
+ error.type = errorType;
+ error.request = realSrc;
+ installedChunkData[1](error);
+ }
+ }
+ };
+ REQ_.l(url, loadingEnded, `chunk-${ chunkId}`, chunkId);
+ }
+ }
+ }
+ };
+
+ // no prefetching
+
+ // no preloaded
+
+ // no HMR
+
+ // no HMR manifest
+
+ // no on chunks loaded
+
+ // install a JSONP callback for chunk loading
+ const webpackJsonpCallback = (parentChunkLoadingFunction, data) => {
+ const [chunkIds, moreModules, runtime] = data;
+ // add "moreModules" to the modules object,
+ // then flag all "chunkIds" as loaded and fire callback
+ let moduleId, chunkId, i = 0;
+ if(chunkIds.some((id) => installedChunks[id] !== 0)) {
+ for(moduleId in moreModules) {
+ if(REQ_.o(moreModules, moduleId)) {
+ REQ_.m[moduleId] = moreModules[moduleId];
+ }
+ }
+ if(runtime) var result = runtime(REQ_);
+ }
+ if(parentChunkLoadingFunction) parentChunkLoadingFunction(data);
+ for(;i < chunkIds.length; i++) {
+ chunkId = chunkIds[i];
+ if(REQ_.o(installedChunks, chunkId) && installedChunks[chunkId]) {
+ installedChunks[chunkId][0]();
+ }
+ installedChunks[chunkId] = 0;
+ }
+
+ }
+
+ const chunkLoadingGlobal = self.webpackChunk_meganz_webclient = self.webpackChunk_meganz_webclient || [];
+ chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0));
+ chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal));
+ })();
+
+
+const EXP_ = {};
+// This entry needs to be wrapped in an IIFE because it needs to be isolated against other entry modules.
+(() => {
+/**
+ * `MegaChunkLoader`
+ * ---------------------------------------------------------------------------------------------------------------------
+ * Overrides the default `webpack` chunk loading mechanism (`REQ_.l`) to integrate
+ * `React.lazy`/`React.Suspense` with the `secureboot` architecture of the `webclient`, which ensures lazy-loaded chunks
+ * go through MEGA's XHR + hash verification pipeline.
+ *
+ * 1) What
+ * ---------------------------------------------------------------------------------------------------------------------
+ * By default `webpack` loads chunks by injecting `script` tags with standard URLs. MEGA's security model requires all
+ * code to be i) loaded via XHR (as to create blob URL entities) and ii) verified against a pre-computed SHA-256 hash.
+ *
+ * The default `webpack` loader behavior bypasses these integrity checks, which is not optimal. Additionally, the
+ * `webpack` Hot Module Replacement (HMR) relies on injecting unverified code at runtime, which is incompatible with
+ * the `webclient` integrity model.
+ *
+ * 2) How
+ * ---------------------------------------------------------------------------------------------------------------------
+ * This loader intercepts the `import()` calls generated by `React.lazy()`:
+ *
+ * i) `webpack` calls `REQ_.l(url, done)` to load a chunk; we capture this call and derive the `url`
+ * from `chunkFilename` in `webpack.config.js` (ex.: `js/chat/bundle.call.js`)
+ * ii) we parse the URL as to extract the logical chunk name (ex.: `js/chat/bundle.call.js` -> `call` -> `chat:call_js`)
+ * iii) we request the resource via `M.require('chat:call_js')` call, as `secureboot.js` maintains the respective
+ * registry (jsl2) by mapping this logical key to the physical, hashed filename in production.
+ * iv) `M.require` handles the XHR download and performs the SHA-256 hash check; if the hash does not match the
+ * build-time manifest, the load is blocked to prevent tampering.
+ * v) we call the `done()` callback on success, which allows the `React.Suspense` boundary to render the component.
+ *
+ * 3) Constraints
+ * ---------------------------------------------------------------------------------------------------------------------
+ * - the original `REQ_.l` loader is intentionally not preserved as a fallback -- if a chunk fails the
+ * integrity check (no `jsl2` entry) chunk loading fails securely rather than bypassing hash verification via the
+ * default `script` tag injection.
+ * - `splitChunks` is disabled; we want deterministic, manually defined chunks (via `webpackChunkName`) to
+ * ensure 1:1 mapping with the `secureboot` registry.
+ * - `hot` (HMR) is disabled; development can rely on standard page reloads in favor of ensuring the dev environment
+ * mirrors the production security pipeline.
+ */
+
+const webpackRequire = true ? REQ_ : 0;
+if (webpackRequire && webpackRequire.l) {
+ const CHUNK_LOADER_DEBUG = d && localStorage.chunkLoaderDebug;
+ const logger = MegaLogger.getLogger('MegaChunkLoader', {
+ levelColors: {
+ 'DEBUG': 'olive',
+ 'ERROR': 'tomato'
+ }
+ });
+ webpackRequire.l = (url, done) => {
+ const startTime = CHUNK_LOADER_DEBUG ? performance.now() : 0;
+ const match = url.match(/bundle\.([^.]+)\.js$/);
+ const chunkName = match == null ? void 0 : match[1];
+ const jslName = chunkName ? `chat:${chunkName.replace(/-/g, '_')}_js` : null;
+ const hasJslEntry = jslName && jsl2[jslName];
+ if (hasJslEntry) {
+ M.require(jslName).then(() => {
+ if (CHUNK_LOADER_DEBUG) {
+ const duration = (performance.now() - startTime).toFixed(1);
+ logger.debug(`Loaded '${chunkName}' chunk in ${duration}ms`, {
+ chunkName,
+ jslName,
+ url
+ });
+ }
+ done({
+ type: 'load'
+ });
+ }).catch(ex => {
+ logger.error(`Failed to load ${jslName}`, {
+ error: ex,
+ chunkName,
+ jslName,
+ url
+ });
+ done({
+ type: 'error',
+ target: {
+ src: url
+ }
+ });
+ });
+ } else {
+ logger.error(`Blocked insecure chunk load ('jsl2' entry missing)`, {
+ chunkName,
+ jslName,
+ url
+ });
+ done({
+ type: 'error',
+ target: {
+ src: url
+ }
+ });
+ }
+ };
+}
+})();
+// This entry needs to be wrapped in an IIFE because it needs to be in strict mode.
+(() => {
+"use strict";
+// UNUSED EXPORTS: default
-class EmojiAutocomplete extends mixins.w9 {
- constructor(props) {
- super(props);
- this.domRef = REaCt().createRef();
- this.state = {
- 'selected': 0
+// EXTERNAL MODULE: external "React"
+const external_React_ = REQ_(1594);
+const REaCt = REQ_.n(external_React_);
+// EXTERNAL MODULE: external "ReactDOM"
+const external_ReactDOM_ = REQ_(5206);
+// EXTERNAL MODULE: ./js/chat/ui/conversations.jsx + 2 modules
+const conversations = REQ_(4904);
+;// ./js/chat/chatRouting.jsx
+let _ChatRouting;
+class ChatRouting {
+ constructor(megaChatInstance) {
+ this.megaChat = megaChatInstance;
+ }
+ openCustomView(sectionName) {
+ const {megaChat} = this;
+ megaChat.routingSection = sectionName;
+ megaChat.hideAllChats();
+ delete megaChat.lastOpenedChat;
+ }
+ route(resolve, reject, location, event, isLandingPage) {
+ if (!M.chat) {
+ console.error('This function is meant to navigate within the chat...');
+ return;
+ }
+ const args = String(location || '').split('/').map(String.trim).filter(String);
+ if (args[0] === 'fm') {
+ args.shift();
+ }
+ if (args[0] === 'chat') {
+ args.shift();
+ }
+ if (args[0] && args[0].length > 8 && args[0].substring(0, 8) === 'contacts') {
+ location = location.replace(args[0], 'contacts');
+ args[0] = 'contacts';
+ }
+ const [section] = args;
+ const {
+ megaChat
+ } = this;
+ if (d) {
+ megaChat.logger.warn('navigate(%s)', location, args);
+ }
+ args.route = {
+ location,
+ section,
+ args
};
- this.loading = false;
- this.data_emojis = [];
- }
- preload_emojis() {
- if (this.loading === false) {
- this.loading = true;
- megaChat.getEmojiDataSet('emojis').then(emojis => {
- this.loading = 0;
- this.data_emojis = emojis;
- this.safeForceUpdate();
- });
+ if (isLandingPage) {
+ megaChat.eventuallyInitMeetingUI();
}
- }
- unbindKeyEvents() {
- $(document).off(`keydown.emojiAutocomplete${ this.getUniqueId()}`);
- }
- bindKeyEvents() {
- const self = this;
- $(document).rebind(`keydown.emojiAutocomplete${ self.getUniqueId()}`, (e) => {
- if (!self.props.emojiSearchQuery) {
- self.unbindKeyEvents();
- return;
- }
- let key = e.keyCode || e.which;
- if (!$(e.target).is("textarea")) {
- console.error("this should never happen.");
- return;
- }
- if (e.altKey || e.metaKey) {
- return;
- }
- let selected = $.isNumeric(self.state.selected) ? self.state.selected : 0;
- if (document.body.classList.contains('rtl') && (key === 37 || key === 39)) {
- key = key === 37 ? 39 : 37;
+ megaChat.routingSection = 'chat';
+ megaChat.routingSubSection = null;
+ megaChat.routingParams = null;
+ const handler = ChatRouting.gPageHandlers[section || 'start'];
+ if (handler) {
+ handler.call(this, args.route).then(resolve).catch(reject);
+ resolve = null;
+ } else {
+ let roomId = String(args[(section === 'c' || section === 'g' || section === 'p') | 0] || '');
+ if (roomId.includes('#')) {
+ let key = roomId.split('#');
+ roomId = key[0];
+ key = key[1];
+ megaChat.publicChatKeys[roomId] = key;
+ roomId = megaChat.handleToId[roomId] || roomId;
}
- let handled = false;
- if (!e.shiftKey && (key === 37 || key === 38)) {
- selected = selected - 1;
- selected = selected < 0 ? self.maxFound - 1 : selected;
- if (self.found[selected] && self.state.selected !== selected) {
- self.setState({
- selected,
- 'prefilled': true
- });
- handled = true;
- self.props.onPrefill(false, `:${ self.found[selected].n }:`);
- }
- } else if (!e.shiftKey && (key === 39 || key === 40 || key === 9)) {
- selected = selected + (key === 9 ? e.shiftKey ? -1 : 1 : 1);
- selected = selected < 0 ? Object.keys(self.found).length - 1 : selected;
- selected = selected >= self.props.maxEmojis || selected >= Object.keys(self.found).length ? 0 : selected;
- if (self.found[selected] && (key === 9 || self.state.selected !== selected)) {
- self.setState({
- selected,
- 'prefilled': true
- });
- self.props.onPrefill(false, `:${ self.found[selected].n }:`);
- handled = true;
- }
- } else if (key === 13) {
- self.unbindKeyEvents();
- if (selected === -1) {
- if (self.found.length > 0) {
- for (let i = 0; i < self.found.length; i++) {
- if (`:${ self.found[i].n }:` === `${self.props.emojiSearchQuery }:`) {
- self.props.onSelect(false, `:${ self.found[0].n }:`);
- handled = true;
- }
- }
+ const room = megaChat.getChatById(roomId);
+ if (room) {
+ room.show();
+ args.route.location = room.getRoomUrl();
+ } else if (!roomId || roomId === u_handle || roomId.length !== 11 && !is_chatlink) {
+ ChatRouting.gPageHandlers.redirect(args.route, 'fm/chat').then(resolve).catch(reject);
+ resolve = null;
+ } else if (section === 'p') {
+ megaChat.smartOpenChat([u_handle, roomId], 'private', undefined, undefined, undefined, true).then(resolve).catch(reject);
+ resolve = null;
+ } else {
+ megaChat.plugins.chatdIntegration.openChat(roomId).then(chatId => {
+ megaChat.getChatById(chatId).show();
+ return chatId;
+ }).catch(ex => {
+ if (d && ex !== ENOENT) {
+ console.warn('If "%s" is a chat, something went wrong..', roomId, ex);
}
- if (!handled && key === 13) {
- self.props.onCancel();
+ if (page !== location) {
+ return EEXPIRED;
}
- return;
- } else if (self.found.length > 0 && self.found[selected]) {
- self.props.onSelect(false, `:${ self.found[selected].n }:`);
- handled = true;
- } else {
- self.props.onCancel();
- }
- } else if (key === 27) {
- self.unbindKeyEvents();
- self.props.onCancel();
- handled = true;
- }
- if (handled) {
- e.preventDefault();
- e.stopPropagation();
- return false;
- } else {
- if (self.isMounted()) {
- self.setState({
- 'prefilled': false
- });
- }
+ megaChat.cleanup(true);
+ if (ex === ENOENT || ex === EBLOCKED && megaChat.publicChatKeys[roomId]) {
+ msgDialog('warninga', '', l[20641], l[20642], () => {
+ loadSubPage(is_chatlink ? 'start' : 'fm/chat', event);
+ });
+ } else {
+ if (String(location).startsWith('chat')) {
+ location = 'fm/chat';
+ }
+ loadSubPage(location, location.includes('chat') ? 'override' : event);
+ }
+ return EACCESS;
+ }).then(resolve).catch(reject);
+ resolve = null;
}
- });
- }
- componentDidUpdate() {
- if (!this.props.emojiSearchQuery) {
- this.unbindKeyEvents();
- } else {
- this.bindKeyEvents();
}
- }
- componentWillUnmount() {
- super.componentWillUnmount();
- this.unbindKeyEvents();
- }
- render() {
- const self = this;
- if (!self.props.emojiSearchQuery) {
- return null;
+ if (resolve) {
+ onIdle(resolve);
}
- self.preload_emojis();
- if (self.loading) {
- return REaCt().createElement("div", {
- className: "textarea-autofill-bl"
- }, REaCt().createElement("div", {
- className: "textarea-autofill-info"
- }, l[5533]));
- }
- const q = self.props.emojiSearchQuery.substr(1, self.props.emojiSearchQuery.length);
- let exactMatch = [];
- let partialMatch = [];
- const emojis = self.data_emojis || [];
- for (var i = 0; i < emojis.length; i++) {
- const emoji = emojis[i];
- const match = emoji.n.indexOf(q);
- if (match !== -1) {
- if (match === 0) {
- exactMatch.push(emoji);
- } else if (partialMatch.length < self.props.maxEmojis - exactMatch.length) {
- partialMatch.push(emoji);
- }
- }
- if (exactMatch.length >= self.props.maxEmojis) {
- break;
- }
+ if (args.route.location !== location) {
+ location = args.route.location;
}
- exactMatch.sort((a, b) => {
- if (a.n === q) {
- return -1;
- } else if (b.n === q) {
- return 1;
- } else {
- return 0;
- }
- });
- const found = exactMatch.concat(partialMatch).slice(0, self.props.maxEmojis);
- exactMatch = partialMatch = null;
- this.maxFound = found.length;
- this.found = found;
- if (!found || found.length === 0) {
- queueMicrotask(() => {
- self.props.onCancel();
- });
- return null;
+ const method = page === 'chat' || page === 'fm/chat' || page === location || event && event.type === 'popstate' ? 'replaceState' : 'pushState';
+ mBroadcaster.sendMessage('beforepagechange', location);
+ M.currentdirid = String(page = location).replace('fm/', '');
+ if (location.substr(0, 13) === "chat/contacts") {
+ location = `fm/${ location}`;
}
- const emojisDomList = [];
- for (var i = 0; i < found.length; i++) {
- const meta = found[i];
- const filename = twemoji.convert.toCodePoint(meta.u);
- emojisDomList.push(REaCt().createElement("div", {
- className: `emoji-preview shadow ${ this.state.selected === i ? "active" : ""}`,
- key: `${meta.n }_${ this.state.selected === i ? "selected" : "inselected"}`,
- title: `:${ meta.n }:`,
- onClick (e) {
- self.props.onSelect(e, e.target.title);
- self.unbindKeyEvents();
- }
- }, REaCt().createElement("img", {
- width: "20",
- height: "20",
- className: "emoji emoji-loading",
- draggable: "false",
- alt: meta.u,
- onLoad: e => {
- e.target.classList.remove('emoji-loading');
- },
- onError: e => {
- e.target.classList.remove('emoji-loading');
- e.target.classList.add('emoji-loading-error');
- },
- src: `${staticpath }images/mega/twemojis/2_v2/72x72/${ filename }.png`
- }), REaCt().createElement("div", {
- className: "emoji title"
- }, `:${ meta.n }:`)));
+ if (location === 'chat') {
+ location = 'fm/chat';
}
- return REaCt().createElement("div", {
- ref: this.domRef,
- className: "textarea-autofill-bl"
- }, REaCt().createElement(utils.P9, {
- tag: "div",
- className: "textarea-autofill-info"
- }, l.emoji_suggestion_instruction), REaCt().createElement("div", {
- className: "textarea-autofill-emoji"
- }, emojisDomList));
+ history[method]({
+ subpage: location
+ }, "", (hashLogic ? '#' : '/') + location);
+ mBroadcaster.sendMessage('pagechange', page);
+ }
+ initFmAndChat(targetChatId) {
+ assert(!fminitialized);
+ return new Promise((res, rej) => {
+ M.currentdirid = targetChatId ? `fm/chat/${ targetChatId}` : undefined;
+ loadSubPage('fm');
+ mBroadcaster.once('chat_initialized', () => {
+ authring.onAuthringReady().then(res, rej);
+ });
+ });
+ }
+ reinitAndOpenExistingChat(chatId, publicChatHandle = false, cbBeforeOpen = undefined) {
+ const chatUrl = `fm/chat/c/${ chatId}`;
+ publicChatHandle = publicChatHandle || megaChat.initialPubChatHandle;
+ megaChat.destroy();
+ is_chatlink = false;
+ loadingDialog.pshow();
+ return new Promise((resolve, reject) => {
+ this.initFmAndChat(chatId).always(() => {
+ megaChat.initialPubChatHandle = publicChatHandle;
+ megaChat.initialChatId = chatId;
+ const next = () => {
+ mBroadcaster.once('pagechange', () => {
+ onIdle(() => {
+ loadingDialog.phide();
+ megaChat.renderListing(chatUrl, true).catch(ex => {
+ console.error("Failed to megaChat.renderListing:", ex);
+ reject(ex);
+ }).always(() => {
+ megaChat.updateKeysInProtocolHandlers();
+ const chatRoom = megaChat.getChatById(chatId);
+ assert(chatRoom);
+ if (chatRoom.state === ChatRoom.STATE.READY) {
+ resolve(chatRoom);
+ } else {
+ chatRoom.rebind('onMessagesHistoryDone.reinitAndOpenExistingChat', () => {
+ if (chatRoom.state === ChatRoom.STATE.READY) {
+ resolve(chatRoom);
+ chatRoom.unbind('onMessagesHistoryDone.reinitAndOpenExistingChat');
+ }
+ });
+ }
+ });
+ });
+ });
+ loadSubPage(chatUrl);
+ };
+ if (cbBeforeOpen) {
+ cbBeforeOpen().then(next, ex => {
+ console.error("Failed to execute `cbBeforeOpen`, got a reject of the returned promise:", ex);
+ });
+ } else {
+ next();
+ }
+ }).catch(ex => reject(ex));
+ });
+ }
+ reinitAndJoinPublicChat(chatId, initialPubChatHandle, publicChatKey) {
+ initialPubChatHandle = initialPubChatHandle || megaChat.initialPubChatHandle;
+ megaChat.destroy();
+ is_chatlink = false;
+ loadingDialog.pshow();
+ return new Promise((res, rej) => {
+ this.initFmAndChat(chatId).then(() => {
+ megaChat.initialPubChatHandle = initialPubChatHandle;
+ megaChat.initialChatId = chatId;
+ const mciphReq = megaChat.plugins.chatdIntegration.getMciphReqFromHandleAndKey(initialPubChatHandle, publicChatKey);
+ const isReady = chatRoom => {
+ if (chatRoom.state === ChatRoom.STATE.READY) {
+ res(chatRoom);
+ loadingDialog.phide();
+ } else {
+ chatRoom.rebind('onMessagesHistoryDone.reinitAndOpenExistingChat', () => {
+ if (chatRoom.state === ChatRoom.STATE.READY) {
+ res(chatRoom);
+ loadingDialog.phide();
+ chatRoom.unbind('onMessagesHistoryDone.reinitAndOpenExistingChat');
+ }
+ });
+ }
+ };
+ const join = () => {
+ const existingRoom = megaChat.getChatById(chatId);
+ if (!existingRoom) {
+ megaChat.rebind('onRoomInitialized.reinitAndJoinPublicChat', (e, megaRoom) => {
+ if (megaRoom.chatId === chatId) {
+ megaRoom.setActive();
+ isReady(megaRoom);
+ megaChat.unbind('onRoomInitialized.reinitAndJoinPublicChat');
+ }
+ });
+ } else {
+ existingRoom.setActive();
+ isReady(existingRoom);
+ }
+ };
+ join();
+ asyncApiReq(mciphReq).then(join).catch(ex => {
+ if (ex === EEXIST) {
+ join();
+ } else {
+ loadingDialog.phide();
+ console.error("Bad response for mciphReq:", mciphReq, ex);
+ rej(ex);
+ }
+ });
+ });
+ });
}
}
-EmojiAutocomplete.defaultProps = {
- 'requiresUpdateOnResize': true,
- 'emojiSearchQuery': false,
- 'disableCheckingVisibility': true,
- 'maxEmojis': 12
+_ChatRouting = ChatRouting;
+ChatRouting.gPageHandlers = {
+ async start({
+ location
+ }) {
+ return megaChat.onChatsHistoryReady(15e3).then(() => {
+ return page === location ? megaChat.renderListing() : EACCESS;
+ });
+ },
+ async redirect(target, path = 'fm/chat') {
+ target.location = path;
+ return _ChatRouting.gPageHandlers.start(target);
+ },
+ async new_meeting(target) {
+ megaChat.trigger('onStartNewMeeting');
+ return _ChatRouting.gPageHandlers.redirect(target);
+ },
+ async contacts({
+ section,
+ args
+ }) {
+ this.openCustomView(section);
+ const [, target = ''] = args;
+ if (target.length === 11) {
+ megaChat.routingSubSection = "contact";
+ megaChat.routingParams = target;
+ } else if (target === "received" || target === "sent") {
+ megaChat.routingSubSection = target;
+ }
+ }
};
-// EXTERNAL MODULE: ./js/chat/ui/gifPanel/gifPanel.jsx + 3 modules
-const gifPanel = REQ_(691);
-// EXTERNAL MODULE: ./js/ui/perfectScrollbar.jsx
-const perfectScrollbar = REQ_(486);
-;// ./js/chat/ui/typingArea.jsx
-
-let _dec, _class;
-
-
-
-
-
+// EXTERNAL MODULE: ./js/chat/ui/messages/scheduleMetaChange.jsx
+const scheduleMetaChange = REQ_(5470);
+// EXTERNAL MODULE: ./js/chat/chatRoom.jsx
+const chat_chatRoom = REQ_(7057);
+// EXTERNAL MODULE: ./js/chat/ui/meetings/schedule/helpers.jsx
+const helpers = REQ_(6521);
+;// ./js/chat/meetingsManager.jsx
-const TypingArea = (_dec = (0,mixins.hG)(54, true), _class = class TypingArea extends mixins.w9 {
- constructor(props) {
- super(props);
- this.domRef = REaCt().createRef();
- this.state = {
- emojiSearchQuery: false,
- textareaHeight: 20,
- gifPanelActive: false
- };
- this.getTextareaMaxHeight = () => {
- const {
- containerRef
- } = this.props;
- if (containerRef && containerRef.current) {
- return this.isMounted() ? containerRef.current.offsetHeight * 0.4 : 100;
- }
- return 100;
- };
+class Occurrence {
+ constructor(megaChat, occurrence) {
const {
- chatRoom
- } = props;
- this.logger = d && MegaLogger.getLogger("TypingArea", {}, chatRoom && chatRoom.logger || megaChat.logger);
- this.onEmojiClicked = this.onEmojiClicked.bind(this);
- this.onTypeAreaKeyUp = this.onTypeAreaKeyUp.bind(this);
- this.onTypeAreaKeyDown = this.onTypeAreaKeyDown.bind(this);
- this.onTypeAreaBlur = this.onTypeAreaBlur.bind(this);
- this.onTypeAreaChange = this.onTypeAreaChange.bind(this);
- this.onCopyCapture = this.onCopyCapture.bind(this);
- this.onPasteCapture = this.onPasteCapture.bind(this);
- this.onCutCapture = this.onCutCapture.bind(this);
- this.state.typedMessage = this.props.initialText || '';
- }
- onEmojiClicked(e, slug) {
- if (this.props.disabled) {
- e.preventDefault();
- e.stopPropagation();
- return;
- }
- slug = slug[0] === ':' || slug.substr(-1) === ':' ? slug : `:${slug}:`;
- const textarea = $('.messages-textarea', this.domRef.current)[0];
- const cursorPosition = this.getCursorPosition(textarea);
+ decodeData
+ } = megaChat.plugins.meetingsManager;
+ this.megaChat = megaChat;
+ this.id = occurrence.id;
+ this.uid = `${occurrence.cid}-${occurrence.o || occurrence.s}`;
+ this.chatId = occurrence.cid;
+ this.parentId = occurrence.p;
+ this.start = occurrence.s * 1000;
+ this.startInitial = parseInt(occurrence.o) * 1000 || undefined;
+ this.end = occurrence.e * 1000;
+ this.timezone = decodeData(occurrence.tz);
+ this.title = decodeData(occurrence.t);
+ this.description = decodeData(occurrence.d);
+ this.ownerHandle = occurrence.u;
+ this.flags = occurrence.f;
+ this.canceled = occurrence.c;
+ this.scheduledMeeting = occurrence.scheduledMeeting;
+ }
+ get isUpcoming() {
+ return !this.canceled && this.end > Date.now();
+ }
+ cancel() {
const {
- text,
- onValueChanged
- } = this.props;
- const val = text.slice(0, cursorPosition) + slug + text.slice(cursorPosition);
- onValueChanged(val);
- textarea.selectionEnd = cursorPosition + slug.length;
- this.onTypeAreaChange(e, val);
+ encodeData
+ } = this.megaChat.plugins.meetingsManager;
+ const req = {
+ a: 'mcsmp',
+ p: this.parentId || this.id,
+ ...this.parentId && {
+ id: this.id
+ },
+ cid: this.chatId,
+ o: this.start / 1000,
+ s: this.start / 1000,
+ e: this.end / 1000,
+ tz: encodeData(this.timezone),
+ t: encodeData(this.title),
+ d: encodeData(this.description) || '',
+ f: this.scheduledMeeting.flags,
+ c: 1
+ };
+ asyncApiReq(req).catch(ex => console.error('Occurrence > cancel ->', ex));
}
- stoppedTyping() {
- if (this.props.disabled || !this.props.chatRoom) {
- return;
- }
- this.iAmTyping = false;
- this.props.chatRoom.trigger('stoppedTyping');
+ update(startDateTime, endDateTime) {
+ const {
+ encodeData
+ } = this.megaChat.plugins.meetingsManager;
+ const req = {
+ a: 'mcsmp',
+ cid: this.chatId,
+ p: this.parentId || this.id,
+ ...this.parentId && {
+ id: this.id
+ },
+ o: this.start / 1000,
+ s: startDateTime / 1000,
+ e: endDateTime / 1000,
+ tz: encodeData(this.timezone),
+ t: encodeData(this.title),
+ d: encodeData(this.description) || '',
+ f: this.scheduledMeeting.flags
+ };
+ asyncApiReq(req).catch(ex => console.error('Occurrence > update ->', ex));
}
- typing() {
- if (this.props.disabled || !this.props.chatRoom) {
- return;
- }
- const self = this;
- const now = Date.now();
- delay(this.getReactId(), () => self.iAmTyping && self.stoppedTyping(), 4e3);
- if (!self.iAmTyping || now - self.lastTypingStamp > 4e3) {
- self.iAmTyping = true;
- self.lastTypingStamp = now;
- self.props.chatRoom.trigger('typing');
+}
+class ScheduledMeeting {
+ constructor(megaChat, meetingInfo, fromActionPacket) {
+ const {
+ decodeData
+ } = megaChat.plugins.meetingsManager;
+ this.megaChat = megaChat;
+ this.id = meetingInfo.id;
+ this.chatId = meetingInfo.cid;
+ this.parentId = meetingInfo.p;
+ this.start = meetingInfo.s * 1000;
+ this.startInitial = parseInt(meetingInfo.o) * 1000 || undefined;
+ this.end = meetingInfo.e * 1000;
+ this.timezone = decodeData(meetingInfo.tz);
+ this.title = decodeData(meetingInfo.t);
+ this.description = decodeData(meetingInfo.d);
+ this.flags = meetingInfo.f;
+ this.canceled = meetingInfo.c;
+ this.recurring = meetingInfo.r && {
+ frequency: meetingInfo.r.f || undefined,
+ interval: meetingInfo.r.i || 0,
+ end: meetingInfo.r.u * 1000 || undefined,
+ weekDays: meetingInfo.r.wd || [],
+ monthDays: meetingInfo.r.md || [],
+ offset: meetingInfo.r.mwd && meetingInfo.r.mwd.length ? {
+ value: meetingInfo.r.mwd[0][0],
+ weekDay: meetingInfo.r.mwd[0][1]
+ } : []
+ };
+ this.occurrences = new MegaDataMap();
+ this.nextOccurrenceStart = this.start;
+ this.nextOccurrenceEnd = this.end;
+ this.isCompleted = false;
+ this.ownerHandle = meetingInfo.u;
+ this.chatRoom = meetingInfo.chatRoom;
+ this.chatRoom.scheduledMeeting = this.isRoot ? this : this.parent;
+ if (fromActionPacket) {
+ this.initializeFromActionPacket();
}
}
- triggerOnUpdate(forced) {
- const self = this;
- if (!self.props.onUpdate || !self.isMounted()) {
- return;
- }
- let shouldTriggerUpdate = forced ? forced : false;
- if (!shouldTriggerUpdate && self.props.text !== self.lastTypedMessage) {
- self.lastTypedMessage = self.props.text;
- shouldTriggerUpdate = true;
- }
- if (!shouldTriggerUpdate) {
- const $textarea = $('.chat-textarea:visible textarea:visible', self.domRef.current);
- if (!self._lastTextareaHeight || self._lastTextareaHeight !== $textarea.height()) {
- self._lastTextareaHeight = $textarea.height();
- shouldTriggerUpdate = true;
- if (self.props.onResized) {
- self.props.onResized();
- }
- }
- }
- if (shouldTriggerUpdate) {
- self.props.onUpdate();
- }
+ get isRoot() {
+ return !this.parentId;
}
- onCancelClicked() {
- const self = this;
- self.props.onValueChanged('');
- if (self.props.chatRoom && self.iAmTyping) {
- self.stoppedTyping();
- }
- self.onConfirmTrigger(false);
- self.triggerOnUpdate();
+ get isCanceled() {
+ return !!this.canceled;
}
- onSaveClicked() {
- const self = this;
- if (self.props.disabled || !self.isMounted()) {
- return;
- }
- const val = $.trim($('.chat-textarea:visible textarea:visible', this.domRef.current).val());
- if (self.onConfirmTrigger(val) !== true) {
- self.props.onValueChanged('');
- }
- if (self.props.chatRoom && self.iAmTyping) {
- self.stoppedTyping();
- }
- self.triggerOnUpdate();
+ get isPast() {
+ return (this.isRecurring ? this.recurring.end : this.end) < Date.now();
}
- onConfirmTrigger(val) {
- const {
- onConfirm,
- persist,
- chatRoom
- } = this.props;
- const result = onConfirm(val);
- if (val !== false && result !== false) {
- $('.textarea-scroll', this.domRef.current).scrollTop(0);
- }
- if (persist) {
- const {
- persistedTypeArea
- } = chatRoom.megaChat.plugins;
- if (persistedTypeArea) {
- if (d > 2) {
- this.logger.info('Removing persisted-typed value...');
- }
- persistedTypeArea.removePersistedTypedValue(chatRoom);
- }
- }
- return result;
+ get isUpcoming() {
+ return !(this.isCanceled || this.isPast || this.isCompleted);
}
- onTypeAreaKeyDown(e) {
- if (this.props.disabled) {
- e.preventDefault();
- e.stopPropagation();
- return;
- }
- const self = this;
- const key = e.keyCode || e.which;
- const element = e.target;
- const val = $.trim(element.value);
- if (self.state.emojiSearchQuery) {
- return;
- }
- if (key === 13 && !e.shiftKey && !e.ctrlKey && !e.altKey) {
- if (e.isPropagationStopped() || e.isDefaultPrevented()) {
- return;
- }
- if (self.onConfirmTrigger(val) !== true) {
- self.props.onValueChanged('');
- $(document).trigger('closeDropdowns');
- }
- e.preventDefault();
- e.stopPropagation();
- if (self.props.chatRoom && self.iAmTyping) {
- self.stoppedTyping();
- }
- }
+ get isRecurring() {
+ return !!this.recurring;
}
- onTypeAreaKeyUp(e) {
- if (this.props.disabled) {
- e.preventDefault();
- e.stopPropagation();
- return;
- }
- const self = this;
- const key = e.keyCode || e.which;
- const element = e.target;
- const val = $.trim(element.value);
- if (key === 13 && !e.shiftKey && !e.ctrlKey && !e.altKey) {
- e.preventDefault();
- e.stopPropagation();
- } else if (key === 13) {
- if (self.state.emojiSearchQuery) {
- return;
- }
- if (e.altKey) {
- let content = element.value;
- const cursorPos = self.getCursorPosition(element);
- content = `${content.substring(0, cursorPos) }\n${ content.substring(cursorPos, content.length)}`;
- self.props.onValueChanged(content);
- self.onUpdateCursorPosition = cursorPos + 1;
- e.preventDefault();
- } else if ($.trim(val).length === 0) {
- e.preventDefault();
- }
- } else if (key === 38) {
- if (self.state.emojiSearchQuery) {
- return;
- }
- if ($.trim(val).length === 0) {
- if (self.props.onUpEditPressed && self.props.onUpEditPressed() === true) {
- e.preventDefault();
- }
- }
- } else if (key === 27) {
- if (self.state.emojiSearchQuery) {
- return;
- }
- if (self.props.showButtons === true) {
- e.preventDefault();
- self.onCancelClicked(e);
- }
- } else {
- if (self.prefillMode && (key === 8 || key === 32 || key === 186 || key === 13)) {
- self.prefillMode = false;
- }
- const currentContent = element.value;
- const currentCursorPos = self.getCursorPosition(element) - 1;
- if (self.prefillMode && (currentCursorPos > self.state.emojiEndPos || currentCursorPos < self.state.emojiStartPos)) {
- self.prefillMode = false;
- self.setState({
- 'emojiSearchQuery': false,
- 'emojiStartPos': false,
- 'emojiEndPos': false
- });
- return;
- }
- if (self.prefillMode) {
- return;
- }
- const char = String.fromCharCode(key);
- if (key === 16 || key === 17 || key === 18 || key === 91 || key === 8 || key === 37 || key === 39 || key === 40 || key === 38 || key === 9 || /[\w:-]/.test(char)) {
- const parsedResult = mega.utils.emojiCodeParser(currentContent, currentCursorPos);
- self.setState({
- 'emojiSearchQuery': parsedResult[0],
- 'emojiStartPos': parsedResult[1],
- 'emojiEndPos': parsedResult[2]
- });
- return;
- }
- if (self.state.emojiSearchQuery) {
- self.setState({
- 'emojiSearchQuery': false
- });
- }
+ get isNear() {
+ return this.start - Date.now() < ChatRoom.SCHEDULED_MEETINGS_INTERVAL;
+ }
+ get iAmOwner() {
+ if (this.ownerHandle) {
+ return this.ownerHandle === u_handle;
}
+ return null;
}
- onTypeAreaBlur(e) {
- if (this.props.disabled) {
- e.preventDefault();
- e.stopPropagation();
- return;
- }
- const self = this;
- if (self.state.emojiSearchQuery) {
- setTimeout(() => {
- if (self.isMounted()) {
- self.setState({
- 'emojiSearchQuery': false,
- 'emojiStartPos': false,
- 'emojiEndPos': false
- });
- }
- }, 300);
- }
+ get parent() {
+ return this.isRoot ? null : this.megaChat.plugins.meetingsManager.getMeetingById(this.parentId);
}
- onTypeAreaChange(e, value) {
- if (this.props.disabled) {
- e.preventDefault();
- e.stopPropagation();
+ setNextOccurrence() {
+ const upcomingOccurrences = Object.values(this.occurrences).filter(o => o.isUpcoming);
+ if (!upcomingOccurrences || !upcomingOccurrences.length) {
+ this.isCompleted = this.isRecurring;
return;
}
- const self = this;
- value = String(value || e.target.value || '').replace(/^\s+/, '');
- if (self.props.text !== value) {
- self.props.onValueChanged(value);
- self.forceUpdate();
- }
- if (value.length) {
- self.typing();
- } else {
- self.stoppedTyping();
- }
- if (this.props.persist) {
- const {
- chatRoom
- } = this.props;
- const {
- megaChat
- } = chatRoom;
- const {
- persistedTypeArea
- } = megaChat.plugins;
- if (persistedTypeArea) {
- if (d > 2) {
- this.logger.debug('%s persisted-typed value...', value.length ? 'Updating' : 'Removing');
- }
- if (value.length) {
- persistedTypeArea.updatePersistedTypedValue(chatRoom, value);
- } else {
- persistedTypeArea.removePersistedTypedValue(chatRoom);
- }
- }
- }
- self.updateScroll();
+ const sortedOccurrences = upcomingOccurrences.sort((a, b) => a.start - b.start);
+ this.nextOccurrenceStart = sortedOccurrences[0].start;
+ this.nextOccurrenceEnd = sortedOccurrences[0].end;
}
- focusTypeArea() {
- if (this.props.disabled) {
- return;
- }
- if ($('.chat-textarea:visible textarea:visible', this.domRef.current).length > 0 && !$('.chat-textarea:visible textarea:visible:first', this.domRef.current).is(":focus")) {
- moveCursortoToEnd($('.chat-textarea:visible:first textarea', this.domRef.current)[0]);
+ async getOccurrences(options) {
+ const {
+ from,
+ to,
+ count
+ } = options || {};
+ const {
+ meetingsManager
+ } = this.megaChat.plugins;
+ const req = {
+ a: 'mcsmfo',
+ cid: this.chatId,
+ ...from && {
+ cf: Math.round(from / 1000)
+ },
+ ...to && {
+ ct: Math.round(to / 1000)
+ },
+ ...count && {
+ cc: count
+ }
+ };
+ if (is_chatlink) {
+ req.ph = is_chatlink.ph;
+ delete req.cid;
}
- }
- componentDidMount() {
- super.componentDidMount();
- this._lastTextareaHeight = 20;
- this.lastTypedMessage = this.props.initialText || this.lastTypedMessage;
- chatGlobalEventManager.addEventListener('resize', `typingArea${this.getUniqueId()}`, () => this.handleWindowResize());
- this.triggerOnUpdate(true);
- this.updateScroll();
- megaChat.rebind(`viewstateChange.gifpanel${this.getUniqueId()}`, e => {
- const {
- gifPanelActive
- } = this.state;
- const {
- state
- } = e.data;
- if (state === 'active' && !gifPanelActive && this.gifResume) {
- this.setState({
- gifPanelActive: true
- });
- delete this.gifResume;
- } else if (state !== 'active' && gifPanelActive && !this.gifResume) {
- this.gifResume = true;
- this.setState({
- gifPanelActive: false
+ const occurrences = await asyncApiReq(req);
+ if (Array.isArray(occurrences)) {
+ if (!options) {
+ this.occurrences.clear();
+ }
+ for (let i = 0; i < occurrences.length; i++) {
+ const occurrence = new Occurrence(this.megaChat, {
+ scheduledMeeting: this,
+ ...occurrences[i]
});
+ this.occurrences.set(occurrence.uid, occurrence);
}
- });
+ this.isCompleted = false;
+ this.setNextOccurrence();
+ this.megaChat.trigger(meetingsManager.EVENTS.OCCURRENCES_UPDATE, this);
+ }
+ return this.occurrences;
}
- UNSAFE_componentWillMount() {
- const {
- chatRoom,
- initialText,
- persist,
- onValueChanged
- } = this.props;
+ getOccurrencesById(occurrenceId) {
+ const occurrences = Object.values(this.occurrences.toJS()).filter(o => o.id === occurrenceId);
+ return occurrences.length ? occurrences : false;
+ }
+ initializeFromActionPacket() {
const {
megaChat,
- roomId
- } = chatRoom;
- const {
- persistedTypeArea
- } = megaChat.plugins;
- if (persist && persistedTypeArea) {
- if (!initialText) {
- persistedTypeArea.getPersistedTypedValue(chatRoom).then(res => {
- if (res && this.isMounted() && !this.props.text) {
- onValueChanged(res);
- }
- }).catch(ex => {
- if (this.logger && ex !== undefined) {
- this.logger.warn(`Failed to retrieve persistedTypeArea for ${roomId}: ${ex}`, [ex]);
+ isUpcoming,
+ isCanceled,
+ isRecurring,
+ parent
+ } = this;
+ if (isUpcoming && isRecurring || parent) {
+ return parent ? (() => {
+ const occurrences = Object.values(parent.occurrences);
+ if (occurrences.length <= 20) {
+ return parent.getOccurrences().catch(nop);
+ }
+ occurrences.sort((a, b) => a.start - b.start);
+ const {
+ chatId,
+ start,
+ startInitial
+ } = this;
+ const currentIndex = occurrences.findIndex(o => o.uid === `${chatId}-${(startInitial || start) / 1000}`);
+ const previous = occurrences[currentIndex - 1];
+ if (!previous) {
+ return parent.getOccurrences().catch(nop);
+ }
+ const movedBack = start <= previous.start;
+ let tmp = 0;
+ let newStart = movedBack ? Date.now() : previous.end;
+ const maxIdx = movedBack ? currentIndex + 1 : occurrences.length;
+ const startIdx = movedBack ? 0 : currentIndex;
+ for (let i = startIdx; i < maxIdx; i++) {
+ if (++tmp % 20 === 0) {
+ parent.getOccurrences({
+ from: newStart,
+ to: occurrences[i].end,
+ count: 20
+ }).catch(dump);
+ newStart = occurrences[i].end;
+ tmp = 0;
}
- });
- }
- persistedTypeArea.addChangeListener(this.getUniqueId(), (e, k, v) => {
- if (roomId === k) {
- onValueChanged(v || '');
- this.triggerOnUpdate(true);
+ parent.occurrences.remove(occurrences[i].uid);
}
- });
+ if (tmp) {
+ parent.getOccurrences({
+ from: newStart,
+ count: tmp,
+ to: movedBack ? occurrences[currentIndex].end : occurrences[occurrences.length - 1].end
+ }).catch(dump);
+ }
+ })() : this.getOccurrences().catch(nop);
}
+ megaChat.trigger(megaChat.plugins.meetingsManager.EVENTS[isCanceled ? 'CANCEL' : 'INITIALIZE'], this);
}
- componentWillUnmount() {
- super.componentWillUnmount();
- const self = this;
- self.triggerOnUpdate();
- if (megaChat.plugins.persistedTypeArea) {
- megaChat.plugins.persistedTypeArea.removeChangeListener(self.getUniqueId());
+ isSameAsOpts(opts) {
+ const {
+ timezone,
+ startDateTime,
+ endDateTime,
+ topic,
+ description,
+ f,
+ recurring
+ } = opts;
+ if (this.timezone !== timezone || this.start !== startDateTime || this.end !== endDateTime) {
+ return false;
}
- chatGlobalEventManager.removeEventListener('resize', `typingArea${ self.getUniqueId()}`);
- megaChat.off(`viewstateChange.gifpanel${this.getUniqueId()}`);
- }
- componentDidUpdate() {
- if (this.isComponentEventuallyVisible() && !window.getSelection().toString() && $('textarea:focus,select:focus,input:focus').filter(":visible").length === 0) {
- this.focusTypeArea();
+ if (this.title !== topic) {
+ return false;
}
- this.updateScroll();
- if (this.onUpdateCursorPosition) {
- const el = $('.chat-textarea:visible:first textarea:visible', this.domRef.current)[0];
- el.selectionStart = el.selectionEnd = this.onUpdateCursorPosition;
- this.onUpdateCursorPosition = false;
+ if (this.description !== description) {
+ return false;
}
- }
- updateScroll() {
- if (!this.isComponentEventuallyVisible() || !this.$node && !this.domRef && !this.domRef.current) {
- return;
+ if (this.flags !== f) {
+ return false;
}
- const $node = this.$node = this.$node || this.domRef.current;
- const $textarea = this.$textarea = this.$textarea || $('textarea:first', $node);
- const $scrollBlock = this.$scrollBlock = this.$scrollBlock || $textarea.closest('.textarea-scroll');
- const $preview = $('.message-preview', $scrollBlock).safeHTML(`${escapeHTML(this.props.text).replace(/\n/g, '
')}
`);
- const textareaHeight = $preview.height();
- $scrollBlock.height(Math.min(textareaHeight, this.getTextareaMaxHeight()));
- if (textareaHeight !== this._lastTextareaHeight) {
- this._lastTextareaHeight = textareaHeight;
- this.setState({
- textareaHeight
- });
- if (this.props.onResized) {
- this.props.onResized();
+ if (!!this.recurring ^ !!recurring) {
+ return false;
+ }
+ if (this.recurring) {
+ if (this.recurring.frequency !== recurring.frequency || this.recurring.interval !== (recurring.interval || 0)) {
+ return false;
+ }
+ if (this.recurring.end !== recurring.end) {
+ return false;
+ }
+ let diff = array.diff(this.recurring.weekDays, recurring.weekDays || []);
+ if (diff.removed.length + diff.added.length) {
+ return false;
+ }
+ diff = array.diff(this.recurring.monthDays, recurring.monthDays || []);
+ if (diff.removed.length + diff.added.length) {
+ return false;
+ }
+ if (Array.isArray(this.recurring.offset) && !Array.isArray(recurring.offset) || !Array.isArray(this.recurring.offset) && Array.isArray(recurring.offset)) {
+ return false;
+ }
+ if ((this.recurring.offset.value || 0) !== (recurring.offset.value || 0) || (this.recurring.offset.weekDay || 0) !== (recurring.offset.weekDay || 0)) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
+class MeetingsManager {
+ constructor(megaChat) {
+ this.EVENTS = {
+ INITIALIZE: 'onMeetingInitialize',
+ EDIT: 'onMeetingEdit',
+ CANCEL: 'onMeetingCancel',
+ LEAVE: 'onMeetingLeave',
+ OCCURRENCES_UPDATE: 'onOccurrencesUpdate'
+ };
+ this.startDayStrings = [l.schedule_occur_sun, l.schedule_occur_mon, l.schedule_occur_tue, l.schedule_occur_wed, l.schedule_occur_thu, l.schedule_occur_fri, l.schedule_occur_sat];
+ this.midDayStrings = [l.schedule_occur_sun_mid, l.schedule_occur_mon_mid, l.schedule_occur_tue_mid, l.schedule_occur_wed_mid, l.schedule_occur_thu_mid, l.schedule_occur_fri_mid, l.schedule_occur_sat_mid];
+ this.NOTIF_TITLES = {
+ recur: {
+ desc: {
+ update: l.schedule_notif_update_desc
+ },
+ name: {
+ update: l.schedule_mgmt_title
+ },
+ time: {
+ occur: l.schedule_mgmt_update_occur,
+ all: l.schedule_mgmt_update_recur
+ },
+ convert: l.schedule_mgmt_update_convert_recur,
+ inv: l.schedule_notif_invite_recur,
+ multi: l.schedule_notif_update_multi,
+ cancel: {
+ occur: l.schedule_mgmt_cancel_occur,
+ all: l.schedule_mgmt_cancel_recur
+ }
+ },
+ once: {
+ desc: {
+ update: l.schedule_notif_update_desc
+ },
+ name: {
+ update: l.schedule_mgmt_title
+ },
+ time: {
+ occur: '',
+ all: l.schedule_mgmt_update
+ },
+ convert: l.schedule_mgmt_update_convert,
+ inv: l.schedule_notif_invite,
+ multi: l.schedule_notif_update_multi,
+ cancel: {
+ occur: '',
+ all: l.schedule_mgmt_cancel
+ }
}
- $textarea.height(textareaHeight);
- }
- if (this.textareaScroll) {
- this.textareaScroll.reinitialise();
- }
- }
- getCursorPosition(el) {
- let pos = 0;
- if ('selectionStart' in el) {
- pos = el.selectionStart;
- } else if ('selection' in document) {
- el.focus();
- const sel = document.selection.createRange(),
- selLength = document.selection.createRange().text.length;
- sel.moveStart('character', -el.value.length);
- pos = sel.text.length - selLength;
- }
- return pos;
- }
- customIsEventuallyVisible() {
- return this.props.chatRoom.isCurrentlyActive;
- }
- handleWindowResize(e) {
- if (!this.isComponentEventuallyVisible()) {
- return;
- }
- if (e) {
- this.updateScroll();
- }
- this.triggerOnUpdate();
- }
- isActive() {
- return document.hasFocus() && this.$messages && this.$messages.is(":visible");
- }
- resetPrefillMode() {
- this.prefillMode = false;
- }
- onCopyCapture() {
- this.resetPrefillMode();
- }
- onCutCapture() {
- this.resetPrefillMode();
- }
- onPasteCapture() {
- this.resetPrefillMode();
- }
- render() {
- const self = this;
- const room = this.props.chatRoom;
- let buttons = null;
- if (self.props.showButtons === true) {
- buttons = [REaCt().createElement(ui_buttons.$, {
- key: "save",
- className: `${"mega-button right"} positive`,
- label: l[776],
- onClick: self.onSaveClicked.bind(self)
- }), REaCt().createElement(ui_buttons.$, {
- key: "cancel",
- className: "mega-button right",
- label: l.msg_dlg_cancel,
- onClick: self.onCancelClicked.bind(self)
- })];
- }
- const textareaStyles = {
- height: self.state.textareaHeight
};
- const textareaScrollBlockStyles = {};
- const newHeight = Math.min(self.state.textareaHeight, self.getTextareaMaxHeight());
- if (newHeight > 0) {
- textareaScrollBlockStyles.height = newHeight;
- }
- let emojiAutocomplete = null;
- if (self.state.emojiSearchQuery) {
- emojiAutocomplete = REaCt().createElement(EmojiAutocomplete, {
- emojiSearchQuery: self.state.emojiSearchQuery,
- emojiStartPos: self.state.emojiStartPos,
- emojiEndPos: self.state.emojiEndPos,
- typedMessage: self.props.text,
- onPrefill (e, emojiAlias) {
- if ($.isNumeric(self.state.emojiStartPos) && $.isNumeric(self.state.emojiEndPos)) {
- const msg = self.props.text;
- const pre = msg.substr(0, self.state.emojiStartPos);
- let post = msg.substr(self.state.emojiEndPos + 1, msg.length);
- const startPos = self.state.emojiStartPos;
- const fwdPos = startPos + emojiAlias.length;
- let endPos = fwdPos;
- self.onUpdateCursorPosition = fwdPos;
- self.prefillMode = true;
- if (post.substr(0, 2) == "::" && emojiAlias.substr(-1) == ":") {
- emojiAlias = emojiAlias.substr(0, emojiAlias.length - 1);
- endPos -= 1;
- } else {
- post = post ? post.substr(0, 1) !== " " ? ` ${ post}` : post : " ";
- self.onUpdateCursorPosition++;
- }
- self.setState({
- 'emojiEndPos': endPos
- });
- self.props.onValueChanged(pre + emojiAlias + post);
+ this.OCCUR_STRINGS = {
+ recur: {
+ daily: {
+ continuous: {
+ occur: l.schedule_recur_time_daily_cont,
+ skip: l.scheduled_recur_time_daily_skip_cont
+ },
+ limited: {
+ occur: l.schedule_recur_time_daily,
+ skip: l.scheduled_recur_time_daily_skip
}
},
- onSelect (e, emojiAlias, forceSend) {
- if ($.isNumeric(self.state.emojiStartPos) && $.isNumeric(self.state.emojiEndPos)) {
- const msg = self.props.text;
- const pre = msg.substr(0, self.state.emojiStartPos);
- let post = msg.substr(self.state.emojiEndPos + 1, msg.length);
- if (post.substr(0, 2) == "::" && emojiAlias.substr(-1) == ":") {
- emojiAlias = emojiAlias.substr(0, emojiAlias.length - 1);
- } else {
- post = post ? post.substr(0, 1) !== " " ? ` ${ post}` : post : " ";
- }
- const val = pre + emojiAlias + post;
- self.prefillMode = false;
- self.setState({
- 'emojiSearchQuery': false,
- 'emojiStartPos': false,
- 'emojiEndPos': false
- });
- self.props.onValueChanged(val);
- if (forceSend) {
- if (self.onConfirmTrigger($.trim(val)) !== true) {
- self.props.onValueChanged('');
- }
- }
+ weekly: {
+ continuous: {
+ list: l.schedule_recur_time_week_cont_list,
+ spec: l.schedule_recur_time_week_cont
+ },
+ limited: {
+ list: l.schedule_recur_time_week_list,
+ spec: l.schedule_recur_time_week
}
},
- onCancel () {
- self.prefillMode = false;
- self.setState({
- 'emojiSearchQuery': false,
- 'emojiStartPos': false,
- 'emojiEndPos': false
- });
+ monthly: {
+ continuous: {
+ num: l.schedule_recur_time_num_day_month_cont,
+ pos: [[l.schedule_recur_time_first_day_month_6_cont, l.schedule_recur_time_first_day_month_0_cont, l.schedule_recur_time_first_day_month_1_cont, l.schedule_recur_time_first_day_month_2_cont, l.schedule_recur_time_first_day_month_3_cont, l.schedule_recur_time_first_day_month_4_cont, l.schedule_recur_time_first_day_month_5_cont], [l.schedule_recur_time_second_day_month_6_cont, l.schedule_recur_time_second_day_month_0_cont, l.schedule_recur_time_second_day_month_1_cont, l.schedule_recur_time_second_day_month_2_cont, l.schedule_recur_time_second_day_month_3_cont, l.schedule_recur_time_second_day_month_4_cont, l.schedule_recur_time_second_day_month_5_cont], [l.schedule_recur_time_third_day_month_6_cont, l.schedule_recur_time_third_day_month_0_cont, l.schedule_recur_time_third_day_month_1_cont, l.schedule_recur_time_third_day_month_2_cont, l.schedule_recur_time_third_day_month_3_cont, l.schedule_recur_time_third_day_month_4_cont, l.schedule_recur_time_third_day_month_5_cont], [l.schedule_recur_time_fourth_day_month_6_cont, l.schedule_recur_time_fourth_day_month_0_cont, l.schedule_recur_time_fourth_day_month_1_cont, l.schedule_recur_time_fourth_day_month_2_cont, l.schedule_recur_time_fourth_day_month_3_cont, l.schedule_recur_time_fourth_day_month_4_cont, l.schedule_recur_time_fourth_day_month_5_cont], [l.schedule_recur_time_fifth_day_month_6_cont, l.schedule_recur_time_fifth_day_month_0_cont, l.schedule_recur_time_fifth_day_month_1_cont, l.schedule_recur_time_fifth_day_month_2_cont, l.schedule_recur_time_fifth_day_month_3_cont, l.schedule_recur_time_fifth_day_month_4_cont, l.schedule_recur_time_fifth_day_month_5_cont]],
+ last: [l.schedule_recur_time_fifth_day_month_6_cont, l.schedule_recur_time_fifth_day_month_0_cont, l.schedule_recur_time_fifth_day_month_1_cont, l.schedule_recur_time_fifth_day_month_2_cont, l.schedule_recur_time_fifth_day_month_3_cont, l.schedule_recur_time_fifth_day_month_4_cont, l.schedule_recur_time_fifth_day_month_5_cont]
+ },
+ limited: {
+ num: l.schedule_recur_time_num_day_month,
+ pos: [[l.schedule_recur_time_first_day_month_6, l.schedule_recur_time_first_day_month_0, l.schedule_recur_time_first_day_month_1, l.schedule_recur_time_first_day_month_2, l.schedule_recur_time_first_day_month_3, l.schedule_recur_time_first_day_month_4, l.schedule_recur_time_first_day_month_5], [l.schedule_recur_time_second_day_month_6, l.schedule_recur_time_second_day_month_0, l.schedule_recur_time_second_day_month_1, l.schedule_recur_time_second_day_month_2, l.schedule_recur_time_second_day_month_3, l.schedule_recur_time_second_day_month_4, l.schedule_recur_time_second_day_month_5], [l.schedule_recur_time_third_day_month_6, l.schedule_recur_time_third_day_month_0, l.schedule_recur_time_third_day_month_1, l.schedule_recur_time_third_day_month_2, l.schedule_recur_time_third_day_month_3, l.schedule_recur_time_third_day_month_4, l.schedule_recur_time_third_day_month_5], [l.schedule_recur_time_fourth_day_month_6, l.schedule_recur_time_fourth_day_month_0, l.schedule_recur_time_fourth_day_month_1, l.schedule_recur_time_fourth_day_month_2, l.schedule_recur_time_fourth_day_month_3, l.schedule_recur_time_fourth_day_month_4, l.schedule_recur_time_fourth_day_month_5], [l.schedule_recur_time_fifth_day_month_6, l.schedule_recur_time_fifth_day_month_0, l.schedule_recur_time_fifth_day_month_1, l.schedule_recur_time_fifth_day_month_2, l.schedule_recur_time_fifth_day_month_3, l.schedule_recur_time_fifth_day_month_4, l.schedule_recur_time_fifth_day_month_5]],
+ last: [l.schedule_recur_time_last_day_month_6, l.schedule_recur_time_last_day_month_0, l.schedule_recur_time_last_day_month_1, l.schedule_recur_time_last_day_month_2, l.schedule_recur_time_last_day_month_3, l.schedule_recur_time_last_day_month_4, l.schedule_recur_time_last_day_month_5]
+ }
+ },
+ [scheduleMetaChange.A.MODE.CANCELLED]: {
+ occur: l.schedule_occurrence_time,
+ all: ''
}
- });
- }
- const disabledTextarea = !!(room.pubCu25519KeyIsMissing === true || this.props.disabled);
- return REaCt().createElement("div", {
- ref: this.domRef,
- className: `
- typingarea-component
- ${this.props.className}
- `
- }, this.state.gifPanelActive && REaCt().createElement(gifPanel.Ay, {
- chatRoom: this.props.chatRoom,
- onToggle: () => {
- this.setState({
- gifPanelActive: false
- });
- delete this.gifResume;
- }
- }), REaCt().createElement("div", {
- className: `
- chat-textarea
- ${this.props.className}
- `
- }, emojiAutocomplete, self.props.children, self.props.editing ? null : REaCt().createElement(ui_buttons.$, {
- className: `
- popup-button
- gif-button
- ${this.state.gifPanelActive ? 'active' : ''}
- `,
- icon: "small-icon gif",
- disabled: this.props.disabled,
- onClick: () => this.setState(state => {
- delete this.gifResume;
- return {
- gifPanelActive: !state.gifPanelActive
- };
- })
- }), REaCt().createElement(ui_buttons.$, {
- className: "popup-button emoji-button",
- icon: "sprite-fm-theme icon-emoji",
- iconHovered: "sprite-fm-theme icon-emoji-active",
- disabled: this.props.disabled
- }, REaCt().createElement(emojiDropdown.L, {
- className: "popup emoji",
- vertOffset: 17,
- onClick: this.onEmojiClicked
- })), REaCt().createElement("hr", null), REaCt().createElement(perfectScrollbar.O, {
- chatRoom: self.props.chatRoom,
- className: "chat-textarea-scroll textarea-scroll",
- options: {
- 'suppressScrollX': true
},
- style: textareaScrollBlockStyles,
- ref: ref => {
- self.textareaScroll = ref;
- }
- }, REaCt().createElement("div", {
- className: "messages-textarea-placeholder"
- }, self.props.text ? null : REaCt().createElement(utils.zT, null, (l[18763] || `Write message to \u201c%s\u201d\u2026`).replace('%s', room.getRoomTitle()))), REaCt().createElement("textarea", {
- className: `
- ${"messages-textarea"}
- ${disabledTextarea ? 'disabled' : ''}
- `,
- onKeyUp: this.onTypeAreaKeyUp,
- onKeyDown: this.onTypeAreaKeyDown,
- onBlur: this.onTypeAreaBlur,
- onChange: this.onTypeAreaChange,
- onCopyCapture: this.onCopyCapture,
- onPasteCapture: this.onPasteCapture,
- onCutCapture: this.onCutCapture,
- value: self.props.text,
- style: textareaStyles,
- disabled: disabledTextarea,
- readOnly: disabledTextarea
- }), REaCt().createElement("div", {
- className: "message-preview"
- }))), buttons);
- }
-}, (0,applyDecoratedDescriptor.A)(_class.prototype, "handleWindowResize", [_dec], Object.getOwnPropertyDescriptor(_class.prototype, "handleWindowResize"), _class.prototype), _class);
-
-},
-
-501
-(_, EXP_, REQ_) {
-
-"use strict";
-REQ_.d(EXP_, {
-Y: () => withUpdateObserver
-});
-const _extends0__ = REQ_(168);
-const react1__ = REQ_(594);
-const react1 = REQ_.n(react1__);
-const _mixins_js2__ = REQ_(137);
-
-
-
-const withUpdateObserver = Component => class extends _mixins_js2__.w9 {
- constructor(...args) {
- super(...args);
- this.updateInterval = 600000;
- this.instanceRef = react1().createRef();
- this.intervalRef = undefined;
- this.state = {
- updated: 0
- };
- this.updateListener = () => {
- return this.isComponentVisible() && document.visibilityState === 'visible' && this.setState(state => ({
- updated: ++state.updated
- }), () => this.safeForceUpdate());
- };
- }
- componentWillUnmount() {
- super.componentWillUnmount();
- document.removeEventListener('visibilitychange', this.updateListener);
- clearInterval(this.intervalRef);
- }
- componentDidMount() {
- super.componentDidMount();
- document.addEventListener('visibilitychange', this.updateListener);
- this.intervalRef = setInterval(this.instanceRef.current[Component.updateListener] || this.updateListener, Component.updateInterval || this.updateInterval);
- }
- render() {
- return react1().createElement(Component, (0,_extends0__.A)({
- ref: this.instanceRef
- }, this.state, this.props));
- }
-};
-
-},
-
-994
-(_, EXP_, REQ_) {
-
-"use strict";
-REQ_.d(EXP_, {
-$: () => Button
-});
-const _extends0__ = REQ_(168);
-const react1__ = REQ_(594);
-const react1 = REQ_.n(react1__);
-const _chat_mixins_js2__ = REQ_(137);
-
-
-
-const BLURRABLE_CLASSES = '.conversationsApp, .join-meeting, .main-blur-block';
-class Button extends _chat_mixins_js2__.w9 {
- constructor(props) {
- super(props);
- this.domRef = react1().createRef();
- this.buttonClass = `.button`;
- this.state = {
- focused: false,
- hovered: false,
- iconHovered: ''
- };
- this.onBlur = e => {
- let _this$domRef;
- if (!this.isMounted()) {
- return;
- }
- if (!e || !$(e.target).closest(this.buttonClass).is((_this$domRef = this.domRef) == null ? void 0 : _this$domRef.current)) {
- this.setState({
- focused: false
- }, () => {
- this.unbindEvents();
- this.safeForceUpdate();
- });
+ once: {
+ [scheduleMetaChange.A.MODE.CREATED]: {
+ occur: l.schedule_occurrence_time
+ },
+ [scheduleMetaChange.A.MODE.EDITED]: {
+ occur: l.schedule_occurrence_time_recur
+ },
+ [scheduleMetaChange.A.MODE.CANCELLED]: {
+ occur: ''
+ }
}
};
- this.onClick = e => {
- let _this$domRef2;
- if (this.props.disabled === true) {
- e.preventDefault();
- e.stopPropagation();
- return;
- }
- if ($(e.target).closest('.popup').closest(this.buttonClass).is((_this$domRef2 = this.domRef) == null ? void 0 : _this$domRef2.current) && this.state.focused === true) {
- e.preventDefault();
- e.stopPropagation();
- return;
- }
- if ($(e.target).is('input, textarea, select')) {
+ this.megaChat = megaChat;
+ this.scheduledMeetings = megaChat.scheduledMeetings || new MegaDataMap();
+ this._goneOccurrences = {};
+ this.megaChat.rebind(this.EVENTS.CANCEL, ({
+ data
+ }) => this.archiveMeeting(data));
+ this.megaChat.rebind(this.EVENTS.LEAVE, ({
+ data
+ }) => this.detachMeeting(data));
+ this.megaChat.rebind(`${this.EVENTS.OCCURRENCES_UPDATE}.tracker`, ({
+ data
+ }) => {
+ if (!this._goneOccurrences[data.chatId]) {
return;
}
- if (this.state.focused === false) {
- if (this.props.onClick) {
- this.props.onClick(this, e);
- } else if (react1().Children.count(this.props.children) > 0) {
- this.setState({
- focused: true
- }, () => this.safeForceUpdate());
+ const {
+ chatId
+ } = data;
+ for (const scheduledId of Object.keys(this._goneOccurrences[chatId])) {
+ if (this._goneOccurrences[chatId][scheduledId] === -1) {
+ this._goneOccurrences[chatId][scheduledId] = this.scheduledMeetings[scheduledId] ? 0 : 1;
}
- } else if (this.state.focused === true) {
- this.setState({
- focused: false
- });
- this.unbindEvents();
- }
- };
- this.state.iconHovered = this.props.iconHovered || '';
- }
- UNSAFE_componentWillUpdate(nextProps, nextState) {
- if (nextProps.disabled === true && nextState.focused === true) {
- nextState.focused = false;
- }
- if (this.state.focused !== nextState.focused && nextState.focused === true) {
- this.bindEvents();
- if (this._pageChangeListener) {
- mBroadcaster.removeListener(this._pageChangeListener);
}
- this._pageChangeListener = mBroadcaster.addListener('pagechange', () => {
- if (this.state.focused === true) {
- this.onBlur();
- }
- });
- }
- }
- componentWillUnmount() {
- super.componentWillUnmount();
- this.unbindEvents();
+ });
}
- renderChildren() {
- return this.props.children && react1().Children.map(this.props.children, child => child && (typeof child.type === 'string' || child.type === undefined ? child : react1().cloneElement(child, {
- active: this.state.focused,
- closeDropdown: () => this.setState({
- focused: false
- }, () => this.unbindEvents()),
- onActiveChange: active => {
- let _this$domRef3;
- const $element = $(((_this$domRef3 = this.domRef) == null ? void 0 : _this$domRef3.current) || this.domNode);
- const $scrollables = $element.parents('.ps');
- if ($scrollables.length > 0) {
- $scrollables.map((k, element) => Ps[active ? 'disable' : 'enable'](element));
+ checkForNotifications() {
+ const time = Date.now();
+ const upcomingMeetings = Object.values(this.scheduledMeetings.toJS()).filter(c => c.isUpcoming);
+ for (const meeting of upcomingMeetings) {
+ if (pushNotificationSettings.isAllowedForChatId(meeting.chatId)) {
+ if (meeting.nextOccurrenceStart >= time + 9e5 && meeting.nextOccurrenceStart <= time + 96e4) {
+ const ss = Math.floor(meeting.nextOccurrenceStart / 1000);
+ const ns = Math.floor(time / 1000) + 900;
+ if (ss - ns <= 10) {
+ this.megaChat.trigger('onScheduleUpcoming', meeting);
+ } else {
+ tSleep(ss - ns).always(() => {
+ this.megaChat.trigger('onScheduleUpcoming', meeting);
+ });
+ }
+ } else if (meeting.nextOccurrenceStart >= time && meeting.nextOccurrenceStart < time + 6e4) {
+ const ss = Math.floor(meeting.nextOccurrenceStart / 1000);
+ const ns = Math.floor(time / 1000);
+ tSleep(ss - ns).always(() => {
+ this.megaChat.trigger('onScheduleStarting', meeting);
+ });
}
- child.props.onActiveChange == null || child.props.onActiveChange(active);
- return this[active ? 'bindEvents' : 'unbindEvents']();
}
- })));
+ }
}
- bindEvents() {
- $(BLURRABLE_CLASSES).rebind(`mousedown.button--${this.getUniqueId()}`, this.onBlur);
- $(document).rebind(`keyup.button--${this.getUniqueId()}`, ev => this.state.focused === true && ev.keyCode === 27 && this.onBlur());
- $(document).rebind(`closeDropdowns.${this.getUniqueId()}`, this.onBlur);
+ encodeData(data) {
+ return data && base64urlencode(to8(data));
}
- unbindEvents() {
- $(BLURRABLE_CLASSES).unbind(`mousedown.button--${this.getUniqueId()}`);
- $(document).off(`keyup.button--${this.getUniqueId()}`);
- $(document).off(`closeDropdowns.${this.getUniqueId()}`);
- mBroadcaster.removeListener(this._pageChangeListener);
+ decodeData(data) {
+ return data && from8(base64urldecode(data));
}
- render() {
+ getMeetingById(meetingId) {
+ return this.scheduledMeetings[meetingId];
+ }
+ getMeetingOrOccurrenceParent(meetingId) {
+ const meeting = this.scheduledMeetings[meetingId];
+ if (!meeting) {
+ return false;
+ }
+ if (meeting.parentId) {
+ return this.getMeetingOrOccurrenceParent(meeting.parentId);
+ }
+ return meeting;
+ }
+ getRoomByMeetingId() {}
+ async createMeeting(meetingInfo) {
+ await this.megaChat.createAndShowGroupRoomFor(meetingInfo.participants, meetingInfo.topic, {
+ keyRotation: false,
+ createChatLink: meetingInfo.link,
+ isMeeting: true,
+ openInvite: meetingInfo.openInvite,
+ waitingRoom: meetingInfo.waitingRoom,
+ scheduledMeeting: {
+ a: 'mcsmp',
+ s: meetingInfo.startDateTime / 1000,
+ e: meetingInfo.endDateTime / 1000,
+ tz: this.encodeData(meetingInfo.timezone),
+ t: this.encodeData(meetingInfo.topic),
+ d: this.encodeData(meetingInfo.description),
+ f: meetingInfo.sendInvite ? 0x01 : 0x00,
+ ...meetingInfo.recurring && {
+ r: {
+ f: meetingInfo.recurring.frequency,
+ wd: meetingInfo.recurring.weekDays,
+ md: meetingInfo.recurring.monthDays,
+ mwd: meetingInfo.recurring.offset,
+ ...meetingInfo.recurring.end && {
+ u: meetingInfo.recurring.end / 1000
+ },
+ ...meetingInfo.recurring.interval && {
+ i: meetingInfo.recurring.interval
+ }
+ }
+ }
+ }
+ });
+ }
+ async updateMeeting(meetingInfo, chatRoom) {
const {
- className,
- disabled,
- style,
- icon,
- iconHovered,
- label,
- attrs,
- toggle,
- secondLabel,
- secondLabelClass
- } = this.props;
- const isMegaButton = className && className.indexOf('mega-button') > -1;
- const TagName = isMegaButton ? 'button' : 'div';
- return react1().createElement(TagName, (0,_extends0__.A)({
- ref: this.domRef,
- className: `
- button
- ${className || ''}
- ${disabled ? 'disabled' : ''}
- ${this.state.focused ? 'active active-dropdown' : ''}
- `,
- style,
- onClick: this.onClick,
- onMouseEnter: () => iconHovered && this.setState({
- hovered: true
- }),
- onMouseLeave: () => iconHovered && this.setState({
- hovered: false
- })
- }, attrs), icon && !isMegaButton && react1().createElement("div", null, react1().createElement("i", {
- className: this.state.hovered ? this.state.iconHovered : icon
- })), icon && isMegaButton && react1().createElement("div", null, react1().createElement("i", {
- className: this.state.hovered ? this.state.iconHovered : icon
- })), label && react1().createElement("span", null, label), secondLabel && react1().createElement("span", {
- className: secondLabelClass ? secondLabelClass : ''
- }, secondLabel), toggle && react1().createElement("div", {
- className: `
- mega-switch
- ${toggle.className ? toggle.className : ''}
- ${toggle.enabled ? 'toggle-on' : ''}
- `,
- role: "switch",
- "aria-checked": !!toggle.enabled,
- onClick: ev => {
- ev.stopPropagation();
- if (this.props.toggle.onClick) {
- this.props.toggle.onClick();
+ scheduledMeeting,
+ chatId,
+ publicLink,
+ options
+ } = chatRoom;
+ await megaChat.plugins.chatdIntegration.updateScheduledMeeting(meetingInfo, scheduledMeeting.id, chatId);
+ const nextParticipants = meetingInfo.participants;
+ const prevParticipants = chatRoom.getParticipantsExceptMe();
+ const participantsDiff = JSON.stringify(nextParticipants) !== JSON.stringify(prevParticipants);
+ if (participantsDiff) {
+ const removed = prevParticipants.filter(h => !nextParticipants.includes(h));
+ const added = nextParticipants.filter(h => !prevParticipants.includes(h));
+ if (removed.length) {
+ for (let i = removed.length; i--;) {
+ chatRoom.trigger('onRemoveUserRequest', [removed[i]]);
}
}
- }, react1().createElement("div", {
- className: `mega-feature-switch sprite-fm-mono-after
- ${toggle.enabled ? 'icon-check-after' : 'icon-minimise-after'}`
- })), this.renderChildren());
+ if (added.length) {
+ chatRoom.trigger('onAddUserRequest', [added]);
+ }
+ }
+ if (!!meetingInfo.link !== !!publicLink) {
+ chatRoom.updatePublicHandle(!meetingInfo.link, meetingInfo.link);
+ }
+ if (meetingInfo.waitingRoom !== options[chat_chatRoom.U_.WAITING_ROOM]) {
+ chatRoom.toggleWaitingRoom();
+ }
+ if (meetingInfo.openInvite !== options[chat_chatRoom.U_.OPEN_INVITE]) {
+ chatRoom.toggleOpenInvite();
+ }
}
-}
-
-},
-
-911
-(_, EXP_, REQ_) {
-
-"use strict";
-REQ_.r(EXP_);
-REQ_.d(EXP_, {
-Dropdown: () => Dropdown,
-DropdownContactsSelector: () => DropdownContactsSelector,
-DropdownItem: () => DropdownItem
-});
-const _utils_jsx0__ = REQ_(314);
-const _chat_mixins1__ = REQ_(137);
-const _chat_ui_contacts_jsx2__ = REQ_(251);
-const React = REQ_(594);
-
-
-
-class Dropdown extends _chat_mixins1__.w9 {
- constructor(props) {
- super(props);
- this.domRef = React.createRef();
- this.onActiveChange = this.onActiveChange.bind(this);
- this.onResized = this.onResized.bind(this);
+ cancelMeeting(scheduledMeeting, chatId) {
+ return this.megaChat.plugins.chatdIntegration.cancelScheduledMeeting(scheduledMeeting, chatId);
}
- UNSAFE_componentWillUpdate(nextProps) {
- if (this.props.active != nextProps.active) {
- this.onActiveChange(nextProps.active);
+ deleteMeeting(scheduledMeetingId, chatId) {
+ return this.megaChat.plugins.chatdIntegration.deleteScheduledMeeting(scheduledMeetingId, chatId);
+ }
+ attachMeeting(meetingInfo, fromActionPacket) {
+ const chatRoom = meetingInfo.chatRoom || this.megaChat.getChatById(meetingInfo.cid);
+ if (chatRoom) {
+ const scheduledMeeting = new ScheduledMeeting(this.megaChat, {
+ chatRoom,
+ ...meetingInfo
+ }, fromActionPacket);
+ this.scheduledMeetings.set(meetingInfo.id, scheduledMeeting);
+ return scheduledMeeting;
}
}
- specShouldComponentUpdate(nextProps, nextState) {
- if (this.props.active != nextProps.active) {
- if (this.props.onBeforeActiveChange) {
- this.props.onBeforeActiveChange(nextProps.active);
+ detachMeeting(scheduledMeeting) {
+ if (scheduledMeeting) {
+ this.archiveMeeting(scheduledMeeting);
+ scheduledMeeting.chatRoom.scheduledMeeting = null;
+ this.scheduledMeetings.remove(scheduledMeeting.id);
+ if (fmdb) {
+ fmdb.del('mcsm', scheduledMeeting.id);
}
- return true;
- } else if (this.props.focused != nextProps.focused) {
- return true;
- } else if (this.state && this.state.active != nextState.active) {
- return true;
}
- return undefined;
}
- onActiveChange(newVal) {
- if (this.props.onActiveChange) {
- this.props.onActiveChange(newVal);
- }
+ archiveMeeting(scheduledMeeting) {
+ const {
+ chatRoom
+ } = scheduledMeeting;
+ tSleep(2).then(() => chatRoom.hasMessages(true) ? null : chatRoom.archive());
}
- reposElementUsing(element, obj, info) {
- let $element;
- if (this.popupElement) {
- $element = $(this.popupElement);
+ filterUpcomingMeetings(conversations) {
+ const upcomingMeetings = Object.values(conversations || {}).filter(c => {
+ return c.isDisplayable() && c.isMeeting && c.scheduledMeeting && c.scheduledMeeting.isUpcoming && c.iAmInRoom() && !c.havePendingCall();
+ }).sort((a, b) => a.scheduledMeeting.nextOccurrenceStart - b.scheduledMeeting.nextOccurrenceStart || a.ctime - b.ctime);
+ const nextOccurrences = upcomingMeetings.reduce((nextOccurrences, chatRoom) => {
+ const {
+ nextOccurrenceStart
+ } = chatRoom.scheduledMeeting;
+ if ((0,helpers.cK)(nextOccurrenceStart)) {
+ nextOccurrences.today.push(chatRoom);
+ } else if ((0,helpers.ef)(nextOccurrenceStart)) {
+ nextOccurrences.tomorrow.push(chatRoom);
+ } else {
+ const date = time2date(nextOccurrenceStart / 1000, 19);
+ if (!nextOccurrences.rest[date]) {
+ nextOccurrences.rest[date] = [];
+ }
+ nextOccurrences.rest[date].push(chatRoom);
+ }
+ return nextOccurrences;
+ }, {
+ today: [],
+ tomorrow: [],
+ rest: {}
+ });
+ return {
+ upcomingMeetings,
+ nextOccurrences
+ };
+ }
+ getOccurrenceStrings(meta) {
+ const res = [];
+ const {
+ prevTiming,
+ timeRules,
+ mode,
+ occurrence,
+ recurring,
+ converted
+ } = meta;
+ const {
+ MODE
+ } = scheduleMetaChange.A;
+ if (!mode) {
+ return res;
+ }
+ const {
+ OCCUR_STRINGS
+ } = this;
+ let string;
+ if (recurring) {
+ res.push(this._parseOccurrence(timeRules, mode, occurrence));
+ if (prevTiming && !(occurrence && mode === MODE.CANCELLED)) {
+ res.push(this._parseOccurrence(prevTiming, mode, occurrence));
+ }
} else {
- return;
- }
- const self = this;
- let vertOffset = 0;
- let horizOffset = 0;
- if (!self.props.noArrow) {
- const $arrow = $('.dropdown-white-arrow', $element);
- let arrowHeight;
- if (self.props.arrowHeight) {
- arrowHeight = self.props.arrowHeight;
- if (info.vertical === "top") {
- arrowHeight = 0;
+ const {
+ startTime,
+ endTime
+ } = timeRules;
+ string = OCCUR_STRINGS.once[mode].occur;
+ res.push(string.replace('%1', toLocaleTime(startTime)).replace('%2', toLocaleTime(endTime)).replace('%6', time2date(startTime, 20)).replace('%s', time2date(startTime, 11)));
+ if (prevTiming) {
+ const {
+ startTime: pStartTime,
+ endTime: pEndTime
+ } = prevTiming;
+ if (converted) {
+ res.push(this._parseOccurrence(prevTiming, mode, occurrence));
} else {
- arrowHeight *= -1;
+ res.push(string.replace('%1', toLocaleTime(pStartTime)).replace('%2', toLocaleTime(pEndTime)).replace('%6', time2date(pStartTime, 20)).replace('%s', time2date(pStartTime, 11)));
}
- } else {
- arrowHeight = $arrow.outerHeight();
}
- if (info.vertical === "top") {
- $(element).removeClass("down-arrow").addClass("up-arrow");
+ }
+ return res;
+ }
+ _parseOccurrence(timeRules, mode, occurrence) {
+ const {
+ startTime,
+ endTime,
+ days,
+ dayInt,
+ interval,
+ month,
+ recurEnd,
+ skipDay
+ } = timeRules;
+ const {
+ recur,
+ once
+ } = this.OCCUR_STRINGS;
+ const occurrenceEnd = recurEnd ? 'limited' : 'continuous';
+ let string = '';
+ if (recur[mode]) {
+ return occurrence ? recur[mode].occur.replace('%1', toLocaleTime(startTime)).replace('%2', toLocaleTime(endTime)).replace('%s', time2date(startTime, 11)) : recur[mode].all;
+ } else if (month) {
+ const {
+ count,
+ occur
+ } = month;
+ string = count < 0 ? mega.icu.format(recur.monthly[occurrenceEnd].last[occur], interval) : mega.icu.format(recur.monthly[occurrenceEnd].pos[count][occur], interval);
+ return string.replace('%1', toLocaleTime(startTime)).replace('%2', toLocaleTime(endTime)).replace('%3', time2date(startTime, 2)).replace('%4', time2date(recurEnd, 2));
+ } else if (days) {
+ if (days.length > 1) {
+ if (days.length === 7) {
+ return recur.daily[occurrenceEnd].occur.replace('%1', toLocaleTime(startTime)).replace('%2', toLocaleTime(endTime)).replace('%3', time2date(startTime, 2)).replace('%4', time2date(recurEnd, 2));
+ }
+ const weekDays = days.map((day, idx) => {
+ if (idx) {
+ return this.midDayStrings[day];
+ }
+ return this.startDayStrings[day];
+ });
+ string = mega.icu.format(recur.weekly[occurrenceEnd].list, interval);
+ string = mega.utils.trans.listToString(weekDays, string);
} else {
- $(element).removeClass("up-arrow").addClass("down-arrow");
+ string = mega.icu.format(recur.weekly[occurrenceEnd].spec, interval).replace('%s', this.startDayStrings[days[0]]);
}
- vertOffset += info.vertical === "top" ? arrowHeight : 0;
- }
- if (self.props.vertOffset) {
- vertOffset += self.props.vertOffset * (info.vertical === "top" ? 1 : -1);
- }
- if (self.props.horizOffset) {
- horizOffset += self.props.horizOffset;
- }
- $(element).css({
- left: `${obj.left + 0 + horizOffset }px`,
- top: `${obj.top + vertOffset }px`
- });
- if (this.props.positionLeft) {
- $(element).css({
- left: this.props.positionLeft
- });
+ return string.replace('%1', toLocaleTime(startTime)).replace('%2', toLocaleTime(endTime)).replace('%3', time2date(startTime, 2)).replace('%4', time2date(recurEnd, 2));
+ } else if (dayInt) {
+ string = mega.icu.format(recur.monthly[occurrenceEnd].num, interval);
+ return string.replace('%1', toLocaleTime(startTime)).replace('%2', toLocaleTime(endTime)).replace('%3', time2date(startTime, 2)).replace('%4', time2date(recurEnd, 2)).replace('%5', dayInt);
+ } else if (skipDay) {
+ string = mega.icu.format(recur.daily[occurrenceEnd].skip, interval);
+ return string.replace('%1', toLocaleTime(startTime)).replace('%2', toLocaleTime(endTime)).replace('%3', time2date(startTime, 2)).replace('%4', time2date(recurEnd, 2));
}
+ string = once[mode].occur;
+ return string.replace('%1', toLocaleTime(startTime)).replace('%2', toLocaleTime(endTime)).replace('%6', time2date(startTime, 20)).replace('%s', time2date(startTime, 11));
}
- onResized() {
- const self = this;
- if (this.props.active === true && this.popupElement) {
- const $element = $(this.popupElement);
- const $positionToElement = $('.button.active-dropdown:visible');
- if ($positionToElement.length === 0) {
- return;
+ getFormattingMeta(scheduledId, data, chatRoom) {
+ const {
+ MODE
+ } = scheduleMetaChange.A;
+ const meta = {
+ userId: data.sender || false,
+ timeRules: {},
+ mode: MODE.EDITED,
+ handle: scheduledId,
+ cid: chatRoom.chatId
+ };
+ const changeSet = data.schedChange || data.cs || false;
+ if (changeSet) {
+ const {
+ s,
+ e,
+ c,
+ r,
+ t,
+ d: desc
+ } = changeSet;
+ let onlyTitle = typeof t !== 'undefined';
+ if (Array.isArray(c) && c[1]) {
+ meta.mode = MODE.CANCELLED;
}
- let $container = $positionToElement.closest('.messages.scroll-area');
- if ($container.length === 0) {
- $container = $(document.body);
+ if (Array.isArray(s)) {
+ meta.prevTiming = {
+ startTime: s[0]
+ };
+ meta.timeRules.startTime = s[1] || s[0];
}
- $element.css('margin-left', '');
- $element.position({
- of: $positionToElement,
- my: self.props.positionMy ? self.props.positionMy : "center top",
- at: self.props.positionAt ? self.props.positionAt : "center bottom",
- collision: this.props.collision || 'flipfit',
- within: self.props.wrapper || $container,
- using (obj, info) {
- self.reposElementUsing(this, obj, info);
+ const meeting = this.getMeetingOrOccurrenceParent(scheduledId);
+ if (Array.isArray(e)) {
+ if (!meta.prevTiming) {
+ meta.prevTiming = {
+ startTime: meeting ? Math.floor(meeting.start / 1000) : 0
+ };
+ meta.timeRules.startTime = meta.prevTiming.startTime;
}
- });
- }
- }
- componentDidMount() {
- super.componentDidMount();
- chatGlobalEventManager.addEventListener('resize', `drpdwn${ this.getUniqueId()}`, this.onResized.bind(this));
- this.onResized();
- const self = this;
- $(document.body).rebind(`closeAllDropdownsExcept.drpdwn${ this.getUniqueId()}`, (e, target) => {
- if (self.props.active && target !== self) {
- if (self.props && self.props.closeDropdown) {
- self.props.closeDropdown();
+ meta.prevTiming.endTime = e[0];
+ meta.timeRules.endTime = e[1] || e[0];
+ onlyTitle = false;
+ }
+ if (desc) {
+ meta.description = true;
+ onlyTitle = false;
+ }
+ if (Array.isArray(r)) {
+ const parseR = r => r ? typeof r === 'string' ? JSON.parse(r) : r : false;
+ const prev = parseR(r[0]);
+ const next = parseR(r[1]);
+ if (r.length === 1) {
+ meta.converted = false;
+ meta.timeRules = this._recurringTimings(prev, meta.timeRules || {});
+ meta.prevTiming = this._recurringTimings(prev, meta.prevTiming);
+ meta.recurring = r[0] !== '';
+ } else {
+ meta.converted = !!(!!prev ^ !!next);
+ if (prev) {
+ meta.prevTiming = this._recurringTimings(prev, meta.prevTiming || {});
+ }
+ meta.timeRules = this._recurringTimings(next, meta.timeRules || {});
+ meta.recurring = next !== false;
}
+ onlyTitle = false;
}
- });
- }
- componentDidUpdate() {
- this.onResized();
- }
- componentWillUnmount() {
- super.componentWillUnmount();
- $(document.body).unbind(`closeAllDropdownsExcept.drpdwn${ this.getUniqueId()}`);
- if (this.props.active) {
- this.onActiveChange(false);
- }
- chatGlobalEventManager.removeEventListener('resize', `drpdwn${ this.getUniqueId()}`);
- }
- doRerender() {
- const self = this;
- setTimeout(() => {
- self.safeForceUpdate();
- }, 100);
- setTimeout(() => {
- self.onResized();
- }, 200);
- }
- renderChildren() {
- const self = this;
- return React.Children.map(this.props.children, (child) => {
- if (child) {
- let activeVal = self.props.active || self.state.active;
- activeVal = String(activeVal);
- return React.cloneElement(child, {
- active: activeVal
- });
+ if (!meeting || meeting.id !== scheduledId) {
+ meta.occurrence = true;
+ meta.recurring = true;
}
- return null;
- });
+ if (Array.isArray(t)) {
+ meta.topicChange = true;
+ meta.onlyTitle = onlyTitle;
+ meta.topic = this.decodeData(t[1]);
+ meta.oldTopic = this.decodeData(t[0]);
+ }
+ return meta;
+ }
+ return this.noCsMeta(scheduledId, data, chatRoom);
}
- render() {
- if (this.props.active !== true) {
- return null;
+ _recurringTimings(meta, obj) {
+ if (!meta) {
+ return obj;
+ }
+ obj.recurEnd = meta.u || false;
+ obj.interval = meta.i || 1;
+ if (meta.wd) {
+ obj.days = meta.wd.sort((a, b) => a - b).map(wd => wd === 7 ? 0 : wd);
+ }
+ if (meta.md) {
+ obj.dayInt = meta.md[0];
+ }
+ if (meta.mwd) {
+ obj.month = meta.mwd.map(oc => {
+ return {
+ count: (oc[0] || 1) - 1,
+ occur: oc[1] ? oc[1] === 7 ? 0 : oc[1] : 1
+ };
+ })[0];
}
- const self = this;
- let child = null;
- if (this.props.children) {
- child = React.createElement("div", {
- ref: this.domRef
- }, self.renderChildren());
- } else if (this.props.dropdownItemGenerator) {
- child = this.props.dropdownItemGenerator(this);
+ if (meta.f === 'd' && meta.i > 1) {
+ obj.skipDay = true;
+ } else if (meta.f === 'd' && meta.i === 1) {
+ obj.days = [1, 2, 3, 4, 5, 6, 0];
}
- if (!child && !this.props.forceShowWhenEmpty) {
- if (this.props.active !== false) {
- queueMicrotask(() => {
- self.onActiveChange(false);
- });
+ return obj;
+ }
+ noCsMeta(scheduledId, data, chatRoom) {
+ const meta = {
+ timeRules: {},
+ userId: data.sender || false,
+ ap: data,
+ handle: scheduledId,
+ cid: chatRoom.chatId
+ };
+ if (!this.getMeetingOrOccurrenceParent(scheduledId) && !chatRoom.scheduledMeeting) {
+ const res = this._checkOccurrenceAwait(chatRoom, scheduledId, meta);
+ if (res) {
+ return res;
}
- return null;
}
- return React.createElement(_utils_jsx0__.Ay.RenderTo, {
- element: document.body,
- className: `
- dropdown
- body
- ${this.props.noArrow ? '' : 'dropdown-arrow up-arrow'}
- ${this.props.className || ''}
- `,
- style: this.popupElement && {
- zIndex: 123,
- position: 'absolute',
- width: this.props.styles ? this.props.styles.width : undefined
- },
- popupDidMount: popupElement => {
- this.popupElement = popupElement;
- this.onResized();
- },
- popupWillUnmount: () => {
- delete this.popupElement;
+ const meeting = this.getMeetingOrOccurrenceParent(scheduledId) || chatRoom.scheduledMeeting;
+ assert(meeting, `Invalid scheduled meeting state for ${scheduledId} msg`);
+ const toS = ms => Math.floor(ms / 1000);
+ const {
+ MODE
+ } = scheduleMetaChange.A;
+ meta.timeRules.startTime = toS(meeting.start);
+ meta.timeRules.endTime = toS(meeting.end);
+ meta.topic = meeting.title;
+ meta.recurring = !!meeting.recurring;
+ meta.mode = meeting.canceled ? MODE.CANCELLED : MODE.CREATED;
+ meta.occurrence = meta.recurring && meeting.id !== scheduledId;
+ if (!meta.occurrence && !meeting.canceled) {
+ meta.mode = MODE.CREATED;
+ }
+ const cal = ms => {
+ const date = new Date(ms);
+ return {
+ date: date.getDate(),
+ month: time2date(toS(ms), 12)
+ };
+ };
+ if (meta.occurrence) {
+ const occurrences = meeting.getOccurrencesById(scheduledId);
+ if (!occurrences) {
+ meta.mode = MODE.EDITED;
+ const res = this._checkOccurrenceAwait(chatRoom, scheduledId, meta);
+ if (res) {
+ return res;
+ }
+ meta.ap = data;
+ return meta;
}
- }, React.createElement("div", {
- ref: this.domRef,
- onClick: () => {
- $(document.body).trigger('closeAllDropdownsExcept', this);
+ meta.mode = occurrences.some(o => o.canceled) ? MODE.CANCELLED : MODE.EDITED;
+ meta.calendar = cal(occurrences[0].start);
+ const timeDiff = meta.timeRules.endTime - meta.timeRules.startTime;
+ meta.timeRules.startTime = toS(occurrences[0].start);
+ meta.timeRules.endTime = toS(occurrences[0].end);
+ if (occurrences.length === 1 && occurrences[0].startInitial) {
+ meta.prevTiming = {
+ startTime: toS(occurrences[0].startInitial)
+ };
+ meta.prevTiming.endTime = meta.prevTiming.startTime + timeDiff;
}
- }, this.props.noArrow ? null : React.createElement("i", {
- className: "dropdown-white-arrow"
- }), child));
- }
-}
-Dropdown.defaultProps = {
- 'requiresUpdateOnResize': true
-};
-class DropdownContactsSelector extends _chat_mixins1__.w9 {
- constructor(props) {
- super(props);
- this.state = {
- 'selected': this.props.selected ? this.props.selected : []
- };
- this.onSelectClicked = this.onSelectClicked.bind(this);
- this.onSelected = this.onSelected.bind(this);
- }
- specShouldComponentUpdate(nextProps, nextState) {
- if (this.props.active != nextProps.active) {
- return true;
- } else if (this.props.focused != nextProps.focused) {
- return true;
- } else if (this.state && this.state.active != nextState.active) {
- return true;
- } else if (this.state && JSON.stringify(this.state.selected) != JSON.stringify(nextState.selected)) {
- return true;
+ } else if (meta.recurring) {
+ const {
+ end,
+ weekDays = [],
+ interval,
+ monthDays = [],
+ offset,
+ frequency
+ } = meeting.recurring;
+ meta.recurring = true;
+ meta.timeRules.recurEnd = end ? toS(end) : false;
+ meta.timeRules.interval = interval || 1;
+ if (frequency === 'd' && interval > 1) {
+ meta.timeRules.skipDay = true;
+ } else if (frequency === 'd' && interval === 1) {
+ meta.timeRules.days = [1, 2, 3, 4, 5, 6, 0];
+ }
+ if (weekDays.length) {
+ meta.timeRules.days = weekDays.sort((a, b) => a - b).map(wd => wd === 7 ? 0 : wd);
+ }
+ if (monthDays.length) {
+ meta.timeRules.dayInt = monthDays[0];
+ }
+ if (!Array.isArray(offset)) {
+ meta.timeRules.month = {
+ count: (offset.value || 1) - 1,
+ occur: offset.weekDay ? offset.weekDay === 7 ? 0 : offset.weekDay : 1
+ };
+ }
+ meta.calendar = cal(meeting.start);
} else {
- return undefined;
+ meta.calendar = cal(meeting.start);
}
- }
- onSelected(nodes) {
- this.setState({
- 'selected': nodes
- });
- if (this.props.onSelected) {
- this.props.onSelected(nodes);
+ if (!meta.occurrence && meeting.canceled && $.len(meta.timeRules)) {
+ meta.mode = MODE.CREATED;
}
- this.forceUpdate();
- }
- onSelectClicked() {
- this.props.onSelectClicked();
- }
- render() {
- return React.createElement(Dropdown, {
- className: `
- popup contacts-search
- ${this.props.className}
- tooltip-blur
- `,
- active: this.props.active,
- closeDropdown: this.props.closeDropdown,
- ref: ref => {
- this.dropdownRef = ref;
- },
- positionMy: this.props.positionMy,
- positionAt: this.props.positionAt,
- arrowHeight: this.props.arrowHeight,
- horizOffset: this.props.horizOffset,
- vertOffset: this.props.vertOffset,
- noArrow: true
- }, React.createElement(_chat_ui_contacts_jsx2__.ContactPickerWidget, {
- onClose: this.props.closeDropdown,
- onEventuallyUpdated: () => {
- let _this$dropdownRef;
- return (_this$dropdownRef = this.dropdownRef) == null ? void 0 : _this$dropdownRef.doRerender();
- },
- active: this.props.active,
- className: "popup contacts-search tooltip-blur small-footer",
- contacts: M.u,
- selectFooter: this.props.selectFooter,
- megaChat: this.props.megaChat,
- exclude: this.props.exclude,
- allowEmpty: this.props.allowEmpty,
- multiple: this.props.multiple,
- topButtons: this.props.topButtons,
- showAddContact: this.props.showAddContact,
- onAddContact: () => eventlog(500237),
- onSelected: () => eventlog(500238),
- onSelectDone: this.props.onSelectDone,
- multipleSelectedButtonLabel: this.props.multipleSelectedButtonLabel,
- singleSelectedButtonLabel: this.props.singleSelectedButtonLabel,
- nothingSelectedButtonLabel: this.props.nothingSelectedButtonLabel
- }));
- }
-}
-DropdownContactsSelector.defaultProps = {
- requiresUpdateOnResize: true
-};
-class DropdownItem extends _chat_mixins1__.w9 {
- constructor(props) {
- super(props);
- this.domRef = React.createRef();
- this.state = {
- 'isClicked': false
- };
- this.onClick = this.onClick.bind(this);
- this.onMouseOver = this.onMouseOver.bind(this);
- }
- renderChildren() {
- const self = this;
- return React.Children.map(this.props.children, (child) => {
- const props = {
- active: self.state.isClicked,
- closeDropdown () {
- self.setState({
- 'isClicked': false
- });
- }
- };
- return React.cloneElement(child, props);
- });
+ delete meta.ap;
+ return meta;
}
- onClick(ev) {
- const {
- children,
- persistent,
- onClick
- } = this.props;
- if (children) {
- ev.stopPropagation();
- ev.preventDefault();
- this.setState({
- isClicked: !this.state.isClicked
- });
+ _checkOccurrenceAwait(chatRoom, scheduledId, meta) {
+ if (!this._goneOccurrences[chatRoom.chatId]) {
+ this._goneOccurrences[chatRoom.chatId] = {};
}
- if (!persistent) {
- $(document).trigger('closeDropdowns');
+ if (typeof this._goneOccurrences[chatRoom.chatId][scheduledId] === 'undefined') {
+ this._goneOccurrences[chatRoom.chatId][scheduledId] = -1;
+ return meta;
+ }
+ const datum = this._goneOccurrences[chatRoom.chatId];
+ if (datum[scheduledId] === -1) {
+ return meta;
+ } else if (datum[scheduledId] === 1) {
+ meta.gone = true;
+ return meta;
}
- return onClick && onClick(ev);
+ return false;
}
- onMouseOver(e) {
- if (this.props.submenu) {
- const $contextItem = $(e.target).closest(".contains-submenu");
- const $subMenu = $contextItem.next('.submenu');
- const contextTopPos = $contextItem.position().top;
- let contextleftPos = 0;
- $contextItem.addClass("opened");
- $subMenu.addClass("active");
- contextleftPos = $contextItem.offset().left + $contextItem.outerWidth() + $subMenu.outerWidth() + 10;
- if (contextleftPos > $(document.body).width()) {
- $subMenu.addClass("left-position");
+ areMetaObjectsSame(obj1, obj2) {
+ if (obj1 && !obj2 || !obj1 && obj2) {
+ return false;
+ }
+ const keys = Object.keys(obj1);
+ if (keys.length !== $.len(obj2)) {
+ return false;
+ }
+ const diff = array.diff(keys, Object.keys(obj2));
+ if (diff.removed.length + diff.added.length) {
+ return false;
+ }
+ for (const key of keys) {
+ if (!obj2.hasOwnProperty(key)) {
+ return false;
+ }
+ if (obj1[key] instanceof Object && obj2[key] instanceof Object) {
+ if (!this.areMetaObjectsSame(obj1[key], obj2[key])) {
+ return false;
+ }
+ } else if (Array.isArray(obj1[key]) && Array.isArray(obj2[key])) {
+ const keyDiff = array.diff(obj1[key], obj2[key]);
+ if (keyDiff.removed.length + keyDiff.added.length) {
+ return false;
+ }
+ } else if (obj1[key] !== obj2[key]) {
+ return false;
}
- $subMenu.css({
- "top": contextTopPos
- });
- } else if (!$(e.target).parent('.submenu').length) {
- const $dropdown = $(e.target).closest(".dropdown.body");
- $dropdown.find(".contains-submenu").removeClass("opened");
- $dropdown.find(".submenu").removeClass("active");
}
- }
- render() {
- const {
- className,
- disabled,
- label,
- icon,
- submenu
- } = this.props;
- return React.createElement("div", {
- ref: this.domRef,
- className: `
- dropdown-item
- ${className ? className : ''}
- ${submenu ? 'contains-submenu' : ''}
- ${disabled ? 'disabled' : ''}
- `,
- onClick: disabled ? undefined : ev => this.onClick(ev),
- onMouseOver: this.onMouseOver
- }, icon && React.createElement("i", {
- className: icon
- }), label && React.createElement("span", null, label), submenu ? React.createElement("i", {
- className: "sprite-fm-mono icon-arrow-right submenu-icon"
- }) : '', React.createElement("div", null, this.renderChildren()));
+ return true;
}
}
-DropdownItem.defaultProps = {
- requiresUpdateOnResize: true
-};
-
-},
-
-844
-(_, EXP_, REQ_) {
-
-"use strict";
-REQ_.d(EXP_, {
-L: () => DropdownEmojiSelector
-});
-const _extends0__ = REQ_(168);
-const _chat_mixins1__ = REQ_(137);
+ const meetingsManager = MeetingsManager;
+window.MeetingsManager = MeetingsManager;
+// EXTERNAL MODULE: ./node_modules/@babel/runtime/helpers/esm/applyDecoratedDescriptor.js
+const applyDecoratedDescriptor = REQ_(793);
+// EXTERNAL MODULE: ./js/chat/mixins.js
+const mixins = REQ_(8264);
+;// ./js/chat/chatOnboarding.jsx
-const React = REQ_(594);
+let _dec, _class;
-const DropdownsUI = REQ_(911);
-const PerfectScrollbar = REQ_(486).O;
-class DropdownEmojiSelector extends _chat_mixins1__.w9 {
- constructor(props) {
- super(props);
- this.domRef = React.createRef();
- this.emojiSearchRef = React.createRef();
- this.data_categories = null;
- this.data_emojis = null;
- this.data_emojiByCategory = null;
- this.customCategoriesOrder = ["frequently_used", "people", "nature", "food", "activity", "travel", "objects", "symbols", "flags"];
- this.frequentlyUsedEmojis = ['slight_smile', 'grinning', 'smile', 'rofl', 'wink', 'yum', 'rolling_eyes', 'stuck_out_tongue', 'smiling_face_with_3_hearts', 'heart_eyes', 'kissing_heart', 'sob', 'pleading_face', 'thumbsup', 'pray', 'wave', 'fire', 'sparkles'];
- this.heightDefs = {
- 'categoryTitleHeight': 55,
- 'emojiRowHeight': 35,
- 'containerHeight': 302,
- 'totalScrollHeight': 302,
- 'numberOfEmojisPerRow': 9
- };
- this.categoryLabels = {
- 'frequently_used': l[17737],
- 'people': l[8016],
- 'objects': l[17735],
- 'activity': l[8020],
- 'nature': l[8017],
- 'travel': l[8021],
- 'symbols': l[17736],
- 'food': l[8018],
- 'flags': l[17703]
- };
- this.state = this.getInitialState();
- this.onSearchChange = this.onSearchChange.bind(this);
- this.onUserScroll = this.onUserScroll.bind(this);
- this._onScrollChanged = this._onScrollChanged.bind(this);
- }
- getInitialState() {
- return clone({
- 'previewEmoji': null,
- 'searchValue': '',
- 'browsingCategory': false,
- 'isActive': false,
- 'isLoading': true,
- 'loadFailed': false,
- 'visibleCategories': "0"
- });
- }
- _generateEmoji(meta) {
- const filename = twemoji.convert.toCodePoint(meta.u);
- return React.createElement("img", {
- width: "20",
- height: "20",
- className: "emoji emoji-loading",
- draggable: "false",
- alt: meta.u,
- title: `:${ meta.n }:`,
- onLoad: e => {
- e.target.classList.remove('emoji-loading');
- },
- onError: e => {
- e.target.classList.remove('emoji-loading');
- e.target.classList.add('emoji-loading-error');
- },
- src: `${staticpath }images/mega/twemojis/2_v2/72x72/${ filename }.png`
- });
- }
- _generateEmojiElement(emoji, cat) {
- const self = this;
- const categoryName = self.data_categories[cat];
- return React.createElement("div", {
- "data-emoji": emoji.n,
- className: "button square-button emoji",
- key: `${categoryName }_${ emoji.n}`,
- onMouseEnter: e => {
- if (self.mouseEnterTimer) {
- clearTimeout(self.mouseEnterTimer);
- }
- e.stopPropagation();
- e.preventDefault();
- self.mouseEnterTimer = setTimeout(() => {
- self.setState({
- 'previewEmoji': emoji
- });
- }, 250);
- },
- onMouseLeave: e => {
- if (self.mouseEnterTimer) {
- clearTimeout(self.mouseEnterTimer);
- }
- e.stopPropagation();
- e.preventDefault();
- self.setState({
- 'previewEmoji': null
- });
- },
- onClick: e => {
- if (self.props.onClick) {
- self.props.onClick(e, emoji.n, emoji);
- $(document).trigger('closeDropdowns');
- }
- }
- }, self._generateEmoji(emoji));
- }
- UNSAFE_componentWillUpdate(nextProps, nextState) {
- if (nextState.searchValue !== this.state.searchValue || nextState.browsingCategories !== this.state.browsingCategories) {
- this._cachedNodes = {};
- if (this.scrollableArea) {
- this.scrollableArea.scrollToY(0);
- }
- this._onScrollChanged(0, nextState);
- }
- if (nextState.isActive === true) {
- const self = this;
- if (nextState.isLoading === true || !self.loadingPromise && (!self.data_categories || !self.data_emojis)) {
- const p = [megaChat.getEmojiDataSet('categories'), megaChat.getEmojiDataSet('emojis')];
- this.loadingPromise = Promise.all(p).then(([categories, emojis]) => {
- this.data_emojis = emojis;
- this.data_categories = categories;
- self.data_categories.push('frequently_used');
- self.data_categoriesWithCustomOrder = [];
- self.customCategoriesOrder.forEach((catName) => {
- self.data_categoriesWithCustomOrder.push(self.data_categories.indexOf(catName));
- });
- self.data_emojiByCategory = {};
- const frequentlyUsedEmojisMeta = {};
- self.data_emojis.forEach((emoji) => {
- const cat = emoji.c;
- if (!self.data_emojiByCategory[cat]) {
- self.data_emojiByCategory[cat] = [];
- }
- if (self.frequentlyUsedEmojis.indexOf(emoji.n) > -1) {
- frequentlyUsedEmojisMeta[emoji.n] = emoji.u;
- }
- emoji.element = self._generateEmojiElement(emoji, cat);
- self.data_emojiByCategory[cat].push(emoji);
- });
- self.data_emojiByCategory[8] = [];
- self.frequentlyUsedEmojis.forEach((slug) => {
- const emoji = {
- 'n': slug,
- 'u': frequentlyUsedEmojisMeta[slug]
- };
- emoji.element = self._generateEmojiElement(emoji, 99);
- self.data_emojiByCategory[8].push(emoji);
- });
- self._onScrollChanged(0);
- self.setState({
- 'isLoading': false
- });
- }).catch(ex => {
- if (d) {
- console.error("Emoji loading failed.", ex);
- }
- this.setState({
- 'loadFailed': true,
- 'isLoading': false
- });
- });
- }
- } else if (nextState.isActive === false) {
- if (this.data_emojis) {
- for (let i = this.data_emojis.length; i--;) {
- delete this.data_emojis[i].element;
+const ChatOnboarding = (_dec = (0,mixins.hG)(1000), _class = class ChatOnboarding {
+ constructor(megaChat) {
+ this.finished = false;
+ if (u_type === 3 && !is_mobile) {
+ this.state = {
+ [OBV4_FLAGS.CHAT]: -1
+ };
+ this.megaChat = megaChat;
+ this.flagMap = attribCache.bitMapsManager.exists('obv4') ? attribCache.bitMapsManager.get('obv4') : new MegaDataBitMap('obv4', false, Object.values(OBV4_FLAGS));
+ const keys = Object.keys(this.state);
+ const promises = keys.map(key => this.flagMap.get(key));
+ Promise.allSettled(promises).then(res => {
+ for (let i = 0; i < res.length; ++i) {
+ const v = res[i];
+ if (v.status === 'fulfilled') {
+ this.handleFlagChange(null, null, keys[i], v.value);
+ }
}
- }
- this.data_emojis = null;
- this.data_categories = null;
- this.data_emojiByCategory = null;
- this.loadingPromise = null;
+ });
+ this.interval = setInterval(() => {
+ if (!$.dialog) {
+ this._checkAndShowStep();
+ }
+ }, 10000);
+ this.initListeners();
}
}
- onSearchChange(e) {
- const self = this;
- self.setState({
- searchValue: e.target.value,
- browsingCategory: false
+ initListeners() {
+ this.flagMap.addChangeListener((...args) => this.handleFlagChange(...args));
+ this.megaChat.chatUIFlags.addChangeListener(SoonFc(200, () => {
+ if (this.megaChat.chatUIFlags.convPanelCollapse && $.dialog === 'onboardingDialog') {
+ closeDialog();
+ }
+ this._checkAndShowStep();
+ }));
+ this.megaChat.addChangeListener(() => {
+ const room = this.megaChat.getCurrentRoom();
+ if (!room) {
+ return;
+ }
+ this.checkAndShowStep();
});
}
- onUserScroll($ps) {
- if (this.state.browsingCategory) {
- const $cat = $(`.emoji-category-container[data-category-name="${ this.state.browsingCategory }"]`);
- if (!elementInViewport($cat)) {
- this.setState({
- 'browsingCategory': false
- });
- }
- }
- this._onScrollChanged($ps.getScrollPositionY());
+ checkAndShowStep() {
+ this._checkAndShowStep();
}
- generateEmojiElementsByCategory(categoryId, posTop, stateObj) {
- const self = this;
- if (!self._cachedNodes) {
- self._cachedNodes = {};
+ _shouldSkipShow() {
+ if (!M.chat || !mega.ui.onboarding || $.dialog || loadingDialog.active || u_type < 3 || is_mobile || $.msgDialog) {
+ return true;
}
- if (!stateObj) {
- stateObj = self.state;
+ this.$topRightMenu = this.$topRightMenu || $('.top-menu-popup', '#topmenu');
+ if (!this.$topRightMenu.hasClass('o-hidden')) {
+ return true;
}
- if (typeof self._cachedNodes[categoryId] !== 'undefined') {
- return self._cachedNodes[categoryId];
+ this.$topAccDropdown = this.$topAccDropdown || $('.js-dropdown-account', '#topmenu');
+ if (this.$topAccDropdown.hasClass('show')) {
+ return true;
}
- const categoryName = self.data_categories[categoryId];
- const emojis = [];
- const {searchValue} = stateObj;
- let totalEmojis = 0;
- self.data_emojiByCategory[categoryId].forEach((meta) => {
- const slug = meta.n;
- if (searchValue.length > 0) {
- if (`:${ slug }:`.toLowerCase().indexOf(searchValue.toLowerCase()) < 0) {
- return;
- }
- }
- totalEmojis++;
- emojis.push(meta.element);
- });
- if (emojis.length > 0) {
- const totalHeight = self.heightDefs.categoryTitleHeight + Math.ceil(totalEmojis / self.heightDefs.numberOfEmojisPerRow) * self.heightDefs.emojiRowHeight;
- return self._cachedNodes[categoryId] = [totalHeight, React.createElement("div", {
- key: categoryName,
- "data-category-name": categoryName,
- className: "emoji-category-container",
- style: {
- 'position': 'absolute',
- 'top': posTop
- }
- }, emojis.length > 0 ? React.createElement("div", {
- className: "clear"
- }) : null, React.createElement("div", {
- className: "emoji-type-txt"
- }, self.categoryLabels[categoryName] ? self.categoryLabels[categoryName] : categoryName), React.createElement("div", {
- className: "clear"
- }), emojis, React.createElement("div", {
- className: "clear"
- }))];
- } else {
- return self._cachedNodes[categoryId] = undefined;
+ this.$topNotifDropdown = this.$topNotifDropdown || $('.js-dropdown-notification', '#topmenu');
+ if (this.$topNotifDropdown.hasClass('show')) {
+ return true;
}
+ this.$searchPanel = this.$searchPanel || $('.search-panel', '.conversationsApp');
+ return this.$searchPanel.hasClass('expanded');
}
- _isVisible(scrollTop, scrollBottom, elTop, elBottom) {
- const visibleTop = elTop < scrollTop ? scrollTop : elTop;
- const visibleBottom = elBottom > scrollBottom ? scrollBottom : elBottom;
- return visibleBottom - visibleTop > 0;
- }
- _onScrollChanged(scrollPositionY, stateObj) {
- const self = this;
- if (!self.data_categoriesWithCustomOrder) {
+ _checkAndShowStep() {
+ if (this._shouldSkipShow()) {
return;
}
- if (scrollPositionY === false) {
- scrollPositionY = self.scrollableArea.getScrollPositionY();
+ const {
+ sections
+ } = mega.ui.onboarding;
+ if (!sections) {
+ return;
}
- if (!stateObj) {
- stateObj = self.state;
+ const {
+ chat: obChat
+ } = sections;
+ if (!obChat) {
+ return;
}
- const visibleStart = scrollPositionY;
- const visibleEnd = visibleStart + self.heightDefs.containerHeight;
- let currentPos = 0;
- let visibleCategories = [];
- self._emojiReactElements = [];
- self.data_categoryPositions = {};
- self.data_categoriesWithCustomOrder.forEach((k) => {
- const categoryDivMeta = self.generateEmojiElementsByCategory(k, currentPos, stateObj);
- if (categoryDivMeta) {
- const startPos = currentPos;
- currentPos += categoryDivMeta[0];
- const endPos = currentPos;
- self.data_categoryPositions[k] = startPos;
- if (self._isVisible(visibleStart, visibleEnd, startPos, endPos)) {
- visibleCategories.push(k);
- self._emojiReactElements.push(categoryDivMeta[1]);
- }
- }
- });
- if (self._emojiReactElements.length === 0) {
- const emojisNotFound = React.createElement("span", {
- className: "emojis-not-found",
- key: 'emojis-not-found'
- }, l[20920]);
- self._emojiReactElements.push(emojisNotFound);
+ if (this.state[OBV4_FLAGS.CHAT]) {
+ return;
}
- visibleCategories = visibleCategories.join(',');
- self.setState({
- 'totalScrollHeight': currentPos,
- visibleCategories
- });
+ this.showDefaultNextStep(obChat);
}
- _renderEmojiPickerPopup() {
- const self = this;
- let preview;
- if (self.state.previewEmoji) {
- const meta = self.state.previewEmoji;
- preview = React.createElement("div", {
- className: "emoji-preview"
- }, self._generateEmoji(meta), React.createElement("div", {
- className: "emoji title"
- }, `:${ meta.n }:`));
+ showDefaultNextStep(obChat) {
+ const nextIdx = obChat.searchNextOpenStep();
+ if (nextIdx !== false && (!this.$obDialog || !this.$obDialog.is(':visible')) && (this.obToggleDrawn || $('.conversations-category', '.conversationsApp').length)) {
+ this.obToggleDrawn = true;
+ if (obChat.steps && obChat.steps[nextIdx] && obChat.steps[nextIdx].isComplete) {
+ return;
+ }
+ obChat.startNextOpenSteps(nextIdx);
+ this.$obDialog = this.$obDialog || $('#ob-dialog');
}
- const categoryIcons = {
- "frequently_used": "icon-emoji-type-frequent",
- "people": "icon-emoji-type-people",
- "nature": "icon-emoji-type-nature",
- "food": "icon-emoji-type-food",
- "activity": "icon-emoji-type-activity",
- "travel": "icon-emoji-type-travel",
- "objects": "icon-emoji-type-objects",
- "symbols": "icon-emoji-type-symbol",
- "flags": "icon-emoji-type-flag"
- };
- const categoryButtons = [];
- let activeCategoryName = false;
- if (!self.state.searchValue) {
- const firstActive = self.state.visibleCategories.split(",")[0];
- if (firstActive) {
- activeCategoryName = self.data_categories[firstActive];
+ }
+ handleFlagChange(...args) {
+ if (args.length >= 4 && typeof args[2] === 'string' && typeof args[3] === 'number' && this.state.hasOwnProperty(args[2])) {
+ if (d) {
+ console.debug(`Chat onboarding flag ${args[2]}: ${this.state[args[2]]} -> ${args[3]}`);
+ }
+ this.state[args[2]] = args[3];
+ if (args[2] === OBV4_FLAGS.CHAT && args[3] === 1 && this.interval) {
+ clearInterval(this.interval);
+ delete this.interval;
}
}
- self.customCategoriesOrder.forEach(categoryName => {
- categoryButtons.push(React.createElement("div", {
- visiblecategories: this.state.visibleCategories,
- className: `
- button square-button emoji
- ${activeCategoryName === categoryName ? 'active' : ''}
- `,
- key: categoryIcons[categoryName],
- onClick: e => {
- e.stopPropagation();
- e.preventDefault();
- this.setState({
- browsingCategory: categoryName,
- searchValue: ''
- });
- this._cachedNodes = {};
- const categoryPosition = this.data_categoryPositions[this.data_categories.indexOf(categoryName)] + 10;
- this.scrollableArea.scrollToY(categoryPosition);
- this._onScrollChanged(categoryPosition);
- const {
- current
- } = this.emojiSearchRef || !1;
- current == null || current.focus();
+ }
+ destroy() {
+ if (this.interval) {
+ clearInterval(this.interval);
+ delete this.interval;
+ }
+ }
+}, (0,applyDecoratedDescriptor.A)(_class.prototype, "checkAndShowStep", [_dec], Object.getOwnPropertyDescriptor(_class.prototype, "checkAndShowStep"), _class.prototype), _class);
+
+// EXTERNAL MODULE: ./js/chat/ui/meetings/utils.jsx
+const utils = REQ_(3901);
+// EXTERNAL MODULE: ./js/chat/chatGlobalEventManager.jsx
+const chatGlobalEventManager = REQ_(8676);
+// EXTERNAL MODULE: ./js/chat/ui/messages/utils.jsx
+const messages_utils = REQ_(187);
+// EXTERNAL MODULE: ./js/chat/utils.jsx
+const chat_utils = REQ_(5779);
+// EXTERNAL MODULE: ./node_modules/@babel/runtime/helpers/esm/extends.js
+const esm_extends = REQ_(8168);
+// EXTERNAL MODULE: ./js/chat/ui/contacts.jsx
+const contacts = REQ_(8022);
+// EXTERNAL MODULE: ./js/ui/modalDialogs.jsx + 1 modules
+const modalDialogs = REQ_(8120);
+// EXTERNAL MODULE: ./js/chat/ui/meetings/button.jsx
+const meetings_button = REQ_(6740);
+// EXTERNAL MODULE: ./js/ui/utils.jsx
+const ui_utils = REQ_(6411);
+;// ./js/chat/ui/meetings/workflow/incoming.jsx
+
+
+
+
+
+
+
+class Incoming extends REaCt().Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ video: false,
+ unsupported: undefined,
+ hoveredSwitch: true,
+ hideOverlay: false
+ };
+ this.renderSwitchControls = () => {
+ const className = `mega-button large round switch ${this.state.hoveredSwitch ? 'hovered' : ''}`;
+ const toggleHover = () => this.setState(state => ({
+ hoveredSwitch: !state.hoveredSwitch
+ }));
+ return JSX_("div", {
+ className: "switch-button"
+ }, JSX_("div", {
+ className: "switch-button-container simpletip",
+ "data-simpletip": l.end_and_answer,
+ "data-simpletipposition": "top",
+ onMouseEnter: toggleHover,
+ onMouseLeave: toggleHover,
+ onClick: ev => {
+ ev.stopPropagation();
+ this.props.onSwitch();
}
- }, React.createElement("i", {
- className: `sprite-fm-mono ${categoryIcons[categoryName]}`
+ }, JSX_(meetings_button.A, {
+ className: `${className} negative`,
+ icon: "icon-end-call"
+ }), JSX_(meetings_button.A, {
+ className: `${className} positive`,
+ icon: "icon-phone"
})));
- });
- return React.createElement(React.Fragment, null, React.createElement("div", {
- className: "popup-header emoji"
- }, preview || React.createElement("div", {
- className: "search-block emoji"
- }, React.createElement("i", {
- className: "sprite-fm-mono icon-preview-reveal"
- }), React.createElement("input", {
- ref: this.emojiSearchRef,
- type: "search",
- placeholder: l[102],
- onChange: this.onSearchChange,
- autoFocus: true,
- value: this.state.searchValue
- }))), React.createElement(PerfectScrollbar, {
- className: "popup-scroll-area emoji perfectScrollbarContainer",
- searchValue: this.state.searchValue,
- onUserScroll: this.onUserScroll,
- visibleCategories: this.state.visibleCategories,
- ref: ref => {
- this.scrollableArea = ref;
- }
- }, React.createElement("div", {
- className: "popup-scroll-content emoji"
- }, React.createElement("div", {
- style: {
- height: this.state.totalScrollHeight
- }
- }, this._emojiReactElements))), React.createElement("div", {
- className: "popup-footer emoji"
- }, categoryButtons));
+ };
+ this.renderAnswerControls = () => {
+ const {
+ video,
+ unsupported
+ } = this.state;
+ const {
+ onAnswer,
+ onToggleVideo
+ } = this.props;
+ return JSX_(REaCt().Fragment, null, JSX_(meetings_button.A, {
+ className: `
+ mega-button
+ positive
+ answer
+ ${unsupported ? 'disabled' : ''}
+ `,
+ icon: "icon-phone",
+ simpletip: unsupported ? null : {
+ position: 'top',
+ label: l[7205]
+ },
+ onClick: unsupported ? null : onAnswer
+ }, JSX_("span", null, l[7205])), JSX_(meetings_button.A, {
+ className: `
+ mega-button
+ large
+ round
+ video
+ ${video ? '' : 'negative'}
+ ${unsupported ? 'disabled' : ''}
+ `,
+ icon: video ? 'icon-video-call-filled' : 'icon-video-off',
+ simpletip: unsupported ? null : {
+ position: 'top',
+ label: video ? l[22894] : l[22893]
+ },
+ onClick: () => unsupported ? null : this.setState({
+ video: !video
+ }, () => onToggleVideo(video))
+ }, JSX_("span", null, video ? l[22894] : l[22893])));
+ };
+ this.state.unsupported = !megaChat.hasSupportForCalls;
+ this.state.hideOverlay = document.body.classList.contains('overlayed') && !$.msgDialog;
+ }
+ componentDidMount() {
+ this._old$dialog = $.dialog;
+ $.dialog = "chat-incoming-call";
+ }
+ componentWillUnmount() {
+ $.dialog = this._old$dialog;
}
render() {
- const self = this;
- let popupContents = null;
- if (self.state.isActive === true) {
- if (self.state.loadFailed === true) {
- popupContents = React.createElement("div", {
- className: "loading"
- }, l[1514]);
- } else if (this.state.isLoading || !this.data_emojiByCategory || !this.data_categories) {
- popupContents = React.createElement("div", {
- className: "loading"
- }, l[5533]);
- } else {
- popupContents = self._renderEmojiPickerPopup();
- }
- } else {
- popupContents = null;
+ const {
+ chatRoom
+ } = this.props;
+ if (chatRoom) {
+ const {
+ NAMESPACE
+ } = Incoming;
+ const {
+ callerId,
+ onClose,
+ onReject
+ } = this.props;
+ const {
+ unsupported
+ } = this.state;
+ const CALL_IN_PROGRESS = window.sfuClient;
+ const isPrivateRoom = chatRoom.type === 'private';
+ const rejectLabel = isPrivateRoom ? l[20981] : l.msg_dlg_cancel;
+ return JSX_(modalDialogs.A.ModalDialog, (0,esm_extends.A)({}, this.state, {
+ name: NAMESPACE,
+ className: NAMESPACE,
+ roomName: chatRoom.getRoomTitle(),
+ onClose: () => onClose()
+ }), JSX_("div", {
+ className: "fm-dialog-body"
+ }, JSX_("div", {
+ className: `${NAMESPACE}-avatar`
+ }, JSX_(contacts.eu, {
+ contact: M.u[callerId]
+ })), JSX_("div", {
+ className: `${NAMESPACE}-info`
+ }, JSX_("h1", null, JSX_(ui_utils.zT, null, chatRoom.getRoomTitle())), JSX_("span", null, isPrivateRoom ? l[17878] : l[19995])), JSX_("div", {
+ className: `
+ ${NAMESPACE}-controls
+ ${CALL_IN_PROGRESS ? 'call-in-progress' : ''}
+ `
+ }, JSX_(meetings_button.A, {
+ className: `
+ mega-button
+ large
+ round
+ negative
+ `,
+ icon: "icon-end-call",
+ simpletip: {
+ position: 'top',
+ label: rejectLabel
+ },
+ onClick: onReject
+ }, JSX_("span", null, rejectLabel)), CALL_IN_PROGRESS ? this.renderSwitchControls() : this.renderAnswerControls()), unsupported && JSX_("div", {
+ className: `${NAMESPACE}-unsupported`
+ }, JSX_("div", {
+ className: "unsupported-message"
+ }, (0,utils.HV)()))));
}
- return React.createElement(DropdownsUI.Dropdown, (0,_extends0__.A)({
- className: "popup emoji"
- }, self.props, {
- isLoading: self.state.isLoading,
- loadFailed: self.state.loadFailed,
- visibleCategories: this.state.visibleCategories,
- forceShowWhenEmpty: true,
- onActiveChange: newValue => {
- if (newValue === false) {
- self.setState(self.getInitialState());
- self._cachedNodes = {};
- self._onScrollChanged(0);
- } else {
- self.setState({
- 'isActive': true
- });
- }
- if (self.props.onActiveChange) {
- self.props.onActiveChange(newValue);
+ console.error('Incoming dialog received missing chatRoom prop.');
+ return null;
+ }
+}
+Incoming.NAMESPACE = 'incoming-dialog';
+;// ./js/chat/chat.jsx
+
+
+
+
+
+
+
+
+
+window.chatGlobalEventManager = chatGlobalEventManager.r;
+
+mega.ui = mega.ui || {};
+mega.ui.chat = mega.ui.chat || {};
+mega.ui.chat.getMessageString = messages_utils.d;
+
+
+const ScheduleMeeting = (0,external_React_.lazy)(() => REQ_.e( 716).then(REQ_.bind(REQ_, 8389)));
+const StartMeeting = (0,external_React_.lazy)(() => REQ_.e( 543).then(REQ_.bind(REQ_, 7190)));
+const ContactSelectorDialog = (0,external_React_.lazy)(() => REQ_.e( 543).then(REQ_.bind(REQ_, 2678)));
+const StartGroupChatWizard = (0,external_React_.lazy)(() => REQ_.e( 543).then(REQ_.bind(REQ_, 5199)));
+const CloudBrowserDialog = (0,external_React_.lazy)(() => REQ_.e( 313).then(REQ_.bind(REQ_, 6961)));
+window.ChatCallIncomingDialog = (0,chat_utils.li)(Incoming);
+window.ScheduleMeetingDialogUI = {
+ Schedule: (0,chat_utils.li)(ScheduleMeeting)
+};
+window.StartMeetingDialogUI = {
+ Start: (0,chat_utils.li)(StartMeeting)
+};
+window.ContactSelectorDialogUI = {
+ ContactSelectorDialog: (0,chat_utils.li)(ContactSelectorDialog)
+};
+window.StartGroupChatDialogUI = {
+ StartGroupChatWizard: (0,chat_utils.li)(StartGroupChatWizard)
+};
+Object.defineProperty(mega, 'CloudBrowserDialog', {
+ value: (0,chat_utils.li)(CloudBrowserDialog)
+});
+const EMOJI_DATASET_VERSION = 5;
+const CHAT_ONHISTDECR_RECNT = "onHistoryDecrypted.recent";
+const LOAD_ORIGINALS = {
+ 'image/gif': 25e6,
+ 'image/png': 2e5,
+ 'image/webp': 2e5
+};
+const CHATUIFLAGS_MAPPING = {
+ 'convPanelCollapse': 'cPC'
+};
+function Chat() {
+ const self = this;
+ this.is_initialized = false;
+ this.logger = MegaLogger.getLogger("chat");
+ this.mbListeners = [];
+ this.chats = new MegaDataMap();
+ this.scheduledMeetings = new MegaDataMap();
+ this.chatUIFlags = new MegaDataMap();
+ this.$chatTreePanePs = [];
+ this.initChatUIFlagsManagement();
+ this.currentlyOpenedChat = null;
+ this.currentlyOpenedView = null;
+ this.lastOpenedChat = null;
+ this.archivedChatsCount = 0;
+ this.FORCE_EMAIL_LOADING = localStorage.fel;
+ this.WITH_SELF_NOTE = mega.flags.ff_n2s || localStorage.withSelfNote;
+ this._imageLoadCache = Object.create(null);
+ this._imagesToBeLoaded = Object.create(null);
+ this._imageAttributeCache = Object.create(null);
+ this._queuedMccPackets = [];
+ this._queuedMcsmPackets = {};
+ this._queuedMessageUpdates = [];
+ this._queuedChatRoomEvents = Object.create(null);
+ this.handleToId = Object.create(null);
+ this.publicChatKeys = Object.create(null);
+ this.SOUNDS = {
+ ALERT: 'alert_info_message',
+ INCOMING_MSG: 'incoming_chat_message',
+ INCOMING_CALL: 'incoming_voice_video_call',
+ CALL_JOIN: 'user_join_call',
+ CALL_LEFT: 'user_left_call',
+ CALL_END: 'end_call',
+ CALL_JOIN_WAITING: 'user_join_waiting',
+ RECONNECT: 'reconnecting',
+ SPEAKER_TEST: 'test_speaker'
+ };
+ this.options = {
+ 'delaySendMessageIfRoomNotAvailableTimeout': 3000,
+ 'plugins': {
+ 'chatdIntegration': ChatdIntegration,
+ 'callManager2': CallManager2,
+ 'urlFilter': UrlFilter,
+ 'emoticonShortcutsFilter': EmoticonShortcutsFilter,
+ 'emoticonsFilter': EmoticonsFilter,
+ 'callFeedback': CallFeedback,
+ 'presencedIntegration': PresencedIntegration,
+ 'persistedTypeArea': PersistedTypeArea,
+ 'btRtfFilter': BacktickRtfFilter,
+ 'rtfFilter': RtfFilter,
+ 'richpreviewsFilter': RichpreviewsFilter,
+ 'chatToastIntegration': ChatToastIntegration,
+ 'chatStats': ChatStats,
+ 'geoLocationLinks': GeoLocationLinks,
+ meetingsManager,
+ 'chatOnboarding': ChatOnboarding,
+ 'userHelper': ChatUserHelper
+ },
+ 'chatNotificationOptions': {
+ 'textMessages': {
+ 'incoming-chat-message': {
+ title: l.notif_title_incoming_msg,
+ 'icon' (notificationObj) {
+ return notificationObj.options.icon;
+ },
+ 'body' (notificationObj, params) {
+ if (params.type === 'private') {
+ return l.notif_body_incoming_msg.replace('%s', params.from);
+ }
+ return l.notif_body_incoming_msg_group.replace('%1', params.from).replace('%2', params.roomTitle);
+ }
+ },
+ 'incoming-voice-video-call': {
+ 'title': l[17878] || "Incoming call",
+ 'icon' (notificationObj) {
+ return notificationObj.options.icon;
+ },
+ 'body' (notificationObj, params) {
+ return l[5893].replace('[X]', params.from);
+ }
+ },
+ 'screen-share-error': {
+ title: l.screenshare_failed_notif || 'You are no longer sharing your screen',
+ icon: notificationObj => {
+ return notificationObj.options.icon;
+ },
+ body: ''
+ },
+ 'upcoming-scheduled-occurrence': {
+ title: ({
+ options
+ }) => {
+ return options.meeting.title;
+ },
+ icon: `${staticpath}/images/mega/mega-icon.svg`,
+ body: l.notif_body_scheduled_upcoming
+ },
+ 'starting-scheduled-occurrence': {
+ title: ({
+ options
+ }) => {
+ return options.meeting.title;
+ },
+ icon: `${staticpath}/images/mega/mega-icon.svg`,
+ body: l.notif_body_scheduled_starting
}
},
- searchValue: self.state.searchValue,
- browsingCategory: self.state.browsingCategory,
- previewEmoji: self.state.previewEmoji
- }), React.createElement("div", {
- ref: this.domRef
- }, popupContents));
- }
+ sounds: Object.values(this.SOUNDS)
+ },
+ 'chatStoreOptions': {
+ 'autoPurgeMaxMessagesPerRoom': 1024
+ }
+ };
+ this.SOUNDS.buffers = Object.create(null);
+ this.plugins = {};
+ self.filePicker = null;
+ self._chatsAwaitingAps = {};
+ MegaDataObject.call(this, {
+ "currentlyOpenedChat": null,
+ "activeCall": null,
+ 'routingSection': null,
+ 'routingSubSection': null,
+ 'routingParams': null
+ });
+ this.routing = new ChatRouting(this);
+ Object.defineProperty(this, 'hasSupportForCalls', {
+ get () {
+ return typeof SfuClient !== 'undefined' && typeof TransformStream !== 'undefined' && window.RTCRtpSender && !!RTCRtpSender.prototype.createEncodedStreams;
+ }
+ });
+ this.minuteClockInterval = setInterval(() => this._syncChats(), 6e4);
+ return this;
}
-DropdownEmojiSelector.defaultProps = {
- 'requiresUpdateOnResize': true,
- 'hideable': true
-};
-
-},
-
-701
-(_, EXP_, REQ_) {
-
-"use strict";
-
-// EXPORTS
-REQ_.d(EXP_, {
- A: () => FMView
+inherits(Chat, MegaDataObject);
+Object.defineProperty(Chat, 'mcf', {
+ value: Object.create(null)
});
-
-// EXTERNAL MODULE: external "React"
-const React_ = REQ_(594);
-const REaCt = REQ_.n(React_);
-// EXTERNAL MODULE: ./js/chat/mixins.js
-const mixins = REQ_(137);
-// EXTERNAL MODULE: ./node_modules/@babel/runtime/helpers/esm/extends.js
-const esm_extends = REQ_(168);
-// EXTERNAL MODULE: ./node_modules/@babel/runtime/helpers/esm/applyDecoratedDescriptor.js
-const applyDecoratedDescriptor = REQ_(793);
-// EXTERNAL MODULE: ./js/ui/perfectScrollbar.jsx
-const perfectScrollbar = REQ_(486);
-;// ./js/ui/jsx/megaList/megaList2.jsx
-
-
-let _dec, _class;
-
-
-
-const MegaList2 = (_dec = (0,mixins.hG)(30, true), _class = class MegaList2 extends mixins.w9 {
- constructor(props) {
- super(props);
- this._calculated = false;
- this._firstRender = true;
- this.customIsEventuallyVisible = true;
- this.requiresUpdateOnResize = true;
- this.adapterChangedDoRepaint = false;
- assert(props.listAdapter, 'missing `listAdapter` for MegaList2');
- assert(props.nodeAdapter, 'missing `nodeAdapter` for MegaList2');
- assert(props.entries, 'missing `entries` for MegaList2');
- this.options = {
- extraRows: 8,
- batchPages: 0,
- perfectScrollOptions: {
- 'handlers': ['click-rail', 'drag-thumb', 'wheel', 'touch'],
- 'minScrollbarLength': 20
+Object.defineProperty(Chat, 'mcsm', {
+ value: Object.create(null)
+});
+Chat.prototype.init = promisify(function (resolve, reject) {
+ const self = this;
+ if (self.is_initialized) {
+ self.destroy();
+ }
+ if (d) {
+ console.time('megachat:plugins:init');
+ }
+ self.plugins = Object.create(null);
+ self.plugins.chatNotifications = new ChatNotifications(self, self.options.chatNotificationOptions);
+ self.plugins.chatNotifications.notifications.rebind('onAfterNotificationCreated.megaChat', () => {
+ self.updateSectionUnreadCount();
+ });
+ Object.keys(self.options.plugins).forEach(plugin => {
+ self.plugins[plugin] = new self.options.plugins[plugin](self);
+ });
+ if (d) {
+ console.timeEnd('megachat:plugins:init');
+ }
+ $(document.body);
+ if (!is_chatlink) {
+ $(mega.ui.header.setStatus).rebind('mousedown.megachat', '.sub-menu.status button', function () {
+ const presence = $(this).data("presence");
+ self._myPresence = presence;
+ const targetPresence = PresencedIntegration.cssClassToPresence(presence);
+ self.plugins.presencedIntegration.setPresence(targetPresence);
+ if (targetPresence !== UserPresence.PRESENCE.OFFLINE) {
+ Object.keys(self.plugins.chatdIntegration.chatd.shards).forEach(k => {
+ const v = self.plugins.chatdIntegration.chatd.shards[k];
+ v.connectionRetryManager.requiresConnection();
+ });
}
- };
- this.onPsUserScroll = this.onPsUserScroll.bind(this);
- this.thumbsLoadingHandlers = new MapSet();
- this.thumbsThatRequireLoading = new MapSet();
- this.requestThumbnailCb = this.requestThumbnailCb.bind(this);
+ });
}
- specShouldComponentUpdate(nextProps) {
- let invalidate = false;
- if (nextProps.listAdapter.prototype.constructor.name !== this.props.listAdapter.prototype.constructor.name || nextProps.entries !== this.props.entries || nextProps.viewMode !== this.props.viewMode) {
- invalidate = true;
- }
- if (nextProps.sortBy !== this.props.sortBy || nextProps.currentlyViewedEntry !== this.props.currentlyViewedEntry) {
- invalidate = true;
- this.domRef.scrollToY(0);
- }
- if (invalidate) {
- this._calculated = false;
- this.adapterChangedDoRepaint = true;
- return true;
+ self.$container = $('.fm-chat-block');
+ if (M.chat && !is_chatlink) {
+ $('.activity-status-block, .activity-status').removeClass('hidden');
+ $('.js-dropdown-account .status-dropdown').removeClass('hidden');
+ }
+ if (is_chatlink) {
+ const {
+ ph,
+ key
+ } = is_chatlink;
+ Chat.mcf[ph] = key;
+ this.publicChatKeys[ph] = key;
+ }
+ const promises = [];
+ const rooms = Object.keys(Chat.mcf);
+ for (let i = rooms.length; i--;) {
+ const roomId = rooms[i];
+ const room = Chat.mcf[roomId];
+ if (!this.publicChatKeys[rooms[i]]) {
+ promises.push(self.plugins.chatdIntegration.openChat(room, true));
}
- return null;
+ delete Chat.mcf[rooms[i]];
}
- _recalculate() {
- if (this._calculated) {
- return this._calculated;
+ Promise.allSettled(promises).then(res => {
+ const pub = Object.keys(this.publicChatKeys);
+ return Promise.allSettled([res].concat(pub.map(pch => {
+ return this.plugins.chatdIntegration.openChat(pch, true);
+ })));
+ }).then(res => {
+ res = res[0].value.concat(res.slice(1));
+ this.logger.info('chats settled...', res);
+ if (is_mobile) {
+ return;
}
- const calculated = this._calculated = Object.create(null);
- lazy(calculated, 'scrollWidth', () => {
- return this.domRef.getClientWidth();
- });
- lazy(calculated, 'scrollHeight', () => this.domRef.getClientHeight() - calculated.headerHeight);
- lazy(calculated, 'itemWidth', () => {
- if (this.props.listAdapter.itemWidth === false) {
- return calculated.scrollWidth;
- }
- return this.props.listAdapter.itemWidth;
- });
- lazy(calculated, 'itemHeight', () => {
- return this.props.itemHeight || this.props.listAdapter.itemHeight;
- });
- lazy(calculated, 'headerHeight', () => this.props.headerHeight || 0);
- lazy(calculated, 'contentWidth', () => {
- const contentWidth = this.domRef.getContentWidth();
- if (contentWidth) {
- return contentWidth;
- }
- return calculated.itemWidth;
- });
- lazy(calculated, 'itemsPerRow', () => {
- if (this.props.listAdapter.itemsPerRow) {
- return this.props.listAdapter.itemsPerRow;
+ if (is_chatlink) {
+ const start = document.getElementById('startholder');
+ this.flyoutStartHolder = start.querySelector('.flyout-holder') || mCreateElement('div', {
+ class: 'flyout-holder'
+ }, start);
+ }
+ const selector = is_chatlink ? '.chat-links-preview > .chat-app-container' : '.section.conversations';
+ const rootDOMNode = this.rootDOMNode = document.querySelector(selector);
+ const $$root = this.$$root = (0,external_ReactDOM_.createRoot)(rootDOMNode);
+ $$root.render(JSX_(conversations.Ay, {
+ megaChat: this,
+ routingSection: this.routingSection,
+ routingSubSection: this.routingSubSection,
+ routingParams: this.routingParams
+ }));
+ this.onChatsHistoryReady().then(() => {
+ const room = this.getCurrentRoom();
+ if (room) {
+ room.scrollToChat();
}
- return Math.max(1, Math.floor(calculated.contentWidth / calculated.itemWidth));
- });
- lazy(calculated, 'contentHeight', () => {
- return Math.ceil(this.props.entries.length / calculated.itemsPerRow) * calculated.itemHeight;
- });
- lazy(calculated, 'scrollLeft', () => {
- return this.domRef.getScrollPositionX();
- });
- lazy(calculated, 'scrollTop', () => {
- if (this.adapterChangedDoRepaint) {
- return 0;
+ return room;
+ }).dump('on-chat-history-loaded');
+ this.is_initialized = true;
+ this.registerUploadListeners();
+ this.trigger('onInit');
+ mBroadcaster.sendMessage('chat_initialized');
+ setInterval(this.removeMessagesByRetentionTime.bind(this, null), 2e4);
+ this.autoJoinIfNeeded();
+ const scheduledMeetings = Object.values(Chat.mcsm);
+ if (scheduledMeetings && scheduledMeetings.length) {
+ for (let i = scheduledMeetings.length; i--;) {
+ const scheduledMeeting = scheduledMeetings[i];
+ this.plugins.meetingsManager.attachMeeting(scheduledMeeting);
+ delete Chat.mcsm[scheduledMeeting.id];
}
- return this.domRef.getScrollPositionY();
- });
- lazy(calculated, 'scrolledPercentX', () => {
- return 100 / calculated.scrollWidth * calculated.scrollLeft;
- });
- lazy(calculated, 'scrolledPercentY', () => {
- return 100 / calculated.scrollHeight * calculated.scrollTop;
- });
- lazy(calculated, 'isAtTop', () => {
- return calculated.scrollTop === 0;
- });
- lazy(calculated, 'isAtBottom', () => {
- return calculated.scrollTop === calculated.scrollHeight;
- });
- lazy(calculated, 'itemsPerPage', () => {
- return Math.ceil(calculated.scrollHeight / calculated.itemHeight) * calculated.itemsPerRow;
- });
- lazy(calculated, 'visibleFirstItemNum', () => {
- let value = 0;
- value = Math.floor(Math.floor(calculated.scrollTop / calculated.itemHeight) * calculated.itemsPerRow);
- if (value > 0) {
- value = Math.max(0, value - this.options.extraRows * calculated.itemsPerRow);
+ }
+ if (notify) {
+ notify.countAndShowNewNotifications();
+ }
+ return true;
+ }).then(resolve).catch(reject);
+});
+Chat.prototype.showUpgradeDialog = function () {
+ return is_extension ? msgDialog('warningb', l[1900], l[8841]) : msgDialog('confirmation', l[1900], l[8840], '', cb => cb && location.reload());
+};
+Chat.prototype._syncChats = function () {
+ if (!this.is_initialized) {
+ return;
+ }
+ this.plugins.meetingsManager.checkForNotifications();
+ const {
+ chats,
+ logger
+ } = this;
+ if (chats && chats.length) {
+ chats.forEach(({
+ chatId,
+ scheduledMeeting
+ }) => {
+ const dnd = pushNotificationSettings.getDnd(chatId);
+ if (dnd && dnd < unixtime()) {
+ pushNotificationSettings.disableDnd(chatId);
+ if (logger) {
+ logger.debug(`Chat.prototype._syncDnd chatId=${chatId}`);
+ }
}
- return value;
- });
- lazy(calculated, 'visibleLastItemNum', () => {
- let value = Math.min(this.props.entries.length, Math.ceil(Math.ceil(calculated.scrollTop / calculated.itemHeight) * calculated.itemsPerRow + calculated.itemsPerPage));
- if (value < this.props.entries.length) {
- value = Math.min(this.props.entries.length, value + this.options.extraRows * calculated.itemsPerRow);
+ const {
+ isUpcoming,
+ chatRoom,
+ id
+ } = scheduledMeeting || {};
+ if (isUpcoming) {
+ scheduledMeeting.setNextOccurrence();
+ chatRoom.trackDataChange();
+ if (logger) {
+ logger.debug(`Chat.prototype.__syncScheduledMeetings id=${id} chatId=${chatId}`);
+ }
}
- return value;
- });
- if (this.options.batchPages > 0) {
- const perPage = calculated.itemsPerPage;
- const visibleF = calculated.visibleFirstItemNum;
- calculated.visibleFirstItemNum = Math.max(0, ((visibleF - visibleF % perPage) / perPage - 1 - this.options.batchPages) * perPage);
- const visibleL = calculated.visibleLastItemNum;
- calculated.visibleLastItemNum = Math.min(this.props.entries.length, ((visibleL - visibleL % perPage) / perPage + 1 + this.options.batchPages) * perPage);
- }
- Object.defineProperty(M, 'rmItemsInView', {
- get: () => {
- const c = this.domRef && this._calculated || !1;
- return c.itemsPerPage + c.itemsPerRow | 0;
- },
- configurable: true
});
}
- _contentUpdated() {
- this._calculated = false;
- this._recalculate();
- if (this.listContent && this._lastContentHeight !== this._calculated.contentHeight) {
- this._lastContentHeight = this._calculated.contentHeight;
- this.listContent.style.height = `${this._calculated.contentHeight }px`;
- }
- if (this.domRef && this._calculated.scrollHeight + this._calculated.scrollTop > this._calculated.contentHeight) {
- this.domRef.scrollToY(this._calculated.contentHeight - this._calculated.scrollHeight);
- }
- if (this.listAdapterInstance && this.listAdapterInstance.onContentUpdated) {
- this.listAdapterInstance.onContentUpdated();
+};
+Chat.prototype.loadChatUIFlagsFromConfig = function (val) {
+ let hadChanged = false;
+ let flags = val || mega.config.get("cUIF");
+ if (flags) {
+ if (typeof flags !== 'object') {
+ flags = {};
}
+ Object.keys(CHATUIFLAGS_MAPPING).forEach(k => {
+ const v = flags[CHATUIFLAGS_MAPPING[k]];
+ hadChanged = v !== undefined && this.chatUIFlags.set(k, v) !== false || hadChanged;
+ });
}
- _getCalcsThatTriggerChange() {
- return [this.props.entries.length, this._calculated.scrollHeight, this._calculated.itemWidth, this._calculated.itemHeight, this._calculated.contentWidth, this._calculated.itemsPerRow, this._calculated.contentHeight, this._calculated.visibleFirstItemNum, this._calculated.visibleLastItemNum];
+ return hadChanged;
+};
+Chat.prototype.cleanup = function (clean) {
+ const room = this.getCurrentRoom();
+ if (room) {
+ room.hide();
}
- indexOfEntry(nodeHandle, prop) {
- prop = prop || 'h';
- for (let i = 0; i < this.props.entries.length; i++) {
- const entry = this.props.entries[i];
- if (entry[prop] === nodeHandle) {
- return i;
- }
- }
- return -1;
+ M.chat = false;
+ this.routingParams = null;
+ this.routingSection = null;
+ this.routingSubSection = null;
+ if (clean) {
+ M.currentdirid = page = false;
}
- scrollToItem(nodeHandle) {
- const elementIndex = this.indexOfEntry(nodeHandle);
- if (elementIndex === -1) {
- return false;
- }
- let shouldScroll = false;
- const itemOffsetTop = Math.floor(elementIndex / this._calculated.itemsPerRow) * this._calculated.itemHeight;
- const itemOffsetTopPlusHeight = itemOffsetTop + this._calculated.itemHeight;
- if (itemOffsetTop < this._calculated.scrollTop || itemOffsetTopPlusHeight > this._calculated.scrollTop + this._calculated.scrollHeight) {
- shouldScroll = true;
- }
- if (shouldScroll) {
- this.domRef.scrollToY(itemOffsetTop);
- onIdle(() => {
- this.safeForceUpdate();
- });
- return true;
+};
+Chat.prototype.initChatUIFlagsManagement = function () {
+ const self = this;
+ self.loadChatUIFlagsFromConfig();
+ this.chatUIFlags.addChangeListener((hashmap, extraArg) => {
+ const flags = mega.config.get("cUIF") || {};
+ let hadChanged = false;
+ let hadLocalChanged = false;
+ Object.keys(CHATUIFLAGS_MAPPING).forEach((k) => {
+ if (flags[CHATUIFLAGS_MAPPING[k]] !== self.chatUIFlags[k]) {
+ if (extraArg === 0xDEAD) {
+ self.chatUIFlags._data[k] = flags[CHATUIFLAGS_MAPPING[k]];
+ hadLocalChanged = true;
+ } else {
+ flags[CHATUIFLAGS_MAPPING[k]] = self.chatUIFlags[k];
+ hadChanged = true;
+ }
+ }
+ });
+ if (hadLocalChanged) {
+ if (extraArg !== 0xDEAD) {
+ self.chatUIFlags.trackDataChange(0xDEAD);
+ }
+ $.tresizer();
}
- return false;
- }
- onPsUserScroll() {
- if (!this.isMounted()) {
+ if (extraArg === 0xDEAD) {
return;
}
- const oldCalc = JSON.stringify(this._getCalcsThatTriggerChange());
- this._contentUpdated();
- const newCalc = JSON.stringify(this._getCalcsThatTriggerChange());
- if (oldCalc !== newCalc) {
- this.forceUpdate();
- }
- }
- onResizeDoUpdate() {
- super.onResizeDoUpdate();
- this._contentUpdated();
- }
- componentDidMount() {
- super.componentDidMount();
- this._contentUpdated();
- this.forceUpdate();
- }
- componentDidUpdate() {
- super.componentDidUpdate();
- this._contentUpdated();
- if (this.adapterChangedDoRepaint) {
- this.adapterChangedDoRepaint = false;
- this._calculated = false;
- this._recalculate();
- }
- if (this.thumbsThatRequireLoading.size) {
- delay('chat:mega-list2:thumb-loader', () => this.enqueueThumbnailRetrieval(), 20);
+ if (hadChanged) {
+ mega.config.set("cUIF", flags);
}
- this._firstRender = this._firstRender || this.props.viewmode !== M.viewmode;
- if (this._firstRender && this.domRef) {
- let _this$domRef;
- this._firstRender = false;
- Ps.update((_this$domRef = this.domRef) == null ? void 0 : _this$domRef.$Node);
+ });
+ this.mbListeners.push(mBroadcaster.addListener('fmconfig:cUIF', tryCatch(v => {
+ if (self.loadChatUIFlagsFromConfig(v)) {
+ self.chatUIFlags.trackDataChange(0xDEAD);
}
+ })), mBroadcaster.addListener('statechange', state => {
+ this.trigger('viewstateChange', state);
+ }));
+};
+Chat.prototype.unregisterUploadListeners = function (destroy) {
+ 'use strict';
+
+ const self = this;
+ mBroadcaster.removeListener(self._uplDone);
+ mBroadcaster.removeListener(self._uplError);
+ mBroadcaster.removeListener(self._uplAbort);
+ mBroadcaster.removeListener(self._uplFAError);
+ mBroadcaster.removeListener(self._uplFAReady);
+ if (destroy) {
+ mBroadcaster.removeListener(self._uplStart);
}
- enqueueThumbnailRetrieval() {
- const loaders = new Map(this.thumbsLoadingHandlers);
- const nodes = new Map(this.thumbsThatRequireLoading);
- const pending = [];
- const defaultCallback = (n, src, id) => {
- let img = document.getElementById(id || `chat_${n.h}`);
- if (img && (img = img.querySelector('img'))) {
- let _img$parentNode$paren;
- img.src = src;
- (_img$parentNode$paren = img.parentNode.parentNode) == null || _img$parentNode$paren.classList.add('thumb');
+ delete self._uplError;
+};
+Chat.prototype.registerUploadListeners = function () {
+ const self = this;
+ const logger = d && MegaLogger.getLogger('chatUploadListener', false, self.logger);
+ const ufo = Object.create(null);
+ self.unregisterUploadListeners(true);
+ const forEachChat = function (chats, callback) {
+ let result = 0;
+ if (!Array.isArray(chats)) {
+ chats = [chats];
+ }
+ for (let i = chats.length; i--;) {
+ const room = self.getRoomFromUrlHash(chats[i]);
+ if (room) {
+ callback(room, ++result);
}
- };
- const setSource = n => {
- if (thumbnails.has(n.fa)) {
- const src = thumbnails.get(n.fa);
- const batch = [...nodes.get(n.fa)];
- for (let i = batch.length; i--;) {
- const n = batch[i];
- const handlers = [...loaders.get(n.h)];
- for (let i = handlers.length; i--;) {
- let callback = handlers[i];
- if (typeof callback !== 'function') {
- callback = defaultCallback;
- }
- tryCatch(() => {
- const id = callback(n, src);
- if (id) {
- defaultCallback(n, src, id);
- }
- })();
- }
- }
- return true;
+ }
+ return result;
+ };
+ const lookupPendingUpload = function (id) {
+ console.assert((id | 0) > 0 || String(id).length === 8, 'Invalid lookupPendingUpload arguments...');
+ for (const uid in ulmanager.ulEventData) {
+ if (ulmanager.ulEventData[uid].faid === id || ulmanager.ulEventData[uid].h === id) {
+ return uid;
}
- };
- for (const [, [n]] of nodes) {
- if (!setSource(n)) {
- pending.push(n);
+ }
+ };
+ const unregisterListeners = function () {
+ if (!$.len(ulmanager.ulEventData)) {
+ self.unregisterUploadListeners();
+ if (d) {
+ logger.warn('Revoked upload listeners.');
}
}
- if (pending.length) {
- fm_thumbnails('standalone', pending, setSource);
+ };
+ const onUploadComplete = function (ul) {
+ if (ulmanager.ulEventData[ul && ul.uid]) {
+ forEachChat(ul.chat, (room) => {
+ if (d) {
+ logger.debug('Attaching node[%s] to chat room[%s]...', ul.h, room.chatId, ul.uid, ul, M.d[ul.h]);
+ }
+ room.attachNodes([ul.h]).catch(dump);
+ });
+ delete ulmanager.ulEventData[ul.uid];
+ unregisterListeners();
+ } else if (d) {
+ logger.warn('could not complete upload...', ul);
}
- this.thumbsLoadingHandlers.clear();
- this.thumbsThatRequireLoading.clear();
- }
- requestThumbnailCb(node, immediate, callback) {
- if (node && node.fa) {
- if (typeof immediate === 'function') {
- callback = immediate;
- immediate = 0;
+ };
+ const onUploadCompletion = function (uid, handle, faid, chat) {
+ if (!chat) {
+ if (d > 1) {
+ logger.debug('ignoring upload:completion that is unrelated to chat.', arguments);
}
- node.seen = node.seen || -7;
- this.thumbsLoadingHandlers.set(node.h, callback);
- this.thumbsThatRequireLoading.set(node.fa, node);
- delay('chat:mega-list2:thumb-loader', () => this.enqueueThumbnailRetrieval(), immediate || 480);
+ return;
}
- }
- render() {
- if (this.isMounted() && !this._calculated) {
- this._recalculate();
+ const n = M.getNodeByHandle(handle);
+ const ul = ulmanager.ulEventData[uid] || false;
+ if (d) {
+ logger.info('upload:completion', uid, handle, faid, ul, n);
}
- const {
- listAdapter,
- listAdapterOpts,
- entries,
- nodeAdapterProps,
- viewMode,
- header,
- onContextMenu
- } = this.props;
- const className = `${listAdapter.containerClassName } megaList megaList2`;
- const first = this._calculated.visibleFirstItemNum;
- const last = this._calculated.visibleLastItemNum;
- const nodes = [];
- for (let i = first; i < last; i++) {
- const node = entries[i];
- nodes.push(REaCt().createElement(this.props.nodeAdapter, (0,esm_extends.A)({
- key: `${i }_${ node[this.props.keyProp]}`,
- h: node[this.props.keyProp],
- index: i,
- megaList: this,
- listAdapter,
- node,
- calculated: this._calculated,
- listAdapterOpts,
- onContextMenu,
- selected: this.props.selected ? this.props.selected.indexOf(node[this.props.keyProp]) > -1 : false,
- highlighted: this.props.highlighted ? this.props.highlighted.indexOf(node[this.props.keyProp]) > -1 : false,
- requestThumbnailCb: this.requestThumbnailCb,
- keyProp: this.props.keyProp || 'h'
- }, nodeAdapterProps)));
- }
- const listAdapterName = listAdapter.prototype.constructor.name;
- return REaCt().createElement(REaCt().Fragment, null, REaCt().createElement(perfectScrollbar.O, {
- key: `ps_${ listAdapterName }_${ viewMode}`,
- options: this.options.perfectScrollOptions,
- onUserScroll: this.onPsUserScroll,
- className,
- style: {
- 'position': 'relative'
- },
- ref: instance => {
- this.domRef = instance;
- }
- }, REaCt().createElement(this.props.listAdapter, (0,esm_extends.A)({
- containerClassName: this.props.containerClassName,
- key: `ps_${ listAdapterName }_${ this.props.viewMode }_la`,
- ref: listAdapterInstance => {
- this.listAdapterInstance = listAdapterInstance;
- },
- listContentRef: listContent => {
- this.listContent = listContent;
- },
- header,
- megaList: this,
- calculated: this._calculated
- }, listAdapterOpts), nodes)));
- }
-}, (0,applyDecoratedDescriptor.A)(_class.prototype, "onPsUserScroll", [_dec], Object.getOwnPropertyDescriptor(_class.prototype, "onPsUserScroll"), _class.prototype), _class);
-// EXTERNAL MODULE: ./js/ui/jsx/fm/nodes/genericNodePropsComponent.jsx + 1 modules
-const genericNodePropsComponent = REQ_(984);
-;// ./js/ui/jsx/fm/nodes/genericGrid.jsx
-
-
-class GenericGrid extends genericNodePropsComponent.B {
- render() {
- const {
- node,
- calculated,
- index,
- listAdapter,
- className,
- keyProp
- } = this.props;
- const style = {};
- listAdapter.repositionItem(node, calculated, index, style);
- const toApplySensitive = !!mega.sensitives.isSensitive(node) && (mega.sensitives.showGlobally ? 1 : 2);
- let image = null;
- let src = null;
- let isThumbClass = "";
- if (node.fa && (is_image2(node) || is_video(node))) {
- src = thumbnails.get(node.fa);
- if (!src) {
- this.props.requestThumbnailCb(node);
- src = window.noThumbURI || '';
- }
- image = src ? REaCt().createElement("img", {
- alt: "",
- src
- }) : REaCt().createElement("img", {
- alt: ""
- });
- isThumbClass = " thumb";
+ if (!ul) {
+ if (d) {
+ logger.error('Upload event data store missing...', uid, n, ul);
+ }
} else {
- image = REaCt().createElement("img", null);
- }
- let fileStatusClass = "";
- if (node.fav) {
- fileStatusClass += " icon-favourite-filled";
- }
- return REaCt().createElement("a", {
- className: `data-block-view megaListItem ui-droppable ui-draggable ui-draggable-handle ${ this.nodeProps.classNames.join(" ") }${className && className(node) || "" }${toApplySensitive ? toApplySensitive === 1 ? ' is-sensitive' : ' hidden-as-sensitive' : ''}`,
- id: `chat_${ node[keyProp]}`,
- onClick: e => {
- this.props.onClick(e, this.props.node);
- },
- onDoubleClick: e => {
- this.props.onDoubleClick(e, this.props.node);
- },
- title: this.nodeProps.title,
- style
- }, REaCt().createElement("span", {
- className: `data-block-bg ${ isThumbClass}`
- }, REaCt().createElement("span", {
- className: "data-block-indicators"
- }, REaCt().createElement("span", {
- className: `file-status-icon indicator sprite-fm-mono${ fileStatusClass}`
- }), REaCt().createElement("span", {
- className: "versioning-indicator"
- }, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-versions-previous"
- })), REaCt().createElement("i", {
- className: "sprite-fm-mono icon-link"
- })), REaCt().createElement("span", {
- className: `item-type-icon-90 icon-${ this.nodeProps.icon }-90`
- }, image), REaCt().createElement("div", {
- className: "video-thumb-details"
- }, REaCt().createElement("i", {
- className: "small-icon small-play-icon"
- }), REaCt().createElement("span", null, "00:00"))), REaCt().createElement("span", {
- className: "file-block-title"
- }, this.nodeProps.title));
- }
-}
-;// ./js/ui/jsx/fm/nodes/genericTable.jsx
-
-
-
-class GenericTableHeader extends mixins.w9 {
- constructor(...args) {
- super(...args);
- this.domRef = REaCt().createRef();
- }
- render() {
- const {
- sortBy,
- columns
- } = this.props;
- const columnsRendered = [];
- for (let i = 0; i < columns.length; i++) {
- var _colProps;
- let col = columns[i];
- let colProps;
- if (Array.isArray(col)) {
- colProps = col[1];
- col = col[0];
- }
- let sortable;
- if (col.sortable) {
- let classes = "";
- if (sortBy[0] === col.id) {
- const ordClass = sortBy[1] === "desc" ? "icon-arrow-down" : "icon-arrow-up";
- classes = `${classes} ${ordClass}`;
- }
- if (col.id === 'fav') {
- classes += ' hidden';
+ ul.h = handle;
+ if (ul.efa && !n) {
+ if (d) {
+ logger.error('Invalid state, efa set on deduplication?', ul.efa, ul);
}
- sortable = REaCt().createElement("i", {
- className: `sprite-fm-mono ${col.id} ${classes}`
- });
- }
- columnsRendered.push(REaCt().createElement("th", {
- megatype: col.megatype,
- className: col.headerClassName || col.megatype || "",
- key: `${col.id }_${ i}`,
- onClick: e => {
- e.preventDefault();
- if (col.sortable) {
- this.props.onClick(col.id);
- }
+ ul.efa = 0;
+ } else if (ufo[faid]) {
+ if (d) {
+ logger.info(`Recovering fa:error state for ${faid}`, ufo[faid], ul.efa);
}
- }, REaCt().createElement("span", null, ((_colProps = colProps) == null ? void 0 : _colProps.label) || col.label), col.icon && REaCt().createElement("i", {
- className: `sprite-fm-mono ${ col.icon}`
- }), sortable));
- }
- return REaCt().createElement("thead", {
- ref: this.domRef
- }, REaCt().createElement("tr", null, columnsRendered));
- }
-}
-class GenericTable extends genericNodePropsComponent.B {
- render() {
- let _this$nodeProps;
- const {
- node,
- index,
- listAdapterOpts,
- className,
- keyProp
- } = this.props;
- const toApplySensitive = !!mega.sensitives.isSensitive(node) && (mega.sensitives.showGlobally ? 1 : 2);
- const columns = [];
- for (let i = 0; i < listAdapterOpts.columns.length; i++) {
- const customColumn = listAdapterOpts.columns[i];
- if (Array.isArray(customColumn)) {
- columns.push(REaCt().createElement(customColumn[0], {
- ...customColumn[1],
- 'nodeAdapter': this,
- 'h': node[keyProp],
- node,
- 'key': `${i }_${ customColumn[0].prototype.constructor.name}`,
- keyProp
- }));
- } else {
- columns.push(REaCt().createElement(customColumn, {
- 'nodeAdapter': this,
- 'h': node[keyProp],
- node,
- 'key': `${i }_${ customColumn.prototype.constructor.name}`,
- keyProp
- }));
+ ul.efa = Math.max(0, ul.efa - ufo[faid]) | 0;
}
- }
- const listClassName = listAdapterOpts.className;
- return REaCt().createElement("tr", {
- className: `node_${ node[keyProp] } ${ className && className(node) || "" } ${ listClassName && listClassName(node) || "" } ${ (_this$nodeProps = this.nodeProps) == null ? void 0 : _this$nodeProps.classNames.join(" ") }${toApplySensitive ? toApplySensitive === 1 ? ' is-sensitive' : ' hidden-as-sensitive' : ''}`,
- id: node[keyProp],
- onContextMenu: ev => {
- if (this.props.onContextMenu) {
- this.props.onContextMenu(ev, node[keyProp]);
- }
- },
- onClick: e => {
- this.props.onClick(e, this.props.node);
- },
- onDoubleClick: e => {
- this.props.onDoubleClick(e, this.props.node);
- },
- key: `${index }_${ node[keyProp]}`
- }, columns);
- }
-}
-;// ./js/ui/jsx/megaList/adapters.jsx
-
-
-class GenericListAdapter extends mixins.w9 {
- constructor(...args) {
- super(...args);
- this.customIsEventuallyVisible = true;
- }
-}
-class Grid extends GenericListAdapter {
- static repositionItem(node, calculated, index, style) {
- style.position = "absolute";
- style.top = calculated.itemHeight * Math.floor(index / calculated.itemsPerRow);
- if (calculated.itemsPerRow > 1) {
- style.left = index % calculated.itemsPerRow * calculated.itemWidth;
- }
- }
- render() {
- return REaCt().createElement("div", {
- className: "megaList-content",
- ref: this.props.listContentRef,
- style: {
- 'position': 'relative'
+ if (ul.efa && (!n.fa || String(n.fa).split('/').length < ul.efa)) {
+ console.assert(!ul.faid || ul.faid === faid, `${faid} != ${ul.faid}`);
+ ul.faid = faid;
+ if (d) {
+ logger.info('Waiting for file attribute to arrive.', handle, ul.efa, n.fa, n.name, ul, [n]);
+ }
+ } else {
+ onUploadComplete(ul);
}
- }, this.props.children);
- }
-}
-Grid.itemWidth = 212;
-Grid.itemHeight = 212;
-Grid.containerClassName = "file-block-scrolling megaListContainer";
-class Table extends GenericListAdapter {
- onContentUpdated() {
- const {
- calculated
- } = this.props;
- const pusherHeight = calculated.visibleFirstItemNum * calculated.itemHeight | 0;
- if (this.topPusher) {
- this.topPusher.style.height = `${pusherHeight }px`;
}
- if (this.bottomPusher) {
- this.bottomPusher.style.height = `${calculated.contentHeight - pusherHeight - (calculated.visibleLastItemNum - calculated.visibleFirstItemNum) * calculated.itemHeight | 0 }px`;
+ };
+ const onUploadError = function (uid, error) {
+ const ul = ulmanager.ulEventData[uid];
+ if (d) {
+ logger.debug(error === -0xDEADBEEF ? 'upload:abort' : 'upload.error', uid, error, [ul]);
}
- }
- componentDidUpdate() {
- super.componentDidUpdate();
- this.onContentUpdated();
- }
- render() {
- return REaCt().createElement("table", {
- width: "100%",
- className: this.props.containerClassName || "grid-table table-hover fm-dialog-table"
- }, this.props.header, REaCt().createElement("tbody", {
- ref: this.props.listContentRef
- }, REaCt().createElement("tr", {
- className: "megalist-pusher top",
- ref: r => {
- this.topPusher = r;
- }
- }), this.props.children, REaCt().createElement("tr", {
- className: "megalist-pusher bottom",
- ref: r => {
- this.bottomPusher = r;
+ if (ul) {
+ delete ulmanager.ulEventData[uid];
+ unregisterListeners();
+ } else if (d) {
+ logger.warn(`No upload association for #${uid}`, error);
+ }
+ };
+ const onAttributeReady = function (handle, fa) {
+ delay(`chat:fa-ready:${ handle}`, () => {
+ const uid = lookupPendingUpload(handle);
+ const ul = ulmanager.ulEventData[uid] || false;
+ if (d) {
+ logger.debug('fa:ready', handle, fa, ul.efa, uid, ul);
+ }
+ if (ul.h && String(fa).split('/').length >= ul.efa) {
+ onUploadComplete(ul);
+ } else if (d) {
+ logger.debug('Not enough file attributes yet, holding...', handle, fa, ul.efa, ul);
+ }
+ });
+ };
+ const onAttributeError = function (faid, error, onStorageAPIError, nFAiled) {
+ const uid = lookupPendingUpload(faid);
+ const ul = ulmanager.ulEventData[uid] || false;
+ if (d) {
+ logger.debug('fa:error', faid, error, onStorageAPIError, uid, ul, nFAiled, ul.efa);
+ }
+ if (ul) {
+ ul.efa = Math.max(0, ul.efa - nFAiled) | 0;
+ if (ul.h) {
+ const n = M.getNodeByHandle(ul.h);
+ if (!ul.efa || n.fa && String(n.fa).split('/').length >= ul.efa) {
+ onUploadComplete(ul);
+ }
}
- })));
- }
-}
-Table.itemHeight = 32;
-Table.itemsPerRow = 1;
-Table.containerClassName = "grid-scrolling-table megaListContainer";
-// EXTERNAL MODULE: ./js/ui/jsx/fm/nodes/columns/columnFavIcon.jsx
-const columnFavIcon = REQ_(161);
-;// ./js/ui/tooltips.jsx
-const React = REQ_(594);
-
-class Handler extends React.Component {
- render() {
- const {
- className,
- onMouseOver,
- onMouseOut,
- children
- } = this.props;
- return React.createElement("span", {
- className: `
- tooltip-handler
- ${className || ''}
- `,
- onMouseOver,
- onMouseOut
- }, children);
- }
-}
-class Contents extends React.Component {
- render() {
- let className = `tooltip-contents dropdown body tooltip ${ this.props.className ? this.props.className : ""}`;
- if (this.props.active) {
- className += " visible";
- return React.createElement("div", {
- className
- }, this.props.withArrow ? React.createElement("i", {
- className: "dropdown-white-arrow"
- }) : null, this.props.children);
} else {
- return null;
+ if (d) {
+ logger.warn(`No upload association for ${faid} (yet?)`, nFAiled, error);
+ }
+ ufo[faid] = (ufo[faid] | 0) + nFAiled;
}
- }
-}
-class Tooltip extends mixins.w9 {
- constructor(props) {
- super(props);
- this.domRef = React.createRef();
- this.state = {
- 'active': false
- };
- }
- componentDidUpdate(oldProps, oldState) {
- const self = this;
- if (oldState.active === true && this.state.active === false) {
- chatGlobalEventManager.removeEventListener('resize', `tooltip${ this.getUniqueId()}`);
+ };
+ const registerLocalListeners = function () {
+ self._uplError = mBroadcaster.addListener('upload:error', onUploadError);
+ self._uplAbort = mBroadcaster.addListener('upload:abort', onUploadError);
+ self._uplFAReady = mBroadcaster.addListener('fa:ready', onAttributeReady);
+ self._uplFAError = mBroadcaster.addListener('fa:error', onAttributeError);
+ self._uplDone = mBroadcaster.addListener('upload:completion', onUploadCompletion);
+ };
+ self._uplStart = mBroadcaster.addListener('upload:start', (data) => {
+ if (d) {
+ logger.info('onUploadStart', [data]);
}
- if (self.state.active === true) {
- self.repositionTooltip();
- chatGlobalEventManager.addEventListener('resize', `tooltip${ this.getUniqueId()}`, () => {
- self.repositionTooltip();
- });
- if (this.props.onShown) {
- this.props.onShown();
+ const notify = function (room) {
+ room.onUploadStart(data);
+ };
+ for (const k in data) {
+ const chats = data[k].chat;
+ if (chats && forEachChat(chats, notify) && !self._uplError) {
+ registerLocalListeners();
}
}
+ });
+};
+Chat.prototype.getRoomFromUrlHash = function (urlHash) {
+ if (urlHash.indexOf("#") === 0) {
+ urlHash = urlHash.subtr(1, urlHash.length);
}
- repositionTooltip() {
- let _this$domRef;
- let elLeftPos, elTopPos, elWidth, elHeight;
- let tooltipLeftPos, tooltipTopPos, tooltipWidth, tooltipHeight;
- let docHeight;
- let arrowClass;
- if (!this.isMounted()) {
+ if (urlHash.indexOf("chat/g/") > -1 || urlHash.indexOf("chat/c/") > -1) {
+ var foundRoom = null;
+ urlHash = urlHash.replace("chat/g/", "").replace("chat/c/", "");
+ megaChat.chats.forEach((room) => {
+ if (!foundRoom && room.chatId === urlHash) {
+ foundRoom = room;
+ }
+ });
+ return foundRoom;
+ } else if (urlHash.indexOf("chat/p/") > -1) {
+ const contactHash = urlHash.replace("chat/p/", "");
+ if (!contactHash) {
return;
}
- const $container = $((_this$domRef = this.domRef) == null ? void 0 : _this$domRef.current);
- const $el = $('.tooltip-handler', $container);
- const $tooltip = $('.tooltip-contents', $container);
- let {tooltipOffset} = this.props;
- const arrow = this.props.withArrow;
- if ($el && $tooltip) {
- elWidth = $el.outerWidth();
- elHeight = $el.outerHeight();
- elLeftPos = $el.offset().left;
- elTopPos = $el.offset().top;
- tooltipWidth = $tooltip.outerWidth();
- tooltipHeight = $tooltip.outerHeight();
- docHeight = $(window).height();
- $tooltip.removeClass('dropdown-arrow left-arrow right-arrow up-arrow down-arrow').removeAttr('style');
- if (!tooltipOffset) {
- tooltipOffset = 7;
- }
- if (elTopPos - tooltipHeight - tooltipOffset > 10) {
- tooltipLeftPos = elLeftPos + elWidth / 2 - tooltipWidth / 2;
- tooltipTopPos = elTopPos - tooltipHeight - tooltipOffset;
- arrowClass = arrow ? 'dropdown-arrow down-arrow' : '';
- } else if (docHeight - (elTopPos + elHeight + tooltipHeight + tooltipOffset) > 10) {
- tooltipLeftPos = elLeftPos + elWidth / 2 - tooltipWidth / 2;
- tooltipTopPos = elTopPos + elHeight + tooltipOffset;
- arrowClass = arrow ? 'dropdown-arrow up-arrow' : '';
- } else if (elLeftPos - tooltipWidth - tooltipOffset > 10) {
- tooltipLeftPos = elLeftPos - tooltipWidth - tooltipOffset;
- tooltipTopPos = elTopPos + elHeight / 2 - tooltipHeight / 2;
- arrowClass = arrow ? 'dropdown-arrow right-arrow' : '';
- } else {
- tooltipLeftPos = elLeftPos + elWidth + tooltipOffset;
- tooltipTopPos = elTopPos + elHeight / 2 - tooltipHeight / 2;
- arrowClass = arrow ? 'dropdown-arrow left-arrow' : '';
+ const chatRoom = this.getPrivateRoom(contactHash);
+ return chatRoom;
+ } else if (urlHash.indexOf("chat/") > -1 && urlHash[13] === "#") {
+ var foundRoom = null;
+ const pubHandle = urlHash.replace("chat/", "").split("#")[0];
+ urlHash = urlHash.replace("chat/g/", "");
+ const chatIds = megaChat.chats.keys();
+ for (let i = 0; i < chatIds.length; i++) {
+ const cid = chatIds[i];
+ const room = megaChat.chats[cid];
+ if (room.publicChatHandle === pubHandle) {
+ foundRoom = room;
+ break;
}
- $tooltip.css({
- 'left': tooltipLeftPos,
- 'top': tooltipTopPos - 5
- });
- $tooltip.addClass(arrowClass);
}
+ return foundRoom;
+ } else {
+ return null;
}
- onHandlerMouseOver() {
- this.setState({
- 'active': true
- });
- }
- onHandlerMouseOut() {
- this.setState({
- 'active': false
- });
- }
- render() {
- const self = this;
- const others = [];
- let handler = null;
- let contents = null;
- let x = 0;
- React.Children.forEach(this.props.children, (child) => {
- if (child.type.name === 'Handler') {
- handler = React.cloneElement(child, {
- onMouseOver () {
- self.onHandlerMouseOver();
- },
- onMouseOut () {
- self.onHandlerMouseOut();
- }
- });
- } else if (child.type.name === 'Contents') {
- contents = React.cloneElement(child, {
- active: self.state.active,
- withArrow: self.props.withArrow
- });
- } else {
- const tmp = React.cloneElement(child, {
- key: x++
- });
- others.push(tmp);
- }
- });
- return React.createElement("span", {
- ref: this.domRef,
- className: this.props.className || ''
- }, handler, contents, others);
- }
-}
-Tooltip.defaultProps = {
- 'hideable': true
-};
-const tooltips = {
- Tooltip,
- Handler,
- Contents
};
-;// ./js/ui/jsx/fm/nodes/columns/columnNodeName.jsx
-
-
-
-class ColumnNodeName extends genericNodePropsComponent.B {
- constructor(...args) {
- super(...args);
- this.state = {
- src: null
- };
- }
- static get label() {
- return l[86];
- }
- componentDidMount() {
- super.componentDidMount();
- }
- render() {
- const {
- nodeAdapter
- } = this.props;
- const {
- node,
- requestThumbnailCb
- } = nodeAdapter.props;
- const src = this.state.src || thumbnails.get(node.fa);
- return REaCt().createElement("td", {
- megatype: ColumnNodeName.megatype
- }, src || is_image2(node) || is_video(node) ? REaCt().createElement(tooltips.Tooltip, {
- withArrow: true,
- className: "tooltip-handler-container",
- onShown: () => {
- if (!src) {
- requestThumbnailCb(node, true, (n, src) => {
- this.setState({
- src
- });
- return `preview_${n.h}`;
- });
- }
- }
- }, REaCt().createElement(tooltips.Handler, {
- className: `item-type-icon icon-${fileIcon(node)}-24`
- }), REaCt().createElement(tooltips.Contents, {
- className: "img-preview"
- }, REaCt().createElement("div", {
- className: "dropdown img-wrapper img-block",
- id: `preview_${node.h}`
- }, REaCt().createElement("img", {
- alt: "",
- className: `thumbnail-placeholder ${node.h}`,
- src: node.fa || src ? src || `${staticpath}/images/mega/ajax-loader-tiny.gif` : window.noThumbURI
- })))) : REaCt().createElement("span", {
- className: `
- item-type-icon icon-${fileIcon(node)}-24
- `
- }), REaCt().createElement("span", {
- className: "tranfer-filetype-txt"
- }, nodeAdapter.nodeProps.title));
- }
-}
-ColumnNodeName.sortable = true;
-ColumnNodeName.id = 'name';
-ColumnNodeName.megatype = 'fname';
-;// ./js/ui/jsx/fm/nodes/columns/columnSize.jsx
-
-
-class ColumnSize extends genericNodePropsComponent.B {
- static get label() {
- return l[87];
- }
- render() {
- const {
- nodeAdapter
- } = this.props;
- return REaCt().createElement("td", {
- megatype: ColumnSize.megatype,
- className: "size"
- }, nodeAdapter.nodeProps.size);
- }
-}
-ColumnSize.sortable = true;
-ColumnSize.id = "size";
-ColumnSize.megatype = "size";
-;// ./js/ui/jsx/fm/nodes/columns/columnTimeAdded.jsx
-
-
-class ColumnTimeAdded extends genericNodePropsComponent.B {
- static get label() {
- return l[16169];
- }
- render() {
- const {
- nodeAdapter
- } = this.props;
- return REaCt().createElement("td", {
- megatype: ColumnTimeAdded.megatype,
- className: "time ad"
- }, nodeAdapter.nodeProps.timestamp);
- }
-}
-ColumnTimeAdded.sortable = true;
-ColumnTimeAdded.id = "ts";
-ColumnTimeAdded.megatype = "timeAd";
-;// ./js/ui/jsx/fm/nodes/columns/columnExtras.jsx
-
-
-class ColumnExtras extends genericNodePropsComponent.B {
- render() {
- return REaCt().createElement("td", {
- megatype: ColumnExtras.megatype,
- className: "grid-url-field own-data extras-column"
- }, REaCt().createElement("span", {
- className: "versioning-indicator"
- }, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-versions-previous"
- })), REaCt().createElement("i", {
- className: "sprite-fm-mono icon-link"
- }));
- }
-}
-ColumnExtras.sortable = false;
-ColumnExtras.id = "extras";
-ColumnExtras.label = "";
-ColumnExtras.megatype = "extras";
-ColumnExtras.headerClassName = "grid-url-header";
-;// ./js/ui/jsx/fm/browserEntries.jsx
-
-
-
-
-
-
-
-
-
-
-
-class BrowserEntries extends mixins.w9 {
- constructor(props) {
- super(props);
- this.state = {
- 'sortBy': props.sortBy || ['name', 'asc']
- };
- this.toggleSortBy = this.toggleSortBy.bind(this);
- }
- UNSAFE_componentWillMount() {
- this.lastCharKeyPressed = false;
- this.lastCharKeyIndex = -1;
- }
- componentDidMount() {
- super.componentDidMount();
- this.bindEvents();
- }
- componentWillUnmount() {
- super.componentWillUnmount();
- this.unbindEvents();
+Chat.prototype.updateSectionUnreadCount = SoonFc(function () {
+ if (!this.is_initialized) {
+ return;
}
- componentDidUpdate(oldProps) {
- if (oldProps.sortBy && (oldProps.sortBy[0] !== this.props.sortBy[0] || oldProps.sortBy[1] !== this.props.sortBy[1])) {
- this.setState({
- 'sortBy': this.props.sortBy
- });
+ let unreadCount = 0;
+ const notificationsCount = {
+ unreadChats: 0,
+ unreadMeetings: 0,
+ unreadUpcoming: 0,
+ chatsCall: false,
+ meetingCall: false
+ };
+ let havePendingCall = false;
+ let haveAdHocMessage = false;
+ this.chats.forEach(chatRoom => {
+ if (chatRoom.isArchived() || chatRoom.state === ChatRoom.STATE.LEFT) {
+ return;
+ }
+ const unreads = parseInt(chatRoom.messagesBuff.getUnreadCount(), 10);
+ unreadCount += unreads;
+ if (unreads) {
+ notificationsCount[chatRoom.isMeeting ? 'unreadMeetings' : 'unreadChats'] += unreads;
+ if (chatRoom.scheduledMeeting && chatRoom.scheduledMeeting.isUpcoming) {
+ notificationsCount.unreadUpcoming += unreads;
+ }
}
- }
- handleKeyNavigation(selectionManager, shiftKey, keyCode, viewMode) {
- let curr;
- const {
- folderSelectNotAllowed
- } = this.props;
- if (shiftKey && folderSelectNotAllowed) {
- curr = selectionManager.last_selected;
- }
- const {KEYS} = BrowserEntries;
- if (viewMode) {
- if (keyCode === KEYS.LEFT) {
- selectionManager.select_prev(shiftKey, true);
- } else if (keyCode === KEYS.RIGHT) {
- selectionManager.select_next(shiftKey, true);
- } else if (keyCode === KEYS.UP) {
- selectionManager.select_grid_up(shiftKey, true);
+ if (chatRoom.havePendingCall() && chatRoom.uniqueCallParts && !chatRoom.uniqueCallParts[u_handle]) {
+ havePendingCall = true;
+ if (chatRoom.isMeeting) {
+ notificationsCount.meetingCall = true;
+ if (!chatRoom.scheduledMeeting && unreads) {
+ haveAdHocMessage = true;
+ }
} else {
- selectionManager.select_grid_down(shiftKey, true);
+ notificationsCount.chatsCall = true;
}
- } else if (keyCode === KEYS.UP) {
- selectionManager.select_prev(shiftKey, true);
+ }
+ });
+ unreadCount = unreadCount > 9 ? "9+" : unreadCount;
+ if (!is_chatlink && mega.ui.header) {
+ if (notificationsCount.unreadChats || notificationsCount.unreadUpcoming || haveAdHocMessage) {
+ mega.ui.header.chatsButton.addClass('decorated');
} else {
- selectionManager.select_next(shiftKey, true);
+ mega.ui.header.chatsButton.removeClass('decorated');
}
- if (shiftKey && folderSelectNotAllowed && $.selected.length > 1) {
- const folderNodes = $.selected.filter(n => !M.isFileNode(M.getNodeByHandle(n)));
- if (folderNodes.length > 1) {
- if (!M.isFileNode(M.getNodeByHandle(curr))) {
- array.remove(folderNodes, curr);
- }
- if (folderNodes.length) {
- const newCurr = selectionManager.last_selected;
- for (let i = 0; i < folderNodes.length; i++) {
- selectionManager.remove_from_selection(folderNodes[i]);
- }
- if (M.isFileNode(M.getNodeByHandle(newCurr))) {
- selectionManager.set_currently_selected(curr);
- } else if (curr && $.selected.includes(curr)) {
- selectionManager.set_currently_selected(curr);
- } else if ($.selected.length) {
- selectionManager.set_currently_selected($.selected[0]);
- }
- }
- }
+ const phoneIcon = mega.ui.header.domNode.querySelector('.top-chats-call');
+ if (phoneIcon) {
+ phoneIcon.classList[havePendingCall ? 'remove' : 'add']('hidden');
}
}
- _invalidKeydownTarget(e) {
- return e.target && (e.target.tagName === 'INPUT' || e.target.tagName === 'BUTTON' || e.target.tagName === 'TEXTAREA' && !e.target.classList.contains('messages-textarea') || e.target.tagName === 'SELECT');
- }
- _isNavigationKeyDown(e, keyCode) {
- const {
- KEYS
- } = BrowserEntries;
- const {
- viewMode
- } = this.props;
- return !e.metaKey && (!viewMode && (keyCode === KEYS.UP || keyCode === KEYS.DOWN) || viewMode && (keyCode === KEYS.UP || keyCode === KEYS.DOWN || keyCode === KEYS.LEFT || keyCode === KEYS.RIGHT));
+ if (this._lastUnreadCount !== unreadCount) {
+ this._lastUnreadCount = unreadCount;
+ notify.updateNotificationIndicator();
}
- bindEvents() {
- const {
- KEYS
- } = BrowserEntries;
- $(document.body).rebind(`keydown.be${this.getUniqueId()}`, e => {
- let charTyped = false;
- const keyCode = e.which || e.keyCode;
- const $searchField = $('div.fm-files-search input');
- const $typingArea = $('textarea.messages-textarea');
- const {
- selectionManager,
- viewMode
- } = this.props;
- if (this._invalidKeydownTarget(e)) {
- return;
- }
- if ($searchField.is(':focus')) {
- return;
- }
- if ($typingArea.is(':focus')) {
- $typingArea.trigger('blur');
- }
- if (keyCode === KEYS.A && (e.ctrlKey || e.metaKey)) {
- this.handleSelectAll();
- e.preventDefault();
- e.stopPropagation();
- } else if (e.metaKey && keyCode === KEYS.UP || keyCode === KEYS.BACKSPACE) {
- this.handleKeyBack();
- } else if (this._isNavigationKeyDown(e, keyCode)) {
- this.handleKeyNavigation(selectionManager, e.shiftKey, keyCode, viewMode);
- } else if (keyCode >= 48 && keyCode <= 57 || keyCode >= 65 && keyCode <= 123 || keyCode > 255) {
- charTyped = String.fromCharCode(keyCode).toLowerCase();
- this.handleCharTyped(charTyped);
- } else if (keyCode === KEYS.ENTER || e.metaKey && keyCode === KEYS.DOWN) {
- this.handleAttach();
- }
- mega.ui.mInfoPanel.reRenderIfVisible($.selected);
- if (!charTyped) {
- this.lastCharKeyPressed = false;
- this.lastCharKeyIndex = -1;
- }
- });
+ if (!this._lastNotifications || !shallowEqual(this._lastNotifications, notificationsCount)) {
+ this._lastNotifications = notificationsCount;
+ megaChat.trigger('onUnreadCountUpdate', notificationsCount);
}
- handleSelectAll() {
- const {
- selectionManager,
- folderSelectNotAllowed,
- entries
- } = this.props;
- selectionManager.select_all();
- if (folderSelectNotAllowed) {
- const folders = entries.filter(h => !M.isFileNode(M.getNodeByHandle(h)));
- for (let i = 0; i < folders.length; i++) {
- selectionManager.remove_from_selection(folders[i].h);
- }
- }
+}, 100);
+Chat.prototype.dropAllDatabases = promisify(function (resolve, reject) {
+ const chatd = this.plugins.chatdIntegration.chatd || false;
+ const promises = [];
+ if (chatd.chatdPersist) {
+ promises.push(chatd.chatdPersist.drop());
}
- handleKeyBack() {
- const {
- viewMode,
- currentlyViewedEntry
- } = this.props;
- if (!viewMode) {
- const currentFolder = M.getNode(currentlyViewedEntry);
- if (currentFolder.p) {
- this.expandFolder(currentFolder.p);
- }
- }
+ if ('messagesQueueKvStorage' in chatd) {
+ promises.push(chatd.messagesQueueKvStorage.destroy());
}
- handleCharTyped(charTyped) {
- const {
- entries,
- keyProp,
- selectionManager
- } = this.props;
- const foundMatchingNodes = entries.filter(node => {
- return node.name && node.name.substring(0, 1).toLowerCase() === charTyped;
- });
- if (this.lastCharKeyPressed === charTyped) {
- this.lastCharKeyIndex++;
- }
- this.lastCharKeyPressed = charTyped;
- if (foundMatchingNodes.length > 0) {
- if (!foundMatchingNodes[this.lastCharKeyIndex]) {
- this.lastCharKeyIndex = 0;
- }
- const foundNode = foundMatchingNodes[this.lastCharKeyIndex];
- selectionManager.clear_selection();
- selectionManager.set_currently_selected(foundNode[keyProp], true);
- }
+ if (Reactions.ready) {
+ promises.push(Reactions._db.destroy());
}
- handleAttach() {
- const {
- highlighted,
- folderSelectNotAllowed,
- entries,
- keyProp,
- onAttachClicked
- } = this.props;
- let selectedNodes = highlighted;
- if (folderSelectNotAllowed) {
- selectedNodes = highlighted.filter(h => {
- const node = entries.find(e => e[keyProp] === h);
- return node && node.t === 0;
- });
- if (selectedNodes.length === 0) {
- const cursorNode = highlighted[0] && M.getNodeByHandle(highlighted[0]);
- if (cursorNode.t === 1) {
- this.expandFolder(cursorNode[keyProp]);
- return;
- } else if (highlighted.length > 0) {
- this.expandFolder(highlighted[0]);
- return;
- }
- return;
- }
- }
- onAttachClicked(selectedNodes);
+ if (PersistedTypeArea.ready) {
+ promises.push(PersistedTypeArea._db.destroy());
}
- unbindEvents() {
- $(document.body).off(`keydown.be${ this.getUniqueId()}`);
+ Promise.allSettled(promises).then(resolve).catch(reject);
+});
+Chat.prototype.destroy = function (isLogout) {
+ if (!this.is_initialized) {
+ return;
}
- onEntryClick(e, node) {
- const {
- selectionManager,
- keyProp,
- folderSelectNotAllowed,
- highlighted = []
- } = this.props;
- this.lastCharKeyPressed = false;
- this.lastCharKeyIndex = -1;
- e.stopPropagation();
- e.preventDefault();
- if (!e.shiftKey && !e.ctrlKey && !e.metaKey) {
- selectionManager.clear_selection();
- selectionManager.set_currently_selected(node[keyProp]);
- } else if (e.shiftKey) {
- if ($.selected && $.selected.length) {
- let selFolders;
- if (folderSelectNotAllowed) {
- selFolders = $.selected.filter(n => !M.isFileNode(M.getNodeByHandle(n)));
- }
- selectionManager.shift_select_to(node[keyProp], false, true, false);
- if (folderSelectNotAllowed && $.selected.length > 1) {
- const folderNodes = $.selected.filter(n => !M.isFileNode(M.getNodeByHandle(n)));
- if (folderNodes.length > 1) {
- array.remove(folderNodes, selFolders[0] || folderNodes[0]);
- for (let i = 0; i < folderNodes.length; i++) {
- selectionManager.remove_from_selection(folderNodes[i]);
- }
- }
- }
- } else {
- selectionManager.set_currently_selected(node[keyProp]);
- }
- } else if (e.ctrlKey || e.metaKey) {
- if (!highlighted || !highlighted.includes(node[keyProp])) {
- if (folderSelectNotAllowed) {
- if (node.t === 1 && highlighted.length > 0) {
- return;
- } else if (highlighted.some(nodeId => {
- const node = M.getNodeByHandle(nodeId);
- return node && node.t === 1;
- })) {
- selectionManager.clear_selection();
- }
- }
- selectionManager.add_to_selection(node[keyProp]);
- } else if (highlighted && highlighted.includes(node[keyProp])) {
- if (folderSelectNotAllowed) {
- if (node.t === 1) {
- return;
- } else if (highlighted.some(nodeId => {
- const node = M.getNodeByHandle(nodeId);
- return node && node.t === 1;
- })) {
- selectionManager.clear();
- }
- }
- selectionManager.remove_from_selection(node[keyProp]);
- }
- }
+ this.isLoggingOut = isLogout;
+ for (let i = 0; i < this.mbListeners.length; i++) {
+ mBroadcaster.removeListener(this.mbListeners[i]);
}
- expandFolder(nodeId) {
- const self = this;
- const node = M.getNodeByHandle(nodeId);
- if (node) {
- self.lastCharKeyPressed = false;
- self.lastCharKeyIndex = -1;
- self.setState({
- 'selected': [],
- 'highlighted': [],
- 'cursor': false
- });
- self.props.onExpand(node);
- self.forceUpdate();
+ this.unregisterUploadListeners(true);
+ this.trigger('onDestroy', [isLogout]);
+ tryCatch(() => this.$$root.unmount())();
+ this.chats.forEach((chatRoom, chatId) => {
+ if (!isLogout) {
+ chatRoom.destroy(false, true);
}
+ this.chats.remove(chatId);
+ });
+ this.is_initialized = false;
+ if (this.plugins.chatdIntegration && this.plugins.chatdIntegration.chatd && this.plugins.chatdIntegration.chatd.shards) {
+ const {
+ shards
+ } = this.plugins.chatdIntegration.chatd;
+ Object.keys(shards).forEach(shard => shards[shard].connectionRetryManager.options.functions.forceDisconnect());
}
- onEntryDoubleClick(e, node) {
- const self = this;
- self.lastCharKeyPressed = false;
- self.lastCharKeyIndex = -1;
- e.stopPropagation();
- e.preventDefault();
- const share = M.getNodeShare(node);
- if (share && share.down) {
- return;
- }
- if (node.t) {
- self.props.onExpand(node);
- self.forceUpdate();
- } else {
- self.onEntryClick(e, node);
- self.props.onAttachClicked();
+ for (const pluginName in this.plugins) {
+ const plugin = this.plugins[pluginName];
+ if (plugin.destroy) {
+ plugin.destroy();
}
}
- customIsEventuallyVisible() {
- return true;
- }
- toggleSortBy(colId) {
- const newState = {};
- if (this.state.sortBy[0] === colId) {
- newState.sortBy = [colId, this.state.sortBy[1] === "asc" ? "desc" : "asc"];
- } else {
- newState.sortBy = [colId, "asc"];
- }
- this.setState(newState);
- this.props.onSortByChanged(newState.sortBy);
+ if (this.minuteClockInterval) {
+ clearInterval(this.minuteClockInterval);
}
- render() {
- const {viewMode} = this.props;
- const listAdapterOpts = this.props.listAdapterOpts || {};
- if (!viewMode) {
- listAdapterOpts.columns = [columnFavIcon.$, ColumnNodeName, ColumnSize, ColumnTimeAdded, ColumnExtras];
- }
- if (this.props.listAdapterColumns) {
- listAdapterOpts.columns = this.props.listAdapterColumns;
- }
- if (this.props.isLoading) {
- return REaCt().createElement("div", {
- className: "dialog-empty-block active dialog-fm folder"
- }, REaCt().createElement("div", {
- className: "dialog-empty-pad"
- }, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-cloud-drive"
- }), REaCt().createElement("div", {
- className: "dialog-empty-header"
- }, l[5533])));
- } else if (!this.props.entries.length && this.props.currentlyViewedEntry === 'search') {
- return REaCt().createElement("div", {
- className: "dialog-empty-block active dialog-fm folder"
- }, REaCt().createElement("div", {
- className: "dialog-empty-pad"
- }, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-preview-reveal"
- }), REaCt().createElement("div", {
- className: "dialog-empty-header"
- }, l[978])));
- } else if (!this.props.entries.length) {
- const nilComp = this.props.NilComponent;
- return nilComp && (typeof nilComp === "function" ? nilComp() : nilComp) || REaCt().createElement("div", {
- className: "dialog-empty-block active dialog-fm folder"
- }, this.props.currentlyViewedEntry === 'shares' ? REaCt().createElement("div", {
- className: "dialog-empty-pad"
- }, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-folder-incoming-share-filled"
- }), REaCt().createElement("div", {
- className: "dialog-empty-header"
- }, l[6871])) : REaCt().createElement("div", {
- className: "dialog-empty-pad"
- }, REaCt().createElement("i", {
- className: "sprite-fm-mono icon-folder-filled"
- }), REaCt().createElement("div", {
- className: "dialog-empty-header"
- }, this.props.currentlyViewedEntry === M.RootID ? l[1343] : M.u[this.props.currentlyViewedEntry] ? l[6787] : l[782])));
- }
- return REaCt().createElement(MegaList2, {
- viewMode,
- sortBy: this.state.sortBy,
- currentlyViewedEntry: this.props.currentlyViewedEntry,
- selected: this.props.selected,
- highlighted: this.props.highlighted,
- containerClassName: this.props.containerClassName,
- nodeAdapterProps: {
- 'onClick': (e, node) => {
- this.onEntryClick(e, node);
- mega.ui.mInfoPanel.reRenderIfVisible($.selected);
- },
- 'onDoubleClick': (e, node) => {
- this.onEntryDoubleClick(e, node);
- },
- 'className': node => {
- return this.props.highlighted.indexOf(node[this.props.keyProp]) > -1 ? " ui-selected" : "";
- }
- },
- ref: r => {
- this.megaList = r;
- },
- listAdapter: viewMode ? Grid : Table,
- nodeAdapter: viewMode ? GenericGrid : GenericTable,
- listAdapterOpts,
- entries: this.props.entries,
- itemHeight: this.props.megaListItemHeight,
- headerHeight: viewMode ? 0 : 56,
- header: !viewMode && REaCt().createElement(GenericTableHeader, {
- columns: listAdapterOpts.columns,
- sortBy: this.state.sortBy,
- onClick: this.toggleSortBy,
- headerContainerClassName: this.props.headerContainerClassName
- }),
- currentdirid: this.props.currentdirid,
- onContextMenu: this.props.onContextMenu,
- keyProp: this.props.keyProp
- });
+ if (megaChat.flyoutStartHolder && mega.ui.flyout) {
+ mega.ui.flyout.reinit(megaChat.flyoutStartHolder);
+ delete megaChat.flyoutStartHolder;
}
-}
-BrowserEntries.KEYS = {
- A: 65,
- UP: 38,
- DOWN: 40,
- LEFT: 37,
- RIGHT: 39,
- ENTER: 13,
- BACKSPACE: 8
-};
-BrowserEntries.defaultProps = {
- 'hideable': true,
- 'requiresUpdateOnResize': true
};
-;// ./js/ui/jsx/fm/fmView.jsx
-
-
-
-class FMView extends mixins.w9 {
- constructor(props) {
- let _this$dataSource;
- super(props);
- this.domRef = REaCt().createRef();
- let initialSortBy = props.initialSortBy || ['name', 'asc'];
- if (props.fmConfigSortEnabled) {
- let _fmconfig$sortmodes;
- const sortId = props.fmConfigSortId;
- assert(sortId, 'missing fmConfigSortId');
- if ((_fmconfig$sortmodes = fmconfig.sortmodes) != null && (_fmconfig$sortmodes = _fmconfig$sortmodes[sortId]) != null && _fmconfig$sortmodes.n) {
- let _fmconfig$sortmodes2;
- initialSortBy = this._translateFmConfigSortMode((_fmconfig$sortmodes2 = fmconfig.sortmodes) == null ? void 0 : _fmconfig$sortmodes2[sortId]);
- }
- }
- this.state = {
- 'sortBy': initialSortBy,
- 'selected': [],
- 'highlighted': [],
- 'entries': null
- };
- this.dataSource = this.props.dataSource;
- this.state.entries = this.getEntries();
- this.onAttachClicked = this.onAttachClicked.bind(this);
- this.onContextMenu = this.onContextMenu.bind(this);
- if ((_this$dataSource = this.dataSource) != null && _this$dataSource.addChangeListener) {
- this._listener = this.dataSource.addChangeListener(() => {
- if (!this.isMounted()) {
- return;
- }
- this.setState({
- 'entries': this.getEntries()
- });
- });
- }
- this.initSelectionManager();
- }
- getDataSourceNode(h) {
- return this.dataSource && this.dataSource[h] || M.getNodeByHandle(h);
- }
- _translateFmConfigSortMode(currentSortModes) {
- const sortId = this.props.fmConfigSortId;
- assert(sortId, 'missing fmConfigSortId');
- const sortByArr = [];
- if (currentSortModes != null && currentSortModes.n) {
- sortByArr[0] = currentSortModes.n;
- const sortMap = this.props.fmConfigSortMap;
- const aliasKeys = sortMap && Object.keys(sortMap) || [];
- for (const alias of aliasKeys) {
- if (sortByArr[0] === sortMap[alias]) {
- sortByArr[0] = alias;
- break;
- }
- }
- sortByArr[1] = currentSortModes.d === 1 ? "asc" : "desc";
+Chat.prototype.getContacts = function () {
+ const results = [];
+ M.u.forEach((k, v) => {
+ if (v.c == 1 || v.c == 2) {
+ results.push(v);
}
- return sortByArr;
+ });
+ return results;
+};
+Chat.prototype.userPresenceToCssClass = function (presence) {
+ if (presence === UserPresence.PRESENCE.ONLINE) {
+ return 'online';
+ } else if (presence === UserPresence.PRESENCE.AWAY) {
+ return 'away';
+ } else if (presence === UserPresence.PRESENCE.DND) {
+ return 'busy';
+ } else if (presence === UserPresence.PRESENCE.OFFLINE) {
+ return 'offline';
+ } else {
+ return 'black';
}
- initSelectionManager(entries) {
- this.selectionManager = new SelectionManager2_React(entries || this.state.entries, this.props.currentdirid || "cloud-drive", () => {
- let _this$browserEntries;
- return (_this$browserEntries = this.browserEntries) == null || (_this$browserEntries = _this$browserEntries.megaList) == null || (_this$browserEntries = _this$browserEntries._calculated) == null ? void 0 : _this$browserEntries.itemsPerRow;
- }, nodeHandle => {
- if (this.browserEntries && this.browserEntries.megaList) {
- this.browserEntries.megaList.scrollToItem(nodeHandle);
- }
- }, {
- 'onSelectedUpdated': selectedList => {
- this.onSelectionUpdated(selectedList);
- }
- });
+};
+Chat.prototype._renderMyStatus = function () {
+ const self = this;
+ if (!self.is_initialized) {
+ return;
}
- onSelectionUpdated(selectedList) {
- selectedList = [...selectedList];
- const highlighted = selectedList;
- if (this.props.folderSelectNotAllowed && !this.props.folderSelectable) {
- selectedList = selectedList.filter(nodeId => !this.getDataSourceNode(nodeId).t);
- }
- this.setState({
- 'selected': selectedList,
- highlighted
- });
- this.props.onSelected(selectedList);
- this.props.onHighlighted(highlighted);
- $.selected = highlighted;
+ if (typeof megaChat.userPresence === 'undefined') {
+ return;
}
- getEntries(newState) {
- const self = this;
- const sortBy = newState && newState.sortBy || self.state.sortBy;
- const order = sortBy[1] === "asc" ? 1 : -1;
- const entries = [];
- let sortFunc, filterFunc, dataSource;
- const minSearchLength = self.props.minSearchLength || 3;
- const showSen = mega.sensitives.showGlobally;
- if (self.props.currentlyViewedEntry === "search" && self.props.searchValue && self.props.searchValue.length >= minSearchLength) {
- dataSource = this.dataSource || {
- ...M.tnd,
- ...M.d
- };
- filterFunc = M.getFilterBySearchFn(self.props.searchValue);
- } else {
- const tmp = M.getChildren(self.props.currentlyViewedEntry) || M.tree[self.props.currentlyViewedEntry] || this.props.dataSource;
- dataSource = Object.create(null);
- for (const h in tmp) {
- const n = this.getDataSourceNode(h);
- if (n) {
- dataSource[h] = n;
- }
- }
- }
- const {
- customFilterFn
- } = this.props;
- for (const h in dataSource) {
- const n = dataSource[h];
- const e = n && (!n.h || n.h.length === 8 && crypto_keyok(n) || n.h.length === 11);
- const s = e && !n.fv && (showSen || !mega.sensitives.isSensitive(n));
- if (s && (!customFilterFn || customFilterFn(n)) && (!filterFunc || filterFunc(n))) {
- entries.push(n);
- }
- }
- if (sortBy[0] === "name") {
- sortFunc = M.getSortByNameFn();
- } else if (sortBy[0] === "size") {
- sortFunc = M.getSortBySizeFn();
- } else if (sortBy[0] === "ts") {
- sortFunc = M.getSortByDateTimeFn();
- } else if (sortBy[0] === "rts") {
- sortFunc = M.getSortByRtsFn();
- } else if (sortBy[0] === "status") {
- sortFunc = M.getSortByStatusFn();
- } else if (sortBy[0] === "interaction") {
- sortFunc = M.getSortByInteractionFn();
- } else if (sortBy[0] === "verification") {
- sortFunc = M.getSortByVerificationFn();
- } else if (sortBy[0] === "email") {
- sortFunc = M.getSortByEmail();
- } else if (sortBy[0] === 'access') {
- sortFunc = (a, b, o) => typeof a.r !== 'undefined' && typeof b.r !== 'undefined' && (a.r < b.r ? -1 : 1) * o;
- } else {
- sortFunc = M.sortByFavFn(order);
- }
- const folders = [];
- if (this.props.sortFoldersFirst) {
- for (let i = entries.length; i--;) {
- if (entries[i] && entries[i].t) {
- folders.unshift(entries[i]);
- entries.splice(i, 1);
- }
- }
- }
- folders.sort((a, b) => {
- return sortFunc(a, b, order);
- });
- entries.sort((a, b) => {
- return sortFunc(a, b, order);
- });
- return folders.concat(entries);
+ const $status = $('.activity-status-block .activity-status', 'body');
+ $('.top-user-status-popup .dropdown-item').removeClass("active");
+ $status.removeClass('online').removeClass('away').removeClass('busy').removeClass('offline').removeClass('black');
+ const actualPresence = self.plugins.presencedIntegration.getMyPresenceSetting();
+ const userPresenceConRetMan = megaChat.userPresence.connectionRetryManager;
+ const presence = self.plugins.presencedIntegration.getMyPresence();
+ let cssClass = PresencedIntegration.presenceToCssClass(presence);
+ if (userPresenceConRetMan.getConnectionState() !== ConnectionRetryManager.CONNECTION_STATE.CONNECTED) {
+ cssClass = "offline";
}
- onHighlighted(nodes) {
- this.setState({
- 'highlighted': nodes
- });
- if (this.props.onHighlighted) {
- this.props.onHighlighted(nodes);
- }
+ const $activityStatus = $('.activity-text', '.js-topbar');
+ if (actualPresence === UserPresence.PRESENCE.ONLINE) {
+ $('.top-user-status-popup .dropdown-item[data-presence="chat"]').addClass("active");
+ $activityStatus.text(l[5923]);
+ } else if (actualPresence === UserPresence.PRESENCE.AWAY) {
+ $('.top-user-status-popup .dropdown-item[data-presence="away"]').addClass("active");
+ $activityStatus.text(l[5924]);
+ } else if (actualPresence === UserPresence.PRESENCE.DND) {
+ $('.top-user-status-popup .dropdown-item[data-presence="dnd"]').addClass("active");
+ $activityStatus.text(l[5925]);
+ } else if (actualPresence === UserPresence.PRESENCE.OFFLINE) {
+ $('.top-user-status-popup .dropdown-item[data-presence="unavailable"]').addClass("active");
+ $activityStatus.text(l[5926]);
+ } else {
+ $('.top-user-status-popup .dropdown-item[data-presence="unavailable"]').addClass("active");
+ $activityStatus.text(l[5926]);
}
- finishedLoading(newState) {
- newState.isLoading = false;
- newState.entries = this.getEntries();
- this.initSelectionManager(newState.entries);
- this.setState(newState);
+ $status.addClass(cssClass);
+ if (userPresenceConRetMan.getConnectionState() === ConnectionRetryManager.CONNECTION_STATE.CONNECTING) {
+ $status.parent().addClass("fadeinout");
+ } else {
+ $status.parent().removeClass("fadeinout");
}
- addOrUpdRawListener() {
- if (this._rawListener) {
- mBroadcaster.removeListener(this._rawListener);
+};
+Chat.prototype.renderMyStatus = SoonFc(Chat.prototype._renderMyStatus, 100);
+Chat.prototype.openChat = function (userHandles, type, chatId, chatShard, chatdUrl, setAsActive, chatHandle, publicChatKey, ck, isMeeting, mcoFlags, organiser) {
+ const self = this;
+ let room = false;
+ type = type || "private";
+ setAsActive = setAsActive === true;
+ let roomId = chatId;
+ if (!publicChatKey && chatHandle && self.publicChatKeys[chatHandle]) {
+ if (type !== "public") {
+ console.error("this should never happen.", type);
+ type = "public";
}
- this._rawListener = mBroadcaster.addListener(`fmViewUpdate:${ this.props.currentlyViewedEntry}`, () => {
- this.setState({
- 'entries': this.getEntries()
- }, () => {
- if (this.browserEntries.isMounted()) {
- this.browserEntries.forceUpdate();
- }
- });
- });
+ publicChatKey = self.publicChatKeys[chatHandle];
}
- componentDidMount() {
- let _this$dataSource2;
- super.componentDidMount();
- if (!((_this$dataSource2 = this.dataSource) != null && _this$dataSource2.addChangeListener)) {
- this.addOrUpdRawListener();
- }
- if (this.props.fmConfigSortEnabled) {
- this._sortModeListener = mBroadcaster.addListener("fmconfig:sortmodes", sortModes => {
- this.onFmConfigSortModeChanged(sortModes);
- });
+ const $promise = new MegaPromise();
+ if (type === "private") {
+ this.initContacts(userHandles, 2);
+ roomId = userHandles.length > 1 ? array.one(userHandles, u_handle) : u_handle;
+ if (self.chats[roomId]) {
+ $promise.resolve(roomId, self.chats[roomId]);
+ return [roomId, self.chats[roomId], $promise];
}
+ } else {
+ assert(roomId, 'Tried to create a group chat, without passing the chatId.');
+ roomId = chatId;
}
- componentDidUpdate(prevProps) {
- const {
- currentlyViewedEntry: currEntry,
- searchValue: currSearch
- } = this.props;
- const {
- currentlyViewedEntry: prevEntry,
- searchValue: prevSearch
- } = prevProps;
- const dataSourceChanged = this.props.dataSource !== prevProps.dataSource;
- if (dataSourceChanged || prevEntry !== currEntry || currSearch !== prevSearch) {
- let _this$dataSource3;
- this.dataSource = this.props.dataSource;
- const newState = {
- 'selected': [],
- 'highlighted': []
- };
- if (!((_this$dataSource3 = this.dataSource) != null && _this$dataSource3.addChangeListener)) {
- this.addOrUpdRawListener();
- }
- const handle = currEntry;
- if (handle === 'shares') {
- newState.isLoading = true;
- this.setState(newState);
- dbfetch.geta(Object.keys(M.c.shares || {})).always(() => {
- this.finishedLoading(newState);
- });
- return;
+ if (type === "group" || type === "public") {
+ if (d) {
+ console.time(`openchat:${ chatId }.${ type}`);
+ }
+ const newUsers = this.initContacts(userHandles);
+ if (newUsers.length) {
+ const chats = self.chats._data;
+ if (d) {
+ console.debug('openchat:%s.%s: processing %s new users...', chatId, type, newUsers.length);
}
- if (this.getDataSourceNode(handle).t && !M.getChildren(handle)) {
- this.setState({
- 'isLoading': true
- });
- dbfetch.get(handle).always(() => {
- this.finishedLoading(newState);
- });
- return;
+ for (const k in chats) {
+ const chatRoom = self.chats[k];
+ const participants = array.to.object(chatRoom.getParticipantsExceptMe());
+ for (let j = newUsers.length; j--;) {
+ const u = newUsers[j];
+ if (participants[u]) {
+ chatRoom.trackDataChange();
+ break;
+ }
+ }
}
- const entries = this.getEntries();
- this.initSelectionManager(entries);
- this.setState({
- entries
- });
- }
- }
- onAttachClicked() {
- this.props.onAttachClicked();
- }
- onContextMenu() {}
- componentWillUnmount() {
- super.componentWillUnmount();
- if (this._listener) {
- let _this$dataSource4;
- (_this$dataSource4 = this.dataSource) == null || _this$dataSource4.removeChangeListener(this._listener);
+ self.renderMyStatus();
}
- if (this._rawListener) {
- mBroadcaster.removeListener(this._rawListener);
+ if (d) {
+ console.timeEnd(`openchat:${ chatId }.${ type}`);
}
- if (this._sortModeListener) {
- mBroadcaster.removeListener(this._sortModeListener);
+ if (type === "group") {
+ ChatdIntegration._ensureKeysAreLoaded([], userHandles, chatHandle).catch(dump);
}
- $.selected = [];
- this.selectionManager.destroy();
- this.selectionManager = undefined;
- $('.dropdown.body.files-menu.context').css('z-index', '');
+ ChatdIntegration._ensureContactExists(userHandles, chatHandle);
}
- onSortByChanged(newState) {
- if (newState[0] === this.state.sortBy[0] && newState[1] === this.state.sortBy[1]) {
- return;
+ if (self.chats[roomId]) {
+ room = self.chats[roomId];
+ if (setAsActive) {
+ room.show();
}
- const entries = this.getEntries({
- 'sortBy': newState
- });
- this.setState({
- 'sortBy': newState,
- entries,
- 'selected': [],
- 'highlighted': []
- }, () => {
- if (this.props.onSortByChanged) {
- this.props.onSortByChanged(newState);
- }
- if (this.props.fmConfigSortEnabled) {
- const sortId = this.props.fmConfigSortId;
- assert(sortId, 'fmConfigSortId missing');
- if (newState[0] === this.props.initialSortBy[0] && newState[1] === this.props.initialSortBy[1]) {
- const sortModes = typeof fmconfig.sortmodes !== 'undefined' ? fmconfig.sortmodes : Object.create(null);
- delete sortModes[sortId];
- mega.config.set('sortmodes', sortModes);
- return;
- }
- const map = this.props.fmConfigSortMap || Object.create(null);
- const name = map[newState[0]] || newState[0];
- const direction = newState[1] === "asc" ? 1 : -1;
- fmsortmode(sortId, name, direction);
- }
- });
- this.initSelectionManager(entries);
+ $promise.resolve(roomId, room);
+ return [roomId, room, $promise];
}
- onFmConfigSortModeChanged(sortModes) {
- const currentSortMode = sortModes[this.props.fmConfigSortId];
- if (!currentSortMode) {
- this.onSortByChanged(this.props.initialSortBy || ['name', 'asc']);
- } else {
- const newSortMode = this._translateFmConfigSortMode(currentSortMode);
- if (this.state.sortBy[0] !== newSortMode[0] || this.state.sortBy[1] !== newSortMode[1]) {
- this.onSortByChanged(newSortMode);
- }
- }
+ if (setAsActive && self.currentlyOpenedChat && self.currentlyOpenedChat !== roomId) {
+ self.hideChat(self.currentlyOpenedChat);
+ self.currentlyOpenedChat = null;
}
- render() {
- return REaCt().createElement("div", {
- ref: this.domRef,
- className: "content-container",
- onClick: ev => {
- $.hideContextMenu(ev);
- }
- }, REaCt().createElement(BrowserEntries, {
- isLoading: this.state.isLoading || this.props.nodeLoading,
- currentlyViewedEntry: this.props.currentlyViewedEntry,
- entries: this.state.entries || [],
- onExpand: node => {
- this.setState({
- 'selected': [],
- 'highlighted': []
- });
- this.props.onExpand(node[this.props.keyProp || 'h']);
- },
- sortBy: this.state.sortBy,
- folderSelectNotAllowed: this.props.folderSelectNotAllowed,
- onAttachClicked: this.onAttachClicked,
- viewMode: this.props.viewMode,
- selected: this.state.selected,
- highlighted: this.state.highlighted,
- onContextMenu: this.props.onContextMenu || this.onContextMenu,
- selectionManager: this.selectionManager,
- ref: browserEntries => {
- this.browserEntries = browserEntries;
- },
- onSortByChanged: newState => {
- this.onSortByChanged(newState);
- },
- listAdapterColumns: this.props.listAdapterColumns,
- currentdirid: this.props.currentdirid,
- containerClassName: this.props.containerClassName,
- headerContainerClassName: this.props.headerContainerClassName,
- megaListItemHeight: this.props.megaListItemHeight,
- keyProp: this.props.keyProp || 'h',
- NilComponent: this.props.NilComponent,
- listAdapterOpts: this.props.listAdapterOpts
- }));
+ room = new ChatRoom(self, roomId, type, userHandles, unixtime(), undefined, chatId, chatShard, chatdUrl, null, chatHandle, publicChatKey, ck, isMeeting, 0, mcoFlags, organiser);
+ self.chats.set(room.roomId, room);
+ if (setAsActive && !self.currentlyOpenedChat || self.currentlyOpenedChat === room.roomId) {
+ room.setActive();
}
-}
-
-},
-
-161
-(_, EXP_, REQ_) {
-
-"use strict";
-REQ_.d(EXP_, {
-$: () => ColumnFavIcon
-});
-const react0__ = REQ_(594);
-const react0 = REQ_.n(react0__);
-const _genericNodePropsComponent1__ = REQ_(984);
-
-
-class ColumnFavIcon extends _genericNodePropsComponent1__.B {
- render() {
- const {
- nodeAdapter
- } = this.props;
- const {
- node
- } = nodeAdapter.props;
- const isFavouritable = node.r === 2;
- return react0().createElement("td", {
- megatype: ColumnFavIcon.megatype,
- className: ColumnFavIcon.megatype
- }, react0().createElement("span", {
- className: `grid-status-icon sprite-fm-mono ${ missingkeys[node.h] ? " icon-info" : nodeAdapter.nodeProps.fav ? " icon-favourite-filled" : " icon-dot" }${!isFavouritable && " disabled" || ""}`,
- onClick: () => {
- if (isFavouritable) {
- M.favourite([node.h], !node.fav);
+ room.showAfterCreation = setAsActive !== false;
+ return [roomId, room, new Promise((resolve, reject) => {
+ this.trigger('onRoomInitialized', [room, resolve, reject]);
+ room.setState(ChatRoom.STATE.JOINING);
+ const q = this._queuedChatRoomEvents[chatId];
+ if (q) {
+ delete this._queuedChatRoomEvents[chatId];
+ for (let i = 0; i < q.length; ++i) {
+ const [event, data] = q[i];
+ if (d) {
+ this.logger.debug(`Dispatching deferred event '${event}'`, data);
}
+ room.trigger(event, data);
}
- }));
- }
-}
-ColumnFavIcon.sortable = true;
-ColumnFavIcon.id = "fav";
-ColumnFavIcon.label = "";
-ColumnFavIcon.icon = "icon-favourite-filled";
-ColumnFavIcon.megatype = "fav";
-ColumnFavIcon.headerClassName = "grid-first-th fav";
-
-},
-
-984
-(_, EXP_, REQ_) {
-
-"use strict";
-
-// EXPORTS
-REQ_.d(EXP_, {
- B: () => GenericNodePropsComponent
-});
-
-// EXTERNAL MODULE: ./js/chat/mixins.js
-const mixins = REQ_(137);
-;// ./js/ui/jsx/fm/nodes/nodeProperties.jsx
-class NodeProperties {
- static get(node, changeListener) {
- assert(node.h, 'missing handle for node');
- if (NodeProperties._globalCleanupTimer) {
- NodeProperties._globalCleanupTimer.abort();
- }
- (NodeProperties._globalCleanupTimer = tSleep(120)).then(() => {
- NodeProperties.cleanup(0);
- });
- let nodeProps;
- if (!NodeProperties._cache.has(node.h)) {
- nodeProps = new NodeProperties(node, changeListener);
- NodeProperties._cache.set(node.h, nodeProps);
+ q.timer.abort();
}
- return nodeProps || NodeProperties._cache.get(node.h);
+ this.processQueuedMcsmPackets();
+ })];
+};
+Chat.prototype.initContacts = function (userHandles, c) {
+ const newUsers = [];
+ for (let i = userHandles.length; i--;) {
+ const u = userHandles[i];
+ const e = u in M.u;
+ M.addUser(e ? {
+ u
+ } : {
+ u,
+ c
+ }, e || !newUsers.push(u));
}
- unuse(changeListener) {
- const {node} = this;
- if (!node) {
- if (d) {
- console.warn("This should not happen.");
- }
- return;
- }
- this.changeListeners.delete(changeListener);
- let usages = NodeProperties._usages.get(this);
- if (usages) {
- NodeProperties._usages.set(this, --usages);
- if (usages === 0 && NodeProperties._cache.size > NodeProperties.MAX_CACHE_SIZE) {
- delay('nodePropCleanup', NodeProperties.cleanup, 1000);
- }
- }
- }
- static cleanup(maxCacheSize) {
- maxCacheSize = typeof maxCacheSize === "undefined" ? NodeProperties.MAX_CACHE_SIZE : maxCacheSize;
- const len = NodeProperties._cache.size;
- let removed = 0;
- for (const entry of NodeProperties._cache) {
- const id = entry[0];
- const node = entry[1];
- const usage = NodeProperties._usages.get(node);
- if (usage === 0) {
- NodeProperties._usages.delete(node);
- node._cleanup();
- NodeProperties._cache.delete(id);
- removed++;
- if (len - removed < maxCacheSize) {
- return;
- }
- }
+ return newUsers;
+};
+Chat.prototype.smartOpenChat = function (...args) {
+ const self = this;
+ if (typeof args[0] === 'string') {
+ args[0] = [u_handle, args[0]];
+ if (args.length < 2) {
+ args.push('private');
}
}
- constructor(node, changeListener) {
- this.node = node;
- this.changeListeners = new Set();
- if (changeListener) {
- this.changeListeners.add(changeListener);
- }
- const _onChange = () => {
- this.initProps();
- for (const listener of this.changeListeners) {
- listener();
+ return new Promise((resolve, reject) => {
+ const waitForReadyState = function (aRoom, aShow) {
+ const verify = function () {
+ return aRoom.state === ChatRoom.STATE.READY;
+ };
+ const ready = function () {
+ if (aShow) {
+ aRoom.show();
+ }
+ resolve(aRoom);
+ };
+ if (verify()) {
+ return ready();
}
+ const {
+ roomId
+ } = aRoom;
+ createTimeoutPromise(verify, 300, 3e4, false, `waitForReadyState(${roomId})`).then(ready).catch(reject);
};
- if (this.node.addChangeListener) {
- this._listener = this.node.addChangeListener(_onChange);
- } else {
- this._mbListener = mBroadcaster.addListener(`nodeUpdated:${ node.h}`, _onChange);
- }
- this.initProps();
- }
- use(changeListener) {
- if (changeListener) {
- this.changeListeners.add(changeListener);
- }
- NodeProperties._usages.set(this, (NodeProperties._usages.get(this) | 0) + 1);
- }
- _cleanup() {
- if (this._listener) {
- this.node.removeChangeListener(this._listener);
- }
- if (this._mbListener) {
- mBroadcaster.removeListener(this._mbListener);
- }
- oDestroy(this);
- }
- initProps() {
- const {node} = this;
- lazy(this, 'title', () => {
- if (missingkeys[node.h]) {
- return node.t ? l[8686] : l[8687];
- }
- return M.getNameByHandle(node.h);
- });
- lazy(this, 'classNames', () => {
- const classNames = [];
- if (node.su) {
- classNames.push('inbound-share');
- }
- if (node.t) {
- classNames.push('folder');
- } else {
- classNames.push('file');
- }
- const share = this.shareData;
- if (missingkeys[node.h] || share.down) {
- if (share.down) {
- classNames.push('taken-down');
- }
- if (missingkeys[node.h]) {
- classNames.push('undecryptable');
+ const [members, type] = args;
+ if (members.length === 2 && type === 'private') {
+ const chatRoom = self.chats[members.every(h => h === members[0]) ? u_handle : array.one(members, u_handle)];
+ if (chatRoom) {
+ if (args[5]) {
+ chatRoom.show();
}
+ return waitForReadyState(chatRoom, args[5]);
}
- if (share) {
- classNames.push('linked');
- }
- if (node.lbl && !folderlink) {
- const colourLabel = M.getLabelClassFromId(node.lbl);
- classNames.push('colour-label');
- classNames.push(colourLabel);
- }
- return classNames;
- });
- lazy(this, 'icon', () => {
- return fileIcon(node);
- });
- lazy(this, 'isFolder', () => {
- return !!node.t;
- });
- lazy(this, 'shareData', () => {
- return M.getNodeShare(node);
- });
- lazy(this, 'isTakendown', () => {
- return this.shareData && !!this.shareData.down;
- });
- lazy(this, 'fav', () => {
- return !!node.fav;
- });
- lazy(this, 'size', () => {
- return bytesToSize(node.tb || node.s);
- });
- lazy(this, 'timestamp', () => {
- return time2date(node.ts);
- });
- lazy(this, 'root', () => {
- return M.getNodeRoot(node.h);
- });
- lazy(this, 'incomingShareData', () => {
- const result = {};
- if (node.r === 1) {
- result.accessLabel = l[56];
- result.accessIcon = 'icon-permissions-write';
- } else if (node.r === 2) {
- result.accessLabel = l[57];
- result.accessIcon = 'icon-star';
- } else {
- result.accessLabel = l[55];
- result.accessIcon = 'icon-read-only';
+ }
+ const result = self.openChat.apply(self, args);
+ if (result instanceof MegaPromise) {
+ result.then(reject).catch(reject);
+ } else if (!Array.isArray(result)) {
+ reject(EINTERNAL);
+ } else {
+ const room = result[1];
+ const roomId = result[0];
+ const promise = result[2];
+ if (!(promise instanceof Promise)) {
+ self.logger.error('Unexpected openChat() response...');
+ return reject(EINTERNAL);
}
- return result;
- });
- lazy(this, 'timestamp', () => {
- return time2date(node.ts);
- });
- lazy(this, 'onlineStatus', () => {
- return M.onlineStatusClass(node.presence ? node.presence : "unavailable");
- });
- }
-}
-NodeProperties._cache = new Map();
-NodeProperties._usages = new WeakMap();
-NodeProperties._globalCleanupTimer = void 0;
-NodeProperties.MAX_CACHE_SIZE = 100;
-if (d) {
- window.NodeProperties = NodeProperties;
-}
-;// ./js/ui/jsx/fm/nodes/genericNodePropsComponent.jsx
-
-
-class GenericNodePropsComponent extends mixins.w9 {
- constructor(props) {
- super(props);
- if (this.props.node.h) {
- this.nodeProps = NodeProperties.get(this.props.node);
- this.changeListener = this.changeListener.bind(this);
+ self.logger.debug('Waiting for chat "%s" to be ready...', roomId, [room]);
+ promise.then(aRoom => {
+ const aRoomId = aRoom && aRoom.roomId;
+ if (aRoomId !== roomId || room && room !== aRoom || !(aRoom instanceof ChatRoom)) {
+ self.logger.error('Unexpected openChat() procedure...', aRoomId, [aRoom]);
+ return reject(EINTERNAL);
+ }
+ waitForReadyState(aRoom);
+ }).catch(ex => {
+ if (ex === EACCESS) {
+ room.destroy();
+ }
+ reject(ex);
+ });
}
- }
- changeListener() {
- if (this.isMounted()) {
- this.safeForceUpdate();
+ });
+};
+Chat.prototype.hideAllChats = function () {
+ const self = this;
+ self.chats.forEach(chatRoom => {
+ if (chatRoom.isCurrentlyActive) {
+ chatRoom.hide();
}
+ });
+};
+Chat.prototype.retrieveSharedFilesHistory = async function (len = 47, chatRoom = null) {
+ chatRoom = len instanceof ChatRoom ? len : chatRoom || this.getCurrentRoom();
+ return chatRoom.messagesBuff.retrieveSharedFilesHistory(len);
+};
+Chat.prototype.getCurrentRoom = function () {
+ return this.chats[this.currentlyOpenedChat];
+};
+Chat.prototype.getCurrentMeeting = function () {
+ const chatRoom = this.getCurrentRoom();
+ return chatRoom && chatRoom.scheduledMeeting || null;
+};
+Chat.prototype.getCurrentRoomJid = function () {
+ return this.currentlyOpenedChat;
+};
+Chat.prototype.hideChat = function (roomJid) {
+ const self = this;
+ const room = self.chats[roomJid];
+ if (room) {
+ room.hide();
+ } else {
+ self.logger.warn("Room not found: ", roomJid);
+ }
+};
+Chat.prototype.sendMessage = function (roomJid, val) {
+ const fail = ex => {
+ this.logger.error(`sendMessage(${roomJid}) failed.`, ex);
+ };
+ if (!this.chats[roomJid]) {
+ this.logger.warn("Queueing message for room: ", roomJid, val);
+ const timeout = this.options.delaySendMessageIfRoomNotAvailableTimeout;
+ return createTimeoutPromise(() => !!this.chats[roomJid], 500, timeout).then(() => {
+ return this.chats[roomJid].sendMessage(val);
+ }).catch(fail);
}
- UNSAFE_componentWillReceiveProps(nextProps) {
- if (nextProps.highlighted !== this.props.highlighted) {
- this.safeForceUpdate();
+ return this.chats[roomJid].sendMessage(val).catch(fail);
+};
+Chat.prototype.processNewUser = function (u, isNewChat) {
+ const self = this;
+ if (self.plugins.presencedIntegration) {
+ const user = M.u[u] || false;
+ if (user.c === 1) {
+ self.plugins.presencedIntegration.addContact(u, isNewChat);
}
}
- UNSAFE_componentWillMount() {
- let _this$nodeProps;
- if (super.UNSAFE_componentWillMount) {
- super.UNSAFE_componentWillMount();
+ self.chats.forEach((chatRoom) => {
+ if (chatRoom.getParticipantsExceptMe().indexOf(u) > -1) {
+ chatRoom.trackDataChange();
}
- (_this$nodeProps = this.nodeProps) == null || _this$nodeProps.use(this.changeListener);
+ });
+ self.renderMyStatus();
+};
+Chat.prototype.processRemovedUser = function (u) {
+ const self = this;
+ if (self.plugins.presencedIntegration) {
+ self.plugins.presencedIntegration.removeContact(u);
}
- componentWillUnmount() {
- let _this$nodeProps2;
- super.componentWillUnmount();
- (_this$nodeProps2 = this.nodeProps) == null || _this$nodeProps2.unuse(this.changeListener);
+ self.chats.forEach((chatRoom) => {
+ if (chatRoom.getParticipantsExceptMe().indexOf(u) > -1) {
+ chatRoom.trackDataChange();
+ }
+ });
+ self.renderMyStatus();
+};
+Chat.prototype.refreshConversations = function () {
+ const self = this;
+ if (!u_type && !self.$container && !megaChatIsReady) {
+ $('.fm-chat-block').hide();
+ return false;
}
-}
-
-},
-
-818
-(_, EXP_, REQ_) {
-
-"use strict";
-REQ_.d(EXP_, {
-A: () => __WEBPACK_DEFAULT_EXPORT__
-});
-const react0__ = REQ_(594);
-const react0 = REQ_.n(react0__);
-const _chat_mixins1__ = REQ_(137);
-
-
-class ToggleCheckbox extends _chat_mixins1__.w9 {
- constructor(props) {
- super(props);
- this.domRef = react0().createRef();
- this.onToggle = () => {
- const newState = !this.state.value;
- this.setState({
- value: newState
- });
- if (this.props.onToggle) {
- this.props.onToggle(newState);
- }
- };
- this.state = {
- value: this.props.value
- };
+ $('.section.conversations .fm-chat-is-loading').addClass('hidden');
+ if (self.$container.parent('.section.conversations .fm-right-files-block').length == 0) {
+ $('.section.conversations .fm-right-files-block').append(self.$container);
}
- render() {
- return react0().createElement("div", {
- ref: this.domRef,
- className: `
- mega-switch
- ${this.props.className}
- ${this.state.value ? 'toggle-on' : ''}
- `,
- role: "switch",
- "aria-checked": !!this.state.value,
- onClick: this.onToggle
- }, react0().createElement("div", {
- className: `mega-feature-switch sprite-fm-mono-after
- ${this.state.value ? 'icon-check-after' : 'icon-minimise-after'}`
- }));
+ self.$leftPane = self.$leftPane || $('.conversationsApp .fm-left-panel');
+ if (is_chatlink || megaChat._joinDialogIsShown) {
+ self.$leftPane.addClass('hidden');
+ } else {
+ self.$leftPane.removeClass('hidden');
}
-}
-const __WEBPACK_DEFAULT_EXPORT__ = {
- ToggleCheckbox
};
-
-},
-
-318
-(_, EXP_, REQ_) {
-
-"use strict";
-
-// EXPORTS
-REQ_.d(EXP_, {
- A: () => modalDialogs
-});
-
-// UNUSED EXPORTS: ExtraFooterElement
-
-// EXTERNAL MODULE: ./js/ui/utils.jsx
-const utils = REQ_(314);
-// EXTERNAL MODULE: ./js/chat/mixins.js
-const mixins = REQ_(137);
-;// ./js/ui/forms.jsx
-const React = REQ_(594);
-
-class Checkbox extends mixins.w9 {
- constructor(props) {
- super(props);
- this.domRef = React.createRef();
- this.state = {
- checked: this.props.checked ? this.props.checked : false
- };
- this.onLabelClick = this.onLabelClick.bind(this);
- this.onChange = this.onChange.bind(this);
- }
- onLabelClick(e) {
- const state = !this.state.checked;
- this.setState({
- 'checked': state
- });
- if (this.props.onLabelClick) {
- this.props.onLabelClick(e, state);
+Chat.prototype.navigate = function megaChatNavigate(location, event, isLandingPage) {
+ return new Promise((resolve, reject) => {
+ this.routing.route(resolve, reject, location, event, isLandingPage);
+ });
+};
+if (is_mobile) {
+ Chat.prototype.navigate = function (location, event, isLandingPage) {
+ if (d) {
+ this.logger.warn('mobile-nop navigate(%s)', location, event, isLandingPage);
}
- this.onChange(e);
- }
- onChange(e) {
- if (this.props.onChange) {
- this.props.onChange(e, this.state.checked);
+ if (is_chatlink) {
+ mobile.chatlink.show(is_chatlink.ph, is_chatlink.key);
+ } else {
+ loadSubPage('fm', event);
}
- }
- render() {
- const {
- name,
- id,
- children
- } = this.props;
- const className = this.state.checked ? 'checkboxOn' : 'checkboxOff';
- return React.createElement("div", {
- ref: this.domRef,
- className: "formsCheckbox"
- }, React.createElement("div", {
- className: `
- checkdiv
- ${className}
- `,
- onClick: this.onLabelClick
- }, React.createElement("input", {
- type: "checkbox",
- name,
- id,
- className,
- checked: this.state.checked,
- onChange: this.onChange
- })), React.createElement("label", {
- htmlFor: id,
- className: "radio-txt"
- }, children));
- }
+ return Promise.resolve();
+ };
}
-const ui_forms = {
- Checkbox
-};
-;// ./js/ui/modalDialogs.jsx
-const modalDialogs_React = REQ_(594);
-
-
-
-const ContactsUI = REQ_(251);
-class ExtraFooterElement extends modalDialogs_React.Component {
- render() {
- return this.props.children;
+Chat.prototype.renderListing = async function megaChatRenderListing(location, isInitial) {
+ if (!isInitial && !M.chat) {
+ console.debug('renderListing: Not in chat.');
+ throw EACCESS;
}
-}
-class SafeShowDialogController extends mixins.w9 {
- constructor(props) {
- super(props);
- this.dialogName = 'unnamed-dialog';
- this.dialogBecameVisible = null;
- const {
- render
- } = this;
- this.render = () => {
- if (this.dialogBecameVisible) {
- console.assert($.dialog === this.dialogName, `${this.dialogName} state overridden.`);
- return render.call(this);
- }
- return null;
- };
+ M.hideEmptyGrids();
+ this.refreshConversations();
+ this.hideAllChats();
+ if (!is_chatlink && mega.ui.flyout && (mega.ui.flyout.name.startsWith('contact') || mega.ui.flyout.name === 'chat')) {
+ mega.ui.flyout.hide();
}
- shouldComponentUpdate(nextProps, nextState) {
- if (!this.dialogBecameVisible) {
- return false;
+ $('.files-grid-view').addClass('hidden');
+ $('.fm-blocks-view').addClass('hidden');
+ $('.fm-chat-block').addClass('hidden');
+ $('.fm-right-files-block').addClass('hidden');
+ $('.fm-right-files-block.in-chat').removeClass('hidden');
+ $('.nw-conversations-item').removeClass('selected');
+ $('.fm-empty-conversations').removeClass('hidden');
+ M.onSectionUIOpen('conversations');
+ let room;
+ if (!location && this.chats.length) {
+ const valid = room => room && room._leaving !== true && !room.isNote && room.isDisplayable() && room;
+ room = valid(this.chats[this.lastOpenedChat]);
+ if (!room) {
+ let idx = 0;
+ const rooms = Object.values(this.chats).filter(r => this.currentlyOpenedView === null || r.isMeeting === !!this.currentlyOpenedView).sort(M.sortObjFn('lastActivity', -1));
+ do {
+ room = valid(rooms[idx]);
+ } while (!room && ++idx < rooms.length);
+ }
+ if (room) {
+ location = room.getRoomUrl();
}
- return super.shouldComponentUpdate(nextProps, nextState);
}
- componentDidMount() {
- super.componentDidMount();
- M.safeShowDialog(this.dialogName, () => {
- if (!this.isMounted()) {
- throw new Error(`${this.dialogName} component is no longer mounted.`);
+ if (location) {
+ $('.fm-empty-conversations').addClass('hidden');
+ return this.navigate(location, undefined, isInitial).catch(ex => {
+ if (d) {
+ this.logger.warn('Failed to navigate to %s...', location, room, ex);
}
- this.dialogBecameVisible = 1;
- this.forceUpdate();
- });
- }
- componentWillUnmount() {
- super.componentWillUnmount();
- if (this.dialogBecameVisible) {
- this.dialogBecameVisible = false;
- console.assert($.dialog === this.dialogName);
- if ($.dialog === this.dialogName) {
- closeDialog();
+ if (!room) {
+ return this.renderListing(null);
}
- }
- }
- componentDidUpdate() {
- assert(this.dialogBecameVisible);
- super.componentDidUpdate();
- if (++this.dialogBecameVisible === 2) {
- requestAnimationFrame(() => {
- const dialog = document.querySelectorAll(`.${this.dialogName}`);
- console.assert(dialog.length === 1, `Unexpected ${this.dialogName} state.`);
- console.assert($.dialog === this.dialogName, `${this.dialogName} state overridden.`);
- if (dialog.length === 1 && $.dialog === this.dialogName) {
- dialog[0].classList.remove('hidden', 'arrange-to-back');
- }
+ onIdle(() => {
+ room.destroy();
});
- }
- }
-}
-class ModalDialog extends mixins.w9 {
- constructor(props) {
- super(props);
- this.domRef = modalDialogs_React.createRef();
- this.onBlur = this.onBlur.bind(this);
- this.onCloseClicked = this.onCloseClicked.bind(this);
- this.onPopupDidMount = this.onPopupDidMount.bind(this);
+ throw ex;
+ });
}
- componentDidMount() {
- super.componentDidMount();
- if (!this.props.hideOverlay) {
- $(document.body).addClass('overlayed');
- $('.fm-dialog-overlay').removeClass('hidden');
+ return ENOENT;
+};
+Chat.prototype.setAttachments = function (roomId) {
+ 'use strict';
+
+ if (M.chat) {
+ if (d) {
+ console.assert(this.chats[roomId] && this.chats[roomId].isCurrentlyActive, 'check this...');
}
- $('textarea:focus').trigger("blur");
- if (!this.props.noCloseOnClickOutside) {
- const convApp = document.querySelector('.conversationsApp');
- if (convApp) {
- convApp.removeEventListener('click', this.onBlur);
- convApp.addEventListener('click', this.onBlur);
- }
- $('.fm-modal-dialog').rebind(`click.modalDialogOv${ this.getUniqueId()}`, ({
- target
- }) => {
- if ($(target).is('.fm-modal-dialog')) {
- this.onBlur();
+ M.v = Object.values(M.chc[roomId] || {});
+ if (M.v.length) {
+ let _this$chats$roomId;
+ const sv = (_this$chats$roomId = this.chats[roomId]) == null || (_this$chats$roomId = _this$chats$roomId.messagesBuff) == null || (_this$chats$roomId = _this$chats$roomId.sharedFiles) == null ? void 0 : _this$chats$roomId._sortedVals;
+ if (sv && sv.length === M.v.length) {
+ M.v.sort((a, b) => sv.indexOf(a.m) - sv.indexOf(b.m));
+ } else {
+ if (d) {
+ this.logger.info('falling back to order-value sorting.', sv);
}
- });
- $('.fm-dialog-overlay').rebind(`click.modalDialog${ this.getUniqueId()}`, () => {
- if (this.props.closeDlgOnClickOverlay) {
- this.onBlur();
+ M.v.sort(M.sortObjFn('co'));
+ }
+ for (let i = M.v.length; i--;) {
+ const n = M.v[i];
+ if (!n.revoked && !n.seen) {
+ n.seen = -1;
+ if (this._shallLoadImageFor(n)) {
+ this._enqueueImageLoad(n);
+ }
}
- return false;
- });
- }
- $(document).rebind(`keyup.modalDialog${ this.getUniqueId()}`, ({
- keyCode
- }) => {
- if (!this.props.stopKeyPropagation && keyCode === 27) {
- this.onBlur();
}
- });
+ if ($.triggerSlideShow) {
+ delay('chat:refresh-slideshow-on-single-entry', () => {
+ const {
+ slideshowid: id
+ } = window;
+ if (id && $.triggerSlideShow === id) {
+ slideshow(id);
+ }
+ delete $.triggerSlideShow;
+ });
+ }
+ }
+ } else if (d) {
+ console.warn('Not in chat...');
}
- onBlur(e) {
- let _this$domRef;
- const $element = $((_this$domRef = this.domRef) == null ? void 0 : _this$domRef.current);
- if (!e || !$(e.target).closest('.mega-dialog').is($element)) {
- const convApp = document.querySelector('.conversationsApp');
- if (convApp) {
- convApp.removeEventListener('click', this.onBlur);
+};
+Chat.prototype._enqueueMessageUpdate = function (message) {
+ this._queuedMessageUpdates.push(message);
+ delay('chat:enqueue-message-updates', () => {
+ const queue = this._queuedMessageUpdates;
+ this._queuedMessageUpdates = [];
+ for (let i = queue.length; i--;) {
+ queue[i].trackDataChange();
+ }
+ }, 400);
+};
+Chat.prototype._shallLoadImageFor = function (n) {
+ return n && /:[01]\*/.test(n.fa);
+};
+Chat.prototype._enqueueImageLoad = function (n) {
+ 'use strict';
+ let cc = previews[n.h] || previews[n.hash];
+ if (cc) {
+ if (cc.poster) {
+ n.src = cc.poster;
+ } else {
+ if (cc.full && n.mime !== 'image/png' && n.mime !== 'image/webp') {
+ cc = cc.prev || false;
+ }
+ if (String(cc.type).startsWith('image/')) {
+ n.src = cc.src;
}
- this.onCloseClicked();
}
}
- componentWillUnmount() {
- let _this$props$popupWill, _this$props;
- super.componentWillUnmount();
- if (!this.props.noCloseOnClickOutside) {
- const convApp = document.querySelector('.conversationsApp');
- if (convApp) {
- convApp.removeEventListener('click', this.onBlur);
+ let cached = n.src;
+ if (this._shallLoadImageFor(n)) {
+ let load = false;
+ let dedup = true;
+ if (this._imageAttributeCache[n.fa]) {
+ this._imageAttributeCache[n.fa].push(n.ch);
+ } else {
+ this._imageAttributeCache[n.fa] = [n.ch];
+ load = !cached;
+ }
+ if (this._imageLoadCache[n.fa]) {
+ this._imageLoadCache[n.fa].push(n.ch);
+ } else {
+ this._imageLoadCache[n.fa] = [n.ch];
+ if (load) {
+ this._imagesToBeLoaded[n.fa] = n;
+ dedup = false;
}
- $('.fm-dialog-overlay').off(`click.modalDialog${ this.getUniqueId()}`);
}
- if (!this.props.hideOverlay) {
- $(document.body).removeClass('overlayed');
- $('.fm-dialog-overlay').addClass('hidden');
+ if (dedup) {
+ cached = true;
+ } else {
+ delay('chat:enqueue-image-load', this._doLoadImages.bind(this), 350);
}
- $(this.domNode).off(`dialog-closed.modalDialog${ this.getUniqueId()}`);
- $(document).off(`keyup.modalDialog${ this.getUniqueId()}`);
- (_this$props$popupWill = (_this$props = this.props).popupWillUnmount) == null || _this$props$popupWill.call(_this$props);
}
- onCloseClicked() {
- const self = this;
- if (self.props.onClose) {
- self.props.onClose(self);
- }
+ if (cached) {
+ this._doneLoadingImage(n.fa);
}
- onPopupDidMount(elem) {
- this.domNode = elem;
- $(elem).rebind(`dialog-closed.modalDialog${ this.getUniqueId()}`, () => this.onCloseClicked());
- if (this.props.popupDidMount) {
- this.props.popupDidMount(elem);
+};
+Chat.prototype._doLoadImages = function () {
+ "use strict";
+
+ const self = this;
+ const originals = Object.create(null);
+ let imagesToBeLoaded = self._imagesToBeLoaded;
+ self._imagesToBeLoaded = Object.create(null);
+ const chatImageParser = function (h, data) {
+ const n = M.chd[(self._imageLoadCache[h] || [])[0]] || false;
+ if (n && data !== 0xDEAD) {
+ n.src = mObjectURL([data.buffer || data], 'image/jpeg');
+ n.srcBuffer = data;
+ } else if (d) {
+ console.warn('Failed to load image for %s', h, n);
+ }
+ self._doneLoadingImage(h);
+ };
+ for (const k in imagesToBeLoaded) {
+ const node = imagesToBeLoaded[k];
+ const mime = filemime(node);
+ if (node.s < LOAD_ORIGINALS[mime]) {
+ originals[node.fa] = node;
+ delete imagesToBeLoaded[k];
}
}
- render() {
- const self = this;
- let classes = 'mega-dialog';
- let selectedNumEle = null;
- let footer = null;
- const extraFooterElements = [];
- const otherElements = [];
- let x = 0;
- modalDialogs_React.Children.forEach(self.props.children, (child) => {
- if (!child) {
- return;
- }
- if (child.type.name === 'ExtraFooterElement') {
- extraFooterElements.push(modalDialogs_React.cloneElement(child, {
- key: x++
- }));
+ const onSuccess = function (ctx, origNodeHandle, data) {
+ chatImageParser(origNodeHandle, data);
+ };
+ const onError = function (origNodeHandle) {
+ chatImageParser(origNodeHandle, 0xDEAD);
+ };
+ const loadOriginal = function (n) {
+ const origFallback = ex => {
+ const type = String(n.fa).indexOf(':1*') > 0 ? 1 : 0;
+ if (d) {
+ console.debug('Failed to load original image on chat.', n.h, n, ex);
+ }
+ imagesToBeLoaded[n.fa] = originals[n.fa];
+ delete originals[n.fa];
+ delay(`ChatRoom[${ self.roomId }]:origFallback${ type}`, () => {
+ api_getfileattr(imagesToBeLoaded, type, onSuccess, onError);
+ });
+ };
+ M.gfsfetch(n.h, 0, -1).then((data) => {
+ const handler = is_image(n);
+ if (typeof handler === 'function') {
+ handler(data, buffer => {
+ if (buffer) {
+ chatImageParser(n.fa, buffer);
+ } else {
+ origFallback(EFAILED);
+ }
+ });
} else {
- otherElements.push(modalDialogs_React.cloneElement(child, {
- key: x++
- }));
+ chatImageParser(n.fa, data);
}
+ }).catch(origFallback);
+ };
+ if ($.len(originals)) {
+ Object.values(originals).map(loadOriginal);
+ }
+ api_getfileattr(imagesToBeLoaded, 1, onSuccess, onError);
+ [imagesToBeLoaded, originals].forEach((obj) => {
+ Object.keys(obj).forEach((handle) => {
+ self._startedLoadingImage(handle);
});
- if (self.props.className) {
- classes += ` ${self.props.className}`;
- }
- if (self.props.dialogType) {
- classes += ` dialog-template-${self.props.dialogType}`;
- }
- if (self.props.dialogName) {
- classes += ` ${self.props.dialogName}`;
+ });
+ imagesToBeLoaded = Object.create(null);
+};
+Chat.prototype._getImageNodes = function (h, src) {
+ let nodes = this._imageLoadCache[h] || [];
+ let handles = [].concat(nodes);
+ for (let i = nodes.length; i--;) {
+ const n = M.chd[nodes[i]] || false;
+ if (this._imageAttributeCache[n.fa]) {
+ handles = handles.concat(this._imageAttributeCache[n.fa]);
}
- if (self.props.showSelectedNum && self.props.selectedNum) {
- selectedNumEle = modalDialogs_React.createElement("div", {
- className: "selected-num"
- }, modalDialogs_React.createElement("span", null, self.props.selectedNum));
+ }
+ handles = array.unique(handles);
+ nodes = handles.map((ch) => {
+ const n = M.chd[ch] || false;
+ if (src && n.src) {
+ Object.assign(src, n);
}
- let buttons;
- if (self.props.buttons) {
- buttons = [];
- self.props.buttons.forEach((v, i) => {
- if (v) {
- buttons.push(modalDialogs_React.createElement("button", {
- className: (v.defaultClassname ? v.defaultClassname : "mega-button") + (v.className ? ` ${ v.className}` : "") + (self.props.dialogType === "action" ? "large" : ""),
- onClick: e => {
- if ($(e.target).is(".disabled")) {
- return false;
- }
- if (v.onClick) {
- v.onClick(e, self);
- }
- },
- key: v.key + i
- }, v.iconBefore ? modalDialogs_React.createElement("div", null, modalDialogs_React.createElement("i", {
- className: v.iconBefore
- })) : null, modalDialogs_React.createElement("span", null, v.label), v.iconAfter ? modalDialogs_React.createElement("div", null, modalDialogs_React.createElement("i", {
- className: v.iconAfter
- })) : null));
- }
- });
- if (buttons && buttons.length > 0 || extraFooterElements && extraFooterElements.length > 0) {
- footer = modalDialogs_React.createElement("footer", null, buttons && buttons.length > 0 ? modalDialogs_React.createElement("div", {
- className: "footer-container"
- }, buttons) : null, extraFooterElements && extraFooterElements.length > 0 ? modalDialogs_React.createElement("aside", null, extraFooterElements) : null);
+ return n;
+ });
+ return nodes;
+};
+Chat.prototype._startedLoadingImage = function (h) {
+ "use strict";
+
+ const nodes = this._getImageNodes(h);
+ for (let i = nodes.length; i--;) {
+ const n = nodes[i];
+ if (!n.src && n.seen !== 2) {
+ let imgNode = document.getElementById(n.ch);
+ if (imgNode && (imgNode = imgNode.querySelector('img'))) {
+ imgNode.parentNode.parentNode.classList.add('thumb-loading');
}
}
- return modalDialogs_React.createElement(utils.Ay.RenderTo, {
- element: document.body,
- className: "fm-modal-dialog",
- popupDidMount: this.onPopupDidMount
- }, modalDialogs_React.createElement("div", {
- ref: this.domRef,
- id: self.props.id,
- className: classes,
- "aria-labelledby": self.props.dialogName ? `${self.props.dialogName }-title` : null,
- role: "dialog",
- "aria-modal": "true",
- onClick: self.props.onClick
- }, modalDialogs_React.createElement("button", {
- className: "close",
- onClick: self.onCloseClicked
- }, modalDialogs_React.createElement("i", {
- className: "sprite-fm-mono icon-dialog-close"
- })), self.props.title ? self.props.dialogType === "message" ? modalDialogs_React.createElement("header", null, self.props.icon ? modalDialogs_React.createElement("i", {
- className: `graphic ${self.props.icon}`
- }) : self.props.iconElement, modalDialogs_React.createElement("div", null, modalDialogs_React.createElement("h3", {
- id: self.props.dialogName ? `${self.props.dialogName }-title` : null
- }, self.props.title, selectedNumEle), self.props.subtitle ? modalDialogs_React.createElement("p", null, self.props.subtitle) : null, otherElements)) : modalDialogs_React.createElement("header", null, self.props.icon ? modalDialogs_React.createElement("i", {
- className: `graphic ${self.props.icon}`
- }) : self.props.iconElement, modalDialogs_React.createElement("h2", {
- id: self.props.dialogName ? `${self.props.dialogName }-title` : null
- }, self.props.title, selectedNumEle), self.props.subtitle ? modalDialogs_React.createElement("p", null, self.props.subtitle) : null) : null, self.props.dialogType !== "message" ? otherElements : null, buttons || extraFooterElements ? footer : null));
}
-}
-ModalDialog.defaultProps = {
- 'hideable': true,
- 'noCloseOnClickOutside': false,
- 'closeDlgOnClickOverlay': true,
- 'showSelectedNum': false,
- 'selectedNum': 0
};
-class SelectContactDialog extends mixins.w9 {
- constructor(props) {
- super(props);
- this.dialogName = 'send-contact-dialog';
- this.state = {
- selected: []
+Chat.prototype._doneLoadingImage = function (h) {
+ const self = this;
+ const setSource = function (n, img, src) {
+ const message = n.mo;
+ img.onload = function () {
+ img.onload = null;
+ n.srcWidth = this.naturalWidth;
+ n.srcHeight = this.naturalHeight;
+ if (message) {
+ self._enqueueMessageUpdate(message);
+ }
};
- this.state.selected = this.props.selected || [];
- this.onSelected = this.onSelected.bind(this);
- }
- onSelected(nodes) {
- let _this$props$onSelecte, _this$props2;
- this.setState({
- selected: nodes
- });
- (_this$props$onSelecte = (_this$props2 = this.props).onSelected) == null || _this$props$onSelecte.call(_this$props2, nodes);
- }
- componentDidMount() {
- super.componentDidMount();
- M.safeShowDialog(this.dialogName, () => $(`.${this.dialogName}`));
- }
- componentWillUnmount() {
- super.componentWillUnmount();
- if ($.dialog === this.dialogName) {
- closeDialog();
+ img.setAttribute('src', src);
+ };
+ const root = {};
+ const nodes = this._getImageNodes(h, root);
+ const {src} = root;
+ for (let i = nodes.length; i--;) {
+ const n = nodes[i];
+ let imgNode = document.getElementById(n.ch);
+ if (imgNode && (imgNode = imgNode.querySelector('img'))) {
+ const parent = imgNode.parentNode;
+ const container = parent.parentNode;
+ if (src) {
+ container.classList.add('thumb');
+ parent.classList.remove('no-thumb');
+ } else {
+ container.classList.add('thumb-failed');
+ }
+ n.seen = 2;
+ container.classList.remove('thumb-loading');
+ setSource(n, imgNode, src || window.noThumbURI || '');
}
+ if (src) {
+ n.src = src;
+ if (root.srcBuffer && root.srcBuffer.byteLength) {
+ n.srcBuffer = root.srcBuffer;
+ }
+ if (n.srcBuffer && !previews[n.h] && is_image3(n)) {
+ preqs[n.h] = 1;
+ previewimg(n.h, n.srcBuffer, 'image/jpeg');
+ previews[n.h].fromChat = Date.now();
+ }
+ }
+ delete n.mo;
}
- render() {
- return modalDialogs_React.createElement(ModalDialog, {
- title: l.share_contact_title,
- className: `
- send-contact
- contrast
- small-footer
- dialog-template-tool
- ${this.props.className}
- ${this.dialogName}
- `,
- selected: this.state.selected,
- buttons: [{
- key: "cancel",
- label: this.props.cancelLabel,
- onClick: ev => {
- this.props.onClose();
- ev.preventDefault();
- ev.stopPropagation();
- }
- }, {
- key: "select",
- label: this.props.selectLabel,
- className: this.state.selected.length === 0 ? 'positive disabled' : 'positive',
- onClick: ev => {
- if (this.state.selected.length > 0) {
- let _this$props$onSelecte2, _this$props3;
- (_this$props$onSelecte2 = (_this$props3 = this.props).onSelected) == null || _this$props$onSelecte2.call(_this$props3, this.state.selected);
- this.props.onSelectClicked(this.state.selected);
- }
- ev.preventDefault();
- ev.stopPropagation();
- }
- }],
- onClose: this.props.onClose
- }, modalDialogs_React.createElement("section", {
- className: "content"
- }, modalDialogs_React.createElement("div", {
- className: "content-block"
- }, modalDialogs_React.createElement(ContactsUI.ContactPickerWidget, {
- megaChat: this.props.megaChat,
- exclude: this.props.exclude,
- selectableContacts: "true",
- onSelectDone: this.props.onSelectClicked,
- onSelected: this.onSelected,
- onClose: this.props.onClose,
- selected: this.state.selected,
- contacts: M.u,
- headerClasses: "left-aligned",
- multiple: true
- }))));
- }
-}
-SelectContactDialog.clickTime = 0;
-SelectContactDialog.defaultProps = {
- selectLabel: l.share_contact_action,
- cancelLabel: l.msg_dlg_cancel,
- hideable: true
-};
-class ConfirmDialog extends mixins.w9 {
- static saveState(o) {
- const state = mega.config.get('xcod') >>> 0;
- mega.config.set('xcod', state | 1 << o.props.pref);
- }
- static clearState(o) {
- const state = mega.config.get('xcod') >>> 0;
- mega.config.set('xcod', state & ~(1 << o.props.pref));
- }
- static autoConfirm(o) {
- console.assert(o.props.pref > 0);
- const state = mega.config.get('xcod') >>> 0;
- return !!(state & 1 << o.props.pref);
- }
- constructor(props) {
- super(props);
- this.dialogName = 'confirm-dialog';
- this._wasAutoConfirmed = undefined;
- this._keyUpEventName = `keyup.confirmDialog${ this.getUniqueId()}`;
- this.dialogName = this.props.name || this.dialogName;
- lazy(this, '_autoConfirm', () => this.props.onConfirmClicked && this.props.dontShowAgainCheckbox && ConfirmDialog.autoConfirm(this));
- }
- unbindEvents() {
- $(document).off(this._keyUpEventName);
+ if (src) {
+ mBroadcaster.sendMessage('chat_image_preview');
}
- componentDidMount() {
- super.componentDidMount();
- M.safeShowDialog(this.dialogName, () => {
- queueMicrotask(() => {
- if (!this.isMounted()) {
- return;
- }
- if (this._autoConfirm) {
- if (!this._wasAutoConfirmed) {
- this._wasAutoConfirmed = 1;
- queueMicrotask(() => {
- this.onConfirmClicked();
- });
- }
- return;
- }
- $(document).rebind(this._keyUpEventName, e => {
- if (e.which === 13 || e.keyCode === 13) {
- if (!this.isMounted()) {
- this.unbindEvents();
- return;
- }
- this.onConfirmClicked();
- return false;
- }
- });
- });
- });
+};
+Chat.prototype.onChatsHistoryReady = promisify(function (resolve, reject, timeout) {
+ if (this.allChatsHadInitialLoadedHistory()) {
+ return resolve();
}
- componentWillUnmount() {
- super.componentWillUnmount();
- this.unbindEvents();
- if ($.dialog === this.dialogName) {
- closeDialog();
+ let timer = null;
+ const {chatd} = this.plugins.chatdIntegration;
+ const eventName = `onMessagesHistoryDone.ochr${ makeid(16)}`;
+ const ready = () => {
+ queueMicrotask(resolve);
+ chatd.off(eventName);
+ if (timer) {
+ timer.abort();
+ timer = null;
}
- delete this._wasAutoConfirmed;
- }
- onConfirmClicked() {
- this.unbindEvents();
- if (this.props.onConfirmClicked) {
- this.props.onConfirmClicked();
+ };
+ chatd.on(eventName, () => {
+ if (this.allChatsHadInitialLoadedHistory()) {
+ ready();
}
+ });
+ if (timeout > 0) {
+ (timer = tSleep(timeout / 1e3)).then(ready);
}
- render() {
- const self = this;
- if (this._autoConfirm) {
- return null;
+});
+Chat.prototype.allChatsHadLoadedHistory = function () {
+ const chatIds = this.chats.keys();
+ for (let i = chatIds.length; i--;) {
+ const room = this.chats[chatIds[i]];
+ if (room.isLoading()) {
+ return false;
}
- const classes = `delete-message${ self.props.name ? ` ${self.props.name}` : "" }${self.props.className ? ` ${self.props.className}` : ""}`;
- let dontShowCheckbox = null;
- if (self.props.dontShowAgainCheckbox) {
- dontShowCheckbox = modalDialogs_React.createElement("div", {
- className: "footer-checkbox"
- }, modalDialogs_React.createElement(ui_forms.Checkbox, {
- name: "delete-confirm",
- id: "delete-confirm",
- onLabelClick: (e, state) => {
- if (state === true) {
- ConfirmDialog.saveState(self);
- } else {
- ConfirmDialog.clearState(self);
- }
- }
- }, l[7039]));
+ }
+ return true;
+};
+Chat.prototype.allChatsHadInitialLoadedHistory = function () {
+ const self = this;
+ const chatIds = self.chats.keys();
+ for (let i = chatIds.length; i--;) {
+ const room = self.chats[chatIds[i]];
+ if (room.chatId && room.initialMessageHistLoaded === false) {
+ return false;
}
- return modalDialogs_React.createElement(ModalDialog, {
- title: this.props.title,
- subtitle: this.props.subtitle,
- className: classes,
- dialogId: this.props.name,
- dialogType: this.props.dialogType,
- icon: this.props.icon,
- onClose: () => {
- self.props.onClose(self);
- },
- buttons: [{
- "label": self.props.cancelLabel,
- "key": "cancel",
- "onClick" (e) {
- ConfirmDialog.clearState(self);
- self.props.onClose(self);
- e.preventDefault();
- e.stopPropagation();
- }
- }, {
- "label": self.props.confirmLabel,
- "key": "select",
- "className": "positive",
- "onClick" (e) {
- self.onConfirmClicked();
- e.preventDefault();
- e.stopPropagation();
- }
- }]
- }, self.props.children, dontShowCheckbox ? modalDialogs_React.createElement(ExtraFooterElement, null, dontShowCheckbox) : null);
}
-}
-lazy(ConfirmDialog, 'defaultProps', () => {
- return freeze({
- 'confirmLabel': l[6826],
- 'cancelLabel': l.msg_dlg_cancel,
- 'dontShowAgainCheckbox': true,
- 'hideable': true,
- 'dialogType': 'message'
- });
-});
-const modalDialogs = {
- ModalDialog,
- SelectContactDialog,
- SafeShowDialogController,
- ConfirmDialog
+ return true;
};
+Chat.prototype.getPrivateRoom = function (h) {
+ 'use strict';
-},
-
-486
-(_, EXP_, REQ_) {
-
-"use strict";
-REQ_.d(EXP_, {
-O: () => PerfectScrollbar
+ return this.chats[h] || false;
+};
+Chat.prototype.createAndShowPrivateRoom = promisify(function (resolve, reject, h) {
+ M.openFolder(`chat/p/${ h}`).then(() => {
+ const room = this.getPrivateRoom(h);
+ assert(room, 'room not found..');
+ resolve(room);
+ }).catch(reject);
});
-const _applyDecoratedDescriptor0__ = REQ_(793);
-const _chat_mixins1__ = REQ_(137);
-
-let _dec, _dec2, _class, _PerfectScrollbar;
-const React = REQ_(594);
-
-const PerfectScrollbar = (_dec = (0,_chat_mixins1__.hG)(30, true), _dec2 = (0,_chat_mixins1__.hG)(30, true), _class = (_PerfectScrollbar = class PerfectScrollbar extends _chat_mixins1__.w9 {
- constructor(props) {
- super(props);
- this.domRef = React.createRef();
- this.isUserScroll = true;
- this.scrollEventIncId = 0;
- }
- get$Node() {
- if (!this.$Node) {
- let _this$domRef;
- this.$Node = $((_this$domRef = this.domRef) == null ? void 0 : _this$domRef.current);
- }
- return this.$Node;
- }
- doProgramaticScroll(newPos, forced, isX, skipReinitialised) {
- if (!this.isMounted()) {
- return;
- }
- const self = this;
- const $elem = self.get$Node();
- let animFrameInner = false;
- const prop = !isX ? 'scrollTop' : 'scrollLeft';
- const event = `scroll.progscroll${ self.scrollEventIncId++}`;
- $elem.rebind(event, () => {
- if (animFrameInner) {
- cancelAnimationFrame(animFrameInner);
- animFrameInner = false;
- }
- $elem.off(event);
- if (!skipReinitialised) {
- self.reinitialised(true);
- } else if (typeof skipReinitialised === 'function') {
- onIdle(skipReinitialised);
- }
- self.isUserScroll = true;
- });
- self.isUserScroll = false;
- $elem[0][prop] = Math.round(newPos);
- Ps.update($elem[0]);
- animFrameInner = requestAnimationFrame(() => {
- animFrameInner = false;
- self.isUserScroll = true;
- $elem.off(event);
+Chat.prototype.createAndShowGroupRoomFor = function (contactHashes, topic = '', opts = {}) {
+ this.trigger('onNewGroupChatRequest', [contactHashes, {
+ topic,
+ ...opts
+ }]);
+};
+Chat.prototype.createAndStartMeeting = function (topic, audio, video) {
+ megaChat.createAndShowGroupRoomFor([], topic, {
+ keyRotation: false,
+ createChatLink: true,
+ isMeeting: true
+ });
+ megaChat.rebind('onRoomInitialized.meetingCreate', (e, room) => {
+ room.rebind('onNewMeetingReady.meetingCreate', () => {
+ room.startCall(audio, video);
});
- return true;
- }
- componentDidMount() {
- let _this$props$didMount, _this$props;
- super.componentDidMount();
- const self = this;
- const $elem = self.get$Node();
- $elem.height('100%');
- const options = Object.assign({}, {
- 'handlers': ['click-rail', 'drag-thumb', 'keyboard', 'wheel', 'touch'],
- 'minScrollbarLength': 20
- }, self.props.options);
- Ps.initialize($elem[0], options);
- if (self.props.onFirstInit) {
- self.props.onFirstInit(self, $elem);
- }
- $elem.rebind(`ps-scroll-y.ps${ self.getUniqueId()}`, (e) => {
- if ($elem.attr('data-scroll-disabled') === "true") {
- e.stopPropagation();
- e.preventDefault();
- e.originalEvent.stopPropagation();
- e.originalEvent.preventDefault();
- return false;
- }
- if (self.props.onUserScroll && self.isUserScroll === true && $elem.is(e.target)) {
- self.props.onUserScroll(self, $elem, e);
+ });
+};
+Chat.prototype._destroyAllChatsFromChatd = function () {
+ const self = this;
+ asyncApiReq({
+ 'a': 'mcf',
+ 'v': Chatd.VERSION
+ }).then(r => {
+ r.c.forEach((chatRoomMeta) => {
+ if (chatRoomMeta.g === 1) {
+ chatRoomMeta.u.forEach((u) => {
+ if (u.u !== u_handle) {
+ api_req({
+ a: 'mcr',
+ id: chatRoomMeta.id,
+ u: u.u,
+ v: Chatd.VERSION
+ });
+ }
+ });
+ api_req({
+ a: 'mcr',
+ id: chatRoomMeta.id,
+ u: u_handle,
+ v: Chatd.VERSION
+ });
}
});
- $elem.rebind(`disable-scroll.ps${ self.getUniqueId()}`, () => {
- Ps.destroy($elem[0]);
- });
- $elem.rebind(`enable-scroll.ps${ self.getUniqueId()}`, () => {
- Ps.initialize($elem[0], options);
- });
- $elem.rebind(`forceResize.ps${ self.getUniqueId()}`, (e, forced, scrollPositionYPerc, scrollToElement) => {
- self.onResize(forced, scrollPositionYPerc, scrollToElement);
+ });
+};
+Chat.prototype._leaveAllGroupChats = function () {
+ asyncApiReq({
+ 'a': 'mcf',
+ 'v': Chatd.VERSION
+ }).then(r => {
+ r.c.forEach((chatRoomMeta) => {
+ if (chatRoomMeta.g === 1) {
+ asyncApiReq({
+ "a": "mcr",
+ "id": chatRoomMeta.id,
+ "v": Chatd.VERSION
+ });
+ }
});
- self.onResize();
- this.attachAnimationEvents();
- (_this$props$didMount = (_this$props = this.props).didMount) == null || _this$props$didMount.call(_this$props, this.getUniqueId(), this);
+ });
+};
+Chat.prototype.getEmojiDataSet = async function (name) {
+ assert(name === "categories" || name === "emojis", "Invalid emoji dataset name passed.");
+ if (!this._emojiDataLoading) {
+ this._emojiDataLoading = Object.create(null);
}
- componentWillUnmount() {
- let _this$props$willUnmou, _this$props2;
- super.componentWillUnmount();
- const $elem = this.get$Node();
- $elem.off(`ps-scroll-y.ps${ this.getUniqueId()}`);
- const ns = `.ps${ this.getUniqueId()}`;
- $elem.parents('.have-animation').unbind(`animationend${ ns } webkitAnimationEnd${ ns } oAnimationEnd${ ns}`);
- (_this$props$willUnmou = (_this$props2 = this.props).willUnmount) == null || _this$props$willUnmou.call(_this$props2, this.getUniqueId(), this);
+ if (!this._emojiData) {
+ this._emojiData = {
+ 'emojisUtf': Object.create(null),
+ 'emojisSlug': Object.create(null)
+ };
}
- attachAnimationEvents() {}
- eventuallyReinitialise(forced, scrollPositionYPerc, scrollToElement) {
- const self = this;
- if (!self.isComponentEventuallyVisible()) {
+ if (this._emojiData[name]) {
+ return this._emojiData[name];
+ }
+ if (this._emojiDataLoading[name]) {
+ return this._emojiDataLoading[name];
+ }
+ if (name === "categories") {
+ this._emojiData[name] = ["people", "nature", "food", "activity", "travel", "objects", "symbols", "flags"];
+ return this._emojiData[name];
+ }
+ const {
+ promise
+ } = mega;
+ this._emojiDataLoading[name] = promise;
+ M.xhr({
+ type: 'json',
+ url: `${staticpath}js/chat/emojidata/${name}_v${EMOJI_DATASET_VERSION}.json`
+ }).then((ev, data) => {
+ if (!data) {
+ promise.reject(EFAILED);
return;
}
- const $elem = self.get$Node();
- const h = self.getContentHeight();
- if (forced || self._currHeight !== h) {
- self._currHeight = h;
- self._doReinit(scrollPositionYPerc, scrollToElement, forced, $elem);
+ this._emojiData[name] = data;
+ delete this._emojiDataLoading[name];
+ if (name === "emojis") {
+ this._mapEmojisToAliases();
}
- }
- _doReinit(scrollPositionYPerc, scrollToElement, forced, $elem) {
- let fired = false;
- if (this.props.onReinitialise) {
- fired = this.props.onReinitialise(this, $elem, forced, scrollPositionYPerc, scrollToElement);
+ promise.resolve(data);
+ }).catch((ex, error) => {
+ if (d) {
+ this.logger.warn('Failed to load emoji data "%s": %s', name, error, [ex]);
}
- if (fired === false) {
- if (scrollPositionYPerc) {
- if (scrollPositionYPerc === -1) {
- this.scrollToBottom(true);
- } else {
- this.scrollToPercentY(scrollPositionYPerc, true);
- }
- } else if (scrollToElement) {
- this.scrollToElement(scrollToElement, true);
- }
+ delete this._emojiDataLoading[name];
+ promise.reject(error || ex);
+ });
+ return promise;
+};
+Chat.prototype._mapEmojisToAliases = function () {
+ const {
+ emojis
+ } = this._emojiData;
+ if (emojis) {
+ this._emojiData.emojisUtf = Object.create(null);
+ this._emojiData.emojisSlug = Object.create(null);
+ for (let i = emojis.length; i--;) {
+ const emoji = emojis[i];
+ this._emojiData.emojisUtf[emoji.u] = emoji;
+ this._emojiData.emojisSlug[emoji.n] = emoji;
}
}
- scrollToBottom(skipReinitialised) {
- this.reinitialise(skipReinitialised, true);
+};
+Chat.prototype.isValidEmojiSlug = function (slug) {
+ const self = this;
+ const emojiData = self._emojiData.emojis;
+ if (!emojiData) {
+ self.getEmojiDataSet('emojis');
+ return false;
}
- reinitialise(skipReinitialised, bottom) {
- let _this$domRef2;
- const $elem = (_this$domRef2 = this.domRef) == null ? void 0 : _this$domRef2.current;
- if (!$elem) {
- return;
- }
- this.isUserScroll = false;
- if (bottom) {
- $elem.scrollTop = this.getScrollHeight();
- }
- Ps.update($elem);
- this.isUserScroll = true;
- if (!skipReinitialised) {
- this.reinitialised(true);
+ for (let i = 0; i < emojiData.length; i++) {
+ if (emojiData[i].n === slug) {
+ return true;
}
}
- getDOMRect(node) {
- let _this$domRef3;
- node = node || ((_this$domRef3 = this.domRef) == null ? void 0 : _this$domRef3.current);
- return node && node.getBoundingClientRect();
+};
+Chat.prototype.getPresence = function (user_handle) {
+ if (user_handle && this.plugins.presencedIntegration) {
+ return this.plugins.presencedIntegration.getPresence(user_handle);
}
- getScrollOffset(value) {
- let _this$domRef4;
- const $elem = (_this$domRef4 = this.domRef) == null ? void 0 : _this$domRef4.current;
- if ($elem) {
- return this.getDOMRect($elem.children[0])[value] - this.getDOMRect($elem)[value];
+};
+Chat.prototype.getPresenceAsCssClass = function (user_handle) {
+ const presence = this.getPresence(user_handle);
+ return this.presenceStringToCssClass(presence);
+};
+Chat.prototype.presenceStringToCssClass = function (presence) {
+ if (presence === UserPresence.PRESENCE.ONLINE) {
+ return 'online';
+ } else if (presence === UserPresence.PRESENCE.AWAY) {
+ return 'away';
+ } else if (presence === UserPresence.PRESENCE.DND) {
+ return 'busy';
+ } else if (!presence || presence === UserPresence.PRESENCE.OFFLINE) {
+ return 'offline';
+ } else {
+ return 'black';
+ }
+};
+Chat.prototype.generateTempMessageId = function (roomId, messageAndMeta) {
+ let messageIdHash = u_handle + roomId;
+ if (messageAndMeta) {
+ messageIdHash += messageAndMeta;
+ }
+ return `m${ fastHashFunction(messageIdHash) }_${ unixtime()}`;
+};
+Chat.prototype.getChatById = function (chatdId) {
+ const self = this;
+ if (self.chats[chatdId]) {
+ return self.chats[chatdId];
+ } else if (self.chatIdToRoomId && self.chatIdToRoomId[chatdId] && self.chats[self.chatIdToRoomId[chatdId]]) {
+ return self.chats[self.chatIdToRoomId[chatdId]];
+ }
+ if (this.chats[this.handleToId[chatdId]]) {
+ return this.chats[this.handleToId[chatdId]];
+ }
+ let found = false;
+ self.chats.forEach((chatRoom) => {
+ if (!found && chatRoom.chatId === chatdId) {
+ found = chatRoom;
+ return false;
}
- return 0;
+ });
+ return found;
+};
+Chat.prototype.getNoteChat = function () {
+ return Object.values(this.chats).find(c => c.isNote);
+};
+Chat.prototype.getMessageByMessageId = async function (chatId, messageId) {
+ const chatRoom = this.getChatById(chatId);
+ const msg = chatRoom.messagesBuff.getMessageById(messageId);
+ if (msg) {
+ return msg;
}
- getScrollHeight() {
- const res = this.getScrollOffset('height');
- if (res < 1) {
- return this._lastKnownScrollHeight || 0;
+ const {
+ chatdPersist
+ } = this.plugins.chatdIntegration.chatd;
+ if (chatdPersist) {
+ const [msg] = await chatdPersist.getMessageByMessageId(chatId, messageId).catch(dump) || [];
+ if (msg) {
+ return Message.fromPersistableObject(chatRoom, msg);
}
- this._lastKnownScrollHeight = res;
- return res;
}
- getScrollWidth() {
- const res = this.getScrollOffset('width');
- if (res < 1) {
- return this._lastKnownScrollWidth || 0;
+ if (d) {
+ this.logger.debug('getMessageByMessageId: Cannot find %s on %s', messageId, chatId);
+ }
+ return Promise.reject(ENOENT);
+};
+Chat.prototype.haveAnyActiveCall = function () {
+ const self = this;
+ const chatIds = self.chats.keys();
+ for (let i = 0; i < chatIds.length; i++) {
+ if (self.chats[chatIds[i]].haveActiveCall()) {
+ return true;
+ }
+ }
+ return false;
+};
+Chat.prototype.haveAnyOnHoldCall = function () {
+ const self = this;
+ const chatIds = self.chats.keys();
+ for (let i = 0; i < chatIds.length; i++) {
+ if (self.chats[chatIds[i]].haveActiveOnHoldCall()) {
+ return true;
}
- this._lastKnownScrollWidth = res;
- return res;
- }
- getContentHeight() {
- const $elem = this.get$Node();
- return $elem[0].scrollHeight;
}
- getContentWidth() {
- const $elem = this.get$Node();
- return $elem[0].scrollWidth;
+ return false;
+};
+Chat.prototype.openChatAndSendFilesDialog = function (user_handle) {
+ 'use strict';
+
+ this.smartOpenChat(user_handle).then((room) => {
+ if (room.$rConversationPanel && room.$rConversationPanel.isMounted()) {
+ room.trigger('openSendFilesDialog');
+ } else {
+ room.one('onComponentDidMount.sendFilesDialog', () => {
+ onIdle(() => room.trigger('openSendFilesDialog'));
+ });
+ }
+ room.setActive();
+ }).catch(this.logger.error.bind(this.logger));
+};
+Chat.prototype.openChatAndAttachNodes = async function (targets, nodes, silent) {
+ const promises = [];
+ if (d) {
+ console.group('Attaching nodes to chat room(s)...', targets, nodes);
}
- setCssContentHeight(h) {
- const $elem = this.get$Node();
- return $elem.css('height', h);
+ const attachNodes = roomId => this.smartOpenChat(roomId).then(room => {
+ return room.attachNodes(nodes).then(res => {
+ if (res !== EBLOCKED && res !== ENOENT) {
+ return room;
+ }
+ });
+ }).catch(ex => {
+ if (d) {
+ this.logger.warn('Cannot openChat for %s and hence nor attach nodes to it.', roomId, ex);
+ }
+ throw ex;
+ });
+ if (!Array.isArray(targets)) {
+ targets = [targets];
}
- isAtTop() {
- let _this$domRef5;
- return ((_this$domRef5 = this.domRef) == null ? void 0 : _this$domRef5.current.scrollTop) === 0;
+ for (let i = targets.length; i--;) {
+ promises.push(attachNodes(targets[i]));
}
- isAtBottom() {
- return Math.round(this.getScrollPositionY()) === Math.round(this.getScrollHeight());
+ const result = (await Promise.allSettled(promises)).map(e => e.value).filter(Boolean);
+ let folderCount = 0;
+ let fileCount = 0;
+ for (let i = nodes.length; i--;) {
+ const {
+ t
+ } = M.getNodeByHandle(nodes[i]) || {};
+ if (t === 1) {
+ folderCount++;
+ } else {
+ fileCount++;
+ }
}
- isCloseToBottom(minPixelsOff) {
- return this.getScrollHeight() - this.getScrollPositionY() <= minPixelsOff;
+ let message = mega.icu.format(l.toast_send_chat_items, nodes.length);
+ if (fileCount === 0 && folderCount) {
+ message = mega.icu.format(l.toast_send_chat_folders, folderCount);
+ } else if (folderCount === 0 && fileCount) {
+ message = mega.icu.format(l.toast_send_chat_files, fileCount);
}
- getScrolledPercentY() {
- return 100 / this.getScrollHeight() * this.getScrollPositionY();
+ for (let i = result.length; i--;) {
+ if (result[i] instanceof ChatRoom) {
+ const room = result[i];
+ mega.ui.toast.show(message);
+ if (!silent) {
+ await M.openFolder(room.getRoomUrl().replace('fm/', '')).catch(dump);
+ }
+ break;
+ }
}
- getScrollPositionY() {
- let _this$domRef6;
- return (_this$domRef6 = this.domRef) == null ? void 0 : _this$domRef6.current.scrollTop;
+ if (d) {
+ console.groupEnd();
}
- getScrollPositionX() {
- let _this$domRef7;
- return (_this$domRef7 = this.domRef) == null ? void 0 : _this$domRef7.current.scrollLeft;
+ return result;
+};
+Chat.prototype.toggleUIFlag = function (name) {
+ this.chatUIFlags.set(name, this.chatUIFlags[name] ? 0 : 1);
+};
+Chat.prototype.onSnActionPacketReceived = function () {
+ if (this._queuedMccPackets.length > 0) {
+ const aps = this._queuedMccPackets;
+ this._queuedMccPackets = [];
+ for (let i = 0; i < aps.length; i++) {
+ mBroadcaster.sendMessage('onChatdChatUpdatedActionPacket', aps[i]);
+ }
}
- getClientWidth() {
- let _this$domRef8;
- return (_this$domRef8 = this.domRef) == null ? void 0 : _this$domRef8.current.clientWidth;
+ this.processQueuedMcsmPackets();
+};
+Chat.prototype.processQueuedMcsmPackets = function () {
+ const aps = Object.values(this._queuedMcsmPackets);
+ if (aps.length) {
+ for (let i = 0; i < aps.length; i++) {
+ const ap = aps[i];
+ const {
+ type,
+ data
+ } = ap;
+ const {
+ meetingsManager
+ } = this.plugins;
+ if (type === 'mcsmp') {
+ const chatRoom = this.getChatById(data.cid);
+ if (chatRoom) {
+ const scheduledMeeting = meetingsManager.attachMeeting(data, true);
+ delete this._queuedMcsmPackets[scheduledMeeting.id];
+ return scheduledMeeting.iAmOwner ? null : notify.notifyFromActionPacket({
+ ...data,
+ a: type
+ });
+ }
+ }
+ if (type === 'mcsmr') {
+ meetingsManager.detachMeeting(data);
+ delete this._queuedMcsmPackets[data.id];
+ }
+ }
}
- getClientHeight() {
- let _this$domRef9;
- return (_this$domRef9 = this.domRef) == null ? void 0 : _this$domRef9.current.clientHeight;
+};
+Chat.prototype.getFrequentContacts = function () {
+ if (Chat._frequentsCache) {
+ return Chat._frequentsCache;
}
- scrollToPercentY(posPerc, skipReinitialised) {
- const $elem = this.get$Node();
- const targetPx = this.getScrollHeight() / 100 * posPerc;
- if ($elem[0].scrollTop !== targetPx) {
- this.doProgramaticScroll(targetPx, 0, 0, skipReinitialised);
+ const {chats} = this;
+ const recentContacts = {};
+ const promises = [];
+ const finishedLoadingChats = {};
+ const loadingMoreChats = {};
+ const _calculateLastTsFor = function (r, maxMessages) {
+ const mb = r.messagesBuff;
+ const len = mb.messages.length;
+ const msgs = mb.messages.slice(Math.max(0, len - maxMessages), len);
+ for (let i = 0; i < msgs.length; i++) {
+ const msg = msgs[i];
+ let contactHandle = msg.userId === mega.BID && msg.meta ? msg.meta.userId : msg.userId;
+ if (r.type === "private" && contactHandle === u_handle) {
+ contactHandle = contactHandle || r.getParticipantsExceptMe()[0];
+ }
+ if (contactHandle !== mega.BID && contactHandle !== strongvelope.COMMANDER && contactHandle in M.u && M.u[contactHandle].c === 1 && contactHandle !== u_handle) {
+ if (!recentContacts[contactHandle] || recentContacts[contactHandle].ts < msg.delay) {
+ recentContacts[contactHandle] = {
+ 'userId': contactHandle,
+ 'ts': msg.delay
+ };
+ }
+ }
}
- }
- scrollToPercentX(posPerc, skipReinitialised) {
- const $elem = this.get$Node();
- const targetPx = this.getScrollWidth() / 100 * posPerc;
- if ($elem[0].scrollLeft !== targetPx) {
- this.doProgramaticScroll(targetPx, false, true, skipReinitialised);
+ };
+ const _histDecryptedCb = function () {
+ const mb = this.messagesBuff;
+ if (!loadingMoreChats[this.chatId] && mb.messages.length < 32 && mb.haveMoreHistory()) {
+ loadingMoreChats[this.chatId] = true;
+ mb.retrieveChatHistory(false);
+ } else {
+ this.unbind(CHAT_ONHISTDECR_RECNT);
+ _calculateLastTsFor(this, 32);
+ delete loadingMoreChats[this.chatId];
+ finishedLoadingChats[this.chatId] = true;
+ mb.detachMessages();
+ }
+ };
+ const _checkFinished = function (chatId) {
+ return function () {
+ return finishedLoadingChats[chatId] === true;
+ };
+ };
+ chats.forEach(chatRoom => {
+ const name = `getFrequentContacts(${chatRoom.roomId})`;
+ if (chatRoom.isLoading()) {
+ finishedLoadingChats[chatRoom.chatId] = false;
+ chatRoom.rebind(CHAT_ONHISTDECR_RECNT, _histDecryptedCb);
+ promises.push(createTimeoutPromise(_checkFinished(chatRoom.chatId), 300, 10000, false, name));
+ } else if (chatRoom.messagesBuff.messages.length < 32 && chatRoom.messagesBuff.haveMoreHistory()) {
+ loadingMoreChats[chatRoom.chatId] = true;
+ finishedLoadingChats[chatRoom.chatId] = false;
+ chatRoom.messagesBuff.retrieveChatHistory(false);
+ chatRoom.rebind(CHAT_ONHISTDECR_RECNT, _histDecryptedCb);
+ promises.push(createTimeoutPromise(_checkFinished(chatRoom.chatId), 300, 15000, false, name));
+ } else {
+ _calculateLastTsFor(chatRoom, 32);
+ }
+ });
+ Chat._frequentsCache = new Promise((resolve, reject) => {
+ Promise.allSettled(promises).then(() => {
+ const result = Object.values(recentContacts).sort((a, b) => a.ts < b.ts ? 1 : b.ts < a.ts ? -1 : 0).reverse();
+ tSleep(300).then(() => {
+ delete Chat._frequentsCache;
+ });
+ return result;
+ }).then(resolve).catch(reject);
+ });
+ return Chat._frequentsCache;
+};
+Chat.prototype.lastRoomContacts = async function (chatRoom) {
+ let timeout;
+ let loaded = false;
+ let loadMore = false;
+ const {
+ promise
+ } = mega;
+ const proc = () => {
+ if (timeout) {
+ timeout.abort();
+ }
+ const {
+ messages
+ } = chatRoom.messagesBuff;
+ const arr = messages.slice(Math.max(0, messages.length - 32));
+ let first = '';
+ let second = '';
+ for (let i = arr.length; i--;) {
+ const message = arr[i];
+ const h = message.userId === mega.BID && message.meta ? message.meta.userId : message.userId;
+ if (h !== mega.BID && h !== strongvelope.COMMANDER && h !== u_handle && h in M.u && M.u[h].c === 1) {
+ if (first && first !== h) {
+ second = h;
+ break;
+ }
+ first = h;
+ }
+ }
+ if (second) {
+ promise.resolve([first, second]);
+ } else if (first) {
+ promise.resolve([first]);
+ } else {
+ promise.resolve([]);
}
- }
- scrollToY(posY, skipReinitialised) {
- const $elem = this.get$Node();
- if ($elem[0].scrollTop !== posY) {
- this.doProgramaticScroll(posY, 0, 0, skipReinitialised);
+ chatRoom.messagesBuff.detachMessages();
+ };
+ const next = () => {
+ if (!loadMore && chatRoom.messagesBuff.messages.length < 32 && chatRoom.messagesBuff.haveMoreHistory()) {
+ if (timeout) {
+ timeout.restart();
+ }
+ loadMore = true;
+ chatRoom.messagesBuff.retrieveChatHistory(false);
+ } else {
+ chatRoom.off('onHistoryDecrypted.lrc');
+ proc();
}
+ };
+ if (chatRoom.isLoading()) {
+ loaded = false;
+ chatRoom.rebind('onHistoryDecrypted.lrc', next);
+ timeout = tSleep(10);
+ } else if (chatRoom.messagesBuff.messages.length < 32 && chatRoom.messagesBuff.haveMoreHistory()) {
+ loaded = false;
+ loadMore = true;
+ chatRoom.rebind('onHistoryDecrypted.lrc', next);
+ chatRoom.messagesBuff.retrieveChatHistory(false);
+ timeout = tSleep(10);
+ } else {
+ proc();
}
- scrollToElement(element, skipReinitialised) {
- if (element && element.offsetParent) {
- this.doProgramaticScroll(element.offsetTop, 0, 0, skipReinitialised);
- }
+ if (timeout) {
+ timeout.then(() => {
+ if (!loaded) {
+ chatRoom.off('onHistoryDecrypted.lrc');
+ promise.resolve([]);
+ }
+ });
}
- disable() {
- if (this.isMounted()) {
- const $elem = this.get$Node();
- $elem.attr('data-scroll-disabled', true);
- $elem.addClass('ps-disabled');
- Ps.disable($elem[0]);
- }
+ return promise;
+};
+Chat.prototype.eventuallyAddDldTicketToReq = function (req) {
+ if (!u_handle) {
+ return;
}
- enable() {
- if (this.isMounted()) {
- const $elem = this.get$Node();
- $elem.removeAttr('data-scroll-disabled');
- $elem.removeClass('ps-disabled');
- Ps.enable($elem[0]);
- }
+ const currentRoom = this.getCurrentRoom();
+ if (currentRoom && currentRoom.type === "public" && currentRoom.publicChatHandle && (is_chatlink || currentRoom.membersSetFromApi && !currentRoom.membersSetFromApi.members[u_handle])) {
+ req.cauth = currentRoom.publicChatHandle;
}
- reinitialised(forced) {
- if (this.props.onReinitialise) {
- this.props.onReinitialise(this, this.get$Node(), forced ? forced : false);
+};
+Chat.prototype.removeMessagesByRetentionTime = function (chatId) {
+ if (this.chats.length > 0) {
+ if (chatId) {
+ if (this.logger && d > 3) {
+ this.logger.debug(`Chat.prototype.removeMessagesByRetentionTime chatId=${chatId}`);
+ }
+ const room = this.getChatById(chatId);
+ if (room) {
+ room.removeMessagesByRetentionTime();
+ }
+ return;
}
- }
- onResize(forced, scrollPositionYPerc, scrollToElement) {
- if (forced && forced.originalEvent) {
- forced = true;
- scrollPositionYPerc = undefined;
+ const chatIds = this.chats.keys();
+ for (let i = 0; i < chatIds.length; i++) {
+ const chatRoom = this.chats[chatIds[i]];
+ if (chatRoom.retentionTime > 0 && chatRoom.state === ChatRoom.STATE.READY) {
+ if (this.logger && d > 3) {
+ this.logger.debug(`Chat.prototype.removeMessagesByRetentionTime roomId=${chatRoom.roomId}`);
+ }
+ chatRoom.removeMessagesByRetentionTime();
+ }
}
- this.eventuallyReinitialise(forced, scrollPositionYPerc, scrollToElement);
}
- inViewport(domNode) {
- return verge.inViewport(domNode);
+};
+Chat.prototype.loginOrRegisterBeforeJoining = function (chatHandle, forceRegister, forceLogin, notJoinReq, onLoginSuccessCb) {
+ if (!chatHandle && page !== 'securechat' && (page === 'chat' || page.indexOf('chat') > -1)) {
+ chatHandle = getSitePath().split("chat/")[1].split("#")[0];
}
- componentDidUpdate() {
- if (this.props.requiresUpdateOnResize || this.requiresUpdateOnResize) {
- this.onResize(true);
+ assert(chatHandle, 'missing chat handle when calling megaChat.loginOrRegisterBeforeJoining');
+ const chatRoom = megaChat.getCurrentRoom();
+ const chatKey = `#${ window.location.hash.split("#").pop()}`;
+ const finish = function (stay) {
+ if (!notJoinReq) {
+ localStorage.autoJoinOnLoginChat = JSON.stringify([chatHandle, unixtime(), chatKey, chatRoom.chatId]);
}
- this.attachAnimationEvents();
- }
- customIsEventuallyVisible() {
- const {chatRoom} = this.props;
- return !chatRoom || chatRoom.isCurrentlyActive;
- }
- render() {
- const {
- style,
- className,
- children
- } = this.props;
- return React.createElement("div", {
- ref: this.domRef,
- style,
- className
- }, children);
- }
-}, _PerfectScrollbar.defaultProps = {
- className: "perfectScrollbarContainer",
- requiresUpdateOnResize: true
-}, _PerfectScrollbar), (0,_applyDecoratedDescriptor0__.A)(_class.prototype, "eventuallyReinitialise", [_dec], Object.getOwnPropertyDescriptor(_class.prototype, "eventuallyReinitialise"), _class.prototype), (0,_applyDecoratedDescriptor0__.A)(_class.prototype, "onResize", [_dec2], Object.getOwnPropertyDescriptor(_class.prototype, "onResize"), _class.prototype), _class);
-
-},
-
-314
-(_, EXP_, REQ_) {
-
-"use strict";
-REQ_.d(EXP_, {
-Ay: () => __WEBPACK_DEFAULT_EXPORT__,
-P9: () => ParsedHTML,
-T9: () => withOverflowObserver,
-lI: () => reactStringWrap,
-oM: () => OFlowParsedHTML,
-sp: () => OFlowEmoji,
-zT: () => Emoji
-});
-const react0__ = REQ_(594);
-const react0 = REQ_.n(react0__);
-const react_dom1__ = REQ_(206);
-const react_dom1 = REQ_.n(react_dom1__);
-const _chat_mixins_js2__ = REQ_(137);
-
-
-
-class RenderTo extends react0().Component {
- constructor(...args) {
- super(...args);
- this.$$rootRef = undefined;
- this.popupElement = undefined;
- }
- _setClassNames() {
- this.popupElement.className = this.props.className || '';
- }
- _renderLayer() {
- this.$$rootRef.render(this.props.children);
- queueMicrotask(() => {
- let _this$props$popupDidM, _this$props;
- return (_this$props$popupDidM = (_this$props = this.props).popupDidMount) == null ? void 0 : _this$props$popupDidM.call(_this$props, this.popupElement);
- });
- }
- componentDidUpdate() {
- this._setClassNames();
- this._renderLayer();
- }
- componentWillUnmount() {
- let _this$props$popupWill, _this$props2;
- onIdle(() => this.$$rootRef.unmount());
- (_this$props$popupWill = (_this$props2 = this.props).popupWillUnmount) == null || _this$props$popupWill.call(_this$props2, this.popupElement);
- this.props.element.removeChild(this.popupElement);
- }
- componentDidMount() {
- this.popupElement = document.createElement('div');
- this.$$rootRef = (0,react_dom1__.createRoot)(this.popupElement);
- this._setClassNames();
- if (this.props.style) {
- $(this.popupElement).css(this.props.style);
+ if (!stay) {
+ window.location.reload();
}
- this.props.element.appendChild(this.popupElement);
- this._renderLayer();
+ return stay;
+ };
+ const doShowLoginDialog = function () {
+ mega.ui.showLoginRequiredDialog({
+ minUserType: 3,
+ skipInitialDialog: 1,
+ onLoginSuccessCb
+ }).done(() => {
+ if (page !== 'login' && onLoginSuccessCb) {
+ onLoginSuccessCb();
+ }
+ });
+ };
+ const doShowRegisterDialog = function () {
+ mega.ui.showRegisterDialog({
+ title: l[5840],
+ onCreatingAccount () {},
+ onLoginAttemptFailed () {
+ msgDialog(`warninga:${ l[171]}`, l[1578], l[218], null, (e) => {
+ if (e) {
+ $('.pro-register-dialog').addClass('hidden');
+ if (signupPromptDialog) {
+ signupPromptDialog.hide();
+ }
+ doShowLoginDialog();
+ }
+ });
+ },
+ onAccountCreated (gotLoggedIn, registerData) {
+ if (finish(!gotLoggedIn)) {
+ security.register.cacheRegistrationData(registerData);
+ mega.ui.sendSignupLinkDialog(registerData);
+ megaChat.destroy();
+ }
+ },
+ onLoginSuccessCb
+ });
+ };
+ if (u_handle && u_handle !== "AAAAAAAAAAA") {
+ return finish();
}
- render() {
- return null;
+ if (forceRegister) {
+ return doShowRegisterDialog();
+ } else if (forceLogin) {
+ return doShowLoginDialog();
}
-}
-const withOverflowObserver = Component => class extends _chat_mixins_js2__.u9 {
- constructor(props) {
- super(props);
- this.displayName = 'OverflowObserver';
- this.ref = react0().createRef();
- this.state = {
- overflowed: false
- };
- this.handleMouseEnter = this.handleMouseEnter.bind(this);
+ if (u_wasloggedin()) {
+ doShowLoginDialog();
+ } else {
+ doShowRegisterDialog();
}
- handleMouseEnter() {
- const element = this.ref && this.ref.current;
- if (element) {
- this.setState({
- overflowed: element.scrollWidth > element.offsetWidth
- });
+};
+Chat.prototype.highlight = (text, matches, dontEscape) => {
+ if (text && matches) {
+ text = dontEscape ? text : escapeHTML(text);
+ const tags = [];
+ text = text.replace(/<[^>]+>/g, match => `@@!${ tags.push(match) - 1 }!@@`).split(' ');
+ const done = [];
+ for (let i = 0; i < matches.length; i++) {
+ const match = matches[i].str;
+ if (!done.includes(match)) {
+ done.push(match);
+ for (let j = 0; j < text.length; j++) {
+ const word = text[j];
+ const wordNormalized = ChatSearch._normalize_str(word);
+ const matchPos = wordNormalized.indexOf(match);
+ if (matchPos > -1) {
+ const split = wordNormalized.split(match);
+ text[j] = wordNormalized === word ? split.join(`[$]${match}[/$]`) : megaChat._highlightDiacritics(word, matchPos, split, match);
+ }
+ }
+ }
}
+ text = text.join(' ').replace(/\@\@\!\d+\!\@\@/g, match => {
+ return tags[parseInt(match.replace("@@!", "").replace("!@@"), 10)];
+ });
+ return text.replace(/\[\$]/g, '').replace(/\[\/\$]/g, '');
}
- shouldComponentUpdate(nextProps, nextState) {
- return nextState.overflowed !== this.state.overflowed || nextProps.children !== this.props.children || nextProps.content !== this.props.content;
+ return null;
+};
+Chat.prototype._highlightDiacritics = function (word, matchPos, split, match) {
+ const parts = [];
+ const origMatch = word.substring(matchPos, matchPos + match.length);
+ let pos = 0;
+ for (let k = 0; k < split.length; k++) {
+ parts.push(word.substring(pos, pos + split[k].length));
+ pos = pos + split[k].length + match.length;
}
- render() {
- const {
- simpletip
- } = this.props;
- return react0().createElement("div", {
- ref: this.ref,
- className: `
- overflow-observer
- ${this.state.overflowed ? 'simpletip simpletip-tc' : ''}
- `,
- "data-simpletipposition": (simpletip == null ? void 0 : simpletip.position) || 'top',
- "data-simpletipoffset": simpletip == null ? void 0 : simpletip.offset,
- "data-simpletip-class": (simpletip == null ? void 0 : simpletip.className) || 'medium-width center-align',
- onMouseEnter: this.handleMouseEnter
- }, react0().createElement(Component, this.props));
+ return parts.join(`[$]${origMatch}[/$]`);
+};
+Chat.prototype.html = function (content) {
+ if (content) {
+ return this.plugins.emoticonsFilter.processHtmlMessage(escapeHTML(content));
}
+ return '';
};
-const Emoji = ({
- children
-}) => {
- return react0().createElement(ParsedHTML, {
- content: megaChat.html(children)
+Chat.prototype.updateKeysInProtocolHandlers = function () {
+ this.chats.forEach(r => {
+ const ph = r.protocolHandler;
+ if (ph) {
+ ph.reinitWithNewData(u_handle, u_privCu25519, u_privEd25519, u_pubEd25519, ph.chatMode);
+ }
});
};
-class ParsedHTML extends react0().Component {
- constructor(...args) {
- super(...args);
- this.ref = react0().createRef();
+Chat.prototype.eventuallyInitMeetingUI = function () {
+ if (!window.location.hash) {
+ return;
}
- updateInternalState() {
- const {
- children,
- content
- } = this.props;
- const ref = this.ref && this.ref.current;
- if (!children && !content) {
- return d > 1 && console.warn('Emoji: No content passed.');
+ let loc = page.split("#")[0];
+ loc = loc.replace("fm/", "/");
+ if (loc.indexOf("chat/") === 0) {
+ this.initialPubChatHandle = loc.substr(5).split("?")[0];
+ }
+};
+Chat.prototype.enqueueChatRoomEvent = function (eventName, eventData) {
+ if (!this.is_initialized) {
+ return;
+ }
+ const {
+ chatId
+ } = eventData;
+ if (!this._queuedChatRoomEvents[chatId]) {
+ this._queuedChatRoomEvents[chatId] = [];
+ (this._queuedChatRoomEvents[chatId].timer = tSleep(15)).then(() => {
+ if (d) {
+ this.logger.warn('Timer ran out, events lost...', this._queuedChatRoomEvents[chatId]);
+ }
+ delete this._queuedChatRoomEvents[chatId];
+ });
+ }
+ this._queuedChatRoomEvents[chatId].push([eventName, eventData]);
+};
+Chat.prototype.autoJoinIfNeeded = function () {
+ const rawAutoLoginInfo = localStorage.autoJoinOnLoginChat;
+ if (u_type && rawAutoLoginInfo) {
+ const autoLoginChatInfo = tryCatch(JSON.parse.bind(JSON))(rawAutoLoginInfo) || false;
+ if (unixtime() - 7200 < autoLoginChatInfo[1]) {
+ const req = this.plugins.chatdIntegration.getMciphReqFromHandleAndKey(autoLoginChatInfo[0], autoLoginChatInfo[2].substr(1));
+ megaChat.rebind('onRoomInitialized.autoJoin', (e, megaRoom) => {
+ if (megaRoom.chatId === autoLoginChatInfo[3]) {
+ megaRoom.setActive();
+ megaChat.unbind('onRoomInitialized.autoJoin');
+ localStorage.removeItem("autoJoinOnLoginChat");
+ }
+ });
+ asyncApiReq(req).catch(dump);
+ } else {
+ localStorage.removeItem("autoJoinOnLoginChat");
}
- if (ref) {
- if (ref.childNodes.length) {
- while (ref.firstChild) {
- ref.removeChild(ref.firstChild);
+ }
+};
+Chat.prototype.openScheduledMeeting = function (meetingId, toCall) {
+ const meeting = this.scheduledMeetings[meetingId];
+ if (!meeting) {
+ console.warn('Meeting does not exist', meetingId);
+ return;
+ }
+ window.focus();
+ meeting.chatRoom.activateWindow();
+ meeting.chatRoom.show();
+ if (toCall && this.hasSupportForCalls) {
+ this.openScheduledMeeting._queue = this.openScheduledMeeting._queue || [];
+ this.openScheduledMeeting._queue.push(meetingId);
+ delay('megachat:openScheduledMeetingCall', () => {
+ const meetingId = this.openScheduledMeeting._queue[0];
+ delete this.openScheduledMeeting._queue;
+ const meetingRoom = this.scheduledMeetings[meetingId].chatRoom;
+ meetingRoom.activateWindow();
+ meetingRoom.show();
+ const haveCall = this.haveAnyActiveCall();
+ if (haveCall && window.sfuClient) {
+ const {
+ chatRoom
+ } = this.activeCall;
+ if (chatRoom && chatRoom.chatId === meetingRoom.chatId) {
+ const peers = chatRoom.getCallParticipants();
+ if (peers.includes(u_handle)) {
+ return d && console.warn('Already in this call');
+ }
}
}
- ref.appendChild(parseHTML(children || content));
- }
+ (0,utils.dQ)(true, meetingRoom).then(() => meetingRoom.startAudioCall(true)).catch(ex => d && console.warn('Already in a call.', ex));
+ });
}
- shouldComponentUpdate(nextProps) {
- return nextProps && (nextProps.children !== this.props.children || nextProps.content !== this.props.content);
+};
+Chat.prototype.playSound = tryCatch((sound, options, stop) => {
+ if (options === true) {
+ stop = true;
+ options = undefined;
}
- componentDidUpdate() {
- this.updateInternalState();
+ if (stop) {
+ ion.sound.stop(sound);
}
- componentDidMount() {
- this.updateInternalState();
+ return ion.sound.play(sound, options);
+});
+Chat.prototype.fetchSoundBuffer = async function (sound) {
+ if (this.SOUNDS.buffers[sound]) {
+ return this.SOUNDS.buffers[sound].slice();
}
- render() {
- const {
- className,
- onClick,
- tag
- } = this.props;
- return react0().createElement(tag || 'span', {
- ref: this.ref,
- className,
- onClick
+ let res = await M.xhr({
+ url: `${staticpath}media/${sound}.mp3`,
+ type: 'arraybuffer'
+ }).catch(() => {
+ console.warn('Failed to fetch sound .mp3 file', sound);
+ });
+ if (!res) {
+ res = await M.xhr({
+ url: `${staticpath}media/${sound}.ogg`,
+ type: 'arraybuffer'
+ }).catch(() => {
+ console.error('Failed to fetch sound .ogg file', sound);
});
}
-}
-const reactStringWrap = (src, find, WrapClass, wrapProps) => {
- const endTag = find.replace('[', '[/');
- return react0().createElement(react0().Fragment, null, src.split(find)[0], react0().createElement(WrapClass, wrapProps, src.substring(src.indexOf(find) + find.length, src.indexOf(endTag))), src.split(endTag)[1]);
+ if (!res) {
+ throw ENOENT;
+ }
+ this.SOUNDS.buffers[sound] = res.target.response.slice();
+ return res.target.response;
};
-const OFlowEmoji = withOverflowObserver(Emoji);
-const OFlowParsedHTML = withOverflowObserver(ParsedHTML);
-const __WEBPACK_DEFAULT_EXPORT__ = {
- RenderTo,
- SoonFcWrap: _chat_mixins_js2__.hG,
- OFlowEmoji,
- OFlowParsedHTML
+window.Chat = Chat;
+ const chat = {
+ Chat
};
+})();
-},
-
-594
-(module) {
-
-"use strict";
-module.exports = React;
-
-},
-
-206
-(module) {
-
-"use strict";
-module.exports = ReactDOM;
-
-},
-
-793
-(__webpack_module__, EXP_, REQ_) {
-
-"use strict";
-REQ_.d(EXP_, {
-A: () => _applyDecoratedDescriptor
-});
-function _applyDecoratedDescriptor(i, e, r, n, l) {
- let a = {};
- return Object.keys(n).forEach((i) => {
- a[i] = n[i];
- }), a.enumerable = !!a.enumerable, a.configurable = !!a.configurable, ("value" in a || a.initializer) && (a.writable = !0), a = r.slice().reverse().reduce((r, n) => {
- return n(i, e, r) || r;
- }, a), l && void 0 !== a.initializer && (a.value = a.initializer ? a.initializer.call(l) : void 0, a.initializer = void 0), void 0 === a.initializer ? (Object.defineProperty(i, e, a), null) : a;
-}
-
-
-},
-
-168
-(__webpack_module__, EXP_, REQ_) {
-
-"use strict";
-REQ_.d(EXP_, {
-A: () => _extends
-});
-function _extends() {
- return _extends = Object.assign ? Object.assign.bind() : function (n) {
- for (let e = 1; e < arguments.length; e++) {
- const t = arguments[e];
- for (const r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]);
- }
- return n;
- }, _extends.apply(null, arguments);
-}
-
-
-}
-
- };
-
- // The module cache
- const __webpack_module_cache__ =Object.create(null);
-
- // The require function
- function REQ_(moduleId) {
- // Check if module is in cache
- const cachedModule = __webpack_module_cache__[moduleId];
- if (cachedModule !== undefined) {
- return cachedModule.exports;
- }
- // Create a new module (and put it into the cache)
- const module = __webpack_module_cache__[moduleId] = {
- // no module.id needed
- // no module.loaded needed
- exports:Object.create(null)
- };
-
- // Execute the module function
- __webpack_modules__[moduleId](module, module.exports, REQ_);
-
- // Return the exports of the module
- return module.exports;
- }
-
-
-
- (() => {
- // getDefaultExport function for compatibility with non-harmony modules
- REQ_.n = (module) => {
- const getter = module && module.__esModule ?
- () => module.default :
- () => module;
- REQ_.d(getter, { a: getter });
- return getter;
- };
- })();
-
-
- (() => {
- // define getter functions for harmony exports
- REQ_.d = (exports, definition) => {
- for(const key in definition) {
- if(REQ_.o(definition, key) && !REQ_.o(exports, key)) {
- Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
- }
- }
- };
- })();
-
-
- (() => {
- REQ_.o = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop)
- })();
-
-
- (() => {
- // define __esModule on exports
- REQ_.r = (exports) => {
- if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
- Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
- }
- Object.defineProperty(exports, '__esModule', { value: true });
- };
- })();
-
-
-
- // startup
- // Load entry module and return exports
- REQ_(326);
- // This entry module is referenced by other modules so it can't be inlined
- const EXP_ = REQ_(732);
-
-})()
-;
+ })()
+;
\ No newline at end of file
diff --git a/js/chat/bundle.schedule-meeting.js b/js/chat/bundle.schedule-meeting.js
new file mode 100644
index 0000000000..e2822ca2b2
--- /dev/null
+++ b/js/chat/bundle.schedule-meeting.js
@@ -0,0 +1,2439 @@
+/** @file automatically generated, do not edit it. */
+"use strict";
+(self.webpackChunk_meganz_webclient = self.webpackChunk_meganz_webclient || []).push([[716],{
+
+ 8894
+(_, EXP_, REQ_) {
+
+ REQ_.d(EXP_, {
+ V: () => withDateObserver
+ });
+ const _babel_runtime_helpers_extends0__ = REQ_(8168);
+ const react1__ = REQ_(1594);
+ const react1___default = REQ_.n(react1__);
+
+
+const withDateObserver = Component => class extends react1___default().Component {
+ constructor(...args) {
+ super(...args);
+ this.listener = undefined;
+ this.state = {
+ timestamp: undefined
+ };
+ }
+ componentWillUnmount() {
+ mBroadcaster.removeListener(this.listener);
+ }
+ componentDidMount() {
+ this.listener = mBroadcaster.addListener(withDateObserver.NAMESPACE, timestamp => this.setState({
+ timestamp
+ }));
+ }
+ render() {
+ return JSX_(Component, (0,_babel_runtime_helpers_extends0__ .A)({}, this.props, {
+ timestamp: this.state.timestamp
+ }));
+ }
+};
+withDateObserver.NAMESPACE = 'meetings:onSelectDate';
+
+ },
+
+ 9290
+(_, EXP_, REQ_) {
+
+ REQ_.d(EXP_, {
+ A: () => __WEBPACK_DEFAULT_EXPORT__
+ });
+ const react0__ = REQ_(1594);
+ const react0___default = REQ_.n(react0__);
+ const _mixins_js1__ = REQ_(8264);
+ const _dateObserver2__ = REQ_(8894);
+
+
+
+class Datepicker extends react0___default().Component {
+ constructor(props) {
+ super(props);
+ this.OPTIONS = {
+ classes: 'meetings-datepicker-calendar',
+ dateFormat: '@',
+ minDate: null,
+ startDate: null,
+ selectedDates: [],
+ prevHtml: '',
+ nextHtml: '',
+ altField: null,
+ firstDay: 0,
+ autoClose: true,
+ toggleSelected: false,
+ position: 'bottom left',
+ language: {
+ daysMin: [l[8763], l[8764], l[8765], l[8766], l[8767], l[8768], l[8769]],
+ months: [l[408], l[409], l[410], l[411], l[412], l[413], l[414], l[415], l[416], l[417], l[418], l[419]],
+ monthsShort: [l[24035], l[24037], l[24036], l[24038], l[24047], l[24039], l[24040], l[24041], l[24042], l[24043], l[24044], l[24045]]
+ },
+ onSelect: dateText => {
+ const prevDate = new Date(+this.props.value);
+ const nextDate = new Date(+dateText);
+ nextDate.setHours(prevDate.getHours(), prevDate.getMinutes());
+ this.props.onSelect(nextDate.getTime());
+ mBroadcaster.sendMessage(_dateObserver2__ .V.NAMESPACE, nextDate.getTime());
+ }
+ };
+ this.domRef = react0___default().createRef();
+ this.inputRef = react0___default().createRef();
+ this.datepicker = null;
+ this.formatValue = value => {
+ if (typeof value === 'number') {
+ return time2date(value / 1000, 18);
+ }
+ return value;
+ };
+ this.OPTIONS.startDate = new Date(this.props.startDate);
+ this.OPTIONS.selectedDates = this.props.selectedDates || [this.OPTIONS.startDate];
+ this.OPTIONS.minDate = this.props.minDate ? new Date(this.props.minDate) : new Date();
+ this.OPTIONS.position = this.props.position || this.OPTIONS.position;
+ this.OPTIONS.altField = `input.${this.props.altField}`;
+ }
+ initialize() {
+ const inputRef = this.inputRef && this.inputRef.current;
+ if (inputRef) {
+ let _this$props$onMount, _this$props;
+ $(inputRef).datepicker(this.OPTIONS);
+ this.datepicker = $(inputRef).data('datepicker');
+ (_this$props$onMount = (_this$props = this.props).onMount) == null || _this$props$onMount.call(_this$props, this.datepicker);
+ }
+ }
+ componentWillUnmount() {
+ if (this.domRef && this.domRef.current) {
+ $(this.domRef.current).unbind(`keyup.${Datepicker.NAMESPACE}`);
+ }
+ }
+ componentDidMount() {
+ M.require('datepicker_js').done(() => this.initialize());
+ if (this.domRef && this.domRef.current) {
+ $(this.domRef.current).rebind(`keyup.${Datepicker.NAMESPACE}`, ({
+ keyCode
+ }) => {
+ if (keyCode === 13) {
+ this.datepicker.hide();
+ return false;
+ }
+ });
+ }
+ }
+ render() {
+ const {
+ NAMESPACE
+ } = Datepicker;
+ const {
+ value,
+ name,
+ className,
+ placeholder,
+ isLoading,
+ onFocus,
+ onChange,
+ onBlur
+ } = this.props;
+ const formattedValue = this.formatValue(value);
+ return JSX_("div", {
+ ref: this.domRef,
+ className: NAMESPACE
+ }, JSX_("div", {
+ className: "mega-input datepicker-input"
+ }, JSX_("input", {
+ ref: this.inputRef,
+ type: "text",
+ name,
+ className: `
+ dialog-input
+ ${className || ''}
+ `,
+ autoComplete: "off",
+ disabled: isLoading,
+ placeholder: placeholder || '',
+ value: formattedValue,
+ onFocus: ev => onFocus == null ? void 0 : onFocus(ev),
+ onChange: ev => onChange == null ? void 0 : onChange(ev),
+ onBlur: ev => onBlur == null ? void 0 : onBlur(ev)
+ }), JSX_("i", {
+ className: "sprite-fm-mono icon-calendar1",
+ onClick: isLoading ? null : () => {
+ if (this.datepicker) {
+ let _this$inputRef$curren;
+ this.datepicker.show();
+ (_this$inputRef$curren = this.inputRef.current) == null || _this$inputRef$curren.focus();
+ }
+ }
+ })));
+ }
+}
+Datepicker.NAMESPACE = 'meetings-datepicker';
+ const __WEBPACK_DEFAULT_EXPORT__ = (0,_mixins_js1__ .Zz)(_dateObserver2__ .V)(Datepicker);
+
+ },
+
+ 9811
+(_, EXP_, REQ_) {
+
+ REQ_.d(EXP_, {
+ c: () => DateTime
+ });
+ const react0__ = REQ_(1594);
+ const react0___default = REQ_.n(react0__);
+ const _helpers_jsx1__ = REQ_(6521);
+ const _datepicker_jsx2__ = REQ_(9290);
+ const _select_jsx3__ = REQ_(3448);
+
+
+
+
+class DateTime extends react0___default().Component {
+ constructor(...args) {
+ super(...args);
+ this.state = {
+ datepickerRef: undefined,
+ manualDateInput: '',
+ manualTimeInput: '',
+ initialDate: ''
+ };
+ this.handleChange = ev => {
+ const {
+ onChange
+ } = this.props;
+ const {
+ datepickerRef,
+ initialDate
+ } = this.state;
+ if (!datepickerRef) {
+ return;
+ }
+ const {
+ value
+ } = ev.target;
+ const date = (0,_helpers_jsx1__ .XH)(value);
+ const timestamp = date.valueOf();
+ const dateObj = new Date(timestamp);
+ dateObj.setHours(initialDate.getHours(), initialDate.getMinutes());
+ datepickerRef.selectedDates = [dateObj];
+ datepickerRef.currentDate = dateObj;
+ datepickerRef.nav._render();
+ datepickerRef.views.days._render();
+ onChange == null || onChange(value);
+ this.setState({
+ manualDateInput: dateObj.getTime()
+ });
+ };
+ }
+ render() {
+ const {
+ name,
+ startDate,
+ altField,
+ value,
+ minDate,
+ filteredTimeIntervals,
+ label,
+ isLoading,
+ onMount,
+ onSelectDate,
+ onSelectTime,
+ onBlur
+ } = this.props;
+ return JSX_(react0___default().Fragment, null, label && JSX_("span", null, label), JSX_(_datepicker_jsx2__ .A, {
+ name: `${_datepicker_jsx2__ .A.NAMESPACE}-${name}`,
+ className: isLoading ? 'disabled' : '',
+ isLoading,
+ startDate,
+ altField: `${_select_jsx3__ .A.NAMESPACE}-${altField}`,
+ value,
+ minDate,
+ onMount: datepickerRef => this.setState({
+ datepickerRef
+ }, () => onMount(datepickerRef)),
+ onSelect: onSelectDate,
+ onFocus: ({
+ target
+ }) => {
+ this.setState({
+ manualDateInput: undefined,
+ manualTimeInput: undefined,
+ initialDate: new Date(value)
+ }, () => target.select());
+ },
+ onChange: this.handleChange,
+ onBlur: () => onBlur(this.state.manualDateInput)
+ }), JSX_(_select_jsx3__ .A, {
+ name: `${_select_jsx3__ .A.NAMESPACE}-${altField}`,
+ className: isLoading ? 'disabled' : '',
+ isLoading,
+ typeable: true,
+ options: filteredTimeIntervals,
+ value: (() => typeof value === 'number' ? value : this.state.datepickerRef.currentDate.getTime())(),
+ format: toLocaleTime,
+ onSelect: onSelectTime,
+ onChange: () => false,
+ onBlur: timestamp => {
+ if (timestamp) {
+ onSelectTime({
+ value: timestamp
+ });
+ }
+ }
+ }));
+ }
+}
+
+ },
+
+ 4156
+(_, EXP_, REQ_) {
+
+REQ_.r(EXP_);
+ REQ_.d(EXP_, {
+ "default": () => Edit
+ });
+ const _babel_runtime_helpers_extends0__ = REQ_(8168);
+ const react1__ = REQ_(1594);
+ const react1___default = REQ_.n(react1__);
+ const _mixins_js2__ = REQ_(8264);
+ const _utils_jsx3__ = REQ_(1497);
+ const _ui_modalDialogs_jsx4__ = REQ_(8120);
+ const _ui_utils_jsx5__ = REQ_(6411);
+ const _link_jsx6__ = REQ_(4649);
+ const _datetime_jsx7__ = REQ_(9811);
+ const _helpers_jsx8__ = REQ_(6521);
+ const _button_jsx9__ = REQ_(6740);
+
+
+
+
+
+
+
+
+
+
+class Edit extends _mixins_js2__ .w9 {
+ constructor(props) {
+ super(props);
+ this.occurrenceRef = null;
+ this.datepickerRefs = [];
+ this.interval = ChatRoom.SCHEDULED_MEETINGS_INTERVAL;
+ this.incomingCallListener = 'onPrepareIncomingCallDialog.recurringEdit';
+ this.state = {
+ startDateTime: undefined,
+ endDateTime: undefined,
+ isDirty: false,
+ closeDialog: false,
+ overlayed: false
+ };
+ this.onStartDateSelect = startDateTime => {
+ this.setState({
+ startDateTime,
+ isDirty: true
+ }, () => {
+ this.datepickerRefs.endDateTime.selectDate(new Date(startDateTime + this.interval));
+ });
+ };
+ this.onEndDateSelect = endDateTime => {
+ this.setState({
+ endDateTime,
+ isDirty: true
+ }, () => {
+ const {
+ startDateTime,
+ endDateTime
+ } = this.state;
+ if (endDateTime < startDateTime) {
+ if (endDateTime < Date.now()) {
+ return this.setState({
+ endDateTime: startDateTime + this.interval
+ });
+ }
+ this.handleTimeSelect({
+ startDateTime: endDateTime - this.interval
+ });
+ }
+ });
+ };
+ this.handleTimeSelect = ({
+ startDateTime,
+ endDateTime
+ }) => {
+ startDateTime = startDateTime || this.state.startDateTime;
+ endDateTime = endDateTime || this.state.endDateTime;
+ this.setState(state => {
+ return {
+ startDateTime: endDateTime <= state.startDateTime ? endDateTime - this.interval : startDateTime,
+ endDateTime: startDateTime >= state.endDateTime ? startDateTime + this.interval : endDateTime,
+ isDirty: true
+ };
+ });
+ };
+ const {
+ scheduledMeeting,
+ occurrenceId
+ } = this.props;
+ this.occurrenceRef = scheduledMeeting.occurrences[occurrenceId];
+ if (this.occurrenceRef) {
+ this.state.startDateTime = this.occurrenceRef.start;
+ this.state.endDateTime = this.occurrenceRef.end;
+ }
+ }
+ componentWillUnmount() {
+ super.componentWillUnmount();
+ if (this.incomingCallListener) {
+ megaChat.off(this.incomingCallListener);
+ }
+ if ($.dialog === _utils_jsx3__ .oK) {
+ closeDialog();
+ }
+ }
+ componentDidMount() {
+ super.componentDidMount();
+ M.safeShowDialog(_utils_jsx3__ .oK, () => {
+ if (!this.isMounted()) {
+ throw Error(`Edit dialog: component not mounted.`);
+ }
+ megaChat.rebind(this.incomingCallListener, () => {
+ if (this.isMounted()) {
+ this.setState({
+ overlayed: true,
+ closeDialog: false
+ });
+ megaChat.plugins.callManager2.rebind('onRingingStopped.recurringEdit', () => {
+ megaChat.plugins.callManager2.off('onRingingStopped.recurringEdit');
+ this.setState({
+ overlayed: false
+ });
+ fm_showoverlay();
+ });
+ }
+ });
+ return $(`#${_utils_jsx3__ .CU}`);
+ });
+ }
+ componentDidUpdate(prevProps) {
+ if (prevProps.callExpanded && !this.props.callExpanded) {
+ if (!$.dialog) {
+ M.safeShowDialog(_utils_jsx3__ .oK, `#${_utils_jsx3__ .CU}`);
+ }
+ fm_showoverlay();
+ this.setState({
+ closeDialog: false
+ });
+ }
+ if (!prevProps.callExpanded && this.props.callExpanded) {
+ this.setState({
+ closeDialog: false
+ });
+ }
+ }
+ render() {
+ const {
+ chatRoom,
+ callExpanded,
+ onClose
+ } = this.props;
+ const {
+ startDateTime,
+ endDateTime,
+ isDirty,
+ closeDialog,
+ overlayed
+ } = this.state;
+ const dialogClasses = ['fluid'];
+ if (closeDialog) {
+ dialogClasses.push('with-confirmation-dialog');
+ }
+ if (callExpanded || overlayed) {
+ dialogClasses.push('hidden');
+ }
+ const withUpgrade = !u_attr.p && endDateTime - startDateTime > 36e5;
+ if (withUpgrade) {
+ dialogClasses.push('upgrade');
+ }
+ return JSX_(_ui_modalDialogs_jsx4__ .A.ModalDialog, (0,_babel_runtime_helpers_extends0__ .A)({}, this.state, {
+ id: _utils_jsx3__ .CU,
+ className: dialogClasses.join(' '),
+ dialogName: _utils_jsx3__ .oK,
+ dialogType: "main",
+ onClose: () => {
+ return isDirty ? this.setState({
+ closeDialog: true
+ }) : onClose();
+ }
+ }), JSX_("header", null, JSX_("h2", null, l.edit_meeting_title)), JSX_("div", {
+ className: "fm-dialog-body"
+ }, JSX_(_utils_jsx3__ .fI, null, JSX_("div", {
+ className: "mega-banner body recurring-edit-banner"
+ }, JSX_("div", {
+ className: "cell"
+ }, (0,_ui_utils_jsx5__ .lI)(l.scheduled_edit_occurrence_note, '[A]', _link_jsx6__ .A, {
+ onClick: () => {
+ onClose();
+ megaChat.trigger(megaChat.plugins.meetingsManager.EVENTS.EDIT, chatRoom);
+ }
+ })))), JSX_(_utils_jsx3__ .fI, {
+ className: "start-aligned"
+ }, JSX_(_utils_jsx3__ .VP, null, JSX_("i", {
+ className: "sprite-fm-mono icon-recents-filled"
+ })), JSX_("div", {
+ className: "schedule-date-container"
+ }, JSX_(_datetime_jsx7__ .c, {
+ name: "startDateTime",
+ altField: "startTime",
+ datepickerRef: this.datepickerRefs.startDateTime,
+ startDate: startDateTime,
+ value: startDateTime,
+ filteredTimeIntervals: (0,_helpers_jsx8__ .a4)(startDateTime),
+ label: l.schedule_start_date,
+ onMount: datepicker => {
+ this.datepickerRefs.startDateTime = datepicker;
+ },
+ onSelectDate: startDateTime => this.onStartDateSelect(startDateTime),
+ onSelectTime: ({
+ value: startDateTime
+ }) => this.handleTimeSelect({
+ startDateTime
+ }),
+ onChange: value => this.setState({
+ startDateTime: value
+ }),
+ onBlur: timestamp => {
+ if (timestamp) {
+ timestamp = timestamp < Date.now() ? this.occurrenceRef.start : timestamp;
+ this.onStartDateSelect(timestamp);
+ }
+ }
+ }), JSX_(_datetime_jsx7__ .c, {
+ name: "endDateTime",
+ altField: "endTime",
+ datepickerRef: this.datepickerRefs.endDateTime,
+ startDate: endDateTime,
+ value: endDateTime,
+ filteredTimeIntervals: (0,_helpers_jsx8__ .a4)(endDateTime, startDateTime),
+ label: l.schedule_end_date,
+ onMount: datepicker => {
+ this.datepickerRefs.endDateTime = datepicker;
+ },
+ onSelectDate: endDateTime => this.onEndDateSelect(endDateTime),
+ onSelectTime: ({
+ value: endDateTime
+ }) => this.handleTimeSelect({
+ endDateTime
+ }),
+ onChange: timestamp => this.setState({
+ endDateTime: timestamp
+ }),
+ onBlur: timestamp => timestamp && this.onEndDateSelect(timestamp)
+ }))), withUpgrade && JSX_(_utils_jsx3__ .dh, {
+ onUpgradeClicked: () => {
+ onClose();
+ loadSubPage('pro');
+ eventlog(500257);
+ }
+ })), JSX_("footer", null, JSX_("div", {
+ className: "footer-container"
+ }, JSX_(_button_jsx9__ .A, {
+ className: "mega-button positive",
+ onClick: () => {
+ const {
+ startDateTime,
+ endDateTime
+ } = this.state;
+ if (startDateTime !== this.occurrenceRef.start || endDateTime !== this.occurrenceRef.end) {
+ delay('chat-event-sm-edit-meeting', () => eventlog(99923));
+ this.occurrenceRef.update(startDateTime, endDateTime);
+ }
+ onClose();
+ }
+ }, JSX_("span", null, l.update_meeting_button)))), !(overlayed || callExpanded) && closeDialog && JSX_(_utils_jsx3__ .pD, {
+ onToggle: () => this.setState({
+ closeDialog: false
+ }),
+ onClose
+ }));
+ }
+}
+
+ },
+
+ 8389
+(_, EXP_, REQ_) {
+
+// ESM COMPAT FLAG
+REQ_.r(EXP_);
+
+// EXPORTS
+REQ_.d(EXP_, {
+ "default": () => Schedule
+});
+
+// EXTERNAL MODULE: ./node_modules/@babel/runtime/helpers/esm/extends.js
+const esm_extends = REQ_(8168);
+// EXTERNAL MODULE: external "React"
+const external_React_ = REQ_(1594);
+const REaCt = REQ_.n(external_React_);
+// EXTERNAL MODULE: ./js/chat/mixins.js
+const mixins = REQ_(8264);
+// EXTERNAL MODULE: ./js/ui/modalDialogs.jsx + 1 modules
+const modalDialogs = REQ_(8120);
+// EXTERNAL MODULE: ./js/chat/ui/meetings/button.jsx
+const meetings_button = REQ_(6740);
+// EXTERNAL MODULE: ./js/ui/perfectScrollbar.jsx
+const perfectScrollbar = REQ_(1301);
+// EXTERNAL MODULE: ./js/chat/ui/contacts.jsx
+const ui_contacts = REQ_(8022);
+;// ./js/chat/ui/meetings/schedule/invite.jsx
+
+
+
+
+class Invite extends mixins.w9 {
+ constructor(props) {
+ super(props);
+ this.domRef = REaCt().createRef();
+ this.wrapperRef = REaCt().createRef();
+ this.inputRef = REaCt().createRef();
+ this.state = {
+ value: '',
+ expanded: false,
+ loading: true,
+ frequents: [],
+ frequentsInitial: [],
+ contacts: [],
+ contactsInitial: [],
+ selected: []
+ };
+ this.handleMousedown = ({
+ target
+ }) => this.domRef && this.domRef.current && this.domRef.current.contains(target) ? null : this.setState({
+ expanded: false
+ });
+ this.getSortedContactsList = frequents => {
+ const filteredContacts = [];
+ M.u.forEach(contact => {
+ if (contact.c === 1 && !frequents.includes(contact.u) && !this.state.selected.includes(contact.u)) {
+ filteredContacts.push(contact);
+ }
+ });
+ const sortFn = M.getSortByNameFn2(1);
+ filteredContacts.sort((a, b) => sortFn(a, b));
+ return filteredContacts;
+ };
+ this.doMatch = (value, collection) => {
+ value = value.toLowerCase();
+ return collection.filter(contact => {
+ contact = typeof contact === 'string' ? M.getUserByHandle(contact) : contact;
+ const name = M.getNameByHandle(contact.u).toLowerCase();
+ const email = contact.m && contact.m.toLowerCase();
+ return name.includes(value) || email.includes(value);
+ });
+ };
+ this.handleSearch = this.handleSearch.bind(this);
+ this.state.selected = this.props.participants || [];
+ }
+ reinitializeWrapper() {
+ const wrapperRef = this.wrapperRef && this.wrapperRef.current;
+ if (wrapperRef) {
+ wrapperRef.reinitialise();
+ wrapperRef.scrollToY(0);
+ }
+ }
+ buildContactsList() {
+ megaChat.getFrequentContacts().then(frequentContacts => {
+ if (this.isMounted()) {
+ const frequents = frequentContacts.slice(-ui_contacts.lO).map(c => c.userId);
+ const contacts = this.getSortedContactsList(frequents);
+ this.setState({
+ frequents,
+ frequentsInitial: frequents,
+ contacts,
+ contactsInitial: contacts,
+ loading: false
+ });
+ }
+ });
+ }
+ handleSearch(ev) {
+ const {
+ value
+ } = ev.target;
+ const searching = value.length >= 2;
+ const frequents = searching ? this.doMatch(value, this.state.frequentsInitial) : this.state.frequentsInitial;
+ const contacts = searching ? this.doMatch(value, this.state.contactsInitial) : this.state.contactsInitial;
+ this.setState({
+ value,
+ contacts,
+ frequents
+ }, () => this.reinitializeWrapper());
+ }
+ handleSelect({
+ userHandle,
+ expanded = false
+ }) {
+ this.setState(state => ({
+ value: '',
+ expanded,
+ selected: state.selected.includes(userHandle) ? state.selected.filter(c => c !== userHandle) : [...state.selected, userHandle]
+ }), () => {
+ let _this$inputRef$curren;
+ this.props.onSelect(this.state.selected);
+ this.buildContactsList();
+ this.reinitializeWrapper();
+ (_this$inputRef$curren = this.inputRef.current) == null || _this$inputRef$curren.focus();
+ });
+ }
+ getFilteredContacts(contacts) {
+ if (contacts && contacts.length) {
+ return contacts.map(contact => {
+ contact = contact instanceof MegaDataMap ? contact : M.u[contact];
+ return this.state.selected.includes(contact.u) ? null : JSX_("div", {
+ key: contact.u,
+ className: "invite-section-item",
+ onClick: () => {
+ this.handleSelect({
+ userHandle: contact.u,
+ expanded: true
+ });
+ }
+ }, JSX_(ui_contacts.eu, {
+ contact
+ }), JSX_("div", {
+ className: "invite-item-data"
+ }, JSX_("div", {
+ className: "invite-item-name"
+ }, JSX_(ui_contacts.uA, {
+ overflow: true,
+ simpletip: {
+ offset: 10
+ },
+ contact
+ })), JSX_("div", {
+ className: "invite-item-mail"
+ }, contact.m)));
+ });
+ }
+ return null;
+ }
+ renderContent() {
+ const {
+ frequents,
+ contacts,
+ selected
+ } = this.state;
+ const hasMoreFrequents = frequents.length && frequents.some(h => !selected.includes(h));
+ const $$SECTION = (title, children) => JSX_("div", {
+ className: "invite-section"
+ }, JSX_("div", {
+ className: "invite-section-title"
+ }, title), children && JSX_("div", {
+ className: "invite-section-list"
+ }, children));
+ if (hasMoreFrequents || contacts.length) {
+ return JSX_(perfectScrollbar.O, {
+ ref: this.wrapperRef,
+ className: "invite-scroll-wrapper",
+ options: {
+ 'suppressScrollX': true
+ }
+ }, hasMoreFrequents ? $$SECTION(l.recent_contact_label, this.getFilteredContacts(frequents)) : '', contacts.length ? $$SECTION(l.all_contact_label, this.getFilteredContacts(contacts)) : '', frequents.length === 0 && contacts.length === 0 && $$SECTION(l.invite_no_results_found, null));
+ }
+ return $$SECTION(l.invite_no_contacts_to_add, null);
+ }
+ componentWillUnmount() {
+ super.componentWillUnmount();
+ document.removeEventListener('mousedown', this.handleMousedown);
+ }
+ componentDidMount() {
+ super.componentDidMount();
+ document.addEventListener('mousedown', this.handleMousedown);
+ this.buildContactsList();
+ }
+ render() {
+ const {
+ className,
+ isLoading
+ } = this.props;
+ const {
+ value,
+ expanded,
+ loading,
+ selected
+ } = this.state;
+ return JSX_("div", {
+ ref: this.domRef,
+ className: `
+ ${Invite.NAMESPACE}
+ ${className || ''}
+ `
+ }, JSX_("div", {
+ className: "multiple-input"
+ }, JSX_("ul", {
+ className: "token-input-list-mega",
+ onClick: ({
+ target
+ }) => isLoading ? null : target.classList.contains('token-input-list-mega') && this.setState({
+ expanded: true
+ })
+ }, selected.map(handle => {
+ return JSX_("li", {
+ key: handle,
+ className: "token-input-token-mega"
+ }, JSX_("div", {
+ className: "contact-tag-item"
+ }, JSX_(ui_contacts.eu, {
+ contact: M.u[handle],
+ className: "avatar-wrapper box-avatar"
+ }), JSX_(ui_contacts.uA, {
+ contact: M.u[handle],
+ overflow: true
+ }), JSX_("i", {
+ className: "sprite-fm-mono icon-close-component",
+ onClick: () => isLoading ? null : this.handleSelect({
+ userHandle: handle
+ })
+ })));
+ }), JSX_("li", {
+ className: "token-input-input-token-mega"
+ }, JSX_("input", {
+ ref: this.inputRef,
+ type: "text",
+ name: "participants",
+ className: `${Invite.NAMESPACE}-input`,
+ disabled: isLoading,
+ autoComplete: "off",
+ placeholder: selected.length ? '' : l.schedule_participant_input,
+ value,
+ onClick: () => this.setState({
+ expanded: true
+ }),
+ onChange: this.handleSearch,
+ onKeyDown: ({
+ target,
+ keyCode
+ }) => {
+ const {
+ selected
+ } = this.state;
+ return keyCode === 8 && target.value === '' && selected.length && this.handleSelect({
+ userHandle: selected[selected.length - 1]
+ });
+ }
+ })))), loading ? null : JSX_("div", {
+ className: `mega-input-dropdown ${expanded ? '' : 'hidden'}`
+ }, this.renderContent()));
+ }
+}
+Invite.NAMESPACE = 'meetings-invite';
+// EXTERNAL MODULE: ./js/chat/ui/meetings/schedule/helpers.jsx
+const helpers = REQ_(6521);
+// EXTERNAL MODULE: ./js/chat/ui/meetings/schedule/datetime.jsx
+const datetime = REQ_(9811);
+// EXTERNAL MODULE: ./js/chat/chatRoom.jsx
+const chat_chatRoom = REQ_(7057);
+// EXTERNAL MODULE: ./js/ui/utils.jsx
+const utils = REQ_(6411);
+// EXTERNAL MODULE: ./js/chat/ui/conversations.jsx + 2 modules
+const conversations = REQ_(4904);
+// EXTERNAL MODULE: ./js/chat/ui/meetings/schedule/utils.jsx
+const schedule_utils = REQ_(1497);
+// EXTERNAL MODULE: ./js/chat/ui/meetings/schedule/datepicker.jsx
+const datepicker = REQ_(9290);
+// EXTERNAL MODULE: ./js/chat/ui/meetings/schedule/select.jsx
+const schedule_select = REQ_(3448);
+;// ./js/chat/ui/meetings/schedule/recurring.jsx
+
+
+
+
+
+
+
+
+class Recurring extends mixins.w9 {
+ constructor(props) {
+ let _Object$values$find;
+ super(props);
+ this.domRef = REaCt().createRef();
+ this.VIEWS = {
+ DAILY: 0x00,
+ WEEKLY: 0x01,
+ MONTHLY: 0x02
+ };
+ this.FREQUENCIES = {
+ DAILY: 'd',
+ WEEKLY: 'w',
+ MONTHLY: 'm'
+ };
+ this.WEEK_DAYS = {
+ MONDAY: {
+ value: 1,
+ label: l.schedule_day_control_mon
+ },
+ TUESDAY: {
+ value: 2,
+ label: l.schedule_day_control_tue
+ },
+ WEDNESDAY: {
+ value: 3,
+ label: l.schedule_day_control_wed
+ },
+ THURSDAY: {
+ value: 4,
+ label: l.schedule_day_control_thu
+ },
+ FRIDAY: {
+ value: 5,
+ label: l.schedule_day_control_fri
+ },
+ SATURDAY: {
+ value: 6,
+ label: l.schedule_day_control_sat
+ },
+ SUNDAY: {
+ value: 7,
+ label: l.schedule_day_control_sun
+ }
+ };
+ this.OFFSETS = [[l.recur_freq_offset_first_mon || '[A]first[/A][B]Monday[/B]', l.recur_freq_offset_first_tue || '[A]first[/A][B]Tuesday[/B]', l.recur_freq_offset_first_wed || '[A]first[/A][B]Wednesday[/B]', l.recur_freq_offset_first_thu || '[A]first[/A][B]Thursday[/B]', l.recur_freq_offset_first_fri || '[A]first[/A][B]Friday[/B]', l.recur_freq_offset_first_sat || '[A]first[/A][B]Saturday[/B]', l.recur_freq_offset_first_sun || '[A]first[/A][B]Sunday[/B]'], [l.recur_freq_offset_second_mon || '[A]second[/A][B]Monday[/B]', l.recur_freq_offset_second_tue || '[A]second[/A][B]Tuesday[/B]', l.recur_freq_offset_second_wed || '[A]second[/A][B]Wednesday[/B]', l.recur_freq_offset_second_thu || '[A]second[/A][B]Thursday[/B]', l.recur_freq_offset_second_fri || '[A]second[/A][B]Friday[/B]', l.recur_freq_offset_second_sat || '[A]second[/A][B]Saturday[/B]', l.recur_freq_offset_second_sun || '[A]second[/A][B]Sunday[/B]'], [l.recur_freq_offset_third_mon || '[A]third[/A][B]Monday[/B]', l.recur_freq_offset_third_tue || '[A]third[/A][B]Tuesday[/B]', l.recur_freq_offset_third_wed || '[A]third[/A][B]Wednesday[/B]', l.recur_freq_offset_third_thu || '[A]third[/A][B]Thursday[/B]', l.recur_freq_offset_third_fri || '[A]third[/A][B]Friday[/B]', l.recur_freq_offset_third_sat || '[A]third[/A][B]Saturday[/B]', l.recur_freq_offset_third_sun || '[A]third[/A][B]Sunday[/B]'], [l.recur_freq_offset_fourth_mon || '[A]fourth[/A][B]Monday[/B]', l.recur_freq_offset_fourth_tue || '[A]fourth[/A][B]Tuesday[/B]', l.recur_freq_offset_fourth_wed || '[A]fourth[/A][B]Wednesday[/B]', l.recur_freq_offset_fourth_thu || '[A]fourth[/A][B]Thursday[/B]', l.recur_freq_offset_fourth_fri || '[A]fourth[/A][B]Friday[/B]', l.recur_freq_offset_fourth_sat || '[A]fourth[/A][B]Saturday[/B]', l.recur_freq_offset_fourth_sun || '[A]fourth[/A][B]Sunday[/B]'], [l.recur_freq_offset_fifth_mon || '[A]fifth[/A][B]Monday[/B]', l.recur_freq_offset_fifth_tue || '[A]fifth[/A][B]Tuesday[/B]', l.recur_freq_offset_fifth_wed || '[A]fifth[/A][B]Wednesday[/B]', l.recur_freq_offset_fifth_thu || '[A]fifth[/A][B]Thursday[/B]', l.recur_freq_offset_fifth_fri || '[A]fifth[/A][B]Friday[/B]', l.recur_freq_offset_fifth_sat || '[A]fifth[/A][B]Saturday[/B]', l.recur_freq_offset_fifth_sun || '[A]fifth[/A][B]Sunday[/B]']];
+ this.OFFSET_POS_REGEX = /\[A]([^[]+)\[\/A]/;
+ this.OFFSET_DAY_REGEX = /\[B]([^[]+)\[\/B]/;
+ this.MONTH_RULES = {
+ DAY: 'day',
+ OFFSET: 'offset'
+ };
+ this.initialEnd = (0,helpers.PS)(this.props.startDateTime, 6);
+ this.initialWeekDays = Object.values(this.WEEK_DAYS).map(d => d.value);
+ this.initialMonthDay = this.props.startDateTime ? new Date(this.props.startDateTime).getDate() : undefined;
+ this.state = {
+ view: this.VIEWS.DAILY,
+ frequency: this.FREQUENCIES.DAILY,
+ end: this.initialEnd,
+ prevEnd: undefined,
+ interval: 0,
+ weekDays: this.initialWeekDays,
+ monthRule: this.MONTH_RULES.DAY,
+ monthDays: [this.initialMonthDay],
+ offset: {
+ value: 1,
+ weekDay: 1
+ },
+ monthDaysWarning: this.initialMonthDay > 28
+ };
+ this.toggleView = (view, frequency, state) => this.props.isLoading ? null : this.setState({
+ view,
+ frequency,
+ ...state
+ });
+ this.MonthDaySelect = ({
+ offset
+ }) => {
+ const dayIdx = (offset && offset.weekDay || 1) - 1;
+ const posIdx = (offset && offset.value || 1) - 1;
+ const dayValues = this.OFFSETS[posIdx].map((part, idx) => ({
+ value: idx + 1,
+ label: this.OFFSET_DAY_REGEX.exec(part)[1]
+ }));
+ const posValues = [];
+ for (let i = 0; i < this.OFFSETS.length; i++) {
+ posValues.push({
+ value: i + 1,
+ label: this.OFFSET_POS_REGEX.exec(this.OFFSETS[i][dayIdx])[1]
+ });
+ }
+ const posFirst = this.OFFSETS[posIdx][dayIdx].indexOf('[A]') < this.OFFSETS[posIdx][dayIdx].indexOf('[B]');
+ const pos = JSX_(schedule_select.A, {
+ name: "recurring-offset-value",
+ className: "inline",
+ icon: true,
+ value: posValues[posIdx].label,
+ isLoading: this.props.isLoading,
+ options: posValues,
+ onSelect: option => {
+ this.setState(state => ({
+ monthRule: this.MONTH_RULES.OFFSET,
+ offset: {
+ value: option.value,
+ weekDay: state.offset.weekDay || this.WEEK_DAYS.MONDAY.value
+ }
+ }));
+ }
+ });
+ return JSX_(REaCt().Fragment, null, posFirst && pos, JSX_(schedule_select.A, {
+ name: "recurring-offset-day",
+ className: "inline",
+ icon: true,
+ value: dayValues[dayIdx].label,
+ isLoading: this.props.isLoading,
+ options: dayValues,
+ onSelect: option => {
+ this.setState(state => ({
+ monthRule: this.MONTH_RULES.OFFSET,
+ offset: {
+ value: state.offset.value || 1,
+ weekDay: option.value
+ }
+ }));
+ }
+ }), !posFirst && pos);
+ };
+ this.IntervalSelect = () => {
+ const {
+ interval,
+ view
+ } = this.state;
+ return JSX_("div", {
+ className: "mega-input inline recurring-interval"
+ }, JSX_(schedule_select.A, {
+ name: `${Recurring.NAMESPACE}-interval`,
+ value: interval > 0 ? interval : 1,
+ icon: true,
+ isLoading: this.props.isLoading,
+ options: [...Array(view === this.VIEWS.WEEKLY ? 52 : 12).keys()].map(value => {
+ value += 1;
+ return {
+ value,
+ label: value
+ };
+ }),
+ onSelect: ({
+ value
+ }) => {
+ this.setState({
+ interval: value === 1 ? 0 : value
+ });
+ }
+ }));
+ };
+ const {
+ chatRoom,
+ startDateTime
+ } = this.props;
+ const weekDay = new Date(startDateTime).getDay();
+ this.state.offset.weekDay = ((_Object$values$find = Object.values(this.WEEK_DAYS).find(d => d.value === weekDay)) == null ? void 0 : _Object$values$find.value) || this.WEEK_DAYS.SUNDAY.value;
+ if (chatRoom && chatRoom.scheduledMeeting && chatRoom.scheduledMeeting.isRecurring) {
+ const {
+ frequency,
+ interval,
+ end,
+ weekDays,
+ monthDays,
+ offset
+ } = chatRoom.scheduledMeeting.recurring;
+ this.state.view = frequency === 'd' ? this.VIEWS.DAILY : frequency === 'w' ? this.VIEWS.WEEKLY : this.VIEWS.MONTHLY;
+ this.state.frequency = frequency;
+ this.state.end = end;
+ this.state.interval = interval;
+ this.state.weekDays = weekDays && weekDays.length ? weekDays : this.initialWeekDays;
+ this.state.monthRule = monthDays && monthDays.length ? this.MONTH_RULES.DAY : this.MONTH_RULES.OFFSET;
+ this.state.monthDays = monthDays && monthDays.length ? [monthDays[0]] : [this.initialMonthDay];
+ this.state.offset = offset && Object.keys(offset).length ? offset : this.state.offset;
+ }
+ }
+ getFormattedState(state) {
+ const {
+ frequency,
+ end,
+ interval,
+ weekDays,
+ monthRule,
+ monthDays,
+ offset
+ } = state;
+ switch (true) {
+ case frequency === this.FREQUENCIES.DAILY:
+ return {
+ frequency,
+ end,
+ weekDays
+ };
+ case frequency === this.FREQUENCIES.WEEKLY:
+ return {
+ frequency,
+ end,
+ ...interval && {
+ interval
+ },
+ weekDays
+ };
+ case frequency === this.FREQUENCIES.MONTHLY:
+ return {
+ frequency,
+ end,
+ ...interval && {
+ interval
+ },
+ ...monthRule === this.MONTH_RULES.DAY ? {
+ monthDays
+ } : {
+ offset: [[offset.value, offset.weekDay]]
+ }
+ };
+ }
+ }
+ renderDayControls() {
+ const {
+ weekDays,
+ view
+ } = this.state;
+ const handleWeeklySelection = (weekDay, remove) => {
+ this.setState(state => {
+ if (remove) {
+ return {
+ weekDays: state.weekDays.length === 1 ? state.weekDays : state.weekDays.filter(d => d !== weekDay)
+ };
+ }
+ return {
+ weekDays: [...state.weekDays, weekDay]
+ };
+ }, () => {
+ const {
+ weekDays
+ } = this.state;
+ if (weekDays.length === Object.keys(this.WEEK_DAYS).length) {
+ this.toggleView(this.VIEWS.DAILY, this.FREQUENCIES.DAILY);
+ }
+ });
+ };
+ const handleDailySelection = weekDay => {
+ this.toggleView(this.VIEWS.WEEKLY, this.FREQUENCIES.WEEKLY, {
+ weekDays: weekDays.filter(d => d !== weekDay)
+ });
+ };
+ return JSX_("div", {
+ className: "recurring-field-row"
+ }, Object.values(this.WEEK_DAYS).map(({
+ value,
+ label
+ }) => {
+ const isCurrentlySelected = weekDays.includes(value);
+ return JSX_(meetings_button.A, {
+ key: value,
+ className: `
+ mega-button
+ action
+ recurring-toggle-button
+ ${isCurrentlySelected ? 'active' : ''}
+ ${weekDays.length === 1 && isCurrentlySelected ? 'disabled' : ''}
+ `,
+ onClick: this.props.isLoading ? null : () => {
+ if (view === this.VIEWS.WEEKLY) {
+ return handleWeeklySelection(value, isCurrentlySelected);
+ }
+ return handleDailySelection(value);
+ }
+ }, label);
+ }));
+ }
+ renderIntervalControls() {
+ const {
+ view,
+ interval
+ } = this.state;
+ return JSX_("div", {
+ className: "recurring-field-row"
+ }, (0,utils.lI)(mega.icu.format(view === this.VIEWS.MONTHLY ? l.recur_rate_monthly : l.recur_rate_weekly, interval > 0 ? interval : 1), "[S]", this.IntervalSelect));
+ }
+ renderEndControls() {
+ const {
+ isLoading,
+ onMount
+ } = this.props;
+ const {
+ end,
+ prevEnd
+ } = this.state;
+ return JSX_("div", {
+ className: "recurring-field-row"
+ }, JSX_("div", {
+ className: "recurring-title-heading"
+ }, l.recurring_ends), JSX_("div", {
+ className: "recurring-radio-buttons"
+ }, JSX_("div", {
+ className: "recurring-label-wrap"
+ }, JSX_("div", {
+ className: `
+ uiTheme
+ ${end ? 'radioOff' : 'radioOn'}
+ `
+ }, JSX_("input", {
+ type: "radio",
+ name: `${Recurring.NAMESPACE}-radio-end`,
+ disabled: isLoading,
+ className: `
+ uiTheme
+ ${end ? 'radioOff' : 'radioOn'}
+ `,
+ onChange: () => {
+ this.setState(state => ({
+ end: undefined,
+ prevEnd: state.end || state.prevEnd
+ }));
+ }
+ })), JSX_("div", {
+ className: "radio-txt"
+ }, JSX_("span", {
+ className: "recurring-radio-label",
+ onClick: () => isLoading ? null : this.setState(state => ({
+ end: undefined,
+ prevEnd: state.end || state.prevEnd
+ }))
+ }, l.recurring_never))), JSX_("div", {
+ className: "recurring-label-wrap"
+ }, JSX_("div", {
+ className: `
+ uiTheme
+ ${end ? 'radioOn' : 'radioOff'}
+ `
+ }, JSX_("input", {
+ type: "radio",
+ name: `${Recurring.NAMESPACE}-radio-end`,
+ disabled: isLoading,
+ className: `
+ uiTheme
+ ${end ? 'radioOn' : 'radioOff'}
+ `,
+ onChange: () => isLoading ? null : this.setState({
+ end: prevEnd || this.initialEnd
+ })
+ })), JSX_("div", {
+ className: "radio-txt"
+ }, JSX_("span", {
+ className: "recurring-radio-label",
+ onClick: () => isLoading || end ? null : this.setState({
+ end: prevEnd || this.initialEnd
+ })
+ }, l.recurring_on), JSX_(datepicker.A, {
+ name: `${Recurring.NAMESPACE}-endDateTime`,
+ position: "top left",
+ startDate: end || this.initialEnd,
+ selectedDates: [new Date(end)],
+ isLoading,
+ value: end || prevEnd || '',
+ placeholder: time2date(end || prevEnd || this.initialEnd / 1000, 18),
+ onMount,
+ onSelect: timestamp => this.setState({
+ end: timestamp
+ }, () => this.safeForceUpdate())
+ })))));
+ }
+ renderDaily() {
+ return JSX_("div", {
+ className: `${Recurring.NAMESPACE}-daily`
+ }, this.renderDayControls(), this.renderEndControls());
+ }
+ renderWeekly() {
+ return JSX_("div", {
+ className: `${Recurring.NAMESPACE}-weekly`
+ }, this.renderIntervalControls(), this.renderDayControls(), this.renderEndControls());
+ }
+ renderMonthly() {
+ const {
+ isLoading
+ } = this.props;
+ const {
+ monthRule,
+ monthDays,
+ monthDaysWarning,
+ offset
+ } = this.state;
+ return JSX_("div", {
+ className: `${Recurring.NAMESPACE}-monthly`
+ }, this.renderIntervalControls(), JSX_("div", {
+ className: "recurring-field-row"
+ }, JSX_("div", {
+ className: "recurring-radio-buttons",
+ onClick: isLoading ? null : ev => {
+ const {
+ name,
+ value
+ } = ev.target;
+ if (name === `${Recurring.NAMESPACE}-radio-monthRule`) {
+ this.setState({
+ monthRule: value
+ });
+ }
+ }
+ }, JSX_("div", {
+ className: "recurring-label-wrap"
+ }, JSX_("div", {
+ className: `
+ uiTheme
+ ${monthRule === 'day' ? 'radioOn' : 'radioOff'}
+ `
+ }, JSX_("input", {
+ type: "radio",
+ name: `${Recurring.NAMESPACE}-radio-monthRule`,
+ value: "day",
+ disabled: isLoading,
+ className: `
+ uiTheme
+ ${monthRule === 'day' ? 'radioOn' : 'radioOff'}
+ `
+ })), JSX_("div", {
+ className: "radio-txt"
+ }, JSX_("span", {
+ className: "recurring-radio-label",
+ onClick: () => isLoading ? null : this.setState({
+ monthRule: this.MONTH_RULES.DAY
+ })
+ }, l.recurring_frequency_day), JSX_("div", {
+ className: "mega-input inline recurring-day"
+ }, JSX_(schedule_select.A, {
+ name: `${Recurring.NAMESPACE}-monthDay`,
+ icon: true,
+ value: monthDays[0],
+ isLoading,
+ options: [...Array(31).keys()].map(value => {
+ value += 1;
+ return {
+ value,
+ label: value
+ };
+ }),
+ onSelect: ({
+ value
+ }) => {
+ this.setState({
+ monthRule: this.MONTH_RULES.DAY,
+ monthDays: [value],
+ monthDaysWarning: value > 28
+ });
+ }
+ })))), monthDaysWarning && JSX_("div", {
+ className: "recurring-label-wrap"
+ }, JSX_("div", {
+ className: "mega-banner body with-btn"
+ }, JSX_("div", {
+ className: "green-notification cell text-cell"
+ }, JSX_("div", {
+ className: "versioning-body-text"
+ }, mega.icu.format(l.recurring_monthdays_warning, monthDays[0]))))), JSX_("div", {
+ className: "recurring-label-wrap"
+ }, JSX_("div", {
+ className: `
+ uiTheme
+ ${monthRule === this.MONTH_RULES.OFFSET ? 'radioOn' : 'radioOff'}
+ `
+ }, JSX_("input", {
+ type: "radio",
+ name: `${Recurring.NAMESPACE}-radio-monthRule`,
+ value: "offset",
+ disabled: isLoading,
+ className: `
+ uiTheme
+ ${monthRule === this.MONTH_RULES.OFFSET ? 'radioOn' : 'radioOff'}
+ `
+ })), JSX_("div", {
+ className: "radio-txt"
+ }, JSX_(this.MonthDaySelect, {
+ offset
+ }))))), this.renderEndControls());
+ }
+ renderNavigation(view) {
+ return JSX_(REaCt().Fragment, null, JSX_(meetings_button.A, {
+ className: `
+ mega-button
+ action
+ recurring-nav-button
+ ${view === this.VIEWS.DAILY ? 'active' : ''}
+ `,
+ onClick: () => this.toggleView(this.VIEWS.DAILY, this.FREQUENCIES.DAILY)
+ }, l.recurring_daily), JSX_(meetings_button.A, {
+ className: `
+ mega-button
+ action
+ recurring-nav-button
+ ${view === this.VIEWS.WEEKLY ? 'active' : ''}
+ `,
+ onClick: () => this.toggleView(this.VIEWS.WEEKLY, this.FREQUENCIES.WEEKLY)
+ }, l.recurring_weekly), JSX_(meetings_button.A, {
+ className: `
+ mega-button
+ action
+ recurring-nav-button
+ ${view === this.VIEWS.MONTHLY ? 'active' : ''}
+ `,
+ onClick: () => this.toggleView(this.VIEWS.MONTHLY, this.FREQUENCIES.MONTHLY)
+ }, l.recurring_monthly));
+ }
+ renderContent(view) {
+ switch (view) {
+ case this.VIEWS.DAILY:
+ return this.renderDaily();
+ case this.VIEWS.WEEKLY:
+ return this.renderWeekly();
+ case this.VIEWS.MONTHLY:
+ return this.renderMonthly();
+ }
+ }
+ UNSAFE_componentWillUpdate(nextProps, nextState) {
+ if (this.state.view !== this.VIEWS.DAILY && nextState.view === this.VIEWS.DAILY) {
+ nextState.weekDays = this.initialWeekDays;
+ }
+ if (nextState.weekDays.length === Object.keys(this.WEEK_DAYS).length && this.state.view !== this.VIEWS.WEEKLY && nextState.view === this.VIEWS.WEEKLY || !(0,helpers.ro)(nextProps.startDateTime, this.props.startDateTime) && this.state.view === this.VIEWS.WEEKLY) {
+ const weekday = new Date(nextProps.startDateTime).getDay();
+ nextState.weekDays = [weekday === 0 ? 7 : weekday];
+ }
+ if (!(0,helpers.ro)(nextProps.startDateTime, this.props.startDateTime) && this.state.view === this.VIEWS.MONTHLY) {
+ let _Object$values$find2;
+ const nextDate = new Date(nextProps.startDateTime);
+ nextState.monthDays = [nextDate.getDate()];
+ nextState.offset.weekDay = ((_Object$values$find2 = Object.values(this.WEEK_DAYS).find(d => d.value === nextDate.getDay())) == null ? void 0 : _Object$values$find2.value) || this.WEEK_DAYS.SUNDAY.value;
+ nextState.monthDaysWarning = nextState.monthDays > 28;
+ }
+ if (nextState.view === this.VIEWS.MONTHLY && this.state.interval > 12) {
+ nextState.interval = 12;
+ }
+ this.props.onUpdate(this.getFormattedState(nextState));
+ }
+ componentDidMount() {
+ super.componentDidMount();
+ this.props.onUpdate(this.getFormattedState(this.state));
+ }
+ render() {
+ const {
+ NAMESPACE
+ } = Recurring;
+ const {
+ view
+ } = this.state;
+ return JSX_(schedule_utils.fI, null, JSX_(schedule_utils.VP, null), JSX_(schedule_utils.VP, null, JSX_("div", {
+ ref: this.domRef,
+ className: `
+ ${NAMESPACE}
+ ${this.props.isLoading ? 'disabled' : ''}
+ `
+ }, JSX_("div", {
+ className: `${NAMESPACE}-container`
+ }, JSX_("div", {
+ className: `${NAMESPACE}-navigation`
+ }, this.renderNavigation(view)), JSX_("div", {
+ className: `${NAMESPACE}-content`
+ }, this.renderContent(view))))));
+ }
+}
+Recurring.NAMESPACE = 'meetings-recurring';
+;// ./js/chat/ui/meetings/schedule/schedule.jsx
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+class Schedule extends mixins.w9 {
+ constructor(...args) {
+ super(...args);
+ this.domRef = REaCt().createRef();
+ this.scheduledMeetingRef = null;
+ this.localStreamRef = '.float-video';
+ this.datepickerRefs = [];
+ this.incomingCallListener = 'onPrepareIncomingCallDialog.scheduleDialog';
+ this.ringingStoppedListener = 'onRingingStopped.scheduleDialog';
+ this.interval = ChatRoom.SCHEDULED_MEETINGS_INTERVAL;
+ this.nearestHalfHour = (0,helpers.i_)();
+ this.state = {
+ topic: '',
+ startDateTime: this.nearestHalfHour,
+ endDateTime: this.nearestHalfHour + this.interval,
+ timezone: (0,helpers.dB)(),
+ recurring: false,
+ participants: [],
+ link: false,
+ sendInvite: false,
+ waitingRoom: false,
+ openInvite: false,
+ description: '',
+ closeDialog: false,
+ isEdit: false,
+ isDirty: false,
+ isLoading: false,
+ topicInvalid: false,
+ invalidTopicMsg: '',
+ descriptionInvalid: false,
+ overlayed: false
+ };
+ this.onTopicChange = value => {
+ if (value.length > ChatRoom.TOPIC_MAX_LENGTH) {
+ this.setState({
+ invalidTopicMsg: l.err_schedule_title_long,
+ topicInvalid: true
+ });
+ value = value.substring(0, ChatRoom.TOPIC_MAX_LENGTH);
+ } else if (value.length === 0) {
+ this.setState({
+ invalidTopicMsg: l.schedule_title_missing,
+ topicInvalid: true
+ });
+ } else if (this.state.invalidTopicMsg) {
+ this.setState({
+ invalidTopicMsg: '',
+ topicInvalid: false
+ });
+ }
+ this.handleChange('topic', value);
+ };
+ this.onTextareaChange = value => {
+ if (value.length > 3000) {
+ this.setState({
+ descriptionInvalid: true
+ });
+ value = value.substring(0, 3000);
+ } else if (this.state.descriptionInvalid) {
+ this.setState({
+ descriptionInvalid: false
+ });
+ }
+ this.handleChange('description', value);
+ };
+ this.onStartDateSelect = () => {
+ this.datepickerRefs.endDateTime.selectDate(new Date(this.state.startDateTime + this.interval));
+ };
+ this.onEndDateSelect = () => {
+ const {
+ startDateTime,
+ endDateTime
+ } = this.state;
+ if (endDateTime < startDateTime) {
+ if (endDateTime < Date.now()) {
+ return this.setState({
+ endDateTime: startDateTime + this.interval
+ });
+ }
+ this.handleDateSelect({
+ startDateTime: endDateTime - this.interval
+ });
+ }
+ };
+ this.handleToggle = prop => {
+ return Object.keys(this.state).includes(prop) && this.setState(state => ({
+ [prop]: !state[prop],
+ isDirty: true
+ }));
+ };
+ this.handleChange = (prop, value) => {
+ return Object.keys(this.state).includes(prop) && this.setState({
+ [prop]: value,
+ isDirty: true
+ });
+ };
+ this.handleDateSelect = ({
+ startDateTime,
+ endDateTime
+ }, callback) => {
+ this.setState(state => ({
+ startDateTime: startDateTime || state.startDateTime,
+ endDateTime: endDateTime || state.endDateTime,
+ isDirty: true
+ }), () => {
+ const {
+ recurring
+ } = this.state;
+ if (recurring && recurring.end) {
+ const recurringEnd = (0,helpers.PS)(this.state.startDateTime, 6);
+ this.datepickerRefs.recurringEnd.selectDate(new Date(recurringEnd));
+ }
+ if (callback) {
+ callback();
+ }
+ });
+ };
+ this.handleTimeSelect = ({
+ startDateTime,
+ endDateTime
+ }) => {
+ startDateTime = startDateTime || this.state.startDateTime;
+ endDateTime = endDateTime || this.state.endDateTime;
+ this.setState(state => {
+ return {
+ startDateTime: endDateTime <= state.startDateTime ? endDateTime - this.interval : startDateTime,
+ endDateTime: startDateTime >= state.endDateTime ? startDateTime + this.interval : endDateTime,
+ isDirty: true
+ };
+ });
+ };
+ this.handleParticipantSelect = participants => {
+ return participants && Array.isArray(participants) && this.setState({
+ participants,
+ isDirty: true
+ }, () => {
+ const domRef = this.domRef && this.domRef.current;
+ if (domRef) {
+ domRef.reinitialise();
+ }
+ });
+ };
+ this.handleSubmit = () => {
+ if (this.state.topic) {
+ return this.setState({
+ isLoading: true
+ }, async () => {
+ const {
+ chatRoom,
+ onClose
+ } = this.props;
+ const params = [this.state, chatRoom];
+ if (chatRoom) {
+ delay('chat-event-sm-edit-meeting', () => eventlog(99923));
+ } else {
+ delay('chat-event-sm-button-create', () => eventlog(99922));
+ }
+ delay('chat-events-sm-settings', () => this.submitStateEvents({
+ ...this.state
+ }));
+ await megaChat.plugins.meetingsManager[chatRoom ? 'updateMeeting' : 'createMeeting'](...params);
+ this.setState({
+ isLoading: false
+ }, () => {
+ onClose();
+ megaChat.trigger(conversations.qY.NAV_RENDER_VIEW, conversations.Vw.MEETINGS);
+ });
+ });
+ }
+ return this.setState({
+ topicInvalid: true,
+ invalidTopicMsg: l.schedule_title_missing
+ });
+ };
+ }
+ syncPublicLink() {
+ if (this.state.isEdit) {
+ const {
+ chatRoom
+ } = this.props;
+ chatRoom.updatePublicHandle().then(() => this.isMounted() && this.setState({
+ link: !!chatRoom.publicLink
+ })).catch(dump);
+ }
+ }
+ getFilteredTimeIntervals(timestamp, offsetFrom) {
+ const timeIntervals = (0,helpers.a4)(timestamp, offsetFrom);
+ const {
+ end
+ } = this.scheduledMeetingRef || {};
+ if (this.state.isEdit && end < Date.now()) {
+ return timeIntervals;
+ }
+ return timeIntervals.filter(o => {
+ return offsetFrom ? o.value > this.nearestHalfHour : o.value > Date.now();
+ });
+ }
+ submitStateEvents(state) {
+ if (state.link) {
+ eventlog(500162);
+ }
+ if (state.sendInvite) {
+ eventlog(500163);
+ }
+ if (state.waitingRoom) {
+ eventlog(500164);
+ }
+ if (state.openInvite) {
+ eventlog(500165);
+ }
+ if (state.description) {
+ eventlog(500166);
+ }
+ if (state.recurring) {
+ eventlog(500167);
+ } else {
+ eventlog(500168);
+ }
+ eventlog(500169, state.topic.length);
+ }
+ componentWillUnmount() {
+ super.componentWillUnmount();
+ if ($.dialog === schedule_utils.oK) {
+ closeDialog();
+ }
+ [document, this.localStreamRef].map(el => $(el).unbind(`.${schedule_utils.CU}`));
+ megaChat.off(this.incomingCallListener);
+ }
+ UNSAFE_componentWillMount() {
+ const {
+ chatRoom
+ } = this.props;
+ if (chatRoom) {
+ const {
+ scheduledMeeting,
+ publicLink,
+ options
+ } = chatRoom;
+ this.state.topic = scheduledMeeting.title;
+ this.state.startDateTime = scheduledMeeting.start;
+ this.state.endDateTime = scheduledMeeting.end;
+ this.state.timezone = scheduledMeeting.timezone || (0,helpers.dB)();
+ this.state.recurring = scheduledMeeting.recurring;
+ this.state.participants = chatRoom.getParticipantsExceptMe();
+ this.state.link = !!publicLink;
+ this.state.description = scheduledMeeting.description || '';
+ this.state.sendInvite = scheduledMeeting.flags;
+ this.state.waitingRoom = options[chat_chatRoom.U_.WAITING_ROOM];
+ this.state.openInvite = options[chat_chatRoom.U_.OPEN_INVITE];
+ this.state.isEdit = true;
+ this.scheduledMeetingRef = scheduledMeeting;
+ }
+ }
+ componentDidMount() {
+ super.componentDidMount();
+ this.syncPublicLink();
+ if ($.dialog === 'onboardingDialog') {
+ closeDialog();
+ }
+ M.safeShowDialog(schedule_utils.oK, () => {
+ if (!this.isMounted()) {
+ throw new Error(`${schedule_utils.oK} dialog: component ${schedule_utils.CU} not mounted.`);
+ }
+ $(document).rebind(`keyup.${schedule_utils.CU}`, ({
+ keyCode,
+ target
+ }) => {
+ return this.state.closeDialog || target instanceof HTMLTextAreaElement ? null : keyCode === 13 && this.handleSubmit();
+ });
+ $(this.localStreamRef).rebind(`click.${schedule_utils.CU}`, () => {
+ if (this.state.isDirty) {
+ this.handleToggle('closeDialog');
+ return false;
+ }
+ });
+ megaChat.rebind(this.incomingCallListener, () => {
+ if (this.isMounted()) {
+ this.setState({
+ overlayed: true,
+ closeDialog: false
+ });
+ megaChat.plugins.callManager2.rebind(this.ringingStoppedListener, () => {
+ megaChat.plugins.callManager2.off(this.ringingStoppedListener);
+ this.setState({
+ overlayed: false
+ });
+ fm_showoverlay();
+ });
+ }
+ });
+ return $(`#${schedule_utils.CU}`);
+ });
+ }
+ componentDidUpdate(prevProps) {
+ if (prevProps.callExpanded && !this.props.callExpanded) {
+ if (!$.dialog) {
+ M.safeShowDialog(schedule_utils.oK, `#${schedule_utils.CU}`);
+ }
+ fm_showoverlay();
+ this.setState({
+ closeDialog: false
+ });
+ }
+ if (!prevProps.callExpanded && this.props.callExpanded) {
+ this.setState({
+ closeDialog: false
+ });
+ }
+ }
+ render() {
+ let _this$props$chatRoom;
+ const {
+ topic,
+ startDateTime,
+ endDateTime,
+ recurring,
+ participants,
+ link,
+ sendInvite,
+ waitingRoom,
+ openInvite,
+ description,
+ closeDialog,
+ isEdit,
+ isDirty,
+ isLoading,
+ topicInvalid,
+ invalidTopicMsg,
+ descriptionInvalid,
+ overlayed
+ } = this.state;
+ return JSX_(modalDialogs.A.ModalDialog, (0,esm_extends.A)({}, this.state, {
+ id: schedule_utils.CU,
+ className: `
+ ${closeDialog ? 'with-confirmation-dialog' : ''}
+ ${this.props.callExpanded || overlayed ? 'hidden' : ''}
+ `,
+ dialogName: schedule_utils.oK,
+ dialogType: "main",
+ onClose: () => isDirty ? this.handleToggle('closeDialog') : this.props.onClose()
+ }), JSX_(Header, {
+ chatRoom: isEdit && this.props.chatRoom
+ }), JSX_(perfectScrollbar.O, {
+ ref: this.domRef,
+ className: "fm-dialog-body",
+ options: {
+ suppressScrollX: true
+ }
+ }, JSX_(schedule_utils.pd, {
+ name: "topic",
+ placeholder: l.schedule_title_input,
+ value: topic,
+ invalid: topicInvalid,
+ invalidMessage: invalidTopicMsg,
+ autoFocus: true,
+ isLoading,
+ onFocus: () => topicInvalid && this.setState({
+ topicInvalid: false
+ }),
+ onChange: this.onTopicChange
+ }), JSX_(schedule_utils.fI, {
+ className: `unencrypted-warning-row ${topicInvalid ? 'with-topic-err' : ''}`
+ }, JSX_(schedule_utils.VP, null), JSX_(schedule_utils.VP, null, JSX_("div", {
+ className: "unencrypted-warning"
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-info"
+ }), JSX_("span", null, l.schedule_encryption_note)))), JSX_(schedule_utils.fI, {
+ className: "start-aligned"
+ }, JSX_(schedule_utils.VP, null, JSX_("i", {
+ className: "sprite-fm-mono icon-recents-filled"
+ })), JSX_("div", {
+ className: "schedule-date-container"
+ }, JSX_(datetime.c, {
+ name: "startDateTime",
+ altField: "startTime",
+ datepickerRef: this.datepickerRefs.startDateTime,
+ startDate: startDateTime,
+ value: startDateTime,
+ filteredTimeIntervals: this.getFilteredTimeIntervals(startDateTime),
+ label: l.schedule_start_date,
+ isLoading,
+ onMount: datepicker => {
+ this.datepickerRefs.startDateTime = datepicker;
+ },
+ onSelectDate: startDateTime => {
+ this.handleDateSelect({
+ startDateTime
+ }, this.onStartDateSelect);
+ },
+ onSelectTime: ({
+ value: startDateTime
+ }) => this.handleTimeSelect({
+ startDateTime
+ }),
+ onChange: value => this.handleChange('startDateTime', value),
+ onBlur: timestamp => {
+ if (timestamp) {
+ const startDateTime = timestamp < Date.now() ? this.nearestHalfHour : timestamp;
+ this.handleDateSelect({
+ startDateTime
+ }, this.onStartDateSelect);
+ }
+ }
+ }), JSX_(datetime.c, {
+ name: "endDateTime",
+ altField: "endTime",
+ datepickerRef: this.datepickerRefs.endDateTime,
+ isLoading,
+ startDate: endDateTime,
+ value: endDateTime,
+ filteredTimeIntervals: this.getFilteredTimeIntervals(endDateTime, startDateTime),
+ label: l.schedule_end_date,
+ onMount: datepicker => {
+ this.datepickerRefs.endDateTime = datepicker;
+ },
+ onSelectDate: endDateTime => {
+ this.handleDateSelect({
+ endDateTime
+ }, this.onEndDateSelect);
+ },
+ onSelectTime: ({
+ value: endDateTime
+ }) => this.handleTimeSelect({
+ endDateTime
+ }),
+ onChange: value => this.handleChange('endDateTime', value),
+ onBlur: timestamp => {
+ this.handleDateSelect({
+ endDateTime: timestamp
+ }, this.onEndDateSelect);
+ }
+ }))), !u_attr.p && endDateTime - startDateTime > 36e5 && JSX_(schedule_utils.dh, {
+ onUpgradeClicked: () => {
+ this.props.onClose();
+ loadSubPage('pro');
+ eventlog(500258);
+ }
+ }), JSX_(schedule_utils.Sc, {
+ name: "recurring",
+ checked: recurring,
+ label: l.schedule_recurring_label,
+ isLoading,
+ onToggle: prop => {
+ this.handleToggle(prop);
+ delay('chat-event-sm-recurring', () => eventlog(99919));
+ }
+ }), recurring && JSX_(Recurring, {
+ chatRoom: this.props.chatRoom,
+ startDateTime,
+ endDateTime,
+ isLoading,
+ onMount: datepicker => {
+ this.datepickerRefs.recurringEnd = datepicker;
+ },
+ onUpdate: state => {
+ this.setState({
+ recurring: state
+ });
+ }
+ }), JSX_(schedule_utils.fI, null, JSX_(schedule_utils.VP, null, JSX_("i", {
+ className: "sprite-fm-mono icon-contacts"
+ })), JSX_(schedule_utils.VP, null, JSX_(Invite, {
+ className: isLoading ? 'disabled' : '',
+ isLoading,
+ participants,
+ onSelect: this.handleParticipantSelect
+ }))), JSX_(schedule_utils.dO, {
+ name: "link",
+ toggled: link,
+ label: l.schedule_link_label,
+ isLoading,
+ subLabel: l.schedule_link_info,
+ onToggle: prop => {
+ this.handleToggle(prop);
+ delay('chat-event-sm-meeting-link', () => eventlog(99920));
+ }
+ }), JSX_(schedule_utils.Sc, {
+ name: "sendInvite",
+ checked: sendInvite,
+ label: l.schedule_invite_label,
+ isLoading,
+ onToggle: prop => {
+ this.handleToggle(prop);
+ delay('chat-event-sm-calendar-invite', () => eventlog(99921));
+ }
+ }), JSX_(schedule_utils.Sc, {
+ name: "waitingRoom",
+ className: (_this$props$chatRoom = this.props.chatRoom) != null && _this$props$chatRoom.havePendingCall() ? 'disabled' : '',
+ checked: waitingRoom,
+ label: l.waiting_room,
+ subLabel: l.waiting_room_info,
+ isLoading,
+ onToggle: waitingRoom => {
+ let _this$props$chatRoom2;
+ if ((_this$props$chatRoom2 = this.props.chatRoom) != null && _this$props$chatRoom2.havePendingCall()) {
+ return;
+ }
+ this.handleToggle(waitingRoom);
+ delay('chat-event-sm-waiting-room', () => eventlog(500297));
+ }
+ }), JSX_(schedule_utils.Sc, {
+ name: "openInvite",
+ checked: openInvite,
+ label: l.open_invite_desc,
+ isLoading,
+ onToggle: ev => {
+ this.handleToggle(ev);
+ delay('chat-event-sm-open-invite', () => eventlog(500298));
+ }
+ }), waitingRoom && openInvite ? JSX_(schedule_utils.fI, null, JSX_("div", {
+ className: "schedule-dialog-banner warn"
+ }, JSX_(utils.P9, null, l.waiting_room_invite.replace('[A]', `
+ `).replace('[/A]', '')))) : null, JSX_(schedule_utils.TM, {
+ name: "description",
+ isLoading,
+ invalid: descriptionInvalid,
+ placeholder: l.schedule_description_input,
+ value: description,
+ onFocus: () => descriptionInvalid && this.setState({
+ descriptionInvalid: false
+ }),
+ onChange: this.onTextareaChange
+ })), JSX_(Footer, {
+ isLoading,
+ isEdit,
+ topic,
+ onSubmit: this.handleSubmit
+ }), !(overlayed || this.props.callExpanded) && closeDialog && JSX_(schedule_utils.pD, {
+ onToggle: this.handleToggle,
+ onClose: this.props.onClose
+ }));
+ }
+}
+const Header = ({
+ chatRoom
+}) => {
+ const $$container = title => JSX_("header", null, JSX_("h2", null, title));
+ if (chatRoom) {
+ const {
+ scheduledMeeting
+ } = chatRoom;
+ return $$container(scheduledMeeting.isRecurring ? l.edit_meeting_series_title : l.edit_meeting_title);
+ }
+ return $$container(l.schedule_meeting_title);
+};
+const Footer = ({
+ isLoading,
+ isEdit,
+ topic,
+ onSubmit
+}) => {
+ return JSX_("footer", null, JSX_("div", {
+ className: "footer-container"
+ }, JSX_(meetings_button.A, {
+ className: `
+ mega-button
+ positive
+ ${isLoading ? 'disabled' : ''}
+ `,
+ onClick: () => isLoading ? null : onSubmit(),
+ topic
+ }, JSX_("span", null, isEdit ? l.update_meeting_button : l.schedule_meeting_button))));
+};
+
+ },
+
+ 3448
+(_, EXP_, REQ_) {
+
+ REQ_.d(EXP_, {
+ A: () => __WEBPACK_DEFAULT_EXPORT__
+ });
+ const react0__ = REQ_(1594);
+ const react0___default = REQ_.n(react0__);
+ const _mixins_js1__ = REQ_(8264);
+ const _ui_perfectScrollbar_jsx2__ = REQ_(1301);
+ const _helpers_jsx3__ = REQ_(6521);
+ const _dateObserver4__ = REQ_(8894);
+
+
+
+
+
+class Select extends react0___default().Component {
+ constructor(...args) {
+ super(...args);
+ this.domRef = react0___default().createRef();
+ this.inputRef = react0___default().createRef();
+ this.menuRef = react0___default().createRef();
+ this.optionRefs = {};
+ this.state = {
+ expanded: false,
+ manualTimeInput: '',
+ timestamp: ''
+ };
+ this.handleMousedown = ({
+ target
+ }) => {
+ let _this$domRef;
+ return (_this$domRef = this.domRef) != null && _this$domRef.current.contains(target) ? null : this.setState({
+ expanded: false
+ });
+ };
+ this.handleToggle = ({
+ target
+ } = {}) => {
+ let _this$menuRef, _menuRef$domRef;
+ const menuRef = (_this$menuRef = this.menuRef) == null ? void 0 : _this$menuRef.current;
+ const menuElement = (_menuRef$domRef = menuRef.domRef) == null ? void 0 : _menuRef$domRef.current;
+ if (target !== menuElement) {
+ const {
+ value
+ } = this.props;
+ this.setState(state => ({
+ expanded: !state.expanded
+ }), () => {
+ if (value && this.optionRefs[value]) {
+ menuRef.scrollToElement(this.optionRefs[value]);
+ }
+ });
+ }
+ };
+ }
+ getFormattedDuration(duration) {
+ duration = moment.duration(duration);
+ const days = duration.get('days');
+ const hours = duration.get('hours');
+ const minutes = duration.get('minutes');
+ if (!hours && !minutes && !days) {
+ return '';
+ }
+ const totalHours = days ? ~~duration.asHours() : hours;
+ if (!hours && minutes) {
+ return days ? `(${totalHours}\u00a0h ${minutes}\u00a0m)` : `(${minutes}\u00a0m)`;
+ }
+ return minutes ? `(${totalHours}\u00a0h ${minutes}\u00a0m)` : `(${totalHours}\u00a0h)`;
+ }
+ componentWillUnmount() {
+ document.removeEventListener('mousedown', this.handleMousedown);
+ if (this.inputRef && this.inputRef.current) {
+ $(this.inputRef.current).unbind(`keyup.${Select.NAMESPACE}`);
+ }
+ }
+ componentDidMount() {
+ let _this$inputRef;
+ document.addEventListener('mousedown', this.handleMousedown);
+ const inputRef = (_this$inputRef = this.inputRef) == null ? void 0 : _this$inputRef.current;
+ if (inputRef) {
+ $(inputRef).rebind(`keyup.${Select.NAMESPACE}`, ({
+ keyCode
+ }) => {
+ if (keyCode === 13) {
+ this.handleToggle();
+ inputRef.blur();
+ return false;
+ }
+ });
+ }
+ }
+ render() {
+ const {
+ NAMESPACE
+ } = Select;
+ const {
+ name,
+ className,
+ icon,
+ typeable,
+ options,
+ value,
+ format,
+ isLoading,
+ onChange,
+ onBlur,
+ onSelect
+ } = this.props;
+ return JSX_("div", {
+ ref: this.domRef,
+ className: `
+ ${NAMESPACE}
+ ${className || ''}
+ `
+ }, JSX_("div", {
+ className: `
+ mega-input
+ dropdown-input
+ ${typeable ? 'typeable' : ''}
+ `,
+ onClick: isLoading ? null : this.handleToggle
+ }, typeable ? null : value && JSX_("span", null, format ? format(value) : value), JSX_("input", {
+ ref: this.inputRef,
+ type: "text",
+ className: `
+ ${NAMESPACE}-input
+ ${name}
+ `,
+ value: (() => {
+ if (this.state.manualTimeInput) {
+ return this.state.manualTimeInput;
+ }
+ return format ? format(value) : value;
+ })(),
+ onFocus: ({
+ target
+ }) => {
+ this.setState({
+ manualTimeInput: '',
+ timestamp: ''
+ }, () => target.select());
+ },
+ onChange: ({
+ target
+ }) => {
+ const {
+ value: manualTimeInput
+ } = target;
+ const {
+ value
+ } = this.props;
+ const prevDate = moment(value);
+ const inputTime = (0,_helpers_jsx3__ .We)(manualTimeInput);
+ prevDate.set({
+ hours: inputTime.get('hours'),
+ minutes: inputTime.get('minutes')
+ });
+ const timestamp = prevDate.valueOf();
+ onChange == null || onChange(timestamp);
+ if (this.optionRefs[value]) {
+ this.menuRef.current.scrollToElement(this.optionRefs[value]);
+ }
+ this.setState({
+ manualTimeInput,
+ timestamp
+ });
+ },
+ onBlur: () => {
+ onBlur(this.state.timestamp);
+ this.setState({
+ manualTimeInput: '',
+ timestamp: ''
+ });
+ }
+ }), icon && JSX_("i", {
+ className: "sprite-fm-mono icon-dropdown"
+ }), options && JSX_("div", {
+ className: `
+ mega-input-dropdown
+ ${this.state.expanded ? '' : 'hidden'}
+ `
+ }, JSX_(_ui_perfectScrollbar_jsx2__ .O, {
+ ref: this.menuRef,
+ options: {
+ suppressScrollX: true
+ }
+ }, options.map(option => {
+ return JSX_("div", {
+ ref: ref => {
+ this.optionRefs[option.value] = ref;
+ },
+ key: option.value,
+ className: `
+ option
+ ${option.value === value || option.label === value ? 'active' : ''}
+ `,
+ onClick: () => onSelect(option)
+ }, option.label, "\xA0", option.duration && this.getFormattedDuration(option.duration));
+ })))));
+ }
+}
+Select.NAMESPACE = 'meetings-select';
+ const __WEBPACK_DEFAULT_EXPORT__ = (0,_mixins_js1__ .Zz)(_dateObserver4__ .V)(Select);
+
+ },
+
+ 1497
+(_, EXP_, REQ_) {
+
+ REQ_.d(EXP_, {
+ CU: () => NAMESPACE,
+ Sc: () => Checkbox,
+ TM: () => Textarea,
+ VP: () => Column,
+ dO: () => Switch,
+ dh: () => UpgradeNotice,
+ fI: () => Row,
+ oK: () => dialogName,
+ pD: () => CloseDialog,
+ pd: () => Input
+ });
+ const react0__ = REQ_(1594);
+ const react0___default = REQ_.n(react0__);
+ const _ui_modalDialogs_jsx1__ = REQ_(8120);
+ const _button_jsx2__ = REQ_(6740);
+
+
+
+const NAMESPACE = 'schedule-dialog';
+const dialogName = `meetings-${"schedule-dialog"}`;
+const CloseDialog = ({
+ onToggle,
+ onClose
+}) => {
+ return JSX_(react0___default().Fragment, null, JSX_(_ui_modalDialogs_jsx1__ .A.ModalDialog, {
+ name: `${NAMESPACE}-confirmation`,
+ dialogType: "message",
+ className: `
+ with-close-btn
+ ${NAMESPACE}-confirmation
+ `,
+ title: l.schedule_discard_dlg_title,
+ icon: "sprite-fm-uni icon-question",
+ buttons: [{
+ key: 'n',
+ label: l.schedule_discard_cancel,
+ onClick: () => onToggle('closeDialog')
+ }, {
+ key: 'y',
+ label: l.schedule_discard_confirm,
+ className: 'positive',
+ onClick: onClose
+ }],
+ noCloseOnClickOutside: true,
+ stopKeyPropagation: true,
+ hideOverlay: true,
+ onClose: () => onToggle('closeDialog')
+ }), JSX_("div", {
+ className: `${NAMESPACE}-confirmation-overlay`,
+ onClick: () => onToggle('closeDialog')
+ }));
+};
+const Row = ({
+ children,
+ className
+}) => JSX_("div", {
+ className: `
+ ${NAMESPACE}-row
+ ${className || ''}
+ `
+}, children);
+const Column = ({
+ children,
+ className
+}) => JSX_("div", {
+ className: `
+ ${NAMESPACE}-column
+ ${className || ''}
+ `
+}, children);
+const Input = ({
+ name,
+ placeholder,
+ value,
+ invalid,
+ invalidMessage,
+ autoFocus,
+ isLoading,
+ onFocus,
+ onChange
+}) => {
+ return JSX_(Row, {
+ className: invalid ? 'invalid-aligned' : ''
+ }, JSX_(Column, null, JSX_("i", {
+ className: "sprite-fm-mono icon-rename"
+ })), JSX_(Column, null, JSX_("div", {
+ className: `
+ mega-input
+ ${invalid ? 'error msg' : ''}
+ `
+ }, JSX_("input", {
+ type: "text",
+ name: `${NAMESPACE}-${name}`,
+ className: isLoading ? 'disabled' : '',
+ disabled: isLoading,
+ autoFocus,
+ autoComplete: "off",
+ placeholder,
+ value,
+ onFocus,
+ onChange: ({
+ target
+ }) => onChange(target.value)
+ }), invalid && JSX_("div", {
+ className: "message-container mega-banner"
+ }, invalidMessage))));
+};
+const Checkbox = ({
+ name,
+ className,
+ checked,
+ label,
+ subLabel,
+ isLoading,
+ onToggle
+}) => {
+ return JSX_(Row, {
+ className: `
+ ${subLabel ? 'start-aligned' : ''}
+ ${className || ''}
+ `
+ }, JSX_(Column, null, JSX_("div", {
+ className: `
+ checkdiv
+ ${checked ? 'checkboxOn' : 'checkboxOff'}
+ ${isLoading ? 'disabled' : ''}
+ `
+ }, JSX_("input", {
+ name: `${NAMESPACE}-${name}`,
+ disabled: isLoading,
+ type: "checkbox",
+ onChange: () => onToggle(name)
+ }))), JSX_(Column, {
+ className: subLabel ? 'with-sub-label' : ''
+ }, JSX_("label", {
+ htmlFor: `${NAMESPACE}-${name}`,
+ className: isLoading ? 'disabled' : '',
+ onClick: () => isLoading ? null : onToggle(name)
+ }, label), subLabel && JSX_("div", {
+ className: "sub-label"
+ }, subLabel)));
+};
+const Switch = ({
+ name,
+ toggled,
+ label,
+ isLoading,
+ subLabel,
+ onToggle
+}) => {
+ return JSX_(Row, null, JSX_(Column, null, JSX_("i", {
+ className: "sprite-fm-uni icon-mega-logo"
+ })), JSX_(Column, {
+ className: subLabel ? `with-sub-label ${"schedule-dialog-switch"}` : "schedule-dialog-switch"
+ }, JSX_("span", {
+ className: `
+ schedule-label
+ ${isLoading ? 'disabled' : ''}
+ `,
+ onClick: () => isLoading ? null : onToggle(name)
+ }, label), JSX_("div", {
+ className: `
+ mega-switch
+ ${toggled ? 'toggle-on' : ''}
+ ${isLoading ? 'disabled' : ''}
+ `,
+ onClick: () => isLoading ? null : onToggle(name)
+ }, JSX_("div", {
+ className: `
+ mega-feature-switch
+ sprite-fm-mono-after
+ ${toggled ? 'icon-check-after' : 'icon-minimise-after'}
+ `
+ })), subLabel && JSX_("div", {
+ className: "sub-label"
+ }, subLabel)));
+};
+const Textarea = ({
+ name,
+ placeholder,
+ isLoading,
+ value,
+ invalid,
+ onChange,
+ onFocus
+}) => {
+ return JSX_(Row, {
+ className: "start-aligned"
+ }, JSX_(Column, null, JSX_("i", {
+ className: "sprite-fm-mono icon-description"
+ })), JSX_(Column, null, JSX_("div", {
+ className: `mega-input box-style textarea ${invalid ? 'error' : ''}`
+ }, JSX_("textarea", {
+ name: `${NAMESPACE}-${name}`,
+ className: isLoading ? 'disabled' : '',
+ placeholder,
+ value,
+ readOnly: isLoading,
+ onChange: ({
+ target
+ }) => onChange(target.value),
+ onFocus
+ })), invalid && JSX_("div", {
+ className: "mega-input error msg textarea-error"
+ }, JSX_("div", {
+ className: "message-container mega-banner"
+ }, l.err_schedule_desc_long))));
+};
+const UpgradeNotice = ({
+ onUpgradeClicked
+}) => {
+ return !!mega.flags.ff_chmon && JSX_(Row, {
+ className: "schedule-upgrade-notice"
+ }, JSX_("h3", null, l.schedule_limit_title), JSX_("div", null, l.schedule_limit_upgrade_features), JSX_(_button_jsx2__ .A, {
+ className: "mega-button positive",
+ onClick: onUpgradeClicked
+ }, JSX_("span", null, l.upgrade_now)));
+};
+
+ }
+
+}]);
\ No newline at end of file
diff --git a/js/chat/bundle.start-conversation.js b/js/chat/bundle.start-conversation.js
new file mode 100644
index 0000000000..ad3ec0de31
--- /dev/null
+++ b/js/chat/bundle.start-conversation.js
@@ -0,0 +1,1233 @@
+/** @file automatically generated, do not edit it. */
+"use strict";
+(self.webpackChunk_meganz_webclient = self.webpackChunk_meganz_webclient || []).push([[543],{
+
+ 2678
+(_, EXP_, REQ_) {
+
+REQ_.r(EXP_);
+ REQ_.d(EXP_, {
+ "default": () => __WEBPACK_DEFAULT_EXPORT__
+ });
+ const react0__ = REQ_(1594);
+ const react0___default = REQ_.n(react0__);
+ const _contacts1__ = REQ_(8022);
+ const _ui_modalDialogs_jsx2__ = REQ_(8120);
+ const _mixins_js3__ = REQ_(8264);
+
+
+
+
+class ContactSelectorDialog extends _mixins_js3__ .w9 {
+ constructor(...args) {
+ super(...args);
+ this.dialogName = 'contact-selector-dialog';
+ }
+ componentDidMount() {
+ super.componentDidMount();
+ M.safeShowDialog(this.dialogName, () => $(`.${this.dialogName}`));
+ }
+ componentWillUnmount() {
+ super.componentWillUnmount();
+ if ($.dialog === this.dialogName) {
+ closeDialog();
+ }
+ }
+ render() {
+ const {
+ active,
+ selectFooter,
+ exclude,
+ allowEmpty,
+ multiple,
+ topButtons,
+ showAddContact,
+ className,
+ multipleSelectedButtonLabel,
+ singleSelectedButtonLabel,
+ nothingSelectedButtonLabel,
+ onClose,
+ onSelectDone
+ } = this.props;
+ return JSX_(_ui_modalDialogs_jsx2__ .A.ModalDialog, {
+ className: `
+ popup
+ contacts-search
+ ${className}
+ ${this.dialogName}
+ `,
+ onClose
+ }, JSX_(_contacts1__ .hU, {
+ active,
+ className: "popup contacts-search small-footer",
+ contacts: M.u,
+ selectFooter,
+ megaChat,
+ withSelfNote: megaChat.WITH_SELF_NOTE,
+ exclude,
+ allowEmpty,
+ multiple,
+ topButtons,
+ showAddContact,
+ multipleSelectedButtonLabel,
+ singleSelectedButtonLabel,
+ nothingSelectedButtonLabel,
+ onClose,
+ onAddContact: () => {
+ eventlog(500237);
+ onClose();
+ },
+ onSelected: () => {
+ eventlog(500238);
+ onClose();
+ },
+ onSelectDone
+ }));
+ }
+}
+ const __WEBPACK_DEFAULT_EXPORT__ = ContactSelectorDialog;
+
+ },
+
+ 192
+(_, EXP_, REQ_) {
+
+ REQ_.d(EXP_, {
+ $: () => withPermissionsObserver
+ });
+ const _babel_runtime_helpers_extends0__ = REQ_(8168);
+ const react1__ = REQ_(1594);
+ const react1___default = REQ_.n(react1__);
+ const _mixins_js2__ = REQ_(8264);
+ const _ui_modalDialogs_jsx3__ = REQ_(8120);
+ const _ui_utils_jsx4__ = REQ_(6411);
+
+
+
+
+
+const errors = {
+ browser: 'NotAllowedError: Permission denied',
+ system: 'NotAllowedError: Permission denied by system',
+ dismissed: 'NotAllowedError: Permission dismissed',
+ nil: 'NotFoundError: Requested device not found',
+ sharedCam: 'NotReadableError: Could not start video source',
+ sharedMic: 'NotReadableError: Could not start audio source',
+ sharedGeneric: 'NotReadableError: Device in use'
+};
+const isUserActionError = error => {
+ return error && error === errors.browser;
+};
+const withPermissionsObserver = Component => {
+ return class extends _mixins_js2__ .w9 {
+ constructor(props) {
+ super(props);
+ this.namespace = `PO-${Component.NAMESPACE}`;
+ this.observer = `onLocalMediaError.${this.namespace}`;
+ this.childRef = undefined;
+ this.platform = ua.details.os;
+ this.helpURL = `${l.mega_help_host}/chats-meetings/meetings/enable-audio-video-call-permissions`;
+ this.macURI = 'x-apple.systempreferences:com.apple.preference.security';
+ this.winURI = 'ms-settings';
+ this.CONTENT = {
+ [Av.Audio]: {
+ system: {
+ title: l.no_mic_title,
+ info: this.platform === 'Windows' ? l.no_mic_system_windows.replace('[A]', ``).replace('[/A]', '') : l.no_mic_system_mac.replace('[A]', ``).replace('[/A]', ''),
+ buttons: [this.platform === 'Apple' || this.platform === 'Windows' ? {
+ key: 'open-settings',
+ label: l.open_system_settings,
+ className: 'positive',
+ onClick: () => {
+ window.open(this.platform === 'Apple' ? `${this.macURI}?Privacy_Microphone` : `${this.winURI}:privacy-microphone`, '_blank', 'noopener,noreferrer');
+ this.closePermissionsDialog(Av.Audio);
+ }
+ } : {
+ key: 'ok',
+ label: l.ok_button,
+ className: 'positive',
+ onClick: () => this.closePermissionsDialog(Av.Audio)
+ }]
+ },
+ browser: {
+ title: l.no_mic_title,
+ cover: 'permissions-mic',
+ info: l.allow_mic_access.replace('[X]', ''),
+ buttons: [{
+ key: 'ok',
+ label: l.ok_button,
+ className: 'positive',
+ onClick: () => this.closePermissionsDialog(Av.Audio)
+ }]
+ },
+ nil: {
+ title: l.no_mic_detected_title,
+ info: l.no_mic_detected_info,
+ buttons: [{
+ key: 'ok',
+ label: l.ok_button,
+ className: 'positive',
+ onClick: () => this.closePermissionsDialog(Av.Audio)
+ }]
+ },
+ shared: {
+ title: l.no_mic_title,
+ info: l.shared_mic_err_info.replace('[A]', ``).replace('[/A]', ''),
+ buttons: [{
+ key: 'ok',
+ label: l.ok_button,
+ className: 'positive',
+ onClick: () => this.closePermissionsDialog(Av.Audio)
+ }]
+ }
+ },
+ [Av.Camera]: {
+ system: {
+ title: l.no_camera_title,
+ info: this.platform === 'Windows' ? l.no_camera_system_windows.replace('[A]', ``).replace('[/A]', '') : l.no_camera_system_mac.replace('[A]', ``).replace('[/A]', ''),
+ buttons: [this.platform === 'Apple' || this.platform === 'Windows' ? {
+ key: 'open-settings',
+ label: l.open_system_settings,
+ className: 'positive',
+ onClick: () => {
+ window.open(this.platform === 'Apple' ? `${this.macURI}?Privacy_Camera` : `${this.winURI}:privacy-webcam`, '_blank', 'noopener,noreferrer');
+ this.closePermissionsDialog(Av.Camera);
+ }
+ } : {
+ key: 'ok',
+ label: l.ok_button,
+ className: 'positive',
+ onClick: () => this.closePermissionsDialog(Av.Camera)
+ }]
+ },
+ browser: {
+ title: l.no_camera_title,
+ cover: 'permissions-camera',
+ info: l.allow_camera_access.replace('[X]', ''),
+ buttons: [{
+ key: 'ok',
+ label: l.ok_button,
+ className: 'positive',
+ onClick: () => this.closePermissionsDialog(Av.Camera)
+ }]
+ },
+ nil: {
+ title: l.no_camera_detected_title,
+ info: l.no_camera_detected_info,
+ buttons: [{
+ key: 'ok',
+ label: l.ok_button,
+ className: 'positive',
+ onClick: () => this.closePermissionsDialog(Av.Camera)
+ }]
+ },
+ shared: {
+ title: l.no_camera_title,
+ info: l.shared_cam_err_info.replace('[A]', ``).replace('[/A]', ''),
+ buttons: [{
+ key: 'ok',
+ label: l.ok_button,
+ className: 'positive',
+ onClick: () => this.closePermissionsDialog(Av.Camera)
+ }]
+ }
+ },
+ [Av.Screen]: {
+ title: l.no_screen_title,
+ info: l.no_screen_system.replace('[A]', ``).replace('[/A]', ''),
+ buttons: [{
+ key: 'open-settings',
+ label: l.open_system_settings,
+ className: 'positive',
+ onClick: () => {
+ window.open(`${this.macURI}?Privacy_ScreenCapture`, '_blank', 'noopener,noreferrer');
+ this.closePermissionsDialog(Av.Screen);
+ }
+ }]
+ }
+ };
+ this.state = {
+ errMic: '',
+ errCamera: '',
+ errScreen: '',
+ [`dialog-${Av.Audio}`]: null,
+ [`dialog-${Av.Camera}`]: null,
+ [`dialog-${Av.Screen}`]: null
+ };
+ this.getPermissionsDialogContent = () => {
+ const {
+ CONTENT,
+ state
+ } = this;
+ const {
+ errMic,
+ errCamera
+ } = state;
+ const {
+ browser,
+ system,
+ nil,
+ sharedCam,
+ sharedMic,
+ sharedGeneric
+ } = errors;
+ return {
+ [Av.Audio]: {
+ ...errMic === browser && CONTENT[Av.Audio].browser,
+ ...errMic === system && CONTENT[Av.Audio].system,
+ ...errMic === nil && CONTENT[Av.Audio].nil,
+ ...errMic === sharedMic && CONTENT[Av.Audio].shared,
+ ...errMic === sharedGeneric && CONTENT[Av.Audio].shared
+ },
+ [Av.Camera]: {
+ ...errCamera === browser && CONTENT[Av.Camera].browser,
+ ...errCamera === system && CONTENT[Av.Camera].system,
+ ...errCamera === nil && CONTENT[Av.Camera].nil,
+ ...errCamera === sharedCam && CONTENT[Av.Camera].shared,
+ ...errCamera === sharedGeneric && CONTENT[Av.Camera].shared
+ },
+ [Av.Screen]: CONTENT[Av.Screen]
+ };
+ };
+ this.resetError = av => {
+ this.setState({
+ errMic: av === Av.Audio ? '' : this.state.errMic,
+ errCamera: av === Av.Camera ? '' : this.state.errCamera,
+ errScreen: av === Av.Screen ? '' : this.state.errScreen
+ });
+ };
+ this.hasToRenderPermissionsWarning = this.hasToRenderPermissionsWarning.bind(this);
+ this.renderPermissionsWarning = this.renderPermissionsWarning.bind(this);
+ }
+ hasToRenderPermissionsWarning(av) {
+ const CONFIG = {
+ [Av.Audio]: {
+ showOnUserActionError: true,
+ err: this.state.errMic
+ },
+ [Av.Camera]: {
+ showOnUserActionError: true,
+ err: this.state.errCamera
+ },
+ [Av.Screen]: {
+ showOnUserActionError: false,
+ err: this.state.errScreen
+ }
+ };
+ const current = CONFIG[av];
+ if (current) {
+ return isUserActionError(current.err) ? current.showOnUserActionError : current.err;
+ }
+ return false;
+ }
+ closePermissionsDialog(av) {
+ this.setState({
+ [`dialog-${av}`]: false
+ }, () => {
+ let _this$childRef;
+ return (_this$childRef = this.childRef) == null ? void 0 : _this$childRef.safeForceUpdate();
+ });
+ }
+ renderPermissionsDialog(av, child) {
+ const content = this.getPermissionsDialogContent();
+ const {
+ title,
+ info,
+ buttons,
+ cover
+ } = content[av] || {};
+ return JSX_(_ui_modalDialogs_jsx3__ .A.ModalDialog, {
+ dialogName: `${this.namespace}-permissions-${av}`,
+ className: `
+ meetings-permissions-dialog
+ dialog-template-message
+ with-close-btn
+ warning
+ `,
+ buttons,
+ hideOverlay: Component.NAMESPACE === 'preview-meeting' && !document.body.classList.contains('not-logged'),
+ onClose: () => {
+ this.setState({
+ [`dialog-${av}`]: false
+ }, () => child && child.safeForceUpdate());
+ }
+ }, JSX_("header", null, cover ? null : JSX_("div", {
+ className: "graphic"
+ }, JSX_("i", {
+ className: "warning sprite-fm-uni icon-warning"
+ })), JSX_("div", {
+ className: "info-container"
+ }, JSX_("h3", {
+ id: "msgDialog-title"
+ }, title || l[47]), cover && JSX_("div", {
+ className: "permissions-warning-cover"
+ }, JSX_("span", {
+ className: cover
+ })), JSX_(_ui_utils_jsx4__ .P9, {
+ tag: "p",
+ className: "permissions-warning-info",
+ content: info
+ }))));
+ }
+ renderPermissionsWarning(av, child) {
+ const {
+ errMic,
+ errCamera
+ } = this.state;
+ const dismissed = errMic === errors.dismissed || errCamera === errors.dismissed;
+ return JSX_("div", {
+ className: `
+ ${this.namespace}
+ meetings-signal-issue
+ simpletip
+ ${dismissed ? 'with-small-area' : ''}
+ `,
+ "data-simpletip": l.show_info,
+ "data-simpletipposition": "top",
+ "data-simpletipoffset": "5",
+ "data-simpletip-class": "theme-dark-forced",
+ onClick: () => dismissed ? null : this.setState({
+ [`dialog-${av}`]: true
+ }, () => {
+ if (child) {
+ this.childRef = child;
+ }
+ })
+ }, JSX_("span", {
+ className: "signal-issue-background"
+ }), JSX_("i", {
+ className: "sprite-fm-mono icon-exclamation-filled"
+ }), this.state[`dialog-${av}`] && this.renderPermissionsDialog(av, child));
+ }
+ componentWillUnmount() {
+ super.componentWillUnmount();
+ megaChat.unbind(this.observer);
+ }
+ componentDidMount() {
+ super.componentDidMount();
+ megaChat.rebind(this.observer, (ev, errAv) => {
+ this.setState({
+ errMic: errAv && errAv.mic ? String(errAv.mic) : this.state.errMic,
+ errCamera: errAv && errAv.camera ? String(errAv.camera) : this.state.errCamera,
+ errScreen: errAv && errAv.screen ? String(errAv.screen) : this.state.errScreen
+ });
+ });
+ megaChat.rebind(`onLocalMediaQueryError.${this.namespace}`, (ev, {
+ type,
+ err
+ }) => {
+ if (type === 'screen' && String(err) === errors.system) {
+ this.setState({
+ [`dialog-${Av.Screen}`]: true
+ }, () => this.safeForceUpdate());
+ }
+ });
+ }
+ render() {
+ return JSX_(Component, (0,_babel_runtime_helpers_extends0__ .A)({}, this.props, this.state, {
+ errMic: this.state.errMic,
+ errCamera: this.state.errCamera,
+ errScreen: this.state.errScreen,
+ hasToRenderPermissionsWarning: this.hasToRenderPermissionsWarning,
+ resetError: this.resetError,
+ renderPermissionsWarning: this.renderPermissionsWarning
+ }));
+ }
+ };
+};
+
+ },
+
+ 3546
+(_, EXP_, REQ_) {
+
+ REQ_.d(EXP_, {
+ A: () => __WEBPACK_DEFAULT_EXPORT__
+ });
+ const react0__ = REQ_(1594);
+ const react0___default = REQ_.n(react0__);
+ const _mixins_js1__ = REQ_(8264);
+ const _contacts_jsx2__ = REQ_(8022);
+ const _utils_jsx3__ = REQ_(3901);
+ const _button_jsx4__ = REQ_(6740);
+ const _permissionsObserver_jsx5__ = REQ_(192);
+
+
+
+
+
+
+class Preview extends react0___default().Component {
+ constructor(props) {
+ super(props);
+ this.domRef = react0___default().createRef();
+ this.videoRef = react0___default().createRef();
+ this.stream = null;
+ this.state = {
+ audio: false,
+ video: false,
+ avatarMeta: undefined
+ };
+ this.getTrackType = type => !type ? 'getTracks' : type === Preview.STREAMS.AUDIO ? 'getAudioTracks' : 'getVideoTracks';
+ this.startStream = type => {
+ this.stopStream();
+ const {
+ audio,
+ video
+ } = this.state;
+ navigator.mediaDevices.getUserMedia({
+ audio,
+ video
+ }).then(stream => {
+ const videoRef = this.videoRef.current;
+ if (videoRef) {
+ videoRef.srcObject = stream;
+ this.stream = stream;
+ if (this.props.onToggle) {
+ this.props.onToggle(this.state.audio, this.state.video);
+ }
+ }
+ }).catch(ex => {
+ const stream = type === Preview.STREAMS.AUDIO ? 'audio' : 'video';
+ return this.domRef.current && this.setState(state => ({
+ [stream]: !state[stream]
+ }), () => {
+ megaChat.trigger('onLocalMediaError', {
+ [type === Preview.STREAMS.AUDIO ? 'mic' : 'camera']: `${ex.name}: ${ex.message}`
+ });
+ console.error(`${ex.name}: ${ex.message}`);
+ });
+ });
+ };
+ this.stopStream = type => {
+ if (this.stream) {
+ const trackType = this.getTrackType(type);
+ const tracks = this.stream[trackType]();
+ for (const track of tracks) {
+ track.stop();
+ }
+ }
+ };
+ this.toggleStream = type => {
+ let _this$props$resetErro, _this$props;
+ const stream = type === Preview.STREAMS.AUDIO ? 'audio' : 'video';
+ this.setState(state => ({
+ [stream]: !state[stream]
+ }), () => {
+ if (this.props.onToggle) {
+ this.props.onToggle(this.state.audio, this.state.video);
+ }
+ return this.state[stream] ? this.startStream(type) : this.stopStream(type);
+ });
+ (_this$props$resetErro = (_this$props = this.props).resetError) == null || _this$props$resetErro.call(_this$props, type === Preview.STREAMS.AUDIO ? Av.Audio : Av.Camera);
+ };
+ this.renderAvatar = () => {
+ if ((0,_utils_jsx3__ .P)()) {
+ return JSX_("div", {
+ className: "avatar-guest"
+ }, JSX_("i", {
+ className: "sprite-fm-uni icon-owner"
+ }));
+ }
+ if (is_chatlink) {
+ const {
+ avatarUrl,
+ color,
+ shortName
+ } = this.state.avatarMeta || {};
+ return JSX_("div", {
+ className: `
+ avatar-wrapper
+ ${color ? `color${color}` : ''}
+ `
+ }, avatarUrl && JSX_("img", {
+ src: avatarUrl,
+ alt: ""
+ }), color && JSX_("span", null, shortName));
+ }
+ return JSX_(_contacts_jsx2__ .eu, {
+ contact: M.u[u_handle]
+ });
+ };
+ this.state.audio = this.props.audio || this.state.audio;
+ if (this.props.video) {
+ this.state.video = this.props.video;
+ this.startStream(Preview.STREAMS.VIDEO);
+ this.props.onToggle(this.state.audio, this.state.video);
+ }
+ }
+ componentWillUnmount() {
+ this.stopStream();
+ }
+ componentDidMount() {
+ if (this.props.onToggle) {
+ this.props.onToggle(this.state.audio, this.state.video);
+ }
+ this.setState({
+ avatarMeta: is_chatlink ? generateAvatarMeta(u_handle) : undefined
+ });
+ }
+ render() {
+ const {
+ NAMESPACE
+ } = Preview;
+ const {
+ hasToRenderPermissionsWarning,
+ renderPermissionsWarning
+ } = this.props;
+ const {
+ audio,
+ video
+ } = this.state;
+ const SIMPLETIP_PROPS = {
+ label: undefined,
+ position: 'top',
+ className: 'theme-dark-forced'
+ };
+ return JSX_("div", {
+ ref: this.domRef,
+ className: `
+ ${NAMESPACE}
+ local-stream-mirrored
+ `
+ }, video && JSX_("div", {
+ className: `${NAMESPACE}-video-overlay`
+ }), JSX_("video", {
+ className: video ? 'streaming' : '',
+ muted: true,
+ autoPlay: true,
+ ref: this.videoRef
+ }), !video && this.renderAvatar(), JSX_("div", {
+ className: `${NAMESPACE}-controls`
+ }, JSX_("div", {
+ className: "preview-control-wrapper"
+ }, JSX_(_button_jsx4__ .A, {
+ simpletip: {
+ ...SIMPLETIP_PROPS,
+ label: audio ? l[16214] : l[16708]
+ },
+ className: `
+ mega-button
+ round
+ theme-light-forced
+ ${NAMESPACE}-control
+ ${audio ? '' : 'with-fill'}
+ `,
+ icon: audio ? 'icon-mic-thin-outline' : 'icon-mic-off-thin-outline',
+ onClick: () => {
+ this.toggleStream(Preview.STREAMS.AUDIO);
+ }
+ }), JSX_("span", null, l.mic_button), hasToRenderPermissionsWarning(Av.Audio) ? renderPermissionsWarning(Av.Audio) : null), JSX_("div", {
+ className: "preview-control-wrapper"
+ }, JSX_(_button_jsx4__ .A, {
+ simpletip: {
+ ...SIMPLETIP_PROPS,
+ label: video ? l[22894] : l[22893]
+ },
+ className: `
+ mega-button
+ round
+ theme-light-forced
+ ${NAMESPACE}-control
+ ${video ? '' : 'with-fill'}
+ `,
+ icon: video ? 'icon-video-thin-outline' : 'icon-video-off-thin-outline',
+ onClick: () => this.toggleStream(Preview.STREAMS.VIDEO)
+ }), JSX_("span", null, l.camera_button), hasToRenderPermissionsWarning(Av.Camera) ? renderPermissionsWarning(Av.Camera) : null)));
+ }
+}
+Preview.NAMESPACE = 'preview-meeting';
+Preview.STREAMS = {
+ AUDIO: 1,
+ VIDEO: 2
+};
+ const __WEBPACK_DEFAULT_EXPORT__ = (0,_mixins_js1__ .Zz)(_permissionsObserver_jsx5__ .$)(Preview);
+
+ },
+
+ 7190
+(_, EXP_, REQ_) {
+
+REQ_.r(EXP_);
+ REQ_.d(EXP_, {
+ "default": () => Start
+ });
+ const _babel_runtime_helpers_extends0__ = REQ_(8168);
+ const react1__ = REQ_(1594);
+ const react1___default = REQ_.n(react1__);
+ const _ui_modalDialogs_jsx2__ = REQ_(8120);
+ const _button_jsx3__ = REQ_(6740);
+ const _preview_jsx4__ = REQ_(3546);
+ const _link_jsx5__ = REQ_(4649);
+ const _ui_utils6__ = REQ_(6411);
+
+let _Start;
+
+
+
+
+
+
+class Start extends react1___default().Component {
+ constructor(props) {
+ super(props);
+ this.inputRef = react1___default().createRef();
+ this.defaultTopic = l.default_meeting_topic.replace('%NAME', M.getNameByHandle(u_handle));
+ this.state = {
+ audio: false,
+ video: false,
+ editing: false,
+ previousTopic: undefined,
+ topic: undefined
+ };
+ this.handleChange = ev => this.setState({
+ topic: ev.target.value
+ });
+ this.toggleEdit = () => {
+ this.setState(state => {
+ const topic = state.topic.trim() || this.defaultTopic;
+ return {
+ editing: !state.editing,
+ topic,
+ previousTopic: topic
+ };
+ }, () => onIdle(this.doFocus));
+ };
+ this.doFocus = () => {
+ if (this.state.editing) {
+ const input = this.inputRef.current;
+ input.focus();
+ input.setSelectionRange(0, input.value.length);
+ }
+ };
+ this.doReset = () => this.setState(state => ({
+ editing: false,
+ topic: state.previousTopic,
+ previousTopic: undefined
+ }));
+ this.bindEvents = () => $(document).rebind(`mousedown.${Start.NAMESPACE}`, ev => {
+ if (this.state.editing && !ev.target.classList.contains(Start.CLASS_NAMES.EDIT) && !ev.target.classList.contains(Start.CLASS_NAMES.INPUT)) {
+ this.toggleEdit();
+ }
+ }).rebind(`keyup.${Start.NAMESPACE}`, ({
+ keyCode
+ }) => {
+ if (this.state.editing) {
+ const [ENTER, ESCAPE] = [13, 27];
+ return keyCode === ENTER ? this.toggleEdit() : keyCode === ESCAPE ? this.doReset() : null;
+ }
+ });
+ this.Input = () => JSX_("input", {
+ type: "text",
+ ref: this.inputRef,
+ className: Start.CLASS_NAMES.INPUT,
+ value: this.state.topic,
+ maxLength: ChatRoom.TOPIC_MAX_LENGTH,
+ onChange: this.handleChange
+ });
+ this.onStreamToggle = (audio, video) => this.setState({
+ audio,
+ video
+ });
+ this.startMeeting = () => {
+ const {
+ onStart
+ } = this.props;
+ const {
+ topic,
+ audio,
+ video
+ } = this.state;
+ if (onStart) {
+ onStart(topic.trim() || this.defaultTopic, audio, video);
+ }
+ };
+ this.state.topic = this.defaultTopic;
+ }
+ componentDidMount() {
+ this.bindEvents();
+ if ($.dialog === 'onboardingDialog') {
+ closeDialog();
+ }
+ M.safeShowDialog(Start.dialogName, () => $(`#${Start.NAMESPACE}`));
+ }
+ componentWillUnmount() {
+ $(document).unbind(`.${Start.NAMESPACE}`);
+ if ($.dialog === Start.dialogName) {
+ closeDialog();
+ }
+ }
+ render() {
+ const {
+ NAMESPACE,
+ CLASS_NAMES
+ } = Start;
+ const {
+ editing,
+ topic
+ } = this.state;
+ return JSX_(_ui_modalDialogs_jsx2__ .A.ModalDialog, (0,_babel_runtime_helpers_extends0__ .A)({}, this.state, {
+ id: NAMESPACE,
+ dialogName: NAMESPACE,
+ className: NAMESPACE,
+ stopKeyPropagation: editing,
+ onClose: () => this.props.onClose()
+ }), JSX_("div", {
+ className: `${NAMESPACE}-preview`
+ }, JSX_(_preview_jsx4__ .A, {
+ context: NAMESPACE,
+ onToggle: this.onStreamToggle
+ })), JSX_("div", {
+ className: "fm-dialog-body"
+ }, JSX_("div", {
+ className: `${NAMESPACE}-title`
+ }, editing ? JSX_(this.Input, null) : JSX_("h2", {
+ onClick: this.toggleEdit
+ }, JSX_(_ui_utils6__ .zT, null, topic)), JSX_(_button_jsx3__ .A, {
+ className: `
+ mega-button
+ action
+ small
+ ${CLASS_NAMES.EDIT}
+ ${editing ? 'editing' : ''}
+ `,
+ icon: "icon-rename",
+ simpletip: {
+ label: l[1342],
+ position: 'top'
+ },
+ onClick: this.toggleEdit
+ }, JSX_("span", null, l[1342]))), JSX_(_button_jsx3__ .A, {
+ className: "mega-button positive large start-meeting-button",
+ onClick: () => {
+ this.startMeeting();
+ eventlog(500235);
+ }
+ }, JSX_("span", null, l[7315])), JSX_(_link_jsx5__ .A, {
+ to: "https://mega.io/chatandmeetings",
+ target: "_blank"
+ }, l.how_meetings_work)));
+ }
+}
+_Start = Start;
+Start.NAMESPACE = 'start-meeting';
+Start.dialogName = `${_Start.NAMESPACE}-dialog`;
+Start.CLASS_NAMES = {
+ EDIT: 'call-title-edit',
+ INPUT: 'call-title-input'
+};
+Start.STREAMS = {
+ AUDIO: 1,
+ VIDEO: 2
+};
+
+ },
+
+ 5199
+(_, EXP_, REQ_) {
+
+REQ_.r(EXP_);
+ REQ_.d(EXP_, {
+ "default": () => StartGroupChatWizard
+ });
+ const react0__ = REQ_(1594);
+ const react0___default = REQ_.n(react0__);
+ const _mixins_js1__ = REQ_(8264);
+ const _ui_miniui_jsx2__ = REQ_(5009);
+ const _contacts_jsx3__ = REQ_(8022);
+ const _ui_modalDialogs_jsx4__ = REQ_(8120);
+
+
+
+
+
+class StartGroupChatWizard extends _mixins_js1__ .w9 {
+ constructor(props) {
+ super(props);
+ this.dialogName = 'start-group-chat';
+ this.domRef = react0___default().createRef();
+ this.inputContainerRef = react0___default().createRef();
+ this.inputRef = react0___default().createRef();
+ let haveContacts = false;
+ const keys = M.u.keys();
+ for (let i = 0; i < keys.length; i++) {
+ if (M.u[keys[i]].c === 1) {
+ haveContacts = true;
+ break;
+ }
+ }
+ this.state = {
+ 'selected': this.props.selected ? this.props.selected : [],
+ haveContacts,
+ 'step': this.props.flowType === 2 || !haveContacts ? 1 : 0,
+ 'keyRotation': false,
+ 'createChatLink': this.props.flowType === 2,
+ 'groupName': '',
+ openInvite: 1
+ };
+ this.onFinalizeClick = this.onFinalizeClick.bind(this);
+ this.onSelectClicked = this.onSelectClicked.bind(this);
+ this.onSelected = this.onSelected.bind(this);
+ }
+ onSelected(nodes) {
+ this.setState({
+ 'selected': nodes
+ });
+ if (this.props.onSelected) {
+ this.props.onSelected(nodes);
+ }
+ }
+ onSelectClicked() {
+ if (this.props.onSelectClicked) {
+ this.props.onSelectClicked();
+ }
+ }
+ onFinalizeClick(e) {
+ if (e) {
+ e.preventDefault();
+ e.stopPropagation();
+ }
+ const {
+ groupName,
+ selected,
+ keyRotation,
+ createChatLink,
+ openInvite
+ } = this.state;
+ megaChat.createAndShowGroupRoomFor(selected, groupName.trim(), {
+ keyRotation,
+ createChatLink: keyRotation ? false : createChatLink,
+ openInvite
+ });
+ this.props.onClose(this);
+ eventlog(500236);
+ }
+ componentDidMount() {
+ super.componentDidMount();
+ if (!this.props.subDialog) {
+ M.safeShowDialog(this.dialogName, nop);
+ }
+ }
+ componentWillUnmount() {
+ super.componentWillUnmount();
+ if ($.dialog === this.dialogName) {
+ closeDialog();
+ }
+ }
+ render() {
+ const self = this;
+ const classes = `new-group-chat contrast small-footer contact-picker-widget ${ self.props.className}`;
+ let contacts = M.u;
+ const {haveContacts} = self.state;
+ const buttons = [];
+ let allowNext = false;
+ let failedToEnableChatlink = self.state.failedToEnableChatlink && self.state.createChatLink === true && !self.state.groupName;
+ if (self.state.keyRotation) {
+ failedToEnableChatlink = false;
+ }
+ let extraContent;
+ if (this.props.extraContent) {
+ self.state.step = 0;
+ extraContent = JSX_("div", {
+ className: "content-block imported"
+ });
+ } else if (self.state.step === 0 && haveContacts) {
+ allowNext = true;
+ buttons.push({
+ "label": self.props.cancelLabel,
+ "key": "cancel",
+ "onClick" (e) {
+ self.props.onClose(self);
+ e.preventDefault();
+ e.stopPropagation();
+ }
+ });
+ buttons.push({
+ "label": l[556],
+ "key": "next",
+ "className": !allowNext ? "disabled positive" : "positive",
+ "onClick" (e) {
+ e.preventDefault();
+ e.stopPropagation();
+ self.setState({
+ 'step': 1
+ });
+ }
+ });
+ } else if (self.state.step === 1) {
+ allowNext = self.state.createChatLink ? !failedToEnableChatlink : true;
+ contacts = [];
+ self.state.selected.forEach((h) => {
+ if (h in M.u) {
+ contacts.push(M.u[h]);
+ }
+ });
+ if (!haveContacts || this.props.flowType === 2) {
+ buttons.push({
+ "label": self.props.cancelLabel,
+ "key": "cancel",
+ "onClick" (e) {
+ self.props.onClose(self);
+ e.preventDefault();
+ e.stopPropagation();
+ }
+ });
+ } else {
+ buttons.push({
+ "label": l[822],
+ "key": "back",
+ "onClick" (e) {
+ e.preventDefault();
+ e.stopPropagation();
+ self.setState({
+ 'step': 0
+ });
+ }
+ });
+ }
+ buttons.push({
+ "label": l[726],
+ "key": "done",
+ "className": !allowNext ? "positive disabled" : "positive",
+ "onClick" (e) {
+ if (self.state.createChatLink === true && !self.state.groupName) {
+ self.setState({
+ 'failedToEnableChatlink': true
+ });
+ } else {
+ self.onFinalizeClick(e);
+ }
+ }
+ });
+ }
+ let chatInfoElements;
+ if (self.state.step === 1) {
+ let _this$state$groupName;
+ let checkboxClassName = self.state.createChatLink ? "checkboxOn" : "checkboxOff";
+ if (failedToEnableChatlink && self.state.createChatLink) {
+ checkboxClassName += " intermediate-state";
+ }
+ if (self.state.keyRotation) {
+ checkboxClassName = "checkboxOff";
+ }
+ chatInfoElements = JSX_(react0___default().Fragment, null, JSX_("div", {
+ className: `
+ contacts-search-header left-aligned top-pad
+ ${failedToEnableChatlink ? 'failed' : ''}
+ `
+ }, JSX_("div", {
+ className: `
+ mega-input
+ with-icon
+ box-style
+ ${((_this$state$groupName = this.state.groupName) == null ? void 0 : _this$state$groupName.length) > 0 ? 'valued' : ''}
+ ${failedToEnableChatlink ? 'error msg' : ''}
+ `,
+ ref: this.inputContainerRef
+ }, JSX_("i", {
+ className: "sprite-fm-mono icon-channel-new"
+ }), JSX_("input", {
+ autoFocus: true,
+ className: "megaInputs",
+ type: "text",
+ ref: this.inputRef,
+ placeholder: l[18509],
+ value: this.state.groupName,
+ maxLength: ChatRoom.TOPIC_MAX_LENGTH,
+ onKeyDown: e => {
+ const code = e.which || e.keyCode;
+ if (allowNext && code === 13 && self.state.step === 1) {
+ this.onFinalizeClick();
+ }
+ },
+ onChange: e => {
+ const containerRef = this.inputContainerRef.current;
+ const {
+ value
+ } = e.target;
+ containerRef.classList[value.length > 0 ? 'add' : 'remove']('valued');
+ this.setState({
+ groupName: value,
+ failedToEnableChatlink: false
+ });
+ }
+ }))), this.props.flowType === 2 ? null : JSX_("div", {
+ className: "group-chat-dialog content"
+ }, JSX_(_ui_miniui_jsx2__ .A.ToggleCheckbox, {
+ className: "rotation-toggle",
+ checked: this.state.keyRotation,
+ onToggle: keyRotation => this.setState({
+ keyRotation
+ }, () => this.inputRef.current.focus())
+ }), JSX_("div", {
+ className: "group-chat-dialog header"
+ }, l[20576]), JSX_("div", {
+ className: "group-chat-dialog description"
+ }, l[20484]), JSX_(_ui_miniui_jsx2__ .A.ToggleCheckbox, {
+ className: "open-invite-toggle",
+ checked: this.state.openInvite,
+ value: this.state.openInvite,
+ onToggle: openInvite => this.setState({
+ openInvite
+ }, () => this.inputRef.current.focus())
+ }), JSX_("div", {
+ className: "group-chat-dialog header"
+ }, l.open_invite_label), JSX_("div", {
+ className: "group-chat-dialog description"
+ }, l.open_invite_desc), JSX_("div", {
+ className: `
+ group-chat-dialog checkbox
+ ${this.state.keyRotation ? 'disabled' : ''}
+ ${failedToEnableChatlink ? 'failed' : ''}
+ `,
+ onClick: () => {
+ delay('chatWizard-createChatLink', () => {
+ this.setState(state => ({
+ createChatLink: !state.createChatLink
+ }));
+ this.inputRef.current.focus();
+ }, 100);
+ }
+ }, JSX_("div", {
+ className: `checkdiv ${checkboxClassName}`
+ }, JSX_("input", {
+ type: "checkbox",
+ name: "group-encryption",
+ id: "group-encryption",
+ className: "checkboxOn hidden"
+ })), JSX_("label", {
+ htmlFor: "group-encryption",
+ className: "radio-txt lato mid"
+ }, l[20575]), JSX_("div", {
+ className: "clear"
+ }))), failedToEnableChatlink ? JSX_("div", {
+ className: "group-chat-dialog description chatlinks-intermediate-msg"
+ }, l[20573]) : null);
+ }
+ return JSX_(_ui_modalDialogs_jsx4__ .A.ModalDialog, {
+ step: self.state.step,
+ title: this.props.flowType === 2 && self.state.createChatLink ? l[20638] : this.props.customDialogTitle || l[19483],
+ className: classes,
+ dialogType: "tool",
+ dialogName: "group-chat-dialog",
+ showSelectedNum: self.props.showSelectedNum,
+ selectedNum: self.state.selected.length,
+ closeDlgOnClickOverlay: self.props.closeDlgOnClickOverlay,
+ onClose: () => {
+ self.props.onClose(self);
+ },
+ popupDidMount: elem => {
+ if (this.props.extraContent) {
+ let _elem$querySelector;
+ (_elem$querySelector = elem.querySelector('.content-block.imported')) == null || _elem$querySelector.appendChild(this.props.extraContent);
+ }
+ if (this.props.onExtraContentDidMount) {
+ this.props.onExtraContentDidMount(elem);
+ }
+ },
+ triggerResizeOnUpdate: true,
+ buttons
+ }, JSX_("div", {
+ ref: this.domRef,
+ className: "content-block"
+ }, chatInfoElements, JSX_(_contacts_jsx3__ .hU, {
+ step: self.state.step,
+ exclude: self.props.exclude,
+ contacts,
+ selectableContacts: "true",
+ onSelectDone: self.onSelectClicked,
+ onSelected: self.onSelected,
+ selected: self.state.selected,
+ headerClasses: "left-aligned",
+ multiple: true,
+ readOnly: self.state.step !== 0,
+ allowEmpty: true,
+ showMeAsSelected: self.state.step === 1,
+ className: self.props.pickerClassName,
+ disableFrequents: self.props.disableFrequents,
+ skipMailSearch: self.props.skipMailSearch,
+ autoFocusSearchField: self.props.autoFocusSearchField,
+ selectCleanSearchRes: self.props.selectCleanSearchRes,
+ disableDoubleClick: self.props.disableDoubleClick,
+ selectedWidthSize: self.props.selectedWidthSize,
+ emptySelectionMsg: self.props.emptySelectionMsg,
+ newEmptySearchResult: self.props.newEmptySearchResult,
+ newNoContact: self.props.newNoContact,
+ highlightSearchValue: self.props.highlightSearchValue,
+ emailTooltips: self.props.emailTooltips
+ })), extraContent);
+ }
+}
+StartGroupChatWizard.clickTime = 0;
+StartGroupChatWizard.defaultProps = {
+ 'selectLabel': l[1940],
+ 'cancelLabel': l.msg_dlg_cancel,
+ 'hideable': true,
+ 'flowType': 1,
+ 'pickerClassName': '',
+ 'showSelectedNum': false,
+ 'disableFrequents': false,
+ 'skipMailSearch': false,
+ 'autoFocusSearchField': true,
+ 'selectCleanSearchRes': true,
+ 'disableDoubleClick': false,
+ 'newEmptySearchResult': false,
+ 'newNoContact': false,
+ 'closeDlgOnClickOverlay': true,
+ 'emailTooltips': false
+};
+
+ },
+
+ 5009
+(_, EXP_, REQ_) {
+
+ REQ_.d(EXP_, {
+ A: () => __WEBPACK_DEFAULT_EXPORT__
+ });
+ const react0__ = REQ_(1594);
+ const react0___default = REQ_.n(react0__);
+ const _chat_mixins1__ = REQ_(8264);
+
+
+class ToggleCheckbox extends _chat_mixins1__ .w9 {
+ constructor(props) {
+ super(props);
+ this.domRef = react0___default().createRef();
+ this.onToggle = () => {
+ const newState = !this.state.value;
+ this.setState({
+ value: newState
+ });
+ if (this.props.onToggle) {
+ this.props.onToggle(newState);
+ }
+ };
+ this.state = {
+ value: this.props.value
+ };
+ }
+ render() {
+ return JSX_("div", {
+ ref: this.domRef,
+ className: `
+ mega-switch
+ ${this.props.className}
+ ${this.state.value ? 'toggle-on' : ''}
+ `,
+ role: "switch",
+ "aria-checked": !!this.state.value,
+ onClick: this.onToggle
+ }, JSX_("div", {
+ className: `mega-feature-switch sprite-fm-mono-after
+ ${this.state.value ? 'icon-check-after' : 'icon-minimise-after'}`
+ }));
+ }
+}
+ const __WEBPACK_DEFAULT_EXPORT__ = {
+ ToggleCheckbox
+};
+
+ }
+
+}]);
\ No newline at end of file
diff --git a/js/chat/bundle.waiting-room.js b/js/chat/bundle.waiting-room.js
new file mode 100644
index 0000000000..d3b5cc4759
--- /dev/null
+++ b/js/chat/bundle.waiting-room.js
@@ -0,0 +1,1150 @@
+/** @file automatically generated, do not edit it. */
+"use strict";
+(self.webpackChunk_meganz_webclient = self.webpackChunk_meganz_webclient || []).push([[752],{
+
+ 192
+(_, EXP_, REQ_) {
+
+ REQ_.d(EXP_, {
+ $: () => withPermissionsObserver
+ });
+ const _babel_runtime_helpers_extends0__ = REQ_(8168);
+ const react1__ = REQ_(1594);
+ const react1___default = REQ_.n(react1__);
+ const _mixins_js2__ = REQ_(8264);
+ const _ui_modalDialogs_jsx3__ = REQ_(8120);
+ const _ui_utils_jsx4__ = REQ_(6411);
+
+
+
+
+
+const errors = {
+ browser: 'NotAllowedError: Permission denied',
+ system: 'NotAllowedError: Permission denied by system',
+ dismissed: 'NotAllowedError: Permission dismissed',
+ nil: 'NotFoundError: Requested device not found',
+ sharedCam: 'NotReadableError: Could not start video source',
+ sharedMic: 'NotReadableError: Could not start audio source',
+ sharedGeneric: 'NotReadableError: Device in use'
+};
+const isUserActionError = error => {
+ return error && error === errors.browser;
+};
+const withPermissionsObserver = Component => {
+ return class extends _mixins_js2__ .w9 {
+ constructor(props) {
+ super(props);
+ this.namespace = `PO-${Component.NAMESPACE}`;
+ this.observer = `onLocalMediaError.${this.namespace}`;
+ this.childRef = undefined;
+ this.platform = ua.details.os;
+ this.helpURL = `${l.mega_help_host}/chats-meetings/meetings/enable-audio-video-call-permissions`;
+ this.macURI = 'x-apple.systempreferences:com.apple.preference.security';
+ this.winURI = 'ms-settings';
+ this.CONTENT = {
+ [Av.Audio]: {
+ system: {
+ title: l.no_mic_title,
+ info: this.platform === 'Windows' ? l.no_mic_system_windows.replace('[A]', ``).replace('[/A]', '') : l.no_mic_system_mac.replace('[A]', ``).replace('[/A]', ''),
+ buttons: [this.platform === 'Apple' || this.platform === 'Windows' ? {
+ key: 'open-settings',
+ label: l.open_system_settings,
+ className: 'positive',
+ onClick: () => {
+ window.open(this.platform === 'Apple' ? `${this.macURI}?Privacy_Microphone` : `${this.winURI}:privacy-microphone`, '_blank', 'noopener,noreferrer');
+ this.closePermissionsDialog(Av.Audio);
+ }
+ } : {
+ key: 'ok',
+ label: l.ok_button,
+ className: 'positive',
+ onClick: () => this.closePermissionsDialog(Av.Audio)
+ }]
+ },
+ browser: {
+ title: l.no_mic_title,
+ cover: 'permissions-mic',
+ info: l.allow_mic_access.replace('[X]', ''),
+ buttons: [{
+ key: 'ok',
+ label: l.ok_button,
+ className: 'positive',
+ onClick: () => this.closePermissionsDialog(Av.Audio)
+ }]
+ },
+ nil: {
+ title: l.no_mic_detected_title,
+ info: l.no_mic_detected_info,
+ buttons: [{
+ key: 'ok',
+ label: l.ok_button,
+ className: 'positive',
+ onClick: () => this.closePermissionsDialog(Av.Audio)
+ }]
+ },
+ shared: {
+ title: l.no_mic_title,
+ info: l.shared_mic_err_info.replace('[A]', ``).replace('[/A]', ''),
+ buttons: [{
+ key: 'ok',
+ label: l.ok_button,
+ className: 'positive',
+ onClick: () => this.closePermissionsDialog(Av.Audio)
+ }]
+ }
+ },
+ [Av.Camera]: {
+ system: {
+ title: l.no_camera_title,
+ info: this.platform === 'Windows' ? l.no_camera_system_windows.replace('[A]', ``).replace('[/A]', '') : l.no_camera_system_mac.replace('[A]', ``).replace('[/A]', ''),
+ buttons: [this.platform === 'Apple' || this.platform === 'Windows' ? {
+ key: 'open-settings',
+ label: l.open_system_settings,
+ className: 'positive',
+ onClick: () => {
+ window.open(this.platform === 'Apple' ? `${this.macURI}?Privacy_Camera` : `${this.winURI}:privacy-webcam`, '_blank', 'noopener,noreferrer');
+ this.closePermissionsDialog(Av.Camera);
+ }
+ } : {
+ key: 'ok',
+ label: l.ok_button,
+ className: 'positive',
+ onClick: () => this.closePermissionsDialog(Av.Camera)
+ }]
+ },
+ browser: {
+ title: l.no_camera_title,
+ cover: 'permissions-camera',
+ info: l.allow_camera_access.replace('[X]', ''),
+ buttons: [{
+ key: 'ok',
+ label: l.ok_button,
+ className: 'positive',
+ onClick: () => this.closePermissionsDialog(Av.Camera)
+ }]
+ },
+ nil: {
+ title: l.no_camera_detected_title,
+ info: l.no_camera_detected_info,
+ buttons: [{
+ key: 'ok',
+ label: l.ok_button,
+ className: 'positive',
+ onClick: () => this.closePermissionsDialog(Av.Camera)
+ }]
+ },
+ shared: {
+ title: l.no_camera_title,
+ info: l.shared_cam_err_info.replace('[A]', ``).replace('[/A]', ''),
+ buttons: [{
+ key: 'ok',
+ label: l.ok_button,
+ className: 'positive',
+ onClick: () => this.closePermissionsDialog(Av.Camera)
+ }]
+ }
+ },
+ [Av.Screen]: {
+ title: l.no_screen_title,
+ info: l.no_screen_system.replace('[A]', ``).replace('[/A]', ''),
+ buttons: [{
+ key: 'open-settings',
+ label: l.open_system_settings,
+ className: 'positive',
+ onClick: () => {
+ window.open(`${this.macURI}?Privacy_ScreenCapture`, '_blank', 'noopener,noreferrer');
+ this.closePermissionsDialog(Av.Screen);
+ }
+ }]
+ }
+ };
+ this.state = {
+ errMic: '',
+ errCamera: '',
+ errScreen: '',
+ [`dialog-${Av.Audio}`]: null,
+ [`dialog-${Av.Camera}`]: null,
+ [`dialog-${Av.Screen}`]: null
+ };
+ this.getPermissionsDialogContent = () => {
+ const {
+ CONTENT,
+ state
+ } = this;
+ const {
+ errMic,
+ errCamera
+ } = state;
+ const {
+ browser,
+ system,
+ nil,
+ sharedCam,
+ sharedMic,
+ sharedGeneric
+ } = errors;
+ return {
+ [Av.Audio]: {
+ ...errMic === browser && CONTENT[Av.Audio].browser,
+ ...errMic === system && CONTENT[Av.Audio].system,
+ ...errMic === nil && CONTENT[Av.Audio].nil,
+ ...errMic === sharedMic && CONTENT[Av.Audio].shared,
+ ...errMic === sharedGeneric && CONTENT[Av.Audio].shared
+ },
+ [Av.Camera]: {
+ ...errCamera === browser && CONTENT[Av.Camera].browser,
+ ...errCamera === system && CONTENT[Av.Camera].system,
+ ...errCamera === nil && CONTENT[Av.Camera].nil,
+ ...errCamera === sharedCam && CONTENT[Av.Camera].shared,
+ ...errCamera === sharedGeneric && CONTENT[Av.Camera].shared
+ },
+ [Av.Screen]: CONTENT[Av.Screen]
+ };
+ };
+ this.resetError = av => {
+ this.setState({
+ errMic: av === Av.Audio ? '' : this.state.errMic,
+ errCamera: av === Av.Camera ? '' : this.state.errCamera,
+ errScreen: av === Av.Screen ? '' : this.state.errScreen
+ });
+ };
+ this.hasToRenderPermissionsWarning = this.hasToRenderPermissionsWarning.bind(this);
+ this.renderPermissionsWarning = this.renderPermissionsWarning.bind(this);
+ }
+ hasToRenderPermissionsWarning(av) {
+ const CONFIG = {
+ [Av.Audio]: {
+ showOnUserActionError: true,
+ err: this.state.errMic
+ },
+ [Av.Camera]: {
+ showOnUserActionError: true,
+ err: this.state.errCamera
+ },
+ [Av.Screen]: {
+ showOnUserActionError: false,
+ err: this.state.errScreen
+ }
+ };
+ const current = CONFIG[av];
+ if (current) {
+ return isUserActionError(current.err) ? current.showOnUserActionError : current.err;
+ }
+ return false;
+ }
+ closePermissionsDialog(av) {
+ this.setState({
+ [`dialog-${av}`]: false
+ }, () => {
+ let _this$childRef;
+ return (_this$childRef = this.childRef) == null ? void 0 : _this$childRef.safeForceUpdate();
+ });
+ }
+ renderPermissionsDialog(av, child) {
+ const content = this.getPermissionsDialogContent();
+ const {
+ title,
+ info,
+ buttons,
+ cover
+ } = content[av] || {};
+ return JSX_(_ui_modalDialogs_jsx3__ .A.ModalDialog, {
+ dialogName: `${this.namespace}-permissions-${av}`,
+ className: `
+ meetings-permissions-dialog
+ dialog-template-message
+ with-close-btn
+ warning
+ `,
+ buttons,
+ hideOverlay: Component.NAMESPACE === 'preview-meeting' && !document.body.classList.contains('not-logged'),
+ onClose: () => {
+ this.setState({
+ [`dialog-${av}`]: false
+ }, () => child && child.safeForceUpdate());
+ }
+ }, JSX_("header", null, cover ? null : JSX_("div", {
+ className: "graphic"
+ }, JSX_("i", {
+ className: "warning sprite-fm-uni icon-warning"
+ })), JSX_("div", {
+ className: "info-container"
+ }, JSX_("h3", {
+ id: "msgDialog-title"
+ }, title || l[47]), cover && JSX_("div", {
+ className: "permissions-warning-cover"
+ }, JSX_("span", {
+ className: cover
+ })), JSX_(_ui_utils_jsx4__ .P9, {
+ tag: "p",
+ className: "permissions-warning-info",
+ content: info
+ }))));
+ }
+ renderPermissionsWarning(av, child) {
+ const {
+ errMic,
+ errCamera
+ } = this.state;
+ const dismissed = errMic === errors.dismissed || errCamera === errors.dismissed;
+ return JSX_("div", {
+ className: `
+ ${this.namespace}
+ meetings-signal-issue
+ simpletip
+ ${dismissed ? 'with-small-area' : ''}
+ `,
+ "data-simpletip": l.show_info,
+ "data-simpletipposition": "top",
+ "data-simpletipoffset": "5",
+ "data-simpletip-class": "theme-dark-forced",
+ onClick: () => dismissed ? null : this.setState({
+ [`dialog-${av}`]: true
+ }, () => {
+ if (child) {
+ this.childRef = child;
+ }
+ })
+ }, JSX_("span", {
+ className: "signal-issue-background"
+ }), JSX_("i", {
+ className: "sprite-fm-mono icon-exclamation-filled"
+ }), this.state[`dialog-${av}`] && this.renderPermissionsDialog(av, child));
+ }
+ componentWillUnmount() {
+ super.componentWillUnmount();
+ megaChat.unbind(this.observer);
+ }
+ componentDidMount() {
+ super.componentDidMount();
+ megaChat.rebind(this.observer, (ev, errAv) => {
+ this.setState({
+ errMic: errAv && errAv.mic ? String(errAv.mic) : this.state.errMic,
+ errCamera: errAv && errAv.camera ? String(errAv.camera) : this.state.errCamera,
+ errScreen: errAv && errAv.screen ? String(errAv.screen) : this.state.errScreen
+ });
+ });
+ megaChat.rebind(`onLocalMediaQueryError.${this.namespace}`, (ev, {
+ type,
+ err
+ }) => {
+ if (type === 'screen' && String(err) === errors.system) {
+ this.setState({
+ [`dialog-${Av.Screen}`]: true
+ }, () => this.safeForceUpdate());
+ }
+ });
+ }
+ render() {
+ return JSX_(Component, (0,_babel_runtime_helpers_extends0__ .A)({}, this.props, this.state, {
+ errMic: this.state.errMic,
+ errCamera: this.state.errCamera,
+ errScreen: this.state.errScreen,
+ hasToRenderPermissionsWarning: this.hasToRenderPermissionsWarning,
+ resetError: this.resetError,
+ renderPermissionsWarning: this.renderPermissionsWarning
+ }));
+ }
+ };
+};
+
+ },
+
+ 3056
+(_, EXP_, REQ_) {
+
+REQ_.r(EXP_);
+ REQ_.d(EXP_, {
+ "default": () => Admit
+ });
+ const react0__ = REQ_(1594);
+ const react0___default = REQ_.n(react0__);
+ const _mixins_js1__ = REQ_(8264);
+ const _ui_utils_jsx2__ = REQ_(6411);
+ const _contacts_jsx3__ = REQ_(8022);
+ const _button_jsx4__ = REQ_(6740);
+ const _ui_perfectScrollbar_jsx5__ = REQ_(1301);
+ const _link6__ = REQ_(4649);
+
+
+
+
+
+
+
+const NAMESPACE = 'admit';
+class Admit extends _mixins_js1__ .w9 {
+ constructor(...args) {
+ super(...args);
+ this.domRef = react0___default().createRef();
+ this.peersWaitingRef = react0___default().createRef();
+ this.state = {
+ expanded: false
+ };
+ this.doAdmit = peers => {
+ let _this$props$call;
+ return (_this$props$call = this.props.call) == null || (_this$props$call = _this$props$call.sfuClient) == null ? void 0 : _this$props$call.wrAllowJoin([peers]);
+ };
+ this.doDeny = peers => {
+ let _this$props$call2;
+ return (_this$props$call2 = this.props.call) == null || (_this$props$call2 = _this$props$call2.sfuClient) == null ? void 0 : _this$props$call2.wrKickOut([peers]);
+ };
+ this.Icon = ({
+ icon,
+ label,
+ onClick
+ }) => JSX_("i", {
+ className: `
+ sprite-fm-mono
+ simpletip
+ ${icon}
+ `,
+ "data-simpletip": label,
+ "data-simpletipposition": "top",
+ "data-simpletipoffset": "5",
+ "data-simpletip-class": "theme-dark-forced",
+ onClick
+ });
+ this.CallLimitBanner = ({
+ call
+ }) => JSX_("div", {
+ className: `${NAMESPACE}-user-limit-banner`
+ }, call.organiser === u_handle ? (0,_ui_utils_jsx2__ .lI)(l.admit_limit_banner_organiser, '[A]', _link6__ .A, {
+ onClick() {
+ window.open(`${getBaseUrl()}/pro`, '_blank', 'noopener,noreferrer');
+ eventlog(500259);
+ }
+ }) : l.admit_limit_banner_host);
+ this.renderPeersList = () => {
+ const {
+ peers,
+ call,
+ chatRoom
+ } = this.props;
+ const disableAdding = call.sfuClient.callLimits && call.sfuClient.callLimits.usr && chatRoom.getCallParticipants().length >= call.sfuClient.callLimits.usr;
+ return JSX_(_ui_perfectScrollbar_jsx5__ .O, {
+ ref: this.peersWaitingRef,
+ options: {
+ 'suppressScrollX': true
+ }
+ }, JSX_("div", {
+ className: "peers-waiting"
+ }, this.isUserLimited && JSX_(this.CallLimitBanner, {
+ call
+ }), peers.map(handle => {
+ return JSX_("div", {
+ key: handle,
+ className: "peers-waiting-card"
+ }, JSX_("div", {
+ className: "peer-avatar"
+ }, JSX_(_contacts_jsx3__ .eu, {
+ contact: M.u[handle]
+ })), JSX_("div", {
+ className: "peer-name"
+ }, JSX_(_contacts_jsx3__ .uA, {
+ contact: M.u[handle],
+ emoji: true
+ })), JSX_("div", {
+ className: "peer-controls"
+ }, JSX_(this.Icon, {
+ icon: "icon-close-component",
+ label: l.wr_deny,
+ onClick: () => this.doDeny(handle)
+ }), JSX_(this.Icon, {
+ icon: `icon-check ${disableAdding ? 'disabled' : ''}`,
+ label: l.wr_admit,
+ onClick: () => !disableAdding && this.doAdmit(handle)
+ })));
+ })));
+ };
+ this.renderMultiplePeersWaiting = () => {
+ const {
+ call,
+ peers,
+ expanded,
+ onWrListToggle
+ } = this.props;
+ if (peers && peers.length) {
+ const disableAddAll = this.isUserLimited;
+ return JSX_(react0___default().Fragment, null, JSX_("div", {
+ className: `${NAMESPACE}-head`
+ }, JSX_("h3", null, mega.icu.format(l.wr_peers_waiting, peers.length)), expanded ? JSX_(this.Icon, {
+ icon: "icon-arrow-up",
+ onClick: () => onWrListToggle(false)
+ }) : null), !expanded && disableAddAll && JSX_(this.CallLimitBanner, {
+ call
+ }), expanded && JSX_("div", {
+ className: `${NAMESPACE}-content`
+ }, this.renderPeersList()), JSX_("div", {
+ className: `${NAMESPACE}-controls`
+ }, expanded ? null : JSX_(_button_jsx4__ .A, {
+ className: "mega-button theme-dark-forced",
+ onClick: () => onWrListToggle(true)
+ }, JSX_("span", null, l.wr_see_waiting)), JSX_(_button_jsx4__ .A, {
+ peers,
+ className: `mega-button positive theme-dark-forced ${disableAddAll ? 'disabled' : ''}`,
+ onClick: () => !disableAddAll && call.sfuClient.wrAllowJoin(peers)
+ }, JSX_("span", null, l.wr_admit_all))));
+ }
+ return null;
+ };
+ this.renderSinglePeerWaiting = () => {
+ const {
+ peers,
+ call
+ } = this.props;
+ const peer = peers[0];
+ const disableAdding = this.isUserLimited;
+ if (peer) {
+ return JSX_(react0___default().Fragment, null, JSX_(_ui_utils_jsx2__ .P9, {
+ tag: "h3",
+ content: l.wr_peer_waiting.replace('%s', megaChat.html(M.getNameByHandle(peer)))
+ }), disableAdding && JSX_(this.CallLimitBanner, {
+ call
+ }), JSX_("div", {
+ className: `${NAMESPACE}-controls`
+ }, JSX_(_button_jsx4__ .A, {
+ className: "mega-button theme-dark-forced",
+ onClick: () => this.doDeny(peer)
+ }, JSX_("span", null, l.wr_deny)), JSX_(_button_jsx4__ .A, {
+ className: `mega-button positive theme-dark-forced ${disableAdding ? 'disabled' : ''}`,
+ onClick: () => !disableAdding && this.doAdmit(peer)
+ }, JSX_("span", null, l.wr_admit))));
+ }
+ return null;
+ };
+ }
+ get isUserLimited() {
+ const {
+ call,
+ chatRoom,
+ peers
+ } = this.props;
+ return call.sfuClient.callLimits && call.sfuClient.callLimits.usr && chatRoom.getCallParticipants().length + (peers ? peers.length : 0) > call.sfuClient.callLimits.usr;
+ }
+ render() {
+ const {
+ chatRoom,
+ peers
+ } = this.props;
+ if (chatRoom.iAmOperator()) {
+ return JSX_("div", {
+ ref: this.domRef,
+ className: `
+ ${NAMESPACE}
+ theme-dark-forced
+ `
+ }, JSX_("div", {
+ className: `${NAMESPACE}-wrapper`
+ }, peers && peers.length > 1 ? this.renderMultiplePeersWaiting() : this.renderSinglePeerWaiting()));
+ }
+ return null;
+ }
+}
+
+ },
+
+ 2659
+(_, EXP_, REQ_) {
+
+REQ_.r(EXP_);
+ REQ_.d(EXP_, {
+ VIEW: () => VIEW,
+ "default": () => WaitingRoom
+ });
+ const react0__ = REQ_(1594);
+ const react0___default = REQ_.n(react0__);
+ const _mixins_js1__ = REQ_(8264);
+ const _ui_utils_jsx2__ = REQ_(6411);
+ const _workflow_preview_jsx3__ = REQ_(3546);
+ const _button_jsx4__ = REQ_(6740);
+ const _link_jsx5__ = REQ_(4649);
+
+
+
+
+
+
+const NAMESPACE = 'waiting-room';
+const VIEW = {
+ INTRO: 0,
+ ACCOUNT: 1,
+ GUEST: 2,
+ AWAIT: 3,
+ UNSUPPORTED: 4,
+ REDIRECT: 5
+};
+class WaitingRoom extends _mixins_js1__ .w9 {
+ constructor(props) {
+ super(props);
+ this.domRef = react0___default().createRef();
+ this.redirectInterval = undefined;
+ this.state = {
+ view: VIEW.ACCOUNT,
+ call: false,
+ audio: false,
+ video: false,
+ firstName: '',
+ lastName: '',
+ countdown: 4,
+ loading: false
+ };
+ this.renderLeaveDialog = () => msgDialog(`confirmation:!^${l.wr_leave}!${l.wr_do_not_leave}`, null, l.wr_leave_confirmation, '', cb => {
+ if (cb) {
+ delay('chat-event-wr-leave', () => eventlog(99938));
+ this.doLeave();
+ }
+ }, 1);
+ this.renderDeniedDialog = () => msgDialog('error', '', l.wr_denied, l.wr_denied_details, this.doLeave);
+ this.renderTimeoutDialog = () => msgDialog('error', '', l.wr_timeout, l.wr_timeout_details, this.doLeave);
+ this.renderWaitingRoomInfo = () => {
+ const {
+ chatRoom
+ } = this.props;
+ const {
+ nextOccurrenceStart,
+ nextOccurrenceEnd
+ } = chatRoom.scheduledMeeting || {};
+ return JSX_(react0___default().Fragment, null, JSX_(_ui_utils_jsx2__ .P9, {
+ tag: "h2",
+ content: megaChat.html(chatRoom.topic)
+ }), JSX_("div", {
+ className: `${NAMESPACE}-schedule`
+ }, JSX_("span", null, time2date(nextOccurrenceStart / 1000, 20)), JSX_("span", null, toLocaleTime(nextOccurrenceStart), " - ", toLocaleTime(nextOccurrenceEnd))));
+ };
+ this.doLeave = () => this.setState({
+ view: VIEW.REDIRECT
+ }, () => {
+ tSleep(this.state.countdown).then(() => this.props.onWaitingRoomLeave());
+ this.redirectInterval = setInterval(() => this.setState(({
+ countdown
+ }) => ({
+ countdown: countdown > 0 ? countdown - 1 : 0
+ })), 1e3);
+ sessionStorage.removeItem('previewMedia');
+ });
+ this.setInitialView = () => {
+ if (u_type || is_eplusplus) {
+ let _this$props$chatRoom;
+ return (_this$props$chatRoom = this.props.chatRoom) != null && _this$props$chatRoom.iAmInRoom() ? VIEW.AWAIT : VIEW.ACCOUNT;
+ }
+ return VIEW.INTRO;
+ };
+ this.requestJoin = () => {
+ let _this$props$chatRoom2;
+ const {
+ audio,
+ video
+ } = this.state;
+ (_this$props$chatRoom2 = this.props.chatRoom) == null || _this$props$chatRoom2.joinCall(audio, video);
+ };
+ this.Field = ({
+ name,
+ children
+ }) => {
+ let _this$state$name;
+ return JSX_("div", {
+ className: `
+ mega-input
+ title-ontop
+ ${(_this$state$name = this.state[name]) != null && _this$state$name.length ? 'valued' : ''}
+ `
+ }, JSX_("div", {
+ className: "mega-input-title"
+ }, children, JSX_("span", {
+ className: "required-red"
+ }, "*")), JSX_("input", {
+ type: "text",
+ name,
+ className: "titleTop required megaInputs",
+ placeholder: children,
+ value: this.state[name] || '',
+ maxLength: 40,
+ onChange: ev => this.setState({
+ [name]: ev.target.value
+ })
+ }));
+ };
+ this.Card = ({
+ className,
+ children
+ }) => {
+ const {
+ audio,
+ video
+ } = this.state;
+ return JSX_("div", {
+ className: `
+ card
+ ${className || ''}
+ `
+ }, JSX_("div", {
+ className: "card-body"
+ }, children), JSX_("div", {
+ className: "card-preview"
+ }, JSX_(_workflow_preview_jsx3__ .A, {
+ audio,
+ video,
+ onToggle: (audio, video) => {
+ this.setState({
+ audio,
+ video
+ }, () => {
+ sessionStorage.previewMedia = JSON.stringify({
+ audio,
+ video
+ });
+ });
+ }
+ })));
+ };
+ this.Head = ({
+ title
+ }) => {
+ let _this$props$chatRoom3;
+ return JSX_("div", {
+ className: `${NAMESPACE}-head`
+ }, JSX_("div", {
+ className: `${NAMESPACE}-logo`
+ }, JSX_("i", {
+ className: `
+ sprite-fm-illustration-wide
+ ${mega.ui.isDarkTheme() ? 'mega-logo-dark' : 'img-mega-logo-light'}
+ `
+ })), JSX_("h1", {
+ className: (megaChat.initialChatId || is_chatlink) && this.state.view !== VIEW.INTRO ? 'hidden' : ''
+ }, JSX_(_ui_utils_jsx2__ .zT, null, title || l.you_have_invitation.replace('%1', (_this$props$chatRoom3 = this.props.chatRoom) == null ? void 0 : _this$props$chatRoom3.topic))));
+ };
+ this.Await = () => {
+ return JSX_(react0___default().Fragment, null, megaChat.initialChatId ? JSX_(this.Head, null) : null, JSX_(this.Card, {
+ className: megaChat.initialChatId ? '' : 'fit-spacing'
+ }, this.renderWaitingRoomInfo(), JSX_("div", {
+ className: `${NAMESPACE}-message`
+ }, this.state.call ? l.wr_wait_to_admit : l.wr_wait_to_start), JSX_(_button_jsx4__ .A, {
+ icon: "sprite-fm-mono icon-log-out-thin-solid",
+ className: `${NAMESPACE}-leave`,
+ onClick: () => this.renderLeaveDialog()
+ }, l.wr_leave)));
+ };
+ this.Account = () => {
+ const {
+ loading,
+ audio,
+ video
+ } = this.state;
+ return JSX_(react0___default().Fragment, null, JSX_(this.Head, null), JSX_(this.Card, null, this.renderWaitingRoomInfo(), JSX_(_button_jsx4__ .A, {
+ className: `
+ mega-button
+ positive
+ large
+ ${loading ? 'disabled' : ''}
+ `,
+ onClick: () => {
+ return loading ? null : this.setState({
+ loading: true
+ }, () => {
+ const {
+ chatRoom
+ } = this.props;
+ const {
+ chatId,
+ publicChatHandle,
+ publicChatKey
+ } = chatRoom;
+ if (chatRoom.iAmInRoom()) {
+ return megaChat.routing.reinitAndOpenExistingChat(chatId, publicChatHandle).then(() => {
+ megaChat.getChatById(chatId).joinCall(audio, video);
+ }).catch(ex => console.error(`Failed to open existing room and join call: ${ex}`));
+ }
+ megaChat.routing.reinitAndJoinPublicChat(chatId, publicChatHandle, publicChatKey).then(() => {
+ delete megaChat.initialPubChatHandle;
+ }).catch(ex => console.error(`Failed to join room: ${ex}`));
+ });
+ }
+ }, l.wr_ask_to_join), JSX_("div", null, JSX_(_link_jsx5__ .A, {
+ to: "https://mega.io/chatandmeetings",
+ target: "_blank"
+ }, l.how_meetings_work))));
+ };
+ this.Redirect = () => JSX_(react0___default().Fragment, null, JSX_(this.Head, {
+ title: l.wr_left_heading
+ }), JSX_("h5", null, l.wr_left_countdown.replace('%1', this.state.countdown)));
+ this.Guest = () => {
+ const {
+ chatRoom
+ } = this.props;
+ const {
+ loading,
+ firstName,
+ lastName
+ } = this.state;
+ const isDisabled = !firstName.length || !lastName.length;
+ return JSX_(react0___default().Fragment, null, JSX_(this.Head, null), JSX_(this.Card, null, this.renderWaitingRoomInfo(), JSX_("div", {
+ className: "card-fields"
+ }, JSX_(this.Field, {
+ name: "firstName"
+ }, l[1096]), JSX_(this.Field, {
+ name: "lastName"
+ }, l[1097])), JSX_(_button_jsx4__ .A, {
+ className: `
+ mega-button
+ positive
+ large
+ ${isDisabled || loading ? 'disabled' : ''}
+ `,
+ onClick: () => {
+ if (isDisabled || loading) {
+ return false;
+ }
+ return this.setState({
+ loading: true
+ }, () => {
+ u_eplusplus(this.state.firstName, this.state.lastName).then(() => {
+ return megaChat.routing.reinitAndJoinPublicChat(chatRoom.chatId, chatRoom.publicChatHandle, chatRoom.publicChatKey);
+ }).catch(ex => d && console.error(`E++ account failure: ${ex}`));
+ });
+ }
+ }, l.wr_ask_to_join), JSX_("div", null, JSX_(_link_jsx5__ .A, {
+ to: "https://mega.io/chatandmeetings",
+ target: "_blank"
+ }, l.how_meetings_work))));
+ };
+ this.Intro = () => {
+ const {
+ chatRoom
+ } = this.props;
+ return JSX_(react0___default().Fragment, null, JSX_(this.Head, null), JSX_("div", {
+ className: "join-meeting-content"
+ }, JSX_(_button_jsx4__ .A, {
+ className: "mega-button positive",
+ onClick: () => {
+ megaChat.loginOrRegisterBeforeJoining(chatRoom.publicChatHandle, false, true, undefined, () => this.setState({
+ view: VIEW.ACCOUNT
+ }));
+ }
+ }, l[171]), JSX_(_button_jsx4__ .A, {
+ className: "mega-button",
+ onClick: () => this.setState({
+ view: VIEW.GUEST
+ })
+ }, l.join_as_guest), JSX_("p", null, JSX_(_ui_utils_jsx2__ .P9, {
+ onClick: e => {
+ e.preventDefault();
+ megaChat.loginOrRegisterBeforeJoining(chatRoom.publicChatHandle, true, undefined, undefined, () => this.setState({
+ view: VIEW.ACCOUNT
+ }));
+ }
+ }, l[20635]))));
+ };
+ this.Unsupported = () => {
+ let _this$props$chatRoom4;
+ return JSX_(react0___default().Fragment, null, JSX_(this.Head, null), JSX_("h1", null, l.you_have_invitation.replace('%1', (_this$props$chatRoom4 = this.props.chatRoom) == null ? void 0 : _this$props$chatRoom4.topic)), JSX_("div", {
+ className: "meetings-unsupported-container"
+ }, JSX_("i", {
+ className: "sprite-fm-uni icon-error"
+ }), JSX_("div", {
+ className: "unsupported-info"
+ }, JSX_("h3", null, l.heading_unsupported_browser), JSX_("h3", null, l.join_meeting_methods), JSX_("ul", null, JSX_("li", null, l.join_via_link), JSX_("li", null, JSX_(_ui_utils_jsx2__ .P9, null, l.join_via_mobile.replace('[A]', '').replace('[/A]', '')))))));
+ };
+ this.renderView = view => {
+ switch (view) {
+ default:
+ return this.Await();
+ case VIEW.INTRO:
+ return this.Intro();
+ case VIEW.GUEST:
+ return this.Guest();
+ case VIEW.ACCOUNT:
+ return this.Account();
+ case VIEW.REDIRECT:
+ return this.Redirect();
+ case VIEW.UNSUPPORTED:
+ return this.Unsupported();
+ }
+ };
+ this.state.call = this.props.havePendingCall;
+ this.state.view = megaChat.hasSupportForCalls ? this.setInitialView() : VIEW.UNSUPPORTED;
+ if (sessionStorage.previewMedia) {
+ const {
+ audio,
+ video
+ } = JSON.parse(sessionStorage.previewMedia);
+ this.state.audio = audio;
+ this.state.video = video;
+ sessionStorage.removeItem('previewMedia');
+ }
+ }
+ UNSAFE_componentWillReceiveProps(nextProps) {
+ if (this.props.havePendingCall !== nextProps.havePendingCall) {
+ this.setState({
+ call: nextProps.havePendingCall
+ }, () => this.state.view === VIEW.AWAIT && nextProps.havePendingCall && this.requestJoin());
+ }
+ }
+ componentWillUnmount() {
+ super.componentWillUnmount();
+ clearInterval(this.redirectInterval);
+ this.props.chatRoom.unbind(`onCallLeft.${NAMESPACE}`);
+ this.props.chatRoom.unbind(`onModeratorAdd.${NAMESPACE}`);
+ }
+ componentDidMount() {
+ super.componentDidMount();
+ const {
+ chatRoom
+ } = this.props;
+ const {
+ call,
+ view
+ } = this.state;
+ if (call && view === VIEW.AWAIT) {
+ this.requestJoin();
+ }
+ chatRoom.rebind(`onCallLeft.${NAMESPACE}`, (ev, {
+ termCode
+ }) => {
+ if (termCode === SfuClient.TermCode.kKickedFromWaitingRoom) {
+ return this.renderDeniedDialog();
+ }
+ if (termCode === SfuClient.TermCode.kWaitingRoomAllowTimeout) {
+ delay('chat-event-wr-timeout', () => eventlog(99939));
+ return this.renderTimeoutDialog();
+ }
+ });
+ chatRoom.rebind(`onModeratorAdd.${NAMESPACE}`, (ev, user) => {
+ if (user === u_handle) {
+ chatRoom.meetingsLoading = false;
+ this.requestJoin();
+ }
+ });
+ }
+ render() {
+ const {
+ view
+ } = this.state;
+ return JSX_(_ui_utils_jsx2__ .Ay.RenderTo, {
+ element: document.body
+ }, JSX_("div", {
+ ref: this.domRef,
+ className: `
+ ${NAMESPACE}
+ join-meeting
+ ${view === VIEW.AWAIT ? `${NAMESPACE}--await` : ''}
+ ${view === VIEW.AWAIT && !megaChat.initialChatId ? 'theme-dark-forced' : ''}
+ ${view === VIEW.REDIRECT ? `${NAMESPACE}--redirect` : ''}
+ ${megaChat.initialChatId || is_chatlink ? `${NAMESPACE}--chatlink-landing` : ''}
+ `
+ }, this.renderView(view)));
+ }
+}
+
+ },
+
+ 3546
+(_, EXP_, REQ_) {
+
+ REQ_.d(EXP_, {
+ A: () => __WEBPACK_DEFAULT_EXPORT__
+ });
+ const react0__ = REQ_(1594);
+ const react0___default = REQ_.n(react0__);
+ const _mixins_js1__ = REQ_(8264);
+ const _contacts_jsx2__ = REQ_(8022);
+ const _utils_jsx3__ = REQ_(3901);
+ const _button_jsx4__ = REQ_(6740);
+ const _permissionsObserver_jsx5__ = REQ_(192);
+
+
+
+
+
+
+class Preview extends react0___default().Component {
+ constructor(props) {
+ super(props);
+ this.domRef = react0___default().createRef();
+ this.videoRef = react0___default().createRef();
+ this.stream = null;
+ this.state = {
+ audio: false,
+ video: false,
+ avatarMeta: undefined
+ };
+ this.getTrackType = type => !type ? 'getTracks' : type === Preview.STREAMS.AUDIO ? 'getAudioTracks' : 'getVideoTracks';
+ this.startStream = type => {
+ this.stopStream();
+ const {
+ audio,
+ video
+ } = this.state;
+ navigator.mediaDevices.getUserMedia({
+ audio,
+ video
+ }).then(stream => {
+ const videoRef = this.videoRef.current;
+ if (videoRef) {
+ videoRef.srcObject = stream;
+ this.stream = stream;
+ if (this.props.onToggle) {
+ this.props.onToggle(this.state.audio, this.state.video);
+ }
+ }
+ }).catch(ex => {
+ const stream = type === Preview.STREAMS.AUDIO ? 'audio' : 'video';
+ return this.domRef.current && this.setState(state => ({
+ [stream]: !state[stream]
+ }), () => {
+ megaChat.trigger('onLocalMediaError', {
+ [type === Preview.STREAMS.AUDIO ? 'mic' : 'camera']: `${ex.name}: ${ex.message}`
+ });
+ console.error(`${ex.name}: ${ex.message}`);
+ });
+ });
+ };
+ this.stopStream = type => {
+ if (this.stream) {
+ const trackType = this.getTrackType(type);
+ const tracks = this.stream[trackType]();
+ for (const track of tracks) {
+ track.stop();
+ }
+ }
+ };
+ this.toggleStream = type => {
+ let _this$props$resetErro, _this$props;
+ const stream = type === Preview.STREAMS.AUDIO ? 'audio' : 'video';
+ this.setState(state => ({
+ [stream]: !state[stream]
+ }), () => {
+ if (this.props.onToggle) {
+ this.props.onToggle(this.state.audio, this.state.video);
+ }
+ return this.state[stream] ? this.startStream(type) : this.stopStream(type);
+ });
+ (_this$props$resetErro = (_this$props = this.props).resetError) == null || _this$props$resetErro.call(_this$props, type === Preview.STREAMS.AUDIO ? Av.Audio : Av.Camera);
+ };
+ this.renderAvatar = () => {
+ if ((0,_utils_jsx3__ .P)()) {
+ return JSX_("div", {
+ className: "avatar-guest"
+ }, JSX_("i", {
+ className: "sprite-fm-uni icon-owner"
+ }));
+ }
+ if (is_chatlink) {
+ const {
+ avatarUrl,
+ color,
+ shortName
+ } = this.state.avatarMeta || {};
+ return JSX_("div", {
+ className: `
+ avatar-wrapper
+ ${color ? `color${color}` : ''}
+ `
+ }, avatarUrl && JSX_("img", {
+ src: avatarUrl,
+ alt: ""
+ }), color && JSX_("span", null, shortName));
+ }
+ return JSX_(_contacts_jsx2__ .eu, {
+ contact: M.u[u_handle]
+ });
+ };
+ this.state.audio = this.props.audio || this.state.audio;
+ if (this.props.video) {
+ this.state.video = this.props.video;
+ this.startStream(Preview.STREAMS.VIDEO);
+ this.props.onToggle(this.state.audio, this.state.video);
+ }
+ }
+ componentWillUnmount() {
+ this.stopStream();
+ }
+ componentDidMount() {
+ if (this.props.onToggle) {
+ this.props.onToggle(this.state.audio, this.state.video);
+ }
+ this.setState({
+ avatarMeta: is_chatlink ? generateAvatarMeta(u_handle) : undefined
+ });
+ }
+ render() {
+ const {
+ NAMESPACE
+ } = Preview;
+ const {
+ hasToRenderPermissionsWarning,
+ renderPermissionsWarning
+ } = this.props;
+ const {
+ audio,
+ video
+ } = this.state;
+ const SIMPLETIP_PROPS = {
+ label: undefined,
+ position: 'top',
+ className: 'theme-dark-forced'
+ };
+ return JSX_("div", {
+ ref: this.domRef,
+ className: `
+ ${NAMESPACE}
+ local-stream-mirrored
+ `
+ }, video && JSX_("div", {
+ className: `${NAMESPACE}-video-overlay`
+ }), JSX_("video", {
+ className: video ? 'streaming' : '',
+ muted: true,
+ autoPlay: true,
+ ref: this.videoRef
+ }), !video && this.renderAvatar(), JSX_("div", {
+ className: `${NAMESPACE}-controls`
+ }, JSX_("div", {
+ className: "preview-control-wrapper"
+ }, JSX_(_button_jsx4__ .A, {
+ simpletip: {
+ ...SIMPLETIP_PROPS,
+ label: audio ? l[16214] : l[16708]
+ },
+ className: `
+ mega-button
+ round
+ theme-light-forced
+ ${NAMESPACE}-control
+ ${audio ? '' : 'with-fill'}
+ `,
+ icon: audio ? 'icon-mic-thin-outline' : 'icon-mic-off-thin-outline',
+ onClick: () => {
+ this.toggleStream(Preview.STREAMS.AUDIO);
+ }
+ }), JSX_("span", null, l.mic_button), hasToRenderPermissionsWarning(Av.Audio) ? renderPermissionsWarning(Av.Audio) : null), JSX_("div", {
+ className: "preview-control-wrapper"
+ }, JSX_(_button_jsx4__ .A, {
+ simpletip: {
+ ...SIMPLETIP_PROPS,
+ label: video ? l[22894] : l[22893]
+ },
+ className: `
+ mega-button
+ round
+ theme-light-forced
+ ${NAMESPACE}-control
+ ${video ? '' : 'with-fill'}
+ `,
+ icon: video ? 'icon-video-thin-outline' : 'icon-video-off-thin-outline',
+ onClick: () => this.toggleStream(Preview.STREAMS.VIDEO)
+ }), JSX_("span", null, l.camera_button), hasToRenderPermissionsWarning(Av.Camera) ? renderPermissionsWarning(Av.Camera) : null)));
+ }
+}
+Preview.NAMESPACE = 'preview-meeting';
+Preview.STREAMS = {
+ AUDIO: 1,
+ VIDEO: 2
+};
+ const __WEBPACK_DEFAULT_EXPORT__ = (0,_mixins_js1__ .Zz)(_permissionsObserver_jsx5__ .$)(Preview);
+
+ }
+
+}]);
\ No newline at end of file
diff --git a/js/chat/chat.jsx b/js/chat/chat.jsx
index 6a0df21a98..42adcfece4 100644
--- a/js/chat/chat.jsx
+++ b/js/chat/chat.jsx
@@ -1,19 +1,42 @@
-import React from 'react';
+import React, { lazy } from 'react';
import { createRoot } from 'react-dom';
-import ConversationsUI from './ui/conversations.jsx';
-require("./chatGlobalEventManager.jsx");
-// load chatRoom.jsx, so that its included in bundle.js, despite that ChatRoom is legacy ES ""class""
-require("./chatRoom.jsx");
+import './chatRoom.jsx';
+import ConversationsApp from './ui/conversations.jsx';
-// ensure that the Incoming dialog is included, so that it would be added to the window scope for accessing from
-// vanilla JS
-require("./ui/meetings/workflow/incoming.jsx");
-
-import ChatRouting from "./chatRouting.jsx";
+import ChatRouting from './chatRouting.jsx';
import MeetingsManager from './meetingsManager.jsx';
-import { ChatOnboarding } from "./chatOnboarding.jsx";
-import { inProgressAlert } from "./ui/meetings/call.jsx";
+import { ChatOnboarding } from './chatOnboarding.jsx';
+import { inProgressAlert } from './ui/meetings/utils.jsx';
+
+import { chatGlobalEventManager } from './chatGlobalEventManager';
+window.chatGlobalEventManager = chatGlobalEventManager;
+
+import { getMessageString } from './ui/messages/utils.jsx';
+mega.ui = mega.ui || {};
+mega.ui.chat = mega.ui.chat || {};
+mega.ui.chat.getMessageString = getMessageString;
+
+import { withSuspense } from './utils.jsx';
+import Incoming from './ui/meetings/workflow/incoming.jsx';
+
+const ScheduleMeeting =
+ lazy(() => import(/* webpackChunkName: "schedule-meeting" */ './ui/meetings/schedule/schedule.jsx'));
+const StartMeeting =
+ lazy(() => import(/* webpackChunkName: "start-conversation" */ './ui/meetings/workflow/start.jsx'));
+const ContactSelectorDialog =
+ lazy(() => import(/* webpackChunkName: "start-conversation" */ './ui/contactSelectorDialog.jsx'));
+const StartGroupChatWizard =
+ lazy(() => import(/* webpackChunkName: "start-conversation" */ './ui/startGroupChatWizard.jsx'));
+const CloudBrowserDialog =
+ lazy(() => import(/* webpackChunkName: "cloud-browser" */ '../ui/cloudBrowserModalDialog.jsx'));
+
+window.ChatCallIncomingDialog = withSuspense(Incoming);
+window.ScheduleMeetingDialogUI = { Schedule: withSuspense(ScheduleMeeting) };
+window.StartMeetingDialogUI = { Start: withSuspense(StartMeeting) };
+window.ContactSelectorDialogUI = { ContactSelectorDialog: withSuspense(ContactSelectorDialog) };
+window.StartGroupChatDialogUI = { StartGroupChatWizard: withSuspense(StartGroupChatWizard) };
+Object.defineProperty(mega, 'CloudBrowserDialog', { value: withSuspense(CloudBrowserDialog) });
const EMOJI_DATASET_VERSION = 5;
const CHAT_ONHISTDECR_RECNT = "onHistoryDecrypted.recent";
@@ -323,7 +346,7 @@ Chat.prototype.init = promisify(function(resolve, reject) {
const rootDOMNode = this.rootDOMNode = document.querySelector(selector);
const $$root = this.$$root = createRoot(rootDOMNode);
$$root.render(
- this.triggered(ev));
- $(window).rebind('resize.chatGlobalEventManager', ev => this.triggered(ev));
+/**
+ * Called internally to actually do the resize binding when needed.
+ *
+ * @private
+ * @returns {undefined}
+ * @name listeners
+ * @memberOf ChatGlobalEventManager.prototype
+ */
+lazy(ChatGlobalEventManager.prototype, 'listeners', function() {
+ window.addEventListener('hashchange', ev => this.triggered(ev));
+ $(window).rebind('resize.chatGlobalEventManager', ev => this.triggered(ev));
- var listeners = Object.create(null);
- listeners.resize = Object.create(null);
- listeners.hashchange = Object.create(null);
- return listeners;
- });
+ var listeners = Object.create(null);
+ listeners.resize = Object.create(null);
+ listeners.hashchange = Object.create(null);
+ return listeners;
+});
- /**
- * Add an `cb` event listener for `eventName` with namespace `namespace`
- *
- * @param {String} eventName eventType/Name
- * @param {String} namespace the namespace to use for this listener
- * @param {Function} cb callback to be called for this listener
- *
- * @returns {undefined}
- */
- ChatGlobalEventManager.prototype.addEventListener = function(eventName, namespace, cb) {
- this.listeners[eventName][namespace] = this.listeners[namespace] || cb;
- };
+/**
+ * Add an `cb` event listener for `eventName` with namespace `namespace`
+ *
+ * @param {String} eventName eventType/Name
+ * @param {String} namespace the namespace to use for this listener
+ * @param {Function} cb callback to be called for this listener
+ *
+ * @returns {undefined}
+ */
+ChatGlobalEventManager.prototype.addEventListener = function(eventName, namespace, cb) {
+ this.listeners[eventName][namespace] = this.listeners[namespace] || cb;
+};
- /**
- * Remove listener with namespace `namespace`
- *
- * @param {String} eventName eventType/Name
- * @param {String} namespace the namespace to use for this listener
- * @returns {undefined}
- */
- ChatGlobalEventManager.prototype.removeEventListener = function(eventName, namespace) {
- delete this.listeners[eventName][namespace];
- };
+/**
+ * Remove listener with namespace `namespace`
+ *
+ * @param {String} eventName eventType/Name
+ * @param {String} namespace the namespace to use for this listener
+ * @returns {undefined}
+ */
+ChatGlobalEventManager.prototype.removeEventListener = function(eventName, namespace) {
+ delete this.listeners[eventName][namespace];
+};
- /**
- * Called by the onResize/hashchange
- *
- * @param {String} eventName the eventType/name
- * @param {Event} e the actual Event object
- *
- * @returns {undefined}
- */
- ChatGlobalEventManager.prototype.triggered = SoonFc(140, function _chatEVDispatcher(ev) {
- if (M.chat) {
- var listeners = this.listeners[ev.type];
+/**
+ * Called by the onResize/hashchange
+ *
+ * @param {String} eventName the eventType/name
+ * @param {Event} e the actual Event object
+ *
+ * @returns {undefined}
+ */
+ChatGlobalEventManager.prototype.triggered = SoonFc(140, function _chatEVDispatcher(ev) {
+ if (M.chat) {
+ var listeners = this.listeners[ev.type];
- // eslint-disable-next-line guard-for-in
- for (var k in listeners) {
- listeners[k](ev);
- }
+ // eslint-disable-next-line guard-for-in
+ for (var k in listeners) {
+ listeners[k](ev);
}
- });
+ }
+});
- // init globally. will be initialized only when first .addEventListener is called
- window.chatGlobalEventManager = new ChatGlobalEventManager();
-})();
+// Create and export the singleton instance
+export const chatGlobalEventManager = new ChatGlobalEventManager();
diff --git a/js/chat/chatOnboarding.jsx b/js/chat/chatOnboarding.jsx
index 649668422b..a83eda408d 100644
--- a/js/chat/chatOnboarding.jsx
+++ b/js/chat/chatOnboarding.jsx
@@ -1,5 +1,4 @@
-import { SoonFcWrap } from "./mixins.js";
-import { VIEWS as CONVERSATIONS_APP_VIEWS, EVENTS as CONVERSATIONS_APP_EVENTS } from "./ui/conversations.jsx";
+import { SoonFcWrap } from './mixins.js';
class ChatOnboarding {
diff --git a/js/chat/megaChunkLoader.jsx b/js/chat/megaChunkLoader.jsx
new file mode 100644
index 0000000000..8f4c949a5d
--- /dev/null
+++ b/js/chat/megaChunkLoader.jsx
@@ -0,0 +1,75 @@
+/**
+ * `MegaChunkLoader`
+ * ---------------------------------------------------------------------------------------------------------------------
+ * Overrides the default `webpack` chunk loading mechanism (`__webpack_require__.l`) to integrate
+ * `React.lazy`/`React.Suspense` with the `secureboot` architecture of the `webclient`, which ensures lazy-loaded chunks
+ * go through MEGA's XHR + hash verification pipeline.
+ *
+ * 1) What
+ * ---------------------------------------------------------------------------------------------------------------------
+ * By default `webpack` loads chunks by injecting `script` tags with standard URLs. MEGA's security model requires all
+ * code to be i) loaded via XHR (as to create blob URL entities) and ii) verified against a pre-computed SHA-256 hash.
+ *
+ * The default `webpack` loader behavior bypasses these integrity checks, which is not optimal. Additionally, the
+ * `webpack` Hot Module Replacement (HMR) relies on injecting unverified code at runtime, which is incompatible with
+ * the `webclient` integrity model.
+ *
+ * 2) How
+ * ---------------------------------------------------------------------------------------------------------------------
+ * This loader intercepts the `import()` calls generated by `React.lazy()`:
+ *
+ * i) `webpack` calls `__webpack_require__.l(url, done)` to load a chunk; we capture this call and derive the `url`
+ * from `chunkFilename` in `webpack.config.js` (ex.: `js/chat/bundle.call.js`)
+ * ii) we parse the URL as to extract the logical chunk name (ex.: `js/chat/bundle.call.js` -> `call` -> `chat:call_js`)
+ * iii) we request the resource via `M.require('chat:call_js')` call, as `secureboot.js` maintains the respective
+ * registry (jsl2) by mapping this logical key to the physical, hashed filename in production.
+ * iv) `M.require` handles the XHR download and performs the SHA-256 hash check; if the hash does not match the
+ * build-time manifest, the load is blocked to prevent tampering.
+ * v) we call the `done()` callback on success, which allows the `React.Suspense` boundary to render the component.
+ *
+ * 3) Constraints
+ * ---------------------------------------------------------------------------------------------------------------------
+ * - the original `__webpack_require__.l` loader is intentionally not preserved as a fallback -- if a chunk fails the
+ * integrity check (no `jsl2` entry) chunk loading fails securely rather than bypassing hash verification via the
+ * default `script` tag injection.
+ * - `splitChunks` is disabled; we want deterministic, manually defined chunks (via `webpackChunkName`) to
+ * ensure 1:1 mapping with the `secureboot` registry.
+ * - `hot` (HMR) is disabled; development can rely on standard page reloads in favor of ensuring the dev environment
+ * mirrors the production security pipeline.
+ */
+
+const webpackRequire = typeof __webpack_require__ !== 'undefined' ? __webpack_require__ : null;
+
+if (webpackRequire && webpackRequire.l) {
+ const CHUNK_LOADER_DEBUG = d && localStorage.chunkLoaderDebug;
+ const logger = MegaLogger.getLogger('MegaChunkLoader', { levelColors: { 'DEBUG': 'olive', 'ERROR': 'tomato' } });
+
+ webpackRequire.l = (url, done) => {
+ const startTime = CHUNK_LOADER_DEBUG ? performance.now() : 0;
+
+ const match = url.match(/bundle\.([^.]+)\.js$/);
+ const chunkName = match?.[1];
+
+ const jslName = chunkName ? `chat:${chunkName.replace(/-/g, '_')}_js` : null;
+ const hasJslEntry = jslName && jsl2[jslName];
+
+ if (hasJslEntry) {
+ M.require(jslName)
+ .then(() => {
+ if (CHUNK_LOADER_DEBUG) {
+ const duration = (performance.now() - startTime).toFixed(1);
+ logger.debug(`Loaded '${chunkName}' chunk in ${duration}ms`, { chunkName, jslName, url });
+ }
+ done({ type: 'load' });
+ })
+ .catch(ex => {
+ logger.error(`Failed to load ${jslName}`, { error: ex, chunkName, jslName, url });
+ done({ type: 'error', target: { src: url } });
+ });
+ }
+ else {
+ logger.error(`Blocked insecure chunk load ('jsl2' entry missing)`, { chunkName, jslName, url });
+ done({ type: 'error', target: { src: url } });
+ }
+ };
+}
diff --git a/js/chat/mixins.js b/js/chat/mixins.js
index 52101728e2..0ae3f7d61a 100644
--- a/js/chat/mixins.js
+++ b/js/chat/mixins.js
@@ -1,6 +1,3 @@
-import ReactDOM from "react-dom";
-import React from "react";
-
var INTERSECTION_OBSERVER_AVAILABLE = typeof IntersectionObserver !== 'undefined';
var RESIZE_OBSERVER_AVAILABLE = typeof ResizeObserver !== 'undefined';
diff --git a/js/chat/ui/chatToaster.jsx b/js/chat/ui/chatToaster.jsx
index 6b10afb265..a119a7ed1e 100644
--- a/js/chat/ui/chatToaster.jsx
+++ b/js/chat/ui/chatToaster.jsx
@@ -1,6 +1,6 @@
import React from 'react';
import { getUniqueId } from "../mixins";
-import Call from './meetings/call.jsx';
+import { isExpanded } from './meetings/utils.jsx';
import { Button } from "../../ui/buttons";
const NAMESPACE = 'chat-toast';
@@ -48,7 +48,7 @@ export default class ChatToaster extends React.Component {
const { isRootToaster, showDualNotifications, onShownToast } = this.props;
const now = Date.now();
if (this.toasts.length + this.persistentToasts.length) {
- if (this.domRef.current && (!isRootToaster && Call.isExpanded() || M.chat)) {
+ if (this.domRef.current && (!isRootToaster && isExpanded() || M.chat)) {
if (this.toasts.length && !shownToast) {
this.dispatchToast(this.toasts.shift(), now);
}
diff --git a/js/chat/ui/contactSelectorDialog.jsx b/js/chat/ui/contactSelectorDialog.jsx
index 1c971b329b..b4d7f1c38f 100644
--- a/js/chat/ui/contactSelectorDialog.jsx
+++ b/js/chat/ui/contactSelectorDialog.jsx
@@ -75,9 +75,4 @@ class ContactSelectorDialog extends MegaRenderMixin {
}
}
-
-window.ContactSelectorDialogUI = {
- ContactSelectorDialog
-};
-
export default ContactSelectorDialog;
diff --git a/js/chat/ui/contacts.jsx b/js/chat/ui/contacts.jsx
index ab737b1882..fa68374aaf 100644
--- a/js/chat/ui/contacts.jsx
+++ b/js/chat/ui/contacts.jsx
@@ -5,10 +5,10 @@ import { Emoji, ParsedHTML, OFlowEmoji, reactStringWrap } from '../../ui/utils.j
import { PerfectScrollbar } from '../../ui/perfectScrollbar.jsx';
import { Button } from '../../ui/buttons.jsx';
import { Dropdown, DropdownItem } from '../../ui/dropdowns.jsx';
-import ContactsPanel from './contactsPanel/contactsPanel.jsx';
import ModalDialogs from '../../ui/modalDialogs';
import Link from './link.jsx';
import { withUpdateObserver } from './updateObserver.jsx';
+import { hasContacts } from './contactsPanel/utils.jsx';
export const MAX_FREQUENTS = 3;
@@ -1399,7 +1399,7 @@ export class ContactPickerWidget extends MegaRenderMixin {
self._eventuallyAddContact(M.u[u_handle], contacts, selectableContacts, true);
}
var noOtherContacts = false;
- if (contacts.length === 0 || !ContactsPanel.hasContacts() && this.props.step !== 1) {
+ if (contacts.length === 0 || !hasContacts() && this.props.step !== 1) {
noOtherContacts = true;
var noContactsMsg = "";
if (M.u.length < 2) {
@@ -1598,7 +1598,7 @@ export class ContactPickerWidget extends MegaRenderMixin {
}
{this.props.participantsList ? this.renderParticipantsList() : contactsList}
{selectFooter}
- {this.props.showAddContact && ContactsPanel.hasContacts() ?
+ {this.props.showAddContact && hasContacts() ?