ability to hard-delete p2p messages, debugged pinned messages
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -1671,5 +1671,19 @@
|
||||
"translation": "",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"message_not_found": {
|
||||
"translation": "",
|
||||
"defaultMessage": "message not found",
|
||||
"description": "Pinned message is not found",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"message_deleted": {
|
||||
"translation": "",
|
||||
"defaultMessage": "message deleted",
|
||||
"description": "Pinned message is deleted",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1671,5 +1671,19 @@
|
||||
"translation": "Saved messages",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
"message_not_found": {
|
||||
"translation": "message not found",
|
||||
"defaultMessage": "message not found",
|
||||
"description": "Pinned message is not found",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
"message_deleted": {
|
||||
"translation": "message deleted",
|
||||
"defaultMessage": "message deleted",
|
||||
"description": "Pinned message is deleted",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1671,5 +1671,19 @@
|
||||
"translation": "",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"message_not_found": {
|
||||
"translation": "",
|
||||
"defaultMessage": "message not found",
|
||||
"description": "Pinned message is not found",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"message_deleted": {
|
||||
"translation": "",
|
||||
"defaultMessage": "message deleted",
|
||||
"description": "Pinned message is deleted",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -604,10 +604,18 @@
|
||||
"defaultMessage": "Video call",
|
||||
"description": "Start video call"
|
||||
},
|
||||
"message_deleted": {
|
||||
"defaultMessage": "message deleted",
|
||||
"description": "Pinned message is deleted"
|
||||
},
|
||||
"message_edited_marker": {
|
||||
"defaultMessage": ", edited",
|
||||
"description": "Marker indicating that the message was edited"
|
||||
},
|
||||
"message_not_found": {
|
||||
"defaultMessage": "message not found",
|
||||
"description": "Pinned message is not found"
|
||||
},
|
||||
"message_sending": {
|
||||
"defaultMessage": "sending...",
|
||||
"description": "Message being sent, in place of time stamp"
|
||||
|
||||
@@ -1671,5 +1671,19 @@
|
||||
"translation": "",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"message_not_found": {
|
||||
"translation": "",
|
||||
"defaultMessage": "message not found",
|
||||
"description": "Pinned message is not found",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"message_deleted": {
|
||||
"translation": "",
|
||||
"defaultMessage": "message deleted",
|
||||
"description": "Pinned message is deleted",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1671,5 +1671,19 @@
|
||||
"translation": "",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"message_not_found": {
|
||||
"translation": "",
|
||||
"defaultMessage": "message not found",
|
||||
"description": "Pinned message is not found",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"message_deleted": {
|
||||
"translation": "",
|
||||
"defaultMessage": "message deleted",
|
||||
"description": "Pinned message is deleted",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1671,5 +1671,19 @@
|
||||
"translation": "",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"message_not_found": {
|
||||
"translation": "",
|
||||
"defaultMessage": "message not found",
|
||||
"description": "Pinned message is not found",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"message_deleted": {
|
||||
"translation": "",
|
||||
"defaultMessage": "message deleted",
|
||||
"description": "Pinned message is deleted",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1671,5 +1671,19 @@
|
||||
"translation": "",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"message_not_found": {
|
||||
"translation": "",
|
||||
"defaultMessage": "message not found",
|
||||
"description": "Pinned message is not found",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"message_deleted": {
|
||||
"translation": "",
|
||||
"defaultMessage": "message deleted",
|
||||
"description": "Pinned message is deleted",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1671,5 +1671,19 @@
|
||||
"translation": "",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"message_not_found": {
|
||||
"translation": "",
|
||||
"defaultMessage": "message not found",
|
||||
"description": "Pinned message is not found",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"message_deleted": {
|
||||
"translation": "",
|
||||
"defaultMessage": "message deleted",
|
||||
"description": "Pinned message is deleted",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1671,5 +1671,19 @@
|
||||
"translation": "",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"message_not_found": {
|
||||
"translation": "",
|
||||
"defaultMessage": "message not found",
|
||||
"description": "Pinned message is not found",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"message_deleted": {
|
||||
"translation": "",
|
||||
"defaultMessage": "message deleted",
|
||||
"description": "Pinned message is deleted",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1671,5 +1671,19 @@
|
||||
"translation": "",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"message_not_found": {
|
||||
"translation": "",
|
||||
"defaultMessage": "message not found",
|
||||
"description": "Pinned message is not found",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"message_deleted": {
|
||||
"translation": "",
|
||||
"defaultMessage": "message deleted",
|
||||
"description": "Pinned message is deleted",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1671,5 +1671,19 @@
|
||||
"translation": "",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"message_not_found": {
|
||||
"translation": "",
|
||||
"defaultMessage": "message not found",
|
||||
"description": "Pinned message is not found",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"message_deleted": {
|
||||
"translation": "",
|
||||
"defaultMessage": "message deleted",
|
||||
"description": "Pinned message is deleted",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
}
|
||||
}
|
||||
|
||||
+58
-19
@@ -327,6 +327,7 @@ class MessagesView extends React.Component {
|
||||
showGoToLastButton: false,
|
||||
dragging: false,
|
||||
pins: [],
|
||||
pinsLoaded: false,
|
||||
selectedPin: 0,
|
||||
subsVersion: 0
|
||||
};
|
||||
@@ -411,7 +412,8 @@ class MessagesView extends React.Component {
|
||||
maxSeqId: topic.maxMsgSeq(),
|
||||
latestClearId: topic.maxClearId(),
|
||||
channel: topic.isChannelType(),
|
||||
pins: (topic.aux('pins') || []).slice()
|
||||
pins: (topic.aux('pins') || []).slice(),
|
||||
pinsLoaded: false
|
||||
});
|
||||
|
||||
if (nextProps.callTopic == topic.name && shouldPresentCallPanel(nextProps.callState)) {
|
||||
@@ -428,7 +430,8 @@ class MessagesView extends React.Component {
|
||||
avatar: null,
|
||||
peerMessagingDisabled: false,
|
||||
channel: false,
|
||||
pins: []
|
||||
pins: [],
|
||||
pinsLoaded: false
|
||||
});
|
||||
}
|
||||
} else {
|
||||
@@ -798,8 +801,16 @@ class MessagesView extends React.Component {
|
||||
}
|
||||
|
||||
// Load pinned message too (if any);
|
||||
const topic = this.props.tinode.getTopic(this.state.topic);
|
||||
topic.getPinnedMessages();
|
||||
if (!this.state.pinsLoaded) {
|
||||
// This needs to be guarded to avoid an infinite loop.
|
||||
// The loop may happen if some pinned messages are deleted.
|
||||
const topic = this.props.tinode.getTopic(this.state.topic);
|
||||
this.setState({pinsLoaded: true}, _ => {
|
||||
topic.getPinnedMessages();
|
||||
});
|
||||
} else {
|
||||
this.setState({pinsLoaded: false});
|
||||
}
|
||||
}
|
||||
|
||||
handleAuxUpdate(aux) {
|
||||
@@ -896,12 +907,35 @@ class MessagesView extends React.Component {
|
||||
const menuItems = messageSpecificMenuItems || [];
|
||||
const topic = this.props.tinode.getTopic(params.topicName);
|
||||
if (topic) {
|
||||
if (!topic.isChannelType()) {
|
||||
menuItems.push('message_delete');
|
||||
}
|
||||
const acs = topic.getAccessMode();
|
||||
if (acs && acs.isDeleter()) {
|
||||
menuItems.push('message_delete_hard');
|
||||
// Self -> (1) always hard-delete with [Delete] title.
|
||||
// P2P -> (1) hard-delete if allowed and not too old, (2) always soft-delete.
|
||||
// Group -> (1) hard-delete if allowed and not too old or owner, (2) always soft-delete.
|
||||
if (topic.isSelfType()) {
|
||||
// Hard-delete with plain [Delete] title.
|
||||
menuItems.push('message_delete_generic');
|
||||
} else {
|
||||
if (!topic.isChannelType()) {
|
||||
// P2P or normal group: always allow to soft-delete.
|
||||
menuItems.push('message_delete');
|
||||
}
|
||||
|
||||
const acs = topic.getAccessMode();
|
||||
if (acs && acs.isDeleter()) {
|
||||
// Owner can always hard-delete regardless of age.
|
||||
let canDelete = acs.isOwner();
|
||||
if (!canDelete) {
|
||||
// Not owner: check message age if configured on the server.
|
||||
const maxAge = this.props.tinode.getServerParam(Tinode.MSG_DELETE_AGE, 0) | 0;
|
||||
if (maxAge > 0 && params.timestamp) {
|
||||
// Make sure the message is not too old.
|
||||
canDelete = params.timestamp.getTime() > (new Date().getTime() - maxAge * 1000);
|
||||
}
|
||||
}
|
||||
if (canDelete) {
|
||||
// [Delete for All] title.
|
||||
menuItems.push('message_delete_hard');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.props.showContextMenu(params, menuItems);
|
||||
@@ -1700,9 +1734,10 @@ class MessagesView extends React.Component {
|
||||
<div id="topic-last-seen">{lastSeen}</div>
|
||||
</div>
|
||||
<div style={{marginLeft: 'auto'}}/>
|
||||
{!this.props.displayMobile ?
|
||||
{!this.props.displayMobile && this.state.pins.length > 0 ?
|
||||
<PinnedMessages
|
||||
tinode={this.props.tinode}
|
||||
pins={this.state.pins}
|
||||
messages={pinnedMessages}
|
||||
selected={this.state.selectedPin}
|
||||
isAdmin={this.state.isAdmin}
|
||||
@@ -1724,14 +1759,18 @@ class MessagesView extends React.Component {
|
||||
</div>
|
||||
{this.props.displayMobile ?
|
||||
<>
|
||||
<PinnedMessages
|
||||
tinode={this.props.tinode}
|
||||
messages={pinnedMessages}
|
||||
selected={this.state.selectedPin}
|
||||
isAdmin={this.state.isAdmin}
|
||||
setSelected={index => this.setState({selectedPin: index})}
|
||||
onSelected={this.handleQuoteClick}
|
||||
onCancel={this.handleUnpinMessage} />
|
||||
{this.state.pins.length > 0 ?
|
||||
<PinnedMessages
|
||||
tinode={this.props.tinode}
|
||||
pins={this.state.pins}
|
||||
messages={pinnedMessages}
|
||||
selected={this.state.selectedPin}
|
||||
isAdmin={this.state.isAdmin}
|
||||
setSelected={index => this.setState({selectedPin: index})}
|
||||
onSelected={this.handleQuoteClick}
|
||||
onCancel={this.handleUnpinMessage} />
|
||||
: null
|
||||
}
|
||||
<ErrorPanel
|
||||
level={this.props.errorLevel}
|
||||
text={this.props.errorText}
|
||||
|
||||
@@ -129,6 +129,7 @@ class BaseChatMessage extends React.PureComponent {
|
||||
x: e.pageX,
|
||||
pickReply: this.props.pickReply,
|
||||
editMessage: this.props.editMessage,
|
||||
timestamp: this.props.timestamp,
|
||||
}, menuItems);
|
||||
}
|
||||
|
||||
|
||||
@@ -76,7 +76,6 @@ class ContactList extends React.Component {
|
||||
filterOn.push(('' + c.public.fn).toLowerCase());
|
||||
}
|
||||
if (!this.props.filterFunc(this.props.filter, filterOn)) {
|
||||
console.log('Filtered:', key);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,6 +189,14 @@ class ContextMenu extends React.Component {
|
||||
return this.deleteMessages(false, true, params, errorHandler);
|
||||
}
|
||||
},
|
||||
// Hard-delete but with just 'Delete' title.
|
||||
'message_delete_generic': {
|
||||
id: 'message_delete_generic',
|
||||
title: formatMessage(messages.delete),
|
||||
handler: (params, errorHandler) => {
|
||||
return this.deleteMessages(false, true, params, errorHandler);
|
||||
}
|
||||
},
|
||||
'menu_item_send_retry': {
|
||||
id: 'menu_item_send_retry',
|
||||
title: formatMessage(messages.send_retry),
|
||||
|
||||
@@ -1,20 +1,34 @@
|
||||
// Send message form.
|
||||
import React from 'react';
|
||||
import { injectIntl } from 'react-intl';
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import { Drafty } from 'tinode-sdk';
|
||||
|
||||
import { previewFormatter } from '../lib/formatters.js';
|
||||
import { MIN_SWIPE_DISTANCE } from '../config.js';
|
||||
|
||||
const messages = defineMessages({
|
||||
message_not_found: {
|
||||
id: 'message_not_found',
|
||||
defaultMessage: 'message not found',
|
||||
description: 'Pinned message is not found'
|
||||
},
|
||||
message_deleted: {
|
||||
id: 'message_deleted',
|
||||
defaultMessage: 'message deleted',
|
||||
description: 'Pinned message is deleted'
|
||||
}
|
||||
});
|
||||
|
||||
class PinnedMessages extends React.PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.touchSurface = React.createRef();
|
||||
// Starting location of the touch gesture.
|
||||
this.touchX = null;
|
||||
this.touchY = null;
|
||||
|
||||
this.touchSurface = React.createRef();
|
||||
|
||||
this.getSelectedIndex = this.getSelectedIndex.bind(this);
|
||||
this.handleCancel = this.handleCancel.bind(this);
|
||||
this.handleSelected = this.handleSelected.bind(this);
|
||||
@@ -26,34 +40,29 @@ class PinnedMessages extends React.PureComponent {
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
if (this.touchSurface.current) {
|
||||
this.touchSurface.current.addEventListener('touchstart', this.handleTouchEventStart, {passive: true});
|
||||
this.touchSurface.current.addEventListener('touchend', this.handleTouchEventEnd, {passive: true});
|
||||
this.touchSurface.current.addEventListener('touchcancel', this.handleTouchCancel, {passive: true});
|
||||
}
|
||||
this.touchSurface.current.addEventListener('touchstart', this.handleTouchEventStart, {passive: true});
|
||||
this.touchSurface.current.addEventListener('touchend', this.handleTouchEventEnd, {passive: true});
|
||||
this.touchSurface.current.addEventListener('touchcancel', this.handleTouchCancel, {passive: true});
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.touchSurface.current) {
|
||||
this.touchSurface.current.removeEventListener('touchstart', this.handleTouchEventStart);
|
||||
this.touchSurface.current.removeEventListener('touchend', this.handleTouchEventEnd);
|
||||
this.touchSurface.current.removeEventListener('touchcancel', this.handleTouchCancel);
|
||||
}
|
||||
this.touchSurface.current.removeEventListener('touchstart', this.handleTouchEventStart);
|
||||
this.touchSurface.current.removeEventListener('touchend', this.handleTouchEventEnd);
|
||||
this.touchSurface.current.removeEventListener('touchcancel', this.handleTouchCancel);
|
||||
}
|
||||
|
||||
getSelectedIndex() {
|
||||
const list = (this.props.messages || []);
|
||||
const list = (this.props.pins || []);
|
||||
return list.length - this.props.selected - 1;
|
||||
}
|
||||
|
||||
handleCancel(e) {
|
||||
e.preventDefault();
|
||||
this.props.onCancel(this.props.messages[this.getSelectedIndex()].seq);
|
||||
this.props.onCancel(this.props.pins[this.getSelectedIndex()]);
|
||||
}
|
||||
|
||||
handleSelected(e) {
|
||||
e.preventDefault();
|
||||
this.props.onSelected(this.props.messages[this.getSelectedIndex()].seq);
|
||||
this.props.onSelected(this.props.pins[this.getSelectedIndex()]);
|
||||
}
|
||||
|
||||
handleMoveNext(e, isTouch) {
|
||||
@@ -70,7 +79,7 @@ class PinnedMessages extends React.PureComponent {
|
||||
// Don't call preventDefault for touch events.
|
||||
isTouch || e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const idx = Math.min(this.props.selected + 1, (this.props.messages || []).length - 1);
|
||||
const idx = Math.min(this.props.selected + 1, (this.props.pins || []).length - 1);
|
||||
if (idx != this.props.selected) {
|
||||
this.props.setSelected(idx);
|
||||
}
|
||||
@@ -105,26 +114,32 @@ class PinnedMessages extends React.PureComponent {
|
||||
}
|
||||
}
|
||||
|
||||
handleTouchCancel(e) {
|
||||
handleTouchCancel() {
|
||||
this.touchX = null;
|
||||
}
|
||||
|
||||
render() {
|
||||
const selected = this.getSelectedIndex();
|
||||
let shown = (this.props.messages || [])[selected];
|
||||
shown = shown ? Drafty.format(shown.content, previewFormatter, {
|
||||
formatMessage: this.props.intl.formatMessage.bind(this.props.intl),
|
||||
authorizeURL: this.props.tinode.authorizeURL.bind(this.props.tinode)
|
||||
}) : null;
|
||||
let messageShown = (this.props.messages || [])[selected];
|
||||
messageShown = messageShown ?
|
||||
messageShown._deleted ?
|
||||
<i className="gray">{this.props.intl.formatMessage(messages.message_deleted)}</i>
|
||||
:
|
||||
Drafty.format(messageShown.content, previewFormatter, {
|
||||
formatMessage: this.props.intl.formatMessage.bind(this.props.intl),
|
||||
authorizeURL: this.props.tinode.authorizeURL.bind(this.props.tinode)
|
||||
})
|
||||
:
|
||||
<i className="gray">{this.props.intl.formatMessage(messages.message_not_found)}</i>;
|
||||
|
||||
const dots = [];
|
||||
this.props.messages.forEach(_ => {
|
||||
this.props.pins.forEach(seq => {
|
||||
const cn = dots.length == selected ? 'adot' : 'dot';
|
||||
dots.push(<div key={dots.length} className={cn} />);
|
||||
dots.push(<div key={seq} className={cn} />);
|
||||
});
|
||||
|
||||
return shown ?
|
||||
(<div id="pinned-wrapper" ref={this.touchSurface}>
|
||||
return (
|
||||
<div id="pinned-wrapper" ref={this.touchSurface}>
|
||||
{this.props.isAdmin ?
|
||||
<div className="cancel">
|
||||
<a href="#" onClick={this.handleCancel}><i className="material-icons gray">close</i></a>
|
||||
@@ -132,7 +147,7 @@ class PinnedMessages extends React.PureComponent {
|
||||
<div><i className="material-icons gray">push_pin</i></div>
|
||||
}
|
||||
<div className="pinned-scroll">{dots}</div>
|
||||
<div className="pinned" onClick={this.handleSelected}><p>{shown}</p></div>
|
||||
<div className="pinned" onClick={this.handleSelected}><p>{messageShown}</p></div>
|
||||
<div className="pinned-menu">
|
||||
<span className="menuTrigger upper">
|
||||
{selected > 0 ?
|
||||
@@ -151,7 +166,8 @@ class PinnedMessages extends React.PureComponent {
|
||||
}
|
||||
</span>
|
||||
</div>
|
||||
</div>) : null;
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@ import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import ChipInput from './chip-input.jsx';
|
||||
|
||||
import { Tinode } from 'tinode-sdk';
|
||||
|
||||
import { MAX_TAG_COUNT, MAX_TAG_LENGTH, MIN_TAG_LENGTH } from '../config.js';
|
||||
import { arrayEqual } from '../lib/utils.js';
|
||||
|
||||
@@ -49,7 +51,7 @@ export default class TagManager extends React.Component {
|
||||
}
|
||||
|
||||
handleAddTag(tag) {
|
||||
const maxTagCount = this.props.tinode.getServerParam('maxTagCount', MAX_TAG_COUNT);
|
||||
const maxTagCount = this.props.tinode.getServerParam(Tinode.MAX_TAG_COUNT, MAX_TAG_COUNT);
|
||||
|
||||
if (tag.length > 0 && this.state.tags.length < maxTagCount) {
|
||||
const tags = this.state.tags.slice(0);
|
||||
@@ -87,8 +89,8 @@ export default class TagManager extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
const minTagLength = this.props.tinode.getServerParam('minTagLength', MIN_TAG_LENGTH);
|
||||
const maxTagLength = this.props.tinode.getServerParam('maxTagLength', MAX_TAG_LENGTH);
|
||||
const minTagLength = this.props.tinode.getServerParam(Tinode.MIN_TAG_LENGTH, MIN_TAG_LENGTH);
|
||||
const maxTagLength = this.props.tinode.getServerParam(Tinode.MAX_TAG_LENGTH, MAX_TAG_LENGTH);
|
||||
|
||||
let tags = [];
|
||||
if (this.state.activated) {
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
+105
-51
@@ -5441,6 +5441,7 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
||||
showGoToLastButton: false,
|
||||
dragging: false,
|
||||
pins: [],
|
||||
pinsLoaded: false,
|
||||
selectedPin: 0,
|
||||
subsVersion: 0
|
||||
};
|
||||
@@ -5516,7 +5517,8 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
||||
maxSeqId: topic.maxMsgSeq(),
|
||||
latestClearId: topic.maxClearId(),
|
||||
channel: topic.isChannelType(),
|
||||
pins: (topic.aux('pins') || []).slice()
|
||||
pins: (topic.aux('pins') || []).slice(),
|
||||
pinsLoaded: false
|
||||
});
|
||||
if (nextProps.callTopic == topic.name && shouldPresentCallPanel(nextProps.callState)) {
|
||||
nextState.rtcPanel = nextProps.callTopic;
|
||||
@@ -5531,7 +5533,8 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
||||
avatar: null,
|
||||
peerMessagingDisabled: false,
|
||||
channel: false,
|
||||
pins: []
|
||||
pins: [],
|
||||
pinsLoaded: false
|
||||
});
|
||||
}
|
||||
} else {
|
||||
@@ -5858,8 +5861,18 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
||||
if (count > 0) {
|
||||
this.postReadNotification(0);
|
||||
}
|
||||
const topic = this.props.tinode.getTopic(this.state.topic);
|
||||
topic.getPinnedMessages();
|
||||
if (!this.state.pinsLoaded) {
|
||||
const topic = this.props.tinode.getTopic(this.state.topic);
|
||||
this.setState({
|
||||
pinsLoaded: true
|
||||
}, _ => {
|
||||
topic.getPinnedMessages();
|
||||
});
|
||||
} else {
|
||||
this.setState({
|
||||
pinsLoaded: false
|
||||
});
|
||||
}
|
||||
}
|
||||
handleAuxUpdate(aux) {
|
||||
const pins = (aux['pins'] || []).slice();
|
||||
@@ -5968,12 +5981,25 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
||||
const menuItems = messageSpecificMenuItems || [];
|
||||
const topic = this.props.tinode.getTopic(params.topicName);
|
||||
if (topic) {
|
||||
if (!topic.isChannelType()) {
|
||||
menuItems.push('message_delete');
|
||||
}
|
||||
const acs = topic.getAccessMode();
|
||||
if (acs && acs.isDeleter()) {
|
||||
menuItems.push('message_delete_hard');
|
||||
if (topic.isSelfType()) {
|
||||
menuItems.push('message_delete_generic');
|
||||
} else {
|
||||
if (!topic.isChannelType()) {
|
||||
menuItems.push('message_delete');
|
||||
}
|
||||
const acs = topic.getAccessMode();
|
||||
if (acs && acs.isDeleter()) {
|
||||
let canDelete = acs.isOwner();
|
||||
if (!canDelete) {
|
||||
const maxAge = this.props.tinode.getServerParam(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Tinode.MSG_DELETE_AGE, 0) | 0;
|
||||
if (maxAge > 0 && params.timestamp) {
|
||||
canDelete = params.timestamp.getTime() > new Date().getTime() - maxAge * 1000;
|
||||
}
|
||||
}
|
||||
if (canDelete) {
|
||||
menuItems.push('message_delete_hard');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.props.showContextMenu(params, menuItems);
|
||||
@@ -6688,8 +6714,9 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
||||
style: {
|
||||
marginLeft: 'auto'
|
||||
}
|
||||
}), !this.props.displayMobile ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_pinned_messages_jsx__WEBPACK_IMPORTED_MODULE_15__["default"], {
|
||||
}), !this.props.displayMobile && this.state.pins.length > 0 ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_pinned_messages_jsx__WEBPACK_IMPORTED_MODULE_15__["default"], {
|
||||
tinode: this.props.tinode,
|
||||
pins: this.state.pins,
|
||||
messages: pinnedMessages,
|
||||
selected: this.state.selectedPin,
|
||||
isAdmin: this.state.isAdmin,
|
||||
@@ -6706,8 +6733,9 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
||||
onClick: this.handleContextClick
|
||||
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", {
|
||||
className: "material-icons"
|
||||
}, "more_vert")))), this.props.displayMobile ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_pinned_messages_jsx__WEBPACK_IMPORTED_MODULE_15__["default"], {
|
||||
}, "more_vert")))), this.props.displayMobile ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, this.state.pins.length > 0 ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_pinned_messages_jsx__WEBPACK_IMPORTED_MODULE_15__["default"], {
|
||||
tinode: this.props.tinode,
|
||||
pins: this.state.pins,
|
||||
messages: pinnedMessages,
|
||||
selected: this.state.selectedPin,
|
||||
isAdmin: this.state.isAdmin,
|
||||
@@ -6716,7 +6744,7 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
||||
}),
|
||||
onSelected: this.handleQuoteClick,
|
||||
onCancel: this.handleUnpinMessage
|
||||
}), react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_error_panel_jsx__WEBPACK_IMPORTED_MODULE_7__["default"], {
|
||||
}) : null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_error_panel_jsx__WEBPACK_IMPORTED_MODULE_7__["default"], {
|
||||
level: this.props.errorLevel,
|
||||
text: this.props.errorText,
|
||||
onClearError: this.props.onError
|
||||
@@ -11335,7 +11363,8 @@ class BaseChatMessage extends (react__WEBPACK_IMPORTED_MODULE_0___default().Pure
|
||||
y: e.pageY,
|
||||
x: e.pageX,
|
||||
pickReply: this.props.pickReply,
|
||||
editMessage: this.props.editMessage
|
||||
editMessage: this.props.editMessage,
|
||||
timestamp: this.props.timestamp
|
||||
}, menuItems);
|
||||
}
|
||||
handleProgress(ratio) {
|
||||
@@ -11881,7 +11910,6 @@ class ContactList extends (react__WEBPACK_IMPORTED_MODULE_0___default().Componen
|
||||
filterOn.push(('' + c.public.fn).toLowerCase());
|
||||
}
|
||||
if (!this.props.filterFunc(this.props.filter, filterOn)) {
|
||||
console.log('Filtered:', key);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -12402,6 +12430,13 @@ class ContextMenu extends (react__WEBPACK_IMPORTED_MODULE_0___default().Componen
|
||||
return this.deleteMessages(false, true, params, errorHandler);
|
||||
}
|
||||
},
|
||||
'message_delete_generic': {
|
||||
id: 'message_delete_generic',
|
||||
title: formatMessage(messages.delete),
|
||||
handler: (params, errorHandler) => {
|
||||
return this.deleteMessages(false, true, params, errorHandler);
|
||||
}
|
||||
},
|
||||
'menu_item_send_retry': {
|
||||
id: 'menu_item_send_retry',
|
||||
title: formatMessage(messages.send_retry),
|
||||
@@ -15038,12 +15073,28 @@ __webpack_require__.r(__webpack_exports__);
|
||||
|
||||
|
||||
|
||||
const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({
|
||||
message_not_found: {
|
||||
id: "message_not_found",
|
||||
defaultMessage: [{
|
||||
"type": 0,
|
||||
"value": "message not found"
|
||||
}]
|
||||
},
|
||||
message_deleted: {
|
||||
id: "message_deleted",
|
||||
defaultMessage: [{
|
||||
"type": 0,
|
||||
"value": "message deleted"
|
||||
}]
|
||||
}
|
||||
});
|
||||
class PinnedMessages extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.touchSurface = react__WEBPACK_IMPORTED_MODULE_0___default().createRef();
|
||||
this.touchX = null;
|
||||
this.touchY = null;
|
||||
this.touchSurface = react__WEBPACK_IMPORTED_MODULE_0___default().createRef();
|
||||
this.getSelectedIndex = this.getSelectedIndex.bind(this);
|
||||
this.handleCancel = this.handleCancel.bind(this);
|
||||
this.handleSelected = this.handleSelected.bind(this);
|
||||
@@ -15054,36 +15105,32 @@ class PinnedMessages extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureC
|
||||
this.handleTouchCancel = this.handleTouchCancel.bind(this);
|
||||
}
|
||||
componentDidMount() {
|
||||
if (this.touchSurface.current) {
|
||||
this.touchSurface.current.addEventListener('touchstart', this.handleTouchEventStart, {
|
||||
passive: true
|
||||
});
|
||||
this.touchSurface.current.addEventListener('touchend', this.handleTouchEventEnd, {
|
||||
passive: true
|
||||
});
|
||||
this.touchSurface.current.addEventListener('touchcancel', this.handleTouchCancel, {
|
||||
passive: true
|
||||
});
|
||||
}
|
||||
this.touchSurface.current.addEventListener('touchstart', this.handleTouchEventStart, {
|
||||
passive: true
|
||||
});
|
||||
this.touchSurface.current.addEventListener('touchend', this.handleTouchEventEnd, {
|
||||
passive: true
|
||||
});
|
||||
this.touchSurface.current.addEventListener('touchcancel', this.handleTouchCancel, {
|
||||
passive: true
|
||||
});
|
||||
}
|
||||
componentWillUnmount() {
|
||||
if (this.touchSurface.current) {
|
||||
this.touchSurface.current.removeEventListener('touchstart', this.handleTouchEventStart);
|
||||
this.touchSurface.current.removeEventListener('touchend', this.handleTouchEventEnd);
|
||||
this.touchSurface.current.removeEventListener('touchcancel', this.handleTouchCancel);
|
||||
}
|
||||
this.touchSurface.current.removeEventListener('touchstart', this.handleTouchEventStart);
|
||||
this.touchSurface.current.removeEventListener('touchend', this.handleTouchEventEnd);
|
||||
this.touchSurface.current.removeEventListener('touchcancel', this.handleTouchCancel);
|
||||
}
|
||||
getSelectedIndex() {
|
||||
const list = this.props.messages || [];
|
||||
const list = this.props.pins || [];
|
||||
return list.length - this.props.selected - 1;
|
||||
}
|
||||
handleCancel(e) {
|
||||
e.preventDefault();
|
||||
this.props.onCancel(this.props.messages[this.getSelectedIndex()].seq);
|
||||
this.props.onCancel(this.props.pins[this.getSelectedIndex()]);
|
||||
}
|
||||
handleSelected(e) {
|
||||
e.preventDefault();
|
||||
this.props.onSelected(this.props.messages[this.getSelectedIndex()].seq);
|
||||
this.props.onSelected(this.props.pins[this.getSelectedIndex()]);
|
||||
}
|
||||
handleMoveNext(e, isTouch) {
|
||||
isTouch || e.preventDefault();
|
||||
@@ -15096,7 +15143,7 @@ class PinnedMessages extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureC
|
||||
handleMovePrev(e, isTouch) {
|
||||
isTouch || e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const idx = Math.min(this.props.selected + 1, (this.props.messages || []).length - 1);
|
||||
const idx = Math.min(this.props.selected + 1, (this.props.pins || []).length - 1);
|
||||
if (idx != this.props.selected) {
|
||||
this.props.setSelected(idx);
|
||||
}
|
||||
@@ -15124,25 +15171,29 @@ class PinnedMessages extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureC
|
||||
this.handleMoveNext(e, true);
|
||||
}
|
||||
}
|
||||
handleTouchCancel(e) {
|
||||
handleTouchCancel() {
|
||||
this.touchX = null;
|
||||
}
|
||||
render() {
|
||||
const selected = this.getSelectedIndex();
|
||||
let shown = (this.props.messages || [])[selected];
|
||||
shown = shown ? tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.format(shown.content, _lib_formatters_js__WEBPACK_IMPORTED_MODULE_3__.previewFormatter, {
|
||||
let messageShown = (this.props.messages || [])[selected];
|
||||
messageShown = messageShown ? messageShown._deleted ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", {
|
||||
className: "gray"
|
||||
}, this.props.intl.formatMessage(messages.message_deleted)) : tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.format(messageShown.content, _lib_formatters_js__WEBPACK_IMPORTED_MODULE_3__.previewFormatter, {
|
||||
formatMessage: this.props.intl.formatMessage.bind(this.props.intl),
|
||||
authorizeURL: this.props.tinode.authorizeURL.bind(this.props.tinode)
|
||||
}) : null;
|
||||
}) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", {
|
||||
className: "gray"
|
||||
}, this.props.intl.formatMessage(messages.message_not_found));
|
||||
const dots = [];
|
||||
this.props.messages.forEach(_ => {
|
||||
this.props.pins.forEach(seq => {
|
||||
const cn = dots.length == selected ? 'adot' : 'dot';
|
||||
dots.push(react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
||||
key: dots.length,
|
||||
key: seq,
|
||||
className: cn
|
||||
}));
|
||||
});
|
||||
return shown ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
||||
return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
||||
id: "pinned-wrapper",
|
||||
ref: this.touchSurface
|
||||
}, this.props.isAdmin ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
||||
@@ -15159,7 +15210,7 @@ class PinnedMessages extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureC
|
||||
}, dots), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
||||
className: "pinned",
|
||||
onClick: this.handleSelected
|
||||
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("p", null, shown)), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
||||
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("p", null, messageShown)), react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
||||
className: "pinned-menu"
|
||||
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", {
|
||||
className: "menuTrigger upper"
|
||||
@@ -15175,7 +15226,7 @@ class PinnedMessages extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureC
|
||||
onClick: this.handleMoveNext
|
||||
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", {
|
||||
className: "material-icons"
|
||||
}, "expand_more")) : null))) : null;
|
||||
}, "expand_more")) : null)));
|
||||
}
|
||||
}
|
||||
/* harmony default export */ __webpack_exports__["default"] = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(PinnedMessages));
|
||||
@@ -15857,8 +15908,11 @@ __webpack_require__.r(__webpack_exports__);
|
||||
/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl");
|
||||
/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__);
|
||||
/* harmony import */ var _chip_input_jsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./chip-input.jsx */ "./src/widgets/chip-input.jsx");
|
||||
/* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../config.js */ "./src/config.js");
|
||||
/* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js");
|
||||
/* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk");
|
||||
/* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_3__);
|
||||
/* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../config.js */ "./src/config.js");
|
||||
/* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js");
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -15880,7 +15934,7 @@ class TagManager extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component
|
||||
}
|
||||
static getDerivedStateFromProps(nextProps, prevState) {
|
||||
const tags = nextProps.tags || [];
|
||||
if (!(0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_4__.arrayEqual)(tags, prevState.tags) && !prevState.activated) {
|
||||
if (!(0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_5__.arrayEqual)(tags, prevState.tags) && !prevState.activated) {
|
||||
return {
|
||||
tags: tags
|
||||
};
|
||||
@@ -15903,7 +15957,7 @@ class TagManager extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component
|
||||
}
|
||||
}
|
||||
handleAddTag(tag) {
|
||||
const maxTagCount = this.props.tinode.getServerParam('maxTagCount', _config_js__WEBPACK_IMPORTED_MODULE_3__.MAX_TAG_COUNT);
|
||||
const maxTagCount = this.props.tinode.getServerParam(tinode_sdk__WEBPACK_IMPORTED_MODULE_3__.Tinode.MAX_TAG_COUNT, _config_js__WEBPACK_IMPORTED_MODULE_4__.MAX_TAG_COUNT);
|
||||
if (tag.length > 0 && this.state.tags.length < maxTagCount) {
|
||||
const tags = this.state.tags.slice(0);
|
||||
tags.push(tag);
|
||||
@@ -15946,8 +16000,8 @@ class TagManager extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component
|
||||
}
|
||||
}
|
||||
render() {
|
||||
const minTagLength = this.props.tinode.getServerParam('minTagLength', _config_js__WEBPACK_IMPORTED_MODULE_3__.MIN_TAG_LENGTH);
|
||||
const maxTagLength = this.props.tinode.getServerParam('maxTagLength', _config_js__WEBPACK_IMPORTED_MODULE_3__.MAX_TAG_LENGTH);
|
||||
const minTagLength = this.props.tinode.getServerParam(tinode_sdk__WEBPACK_IMPORTED_MODULE_3__.Tinode.MIN_TAG_LENGTH, _config_js__WEBPACK_IMPORTED_MODULE_4__.MIN_TAG_LENGTH);
|
||||
const maxTagLength = this.props.tinode.getServerParam(tinode_sdk__WEBPACK_IMPORTED_MODULE_3__.Tinode.MAX_TAG_LENGTH, _config_js__WEBPACK_IMPORTED_MODULE_4__.MAX_TAG_LENGTH);
|
||||
let tags = [];
|
||||
if (this.state.activated) {
|
||||
this.state.tags.forEach(tag => {
|
||||
|
||||
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
File diff suppressed because one or more lines are too long
+105
-25
@@ -286,9 +286,8 @@ class CBuffer {
|
||||
getAt(at) {
|
||||
return this.buffer[at];
|
||||
}
|
||||
getLast(at) {
|
||||
at |= 0;
|
||||
return this.buffer.length > at ? this.buffer[this.buffer.length - 1 - at] : undefined;
|
||||
getLast(filter) {
|
||||
return filter ? this.buffer.findLast(filter) : this.buffer[this.buffer.length - 1];
|
||||
}
|
||||
put() {
|
||||
let insert;
|
||||
@@ -1129,6 +1128,7 @@ class DB {
|
||||
});
|
||||
}
|
||||
readMessages(topicName, query, callback, context) {
|
||||
query = query || {};
|
||||
if (!this.isReady()) {
|
||||
return this.disabled ? Promise.resolve([]) : Promise.reject(new Error("not initialized"));
|
||||
}
|
||||
@@ -1164,7 +1164,6 @@ class DB {
|
||||
});
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
query = query || {};
|
||||
const since = query.since > 0 ? query.since : 0;
|
||||
const before = query.before > 0 ? query.before : Number.MAX_SAFE_INTEGER;
|
||||
const limit = query.limit | 0;
|
||||
@@ -1215,14 +1214,50 @@ class DB {
|
||||
}
|
||||
readDelLog(topicName, query) {
|
||||
query = query || {};
|
||||
const since = query.since > 0 ? query.since : 0;
|
||||
const before = query.before > 0 ? query.before : Number.MAX_SAFE_INTEGER;
|
||||
const limit = query.limit | 0;
|
||||
if (!this.isReady()) {
|
||||
return this.disabled ? Promise.resolve([]) : Promise.reject(new Error("not initialized"));
|
||||
}
|
||||
const trx = this.db.transaction(['dellog']);
|
||||
let result = [];
|
||||
if (Array.isArray(query.ranges)) {
|
||||
return new Promise((resolve, reject) => {
|
||||
trx.onerror = event => {
|
||||
this.#logger('PCache', 'readDelLog', event.target.error);
|
||||
reject(event.target.error);
|
||||
};
|
||||
let count = 0;
|
||||
query.ranges.forEach(range => {
|
||||
const hi = range.hi || range.low + 1;
|
||||
const key = IDBKeyRange.bound([topicName, 0, range.low], [topicName, hi, Number.MAX_SAFE_INTEGER], false, true);
|
||||
trx.objectStore('dellog').getAll(key).onsuccess = event => {
|
||||
const entries = event.target.result;
|
||||
if (entries) {
|
||||
if (Array.isArray(entries)) {
|
||||
result = result.concat(array.map(entry => {
|
||||
return {
|
||||
low: entry.low,
|
||||
hi: entry.hi
|
||||
};
|
||||
}));
|
||||
} else {
|
||||
result.push({
|
||||
low: entries.low,
|
||||
hi: entries.hi
|
||||
});
|
||||
}
|
||||
}
|
||||
count++;
|
||||
if (count == query.ranges.length) {
|
||||
resolve(result);
|
||||
}
|
||||
};
|
||||
});
|
||||
});
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
const trx = this.db.transaction(['dellog']);
|
||||
const since = query.since > 0 ? query.since : 0;
|
||||
const before = query.before > 0 ? query.before : Number.MAX_SAFE_INTEGER;
|
||||
const limit = query.limit | 0;
|
||||
trx.onerror = event => {
|
||||
this.#logger('PCache', 'readDelLog', event.target.error);
|
||||
reject(event.target.error);
|
||||
@@ -4094,8 +4129,9 @@ class Topic {
|
||||
return Promise.resolve(0);
|
||||
}
|
||||
const loaded = [];
|
||||
let remains = pins;
|
||||
return this._tinode._db.readMessages(this.name, {
|
||||
ranges: (0,_utils_js__WEBPACK_IMPORTED_MODULE_6__.listToRanges)(pins)
|
||||
ranges: (0,_utils_js__WEBPACK_IMPORTED_MODULE_6__.listToRanges)(remains)
|
||||
}).then(msgs => {
|
||||
msgs.forEach(data => {
|
||||
if (data) {
|
||||
@@ -4104,18 +4140,31 @@ class Topic {
|
||||
this._maybeUpdateMessageVersionsCache(data);
|
||||
}
|
||||
});
|
||||
return loaded.length;
|
||||
}).then(count => {
|
||||
if (count == pins.length) {
|
||||
if (loaded.length < pins.length) {
|
||||
remains = pins.filter(seq => !loaded.includes(seq));
|
||||
return this._tinode._db.readMessages(this.name, {
|
||||
ranges: (0,_utils_js__WEBPACK_IMPORTED_MODULE_6__.listToRanges)(remains)
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}).then(ranges => {
|
||||
if (ranges) {
|
||||
remains.forEach(seq => {
|
||||
if (ranges.find(r => r.low <= seq && r.hi > seq)) {
|
||||
loaded.push(seq);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (loaded.length == pins.length) {
|
||||
return Promise.resolve({
|
||||
topic: this.name,
|
||||
code: 200,
|
||||
params: {
|
||||
count: count
|
||||
count: loaded.length
|
||||
}
|
||||
});
|
||||
}
|
||||
const remains = pins.filter(seq => !loaded.includes(seq));
|
||||
remains = pins.filter(seq => !loaded.includes(seq));
|
||||
return this.getMeta(this.startMetaQuery().withDataList(remains).build());
|
||||
});
|
||||
}
|
||||
@@ -4483,7 +4532,7 @@ class Topic {
|
||||
return undefined;
|
||||
}
|
||||
latestMessage() {
|
||||
return this._messages.getLast();
|
||||
return this._messages.getLast(msg => !msg._deleted);
|
||||
}
|
||||
latestMsgVersion(seq) {
|
||||
const versions = this._messageVersions[seq];
|
||||
@@ -5059,7 +5108,8 @@ class Topic {
|
||||
|
||||
__webpack_require__.r(__webpack_exports__);
|
||||
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
||||
/* harmony export */ clipRange: () => (/* binding */ clipRange),
|
||||
/* harmony export */ clipInRange: () => (/* binding */ clipInRange),
|
||||
/* harmony export */ clipOutRange: () => (/* binding */ clipOutRange),
|
||||
/* harmony export */ isUrlRelative: () => (/* binding */ isUrlRelative),
|
||||
/* harmony export */ jsonParseHelper: () => (/* binding */ jsonParseHelper),
|
||||
/* harmony export */ listToRanges: () => (/* binding */ listToRanges),
|
||||
@@ -5178,7 +5228,7 @@ function normalizeArray(arr) {
|
||||
}
|
||||
}
|
||||
}
|
||||
out.sort().filter((item, pos, ary) => {
|
||||
out = out.sort().filter((item, pos, ary) => {
|
||||
return !pos || item != ary[pos - 1];
|
||||
});
|
||||
}
|
||||
@@ -5193,14 +5243,14 @@ function normalizeRanges(ranges, maxSeq) {
|
||||
}
|
||||
ranges.sort((r1, r2) => {
|
||||
if (r1.low < r2.low) {
|
||||
return true;
|
||||
return -1;
|
||||
}
|
||||
if (r1.low == r2.low) {
|
||||
return !r2.hi || r1.hi >= r2.hi;
|
||||
return (r2.hi | 0) - r1.hi;
|
||||
}
|
||||
return false;
|
||||
return 1;
|
||||
});
|
||||
return ranges.reduce((out, r) => {
|
||||
ranges = ranges.reduce((out, r) => {
|
||||
if (r.low < _config_js__WEBPACK_IMPORTED_MODULE_1__.LOCAL_SEQID && r.low > 0) {
|
||||
if (!r.hi || r.hi < _config_js__WEBPACK_IMPORTED_MODULE_1__.LOCAL_SEQID) {
|
||||
out.push(r);
|
||||
@@ -5213,6 +5263,20 @@ function normalizeRanges(ranges, maxSeq) {
|
||||
}
|
||||
return out;
|
||||
}, []);
|
||||
ranges = ranges.reduce((out, r) => {
|
||||
if (out.length == 0) {
|
||||
out.push(r);
|
||||
} else {
|
||||
let prev = out[out.length - 1];
|
||||
if (r.low <= prev.hi) {
|
||||
prev.hi = Math.max(prev.hi, r.hi);
|
||||
} else {
|
||||
out.push(r);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}, []);
|
||||
return ranges;
|
||||
}
|
||||
function listToRanges(list) {
|
||||
list.sort((a, b) => a - b);
|
||||
@@ -5234,8 +5298,8 @@ function listToRanges(list) {
|
||||
return out;
|
||||
}, []);
|
||||
}
|
||||
function clipRange(src, clip) {
|
||||
if (clip.hi < src.low || clip.low >= src.hi) {
|
||||
function clipOutRange(src, clip) {
|
||||
if (clip.hi <= src.low || clip.low >= src.hi) {
|
||||
return [src];
|
||||
}
|
||||
if (clip.low <= src.low) {
|
||||
@@ -5243,8 +5307,8 @@ function clipRange(src, clip) {
|
||||
return [];
|
||||
}
|
||||
return [{
|
||||
low: src.low,
|
||||
hi: clip.hi
|
||||
low: clip.hi,
|
||||
hi: src.hi
|
||||
}];
|
||||
}
|
||||
const result = [{
|
||||
@@ -5259,6 +5323,19 @@ function clipRange(src, clip) {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
function clipInRange(src, clip) {
|
||||
if (clip.hi <= src.low || clip.low >= src.hi) {
|
||||
return null;
|
||||
}
|
||||
if (src.low >= clip.low && src.hi <= clip.hi) {
|
||||
return src;
|
||||
}
|
||||
return {
|
||||
low: Math.max(src.low, clip.low),
|
||||
hi: Math.min(src.hi, clip.hi)
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
/***/ }),
|
||||
|
||||
@@ -6611,9 +6688,12 @@ Tinode.MESSAGE_STATUS_TO_ME = _config_js__WEBPACK_IMPORTED_MODULE_1__.MESSAGE_ST
|
||||
Tinode.DEL_CHAR = _config_js__WEBPACK_IMPORTED_MODULE_1__.DEL_CHAR;
|
||||
Tinode.MAX_MESSAGE_SIZE = 'maxMessageSize';
|
||||
Tinode.MAX_SUBSCRIBER_COUNT = 'maxSubscriberCount';
|
||||
Tinode.MIN_TAG_LENGTH = 'minTagLength';
|
||||
Tinode.MAX_TAG_LENGTH = 'maxTagLength';
|
||||
Tinode.MAX_TAG_COUNT = 'maxTagCount';
|
||||
Tinode.MAX_FILE_UPLOAD_SIZE = 'maxFileUploadSize';
|
||||
Tinode.REQ_CRED_VALIDATORS = 'reqCred';
|
||||
Tinode.MSG_DELETE_AGE = 'msgDelAge';
|
||||
Tinode.URI_TOPIC_ID_PREFIX = 'tinode:topic/';
|
||||
})();
|
||||
|
||||
|
||||
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
Reference in New Issue
Block a user