widget for showing pinned messages (wip)
This commit is contained in:
@@ -227,7 +227,7 @@ export function filePasted(event, onImageSuccess, onAttachmentSuccess, onError)
|
||||
|
||||
// Get mime type from data URL header.
|
||||
export function getMimeType(header) {
|
||||
var mime = /^data:(image\/[-+a-z0-9.]+);base64/.exec(header);
|
||||
const mime = /^data:(image\/[-+a-z0-9.]+);base64/.exec(header);
|
||||
return (mime && mime.length > 1) ? mime[1] : null;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ export default class ContactsView extends React.Component {
|
||||
const contacts = [];
|
||||
let unreadThreads = 0;
|
||||
let archivedCount = 0;
|
||||
props.chatList.map((c) => {
|
||||
props.chatList.forEach(c => {
|
||||
const blocked = c.acs && !c.acs.isJoiner();
|
||||
// Show only blocked contacts only when props.blocked == true.
|
||||
if (blocked && props.blocked) {
|
||||
|
||||
@@ -17,6 +17,7 @@ import LetterTile from '../widgets/letter-tile.jsx';
|
||||
import LoadSpinner from '../widgets/load-spinner.jsx';
|
||||
import LogoView from './logo-view.jsx';
|
||||
import MetaMessage from '../widgets/meta-message.jsx';
|
||||
import PinnedMessages from '../widgets/pinned-messages.jsx';
|
||||
import SendMessage from '../widgets/send-message.jsx';
|
||||
import VideoPreview from '../widgets/video-preview.jsx';
|
||||
|
||||
@@ -145,6 +146,7 @@ class MessagesView extends React.Component {
|
||||
this.handleEditMessage = this.handleEditMessage.bind(this);
|
||||
this.handleCancelReply = this.handleCancelReply.bind(this);
|
||||
this.handleQuoteClick = this.handleQuoteClick.bind(this);
|
||||
this.handleUnpinMessage = this.handleUnpinMessage.bind(this);
|
||||
this.handleCallHangup = this.handleCallHangup.bind(this);
|
||||
|
||||
this.isDragEnabled = this.isDragEnabled.bind(this);
|
||||
@@ -235,7 +237,7 @@ class MessagesView extends React.Component {
|
||||
topic.onMetaDesc = this.handleDescChange;
|
||||
topic.onSubsUpdated = this.handleSubsUpdated;
|
||||
topic.onPres = this.handleSubsUpdated;
|
||||
topic.onAux = this.handleAuxUpdate;
|
||||
topic.onAuxUpdated = this.handleAuxUpdate;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,7 +447,7 @@ class MessagesView extends React.Component {
|
||||
|
||||
// Don't request the tags. They are useless unless the user
|
||||
// is the owner and is editing the topic.
|
||||
let getQuery = topic.startMetaQuery().withLaterDesc().withLaterSub();
|
||||
let getQuery = topic.startMetaQuery().withLaterDesc().withLaterSub().withAux();
|
||||
if (this.state.isReader || newTopic) {
|
||||
// Reading is either permitted or we don't know because it's a new topic. Ask for messages.
|
||||
getQuery = getQuery.withLaterData(MESSAGES_PAGE);
|
||||
@@ -516,6 +518,7 @@ class MessagesView extends React.Component {
|
||||
oldTopic.onMetaDesc = undefined;
|
||||
oldTopic.onSubsUpdated = undefined;
|
||||
oldTopic.onPres = undefined;
|
||||
oldTopic.onAuxUpdated = undefined;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -789,7 +792,7 @@ class MessagesView extends React.Component {
|
||||
params.set(key, data.resp[key]);
|
||||
}
|
||||
}
|
||||
['name', 'seq'].map((key) => {
|
||||
['name', 'seq'].forEach(key => {
|
||||
if (data[key]) {
|
||||
params.set(key, data[key]);
|
||||
}
|
||||
@@ -1277,6 +1280,11 @@ class MessagesView extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
handleUnpinMessage(seq) {
|
||||
const topic = this.props.tinode.getTopic(this.state.topic);
|
||||
topic.pinMessage(seq, false);
|
||||
}
|
||||
|
||||
isDragEnabled() {
|
||||
return this.state.isWriter && !this.state.unconfirmed && !this.props.forwardMessage && !this.state.peerMessagingDisabled;
|
||||
}
|
||||
@@ -1417,6 +1425,9 @@ class MessagesView extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
const pinnedMessages = [];
|
||||
(this.state.pins || []).forEach(seq => pinnedMessages.push(topic.findMessage(seq)));
|
||||
|
||||
const messageNodes = [];
|
||||
let previousFrom = null;
|
||||
let prevDate = null;
|
||||
@@ -1494,6 +1505,7 @@ class MessagesView extends React.Component {
|
||||
uploader={msg._uploader}
|
||||
userIsWriter={this.state.isWriter}
|
||||
userIsAdmin={this.state.isAdmin}
|
||||
pinned={(this.state.pins || []).includes(msg.seq)}
|
||||
viewportWidth={this.props.viewportWidth} // Used by `formatter`.
|
||||
showContextMenu={this.handleShowMessageContextMenu}
|
||||
onExpandMedia={this.handleExpandMedia}
|
||||
@@ -1609,12 +1621,17 @@ class MessagesView extends React.Component {
|
||||
}<ContactBadges badges={icon_badges} /></div>
|
||||
<div id="topic-last-seen">{lastSeen}</div>
|
||||
</div>
|
||||
<div>{this.state.pins}</div>
|
||||
<PinnedMessages
|
||||
tinode={this.props.tinode}
|
||||
messages={pinnedMessages}
|
||||
selected={0}
|
||||
onSelected={this.handleQuoteClick}
|
||||
onCancel={this.handleUnpinMessage} />
|
||||
{groupTopic ?
|
||||
<GroupSubs
|
||||
tinode={this.props.tinode}
|
||||
subscribers={this.state.onlineSubs} /> :
|
||||
<div id="topic-users" />
|
||||
null
|
||||
}
|
||||
<div>
|
||||
<a href="#" onClick={this.handleContextClick}>
|
||||
|
||||
@@ -46,7 +46,7 @@ export default class SettingsView extends React.PureComponent {
|
||||
render() {
|
||||
const names = {def: "default", ws: "websocket", lp: "long polling"};
|
||||
const transportOptions = [];
|
||||
['def', 'ws', 'lp'].map((item) => {
|
||||
['def', 'ws', 'lp'].forEach(item => {
|
||||
const id = 'transport-' + item;
|
||||
const name = names[item];
|
||||
transportOptions.push(
|
||||
|
||||
@@ -1686,14 +1686,14 @@ class TinodeWeb extends React.Component {
|
||||
}
|
||||
|
||||
if (added && added.length > 0) {
|
||||
added.map((uid) => {
|
||||
added.forEach(uid => {
|
||||
topic.invite(uid, null)
|
||||
.catch(err => this.handleError(err.message, 'err'));
|
||||
});
|
||||
}
|
||||
|
||||
if (removed && removed.length > 0) {
|
||||
removed.map((uid) => {
|
||||
removed.forEach(uid => {
|
||||
topic.delSubscription(uid)
|
||||
.catch(err => this.handleError(err.message, 'err'));
|
||||
});
|
||||
|
||||
@@ -29,7 +29,7 @@ class BadgeList extends React.PureComponent {
|
||||
let badges = null;
|
||||
if (this.props.trustedBadges && this.props.trustedBadges.length > 0) {
|
||||
badges = [];
|
||||
this.props.trustedBadges.map((b) => {
|
||||
this.props.trustedBadges.forEach(b => {
|
||||
const comment = this.props.short ? null : formatMessage(messages['badge_' + b]);
|
||||
const style = 'material-icons ' + b + '-color';
|
||||
badges.push(<div className="trusted-badge" key={b}><i className={style}>{icon_mapping[b] || b}</i> {comment}</div>);
|
||||
|
||||
@@ -114,7 +114,7 @@ class BaseChatMessage extends React.PureComponent {
|
||||
}
|
||||
}
|
||||
if (this.props.userIsAdmin) {
|
||||
menuItems.push('menu_item_pin');
|
||||
menuItems.push(this.props.pinned ? 'menu_item_unpin' : 'menu_item_pin');
|
||||
}
|
||||
}
|
||||
menuItems.push('menu_item_forward');
|
||||
|
||||
@@ -44,7 +44,7 @@ export default class ChipInput extends React.Component {
|
||||
static indexChips(chips) {
|
||||
const index = {};
|
||||
let count = 0;
|
||||
chips.map((item) => {
|
||||
chips.forEach(item => {
|
||||
index[item.user] = count;
|
||||
count ++;
|
||||
});
|
||||
@@ -55,7 +55,7 @@ export default class ChipInput extends React.Component {
|
||||
static sortChips(chips, keep) {
|
||||
const required = [];
|
||||
const normal = [];
|
||||
chips.map((item) => {
|
||||
chips.forEach(item => {
|
||||
if (keep && keep.includes(item.user)) {
|
||||
required.push(item);
|
||||
} else {
|
||||
@@ -115,7 +115,7 @@ export default class ChipInput extends React.Component {
|
||||
const chips = [];
|
||||
let count = 0;
|
||||
const staticMembers = this.props.staticMembers || [];
|
||||
this.state.sortedChips.map((item) => {
|
||||
this.state.sortedChips.forEach(item => {
|
||||
chips.push(
|
||||
<Chip
|
||||
tinode={this.props.tinode}
|
||||
|
||||
@@ -8,7 +8,7 @@ export default class ContactBadges extends React.PureComponent {
|
||||
let badges = null;
|
||||
if (this.props.badges && this.props.badges.length > 0) {
|
||||
badges = [];
|
||||
this.props.badges.map((b) => {
|
||||
this.props.badges.forEach(b => {
|
||||
const color = (b.color ? ' ' + b.color : '');
|
||||
if (b.icon) {
|
||||
badges.push(<i className={'material-icons as-badge' + color} key={b.key || b.icon}>{icon_mapping[b.icon] || b.icon}</i>);
|
||||
|
||||
@@ -32,7 +32,7 @@ class ContactList extends React.Component {
|
||||
const contactNodes = [];
|
||||
let contactsCount = 0;
|
||||
if (this.props.contacts && this.props.contacts.length > 0) {
|
||||
this.props.contacts.map((c) => {
|
||||
this.props.contacts.forEach(c => {
|
||||
if (c.action) {
|
||||
// Action item
|
||||
contactNodes.push(
|
||||
|
||||
@@ -458,29 +458,8 @@ class ContextMenu extends React.Component {
|
||||
if (!topic) {
|
||||
return;
|
||||
}
|
||||
|
||||
let pinned = topic.aux('pins');
|
||||
console.log("topic.aux[pins]=", pinned);
|
||||
if (!Array.isArray(pinned)) {
|
||||
pinned = [];
|
||||
}
|
||||
let changed = false;
|
||||
if (pin) {
|
||||
if (!pinned.includes(params.seq)) {
|
||||
changed = true;
|
||||
pinned.push(params.seq);
|
||||
}
|
||||
} else {
|
||||
if (pinned.includes(params.seq)) {
|
||||
changed = true;
|
||||
pinned = pinned.filter(seq => seq != params.seq)
|
||||
}
|
||||
}
|
||||
if (changed) {
|
||||
console.log("sending pins=", pinned);
|
||||
topic.setMeta({aux: {pins: pinned}})
|
||||
.catch(err => errorHandler ? errorHandler(err.message, 'err') : null);
|
||||
}
|
||||
topic.pinMessage(params.seq, pin)
|
||||
.catch(err => errorHandler ? errorHandler(err.message, 'err') : null);
|
||||
}
|
||||
|
||||
// Function is used by context menu to set permissions.
|
||||
@@ -509,7 +488,7 @@ class ContextMenu extends React.Component {
|
||||
render() {
|
||||
const menu = [];
|
||||
let count = 0;
|
||||
this.props.items.map((item) => {
|
||||
this.props.items.forEach(item => {
|
||||
if (typeof item == 'string') {
|
||||
item = this.MenuItems[item];
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ class GroupManager extends React.Component {
|
||||
|
||||
static indexMembers(members) {
|
||||
let index = {};
|
||||
members.map((m) => {
|
||||
members.forEach(m => {
|
||||
index[m.user] = {delta: 0, present: true}; // Delta: 0 unchanged, +1 added, -1 removed
|
||||
});
|
||||
return index;
|
||||
@@ -49,7 +49,7 @@ class GroupManager extends React.Component {
|
||||
|
||||
static staticMembers(members, keepInitial, requiredMember) {
|
||||
let stat = [];
|
||||
members.map((m) => {
|
||||
members.forEach(m => {
|
||||
if (keepInitial || m.user == requiredMember) {
|
||||
stat.push(m.user);
|
||||
}
|
||||
@@ -59,7 +59,7 @@ class GroupManager extends React.Component {
|
||||
|
||||
static selectedContacts(members) {
|
||||
let sel = [];
|
||||
members.map((m) => {
|
||||
members.forEach(m => {
|
||||
sel.push(m.user);
|
||||
});
|
||||
return sel;
|
||||
@@ -130,20 +130,19 @@ class GroupManager extends React.Component {
|
||||
}
|
||||
|
||||
handleSubmit() {
|
||||
var instance = this;
|
||||
var members = [];
|
||||
var added = [];
|
||||
var removed = [];
|
||||
const members = [];
|
||||
const added = [];
|
||||
const removed = [];
|
||||
|
||||
var keys = Object.keys(this.state.index);
|
||||
keys.map(function(k) {
|
||||
if (instance.state.index[k].present) {
|
||||
const keys = Object.keys(this.state.index);
|
||||
keys.forEach(k => {
|
||||
if (this.state.index[k].present) {
|
||||
members.push(k);
|
||||
}
|
||||
|
||||
if (instance.state.index[k].delta > 0) {
|
||||
if (this.state.index[k].delta > 0) {
|
||||
added.push(k);
|
||||
} else if (instance.state.index[k].delta < 0) {
|
||||
} else if (this.state.index[k].delta < 0) {
|
||||
removed.push(k);
|
||||
}
|
||||
});
|
||||
@@ -155,7 +154,6 @@ class GroupManager extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
const {formatMessage} = this.props.intl;
|
||||
return (
|
||||
<div id="group-manager">
|
||||
<div className="panel-form-row">
|
||||
|
||||
@@ -30,7 +30,9 @@ export default class GroupSubs extends React.Component {
|
||||
);
|
||||
return usersOnline.length == countToShow;
|
||||
});
|
||||
|
||||
if (usersOnline.length == 0) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<div id="topic-users">{usersOnline} {totalCount > countToShow ?
|
||||
<span>
|
||||
|
||||
@@ -36,7 +36,7 @@ export default class HostSelector extends React.PureComponent {
|
||||
}
|
||||
|
||||
render() {
|
||||
var hostOptions = [];
|
||||
const hostOptions = [];
|
||||
for (let key in KNOWN_HOSTS) {
|
||||
let item = KNOWN_HOSTS[key];
|
||||
hostOptions.push(
|
||||
|
||||
@@ -12,7 +12,7 @@ export default class SideNavbar extends React.PureComponent {
|
||||
render() {
|
||||
const icon_badges = [];
|
||||
if (this.props.trustedBadges) {
|
||||
this.props.trustedBadges.map((b) => {
|
||||
this.props.trustedBadges.forEach(b => {
|
||||
icon_badges.push({icon: b, color: 'badge-inv'});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -92,11 +92,11 @@ export default class TagManager extends React.Component {
|
||||
|
||||
let tags = [];
|
||||
if (this.state.activated) {
|
||||
this.state.tags.map((tag) => {
|
||||
this.state.tags.forEach(tag => {
|
||||
tags.push({user: tag, invalid: (tag.length < minTagLength || tag.length > maxTagLength)});
|
||||
});
|
||||
} else {
|
||||
this.state.tags.map((tag) => {
|
||||
this.state.tags.forEach(tag => {
|
||||
tags.push(<span className="badge" key={tags.length}>{tag}</span>);
|
||||
});
|
||||
if (tags.length == 0) {
|
||||
|
||||
Reference in New Issue
Block a user