merge next
This commit is contained in:
+131
-32
@@ -1939,105 +1939,204 @@ ul.tabbar li.active > a {
|
||||
}
|
||||
|
||||
/* Colors of letter tiles */
|
||||
.light-color0 {
|
||||
.lt-bg-0 {
|
||||
background-color: #ef9a9a;
|
||||
}
|
||||
.light-color1 {
|
||||
.lt-bg-1 {
|
||||
background-color: #90caf9;
|
||||
}
|
||||
.light-color2 {
|
||||
.lt-bg-2 {
|
||||
background-color: #b0bec5;
|
||||
}
|
||||
.light-color3 {
|
||||
.lt-bg-3 {
|
||||
background-color: #b39ddb;
|
||||
}
|
||||
.light-color4 {
|
||||
.lt-bg-4 {
|
||||
background-color: #ffab91;
|
||||
}
|
||||
.light-color5 {
|
||||
.lt-bg-5 {
|
||||
background-color: #a5d6a7;
|
||||
}
|
||||
.light-color6 {
|
||||
.lt-bg-6 {
|
||||
background-color: #eeeeee;
|
||||
}
|
||||
.light-color7 {
|
||||
.lt-bg-7 {
|
||||
background-color: #e6ee9c;
|
||||
}
|
||||
.light-color8 {
|
||||
.lt-bg-8 {
|
||||
background-color: #c5e1a5;
|
||||
}
|
||||
.light-color9 {
|
||||
.lt-bg-9 {
|
||||
background-color: #f0e57d;
|
||||
}
|
||||
.light-color10 {
|
||||
.lt-bg-10 {
|
||||
background-color: #f48fb1;
|
||||
}
|
||||
.light-color11 {
|
||||
.lt-bg-11 {
|
||||
background-color: #9fa8da;
|
||||
}
|
||||
.light-color12 {
|
||||
.lt-bg-12 {
|
||||
background-color: #ffe082;
|
||||
}
|
||||
.light-color13 {
|
||||
.lt-bg-13 {
|
||||
background-color: #bcaaa4;
|
||||
}
|
||||
.light-color14 {
|
||||
.lt-bg-14 {
|
||||
background-color: #80deea;
|
||||
}
|
||||
.light-color15 {
|
||||
.lt-bg-15 {
|
||||
background-color: #ce93d8;
|
||||
}
|
||||
|
||||
/* Darker version of letter tile colors */
|
||||
.dark-color0 {
|
||||
.dk-bg-0 {
|
||||
background-color: #C62828;
|
||||
}
|
||||
.dark-color1 {
|
||||
.dk-bg-1 {
|
||||
background-color: #AD1457;
|
||||
}
|
||||
.dark-color2 {
|
||||
.dk-bg-2 {
|
||||
background-color: #6A1B9A;
|
||||
}
|
||||
.dark-color3 {
|
||||
.dk-bg-3 {
|
||||
background-color: #4527A0;
|
||||
}
|
||||
.dark-color4 {
|
||||
.dk-bg-4 {
|
||||
background-color: #283593;
|
||||
}
|
||||
.dark-color5 {
|
||||
.dk-bg-5 {
|
||||
background-color: #1565C0;
|
||||
}
|
||||
.dark-color6 {
|
||||
.dk-bg-6 {
|
||||
background-color: #0277BD;
|
||||
}
|
||||
.dark-color7 {
|
||||
.dk-bg-7 {
|
||||
background-color: #00838F;
|
||||
}
|
||||
.dark-color8 {
|
||||
.dk-bg-8 {
|
||||
background-color: #00695C;
|
||||
}
|
||||
.dark-color9 {
|
||||
.dk-bg-9 {
|
||||
background-color: #2E7D32;
|
||||
}
|
||||
.dark-color10 {
|
||||
.dk-bg-10 {
|
||||
background-color: #558B2F;
|
||||
}
|
||||
.dark-color11 {
|
||||
.dk-bg-11 {
|
||||
background-color: #9E9D24;
|
||||
}
|
||||
.dark-color12 {
|
||||
.dk-bg-12 {
|
||||
background-color: #F9A825;
|
||||
}
|
||||
.dark-color13 {
|
||||
.dk-bg-13 {
|
||||
background-color: #FF8F00;
|
||||
}
|
||||
.dark-color14 {
|
||||
.dk-bg-14 {
|
||||
background-color: #EF6C00;
|
||||
}
|
||||
.dark-color15 {
|
||||
.dk-bg-15 {
|
||||
background-color: #D84315;
|
||||
}
|
||||
|
||||
/* Same colors as above but for text as opposite to background */
|
||||
.lt-fg-0 {
|
||||
color: #ef9a9a!important;
|
||||
}
|
||||
.lt-fg-1 {
|
||||
color: #90caf9!important;
|
||||
}
|
||||
.lt-fg-2 {
|
||||
color: #b0bec5!important;
|
||||
}
|
||||
.lt-fg-3 {
|
||||
color: #b39ddb!important;
|
||||
}
|
||||
.lt-fg-4 {
|
||||
color: #ffab91!important;
|
||||
}
|
||||
.lt-fg-5 {
|
||||
color: #a5d6a7!important;
|
||||
}
|
||||
.lt-fg-6 {
|
||||
color: #eeeeee!important;
|
||||
}
|
||||
.lt-fg-7 {
|
||||
color: #e6ee9c!important;
|
||||
}
|
||||
.lt-fg-8 {
|
||||
color: #c5e1a5!important;
|
||||
}
|
||||
.lt-fg-9 {
|
||||
color: #f0e57d!important;
|
||||
}
|
||||
.lt-fg-10 {
|
||||
color: #f48fb1!important;
|
||||
}
|
||||
.lt-fg-11 {
|
||||
color: #9fa8da!important;
|
||||
}
|
||||
.lt-fg-12 {
|
||||
color: #ffe082!important;
|
||||
}
|
||||
.lt-fg-13 {
|
||||
color: #bcaaa4!important;
|
||||
}
|
||||
.lt-fg-14 {
|
||||
color: #80deea!important;
|
||||
}
|
||||
.lt-fg-15 {
|
||||
color: #ce93d8!important;
|
||||
}
|
||||
|
||||
.dk-fg-0 {
|
||||
color: #C62828!important;
|
||||
}
|
||||
.dk-fg-1 {
|
||||
color: #AD1457!important;
|
||||
}
|
||||
.dk-fg-2 {
|
||||
color: #6A1B9A!important;
|
||||
}
|
||||
.dk-fg-3 {
|
||||
color: #4527A0!important;
|
||||
}
|
||||
.dk-fg-4 {
|
||||
color: #283593!important;
|
||||
}
|
||||
.dk-fg-5 {
|
||||
color: #1565C0!important;
|
||||
}
|
||||
.dk-fg-6 {
|
||||
color: #0277BD!important;
|
||||
}
|
||||
.dk-fg-7 {
|
||||
color: #00838F!important;
|
||||
}
|
||||
.dk-fg-8 {
|
||||
color: #00695C!important;
|
||||
}
|
||||
.dk-fg-9 {
|
||||
color: #2E7D32!important;
|
||||
}
|
||||
.dk-fg-10 {
|
||||
color: #558B2F!important;
|
||||
}
|
||||
.dk-fg-11 {
|
||||
color: #9E9D24!important;
|
||||
}
|
||||
.dk-fg-12 {
|
||||
color: #F9A825!important;
|
||||
}
|
||||
.dk-fg-13 {
|
||||
color: #FF8F00!important;
|
||||
}
|
||||
.dk-fg-14 {
|
||||
color: #EF6C00!important;
|
||||
}
|
||||
.dk-fg-15 {
|
||||
color: #D84315!important;
|
||||
}
|
||||
|
||||
/* Material icons resized from the default 24pt */
|
||||
.material-icons {
|
||||
font-size: 1.4rem;
|
||||
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
+10
-1
@@ -39,7 +39,7 @@ export function bytesToHumanSize(bytes) {
|
||||
|
||||
// Get 32 bit integer hash value for a string. Ideally it should produce the same value
|
||||
// as Java's String#hash().
|
||||
export function stringHash(value) {
|
||||
function stringToColorHash(value) {
|
||||
let hash = 0;
|
||||
value = '' + value;
|
||||
for (let i = 0; i < value.length; i++) {
|
||||
@@ -48,3 +48,12 @@ export function stringHash(value) {
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
// Converts user or topic ID to a CSS color class. Ideally it should produce the same color value as Java version.
|
||||
// params:
|
||||
// - {string} id: user or topic ID
|
||||
// - {boolean} light: light or dark version of the color.
|
||||
// - {boolean} fg: foreground or background color.
|
||||
export function idToColorClass(id, light, fg) {
|
||||
return (light ? 'lt-' : 'dk-') + (fg ? 'fg-' : 'bg-') + (Math.abs(stringToColorHash(id)) % 16);
|
||||
}
|
||||
|
||||
+46
-21
@@ -91,6 +91,7 @@ class InfoView extends React.Component {
|
||||
owner: false,
|
||||
admin: false,
|
||||
sharer: false,
|
||||
deleter: false,
|
||||
muted: false,
|
||||
address: null,
|
||||
groupTopic: undefined,
|
||||
@@ -115,6 +116,7 @@ class InfoView extends React.Component {
|
||||
|
||||
this.resetSubs = this.resetSubs.bind(this);
|
||||
this.resetDesc = this.resetDesc.bind(this);
|
||||
this.resetTags = this.resetTags.bind(this);
|
||||
this.onMetaDesc = this.onMetaDesc.bind(this);
|
||||
this.onSubsUpdated = this.onSubsUpdated.bind(this);
|
||||
this.handleImageChanged = this.handleImageChanged.bind(this);
|
||||
@@ -147,6 +149,7 @@ class InfoView extends React.Component {
|
||||
this.setState({topic: props.topic});
|
||||
this.resetDesc(topic, props);
|
||||
this.resetSubs(topic, props);
|
||||
this.resetTags(topic);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,6 +202,7 @@ class InfoView extends React.Component {
|
||||
owner: acs && acs.isOwner(),
|
||||
admin: acs && acs.isAdmin(),
|
||||
sharer: acs && acs.isSharer(),
|
||||
deleter: acs && acs.isDeleter(),
|
||||
muted: acs && acs.isMuted(),
|
||||
|
||||
fullName: _clip(topic.public ? topic.public.fn : undefined, MAX_TITLE_LENGTH),
|
||||
@@ -215,8 +219,15 @@ class InfoView extends React.Component {
|
||||
auth: defacs.auth,
|
||||
anon: defacs.anon
|
||||
});
|
||||
}
|
||||
|
||||
if (topic.getType() == 'grp' && acs && acs.isOwner()) {
|
||||
resetTags(topic) {
|
||||
if (topic.getType() != 'grp') {
|
||||
return;
|
||||
}
|
||||
|
||||
const acs = topic.getAccessMode();
|
||||
if (acs && acs.isOwner()) {
|
||||
// Requesting tags: owner is editing the topic.
|
||||
topic.getMeta(topic.startMetaQuery().withTags().build());
|
||||
}
|
||||
@@ -257,13 +268,12 @@ class InfoView extends React.Component {
|
||||
}
|
||||
|
||||
handlePermissionsChanged(which, perm) {
|
||||
console.log("handlePermissionsChanged", which, perm);
|
||||
switch (which) {
|
||||
case 'auth':
|
||||
this.props.onTopicDescUpdate(this.props.topic, null, null, {auth: perm});
|
||||
this.props.onTopicDescUpdateRequest(this.props.topic, null, null, {auth: perm});
|
||||
break;
|
||||
case 'anon':
|
||||
this.props.onTopicDescUpdate(this.props.topic, null, null, {anon: perm});
|
||||
this.props.onTopicDescUpdateRequest(this.props.topic, null, null, {anon: perm});
|
||||
break;
|
||||
case 'mode':
|
||||
case 'want':
|
||||
@@ -276,10 +286,11 @@ class InfoView extends React.Component {
|
||||
this.props.onChangePermissions(this.props.topic, perm, this.state.userPermissionsEdited);
|
||||
break;
|
||||
}
|
||||
|
||||
this.handleBackNavigate();
|
||||
}
|
||||
|
||||
handleLaunchPermissionsEditor(which, uid) {
|
||||
console.log(which, uid);
|
||||
const {formatMessage} = this.props.intl;
|
||||
let toEdit, toCompare, toSkip, titleEdit, titleCompare, userTitle, userAvatar;
|
||||
switch (which) {
|
||||
@@ -339,7 +350,7 @@ class InfoView extends React.Component {
|
||||
break;
|
||||
}
|
||||
default:
|
||||
console.log("Unknown permission editing mode '" + which + "'");
|
||||
console.error("Unknown permission editing mode '" + which + "'");
|
||||
return;
|
||||
}
|
||||
this.setState({
|
||||
@@ -396,14 +407,19 @@ class InfoView extends React.Component {
|
||||
return;
|
||||
}
|
||||
|
||||
const isMe = this.props.tinode.isMe(params.topicName);
|
||||
const menuItems = [
|
||||
{title: formatMessage(messages.edit_permissions), handler: () => {
|
||||
this.handleLaunchPermissionsEditor('user', params.topicName);
|
||||
}},
|
||||
'member_delete',
|
||||
user.acs.isMuted() ? 'member_unmute' : 'member_mute',
|
||||
user.acs.isJoiner() ? 'member_block' : 'member_unblock'
|
||||
this.handleLaunchPermissionsEditor(isMe ? 'want' : 'user', params.topicName);
|
||||
}}
|
||||
];
|
||||
if (!isMe) {
|
||||
menuItems.push('member_delete');
|
||||
}
|
||||
menuItems.push(user.acs.isMuted() ? 'member_unmute' : 'member_mute');
|
||||
if (!isMe) {
|
||||
menuItems.push(user.acs.isJoiner() ? 'member_block' : 'member_unblock');
|
||||
}
|
||||
this.props.showContextMenu({
|
||||
topicName: this.props.topic,
|
||||
x: params.x,
|
||||
@@ -413,7 +429,6 @@ class InfoView extends React.Component {
|
||||
|
||||
render() {
|
||||
const args = (this.props.panel || 'info').split('/');
|
||||
console.log("args:", args);
|
||||
const view = args[0];
|
||||
args.shift();
|
||||
|
||||
@@ -464,17 +479,31 @@ class InfoView extends React.Component {
|
||||
tinode={this.props.tinode}
|
||||
topic={this.props.topic}
|
||||
onCredAdd={this.props.onCredAdd}
|
||||
onTopicTagsUpdate={this.props.onTopicTagsUpdate}
|
||||
onTopicTagsUpdateRequest={this.props.onTopicTagsUpdateRequest}
|
||||
onCredConfirm={this.props.onCredConfirm}
|
||||
onCredDelete={this.props.onCredDelete}
|
||||
onUpdateTopicDesc={this.props.onTopicDescUpdate}
|
||||
onUpdateTags={this.props.onUpdateTags}
|
||||
onUpdateTopicDesc={this.props.onTopicDescUpdateRequest}
|
||||
onError={this.props.onError} />
|
||||
:
|
||||
view == 'security' ?
|
||||
<TopicSecurity
|
||||
tinode={this.props.tinode}
|
||||
topic={this.props.topic}
|
||||
owner={this.state.owner}
|
||||
admin={this.state.admin}
|
||||
sharer={this.state.sharer}
|
||||
deleter={this.state.deleter}
|
||||
muted={this.state.muted}
|
||||
|
||||
groupTopic={this.state.groupTopic}
|
||||
channel={this.state.channel}
|
||||
access={this.state.access}
|
||||
modeGiven={this.state.modeGiven}
|
||||
modeWant={this.state.modeWant}
|
||||
modeGiven2={this.state.modeGiven2}
|
||||
modeWant2={this.state.modeWant2}
|
||||
auth={this.state.auth}
|
||||
anon={this.state.anon}
|
||||
|
||||
onShowAlert={this.props.onShowAlert}
|
||||
onDeleteMessages={this.props.onDeleteMessages}
|
||||
onLeaveTopic={this.props.onLeaveTopic}
|
||||
@@ -533,7 +562,6 @@ class InfoView extends React.Component {
|
||||
</div> : null}
|
||||
</div>
|
||||
<div className="hr" />
|
||||
<div className="panel-form-column">
|
||||
<div className="panel-form-row">
|
||||
<label>
|
||||
<FormattedMessage id="label_muting_topic" defaultMessage="Muted:"
|
||||
@@ -541,9 +569,8 @@ class InfoView extends React.Component {
|
||||
</label>
|
||||
<CheckBox name="P" checked={this.state.muted} onChange={this.handleMuted} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="hr" />
|
||||
<div className="panel-form-column">
|
||||
<div className="panel-form-row">
|
||||
<a href="#" className="flat-button" onClick={(e) => {e.preventDefault(); this.props.onNavigate('security');}}>
|
||||
<i className="material-icons">security</i> <FormattedMessage id="button_security"
|
||||
defaultMessage="Security" description="Navigaton button for security panel." />
|
||||
@@ -552,7 +579,6 @@ class InfoView extends React.Component {
|
||||
{this.state.groupTopic && this.state.sharer ?
|
||||
<>
|
||||
<div className="hr" />
|
||||
<div className="panel-form-column">
|
||||
<div className="panel-form-row">
|
||||
<label className="small">
|
||||
<FormattedMessage id="label_group_members" defaultMessage="Group members:"
|
||||
@@ -581,7 +607,6 @@ class InfoView extends React.Component {
|
||||
showContextMenu={this.state.admin ? this.handleContextMenu : false}
|
||||
/>
|
||||
}</FormattedMessage>
|
||||
</div>
|
||||
</>
|
||||
:
|
||||
null
|
||||
|
||||
+29
-36
@@ -98,7 +98,7 @@ class MessagesView extends React.Component {
|
||||
this.handleScrollEvent = this.handleScrollEvent.bind(this);
|
||||
this.handleDescChange = this.handleDescChange.bind(this);
|
||||
this.handleSubsUpdated = this.handleSubsUpdated.bind(this);
|
||||
this.handleNewMessage = this.handleNewMessage.bind(this);
|
||||
this.handleMessageUpdate = this.handleMessageUpdate.bind(this);
|
||||
this.handleAllMessagesReceived = this.handleAllMessagesReceived.bind(this);
|
||||
this.handleInfoReceipt = this.handleInfoReceipt.bind(this);
|
||||
this.handleImagePostview = this.handleImagePostview.bind(this);
|
||||
@@ -144,7 +144,7 @@ class MessagesView extends React.Component {
|
||||
// or vertical shrinking.
|
||||
componentDidUpdate(prevProps, prevState) {
|
||||
if (this.messagesScroller) {
|
||||
if (prevState.topic != this.state.topic || prevState.messages.length != this.state.messages.length) {
|
||||
if (prevState.topic != this.state.topic || prevState.latestMsgSeq != this.state.latestMsgSeq) {
|
||||
// New message
|
||||
this.messagesScroller.scrollTop = this.messagesScroller.scrollHeight - this.state.scrollPosition;
|
||||
} else if (prevProps.viewportHeight > this.props.viewportHeight) {
|
||||
@@ -160,7 +160,7 @@ class MessagesView extends React.Component {
|
||||
}
|
||||
|
||||
if (topic) {
|
||||
topic.onData = this.handleNewMessage;
|
||||
topic.onData = this.handleMessageUpdate;
|
||||
topic.onAllMessagesReceived = this.handleAllMessagesReceived;
|
||||
topic.onInfo = this.handleInfoReceipt;
|
||||
topic.onMetaDesc = this.handleDescChange;
|
||||
@@ -228,7 +228,8 @@ class MessagesView extends React.Component {
|
||||
if (!nextProps.topic) {
|
||||
// Default state: no topic.
|
||||
nextState = {
|
||||
messages: [],
|
||||
latestMsgSeq: -1,
|
||||
latestClearId: -1,
|
||||
onlineSubs: [],
|
||||
topic: null,
|
||||
title: '',
|
||||
@@ -261,7 +262,6 @@ class MessagesView extends React.Component {
|
||||
|
||||
if (topic) {
|
||||
// Topic exists.
|
||||
const msgs = [];
|
||||
const subs = [];
|
||||
|
||||
if (nextProps.connected) {
|
||||
@@ -272,14 +272,7 @@ class MessagesView extends React.Component {
|
||||
});
|
||||
}
|
||||
|
||||
topic.messages(function(msg) {
|
||||
if (!msg.deleted) {
|
||||
msgs.push(msg);
|
||||
}
|
||||
});
|
||||
|
||||
Object.assign(nextState, {
|
||||
messages: msgs,
|
||||
onlineSubs: subs
|
||||
});
|
||||
|
||||
@@ -306,12 +299,15 @@ class MessagesView extends React.Component {
|
||||
});
|
||||
}
|
||||
Object.assign(nextState, {
|
||||
latestMsgSeq: topic.maxMsgSeq(),
|
||||
latestClearId: topic.maxClearId(),
|
||||
channel: topic.isChannelType()
|
||||
});
|
||||
} else {
|
||||
// Invalid topic.
|
||||
Object.assign(nextState, {
|
||||
messages: [],
|
||||
latestMsgSeq: -1,
|
||||
latestClearId: -1,
|
||||
onlineSubs: [],
|
||||
title: '',
|
||||
avatar: null,
|
||||
@@ -401,7 +397,9 @@ class MessagesView extends React.Component {
|
||||
const topic = this.props.tinode.getTopic(this.state.topic);
|
||||
if (topic && topic.isSubscribed() && topic.msgHasMoreMessages()) {
|
||||
newState.fetchingMessages = true;
|
||||
topic.getMessagesPage(MESSAGES_PAGE).catch((err) => {
|
||||
topic.getMessagesPage(MESSAGES_PAGE)
|
||||
.then(() => this.setState({fetchingMessages: false}))
|
||||
.catch((err) => {
|
||||
this.setState({fetchingMessages: false});
|
||||
this.props.onError(err.message, 'err');
|
||||
});
|
||||
@@ -521,22 +519,22 @@ class MessagesView extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
handleNewMessage(msg) {
|
||||
// Regenerate messages list
|
||||
// The 'msg' could be false-ish if some message ranges were deleted.
|
||||
handleMessageUpdate(msg) {
|
||||
const topic = this.props.tinode.getTopic(this.state.topic);
|
||||
const newState = {messages: []};
|
||||
topic.messages((m) => {
|
||||
if (!m.deleted) {
|
||||
newState.messages.push(m);
|
||||
}
|
||||
});
|
||||
|
||||
if (!msg) {
|
||||
// msg could be null if one or more messages were deleted.
|
||||
if (msg && !msg.deleted) {
|
||||
// Updating state to force redraw.
|
||||
this.setState({latestClearId: topic.maxClearId()});
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState({latestMsgSeq: topic.maxMsgSeq()});
|
||||
|
||||
// If the message is added to the end of the message list,
|
||||
// scroll to the bottom.
|
||||
if (topic.isNewMessage(msg.seq)) {
|
||||
newState.scrollPosition = 0;
|
||||
this.setState({scrollPosition: 0});
|
||||
}
|
||||
|
||||
// Aknowledge messages except own messages. They are
|
||||
@@ -545,10 +543,9 @@ class MessagesView extends React.Component {
|
||||
if (status >= Tinode.MESSAGE_STATUS_SENT && msg.from != this.props.myUserId) {
|
||||
this.postReadNotification(msg.seq);
|
||||
}
|
||||
// This will send "received" notifications right away.
|
||||
this.props.onData(msg);
|
||||
}
|
||||
this.setState(newState);
|
||||
}
|
||||
|
||||
handleAllMessagesReceived(count) {
|
||||
this.setState({fetchingMessages: false});
|
||||
@@ -798,7 +795,8 @@ class MessagesView extends React.Component {
|
||||
}
|
||||
|
||||
handleCancelUpload(seq, uploader) {
|
||||
const found = this.state.messages.find(msg => msg.seq == seq);
|
||||
const topic = this.props.tinode.getTopic(this.state.topic);
|
||||
const found = topic.findMessage(seq);
|
||||
if (found) {
|
||||
found._cancelled = true;
|
||||
}
|
||||
@@ -1019,13 +1017,8 @@ class MessagesView extends React.Component {
|
||||
let messageNodes = [];
|
||||
let previousFrom = null;
|
||||
let chatBoxClass = null;
|
||||
for (let i=0; i<this.state.messages.length; i++) {
|
||||
let msg = this.state.messages[i];
|
||||
let nextFrom = null;
|
||||
|
||||
if (i + 1 < this.state.messages.length) {
|
||||
nextFrom = this.state.messages[i+1].from || 'chan';
|
||||
}
|
||||
topic.messages((msg, prev, next, i) => {
|
||||
let nextFrom = next ? (next.from || null) : 'chan';
|
||||
|
||||
let sequence = 'single';
|
||||
let thisFrom = msg.from || 'chan';
|
||||
@@ -1085,7 +1078,7 @@ class MessagesView extends React.Component {
|
||||
|
||||
key={msg.seq} />
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
let lastSeen = null;
|
||||
if (isChannel) {
|
||||
|
||||
@@ -121,7 +121,7 @@ class TinodeWeb extends React.Component {
|
||||
this.handleNewTopicCreated = this.handleNewTopicCreated.bind(this);
|
||||
this.handleTopicUpdateRequest = this.handleTopicUpdateRequest.bind(this);
|
||||
this.handleChangePermissions = this.handleChangePermissions.bind(this);
|
||||
this.handleTagsUpdated = this.handleTagsUpdated.bind(this);
|
||||
this.handleTagsUpdateRequest = this.handleTagsUpdateRequest.bind(this);
|
||||
this.handleLogout = this.handleLogout.bind(this);
|
||||
this.handleDeleteAccount = this.handleDeleteAccount.bind(this);
|
||||
this.handleDeleteTopicRequest = this.handleDeleteTopicRequest.bind(this);
|
||||
@@ -225,7 +225,7 @@ class TinodeWeb extends React.Component {
|
||||
serviceWorkerChannel.addEventListener('message', this.handlePushMessage);
|
||||
} else {
|
||||
// Safari is broken by design.
|
||||
console.warn('Your browser does not support BroadcastChannel. Some features will not be available');
|
||||
console.warn("Your browser does not support BroadcastChannel. Some features will not be available");
|
||||
}
|
||||
|
||||
// Window/tab visible or invisible for pausing timers.
|
||||
@@ -565,8 +565,9 @@ class TinodeWeb extends React.Component {
|
||||
cred = Tinode.credential(cred);
|
||||
// Try to login with login/password. If they are not available, try token. If no token, ask for login/password.
|
||||
let promise = null;
|
||||
const token = this.tinode.getAuthToken();
|
||||
let token = this.tinode.getAuthToken();
|
||||
if (login && password) {
|
||||
token = null;
|
||||
this.setState({password: null});
|
||||
promise = this.tinode.loginBasic(login, password, cred);
|
||||
} else if (token) {
|
||||
@@ -594,7 +595,9 @@ class TinodeWeb extends React.Component {
|
||||
autoLogin: false
|
||||
});
|
||||
this.handleError(err.message, 'err');
|
||||
localStorage.removeItem('auth-token');
|
||||
if (token) {
|
||||
this.handleLogout();
|
||||
}
|
||||
HashNavigation.navigateTo('');
|
||||
});
|
||||
} else {
|
||||
@@ -1275,7 +1278,7 @@ class TinodeWeb extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
handleTagsUpdated(topicName, tags) {
|
||||
handleTagsUpdateRequest(topicName, tags) {
|
||||
const topic = this.tinode.getTopic(topicName);
|
||||
if (topic) {
|
||||
topic.setMeta({tags: tags}).catch((err) => {
|
||||
@@ -1694,7 +1697,7 @@ class TinodeWeb extends React.Component {
|
||||
errorActionText={this.state.errorActionText}
|
||||
|
||||
onNavigate={this.infoNavigator}
|
||||
onTopicDescUpdate={this.handleTopicUpdateRequest}
|
||||
onTopicDescUpdateRequest={this.handleTopicUpdateRequest}
|
||||
onShowAlert={this.handleShowAlert}
|
||||
onChangePermissions={this.handleChangePermissions}
|
||||
onMemberUpdateRequest={this.handleMemberUpdateRequest}
|
||||
@@ -1704,7 +1707,7 @@ class TinodeWeb extends React.Component {
|
||||
onBlockTopic={this.handleBlockTopicRequest}
|
||||
onReportTopic={this.handleReportTopic}
|
||||
onAddMember={this.handleManageGroupMembers}
|
||||
onTopicTagsUpdate={this.handleTagsUpdated}
|
||||
onTopicTagsUpdateRequest={this.handleTagsUpdateRequest}
|
||||
onInitFind={this.tnInitFind}
|
||||
onError={this.handleError}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import Attachment from './attachment.jsx';
|
||||
import LetterTile from './letter-tile.jsx';
|
||||
import ReceivedMarker from './received-marker.jsx'
|
||||
import UploadingImage from './uploading-image.jsx'
|
||||
|
||||
import { sanitizeImageUrl, sanitizeUrl } from '../lib/utils.js';
|
||||
|
||||
class ChatMessage extends React.PureComponent {
|
||||
@@ -106,8 +107,10 @@ class ChatMessage extends React.PureComponent {
|
||||
attachments.push(<Attachment
|
||||
tinode={this.props.tinode}
|
||||
downloadUrl={Drafty.getDownloadUrl(att)}
|
||||
filename={att.name} uploading={Drafty.isProcessing(att)}
|
||||
mimetype={att.mime} size={Drafty.getEntitySize(att)}
|
||||
filename={att.name}
|
||||
uploading={Drafty.isProcessing(att)}
|
||||
mimetype={att.mime}
|
||||
size={Drafty.getEntitySize(att)}
|
||||
progress={this.state.progress}
|
||||
onCancelUpload={this.handleCancelUpload}
|
||||
onError={this.props.onError}
|
||||
@@ -175,10 +178,10 @@ class ChatMessage extends React.PureComponent {
|
||||
</div>
|
||||
{fullDisplay ?
|
||||
<div className="author">
|
||||
<FormattedMessage id="user_not_found" defaultMessage="Not found"
|
||||
description="In place of a user's full name when the user is not found.">{
|
||||
(notFound) => {return this.props.userName || <i>{notFound}</i>}
|
||||
}</FormattedMessage>
|
||||
{this.props.userName ||
|
||||
<i><FormattedMessage id="user_not_found" defaultMessage="Not found"
|
||||
description="In place of a user's full name when the user is not found." /></i>
|
||||
}
|
||||
</div>
|
||||
: null
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import React from 'react';
|
||||
|
||||
import Tinode from 'tinode-sdk';
|
||||
|
||||
import { stringHash } from '../lib/strformat.js';
|
||||
import { idToColorClass } from '../lib/strformat.js';
|
||||
import { sanitizeImageUrl } from '../lib/utils.js';
|
||||
|
||||
export default class LetterTile extends React.PureComponent {
|
||||
@@ -10,8 +10,7 @@ export default class LetterTile extends React.PureComponent {
|
||||
let avatar;
|
||||
if (this.props.avatar === true) {
|
||||
const isGroup = (Tinode.topicType(this.props.topic) == 'grp');
|
||||
const iconColor = (isGroup ? 'light-color' : 'dark-color')
|
||||
+ (Math.abs(stringHash(this.props.topic)) % 16);
|
||||
const iconColor = idToColorClass(this.props.topic, isGroup);
|
||||
if (this.props.topic && this.props.title && this.props.title.trim()) {
|
||||
const letter = this.props.title.trim().charAt(0);
|
||||
const className = 'lettertile ' + iconColor;
|
||||
|
||||
@@ -21,10 +21,11 @@ export default class TopicCommon extends React.Component {
|
||||
addCredActive: false,
|
||||
addCredInvalid: false,
|
||||
newCred: '',
|
||||
tags: [],
|
||||
previousTagsUpdated: undefined
|
||||
tags: []
|
||||
};
|
||||
|
||||
this.previousTagsUpdated = undefined;
|
||||
|
||||
this.onTagsUpdated = this.onTagsUpdated.bind(this);
|
||||
this.handleTagsUpdated = this.handleTagsUpdated.bind(this);
|
||||
this.tnCredsUpdated = this.tnCredsUpdated.bind(this);
|
||||
@@ -105,17 +106,19 @@ export default class TopicCommon extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
// Server informs that the tags have been updated.
|
||||
onTagsUpdated(tags) {
|
||||
this.setState({tags: tags});
|
||||
|
||||
if (this.previousTagsUpdated && this.previousTagsUpdated != this.onTagsUpdated) {
|
||||
this.previousTagsUpdated();
|
||||
this.previousTagsUpdated(tags);
|
||||
}
|
||||
}
|
||||
|
||||
// Request server to change tags.
|
||||
handleTagsUpdated(tags) {
|
||||
if (!arrayEqual(this.state.tags.slice(0), tags.slice(0))) {
|
||||
this.props.onTopicTagsUpdate(this.props.topic, tags);
|
||||
this.props.onTopicTagsUpdateRequest(this.props.topic, tags);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,7 +146,7 @@ export default class TopicCommon extends React.Component {
|
||||
tinode={this.props.tinode}
|
||||
topic={this.props.topic}
|
||||
onUpdateTopicDesc={this.props.onUpdateTopicDesc}
|
||||
onUpdateTags={this.props.onUpdateTags}
|
||||
onUpdateTags={this.handleTagsUpdated}
|
||||
onError={this.props.onError} />
|
||||
{this.state.isMe ?
|
||||
<>
|
||||
|
||||
@@ -28,12 +28,13 @@ export default class TopicDescEdit extends React.Component {
|
||||
private: topic.private ? topic.private.comment : null,
|
||||
description: topic.public ? topic.public.note : undefined,
|
||||
avatar: makeImageUrl(topic.public ? topic.public.photo : null),
|
||||
tags: topic.tags(),
|
||||
tags: topic.tags() || [],
|
||||
newAvatar: null,
|
||||
newAvatarMime: null,
|
||||
previousOnTags: topic.onTagsUpdated
|
||||
newAvatarMime: null
|
||||
};
|
||||
|
||||
this.previousOnTags = null;
|
||||
|
||||
this.tnNewTags = this.tnNewTags.bind(this);
|
||||
this.handleFullNameUpdate = this.handleFullNameUpdate.bind(this);
|
||||
this.handleImageUpdated = this.handleImageUpdated.bind(this);
|
||||
@@ -47,12 +48,13 @@ export default class TopicDescEdit extends React.Component {
|
||||
|
||||
componentDidMount() {
|
||||
const topic = this.props.tinode.getTopic(this.props.topic);
|
||||
this.previousOnTags = topic.onTagsUpdated;
|
||||
topic.onTagsUpdated = this.tnNewTags;
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
const topic = this.props.tinode.getTopic(this.props.topic);
|
||||
topic.onTagsUpdated = this.state.previousOnTags;
|
||||
topic.onTagsUpdated = this.previousOnTags;
|
||||
}
|
||||
|
||||
tnNewTags(tags) {
|
||||
|
||||
@@ -74,48 +74,10 @@ const messages = defineMessages({
|
||||
},
|
||||
});
|
||||
|
||||
class TopicSecurity extends React.Component {
|
||||
class TopicSecurity extends React.PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
const topic = this.props.tinode.getTopic(this.props.topic);
|
||||
if (!topic) {
|
||||
return;
|
||||
}
|
||||
|
||||
const defacs = topic.getDefaultAccess() || {};
|
||||
const acs = topic.getAccessMode();
|
||||
|
||||
let modeGiven2 = NO_ACCESS_MODE;
|
||||
let modeWant2 = NO_ACCESS_MODE;
|
||||
if (topic.getType() == 'p2p') {
|
||||
// Fetch the other party in the p2p conversation.
|
||||
// Topic may not be ready yet, so check if user is found.
|
||||
const user2 = topic.subscriber(props.topic);
|
||||
if (user2 && user2.acs) {
|
||||
modeGiven2 = user2.acs.getGiven();
|
||||
modeWant2 = user2.acs.getWant();
|
||||
}
|
||||
}
|
||||
|
||||
this.state = {
|
||||
owner: acs && acs.isOwner(),
|
||||
admin: acs && acs.isAdmin(),
|
||||
sharer: acs && acs.isSharer(),
|
||||
deleter: acs && acs.isDeleter(),
|
||||
muted: acs && acs.isMuted(),
|
||||
|
||||
groupTopic: topic.isGroupType(),
|
||||
channel: topic.isChannelType(),
|
||||
access: acs ? acs.getMode() : undefined,
|
||||
modeGiven: acs ? acs.getGiven() : undefined,
|
||||
modeWant: acs ? acs.getWant() : undefined,
|
||||
modeGiven2: modeGiven2, // P2P topic, the other user mode given
|
||||
modeWant2: modeWant2, // P2P topic, the other user mode want
|
||||
auth: defacs ? defacs.auth : null,
|
||||
anon: defacs ? defacs.anon : null,
|
||||
};
|
||||
|
||||
this.handleDeleteTopic = this.handleDeleteTopic.bind(this);
|
||||
this.handleDeleteMessages = this.handleDeleteMessages.bind(this);
|
||||
this.handleLeave = this.handleLeave.bind(this);
|
||||
@@ -140,8 +102,8 @@ class TopicSecurity extends React.Component {
|
||||
e.preventDefault();
|
||||
const {formatMessage} = this.props.intl;
|
||||
this.props.onShowAlert(
|
||||
formatMessage(this.state.deleter ? messages.delete_messages : messages.clear_messages), // title
|
||||
formatMessage(this.state.deleter ? messages.delete_messages_warning : messages.clear_messages_warning), // content
|
||||
formatMessage(this.props.deleter ? messages.delete_messages : messages.clear_messages), // title
|
||||
formatMessage(this.props.deleter ? messages.delete_messages_warning : messages.clear_messages_warning), // content
|
||||
(() => { this.props.onDeleteMessages(this.props.topic); }), // onConfirm
|
||||
null, // "OK"
|
||||
true, // Show Reject button
|
||||
@@ -193,16 +155,16 @@ class TopicSecurity extends React.Component {
|
||||
return (
|
||||
<div className="scrollable-panel">
|
||||
<div className="panel-form-column">
|
||||
{!this.state.channel ?
|
||||
{!this.props.channel ?
|
||||
<a href="#" className="flat-button" onClick={this.handleDeleteMessages}>
|
||||
<i className="material-icons">delete_outline</i> {
|
||||
formatMessage(this.state.deleter ? messages.delete_messages : messages.clear_messages)
|
||||
formatMessage(this.props.deleter ? messages.delete_messages : messages.clear_messages)
|
||||
}
|
||||
</a>
|
||||
:
|
||||
null
|
||||
}
|
||||
{this.state.owner ?
|
||||
{this.props.owner ?
|
||||
<a href="#" className="danger flat-button" onClick={this.handleDeleteTopic}>
|
||||
<i className="material-icons">delete</i> {formatMessage(messages.topic_delete)}
|
||||
</a>
|
||||
@@ -211,14 +173,14 @@ class TopicSecurity extends React.Component {
|
||||
<i className="material-icons">exit_to_app</i> {formatMessage(messages.leave_chat)}
|
||||
</a>
|
||||
}
|
||||
{!this.state.groupTopic ?
|
||||
{!this.props.groupTopic ?
|
||||
<a href="#" className="danger flat-button" onClick={this.handleBlock}>
|
||||
<i className="material-icons">block</i> {formatMessage(messages.block_contact)}
|
||||
</a>
|
||||
:
|
||||
null
|
||||
}
|
||||
{!this.state.owner ?
|
||||
{!this.props.owner ?
|
||||
<a href="#" className="danger flat-button" onClick={this.handleReport}>
|
||||
<i className="material-icons">report</i> {formatMessage(messages.report_chat)}
|
||||
</a>
|
||||
@@ -228,7 +190,7 @@ class TopicSecurity extends React.Component {
|
||||
</div>
|
||||
<div className="hr" />
|
||||
<div className="panel-form-column">
|
||||
{this.state.groupTopic ?
|
||||
{this.props.groupTopic ?
|
||||
<>
|
||||
<div className="group">
|
||||
<label>
|
||||
@@ -236,7 +198,7 @@ class TopicSecurity extends React.Component {
|
||||
description="Label for current user permissions" />
|
||||
</label> <tt className="clickable"
|
||||
onClick={(e) => {e.preventDefault(); this.props.onLaunchPermissionsEditor('want')}}>
|
||||
{this.state.access}
|
||||
{this.props.access}
|
||||
</tt>
|
||||
</div>
|
||||
<div className="group">
|
||||
@@ -248,10 +210,10 @@ class TopicSecurity extends React.Component {
|
||||
</div>
|
||||
<div className="quoted">
|
||||
<div>Auth: <tt className="clickable"
|
||||
onClick={(e) => {e.preventDefault(); this.props.onLaunchPermissionsEditor('auth')}}>{this.state.auth}</tt>
|
||||
onClick={(e) => {e.preventDefault(); this.props.onLaunchPermissionsEditor('auth')}}>{this.props.auth}</tt>
|
||||
</div>
|
||||
<div>Anon: <tt className="clickable"
|
||||
onClick={(e) => {e.preventDefault(); this.props.onLaunchPermissionsEditor('anon')}}>{this.state.anon}</tt>
|
||||
onClick={(e) => {e.preventDefault(); this.props.onLaunchPermissionsEditor('anon')}}>{this.props.anon}</tt>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -269,13 +231,13 @@ class TopicSecurity extends React.Component {
|
||||
<FormattedMessage id="label_you" defaultMessage="You:"
|
||||
description="Label for the current user" /> <tt className="clickable"
|
||||
onClick={(e) => {e.preventDefault(); this.props.onLaunchPermissionsEditor('want')}}>
|
||||
{this.state.access}
|
||||
{this.props.access}
|
||||
</tt>
|
||||
</div>
|
||||
<div>{this.state.fullName ? this.state.fullName : formatMessage(messages.other_user)}:
|
||||
<div>{this.props.fullName ? this.props.fullName : formatMessage(messages.other_user)}:
|
||||
<tt className="clickable"
|
||||
onClick={(e) => {e.preventDefault(); this.props.onLaunchPermissionsEditor('given')}}>
|
||||
{this.state.modeGiven2}
|
||||
{this.props.modeGiven2}
|
||||
</tt>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+125
-129
@@ -535,7 +535,7 @@ __webpack_require__.r(__webpack_exports__);
|
||||
/* harmony export */ "shortDateFormat": () => (/* binding */ shortDateFormat),
|
||||
/* harmony export */ "secondsToTime": () => (/* binding */ secondsToTime),
|
||||
/* harmony export */ "bytesToHumanSize": () => (/* binding */ bytesToHumanSize),
|
||||
/* harmony export */ "stringHash": () => (/* binding */ stringHash)
|
||||
/* harmony export */ "idToColorClass": () => (/* binding */ idToColorClass)
|
||||
/* harmony export */ });
|
||||
function shortDateFormat(then, locale) {
|
||||
locale = locale || window.navigator.userLanguage || window.navigator.language;
|
||||
@@ -582,7 +582,8 @@ function bytesToHumanSize(bytes) {
|
||||
const round = bucket > 0 ? count < 3 ? 2 : count < 30 ? 1 : 0 : 0;
|
||||
return count.toFixed(round) + ' ' + sizes[bucket];
|
||||
}
|
||||
function stringHash(value) {
|
||||
|
||||
function stringToColorHash(value) {
|
||||
let hash = 0;
|
||||
value = '' + value;
|
||||
|
||||
@@ -594,6 +595,10 @@ function stringHash(value) {
|
||||
return hash;
|
||||
}
|
||||
|
||||
function idToColorClass(id, light, fg) {
|
||||
return (light ? 'lt-' : 'dk-') + (fg ? 'fg-' : 'bg-') + Math.abs(stringToColorHash(id)) % 16;
|
||||
}
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ "./src/lib/utils.js":
|
||||
@@ -1876,6 +1881,7 @@ class InfoView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component)
|
||||
owner: false,
|
||||
admin: false,
|
||||
sharer: false,
|
||||
deleter: false,
|
||||
muted: false,
|
||||
address: null,
|
||||
groupTopic: undefined,
|
||||
@@ -1899,6 +1905,7 @@ class InfoView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component)
|
||||
};
|
||||
this.resetSubs = this.resetSubs.bind(this);
|
||||
this.resetDesc = this.resetDesc.bind(this);
|
||||
this.resetTags = this.resetTags.bind(this);
|
||||
this.onMetaDesc = this.onMetaDesc.bind(this);
|
||||
this.onSubsUpdated = this.onSubsUpdated.bind(this);
|
||||
this.handleImageChanged = this.handleImageChanged.bind(this);
|
||||
@@ -1932,6 +1939,7 @@ class InfoView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component)
|
||||
});
|
||||
this.resetDesc(topic, props);
|
||||
this.resetSubs(topic, props);
|
||||
this.resetTags(topic);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1990,6 +1998,7 @@ class InfoView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component)
|
||||
owner: acs && acs.isOwner(),
|
||||
admin: acs && acs.isAdmin(),
|
||||
sharer: acs && acs.isSharer(),
|
||||
deleter: acs && acs.isDeleter(),
|
||||
muted: acs && acs.isMuted(),
|
||||
fullName: _clip(topic.public ? topic.public.fn : undefined, _config_js__WEBPACK_IMPORTED_MODULE_13__.MAX_TITLE_LENGTH),
|
||||
description: _clip(topic.public ? topic.public.note : undefined, _config_js__WEBPACK_IMPORTED_MODULE_13__.MAX_TOPIC_DESCRIPTION_LENGTH),
|
||||
@@ -2005,8 +2014,16 @@ class InfoView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component)
|
||||
auth: defacs.auth,
|
||||
anon: defacs.anon
|
||||
});
|
||||
}
|
||||
|
||||
if (topic.getType() == 'grp' && acs && acs.isOwner()) {
|
||||
resetTags(topic) {
|
||||
if (topic.getType() != 'grp') {
|
||||
return;
|
||||
}
|
||||
|
||||
const acs = topic.getAccessMode();
|
||||
|
||||
if (acs && acs.isOwner()) {
|
||||
topic.getMeta(topic.startMetaQuery().withTags().build());
|
||||
}
|
||||
}
|
||||
@@ -2054,17 +2071,15 @@ class InfoView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component)
|
||||
}
|
||||
|
||||
handlePermissionsChanged(which, perm) {
|
||||
console.log("handlePermissionsChanged", which, perm);
|
||||
|
||||
switch (which) {
|
||||
case 'auth':
|
||||
this.props.onTopicDescUpdate(this.props.topic, null, null, {
|
||||
this.props.onTopicDescUpdateRequest(this.props.topic, null, null, {
|
||||
auth: perm
|
||||
});
|
||||
break;
|
||||
|
||||
case 'anon':
|
||||
this.props.onTopicDescUpdate(this.props.topic, null, null, {
|
||||
this.props.onTopicDescUpdateRequest(this.props.topic, null, null, {
|
||||
anon: perm
|
||||
});
|
||||
break;
|
||||
@@ -2082,10 +2097,11 @@ class InfoView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component)
|
||||
this.props.onChangePermissions(this.props.topic, perm, this.state.userPermissionsEdited);
|
||||
break;
|
||||
}
|
||||
|
||||
this.handleBackNavigate();
|
||||
}
|
||||
|
||||
handleLaunchPermissionsEditor(which, uid) {
|
||||
console.log(which, uid);
|
||||
const {
|
||||
formatMessage
|
||||
} = this.props.intl;
|
||||
@@ -2161,7 +2177,7 @@ class InfoView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component)
|
||||
}
|
||||
|
||||
default:
|
||||
console.log("Unknown permission editing mode '" + which + "'");
|
||||
console.error("Unknown permission editing mode '" + which + "'");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2227,12 +2243,24 @@ class InfoView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component)
|
||||
return;
|
||||
}
|
||||
|
||||
const isMe = this.props.tinode.isMe(params.topicName);
|
||||
const menuItems = [{
|
||||
title: formatMessage(messages.edit_permissions),
|
||||
handler: () => {
|
||||
this.handleLaunchPermissionsEditor('user', params.topicName);
|
||||
this.handleLaunchPermissionsEditor(isMe ? 'want' : 'user', params.topicName);
|
||||
}
|
||||
}, 'member_delete', user.acs.isMuted() ? 'member_unmute' : 'member_mute', user.acs.isJoiner() ? 'member_block' : 'member_unblock'];
|
||||
}];
|
||||
|
||||
if (!isMe) {
|
||||
menuItems.push('member_delete');
|
||||
}
|
||||
|
||||
menuItems.push(user.acs.isMuted() ? 'member_unmute' : 'member_mute');
|
||||
|
||||
if (!isMe) {
|
||||
menuItems.push(user.acs.isJoiner() ? 'member_block' : 'member_unblock');
|
||||
}
|
||||
|
||||
this.props.showContextMenu({
|
||||
topicName: this.props.topic,
|
||||
x: params.x,
|
||||
@@ -2243,7 +2271,6 @@ class InfoView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component)
|
||||
|
||||
render() {
|
||||
const args = (this.props.panel || 'info').split('/');
|
||||
console.log("args:", args);
|
||||
const view = args[0];
|
||||
args.shift();
|
||||
const {
|
||||
@@ -2289,15 +2316,27 @@ class InfoView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component)
|
||||
tinode: this.props.tinode,
|
||||
topic: this.props.topic,
|
||||
onCredAdd: this.props.onCredAdd,
|
||||
onTopicTagsUpdate: this.props.onTopicTagsUpdate,
|
||||
onTopicTagsUpdateRequest: this.props.onTopicTagsUpdateRequest,
|
||||
onCredConfirm: this.props.onCredConfirm,
|
||||
onCredDelete: this.props.onCredDelete,
|
||||
onUpdateTopicDesc: this.props.onTopicDescUpdate,
|
||||
onUpdateTags: this.props.onUpdateTags,
|
||||
onUpdateTopicDesc: this.props.onTopicDescUpdateRequest,
|
||||
onError: this.props.onError
|
||||
}) : view == 'security' ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_topic_security_jsx__WEBPACK_IMPORTED_MODULE_12__.default, {
|
||||
tinode: this.props.tinode,
|
||||
topic: this.props.topic,
|
||||
owner: this.state.owner,
|
||||
admin: this.state.admin,
|
||||
sharer: this.state.sharer,
|
||||
deleter: this.state.deleter,
|
||||
muted: this.state.muted,
|
||||
groupTopic: this.state.groupTopic,
|
||||
channel: this.state.channel,
|
||||
access: this.state.access,
|
||||
modeGiven: this.state.modeGiven,
|
||||
modeWant: this.state.modeWant,
|
||||
modeGiven2: this.state.modeGiven2,
|
||||
modeWant2: this.state.modeWant2,
|
||||
auth: this.state.auth,
|
||||
anon: this.state.anon,
|
||||
onShowAlert: this.props.onShowAlert,
|
||||
onDeleteMessages: this.props.onDeleteMessages,
|
||||
onLeaveTopic: this.props.onLeaveTopic,
|
||||
@@ -2386,8 +2425,6 @@ class InfoView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component)
|
||||
})), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, this.state.description)) : null), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
||||
className: "hr"
|
||||
}), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
||||
className: "panel-form-column"
|
||||
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
||||
className: "panel-form-row"
|
||||
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, {
|
||||
id: "label_muting_topic",
|
||||
@@ -2399,10 +2436,10 @@ class InfoView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component)
|
||||
name: "P",
|
||||
checked: this.state.muted,
|
||||
onChange: this.handleMuted
|
||||
}))), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
||||
})), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
||||
className: "hr"
|
||||
}), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
||||
className: "panel-form-column"
|
||||
className: "panel-form-row"
|
||||
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", {
|
||||
href: "#",
|
||||
className: "flat-button",
|
||||
@@ -2421,8 +2458,6 @@ class InfoView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component)
|
||||
}))), this.state.groupTopic && this.state.sharer ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
||||
className: "hr"
|
||||
}), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
||||
className: "panel-form-column"
|
||||
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
||||
className: "panel-form-row"
|
||||
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", {
|
||||
className: "small"
|
||||
@@ -2464,7 +2499,7 @@ class InfoView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component)
|
||||
noScroll: true,
|
||||
onTopicSelected: this.handleMemberSelected,
|
||||
showContextMenu: this.state.admin ? this.handleContextMenu : false
|
||||
})))) : null));
|
||||
}))) : null));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2817,7 +2852,7 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
||||
this.handleScrollEvent = this.handleScrollEvent.bind(this);
|
||||
this.handleDescChange = this.handleDescChange.bind(this);
|
||||
this.handleSubsUpdated = this.handleSubsUpdated.bind(this);
|
||||
this.handleNewMessage = this.handleNewMessage.bind(this);
|
||||
this.handleMessageUpdate = this.handleMessageUpdate.bind(this);
|
||||
this.handleAllMessagesReceived = this.handleAllMessagesReceived.bind(this);
|
||||
this.handleInfoReceipt = this.handleInfoReceipt.bind(this);
|
||||
this.handleImagePostview = this.handleImagePostview.bind(this);
|
||||
@@ -2857,7 +2892,7 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
||||
|
||||
componentDidUpdate(prevProps, prevState) {
|
||||
if (this.messagesScroller) {
|
||||
if (prevState.topic != this.state.topic || prevState.messages.length != this.state.messages.length) {
|
||||
if (prevState.topic != this.state.topic || prevState.latestMsgSeq != this.state.latestMsgSeq) {
|
||||
this.messagesScroller.scrollTop = this.messagesScroller.scrollHeight - this.state.scrollPosition;
|
||||
} else if (prevProps.viewportHeight > this.props.viewportHeight) {
|
||||
this.messagesScroller.scrollTop += prevProps.viewportHeight - this.props.viewportHeight;
|
||||
@@ -2872,7 +2907,7 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
||||
}
|
||||
|
||||
if (topic) {
|
||||
topic.onData = this.handleNewMessage;
|
||||
topic.onData = this.handleMessageUpdate;
|
||||
topic.onAllMessagesReceived = this.handleAllMessagesReceived;
|
||||
topic.onInfo = this.handleInfoReceipt;
|
||||
topic.onMetaDesc = this.handleDescChange;
|
||||
@@ -2937,7 +2972,8 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
||||
|
||||
if (!nextProps.topic) {
|
||||
nextState = {
|
||||
messages: [],
|
||||
latestMsgSeq: -1,
|
||||
latestClearId: -1,
|
||||
onlineSubs: [],
|
||||
topic: null,
|
||||
title: '',
|
||||
@@ -2969,7 +3005,6 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
||||
};
|
||||
|
||||
if (topic) {
|
||||
const msgs = [];
|
||||
const subs = [];
|
||||
|
||||
if (nextProps.connected) {
|
||||
@@ -2980,13 +3015,7 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
||||
});
|
||||
}
|
||||
|
||||
topic.messages(function (msg) {
|
||||
if (!msg.deleted) {
|
||||
msgs.push(msg);
|
||||
}
|
||||
});
|
||||
Object.assign(nextState, {
|
||||
messages: msgs,
|
||||
onlineSubs: subs
|
||||
});
|
||||
|
||||
@@ -3015,11 +3044,14 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
||||
}
|
||||
|
||||
Object.assign(nextState, {
|
||||
latestMsgSeq: topic.maxMsgSeq(),
|
||||
latestClearId: topic.maxClearId(),
|
||||
channel: topic.isChannelType()
|
||||
});
|
||||
} else {
|
||||
Object.assign(nextState, {
|
||||
messages: [],
|
||||
latestMsgSeq: -1,
|
||||
latestClearId: -1,
|
||||
onlineSubs: [],
|
||||
title: '',
|
||||
avatar: null,
|
||||
@@ -3118,7 +3150,9 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
||||
|
||||
if (topic && topic.isSubscribed() && topic.msgHasMoreMessages()) {
|
||||
newState.fetchingMessages = true;
|
||||
topic.getMessagesPage(_config_js__WEBPACK_IMPORTED_MODULE_14__.MESSAGES_PAGE).catch(err => {
|
||||
topic.getMessagesPage(_config_js__WEBPACK_IMPORTED_MODULE_14__.MESSAGES_PAGE).then(() => this.setState({
|
||||
fetchingMessages: false
|
||||
})).catch(err => {
|
||||
this.setState({
|
||||
fetchingMessages: false
|
||||
});
|
||||
@@ -3243,20 +3277,24 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
||||
}
|
||||
}
|
||||
|
||||
handleNewMessage(msg) {
|
||||
handleMessageUpdate(msg) {
|
||||
const topic = this.props.tinode.getTopic(this.state.topic);
|
||||
const newState = {
|
||||
messages: []
|
||||
};
|
||||
topic.messages(m => {
|
||||
if (!m.deleted) {
|
||||
newState.messages.push(m);
|
||||
|
||||
if (!msg) {
|
||||
this.setState({
|
||||
latestClearId: topic.maxClearId()
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState({
|
||||
latestMsgSeq: topic.maxMsgSeq()
|
||||
});
|
||||
|
||||
if (msg && !msg.deleted) {
|
||||
if (topic.isNewMessage(msg.seq)) {
|
||||
newState.scrollPosition = 0;
|
||||
this.setState({
|
||||
scrollPosition: 0
|
||||
});
|
||||
}
|
||||
|
||||
const status = topic.msgStatus(msg, true);
|
||||
@@ -3268,9 +3306,6 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
||||
this.props.onData(msg);
|
||||
}
|
||||
|
||||
this.setState(newState);
|
||||
}
|
||||
|
||||
handleAllMessagesReceived(count) {
|
||||
this.setState({
|
||||
fetchingMessages: false
|
||||
@@ -3528,7 +3563,8 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
||||
}
|
||||
|
||||
handleCancelUpload(seq, uploader) {
|
||||
const found = this.state.messages.find(msg => msg.seq == seq);
|
||||
const topic = this.props.tinode.getTopic(this.state.topic);
|
||||
const found = topic.findMessage(seq);
|
||||
|
||||
if (found) {
|
||||
found._cancelled = true;
|
||||
@@ -3781,15 +3817,8 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
||||
let messageNodes = [];
|
||||
let previousFrom = null;
|
||||
let chatBoxClass = null;
|
||||
|
||||
for (let i = 0; i < this.state.messages.length; i++) {
|
||||
let msg = this.state.messages[i];
|
||||
let nextFrom = null;
|
||||
|
||||
if (i + 1 < this.state.messages.length) {
|
||||
nextFrom = this.state.messages[i + 1].from || 'chan';
|
||||
}
|
||||
|
||||
topic.messages((msg, prev, next, i) => {
|
||||
let nextFrom = next ? next.from || null : 'chan';
|
||||
let sequence = 'single';
|
||||
let thisFrom = msg.from || 'chan';
|
||||
|
||||
@@ -3848,8 +3877,7 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
||||
onFormatQuote: quoteFormatter,
|
||||
key: msg.seq
|
||||
}));
|
||||
}
|
||||
|
||||
});
|
||||
let lastSeen = null;
|
||||
|
||||
if (isChannel) {
|
||||
@@ -4974,7 +5002,7 @@ class TinodeWeb extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component)
|
||||
this.handleNewTopicCreated = this.handleNewTopicCreated.bind(this);
|
||||
this.handleTopicUpdateRequest = this.handleTopicUpdateRequest.bind(this);
|
||||
this.handleChangePermissions = this.handleChangePermissions.bind(this);
|
||||
this.handleTagsUpdated = this.handleTagsUpdated.bind(this);
|
||||
this.handleTagsUpdateRequest = this.handleTagsUpdateRequest.bind(this);
|
||||
this.handleLogout = this.handleLogout.bind(this);
|
||||
this.handleDeleteAccount = this.handleDeleteAccount.bind(this);
|
||||
this.handleDeleteTopicRequest = this.handleDeleteTopicRequest.bind(this);
|
||||
@@ -5062,7 +5090,7 @@ class TinodeWeb extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component)
|
||||
const serviceWorkerChannel = new BroadcastChannel('tinode-sw');
|
||||
serviceWorkerChannel.addEventListener('message', this.handlePushMessage);
|
||||
} else {
|
||||
console.warn('Your browser does not support BroadcastChannel. Some features will not be available');
|
||||
console.warn("Your browser does not support BroadcastChannel. Some features will not be available");
|
||||
}
|
||||
|
||||
document.addEventListener('visibilitychange', this.handleVisibilityEvent);
|
||||
@@ -5421,9 +5449,10 @@ class TinodeWeb extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component)
|
||||
|
||||
cred = tinode_sdk__WEBPACK_IMPORTED_MODULE_4___default().credential(cred);
|
||||
let promise = null;
|
||||
const token = this.tinode.getAuthToken();
|
||||
let token = this.tinode.getAuthToken();
|
||||
|
||||
if (login && password) {
|
||||
token = null;
|
||||
this.setState({
|
||||
password: null
|
||||
});
|
||||
@@ -5456,7 +5485,11 @@ class TinodeWeb extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component)
|
||||
autoLogin: false
|
||||
});
|
||||
this.handleError(err.message, 'err');
|
||||
localStorage.removeItem('auth-token');
|
||||
|
||||
if (token) {
|
||||
this.handleLogout();
|
||||
}
|
||||
|
||||
_lib_navigation_js__WEBPACK_IMPORTED_MODULE_15__.default.navigateTo('');
|
||||
});
|
||||
} else {
|
||||
@@ -6179,7 +6212,7 @@ class TinodeWeb extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component)
|
||||
}
|
||||
}
|
||||
|
||||
handleTagsUpdated(topicName, tags) {
|
||||
handleTagsUpdateRequest(topicName, tags) {
|
||||
const topic = this.tinode.getTopic(topicName);
|
||||
|
||||
if (topic) {
|
||||
@@ -6592,7 +6625,7 @@ class TinodeWeb extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component)
|
||||
errorAction: this.state.errorAction,
|
||||
errorActionText: this.state.errorActionText,
|
||||
onNavigate: this.infoNavigator,
|
||||
onTopicDescUpdate: this.handleTopicUpdateRequest,
|
||||
onTopicDescUpdateRequest: this.handleTopicUpdateRequest,
|
||||
onShowAlert: this.handleShowAlert,
|
||||
onChangePermissions: this.handleChangePermissions,
|
||||
onMemberUpdateRequest: this.handleMemberUpdateRequest,
|
||||
@@ -6602,7 +6635,7 @@ class TinodeWeb extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component)
|
||||
onBlockTopic: this.handleBlockTopicRequest,
|
||||
onReportTopic: this.handleReportTopic,
|
||||
onAddMember: this.handleManageGroupMembers,
|
||||
onTopicTagsUpdate: this.handleTagsUpdated,
|
||||
onTopicTagsUpdateRequest: this.handleTagsUpdateRequest,
|
||||
onInitFind: this.tnInitFind,
|
||||
onError: this.handleError,
|
||||
showContextMenu: this.handleShowContextMenu
|
||||
@@ -7445,15 +7478,13 @@ class ChatMessage extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComp
|
||||
className: "material-icons"
|
||||
}, "expand_more")))), fullDisplay ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
||||
className: "author"
|
||||
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, {
|
||||
}, this.props.userName || react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, {
|
||||
id: "user_not_found",
|
||||
defaultMessage: [{
|
||||
"type": 0,
|
||||
"value": "Not found"
|
||||
}]
|
||||
}, notFound => {
|
||||
return this.props.userName || react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", null, notFound);
|
||||
})) : null));
|
||||
}))) : null));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -10149,7 +10180,7 @@ class LetterTile extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureCompo
|
||||
|
||||
if (this.props.avatar === true) {
|
||||
const isGroup = tinode_sdk__WEBPACK_IMPORTED_MODULE_1___default().topicType(this.props.topic) == 'grp';
|
||||
const iconColor = (isGroup ? 'light-color' : 'dark-color') + Math.abs((0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_2__.stringHash)(this.props.topic)) % 16;
|
||||
const iconColor = (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_2__.idToColorClass)(this.props.topic, isGroup);
|
||||
|
||||
if (this.props.topic && this.props.title && this.props.title.trim()) {
|
||||
const letter = this.props.title.trim().charAt(0);
|
||||
@@ -11722,9 +11753,9 @@ class TopicCommon extends (react__WEBPACK_IMPORTED_MODULE_0___default().Componen
|
||||
addCredActive: false,
|
||||
addCredInvalid: false,
|
||||
newCred: '',
|
||||
tags: [],
|
||||
previousTagsUpdated: undefined
|
||||
tags: []
|
||||
};
|
||||
this.previousTagsUpdated = undefined;
|
||||
this.onTagsUpdated = this.onTagsUpdated.bind(this);
|
||||
this.handleTagsUpdated = this.handleTagsUpdated.bind(this);
|
||||
this.tnCredsUpdated = this.tnCredsUpdated.bind(this);
|
||||
@@ -11831,13 +11862,13 @@ class TopicCommon extends (react__WEBPACK_IMPORTED_MODULE_0___default().Componen
|
||||
});
|
||||
|
||||
if (this.previousTagsUpdated && this.previousTagsUpdated != this.onTagsUpdated) {
|
||||
this.previousTagsUpdated();
|
||||
this.previousTagsUpdated(tags);
|
||||
}
|
||||
}
|
||||
|
||||
handleTagsUpdated(tags) {
|
||||
if (!(0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_4__.arrayEqual)(this.state.tags.slice(0), tags.slice(0))) {
|
||||
this.props.onTopicTagsUpdate(this.props.topic, tags);
|
||||
this.props.onTopicTagsUpdateRequest(this.props.topic, tags);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11878,7 +11909,7 @@ class TopicCommon extends (react__WEBPACK_IMPORTED_MODULE_0___default().Componen
|
||||
tinode: this.props.tinode,
|
||||
topic: this.props.topic,
|
||||
onUpdateTopicDesc: this.props.onUpdateTopicDesc,
|
||||
onUpdateTags: this.props.onUpdateTags,
|
||||
onUpdateTags: this.handleTagsUpdated,
|
||||
onError: this.props.onError
|
||||
}), this.state.isMe ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
||||
className: "hr"
|
||||
@@ -11973,11 +12004,11 @@ class TopicDescEdit extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compon
|
||||
private: topic.private ? topic.private.comment : null,
|
||||
description: topic.public ? topic.public.note : undefined,
|
||||
avatar: (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_8__.makeImageUrl)(topic.public ? topic.public.photo : null),
|
||||
tags: topic.tags(),
|
||||
tags: topic.tags() || [],
|
||||
newAvatar: null,
|
||||
newAvatarMime: null,
|
||||
previousOnTags: topic.onTagsUpdated
|
||||
newAvatarMime: null
|
||||
};
|
||||
this.previousOnTags = null;
|
||||
this.tnNewTags = this.tnNewTags.bind(this);
|
||||
this.handleFullNameUpdate = this.handleFullNameUpdate.bind(this);
|
||||
this.handleImageUpdated = this.handleImageUpdated.bind(this);
|
||||
@@ -11991,12 +12022,13 @@ class TopicDescEdit extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compon
|
||||
|
||||
componentDidMount() {
|
||||
const topic = this.props.tinode.getTopic(this.props.topic);
|
||||
this.previousOnTags = topic.onTagsUpdated;
|
||||
topic.onTagsUpdated = this.tnNewTags;
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
const topic = this.props.tinode.getTopic(this.props.topic);
|
||||
topic.onTagsUpdated = this.state.previousOnTags;
|
||||
topic.onTagsUpdated = this.previousOnTags;
|
||||
}
|
||||
|
||||
tnNewTags(tags) {
|
||||
@@ -12359,45 +12391,9 @@ const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({
|
||||
}
|
||||
});
|
||||
|
||||
class TopicSecurity extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) {
|
||||
class TopicSecurity extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
const topic = this.props.tinode.getTopic(this.props.topic);
|
||||
|
||||
if (!topic) {
|
||||
return;
|
||||
}
|
||||
|
||||
const defacs = topic.getDefaultAccess() || {};
|
||||
const acs = topic.getAccessMode();
|
||||
let modeGiven2 = _config_js__WEBPACK_IMPORTED_MODULE_3__.NO_ACCESS_MODE;
|
||||
let modeWant2 = _config_js__WEBPACK_IMPORTED_MODULE_3__.NO_ACCESS_MODE;
|
||||
|
||||
if (topic.getType() == 'p2p') {
|
||||
const user2 = topic.subscriber(props.topic);
|
||||
|
||||
if (user2 && user2.acs) {
|
||||
modeGiven2 = user2.acs.getGiven();
|
||||
modeWant2 = user2.acs.getWant();
|
||||
}
|
||||
}
|
||||
|
||||
this.state = {
|
||||
owner: acs && acs.isOwner(),
|
||||
admin: acs && acs.isAdmin(),
|
||||
sharer: acs && acs.isSharer(),
|
||||
deleter: acs && acs.isDeleter(),
|
||||
muted: acs && acs.isMuted(),
|
||||
groupTopic: topic.isGroupType(),
|
||||
channel: topic.isChannelType(),
|
||||
access: acs ? acs.getMode() : undefined,
|
||||
modeGiven: acs ? acs.getGiven() : undefined,
|
||||
modeWant: acs ? acs.getWant() : undefined,
|
||||
modeGiven2: modeGiven2,
|
||||
modeWant2: modeWant2,
|
||||
auth: defacs ? defacs.auth : null,
|
||||
anon: defacs ? defacs.anon : null
|
||||
};
|
||||
this.handleDeleteTopic = this.handleDeleteTopic.bind(this);
|
||||
this.handleDeleteMessages = this.handleDeleteMessages.bind(this);
|
||||
this.handleLeave = this.handleLeave.bind(this);
|
||||
@@ -12420,7 +12416,7 @@ class TopicSecurity extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compon
|
||||
const {
|
||||
formatMessage
|
||||
} = this.props.intl;
|
||||
this.props.onShowAlert(formatMessage(this.state.deleter ? messages.delete_messages : messages.clear_messages), formatMessage(this.state.deleter ? messages.delete_messages_warning : messages.clear_messages_warning), () => {
|
||||
this.props.onShowAlert(formatMessage(this.props.deleter ? messages.delete_messages : messages.clear_messages), formatMessage(this.props.deleter ? messages.delete_messages_warning : messages.clear_messages_warning), () => {
|
||||
this.props.onDeleteMessages(this.props.topic);
|
||||
}, null, true, null);
|
||||
}
|
||||
@@ -12463,13 +12459,13 @@ class TopicSecurity extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compon
|
||||
className: "scrollable-panel"
|
||||
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
||||
className: "panel-form-column"
|
||||
}, !this.state.channel ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", {
|
||||
}, !this.props.channel ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", {
|
||||
href: "#",
|
||||
className: "flat-button",
|
||||
onClick: this.handleDeleteMessages
|
||||
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", {
|
||||
className: "material-icons"
|
||||
}, "delete_outline"), " \xA0", formatMessage(this.state.deleter ? messages.delete_messages : messages.clear_messages)) : null, this.state.owner ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", {
|
||||
}, "delete_outline"), " \xA0", formatMessage(this.props.deleter ? messages.delete_messages : messages.clear_messages)) : null, this.props.owner ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", {
|
||||
href: "#",
|
||||
className: "danger flat-button",
|
||||
onClick: this.handleDeleteTopic
|
||||
@@ -12481,13 +12477,13 @@ class TopicSecurity extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compon
|
||||
onClick: this.handleLeave
|
||||
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", {
|
||||
className: "material-icons"
|
||||
}, "exit_to_app"), " \xA0", formatMessage(messages.leave_chat)), !this.state.groupTopic ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", {
|
||||
}, "exit_to_app"), " \xA0", formatMessage(messages.leave_chat)), !this.props.groupTopic ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", {
|
||||
href: "#",
|
||||
className: "danger flat-button",
|
||||
onClick: this.handleBlock
|
||||
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", {
|
||||
className: "material-icons"
|
||||
}, "block"), " \xA0", formatMessage(messages.block_contact)) : null, !this.state.owner ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", {
|
||||
}, "block"), " \xA0", formatMessage(messages.block_contact)) : null, !this.props.owner ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", {
|
||||
href: "#",
|
||||
className: "danger flat-button",
|
||||
onClick: this.handleReport
|
||||
@@ -12497,7 +12493,7 @@ class TopicSecurity extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compon
|
||||
className: "hr"
|
||||
}), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
||||
className: "panel-form-column"
|
||||
}, this.state.groupTopic ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
||||
}, this.props.groupTopic ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
||||
className: "group"
|
||||
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, {
|
||||
id: "label_your_permissions",
|
||||
@@ -12511,7 +12507,7 @@ class TopicSecurity extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compon
|
||||
e.preventDefault();
|
||||
this.props.onLaunchPermissionsEditor('want');
|
||||
}
|
||||
}, this.state.access)), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
||||
}, this.props.access)), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
||||
className: "group"
|
||||
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", {
|
||||
className: "small"
|
||||
@@ -12529,13 +12525,13 @@ class TopicSecurity extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compon
|
||||
e.preventDefault();
|
||||
this.props.onLaunchPermissionsEditor('auth');
|
||||
}
|
||||
}, this.state.auth)), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, "Anon: ", react__WEBPACK_IMPORTED_MODULE_0___default().createElement("tt", {
|
||||
}, this.props.auth)), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, "Anon: ", react__WEBPACK_IMPORTED_MODULE_0___default().createElement("tt", {
|
||||
className: "clickable",
|
||||
onClick: e => {
|
||||
e.preventDefault();
|
||||
this.props.onLaunchPermissionsEditor('anon');
|
||||
}
|
||||
}, this.state.anon))))) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
||||
}, this.props.anon))))) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
||||
className: "group"
|
||||
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("label", {
|
||||
className: "small"
|
||||
@@ -12559,13 +12555,13 @@ class TopicSecurity extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compon
|
||||
e.preventDefault();
|
||||
this.props.onLaunchPermissionsEditor('want');
|
||||
}
|
||||
}, this.state.access)), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, this.state.fullName ? this.state.fullName : formatMessage(messages.other_user), ": \xA0", react__WEBPACK_IMPORTED_MODULE_0___default().createElement("tt", {
|
||||
}, this.props.access)), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", null, this.props.fullName ? this.props.fullName : formatMessage(messages.other_user), ": \xA0", react__WEBPACK_IMPORTED_MODULE_0___default().createElement("tt", {
|
||||
className: "clickable",
|
||||
onClick: e => {
|
||||
e.preventDefault();
|
||||
this.props.onLaunchPermissionsEditor('given');
|
||||
}
|
||||
}, this.state.modeGiven2))))));
|
||||
}, this.props.modeGiven2))))));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+320
-400
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user